From 51c183a25d32de44848c8b3f27fbe4d4196204ea Mon Sep 17 00:00:00 2001 From: Miro Date: Mon, 13 Oct 2025 11:48:42 +0200 Subject: [PATCH 1/2] =?UTF-8?q?Reintroduce=20=E2=80=9CRandom=E2=80=9D=20So?= =?UTF-8?q?rting=20in=20DRep=20Directory=20with=20Pagination=20Support=20-?= =?UTF-8?q?=20BACKEND?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- govtool/backend/src/VVA/API.hs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/govtool/backend/src/VVA/API.hs b/govtool/backend/src/VVA/API.hs index de95e6301..51c098dee 100644 --- a/govtool/backend/src/VVA/API.hs +++ b/govtool/backend/src/VVA/API.hs @@ -28,6 +28,7 @@ import qualified Data.Text.Lazy.Encoding as TL import Data.Time (TimeZone, localTimeToUTC) import Data.Time.LocalTime (TimeZone, getCurrentTimeZone) import qualified Data.Vector as V +import Data.Hashable (hash, hashWithSalt) import Numeric.Natural (Natural) @@ -64,6 +65,7 @@ type VVAApi = :> QueryParam "sort" DRepSortMode :> QueryParam "page" Natural :> QueryParam "pageSize" Natural + :> QueryParam "seed" Text :> Get '[JSON] ListDRepsResponse :<|> "drep" :> "get-voting-power" :> Capture "drepId" HexText :> Get '[JSON] Integer :<|> "drep" :> "getVotes" @@ -175,8 +177,8 @@ delegationToResponse Types.Delegation {..} = } -drepList :: App m => Maybe Text -> [DRepStatus] -> Maybe DRepSortMode -> Maybe Natural -> Maybe Natural -> m ListDRepsResponse -drepList mSearchQuery statuses mSortMode mPage mPageSize = do +drepList :: App m => Maybe Text -> [DRepStatus] -> Maybe DRepSortMode -> Maybe Natural -> Maybe Natural -> Maybe Text -> m ListDRepsResponse +drepList mSearchQuery statuses mSortMode mPage mPageSize mSeed = do CacheEnv {dRepListCache} <- asks vvaCache dreps <- cacheRequest dRepListCache (fromMaybe "" mSearchQuery) (DRep.listDReps mSearchQuery) @@ -193,17 +195,22 @@ drepList mSearchQuery statuses mSortMode mPage mPageSize = do Types.DRep -> True - let filterDRepsByStatus = case statuses of [] -> id _ -> filter $ \Types.DRepRegistration {..} -> mapDRepStatus dRepRegistrationStatus `elem` statuses - randomizedOrderList <- mapM (\_ -> randomRIO (0, 1 :: Double)) dreps + let seedInt :: Int + seedInt = + maybe 0 (hash . Text.toCaseFold) mSeed + + randomKey :: Types.DRepRegistration -> Int + randomKey Types.DRepRegistration{..} = + hashWithSalt seedInt dRepRegistrationDRepHash let sortDReps = case mSortMode of Nothing -> id - Just Random -> fmap snd . sortOn fst . Prelude.zip randomizedOrderList + Just Random -> sortOn randomKey Just VotingPower -> sortOn $ \Types.DRepRegistration {..} -> Down dRepRegistrationVotingPower Just Activity -> sortOn $ \Types.DRepRegistration {..} -> From 8493da9043a2b8776596efadc095d116bb50e5ba Mon Sep 17 00:00:00 2001 From: Adam Tomaszczyk Date: Mon, 13 Oct 2025 11:52:39 +0200 Subject: [PATCH 2/2] =?UTF-8?q?Reintroduce=20=E2=80=9CRandom=E2=80=9D=20So?= =?UTF-8?q?rting=20in=20DRep=20Directory=20with=20Pagination=20Support=20-?= =?UTF-8?q?=20frontend?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- govtool/backend/src/VVA/API.hs | 2 +- .../src/consts/dRepDirectory/sorting.ts | 4 ++++ .../src/hooks/queries/useGetDRepListQuery.ts | 5 ++++- govtool/frontend/src/models/api.ts | 1 + .../src/pages/DRepDirectoryContent.tsx | 22 +++++++++++++++++++ .../src/services/requests/getDRepList.ts | 3 +++ 6 files changed, 35 insertions(+), 2 deletions(-) diff --git a/govtool/backend/src/VVA/API.hs b/govtool/backend/src/VVA/API.hs index 51c098dee..7c4b3f519 100644 --- a/govtool/backend/src/VVA/API.hs +++ b/govtool/backend/src/VVA/API.hs @@ -210,7 +210,7 @@ drepList mSearchQuery statuses mSortMode mPage mPageSize mSeed = do let sortDReps = case mSortMode of Nothing -> id - Just Random -> sortOn randomKey + Just Random -> sortOn randomKey Just VotingPower -> sortOn $ \Types.DRepRegistration {..} -> Down dRepRegistrationVotingPower Just Activity -> sortOn $ \Types.DRepRegistration {..} -> diff --git a/govtool/frontend/src/consts/dRepDirectory/sorting.ts b/govtool/frontend/src/consts/dRepDirectory/sorting.ts index 339f708ae..2fb4af207 100644 --- a/govtool/frontend/src/consts/dRepDirectory/sorting.ts +++ b/govtool/frontend/src/consts/dRepDirectory/sorting.ts @@ -15,4 +15,8 @@ export const DREP_DIRECTORY_SORTING = [ key: "Status", label: "Status", }, + { + key: "Random", + label: "Random", + }, ]; diff --git a/govtool/frontend/src/hooks/queries/useGetDRepListQuery.ts b/govtool/frontend/src/hooks/queries/useGetDRepListQuery.ts index db62f9c09..80c91ed5b 100644 --- a/govtool/frontend/src/hooks/queries/useGetDRepListQuery.ts +++ b/govtool/frontend/src/hooks/queries/useGetDRepListQuery.ts @@ -24,7 +24,7 @@ type Args = GetDRepListArguments & { }; export function useGetDRepListPaginatedQuery( - { page, pageSize = 10, filters = [], searchPhrase, sorting, status }: Args, + { page, pageSize = 10, filters = [], searchPhrase, sorting, status, sortingSeed }: Args, options?: UseQueryOptions>, ): PaginatedResult { const { pendingTransaction } = useCardano(); @@ -47,6 +47,7 @@ export function useGetDRepListPaginatedQuery( searchPhrase ?? "", sorting ?? "", status?.length ? status : "", + sortingSeed ?? "" ]; const baselineKey = useMemo( @@ -64,6 +65,7 @@ export function useGetDRepListPaginatedQuery( searchPhrase, sorting, status, + sortingSeed, }), { keepPreviousData: true, @@ -87,6 +89,7 @@ export function useGetDRepListPaginatedQuery( searchPhrase: "", sorting, status, + sortingSeed }), { initialData: () => diff --git a/govtool/frontend/src/models/api.ts b/govtool/frontend/src/models/api.ts index 4f48125a6..3040c77c0 100644 --- a/govtool/frontend/src/models/api.ts +++ b/govtool/frontend/src/models/api.ts @@ -148,6 +148,7 @@ export enum DRepListSort { VotingPower = "VotingPower", RegistrationDate = "RegistrationDate", Status = "Status", + Random = "Random", } type Reference = { diff --git a/govtool/frontend/src/pages/DRepDirectoryContent.tsx b/govtool/frontend/src/pages/DRepDirectoryContent.tsx index e7559d247..cd67675c3 100644 --- a/govtool/frontend/src/pages/DRepDirectoryContent.tsx +++ b/govtool/frontend/src/pages/DRepDirectoryContent.tsx @@ -61,6 +61,27 @@ export const DRepDirectoryContent: FC = ({ ...dataActionsBarProps } = useDataActionsBar(); + const SEED_STORAGE_KEY = "drep_directory_sorting_seed"; + + const makeSeed = () => + (globalThis.crypto?.randomUUID?.() as string | undefined) ?? + Math.random().toString(36).slice(2); + + const getStoredSeed = () => { + if (typeof window === "undefined") return ""; + return sessionStorage.getItem(SEED_STORAGE_KEY) || ""; + }; + + const [sortingSeed, setSortingSeed] = useState(() => getStoredSeed()); + + useEffect(() => { + if (lastPath && !lastPath.includes("drep_directory")) { + const newSeed = makeSeed(); + setSortingSeed(newSeed); + sessionStorage.setItem(SEED_STORAGE_KEY, newSeed); + } + }, [sortingSeed]); + const { page, pageSize, setPage, setPageSize } = usePagination(); const { chosenFilters, chosenSorting, setChosenFilters, setChosenSorting } = @@ -108,6 +129,7 @@ export const DRepDirectoryContent: FC = ({ searchPhrase: debouncedSearchText, sorting: chosenSorting as DRepListSort, status: chosenFilters as DRepStatus[], + sortingSeed }, { enabled: !!chosenSorting }, ); diff --git a/govtool/frontend/src/services/requests/getDRepList.ts b/govtool/frontend/src/services/requests/getDRepList.ts index 12270b7ea..5d9ba4bd7 100644 --- a/govtool/frontend/src/services/requests/getDRepList.ts +++ b/govtool/frontend/src/services/requests/getDRepList.ts @@ -14,6 +14,7 @@ export type GetDRepListArguments = { sorting?: DRepListSort; status?: DRepStatus[]; searchPhrase?: string; + sortingSeed?: string; }; export const getDRepList = async ({ @@ -23,6 +24,7 @@ export const getDRepList = async ({ pageSize = 10, searchPhrase: rawSearchPhrase = "", status = [], + sortingSeed = "" }: GetDRepListArguments): Promise> => { const searchPhrase = await dRepSearchPhraseProcessor(rawSearchPhrase); @@ -34,6 +36,7 @@ export const getDRepList = async ({ ...(filters.length && { type: filters }), ...(sorting && { sort: sorting }), ...(status.length && { status }), + ...(sortingSeed && { seed: sortingSeed }), }, });