diff --git a/frontend/src/helpers/userTablePreferences.ts b/frontend/src/helpers/userTablePreferences.ts new file mode 100644 index 000000000..a23438746 --- /dev/null +++ b/frontend/src/helpers/userTablePreferences.ts @@ -0,0 +1,73 @@ +const TABLE_PREFERENCES_KEY = "userTablePreferences"; + +export enum PreferenceKey { + PerPage = "perPage" +} + +interface TableSpecificPreferences { + [preferenceKey: string]: any; +} + +interface UserTablePreferences { + [tableName: string]: TableSpecificPreferences; +} + +// Retrieves all table preferences from localStorage +const getAllTablePreferences = (): UserTablePreferences => { + try { + const preferencesString = localStorage.getItem(TABLE_PREFERENCES_KEY); + if (preferencesString) { + return JSON.parse(preferencesString) as UserTablePreferences; + } + } catch (error) { + console.error("Error reading user table preferences from localStorage:", error); + } + return {}; +}; + +// Saves all table preferences to localStorage +const saveAllTablePreferences = (preferences: UserTablePreferences): void => { + try { + localStorage.setItem(TABLE_PREFERENCES_KEY, JSON.stringify(preferences)); + } catch (error) { + console.error("Error saving user table preferences to localStorage:", error); + } +}; + +// Retrieves a specific preference for a given table +export const getUserTablePreference = ( + tableName: string, + preferenceKey: PreferenceKey, + defaultValue: T +): T => { + const preferences = getAllTablePreferences(); + if ( + preferences && + typeof preferences === "object" && + tableName in preferences && + preferenceKey in preferences[tableName] + ) { + const value = preferences[tableName][preferenceKey]; + + if (value !== undefined && value !== null) { + return value as T; + } + } + return defaultValue; +}; + +// Sets a specific preference for a given table and saves it to localStorage +export const setUserTablePreference = ( + tableName: string, + preferenceKey: PreferenceKey, + value: any +): void => { + const preferences = getAllTablePreferences(); + + if (!preferences[tableName]) { + preferences[tableName] = {}; + } + + preferences[tableName][preferenceKey] = value; + saveAllTablePreferences(preferences); +}; diff --git a/frontend/src/pages/kms/KmipPage/components/KmipClientTable.tsx b/frontend/src/pages/kms/KmipPage/components/KmipClientTable.tsx index a9d29d24a..bcc49b11a 100644 --- a/frontend/src/pages/kms/KmipPage/components/KmipClientTable.tsx +++ b/frontend/src/pages/kms/KmipPage/components/KmipClientTable.tsx @@ -43,6 +43,11 @@ import { useSubscription, useWorkspace } from "@app/context"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { OrderByDirection } from "@app/hooks/api/generic/types"; import { useGetKmipClientsByProjectId } from "@app/hooks/api/kmip"; @@ -71,7 +76,14 @@ export const KmipClientTable = () => { perPage, page, setPerPage - } = usePagination(KmipClientOrderBy.Name); + } = usePagination(KmipClientOrderBy.Name, { + initPerPage: getUserTablePreference("kmipClientTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("kmipClientTable", PreferenceKey.PerPage, newPerPage); + }; const { data, isPending, isFetching } = useGetKmipClientsByProjectId({ projectId, @@ -290,7 +302,7 @@ export const KmipClientTable = () => { page={page} perPage={perPage} onChangePage={(newPage) => setPage(newPage)} - onChangePerPage={(newPerPage) => setPerPage(newPerPage)} + onChangePerPage={handlePerPageChange} /> )} {!isPending && kmipClients.length === 0 && ( diff --git a/frontend/src/pages/kms/OverviewPage/components/CmekTable.tsx b/frontend/src/pages/kms/OverviewPage/components/CmekTable.tsx index c6902b4fa..e1a2fe789 100644 --- a/frontend/src/pages/kms/OverviewPage/components/CmekTable.tsx +++ b/frontend/src/pages/kms/OverviewPage/components/CmekTable.tsx @@ -53,6 +53,11 @@ import { useWorkspace } from "@app/context"; import { kmsKeyUsageOptions } from "@app/helpers/kms"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, usePopUp, useResetPageHelper, useTimedReset } from "@app/hooks"; import { useGetCmeksByProjectId, useUpdateCmek } from "@app/hooks/api/cmeks"; import { CmekOrderBy, KmsKeyUsage, TCmek } from "@app/hooks/api/cmeks/types"; @@ -100,7 +105,14 @@ export const CmekTable = () => { perPage, page, setPerPage - } = usePagination(CmekOrderBy.Name); + } = usePagination(CmekOrderBy.Name, { + initPerPage: getUserTablePreference("cmekClientTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("cmekClientTable", PreferenceKey.PerPage, newPerPage); + }; const { data, isPending, isFetching } = useGetCmeksByProjectId({ projectId, @@ -508,7 +520,7 @@ export const CmekTable = () => { page={page} perPage={perPage} onChangePage={(newPage) => setPage(newPage)} - onChangePerPage={(newPerPage) => setPerPage(newPerPage)} + onChangePerPage={handlePerPageChange} /> )} {!isPending && keys.length === 0 && ( diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsTable.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsTable.tsx index e7b89c48d..14de28fd6 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsTable.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsTable.tsx @@ -34,6 +34,11 @@ import { Tr } from "@app/components/v2"; import { OrgPermissionGroupActions, OrgPermissionSubjects, useOrganization } from "@app/context"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useGetOrganizationGroups, useGetOrgRoles, useUpdateGroup } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; @@ -103,7 +108,14 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => { setOrderBy, setOrderDirection, toggleOrderDirection - } = usePagination(GroupsOrderBy.Name, { initPerPage: 20 }); + } = usePagination(GroupsOrderBy.Name, { + initPerPage: getUserTablePreference("orgGroupsTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("orgGroupsTable", PreferenceKey.PerPage, newPerPage); + }; const filteredGroups = useMemo(() => { const filtered = search @@ -376,7 +388,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => { page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isPending && !filteredGroups?.length && ( diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityTable.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityTable.tsx index ddfcc7a7c..d499a7b36 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityTable.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityTable.tsx @@ -42,6 +42,11 @@ import { Tr } from "@app/components/v2"; import { OrgPermissionIdentityActions, OrgPermissionSubjects, useOrganization } from "@app/context"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useGetOrgRoles, useSearchIdentities, useUpdateIdentity } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; @@ -76,7 +81,15 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => { perPage, page, setPerPage - } = usePagination(OrgIdentityOrderBy.Name); + } = usePagination(OrgIdentityOrderBy.Name, { + initPerPage: getUserTablePreference("identityTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("identityTable", PreferenceKey.PerPage, newPerPage); + }; + const [filteredRoles, setFilteredRoles] = useState([]); const organizationId = currentOrg?.id || ""; @@ -379,7 +392,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => { page={page} perPage={perPage} onChangePage={(newPage) => setPage(newPage)} - onChangePerPage={(newPerPage) => setPerPage(newPerPage)} + onChangePerPage={handlePerPageChange} /> )} {!isPending && data && data?.identities.length === 0 && ( diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx index a79da885b..e0350741e 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx @@ -42,6 +42,11 @@ import { useSubscription, useUser } from "@app/context"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useFetchServerStatus, @@ -170,7 +175,14 @@ export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLinks }: Pro setOrderBy, setOrderDirection, toggleOrderDirection - } = usePagination(OrgMembersOrderBy.Name, { initPerPage: 20 }); + } = usePagination(OrgMembersOrderBy.Name, { + initPerPage: getUserTablePreference("orgMembersTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("orgMembersTable", PreferenceKey.PerPage, newPerPage); + }; const filteredUsers = useMemo( () => @@ -513,7 +525,7 @@ export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLinks }: Pro page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isMembersLoading && !filteredUsers?.length && ( diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionsTable.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionsTable.tsx index 379ce877c..bc448663a 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionsTable.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionsTable.tsx @@ -30,6 +30,11 @@ import { Tr } from "@app/components/v2"; import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { TAppConnection, useListAppConnections } from "@app/hooks/api/appConnections"; import { AppConnection } from "@app/hooks/api/appConnections/enums"; @@ -76,7 +81,14 @@ export const AppConnectionsTable = () => { orderBy, setOrderDirection, setOrderBy - } = usePagination(AppConnectionsOrderBy.App, { initPerPage: 20 }); + } = usePagination(AppConnectionsOrderBy.App, { + initPerPage: getUserTablePreference("appConnectionsTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("appConnectionsTable", PreferenceKey.PerPage, newPerPage); + }; const filteredAppConnections = useMemo( () => @@ -282,7 +294,7 @@ export const AppConnectionsTable = () => { page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isPending && !filteredAppConnections?.length && ( diff --git a/frontend/src/pages/organization/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx b/frontend/src/pages/organization/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx index b6af10f2f..6472c34c1 100644 --- a/frontend/src/pages/organization/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx +++ b/frontend/src/pages/organization/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx @@ -25,6 +25,11 @@ import { Tr } from "@app/components/v2"; import { OrgPermissionGroupActions, OrgPermissionSubjects, useOrganization } from "@app/context"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useListGroupUsers, useOidcManageGroupMembershipsEnabled } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; @@ -57,7 +62,14 @@ export const GroupMembersTable = ({ groupId, groupSlug, handlePopUpOpen }: Props offset, orderDirection, toggleOrderDirection - } = usePagination(GroupMembersOrderBy.Name, { initPerPage: 10 }); + } = usePagination(GroupMembersOrderBy.Name, { + initPerPage: getUserTablePreference("groupMembersTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("groupMembersTable", PreferenceKey.PerPage, newPerPage); + }; const { currentOrg } = useOrganization(); @@ -163,7 +175,7 @@ export const GroupMembersTable = ({ groupId, groupSlug, handlePopUpOpen }: Props page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isPending && !filteredGroupMemberships?.length && ( diff --git a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectsTable.tsx b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectsTable.tsx index 680bb8035..ef70d1f96 100644 --- a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectsTable.tsx +++ b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectsTable.tsx @@ -21,6 +21,11 @@ import { THead, Tr } from "@app/components/v2"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useGetIdentityProjectMemberships } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; @@ -53,7 +58,14 @@ export const IdentityProjectsTable = ({ identityId, handlePopUpOpen }: Props) => offset, orderDirection, toggleOrderDirection - } = usePagination(IdentityProjectsOrderBy.Name, { initPerPage: 10 }); + } = usePagination(IdentityProjectsOrderBy.Name, { + initPerPage: getUserTablePreference("identityProjectsTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("identityProjectsTable", PreferenceKey.PerPage, newPerPage); + }; const filteredProjectMemberships = useMemo( () => @@ -132,7 +144,7 @@ export const IdentityProjectsTable = ({ identityId, handlePopUpOpen }: Props) => page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isPending && !filteredProjectMemberships?.length && ( diff --git a/frontend/src/pages/organization/SecretManagerOverviewPage/components/AllProjectView.tsx b/frontend/src/pages/organization/SecretManagerOverviewPage/components/AllProjectView.tsx index 5fd4252e3..6be1a4554 100644 --- a/frontend/src/pages/organization/SecretManagerOverviewPage/components/AllProjectView.tsx +++ b/frontend/src/pages/organization/SecretManagerOverviewPage/components/AllProjectView.tsx @@ -28,6 +28,11 @@ import { } from "@app/components/v2"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context"; import { getProjectHomePage } from "@app/helpers/project"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { useDebounce, usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { useRequestProjectAccess, useSearchProjects } from "@app/hooks/api"; import { ProjectType, Workspace } from "@app/hooks/api/workspace/types"; @@ -104,7 +109,15 @@ export const AllProjectView = ({ limit, toggleOrderDirection, orderDirection - } = usePagination("name", { initPerPage: 50 }); + } = usePagination("name", { + initPerPage: getUserTablePreference("allProjectsTable", PreferenceKey.PerPage, 50) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("allProjectsTable", PreferenceKey.PerPage, newPerPage); + }; + const { popUp, handlePopUpToggle, handlePopUpOpen } = usePopUp([ "requestAccessConfirmation" ] as const); @@ -274,7 +287,7 @@ export const AllProjectView = ({ count={searchedProjects?.totalCount || 0} page={page} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isProjectLoading && !searchedProjects?.totalCount && ( diff --git a/frontend/src/pages/organization/SecretManagerOverviewPage/components/MyProjectView.tsx b/frontend/src/pages/organization/SecretManagerOverviewPage/components/MyProjectView.tsx index e723e1dfe..a04b4e196 100644 --- a/frontend/src/pages/organization/SecretManagerOverviewPage/components/MyProjectView.tsx +++ b/frontend/src/pages/organization/SecretManagerOverviewPage/components/MyProjectView.tsx @@ -19,6 +19,11 @@ import { OrgPermissionCan } from "@app/components/permissions"; import { Button, IconButton, Input, Pagination, Skeleton, Tooltip } from "@app/components/v2"; import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context"; import { getProjectHomePage } from "@app/helpers/project"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useGetUserWorkspaces } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; @@ -63,7 +68,15 @@ export const MyProjectView = ({ limit, toggleOrderDirection, orderDirection - } = usePagination(ProjectOrderBy.Name, { initPerPage: 24 }); + } = usePagination(ProjectOrderBy.Name, { + initPerPage: getUserTablePreference("myProjectsTable", PreferenceKey.PerPage, 24) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("myProjectsTable", PreferenceKey.PerPage, newPerPage); + }; + const { data: projectFavorites, isPending: isProjectFavoritesLoading } = useGetUserProjectFavorites(currentOrg?.id); @@ -415,7 +428,7 @@ export const MyProjectView = ({ count={filteredWorkspaces.length} page={page} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {isWorkspaceEmpty && ( diff --git a/frontend/src/pages/organization/SecretScanningPage/SecretScanningPage.tsx b/frontend/src/pages/organization/SecretScanningPage/SecretScanningPage.tsx index 23cdcf800..f0ad03677 100644 --- a/frontend/src/pages/organization/SecretScanningPage/SecretScanningPage.tsx +++ b/frontend/src/pages/organization/SecretScanningPage/SecretScanningPage.tsx @@ -13,6 +13,11 @@ import { useOrganization, useServerConfig } from "@app/context"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { withPermission } from "@app/hoc"; import { usePagination, usePopUp } from "@app/hooks"; import { @@ -28,8 +33,6 @@ import { SecretScanningFilter } from "./components/SecretScanningFilters"; import { SecretScanningFilterFormData, secretScanningFilterFormSchema } from "./components/types"; import { SecretScanningLogsTable } from "./components"; -const PER_PAGE_INIT = 25; - export const SecretScanningPage = withPermission( () => { const queryParams = useSearch({ @@ -49,9 +52,14 @@ export const SecretScanningPage = withPermission( const { offset, limit, orderBy, setPage, perPage, page, setPerPage } = usePagination( SecretScanningOrderBy.CreatedAt, - { initPerPage: PER_PAGE_INIT } + { initPerPage: getUserTablePreference("secretScanningTable", PreferenceKey.PerPage, 20) } ); + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("secretScanningTable", PreferenceKey.PerPage, newPerPage); + }; + const repositoryNames = watch("repositoryNames"); const resolvedStatus = watch("resolved"); @@ -180,7 +188,7 @@ export const SecretScanningPage = withPermission( )} -
+
{integrationEnabled && (
)} - {!isPending && - risksData?.totalCount !== undefined && - risksData.totalCount >= PER_PAGE_INIT && ( - setPage(newPage)} - onChangePerPage={(newPerPage) => setPerPage(newPerPage)} - /> - )} + {!isPending && risksData?.totalCount !== undefined && risksData.totalCount >= 10 && ( + setPage(newPage)} + onChangePerPage={handlePerPageChange} + /> + )}
diff --git a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserGroupsTable.tsx b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserGroupsTable.tsx index b22b1377f..78065cedb 100644 --- a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserGroupsTable.tsx +++ b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserGroupsTable.tsx @@ -20,6 +20,11 @@ import { THead, Tr } from "@app/components/v2"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { OrderByDirection } from "@app/hooks/api/generic/types"; import { OrgUser } from "@app/hooks/api/types"; @@ -52,7 +57,14 @@ export const UserGroupsTable = ({ handlePopUpOpen, orgMembership }: Props) => { offset, orderDirection, toggleOrderDirection - } = usePagination(UserGroupsOrderBy.Name, { initPerPage: 10 }); + } = usePagination(UserGroupsOrderBy.Name, { + initPerPage: getUserTablePreference("userGroupsTable", PreferenceKey.PerPage, 10) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("userGroupsTable", PreferenceKey.PerPage, newPerPage); + }; const filteredGroupMemberships = useMemo( () => @@ -119,7 +131,7 @@ export const UserGroupsTable = ({ handlePopUpOpen, orgMembership }: Props) => { page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isPending && !filteredGroupMemberships?.length && ( diff --git a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectsTable.tsx b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectsTable.tsx index ff9ed9bbc..9e6042c03 100644 --- a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectsTable.tsx +++ b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectsTable.tsx @@ -22,6 +22,11 @@ import { Tr } from "@app/components/v2"; import { useOrganization } from "@app/context"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useGetOrgMembershipProjectMemberships } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; @@ -54,7 +59,14 @@ export const UserProjectsTable = ({ membershipId, handlePopUpOpen }: Props) => { offset, orderDirection, toggleOrderDirection - } = usePagination(UserProjectsOrderBy.Name, { initPerPage: 10 }); + } = usePagination(UserProjectsOrderBy.Name, { + initPerPage: getUserTablePreference("userProjectsTable", PreferenceKey.PerPage, 10) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("userProjectsTable", PreferenceKey.PerPage, newPerPage); + }; const { data: projectMemberships = [], isPending } = useGetOrgMembershipProjectMemberships( orgId, @@ -136,7 +148,7 @@ export const UserProjectsTable = ({ membershipId, handlePopUpOpen }: Props) => { page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isPending && !filteredProjectMemberships?.length && ( diff --git a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx index 24f459a93..8f06576e2 100644 --- a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx @@ -27,6 +27,11 @@ import { Tr } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useListWorkspaceGroups } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; @@ -62,7 +67,14 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => { orderDirection, orderBy, toggleOrderDirection - } = usePagination(GroupsOrderBy.Name, { initPerPage: 20 }); + } = usePagination(GroupsOrderBy.Name, { + initPerPage: getUserTablePreference("projectGroupsTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("projectGroupsTable", PreferenceKey.PerPage, newPerPage); + }; const { data: groupMemberships = [], isPending } = useListWorkspaceGroups( currentWorkspace?.id || "" @@ -183,7 +195,7 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => { page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isPending && !filteredGroupMemberships?.length && ( diff --git a/frontend/src/pages/project/AccessControlPage/components/IdentityTab/IdentityTab.tsx b/frontend/src/pages/project/AccessControlPage/components/IdentityTab/IdentityTab.tsx index c9e563065..d20beb738 100644 --- a/frontend/src/pages/project/AccessControlPage/components/IdentityTab/IdentityTab.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/IdentityTab/IdentityTab.tsx @@ -42,6 +42,11 @@ import { } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { formatProjectRoleName } from "@app/helpers/roles"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { withProjectPermission } from "@app/hoc"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useDeleteIdentityFromWorkspace, useGetWorkspaceIdentityMemberships } from "@app/hooks/api"; @@ -72,7 +77,14 @@ export const IdentityTab = withProjectPermission( perPage, page, setPerPage - } = usePagination(ProjectIdentityOrderBy.Name); + } = usePagination(ProjectIdentityOrderBy.Name, { + initPerPage: getUserTablePreference("projectIdentityTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("projectIdentityTable", PreferenceKey.PerPage, newPerPage); + }; const workspaceId = currentWorkspace?.id ?? ""; @@ -403,7 +415,7 @@ export const IdentityTab = withProjectPermission( page={page} perPage={perPage} onChangePage={(newPage) => setPage(newPage)} - onChangePerPage={(newPerPage) => setPerPage(newPerPage)} + onChangePerPage={handlePerPageChange} /> )} {!isPending && data && data?.identityMemberships.length === 0 && ( diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersTable.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersTable.tsx index c03f7f793..c1251bef2 100644 --- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersTable.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersTable.tsx @@ -51,6 +51,11 @@ import { useWorkspace } from "@app/context"; import { formatProjectRoleName } from "@app/helpers/roles"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useGetProjectRoles, useGetWorkspaceUsers } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; @@ -101,12 +106,12 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => { setOrderDirection, toggleOrderDirection } = usePagination(MembersOrderBy.Name, { - initPerPage: parseInt(localStorage.getItem("PROJECT_MEMBERS_TABLE_PER_PAGE") || "20", 10) + initPerPage: getUserTablePreference("projectMembersTable", PreferenceKey.PerPage, 20) }); const handlePerPageChange = (newPerPage: number) => { setPerPage(newPerPage); - localStorage.setItem("PROJECT_MEMBERS_TABLE_PER_PAGE", newPerPage.toString()); + setUserTablePreference("projectMembersTable", PreferenceKey.PerPage, newPerPage); }; const { data: members = [], isPending: isMembersLoading } = useGetWorkspaceUsers( diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/IntegrationsTable.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/IntegrationsTable.tsx index a8d2cccd5..775e42c50 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/IntegrationsTable.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/IntegrationsTable.tsx @@ -32,6 +32,11 @@ import { Tooltip, Tr } from "@app/components/v2"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { OrderByDirection } from "@app/hooks/api/generic/types"; import { useSyncIntegration } from "@app/hooks/api/integrations/queries"; @@ -110,7 +115,14 @@ export const IntegrationsTable = ({ orderBy, setOrderDirection, setOrderBy - } = usePagination(IntegrationsOrderBy.App, { initPerPage: 20 }); + } = usePagination(IntegrationsOrderBy.App, { + initPerPage: getUserTablePreference("integrationsTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("integrationsTable", PreferenceKey.PerPage, newPerPage); + }; useEffect(() => { if (integrations?.some((integration) => integration.isSynced === false)) @@ -437,7 +449,7 @@ export const IntegrationsTable = ({ page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isLoading && !filteredIntegrations?.length && ( diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncsTable.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncsTable.tsx index 802e88bc1..fcd42a10f 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncsTable.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncsTable.tsx @@ -38,6 +38,11 @@ import { } from "@app/components/v2"; import { useWorkspace } from "@app/context"; import { SECRET_SYNC_MAP } from "@app/helpers/secretSyncs"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { OrderByDirection } from "@app/hooks/api/generic/types"; import { @@ -119,7 +124,14 @@ export const SecretSyncsTable = ({ secretSyncs }: Props) => { orderBy, setOrderDirection, setOrderBy - } = usePagination(SecretSyncsOrderBy.Name, { initPerPage: 20 }); + } = usePagination(SecretSyncsOrderBy.Name, { + initPerPage: getUserTablePreference("secretSyncTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("secretSyncTable", PreferenceKey.PerPage, newPerPage); + }; const filteredSecretSyncs = useMemo( () => @@ -465,7 +477,7 @@ export const SecretSyncsTable = ({ secretSyncs }: Props) => { page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!filteredSecretSyncs?.length && ( diff --git a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx index 5f0d90f6c..c94aef0d5 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx @@ -64,6 +64,11 @@ import { useWorkspace } from "@app/context"; import { ProjectPermissionSecretRotationActions } from "@app/context/ProjectPermissionContext/types"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { useDebounce, usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { useCreateFolder, @@ -180,7 +185,14 @@ export const OverviewPage = () => { page, setPerPage, orderBy - } = usePagination(DashboardSecretsOrderBy.Name); + } = usePagination(DashboardSecretsOrderBy.Name, { + initPerPage: getUserTablePreference("secretOverviewTable", PreferenceKey.PerPage, 100) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("secretOverviewTable", PreferenceKey.PerPage, newPerPage); + }; const resetSelectedEntries = useCallback(() => { setSelectedEntries({ @@ -1416,7 +1428,7 @@ export const OverviewPage = () => { page={page} perPage={perPage} onChangePage={(newPage) => setPage(newPage)} - onChangePerPage={(newPerPage) => setPerPage(newPerPage)} + onChangePerPage={handlePerPageChange} /> )} diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx index d28f28392..49bf1a72c 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx @@ -29,6 +29,11 @@ import { ProjectPermissionSecretActions, ProjectPermissionSecretRotationActions } from "@app/context/ProjectPermissionContext/types"; +import { + getUserTablePreference, + PreferenceKey, + setUserTablePreference +} from "@app/helpers/userTablePreferences"; import { useDebounce, usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { useGetImportedSecretsSingleEnv, @@ -98,7 +103,14 @@ const Page = () => { page, setPerPage, orderBy - } = usePagination(DashboardSecretsOrderBy.Name); + } = usePagination(DashboardSecretsOrderBy.Name, { + initPerPage: getUserTablePreference("secretDashboardTable", PreferenceKey.PerPage, 100) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("secretDashboardTable", PreferenceKey.PerPage, newPerPage); + }; const [snapshotId, setSnapshotId] = useState(null); const isRollbackMode = Boolean(snapshotId); @@ -558,7 +570,7 @@ const Page = () => { page={page} perPage={perPage} onChangePage={(newPage) => setPage(newPage)} - onChangePerPage={(newPerPage) => setPerPage(newPerPage)} + onChangePerPage={handlePerPageChange} /> )} { offset, orderDirection, toggleOrderDirection - } = usePagination(TagsOrderBy.Slug, { initPerPage: 10 }); + } = usePagination(TagsOrderBy.Slug, { + initPerPage: getUserTablePreference("secretTagsTable", PreferenceKey.PerPage, 20) + }); + + const handlePerPageChange = (newPerPage: number) => { + setPerPage(newPerPage); + setUserTablePreference("secretTagsTable", PreferenceKey.PerPage, newPerPage); + }; const filteredTags = useMemo( () => @@ -151,7 +163,7 @@ export const SecretTagsTable = ({ handlePopUpOpen }: Props) => { page={page} perPage={perPage} onChangePage={setPage} - onChangePerPage={setPerPage} + onChangePerPage={handlePerPageChange} /> )} {!isPending && !filteredTags?.length && (