From 3232bdc6ba0ec4bd8333aef43a7e02d78ae13945 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 17 Jun 2025 17:23:00 +0200 Subject: [PATCH] Add pagination on documents Signed-off-by: Bryan Frimin --- .../DocumentGraphListQuery.graphql.ts | 38 +- .../organizations/documents/DocumentsPage.tsx | 38 +- .../DocumentsListQuery.graphql.ts | 457 ++++++++++++++++++ .../DocumentsPageListFragment.graphql.ts | 113 ++++- 4 files changed, 607 insertions(+), 39 deletions(-) create mode 100644 apps/console/src/pages/organizations/documents/__generated__/DocumentsListQuery.graphql.ts diff --git a/apps/console/src/hooks/graph/__generated__/DocumentGraphListQuery.graphql.ts b/apps/console/src/hooks/graph/__generated__/DocumentGraphListQuery.graphql.ts index 5f24903f8..cbdcc9af0 100644 --- a/apps/console/src/hooks/graph/__generated__/DocumentGraphListQuery.graphql.ts +++ b/apps/console/src/hooks/graph/__generated__/DocumentGraphListQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<3318d21bcfef8523d95b650c01bc7973>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -57,7 +57,7 @@ v4 = [ { "kind": "Literal", "name": "first", - "value": 100 + "value": 50 } ]; return { @@ -219,7 +219,13 @@ return { }, { "alias": null, - "args": (v4/*: any*/), + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100 + } + ], "concreteType": "DocumentVersionSignatureConnection", "kind": "LinkedField", "name": "signatures", @@ -302,6 +308,20 @@ return { "kind": "ScalarField", "name": "hasNextPage", "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasPreviousPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "startCursor", + "storageKey": null } ], "storageKey": null @@ -319,14 +339,16 @@ return { ] } ], - "storageKey": "documents(first:100)" + "storageKey": "documents(first:50)" }, { "alias": null, "args": (v4/*: any*/), - "filters": null, + "filters": [ + "orderBy" + ], "handle": "connection", - "key": "DocumentsPageFragment_documents", + "key": "DocumentsListQuery_documents", "kind": "LinkedHandle", "name": "documents" } @@ -340,12 +362,12 @@ return { ] }, "params": { - "cacheID": "edc04f86b008ac09088a88a6b7918cbe", + "cacheID": "cefd94e1cb5245f2d9852b098653ce53", "id": null, "metadata": {}, "name": "DocumentGraphListQuery", "operationKind": "query", - "text": "query DocumentGraphListQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ...DocumentsPageListFragment\n }\n}\n\nfragment DocumentsPageListFragment on Organization {\n documents(first: 100) {\n edges {\n node {\n id\n ...DocumentsPageRowFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment DocumentsPageRowFragment on Document {\n id\n title\n description\n documentType\n updatedAt\n owner {\n id\n fullName\n }\n versions(first: 1) {\n edges {\n node {\n id\n status\n signatures(first: 100) {\n edges {\n node {\n id\n state\n }\n }\n }\n }\n }\n }\n}\n" + "text": "query DocumentGraphListQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ...DocumentsPageListFragment\n }\n}\n\nfragment DocumentsPageListFragment on Organization {\n documents(first: 50) {\n edges {\n node {\n id\n ...DocumentsPageRowFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment DocumentsPageRowFragment on Document {\n id\n title\n description\n documentType\n updatedAt\n owner {\n id\n fullName\n }\n versions(first: 1) {\n edges {\n node {\n id\n status\n signatures(first: 100) {\n edges {\n node {\n id\n state\n }\n }\n }\n }\n }\n }\n}\n" } }; })(); diff --git a/apps/console/src/pages/organizations/documents/DocumentsPage.tsx b/apps/console/src/pages/organizations/documents/DocumentsPage.tsx index ff4e72a34..faca6d2c8 100644 --- a/apps/console/src/pages/organizations/documents/DocumentsPage.tsx +++ b/apps/console/src/pages/organizations/documents/DocumentsPage.tsx @@ -19,6 +19,7 @@ import { } from "@probo/ui"; import { useFragment, + usePaginationFragment, usePreloadedQuery, type PreloadedQuery, } from "react-relay"; @@ -34,10 +35,25 @@ import { usePageTitle } from "@probo/hooks"; import { sprintf, getDocumentTypeLabel } from "@probo/helpers"; import { CreateDocumentDialog } from "./dialogs/CreateDocumentDialog"; import type { DocumentsPageRowFragment$key } from "./__generated__/DocumentsPageRowFragment.graphql"; +import { SortableTable } from "/components/SortableTable"; const documentsFragment = graphql` - fragment DocumentsPageListFragment on Organization { - documents(first: 100) @connection(key: "DocumentsPageFragment_documents") { + fragment DocumentsPageListFragment on Organization + @refetchable(queryName: "DocumentsListQuery") + @argumentDefinitions( + first: { type: "Int", defaultValue: 50 } + order: { type: "DocumentOrder", defaultValue: null } + after: { type: "CursorKey", defaultValue: null } + before: { type: "CursorKey", defaultValue: null } + last: { type: "Int", defaultValue: null } + ) { + documents( + first: $first + after: $after + last: $last + before: $before + orderBy: $order + ) @connection(key: "DocumentsListQuery_documents") { __id edges { node { @@ -60,13 +76,13 @@ export default function DocumentsPage(props: Props) { documentsQuery, props.queryRef ).organization; - const data = useFragment( + const pagination = usePaginationFragment( documentsFragment, - organization + organization as DocumentsPageListFragment$key ); - const documents = data.documents.edges.map((edge) => edge.node); - const connectionId = data.documents.__id; + const documents = pagination.data.documents.edges.map((edge) => edge.node); + const connectionId = pagination.data.documents.__id; const [sendSigningNotifications] = useSendSigningNotificationsMutation(); usePageTitle(__("Documents")); @@ -86,7 +102,7 @@ export default function DocumentsPage(props: Props) { description={__("Manage your organization's documents")} >
-
- + @@ -121,7 +137,7 @@ export default function DocumentsPage(props: Props) { /> ))} -
{__("Name")}
+ ); } @@ -218,9 +234,7 @@ function DocumentRow({ {isDraft ? __("Draft") : __("Published")} - - {getDocumentTypeLabel(__, document.documentType)} - + {getDocumentTypeLabel(__, document.documentType)}
diff --git a/apps/console/src/pages/organizations/documents/__generated__/DocumentsListQuery.graphql.ts b/apps/console/src/pages/organizations/documents/__generated__/DocumentsListQuery.graphql.ts new file mode 100644 index 000000000..666282df7 --- /dev/null +++ b/apps/console/src/pages/organizations/documents/__generated__/DocumentsListQuery.graphql.ts @@ -0,0 +1,457 @@ +/** + * @generated SignedSource<<7ebb9cf96131d4b0b2670e63ab60e0d6>> + * @lightSyntaxTransform + * @nogrep + */ + +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck + +import { ConcreteRequest } from 'relay-runtime'; +import { FragmentRefs } from "relay-runtime"; +export type DocumentOrderField = "CREATED_AT" | "TITLE"; +export type OrderDirection = "ASC" | "DESC"; +export type DocumentOrder = { + direction: OrderDirection; + field: DocumentOrderField; +}; +export type DocumentsListQuery$variables = { + after?: any | null | undefined; + before?: any | null | undefined; + first?: number | null | undefined; + id: string; + last?: number | null | undefined; + order?: DocumentOrder | null | undefined; +}; +export type DocumentsListQuery$data = { + readonly node: { + readonly " $fragmentSpreads": FragmentRefs<"DocumentsPageListFragment">; + }; +}; +export type DocumentsListQuery = { + response: DocumentsListQuery$data; + variables: DocumentsListQuery$variables; +}; + +const node: ConcreteRequest = (function(){ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "after" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "before" +}, +v2 = { + "defaultValue": 50, + "kind": "LocalArgument", + "name": "first" +}, +v3 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "id" +}, +v4 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "last" +}, +v5 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "order" +}, +v6 = [ + { + "kind": "Variable", + "name": "id", + "variableName": "id" + } +], +v7 = { + "kind": "Variable", + "name": "after", + "variableName": "after" +}, +v8 = { + "kind": "Variable", + "name": "before", + "variableName": "before" +}, +v9 = { + "kind": "Variable", + "name": "first", + "variableName": "first" +}, +v10 = { + "kind": "Variable", + "name": "last", + "variableName": "last" +}, +v11 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null +}, +v12 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}, +v13 = [ + (v7/*: any*/), + (v8/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + { + "kind": "Variable", + "name": "orderBy", + "variableName": "order" + } +]; +return { + "fragment": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), + (v3/*: any*/), + (v4/*: any*/), + (v5/*: any*/) + ], + "kind": "Fragment", + "metadata": null, + "name": "DocumentsListQuery", + "selections": [ + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + { + "args": [ + (v7/*: any*/), + (v8/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + { + "kind": "Variable", + "name": "order", + "variableName": "order" + } + ], + "kind": "FragmentSpread", + "name": "DocumentsPageListFragment" + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), + (v4/*: any*/), + (v5/*: any*/), + (v3/*: any*/) + ], + "kind": "Operation", + "name": "DocumentsListQuery", + "selections": [ + { + "alias": null, + "args": (v6/*: any*/), + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v11/*: any*/), + (v12/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": (v13/*: any*/), + "concreteType": "DocumentConnection", + "kind": "LinkedField", + "name": "documents", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "Document", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v12/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "title", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "description", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "documentType", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "updatedAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "People", + "kind": "LinkedField", + "name": "owner", + "plural": false, + "selections": [ + (v12/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "fullName", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 1 + } + ], + "concreteType": "DocumentVersionConnection", + "kind": "LinkedField", + "name": "versions", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersionEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersion", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v12/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "status", + "storageKey": null + }, + { + "alias": null, + "args": [ + { + "kind": "Literal", + "name": "first", + "value": 100 + } + ], + "concreteType": "DocumentVersionSignatureConnection", + "kind": "LinkedField", + "name": "signatures", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersionSignatureEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "DocumentVersionSignature", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v12/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "state", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "signatures(first:100)" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "versions(first:1)" + }, + (v11/*: any*/) + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "PageInfo", + "kind": "LinkedField", + "name": "pageInfo", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "endCursor", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasNextPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasPreviousPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "startCursor", + "storageKey": null + } + ], + "storageKey": null + }, + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__id", + "storageKey": null + } + ] + } + ], + "storageKey": null + }, + { + "alias": null, + "args": (v13/*: any*/), + "filters": [ + "orderBy" + ], + "handle": "connection", + "key": "DocumentsListQuery_documents", + "kind": "LinkedHandle", + "name": "documents" + } + ], + "type": "Organization", + "abstractKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "3da7d3804fefec2e77c96b6c33c2cefc", + "id": null, + "metadata": {}, + "name": "DocumentsListQuery", + "operationKind": "query", + "text": "query DocumentsListQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 50\n $last: Int = null\n $order: DocumentOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...DocumentsPageListFragment_16fISc\n id\n }\n}\n\nfragment DocumentsPageListFragment_16fISc on Organization {\n documents(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n ...DocumentsPageRowFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment DocumentsPageRowFragment on Document {\n id\n title\n description\n documentType\n updatedAt\n owner {\n id\n fullName\n }\n versions(first: 1) {\n edges {\n node {\n id\n status\n signatures(first: 100) {\n edges {\n node {\n id\n state\n }\n }\n }\n }\n }\n }\n}\n" + } +}; +})(); + +(node as any).hash = "dc234a4cafbe4da1c1ff4943ff75c32a"; + +export default node; diff --git a/apps/console/src/pages/organizations/documents/__generated__/DocumentsPageListFragment.graphql.ts b/apps/console/src/pages/organizations/documents/__generated__/DocumentsPageListFragment.graphql.ts index b9e2372ea..99da9ad4c 100644 --- a/apps/console/src/pages/organizations/documents/__generated__/DocumentsPageListFragment.graphql.ts +++ b/apps/console/src/pages/organizations/documents/__generated__/DocumentsPageListFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<5d1d855cd444dbaa6fc92493bc333dd4>> + * @generated SignedSource<<1082bf950eb1233b6c85c02d89dcd260>> * @lightSyntaxTransform * @nogrep */ @@ -20,6 +20,7 @@ export type DocumentsPageListFragment$data = { }; }>; }; + readonly id: string; readonly " $fragmentType": "DocumentsPageListFragment"; }; export type DocumentsPageListFragment$key = { @@ -27,29 +28,93 @@ export type DocumentsPageListFragment$key = { readonly " $fragmentSpreads": FragmentRefs<"DocumentsPageListFragment">; }; -const node: ReaderFragment = { - "argumentDefinitions": [], +import DocumentsListQuery_graphql from './DocumentsListQuery.graphql'; + +const node: ReaderFragment = (function(){ +var v0 = [ + "documents" +], +v1 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "argumentDefinitions": [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "after" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "before" + }, + { + "defaultValue": 50, + "kind": "LocalArgument", + "name": "first" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "last" + }, + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "order" + } + ], "kind": "Fragment", "metadata": { "connection": [ { "count": null, "cursor": null, - "direction": "forward", - "path": [ - "documents" - ] + "direction": "bidirectional", + "path": (v0/*: any*/) } - ] + ], + "refetch": { + "connection": { + "forward": { + "count": "first", + "cursor": "after" + }, + "backward": { + "count": "last", + "cursor": "before" + }, + "path": (v0/*: any*/) + }, + "fragmentPathInResult": [ + "node" + ], + "operation": DocumentsListQuery_graphql, + "identifierInfo": { + "identifierField": "id", + "identifierQueryVariableName": "id" + } + } }, "name": "DocumentsPageListFragment", "selections": [ { "alias": "documents", - "args": null, + "args": [ + { + "kind": "Variable", + "name": "orderBy", + "variableName": "order" + } + ], "concreteType": "DocumentConnection", "kind": "LinkedField", - "name": "__DocumentsPageFragment_documents_connection", + "name": "__DocumentsListQuery_documents_connection", "plural": false, "selections": [ { @@ -68,13 +133,7 @@ const node: ReaderFragment = { "name": "node", "plural": false, "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null - }, + (v1/*: any*/), { "args": null, "kind": "FragmentSpread", @@ -121,6 +180,20 @@ const node: ReaderFragment = { "kind": "ScalarField", "name": "hasNextPage", "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "hasPreviousPage", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "startCursor", + "storageKey": null } ], "storageKey": null @@ -139,12 +212,14 @@ const node: ReaderFragment = { } ], "storageKey": null - } + }, + (v1/*: any*/) ], "type": "Organization", "abstractKey": null }; +})(); -(node as any).hash = "f6098fe2da00c369d0386e3854cd894b"; +(node as any).hash = "dc234a4cafbe4da1c1ff4943ff75c32a"; export default node;