Check snapshot type and id from url

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-08-28 17:57:12 +02:00
parent 7d80a7d5f4
commit da4553beb2
16 changed files with 227 additions and 45 deletions

View File

@@ -32,7 +32,7 @@ export function PageError({ resetErrorBoundary, error: propsError }: Props) {
}
}, [location, resetErrorBoundary]);
if (!error) {
if (!error || (error && error.toString().includes("PAGE_NOT_FOUND"))) {
return (
<div className={classNames.wrapper}>
<h1 className={classNames.title}>

View File

@@ -1,7 +1,9 @@
import { IconClock } from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { useLazyLoadQuery, graphql } from "react-relay";
import { useLocation } from "react-router";
import type { SnapshotBannerQuery } from "./__generated__/SnapshotBannerQuery.graphql";
import { getSnapshotTypeUrlPath } from "@probo/helpers";
const snapshotQuery = graphql`
query SnapshotBannerQuery($snapshotId: ID!) {
@@ -9,18 +11,25 @@ const snapshotQuery = graphql`
... on Snapshot {
id
name
type
createdAt
}
}
}
`;
const isSnapshotTypeValidForUrl = (type: string, pathname: string) => {
const urlPath = getSnapshotTypeUrlPath(type);
return pathname.includes(urlPath);
};
type Props = {
snapshotId: string;
};
export function SnapshotBanner({ snapshotId }: Props) {
const { __, dateFormat } = useTranslate();
const location = useLocation();
const data = useLazyLoadQuery<SnapshotBannerQuery>(snapshotQuery, { snapshotId });
const snapshot = data.node;
@@ -29,6 +38,10 @@ export function SnapshotBanner({ snapshotId }: Props) {
return null;
}
if (snapshot.type && !isSnapshotTypeValidForUrl(snapshot.type, location.pathname)) {
throw new Error("PAGE_NOT_FOUND");
}
return (
<div className="bg-warning rounded-lg p-4 flex items-center gap-3">
<IconClock className="text-warning-600 flex-shrink-0" size={20} />

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<a11c48ca33ac17dd7eaf6eeca4a0c20d>>
* @generated SignedSource<<3c8b528580116deec511c979e209cfc3>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,6 +9,7 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "RISKS" | "VENDORS";
export type SnapshotBannerQuery$variables = {
snapshotId: string;
};
@@ -17,6 +18,7 @@ export type SnapshotBannerQuery$data = {
readonly createdAt?: any;
readonly id?: string;
readonly name?: string;
readonly type?: SnapshotsType;
};
};
export type SnapshotBannerQuery = {
@@ -54,6 +56,13 @@ v3 = {
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "type",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
@@ -80,7 +89,8 @@ return {
"selections": [
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/)
(v4/*: any*/),
(v5/*: any*/)
],
"type": "Snapshot",
"abstractKey": null
@@ -118,7 +128,8 @@ return {
"kind": "InlineFragment",
"selections": [
(v3/*: any*/),
(v4/*: any*/)
(v4/*: any*/),
(v5/*: any*/)
],
"type": "Snapshot",
"abstractKey": null
@@ -129,16 +140,16 @@ return {
]
},
"params": {
"cacheID": "8f21371ececf96444bb6b00e52783573",
"cacheID": "7e026c7c030cd116b4794260934c394f",
"id": null,
"metadata": {},
"name": "SnapshotBannerQuery",
"operationKind": "query",
"text": "query SnapshotBannerQuery(\n $snapshotId: ID!\n) {\n node(id: $snapshotId) {\n __typename\n ... on Snapshot {\n id\n name\n createdAt\n }\n id\n }\n}\n"
"text": "query SnapshotBannerQuery(\n $snapshotId: ID!\n) {\n node(id: $snapshotId) {\n __typename\n ... on Snapshot {\n id\n name\n type\n createdAt\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "1602d5b6c0ae4a3122998e4d3419af05";
(node as any).hash = "e50a4bb5133d8e918b8b2b9d2a42f1d1";
export default node;