From c9574f4ff981121d8379fb99d8585d8b136f3ffb Mon Sep 17 00:00:00 2001 From: Omar Date: Wed, 15 Jan 2025 11:30:30 +0100 Subject: [PATCH] Enable server-side pagination for update_channels Updated queries for `update_channel` to support server-side pagination. This change ensures data fetching is paginated on the backend while maintaining the current client-side logic. A future update will optimize the respective tables to fully leverage pagination, avoiding an immediate rewrite of the client-side implementation. Part of #779 Signed-off-by: Omar --- frontend/src/api/schema.graphql | 35 ++++++++++++++- .../src/components/UpdateChannelsTable.tsx | 44 ++++++++++++------- frontend/src/forms/CreateUpdateCampaign.tsx | 10 +++-- frontend/src/pages/UpdateCampaignCreate.tsx | 4 +- frontend/src/pages/UpdateChannel.tsx | 16 +++---- frontend/src/pages/UpdateChannels.tsx | 17 ++++--- 6 files changed, 90 insertions(+), 36 deletions(-) diff --git a/frontend/src/api/schema.graphql b/frontend/src/api/schema.graphql index 4a1c4cdd8..42dc453c3 100644 --- a/frontend/src/api/schema.graphql +++ b/frontend/src/api/schema.graphql @@ -2528,6 +2528,27 @@ enum UpdateChannelSortField { NAME } +":update_channel connection" +type UpdateChannelConnection { + "Total count on all pages" + count: Int + + "Page information" + pageInfo: PageInfo! + + ":update_channel edges" + edges: [UpdateChannelEdge!] +} + +":update_channel edge" +type UpdateChannelEdge { + "Cursor" + cursor: String! + + ":update_channel node" + node: UpdateChannel! +} + input UpdateChannelFilterName { isNil: Boolean eq: String @@ -2897,7 +2918,19 @@ type RootQueryType { "A filter to limit the results" filter: UpdateChannelFilterInput - ): [UpdateChannel!]! + + "The number of records to return from the beginning. Maximum 250" + first: Int + + "Show records before the specified keyset." + before: String + + "Show records after the specified keyset." + after: String + + "The number of records to return to the end. Maximum 250" + last: Int + ): UpdateChannelConnection "Retrieves the current tenant." tenantInfo: TenantInfo! diff --git a/frontend/src/components/UpdateChannelsTable.tsx b/frontend/src/components/UpdateChannelsTable.tsx index bf2648c01..d2671acd5 100644 --- a/frontend/src/components/UpdateChannelsTable.tsx +++ b/frontend/src/components/UpdateChannelsTable.tsx @@ -19,8 +19,9 @@ */ import { FormattedMessage } from "react-intl"; -import { graphql, useFragment } from "react-relay/hooks"; +import { graphql, usePaginationFragment } from "react-relay/hooks"; +import type { UpdateChannelsTable_PaginationQuery } from "api/__generated__/UpdateChannelsTable_PaginationQuery.graphql"; import type { UpdateChannelsTable_UpdateChannelFragment$data, UpdateChannelsTable_UpdateChannelFragment$key, @@ -33,22 +34,33 @@ import { Link, Route } from "Navigation"; // We use graphql fields below in columns configuration /* eslint-disable relay/unused-fields */ const DEVICE_GROUPS_TABLE_FRAGMENT = graphql` - fragment UpdateChannelsTable_UpdateChannelFragment on UpdateChannel - @relay(plural: true) { - id - name - handle - targetGroups { + fragment UpdateChannelsTable_UpdateChannelFragment on RootQueryType + @refetchable(queryName: "UpdateChannelsTable_PaginationQuery") { + updateChannels(first: $first, after: $after) + @connection(key: "UpdateChannelsTable_updateChannels") { edges { node { + id name + handle + targetGroups { + edges { + node { + name + } + } + } } } } } `; -type TableRecord = UpdateChannelsTable_UpdateChannelFragment$data[0]; +type TableRecord = NonNullable< + NonNullable< + UpdateChannelsTable_UpdateChannelFragment$data["updateChannels"] + >["edges"] +>[number]["node"]; const columnHelper = createColumnHelper(); const columns = [ @@ -105,14 +117,14 @@ type Props = { }; const UpdateChannelsTable = ({ className, updateChannelsRef }: Props) => { - const updateChannels = useFragment( - DEVICE_GROUPS_TABLE_FRAGMENT, - updateChannelsRef, - ); - - return ( - - ); + const { data } = usePaginationFragment< + UpdateChannelsTable_PaginationQuery, + UpdateChannelsTable_UpdateChannelFragment$key + >(DEVICE_GROUPS_TABLE_FRAGMENT, updateChannelsRef); + + const tableData = data.updateChannels?.edges?.map((edge) => edge.node) ?? []; + + return
; }; export default UpdateChannelsTable; diff --git a/frontend/src/forms/CreateUpdateCampaign.tsx b/frontend/src/forms/CreateUpdateCampaign.tsx index ede7a490e..1dff2e7e2 100644 --- a/frontend/src/forms/CreateUpdateCampaign.tsx +++ b/frontend/src/forms/CreateUpdateCampaign.tsx @@ -47,8 +47,12 @@ const UPDATE_CAMPAIGN_OPTIONS_FRAGMENT = graphql` } } updateChannels { - id - name + edges { + node { + id + name + } + } } } `; @@ -314,7 +318,7 @@ const CreateBaseImageCollectionForm = ({ defaultMessage: "Select an Update Channel", })} - {updateChannels.map((updateChannel) => ( + {updateChannels?.edges?.map(({ node: updateChannel }) => ( diff --git a/frontend/src/pages/UpdateCampaignCreate.tsx b/frontend/src/pages/UpdateCampaignCreate.tsx index d3edd2250..98c2b0ca4 100644 --- a/frontend/src/pages/UpdateCampaignCreate.tsx +++ b/frontend/src/pages/UpdateCampaignCreate.tsx @@ -35,6 +35,7 @@ import type { UpdateCampaignCreate_getOptions_Query$data, } from "api/__generated__/UpdateCampaignCreate_getOptions_Query.graphql"; import type { UpdateCampaignCreate_createUpdateCampaign_Mutation } from "api/__generated__/UpdateCampaignCreate_createUpdateCampaign_Mutation.graphql"; + import Alert from "components/Alert"; import Button from "components/Button"; import Center from "components/Center"; @@ -53,6 +54,7 @@ const GET_CREATE_UPDATE_CAMPAIGN_OPTIONS_QUERY = graphql` } updateChannels { __typename + count } ...CreateUpdateCampaign_OptionsFragment } @@ -218,7 +220,7 @@ const UpdateCampaignWrapper = ({ if (baseImageCollections?.count === 0) { return ; } - if (updateChannels.length === 0) { + if (updateChannels?.count === 0) { return ; } diff --git a/frontend/src/pages/UpdateChannel.tsx b/frontend/src/pages/UpdateChannel.tsx index a450a8796..cd8fbe621 100644 --- a/frontend/src/pages/UpdateChannel.tsx +++ b/frontend/src/pages/UpdateChannel.tsx @@ -22,6 +22,7 @@ import { Suspense, useCallback, useEffect, useState } from "react"; import { useParams } from "react-router-dom"; import { ErrorBoundary } from "react-error-boundary"; import { + ConnectionHandler, graphql, useMutation, usePreloadedQuery, @@ -177,14 +178,13 @@ const UpdateChannelContent = ({ const root = store.getRoot(); - const updateChannels = root.getLinkedRecords("updateChannels"); - if (updateChannels) { - root.setLinkedRecords( - updateChannels.filter( - (updateChannel) => updateChannel.getDataID() !== updateChannelId, - ), - "updateChannels", - ); + const connection = ConnectionHandler.getConnection( + root, + "UpdateChannelsTable_updateChannels", + ); + + if (connection) { + ConnectionHandler.deleteNode(connection, updateChannelId); } const targetGroupIds = new Set( diff --git a/frontend/src/pages/UpdateChannels.tsx b/frontend/src/pages/UpdateChannels.tsx index b20c82362..5e2199c58 100644 --- a/frontend/src/pages/UpdateChannels.tsx +++ b/frontend/src/pages/UpdateChannels.tsx @@ -1,7 +1,7 @@ /* This file is part of Edgehog. - Copyright 2023-2024 SECO Mind Srl + Copyright 2023-2025 SECO Mind Srl Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import { graphql, usePreloadedQuery, useQueryLoader } from "react-relay/hooks"; import type { PreloadedQuery } from "react-relay/hooks"; import type { UpdateChannels_getUpdateChannels_Query } from "api/__generated__/UpdateChannels_getUpdateChannels_Query.graphql"; + import Button from "components/Button"; import Center from "components/Center"; import UpdateChannelsTable from "components/UpdateChannelsTable"; @@ -33,10 +34,8 @@ import Spinner from "components/Spinner"; import { Link, Route } from "Navigation"; const GET_UPDATE_CHANNELS_QUERY = graphql` - query UpdateChannels_getUpdateChannels_Query { - updateChannels { - ...UpdateChannelsTable_UpdateChannelFragment - } + query UpdateChannels_getUpdateChannels_Query($first: Int, $after: String) { + ...UpdateChannelsTable_UpdateChannelFragment } `; @@ -47,7 +46,7 @@ type UpdateChannelsContentProps = { const UpdateChannelsContent = ({ getUpdateChannelsQuery, }: UpdateChannelsContentProps) => { - const { updateChannels } = usePreloadedQuery( + const updateChannels = usePreloadedQuery( GET_UPDATE_CHANNELS_QUERY, getUpdateChannelsQuery, ); @@ -83,7 +82,11 @@ const UpdateChannelsPage = () => { ); const fetchUpdateChannels = useCallback( - () => getUpdateChannels({}, { fetchPolicy: "store-and-network" }), + () => + getUpdateChannels( + { first: 10_000 }, + { fetchPolicy: "store-and-network" }, + ), [getUpdateChannels], );