Make sure page reloads when version is selected

Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
Émile Ré
2026-01-27 16:04:01 +04:00
parent 7c721e5ff7
commit 147ea0f08f
5 changed files with 177 additions and 23 deletions

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<fbb0d6a61d0aa33c1c114772d54efd2a>> * @generated SignedSource<<369fa1f3218710cdc3fedb7e161f4e13>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -12,10 +12,19 @@ import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime"; import { FragmentRefs } from "relay-runtime";
export type DocumentVersionsDropdownMenuQuery$variables = { export type DocumentVersionsDropdownMenuQuery$variables = {
documentId: string; documentId: string;
versionId: string;
versionSpecified: boolean;
}; };
export type DocumentVersionsDropdownMenuQuery$data = { export type DocumentVersionsDropdownMenuQuery$data = {
readonly document: { readonly document: {
readonly __typename: "Document"; readonly __typename: "Document";
readonly lastVersion?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
};
}>;
};
readonly versions: { readonly versions: {
readonly edges: ReadonlyArray<{ readonly edges: ReadonlyArray<{
readonly node: { readonly node: {
@@ -29,6 +38,14 @@ export type DocumentVersionsDropdownMenuQuery$data = {
// value in case none of the concrete values match. // value in case none of the concrete values match.
readonly __typename: "%other"; readonly __typename: "%other";
}; };
readonly version?: {
readonly __typename: "DocumentVersion";
readonly id: string;
} | {
// This will never be '%other', but we need some
// value in case none of the concrete values match.
readonly __typename: "%other";
};
}; };
export type DocumentVersionsDropdownMenuQuery = { export type DocumentVersionsDropdownMenuQuery = {
response: DocumentVersionsDropdownMenuQuery$data; response: DocumentVersionsDropdownMenuQuery$data;
@@ -41,6 +58,16 @@ var v0 = [
"defaultValue": null, "defaultValue": null,
"kind": "LocalArgument", "kind": "LocalArgument",
"name": "documentId" "name": "documentId"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "versionId"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "versionSpecified"
} }
], ],
v1 = [ v1 = [
@@ -70,7 +97,70 @@ v4 = {
"kind": "ScalarField", "kind": "ScalarField",
"name": "id", "name": "id",
"storageKey": null "storageKey": null
}; },
v5 = [
(v4/*: any*/)
],
v6 = {
"condition": "versionSpecified",
"kind": "Condition",
"passingValue": false,
"selections": [
{
"alias": "lastVersion",
"args": [
{
"kind": "Literal",
"name": "first",
"value": 1
},
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
}
],
"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": (v5/*: any*/),
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "versions(first:1,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
}
]
},
v7 = [
{
"kind": "Variable",
"name": "id",
"variableName": "versionId"
}
];
return { return {
"fragment": { "fragment": {
"argumentDefinitions": (v0/*: any*/), "argumentDefinitions": (v0/*: any*/),
@@ -128,13 +218,39 @@ return {
} }
], ],
"storageKey": "versions(first:20)" "storageKey": "versions(first:20)"
} },
(v6/*: any*/)
], ],
"type": "Document", "type": "Document",
"abstractKey": null "abstractKey": null
} }
], ],
"storageKey": null "storageKey": null
},
{
"condition": "versionSpecified",
"kind": "Condition",
"passingValue": true,
"selections": [
{
"alias": "version",
"args": (v7/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": (v5/*: any*/),
"type": "DocumentVersion",
"abstractKey": null
}
],
"storageKey": null
}
]
} }
], ],
"type": "Query", "type": "Query",
@@ -219,7 +335,8 @@ return {
} }
], ],
"storageKey": "versions(first:20)" "storageKey": "versions(first:20)"
} },
(v6/*: any*/)
], ],
"type": "Document", "type": "Document",
"abstractKey": null "abstractKey": null
@@ -227,20 +344,40 @@ return {
(v4/*: any*/) (v4/*: any*/)
], ],
"storageKey": null "storageKey": null
},
{
"condition": "versionSpecified",
"kind": "Condition",
"passingValue": true,
"selections": [
{
"alias": "version",
"args": (v7/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v4/*: any*/)
],
"storageKey": null
}
]
} }
] ]
}, },
"params": { "params": {
"cacheID": "914f2c11640879dfb202ba668fb0bff0", "cacheID": "f940f62593d1a96d898b128a11e8cf3b",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "DocumentVersionsDropdownMenuQuery", "name": "DocumentVersionsDropdownMenuQuery",
"operationKind": "query", "operationKind": "query",
"text": "query DocumentVersionsDropdownMenuQuery(\n $documentId: ID!\n) {\n document: node(id: $documentId) {\n __typename\n ... on Document {\n versions(first: 20) {\n edges {\n node {\n id\n ...DocumentVersionsDropdownItemFragment\n }\n }\n }\n }\n id\n }\n}\n\nfragment DocumentVersionsDropdownItemFragment on DocumentVersion {\n id\n version\n status\n publishedAt\n updatedAt\n}\n" "text": "query DocumentVersionsDropdownMenuQuery(\n $documentId: ID!\n $versionId: ID!\n $versionSpecified: Boolean!\n) {\n document: node(id: $documentId) {\n __typename\n ... on Document {\n versions(first: 20) {\n edges {\n node {\n id\n ...DocumentVersionsDropdownItemFragment\n }\n }\n }\n lastVersion: versions(first: 1, orderBy: {field: CREATED_AT, direction: DESC}) @skip(if: $versionSpecified) {\n edges {\n node {\n id\n }\n }\n }\n }\n id\n }\n version: node(id: $versionId) @include(if: $versionSpecified) {\n __typename\n ... on DocumentVersion {\n id\n }\n id\n }\n}\n\nfragment DocumentVersionsDropdownItemFragment on DocumentVersion {\n id\n version\n status\n publishedAt\n updatedAt\n}\n"
} }
}; };
})(); })();
(node as any).hash = "4cc270e68cee032d619dc7a348715d83"; (node as any).hash = "33baa920362db3aef46644b80477d78a";
export default node; export default node;

View File

@@ -149,7 +149,7 @@ export function DocumentLayout(props: { queryRef: PreloadedQuery<DocumentLayoutQ
{__("Publish")} {__("Publish")}
</Button> </Button>
)} )}
<DocumentVersionsDropdown currentVersionId={currentVersion.id} /> <DocumentVersionsDropdown />
<DocumentActionsDropdownn documentFragmentRef={document} versionFragmentRef={currentVersion} /> <DocumentActionsDropdownn documentFragmentRef={document} versionFragmentRef={currentVersion} />
</div> </div>
</div> </div>

View File

@@ -31,9 +31,11 @@ function DocumentLayoutQueryLoader() {
} }
export default function DocumentLayoutLoader() { export default function DocumentLayoutLoader() {
const { documentId, versionId } = useParams();
return ( return (
<CoreRelayProvider> <CoreRelayProvider>
<Suspense fallback={<PageSkeleton />}> <Suspense key={`${documentId}-${versionId}`} fallback={<PageSkeleton />}>
<DocumentLayoutQueryLoader /> <DocumentLayoutQueryLoader />
</Suspense> </Suspense>
</CoreRelayProvider> </CoreRelayProvider>

View File

@@ -8,12 +8,8 @@ import type { DocumentVersionsDropdownMenuQuery } from "#/__generated__/core/Doc
import { DocumentVersionsDropdownMenu, documentVersionsDropdownMenuQuery } from "./DocumentVersionsDropdownMenu"; import { DocumentVersionsDropdownMenu, documentVersionsDropdownMenuQuery } from "./DocumentVersionsDropdownMenu";
export function DocumentVersionsDropdown(props: { export function DocumentVersionsDropdown() {
currentVersionId: string; const { documentId, versionId } = useParams();
}) {
const { currentVersionId } = props;
const { documentId } = useParams();
if (!documentId) { if (!documentId) {
throw new Error(":documentId missing in route params"); throw new Error(":documentId missing in route params");
} }
@@ -23,7 +19,7 @@ export function DocumentVersionsDropdown(props: {
return ( return (
<Dropdown <Dropdown
onOpenChange={open => open && !queryRef && loadQuery({ documentId })} onOpenChange={open => open && !queryRef && loadQuery({ documentId, versionId: versionId ?? "", versionSpecified: !!versionId })}
toggle={( toggle={(
<Button icon={IconClock} variant="secondary"> <Button icon={IconClock} variant="secondary">
{__("Version history")} {__("Version history")}
@@ -33,7 +29,9 @@ export function DocumentVersionsDropdown(props: {
> >
<Suspense> <Suspense>
{queryRef {queryRef
&& <DocumentVersionsDropdownMenu currentVersionId={currentVersionId} queryRef={queryRef} />} && (
<DocumentVersionsDropdownMenu queryRef={queryRef} />
)}
</Suspense> </Suspense>
</Dropdown> </Dropdown>
); );

View File

@@ -6,7 +6,7 @@ import type { DocumentVersionsDropdownMenuQuery } from "#/__generated__/core/Doc
import { DocumentVersionsDropdownItem } from "./DocumentVersionsDropdownItem"; import { DocumentVersionsDropdownItem } from "./DocumentVersionsDropdownItem";
export const documentVersionsDropdownMenuQuery = graphql` export const documentVersionsDropdownMenuQuery = graphql`
query DocumentVersionsDropdownMenuQuery($documentId: ID!) { query DocumentVersionsDropdownMenuQuery($documentId: ID! $versionId: ID! $versionSpecified: Boolean!) {
document: node(id: $documentId) { document: node(id: $documentId) {
__typename __typename
... on Document { ... on Document {
@@ -18,32 +18,49 @@ export const documentVersionsDropdownMenuQuery = graphql`
} }
} }
} }
# We use this on /documents/:documentId
lastVersion: versions(first: 1 orderBy: { field: CREATED_AT, direction: DESC }) @skip(if: $versionSpecified) {
edges {
node {
id
}
}
}
}
}
# We use this on /documents/:documentId/versions/:versionId
version: node(id: $versionId) @include(if: $versionSpecified) {
__typename
... on DocumentVersion {
id
} }
} }
} }
`; `;
export function DocumentVersionsDropdownMenu(props: { export function DocumentVersionsDropdownMenu(props: {
currentVersionId: string;
queryRef: PreloadedQuery<DocumentVersionsDropdownMenuQuery>; queryRef: PreloadedQuery<DocumentVersionsDropdownMenuQuery>;
}) { }) {
const { currentVersionId, queryRef } = props; const { queryRef } = props;
const { document } = usePreloadedQuery<DocumentVersionsDropdownMenuQuery>( const { document, version } = usePreloadedQuery<DocumentVersionsDropdownMenuQuery>(
documentVersionsDropdownMenuQuery, documentVersionsDropdownMenuQuery,
queryRef, queryRef,
); );
if (document.__typename !== "Document") { if (document.__typename !== "Document" || (version && version.__typename !== "DocumentVersion")) {
throw new Error("invalid type for node"); throw new Error("invalid type for node");
} }
const lastVersion = document.lastVersion?.edges[0].node;
const currentVersion = lastVersion ?? version as NonNullable<typeof lastVersion | typeof version>;
return ( return (
<> <>
{document.versions.edges.map(({ node: version }) => ( {document.versions.edges.map(({ node: version }) => (
<DocumentVersionsDropdownItem <DocumentVersionsDropdownItem
key={version.id} key={version.id}
fragmentRef={version} fragmentRef={version}
active={version.id === currentVersionId} active={version.id === currentVersion.id}
/> />
))} ))}
</> </>