From 2e4ad563cec991f334e048e778df3193020a09ae Mon Sep 17 00:00:00 2001 From: Karolis Date: Fri, 15 May 2026 01:29:25 -0400 Subject: [PATCH 01/10] graphql poc apollo: dashboard variant route + apollo client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a /dashboard-graphql variant that fetches all dashboard data via a single GraphQL query through @apollo/client. The existing dashboard at / is untouched. - codegen.ts with client-preset, reading schema.graphql - scripts/sync-graphql-sdl.mjs syncs SDL into a TS constant for the mock layer so the loader config is bundler-agnostic - MSW handler intercepts POST /graphql with @graphql-tools/mock when NEXT_PUBLIC_MOCK_GRAPHQL=true; toggle is independent of NEXT_PUBLIC_MOCK_API - ApolloProvider sits next to the Redux Provider in _app.tsx; auth link reads the redux token and applies addCommonHeaders, matching RTK Query - Paired with fidesplus graphql-poc-be@104cba76c Local PoC branch — do not push. --- POC-NOTES.md | 68 + clients/admin-ui/codegen.ts | 32 + clients/admin-ui/package.json | 10 +- clients/admin-ui/schema.graphql | 177 + clients/admin-ui/scripts/sync-graphql-sdl.mjs | 24 + .../__generated__/graphql/fragment-masking.ts | 87 + .../admin-ui/src/__generated__/graphql/gql.ts | 46 + .../src/__generated__/graphql/graphql.ts | 241 ++ .../src/__generated__/graphql/index.ts | 2 + .../DashboardGraphqlProvider.tsx | 13 + .../DashboardGraphqlView.tsx | 200 ++ .../dashboard-graphql/apolloClient.ts | 35 + .../dashboard-graphql/dashboard.graphql | 98 + .../dashboard-graphql/schema-string.ts | 5 + .../src/mocks/dashboard-graphql/handlers.ts | 125 + clients/admin-ui/src/mocks/handlers.ts | 27 +- clients/admin-ui/src/pages/_app.tsx | 2 +- .../admin-ui/src/pages/dashboard-graphql.tsx | 15 + clients/package-lock.json | 3121 ++++++++++++++++- 19 files changed, 4162 insertions(+), 166 deletions(-) create mode 100644 POC-NOTES.md create mode 100644 clients/admin-ui/codegen.ts create mode 100644 clients/admin-ui/schema.graphql create mode 100644 clients/admin-ui/scripts/sync-graphql-sdl.mjs create mode 100644 clients/admin-ui/src/__generated__/graphql/fragment-masking.ts create mode 100644 clients/admin-ui/src/__generated__/graphql/gql.ts create mode 100644 clients/admin-ui/src/__generated__/graphql/graphql.ts create mode 100644 clients/admin-ui/src/__generated__/graphql/index.ts create mode 100644 clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlProvider.tsx create mode 100644 clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlView.tsx create mode 100644 clients/admin-ui/src/features/dashboard-graphql/apolloClient.ts create mode 100644 clients/admin-ui/src/features/dashboard-graphql/dashboard.graphql create mode 100644 clients/admin-ui/src/features/dashboard-graphql/schema-string.ts create mode 100644 clients/admin-ui/src/mocks/dashboard-graphql/handlers.ts create mode 100644 clients/admin-ui/src/pages/dashboard-graphql.tsx diff --git a/POC-NOTES.md b/POC-NOTES.md new file mode 100644 index 00000000000..5f20570d3e7 --- /dev/null +++ b/POC-NOTES.md @@ -0,0 +1,68 @@ +# GraphQL PoC — Frontend (Apollo) notes — `graphql-poc-apollo` + +Paired BE branch: `graphql-poc-be` in **fidesplus** at commit `104cba76c`. +Sibling FE branch (urql): `graphql-poc-urql` in fides. + +The dashboard PoC variant route lives at `/dashboard-graphql`. The existing dashboard at `/` is untouched — both render against their respective data layers so the team can compare them side by side without an entire app rewrite. + +## Try it locally + +```bash +# With mocks (no BE needed, schema-driven via @graphql-tools/mock): +NEXT_PUBLIC_MOCK_GRAPHQL=true npm run dev -w admin-ui +# or: cd clients/admin-ui && npm run dev:mock-graphql + +# Against the real BE (run the fidesplus graphql-poc-be branch): +npm run dev -w admin-ui # the env var stays off + +open http://localhost:3000/dashboard-graphql +``` + +After a schema change: + +```bash +# 1. In fidesplus: +nox -s graphql_emit_schema # writes ../fides/clients/admin-ui/schema.graphql + +# 2. In admin-ui: +npm run graphql:generate # codegen + sync schema-string.ts +``` + +## Comparison metrics (Apollo) + +> The numbers below count only what was written by hand to author + consume a single typed query. Generated code is excluded. + +- **FE lines of code per query (Apollo)** + - `dashboard.graphql` query document: **98 lines** (would be the same on either stack — it's the SDL contract). + - Provider + Apollo client + auth link: `DashboardGraphqlProvider.tsx` 13 + `apolloClient.ts` 35 = **48 lines**. + - Hook usage in the view: 1 line (`useQuery(DashboardOverviewDocument)`). + - Total non-render plumbing to ship one typed query: **~50 lines** (provider + client + auth) + 1 hook call. + +- **Bundle size delta**: Apollo Client + graphql add **~50 KB gzipped** to the route bundle compared to a Redux-only baseline. Captured via `npm run analyze:browser` and inspecting the new `/dashboard-graphql` route — measured incrementally over the same baseline used for Variant B. + +- **Setup time** (excluding the shared BE work on `graphql-poc-be`): **~2 hours**. Most of it was finding the right way to use the `client-preset` documents with `useQuery` — `gql()` template-literal matching is brittle, importing the generated `*Document` is the reliable path. + +## Rough edges + +- The `client-preset` `gql()` template-literal type only resolves when the inline template-literal whitespace matches the source `.graphql` document byte-for-byte. Switched to `import { DashboardOverviewDocument } from "~/__generated__/graphql/graphql"` to sidestep this. The docs don't call this out. +- Mocking with `@graphql-tools/mock` requires the SDL as a runtime string. There's no first-class "import .graphql as string" path that survives both Turbopack (`next dev`) and webpack (`next build`), so a small `scripts/sync-graphql-sdl.mjs` step writes `schema-string.ts` from `schema.graphql` whenever codegen runs. Adds one extra step to the pipeline but keeps the loader config untouched. +- Apollo's `setContext` link runs once per operation, so reading the redux token there is the right shape. Importing the store at module top would create a circular dependency with `_app.tsx`; the apollo client lazy-imports the store instead. +- `process.env.NEXT_PUBLIC_FIDESCTL_API` is empty by default in local dev (Next rewrites proxy `/api/v1/...`), so the Apollo `httpLink` URI resolves to `/graphql` which the Next rewrite layer happily forwards in dev and MSW intercepts in mock mode. Good — no extra config needed. + +## What ships in this branch + +- `clients/admin-ui/schema.graphql` — emitted by the fidesplus PoC; committed here so codegen and tooling work without a live fidesplus checkout. +- `clients/admin-ui/codegen.ts` — `client-preset` config. +- `clients/admin-ui/scripts/sync-graphql-sdl.mjs` — SDL → TS-constant emitter. +- `clients/admin-ui/src/__generated__/graphql/` — generated, committed for review reproducibility. +- `clients/admin-ui/src/features/dashboard-graphql/` — provider, client, query, view, SDL string. +- `clients/admin-ui/src/mocks/dashboard-graphql/handlers.ts` — `@graphql-tools/mock`-driven MSW handler. +- `clients/admin-ui/src/pages/dashboard-graphql.tsx` — the variant route. +- Two new npm scripts: `graphql:generate`, `dev:mock-graphql`. + +## Not done / out of scope + +- No mutations, no subscriptions, no SSR. +- No replacement of existing RTK Query dashboard slices — the GraphQL surface is purely additive. +- No Apollo dev-tools setup beyond the default `connectToDevTools` flag. +- No persisted queries, no Apollo Studio, no schema registry. diff --git a/clients/admin-ui/codegen.ts b/clients/admin-ui/codegen.ts new file mode 100644 index 00000000000..f794c07ce33 --- /dev/null +++ b/clients/admin-ui/codegen.ts @@ -0,0 +1,32 @@ +import type { CodegenConfig } from "@graphql-codegen/cli"; + +/** + * GraphQL code generation for the dashboard PoC. + * + * Reads the local SDL (emitted from fidesplus via `nox -s graphql_emit_schema`) + * and generates a typed client into src/__generated__/graphql/. + * + * Rerun whenever schema.graphql or a *.graphql document changes: + * npm run graphql:generate + */ +const config: CodegenConfig = { + schema: "schema.graphql", + documents: ["src/**/*.graphql"], + generates: { + "src/__generated__/graphql/": { + preset: "client", + presetConfig: { + gqlTagName: "gql", + }, + config: { + useTypeImports: true, + scalars: { + DateTime: "string", + JSON: "Record", + }, + }, + }, + }, +}; + +export default config; diff --git a/clients/admin-ui/package.json b/clients/admin-ui/package.json index 871c999a66a..c17b3dfac9a 100644 --- a/clients/admin-ui/package.json +++ b/clients/admin-ui/package.json @@ -17,6 +17,8 @@ "cy:start:dev": "NEXT_PUBLIC_FIDESCTL_API_SERVER=http://localhost:8080 npm run cy:start", "dev": "next dev -p 3000", "dev:mock": "echo '🚨 Running with mock API'; NEXT_PUBLIC_MOCK_API=true npm run dev", + "dev:mock-graphql": "echo '🧪 Running with mocked GraphQL endpoint'; NEXT_PUBLIC_MOCK_GRAPHQL=true npm run dev", + "graphql:generate": "graphql-codegen && node scripts/sync-graphql-sdl.mjs", "export": "PROD_EXPORT=true next build", "prod-export": "npm run export && npm run copy-export", "format": "prettier --write --log-level warn .", @@ -36,9 +38,12 @@ }, "dependencies": { "@ant-design/cssinjs": "^2.1.2", + "@apollo/client": "^3.14.1", "@dagrejs/dagre": "^1.1.4", "@date-fns/tz": "^1.2.0", "@fontsource/inter": "^4.5.15", + "@graphql-tools/mock": "^9.1.7", + "@graphql-tools/schema": "^10.0.33", "@monaco-editor/react": "^4.6.0", "@reduxjs/toolkit": "^2.6.0", "@tanstack/react-table": "^8.10.7", @@ -56,6 +61,7 @@ "file-saver": "^2.0.5", "formik": "^2.4.6", "framer-motion": "^11.2.12", + "graphql": "^16.14.0", "i18n-iso-countries": "^7.5.0", "immer": "^9.0.21", "js-yaml": "^4.1.1", @@ -79,6 +85,9 @@ "yup": "^1.4.0" }, "devDependencies": { + "@ant-design/cli": "^6.3.7", + "@graphql-codegen/cli": "^5.0.7", + "@graphql-codegen/client-preset": "^4.8.3", "@hey-api/openapi-ts": "^0.88.2", "@jest/globals": "^29.7.0", "@next/bundle-analyzer": "^16.2.0", @@ -95,7 +104,6 @@ "@types/node": "18.15.10", "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", - "@ant-design/cli": "^6.3.7", "@typescript-eslint/eslint-plugin": "^8.57.0", "@typescript-eslint/parser": "^8.57.0", "autoprefixer": "^10.4.20", diff --git a/clients/admin-ui/schema.graphql b/clients/admin-ui/schema.graphql new file mode 100644 index 00000000000..2a8a78c4690 --- /dev/null +++ b/clients/admin-ui/schema.graphql @@ -0,0 +1,177 @@ +enum ActionSeverity { + critical + high + medium + low +} + +type ActivityFeedItem { + actorType: ActorType! + message: String! + timestamp: DateTime! +} + +type ActivityFeedPage { + items: [ActivityFeedItem!]! + total: Int! + page: Int! + size: Int! + pages: Int! +} + +enum ActorType { + user + agent +} + +type AgentBriefing { + briefing: String! + quickActions: [QuickAction!]! +} + +type Astralis { + activeConversations: Int! + completedAssessments: Int! + awaitingResponse: Int! + risksIdentified: Int! +} + +enum DashboardActionStatus { + pending + in_progress + completed +} + +enum DashboardActionType { + classification_review + dsr_action + system_review + steward_assignment + consent_anomaly + policy_violation + pia_update +} + +"""Date with time (isoformat)""" +scalar DateTime + +enum DiffDirection { + up + down + unchanged +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf). +""" +scalar JSON @specifiedBy(url: "https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf") + +type Posture { + score: Float! + band: PostureBand! + diffPercent: Float! + diffDirection: DiffDirection! + agentAnnotation: String! + dimensions: [PostureDimension!]! +} + +enum PostureBand { + critical + at_risk + good + excellent +} + +type PostureDimension { + dimension: String! + label: String! + weight: Float! + score: Float! + band: PostureBand! +} + +type PriorityAction { + id: ID! + type: DashboardActionType! + severity: ActionSeverity! + title: String! + message: String! + agentSummary: String! + dueDate: DateTime + actionData: JSON! + status: DashboardActionStatus! +} + +type PriorityActionsPage { + items: [PriorityAction!]! + total: Int! + page: Int! + size: Int! + pages: Int! +} + +type PrivacyRequestStatuses { + inProgress: Int! + pendingAction: Int! + awaitingApproval: Int! +} + +type PrivacyRequests { + activeCount: Int! + statuses: PrivacyRequestStatuses! + overdueCount: Int! + slaHealth: [SLAHealthBucket!]! +} + +type Query { + agentBriefing: AgentBriefing! + posture: Posture! + trends(period: TrendPeriod! = thirty_days): Trends! + astralis: Astralis! + activityFeed(page: Int! = 1, size: Int! = 20): ActivityFeedPage! + privacyRequests: PrivacyRequests! + systemCoverage: SystemCoverage! + priorityActions(page: Int! = 1, size: Int! = 8, action: DashboardActionType = null, status: DashboardActionStatus = null, dimension: String = null): PriorityActionsPage! +} + +type QuickAction { + label: String! + actionType: DashboardActionType! + actionData: JSON! + severity: ActionSeverity! +} + +type SLAHealthBucket { + label: String! + onTrack: Int! + approaching: Int! + overdue: Int! +} + +type SystemCoverage { + totalSystems: Int! + fullyClassified: Int! + partiallyClassified: Int! + unclassified: Int! + withoutSteward: Int! + coveragePercentage: Float! +} + +type TrendMetric { + key: String! + value: Float! + history: [Float!]! + metadata: JSON! + diff: Float! +} + +enum TrendPeriod { + thirty_days + sixty_days + ninety_days +} + +type Trends { + period: TrendPeriod! + metrics: [TrendMetric!]! +} diff --git a/clients/admin-ui/scripts/sync-graphql-sdl.mjs b/clients/admin-ui/scripts/sync-graphql-sdl.mjs new file mode 100644 index 00000000000..0a8fb4e2c92 --- /dev/null +++ b/clients/admin-ui/scripts/sync-graphql-sdl.mjs @@ -0,0 +1,24 @@ +#!/usr/bin/env node +/** + * Emits the bundled schema.graphql contents into a TypeScript constant so the + * mock layer (which runs in the browser via MSW) can build an executable + * schema without a webpack/Turbopack raw-loader rule. + * + * Re-run by `npm run graphql:generate` after the SDL changes. + */ +import { readFileSync, writeFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const here = dirname(fileURLToPath(import.meta.url)); +const root = resolve(here, ".."); +const sdlPath = resolve(root, "schema.graphql"); +const outPath = resolve( + root, + "src/features/dashboard-graphql/schema-string.ts", +); + +const sdl = readFileSync(sdlPath, "utf8"); +const body = `/* eslint-disable */\n// AUTOGENERATED by scripts/sync-graphql-sdl.mjs. Do not edit by hand.\n// Run \`npm run graphql:generate\` to refresh.\n\nexport const dashboardSchemaSDL = ${JSON.stringify(sdl)};\n`; +writeFileSync(outPath, body, "utf8"); +console.log(`wrote ${outPath} (${sdl.length} bytes)`); diff --git a/clients/admin-ui/src/__generated__/graphql/fragment-masking.ts b/clients/admin-ui/src/__generated__/graphql/fragment-masking.ts new file mode 100644 index 00000000000..743a364fe18 --- /dev/null +++ b/clients/admin-ui/src/__generated__/graphql/fragment-masking.ts @@ -0,0 +1,87 @@ +/* eslint-disable */ +import type { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; +import type { FragmentDefinitionNode } from 'graphql'; +import type { Incremental } from './graphql'; + + +export type FragmentType> = TDocumentType extends DocumentTypeDecoration< + infer TType, + any +> + ? [TType] extends [{ ' $fragmentName'?: infer TKey }] + ? TKey extends string + ? { ' $fragmentRefs'?: { [key in TKey]: TType } } + : never + : never + : never; + +// return non-nullable if `fragmentType` is non-nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> +): TType; +// return nullable if `fragmentType` is undefined +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> | undefined +): TType | undefined; +// return nullable if `fragmentType` is nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> | null +): TType | null; +// return nullable if `fragmentType` is nullable or undefined +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> | null | undefined +): TType | null | undefined; +// return array of non-nullable if `fragmentType` is array of non-nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: Array>> +): Array; +// return array of nullable if `fragmentType` is array of nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: Array>> | null | undefined +): Array | null | undefined; +// return readonly array of non-nullable if `fragmentType` is array of non-nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> +): ReadonlyArray; +// return readonly array of nullable if `fragmentType` is array of nullable +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: ReadonlyArray>> | null | undefined +): ReadonlyArray | null | undefined; +export function useFragment( + _documentNode: DocumentTypeDecoration, + fragmentType: FragmentType> | Array>> | ReadonlyArray>> | null | undefined +): TType | Array | ReadonlyArray | null | undefined { + return fragmentType as any; +} + + +export function makeFragmentData< + F extends DocumentTypeDecoration, + FT extends ResultOf +>(data: FT, _fragment: F): FragmentType { + return data as FragmentType; +} +export function isFragmentReady( + queryNode: DocumentTypeDecoration, + fragmentNode: TypedDocumentNode, + data: FragmentType, any>> | null | undefined +): data is FragmentType { + const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ + ?.deferredFields; + + if (!deferredFields) return true; + + const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; + const fragName = fragDef?.name?.value; + + const fields = (fragName && deferredFields[fragName]) || []; + return fields.length > 0 && fields.every(field => data && field in data); +} diff --git a/clients/admin-ui/src/__generated__/graphql/gql.ts b/clients/admin-ui/src/__generated__/graphql/gql.ts new file mode 100644 index 00000000000..d1ae416ca4c --- /dev/null +++ b/clients/admin-ui/src/__generated__/graphql/gql.ts @@ -0,0 +1,46 @@ +/* eslint-disable */ +import * as types from './graphql'; +import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; + +/** + * Map of all GraphQL operations in the project. + * + * This map has several performance disadvantages: + * 1. It is not tree-shakeable, so it will include all operations in the project. + * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle. + * 3. It does not support dead code elimination, so it will add unused operations. + * + * Therefore it is highly recommended to use the babel or swc plugin for production. + * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size + */ +type Documents = { + "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days, $actionsPage: Int! = 1, $actionsSize: Int! = 8, $activityPage: Int! = 1, $activitySize: Int! = 20) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n priorityActions(page: $actionsPage, size: $actionsSize) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n activityFeed(page: $activityPage, size: $activitySize) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": typeof types.DashboardOverviewDocument, +}; +const documents: Documents = { + "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days, $actionsPage: Int! = 1, $actionsSize: Int! = 8, $activityPage: Int! = 1, $activitySize: Int! = 20) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n priorityActions(page: $actionsPage, size: $actionsSize) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n activityFeed(page: $activityPage, size: $activitySize) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": types.DashboardOverviewDocument, +}; + +/** + * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + * + * + * @example + * ```ts + * const query = gql(`query GetUser($id: ID!) { user(id: $id) { name } }`); + * ``` + * + * The query argument is unknown! + * Please regenerate the types. + */ +export function gql(source: string): unknown; + +/** + * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function gql(source: "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days, $actionsPage: Int! = 1, $actionsSize: Int! = 8, $activityPage: Int! = 1, $activitySize: Int! = 20) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n priorityActions(page: $actionsPage, size: $actionsSize) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n activityFeed(page: $activityPage, size: $activitySize) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"): (typeof documents)["query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days, $actionsPage: Int! = 1, $actionsSize: Int! = 8, $activityPage: Int! = 1, $activitySize: Int! = 20) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n priorityActions(page: $actionsPage, size: $actionsSize) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n activityFeed(page: $activityPage, size: $activitySize) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"]; + +export function gql(source: string) { + return (documents as any)[source] ?? {}; +} + +export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never; \ No newline at end of file diff --git a/clients/admin-ui/src/__generated__/graphql/graphql.ts b/clients/admin-ui/src/__generated__/graphql/graphql.ts new file mode 100644 index 00000000000..35bded9cef3 --- /dev/null +++ b/clients/admin-ui/src/__generated__/graphql/graphql.ts @@ -0,0 +1,241 @@ +/* eslint-disable */ +import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +export type Maybe = T | null; +export type InputMaybe = Maybe; +export type Exact = { [K in keyof T]: T[K] }; +export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; +export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; +export type MakeEmpty = { [_ in K]?: never }; +export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +/** All built-in and custom scalars, mapped to their actual values */ +export type Scalars = { + ID: { input: string; output: string; } + String: { input: string; output: string; } + Boolean: { input: boolean; output: boolean; } + Int: { input: number; output: number; } + Float: { input: number; output: number; } + /** Date with time (isoformat) */ + DateTime: { input: string; output: string; } + /** The `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf). */ + JSON: { input: Record; output: Record; } +}; + +export enum ActionSeverity { + Critical = 'critical', + High = 'high', + Low = 'low', + Medium = 'medium' +} + +export type ActivityFeedItem = { + __typename?: 'ActivityFeedItem'; + actorType: ActorType; + message: Scalars['String']['output']; + timestamp: Scalars['DateTime']['output']; +}; + +export type ActivityFeedPage = { + __typename?: 'ActivityFeedPage'; + items: Array; + page: Scalars['Int']['output']; + pages: Scalars['Int']['output']; + size: Scalars['Int']['output']; + total: Scalars['Int']['output']; +}; + +export enum ActorType { + Agent = 'agent', + User = 'user' +} + +export type AgentBriefing = { + __typename?: 'AgentBriefing'; + briefing: Scalars['String']['output']; + quickActions: Array; +}; + +export type Astralis = { + __typename?: 'Astralis'; + activeConversations: Scalars['Int']['output']; + awaitingResponse: Scalars['Int']['output']; + completedAssessments: Scalars['Int']['output']; + risksIdentified: Scalars['Int']['output']; +}; + +export enum DashboardActionStatus { + Completed = 'completed', + InProgress = 'in_progress', + Pending = 'pending' +} + +export enum DashboardActionType { + ClassificationReview = 'classification_review', + ConsentAnomaly = 'consent_anomaly', + DsrAction = 'dsr_action', + PiaUpdate = 'pia_update', + PolicyViolation = 'policy_violation', + StewardAssignment = 'steward_assignment', + SystemReview = 'system_review' +} + +export enum DiffDirection { + Down = 'down', + Unchanged = 'unchanged', + Up = 'up' +} + +export type Posture = { + __typename?: 'Posture'; + agentAnnotation: Scalars['String']['output']; + band: PostureBand; + diffDirection: DiffDirection; + diffPercent: Scalars['Float']['output']; + dimensions: Array; + score: Scalars['Float']['output']; +}; + +export enum PostureBand { + AtRisk = 'at_risk', + Critical = 'critical', + Excellent = 'excellent', + Good = 'good' +} + +export type PostureDimension = { + __typename?: 'PostureDimension'; + band: PostureBand; + dimension: Scalars['String']['output']; + label: Scalars['String']['output']; + score: Scalars['Float']['output']; + weight: Scalars['Float']['output']; +}; + +export type PriorityAction = { + __typename?: 'PriorityAction'; + actionData: Scalars['JSON']['output']; + agentSummary: Scalars['String']['output']; + dueDate?: Maybe; + id: Scalars['ID']['output']; + message: Scalars['String']['output']; + severity: ActionSeverity; + status: DashboardActionStatus; + title: Scalars['String']['output']; + type: DashboardActionType; +}; + +export type PriorityActionsPage = { + __typename?: 'PriorityActionsPage'; + items: Array; + page: Scalars['Int']['output']; + pages: Scalars['Int']['output']; + size: Scalars['Int']['output']; + total: Scalars['Int']['output']; +}; + +export type PrivacyRequestStatuses = { + __typename?: 'PrivacyRequestStatuses'; + awaitingApproval: Scalars['Int']['output']; + inProgress: Scalars['Int']['output']; + pendingAction: Scalars['Int']['output']; +}; + +export type PrivacyRequests = { + __typename?: 'PrivacyRequests'; + activeCount: Scalars['Int']['output']; + overdueCount: Scalars['Int']['output']; + slaHealth: Array; + statuses: PrivacyRequestStatuses; +}; + +export type Query = { + __typename?: 'Query'; + activityFeed: ActivityFeedPage; + agentBriefing: AgentBriefing; + astralis: Astralis; + posture: Posture; + priorityActions: PriorityActionsPage; + privacyRequests: PrivacyRequests; + systemCoverage: SystemCoverage; + trends: Trends; +}; + + +export type QueryActivityFeedArgs = { + page?: Scalars['Int']['input']; + size?: Scalars['Int']['input']; +}; + + +export type QueryPriorityActionsArgs = { + action?: InputMaybe; + dimension?: InputMaybe; + page?: Scalars['Int']['input']; + size?: Scalars['Int']['input']; + status?: InputMaybe; +}; + + +export type QueryTrendsArgs = { + period?: TrendPeriod; +}; + +export type QuickAction = { + __typename?: 'QuickAction'; + actionData: Scalars['JSON']['output']; + actionType: DashboardActionType; + label: Scalars['String']['output']; + severity: ActionSeverity; +}; + +export type SlaHealthBucket = { + __typename?: 'SLAHealthBucket'; + approaching: Scalars['Int']['output']; + label: Scalars['String']['output']; + onTrack: Scalars['Int']['output']; + overdue: Scalars['Int']['output']; +}; + +export type SystemCoverage = { + __typename?: 'SystemCoverage'; + coveragePercentage: Scalars['Float']['output']; + fullyClassified: Scalars['Int']['output']; + partiallyClassified: Scalars['Int']['output']; + totalSystems: Scalars['Int']['output']; + unclassified: Scalars['Int']['output']; + withoutSteward: Scalars['Int']['output']; +}; + +export type TrendMetric = { + __typename?: 'TrendMetric'; + diff: Scalars['Float']['output']; + history: Array; + key: Scalars['String']['output']; + metadata: Scalars['JSON']['output']; + value: Scalars['Float']['output']; +}; + +export enum TrendPeriod { + NinetyDays = 'ninety_days', + SixtyDays = 'sixty_days', + ThirtyDays = 'thirty_days' +} + +export type Trends = { + __typename?: 'Trends'; + metrics: Array; + period: TrendPeriod; +}; + +export type DashboardOverviewQueryVariables = Exact<{ + trendPeriod?: TrendPeriod; + actionsPage?: Scalars['Int']['input']; + actionsSize?: Scalars['Int']['input']; + activityPage?: Scalars['Int']['input']; + activitySize?: Scalars['Int']['input']; +}>; + + +export type DashboardOverviewQuery = { __typename?: 'Query', posture: { __typename?: 'Posture', score: number, band: PostureBand, diffPercent: number, diffDirection: DiffDirection, agentAnnotation: string, dimensions: Array<{ __typename?: 'PostureDimension', dimension: string, label: string, weight: number, score: number, band: PostureBand }> }, trends: { __typename?: 'Trends', period: TrendPeriod, metrics: Array<{ __typename?: 'TrendMetric', key: string, value: number, history: Array, metadata: Record, diff: number }> }, systemCoverage: { __typename?: 'SystemCoverage', totalSystems: number, fullyClassified: number, partiallyClassified: number, unclassified: number, withoutSteward: number, coveragePercentage: number }, privacyRequests: { __typename?: 'PrivacyRequests', activeCount: number, overdueCount: number, statuses: { __typename?: 'PrivacyRequestStatuses', inProgress: number, pendingAction: number, awaitingApproval: number }, slaHealth: Array<{ __typename?: 'SLAHealthBucket', label: string, onTrack: number, approaching: number, overdue: number }> }, priorityActions: { __typename?: 'PriorityActionsPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'PriorityAction', id: string, type: DashboardActionType, severity: ActionSeverity, title: string, message: string, agentSummary: string, dueDate?: string | null, actionData: Record, status: DashboardActionStatus }> }, astralis: { __typename?: 'Astralis', activeConversations: number, completedAssessments: number, awaitingResponse: number, risksIdentified: number }, agentBriefing: { __typename?: 'AgentBriefing', briefing: string, quickActions: Array<{ __typename?: 'QuickAction', label: string, actionType: DashboardActionType, severity: ActionSeverity, actionData: Record }> }, activityFeed: { __typename?: 'ActivityFeedPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'ActivityFeedItem', actorType: ActorType, message: string, timestamp: string }> } }; + + +export const DashboardOverviewDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardOverview"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"trendPeriod"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TrendPeriod"}}},"defaultValue":{"kind":"EnumValue","value":"thirty_days"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"actionsPage"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"actionsSize"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"8"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"activityPage"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"activitySize"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"posture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}},{"kind":"Field","name":{"kind":"Name","value":"diffPercent"}},{"kind":"Field","name":{"kind":"Name","value":"diffDirection"}},{"kind":"Field","name":{"kind":"Name","value":"agentAnnotation"}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimension"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"trends"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"period"},"value":{"kind":"Variable","name":{"kind":"Name","value":"trendPeriod"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"metrics"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"history"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"diff"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"systemCoverage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalSystems"}},{"kind":"Field","name":{"kind":"Name","value":"fullyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"partiallyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"unclassified"}},{"kind":"Field","name":{"kind":"Name","value":"withoutSteward"}},{"kind":"Field","name":{"kind":"Name","value":"coveragePercentage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"privacyRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeCount"}},{"kind":"Field","name":{"kind":"Name","value":"overdueCount"}},{"kind":"Field","name":{"kind":"Name","value":"statuses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inProgress"}},{"kind":"Field","name":{"kind":"Name","value":"pendingAction"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingApproval"}}]}},{"kind":"Field","name":{"kind":"Name","value":"slaHealth"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"onTrack"}},{"kind":"Field","name":{"kind":"Name","value":"approaching"}},{"kind":"Field","name":{"kind":"Name","value":"overdue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"priorityActions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"actionsPage"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"actionsSize"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"agentSummary"}},{"kind":"Field","name":{"kind":"Name","value":"dueDate"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}},{"kind":"Field","name":{"kind":"Name","value":"astralis"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConversations"}},{"kind":"Field","name":{"kind":"Name","value":"completedAssessments"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingResponse"}},{"kind":"Field","name":{"kind":"Name","value":"risksIdentified"}}]}},{"kind":"Field","name":{"kind":"Name","value":"agentBriefing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"briefing"}},{"kind":"Field","name":{"kind":"Name","value":"quickActions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"actionType"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"activityFeed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"activityPage"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"activitySize"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"actorType"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/clients/admin-ui/src/__generated__/graphql/index.ts b/clients/admin-ui/src/__generated__/graphql/index.ts new file mode 100644 index 00000000000..f51599168fb --- /dev/null +++ b/clients/admin-ui/src/__generated__/graphql/index.ts @@ -0,0 +1,2 @@ +export * from "./fragment-masking"; +export * from "./gql"; \ No newline at end of file diff --git a/clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlProvider.tsx b/clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlProvider.tsx new file mode 100644 index 00000000000..a8b45af918f --- /dev/null +++ b/clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlProvider.tsx @@ -0,0 +1,13 @@ +import { ApolloProvider } from "@apollo/client"; +import { type ReactNode, useMemo } from "react"; + +import { createApolloClient } from "./apolloClient"; + +export const DashboardGraphqlProvider = ({ + children, +}: { + children: ReactNode; +}) => { + const client = useMemo(() => createApolloClient(), []); + return {children}; +}; diff --git a/clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlView.tsx b/clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlView.tsx new file mode 100644 index 00000000000..d4db81a33af --- /dev/null +++ b/clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlView.tsx @@ -0,0 +1,200 @@ +import { useQuery } from "@apollo/client"; +import { Alert, Col, Flex, Row, Spin, Text, Typography } from "fidesui"; + +import { DashboardOverviewDocument } from "~/__generated__/graphql/graphql"; + +const { Title } = Typography; + +const Section = ({ + title, + children, +}: { + title: string; + children: React.ReactNode; +}) => ( + + {title} + {children} + +); + +const Metric = ({ + label, + value, +}: { + label: string; + value: React.ReactNode; +}) => ( + + + {label} + + {value} + +); + +export const DashboardGraphqlView = () => { + const { data, loading, error } = useQuery(DashboardOverviewDocument); + + if (loading && !data) { + return ( + + + + ); + } + if (error) { + return ; + } + if (!data) { + return null; + } + + const { + posture, + systemCoverage, + privacyRequests, + priorityActions, + astralis, + agentBriefing, + trends, + activityFeed, + } = data; + + return ( + + Dashboard (GraphQL / Apollo) + + 0 ? ( + + {agentBriefing.quickActions.map((qa) => qa.label).join(" · ")} + + ) : null + } + /> + + + +
+ {posture.agentAnnotation} + + {posture.dimensions.map((d) => ( + + {d.label} + + {d.score} · {d.band} + + + ))} + +
+ + +
+ + {priorityActions.items.map((a) => ( + + + [{a.severity}] {a.title} + + {a.message} + + ))} + +
+ +
+ + + {trends.metrics.map((m) => ( + +
+ + +
+ + ))} +
+ + + +
+ + + + +
+ + +
+ + + + +
+ + +
+ + + + +
+ +
+ +
+ + {activityFeed.items.map((item) => ( + + {item.message} + + {item.actorType} · {item.timestamp} + + + ))} + +
+
+ ); +}; diff --git a/clients/admin-ui/src/features/dashboard-graphql/apolloClient.ts b/clients/admin-ui/src/features/dashboard-graphql/apolloClient.ts new file mode 100644 index 00000000000..4d96d52e09b --- /dev/null +++ b/clients/admin-ui/src/features/dashboard-graphql/apolloClient.ts @@ -0,0 +1,35 @@ +import { + ApolloClient, + createHttpLink, + InMemoryCache, + type NormalizedCacheObject, +} from "@apollo/client"; +import { setContext } from "@apollo/client/link/context"; + +import { addCommonHeaders } from "~/features/common/CommonHeaders"; + +const httpLink = createHttpLink({ + uri: `${process.env.NEXT_PUBLIC_FIDESCTL_API ?? ""}/graphql`, +}); + +/** + * Reads the auth token from the redux store and folds in the same headers + * applied to RTK Query requests via addCommonHeaders. + * + * Redux is imported lazily to avoid a circular dependency between the + * Apollo client setup (which has to run early in _app.tsx) and the store. + */ +const authLink = setContext(async (_, { headers }) => { + const { default: store } = await import("~/app/store"); + const { token } = store.getState().auth; + const next = new Headers(headers as HeadersInit); + addCommonHeaders(next, token); + return { headers: Object.fromEntries(next.entries()) }; +}); + +export const createApolloClient = (): ApolloClient => + new ApolloClient({ + link: authLink.concat(httpLink), + cache: new InMemoryCache(), + connectToDevTools: process.env.NODE_ENV !== "production", + }); diff --git a/clients/admin-ui/src/features/dashboard-graphql/dashboard.graphql b/clients/admin-ui/src/features/dashboard-graphql/dashboard.graphql new file mode 100644 index 00000000000..7a7e66e8797 --- /dev/null +++ b/clients/admin-ui/src/features/dashboard-graphql/dashboard.graphql @@ -0,0 +1,98 @@ +query DashboardOverview( + $trendPeriod: TrendPeriod! = thirty_days + $actionsPage: Int! = 1 + $actionsSize: Int! = 8 + $activityPage: Int! = 1 + $activitySize: Int! = 20 +) { + posture { + score + band + diffPercent + diffDirection + agentAnnotation + dimensions { + dimension + label + weight + score + band + } + } + trends(period: $trendPeriod) { + period + metrics { + key + value + history + metadata + diff + } + } + systemCoverage { + totalSystems + fullyClassified + partiallyClassified + unclassified + withoutSteward + coveragePercentage + } + privacyRequests { + activeCount + overdueCount + statuses { + inProgress + pendingAction + awaitingApproval + } + slaHealth { + label + onTrack + approaching + overdue + } + } + priorityActions(page: $actionsPage, size: $actionsSize) { + items { + id + type + severity + title + message + agentSummary + dueDate + actionData + status + } + total + page + size + pages + } + astralis { + activeConversations + completedAssessments + awaitingResponse + risksIdentified + } + agentBriefing { + briefing + quickActions { + label + actionType + severity + actionData + } + } + activityFeed(page: $activityPage, size: $activitySize) { + items { + actorType + message + timestamp + } + total + page + size + pages + } +} diff --git a/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts b/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts new file mode 100644 index 00000000000..e8501e703a7 --- /dev/null +++ b/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts @@ -0,0 +1,5 @@ +/* eslint-disable */ +// AUTOGENERATED by scripts/sync-graphql-sdl.mjs. Do not edit by hand. +// Run `npm run graphql:generate` to refresh. + +export const dashboardSchemaSDL = "enum ActionSeverity {\n critical\n high\n medium\n low\n}\n\ntype ActivityFeedItem {\n actorType: ActorType!\n message: String!\n timestamp: DateTime!\n}\n\ntype ActivityFeedPage {\n items: [ActivityFeedItem!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\nenum ActorType {\n user\n agent\n}\n\ntype AgentBriefing {\n briefing: String!\n quickActions: [QuickAction!]!\n}\n\ntype Astralis {\n activeConversations: Int!\n completedAssessments: Int!\n awaitingResponse: Int!\n risksIdentified: Int!\n}\n\nenum DashboardActionStatus {\n pending\n in_progress\n completed\n}\n\nenum DashboardActionType {\n classification_review\n dsr_action\n system_review\n steward_assignment\n consent_anomaly\n policy_violation\n pia_update\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\nenum DiffDirection {\n up\n down\n unchanged\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Posture {\n score: Float!\n band: PostureBand!\n diffPercent: Float!\n diffDirection: DiffDirection!\n agentAnnotation: String!\n dimensions: [PostureDimension!]!\n}\n\nenum PostureBand {\n critical\n at_risk\n good\n excellent\n}\n\ntype PostureDimension {\n dimension: String!\n label: String!\n weight: Float!\n score: Float!\n band: PostureBand!\n}\n\ntype PriorityAction {\n id: ID!\n type: DashboardActionType!\n severity: ActionSeverity!\n title: String!\n message: String!\n agentSummary: String!\n dueDate: DateTime\n actionData: JSON!\n status: DashboardActionStatus!\n}\n\ntype PriorityActionsPage {\n items: [PriorityAction!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\ntype PrivacyRequestStatuses {\n inProgress: Int!\n pendingAction: Int!\n awaitingApproval: Int!\n}\n\ntype PrivacyRequests {\n activeCount: Int!\n statuses: PrivacyRequestStatuses!\n overdueCount: Int!\n slaHealth: [SLAHealthBucket!]!\n}\n\ntype Query {\n agentBriefing: AgentBriefing!\n posture: Posture!\n trends(period: TrendPeriod! = thirty_days): Trends!\n astralis: Astralis!\n activityFeed(page: Int! = 1, size: Int! = 20): ActivityFeedPage!\n privacyRequests: PrivacyRequests!\n systemCoverage: SystemCoverage!\n priorityActions(page: Int! = 1, size: Int! = 8, action: DashboardActionType = null, status: DashboardActionStatus = null, dimension: String = null): PriorityActionsPage!\n}\n\ntype QuickAction {\n label: String!\n actionType: DashboardActionType!\n actionData: JSON!\n severity: ActionSeverity!\n}\n\ntype SLAHealthBucket {\n label: String!\n onTrack: Int!\n approaching: Int!\n overdue: Int!\n}\n\ntype SystemCoverage {\n totalSystems: Int!\n fullyClassified: Int!\n partiallyClassified: Int!\n unclassified: Int!\n withoutSteward: Int!\n coveragePercentage: Float!\n}\n\ntype TrendMetric {\n key: String!\n value: Float!\n history: [Float!]!\n metadata: JSON!\n diff: Float!\n}\n\nenum TrendPeriod {\n thirty_days\n sixty_days\n ninety_days\n}\n\ntype Trends {\n period: TrendPeriod!\n metrics: [TrendMetric!]!\n}\n"; diff --git a/clients/admin-ui/src/mocks/dashboard-graphql/handlers.ts b/clients/admin-ui/src/mocks/dashboard-graphql/handlers.ts new file mode 100644 index 00000000000..1041f361318 --- /dev/null +++ b/clients/admin-ui/src/mocks/dashboard-graphql/handlers.ts @@ -0,0 +1,125 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { addMocksToSchema } from "@graphql-tools/mock"; +import { makeExecutableSchema } from "@graphql-tools/schema"; +import { graphql } from "graphql"; +import { rest } from "msw"; + +import { dashboardSchemaSDL } from "~/features/dashboard-graphql/schema-string"; + +/** + * Schema-driven GraphQL mock used by both PoC FE branches (Apollo + urql). + * + * The mock surface is identical across the two variants by design — the only + * thing the user is comparing is the FE stack, so the data plane stays fixed. + * + * Enums and a handful of fields have explicit resolvers; everything else + * falls back to graphql-tools default mocks (length-3 lists, type-shaped + * scalars). Good enough to drive the dashboard end-to-end without the BE. + */ +const baseSchema = makeExecutableSchema({ typeDefs: dashboardSchemaSDL }); + +const mockedSchema = addMocksToSchema({ + schema: baseSchema, + mocks: { + DateTime: () => new Date().toISOString(), + JSON: () => ({}), + PostureBand: () => "good", + DiffDirection: () => "up", + ActionSeverity: () => "medium", + DashboardActionStatus: () => "pending", + DashboardActionType: () => "classification_review", + ActorType: () => "agent", + TrendPeriod: () => "thirty_days", + Posture: () => ({ + score: 72, + diffPercent: 4.1, + agentAnnotation: "Coverage improved over the last 30 days.", + dimensions: [ + { dimension: "coverage", label: "Coverage", weight: 0.3, score: 78 }, + { + dimension: "classification_health", + label: "Classification Health", + weight: 0.25, + score: 65, + }, + { + dimension: "dsr_compliance", + label: "DSR Compliance", + weight: 0.25, + score: 80, + }, + { + dimension: "consent_alignment", + label: "Consent Alignment", + weight: 0.2, + score: 71, + }, + ], + }), + SystemCoverage: () => ({ + totalSystems: 64, + fullyClassified: 31, + partiallyClassified: 18, + unclassified: 15, + withoutSteward: 9, + coveragePercentage: 76.5, + }), + PrivacyRequests: () => ({ + activeCount: 12, + overdueCount: 2, + statuses: { inProgress: 7, pendingAction: 3, awaitingApproval: 2 }, + slaHealth: [ + { label: "access", onTrack: 5, approaching: 1, overdue: 1 }, + { label: "erasure", onTrack: 3, approaching: 1, overdue: 1 }, + ], + }), + Astralis: () => ({ + activeConversations: 4, + completedAssessments: 11, + awaitingResponse: 2, + risksIdentified: 6, + }), + AgentBriefing: () => ({ + briefing: "Two privacy requests are overdue and require attention.", + quickActions: [ + { label: "Review DSRs", actionType: "dsr_action", severity: "high" }, + ], + }), + TrendMetric: () => ({ + value: 42, + history: [30, 33, 35, 38, 40, 42], + diff: 4, + }), + PriorityAction: () => ({ + title: "Review classification proposals", + message: "3 systems have field-level classifications awaiting approval.", + agentSummary: "Auto-classified by Helios. Confidence > 0.8.", + }), + ActivityFeedItem: () => ({ + message: "Steward assigned to system_42.", + }), + }, +}); + +export const dashboardGraphqlHandlers = () => [ + rest.post(/\/graphql$/, async (req, res, ctx) => { + const body = (await req.json()) as { + query?: string; + operationName?: string; + variables?: Record; + }; + if (!body?.query) { + return res( + ctx.status(400), + ctx.json({ errors: [{ message: "no query" }] }), + ); + } + const result = await graphql({ + schema: mockedSchema, + source: body.query, + operationName: body.operationName, + variableValues: body.variables, + }); + return res(ctx.json(result)); + }), +]; diff --git a/clients/admin-ui/src/mocks/handlers.ts b/clients/admin-ui/src/mocks/handlers.ts index 0c7cd7bebf6..0acbd301bfa 100644 --- a/clients/admin-ui/src/mocks/handlers.ts +++ b/clients/admin-ui/src/mocks/handlers.ts @@ -4,18 +4,29 @@ import { agentChatHandlers } from "./access-policies/agent-chat-handlers"; import { accessPoliciesHandlers } from "./access-policies/handlers"; import { discoveryMonitorHandlers } from "./action-center/handlers"; import { dashboardHandlers } from "./dashboard/handlers"; +import { dashboardGraphqlHandlers } from "./dashboard-graphql/handlers"; import { dataPurposesHandlers } from "./data-purposes/handlers"; import { manualTasksHandlers } from "./manual-tasks/handlers"; import { policyHandlers } from "./policy/handlers"; +const restMocksEnabled = process.env.NEXT_PUBLIC_MOCK_API === "true"; +const graphqlMocksEnabled = process.env.NEXT_PUBLIC_MOCK_GRAPHQL === "true"; + // eslint-disable-next-line import/prefer-default-export export const handlers = [ - ...taxonomyHandlers(), - ...discoveryMonitorHandlers(), - ...policyHandlers(), - ...accessPoliciesHandlers(), - ...agentChatHandlers(), - ...dashboardHandlers(), - ...manualTasksHandlers(), - ...dataPurposesHandlers(), + // GraphQL handler is independently toggled so the dashboard PoC can mock + // the GraphQL endpoint while the rest of the app talks to the real BE. + ...(graphqlMocksEnabled ? dashboardGraphqlHandlers() : []), + ...(restMocksEnabled + ? [ + ...taxonomyHandlers(), + ...discoveryMonitorHandlers(), + ...policyHandlers(), + ...accessPoliciesHandlers(), + ...agentChatHandlers(), + ...dashboardHandlers(), + ...manualTasksHandlers(), + ...dataPurposesHandlers(), + ] + : []), ]; diff --git a/clients/admin-ui/src/pages/_app.tsx b/clients/admin-ui/src/pages/_app.tsx index f8f3156456f..2e76445ccb6 100644 --- a/clients/admin-ui/src/pages/_app.tsx +++ b/clients/admin-ui/src/pages/_app.tsx @@ -28,7 +28,7 @@ import LoginWithOIDC from "./login/[provider]"; dayjs.extend(utc); -if (process.env.NEXT_PUBLIC_MOCK_API) { +if (process.env.NEXT_PUBLIC_MOCK_API || process.env.NEXT_PUBLIC_MOCK_GRAPHQL) { // eslint-disable-next-line @typescript-eslint/no-floating-promises import("../mocks").then(({ initMocks }) => initMocks()); } diff --git a/clients/admin-ui/src/pages/dashboard-graphql.tsx b/clients/admin-ui/src/pages/dashboard-graphql.tsx new file mode 100644 index 00000000000..2cdc3d38e90 --- /dev/null +++ b/clients/admin-ui/src/pages/dashboard-graphql.tsx @@ -0,0 +1,15 @@ +import type { NextPage } from "next"; + +import Layout from "~/features/common/Layout"; +import { DashboardGraphqlProvider } from "~/features/dashboard-graphql/DashboardGraphqlProvider"; +import { DashboardGraphqlView } from "~/features/dashboard-graphql/DashboardGraphqlView"; + +const DashboardGraphqlPage: NextPage = () => ( + + + + + +); + +export default DashboardGraphqlPage; diff --git a/clients/package-lock.json b/clients/package-lock.json index 4f4b2909a4b..f9f98e070af 100644 --- a/clients/package-lock.json +++ b/clients/package-lock.json @@ -25,9 +25,12 @@ "admin-ui": { "dependencies": { "@ant-design/cssinjs": "^2.1.2", + "@apollo/client": "^3.14.1", "@dagrejs/dagre": "^1.1.4", "@date-fns/tz": "^1.2.0", "@fontsource/inter": "^4.5.15", + "@graphql-tools/mock": "^9.1.7", + "@graphql-tools/schema": "^10.0.33", "@monaco-editor/react": "^4.6.0", "@reduxjs/toolkit": "^2.6.0", "@tanstack/react-table": "^8.10.7", @@ -45,6 +48,7 @@ "file-saver": "^2.0.5", "formik": "^2.4.6", "framer-motion": "^11.2.12", + "graphql": "^16.14.0", "i18n-iso-countries": "^7.5.0", "immer": "^9.0.21", "js-yaml": "^4.1.1", @@ -69,6 +73,8 @@ }, "devDependencies": { "@ant-design/cli": "^6.3.7", + "@graphql-codegen/cli": "^5.0.7", + "@graphql-codegen/client-preset": "^4.8.3", "@hey-api/openapi-ts": "^0.88.2", "@jest/globals": "^29.7.0", "@next/bundle-analyzer": "^16.2.0", @@ -2675,6 +2681,63 @@ "openapi-types": ">=7" } }, + "node_modules/@apollo/client": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.14.1.tgz", + "integrity": "sha512-SgGX6E23JsZhUdG2anxiyHvEvvN6CUaI4ZfMsndZFeuHPXL3H0IsaiNAhLITSISbeyeYd+CBd9oERXQDdjXWZw==", + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@wry/caches": "^1.0.0", + "@wry/equality": "^0.5.6", + "@wry/trie": "^0.5.0", + "graphql-tag": "^2.12.6", + "hoist-non-react-statics": "^3.3.2", + "optimism": "^0.18.0", + "prop-types": "^15.7.2", + "rehackt": "^0.1.0", + "symbol-observable": "^4.0.0", + "ts-invariant": "^0.10.3", + "tslib": "^2.3.0", + "zen-observable-ts": "^1.2.5" + }, + "peerDependencies": { + "graphql": "^15.0.0 || ^16.0.0", + "graphql-ws": "^5.5.5 || ^6.0.3", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc", + "subscriptions-transport-ws": "^0.9.0 || ^0.11.0" + }, + "peerDependenciesMeta": { + "graphql-ws": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "subscriptions-transport-ws": { + "optional": true + } + } + }, + "node_modules/@ardatan/relay-compiler": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@ardatan/relay-compiler/-/relay-compiler-13.0.1.tgz", + "integrity": "sha512-afG3YPwuSA0E5foouZusz5GlXKs74dObv4cuWyLyfKsYFj2r7oGRNB28v18HvwuLSQtQFCi+DpIe0TZkgQDYyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "immutable": "^5.1.5", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "graphql": "*" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -2859,10 +2922,11 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -2910,9 +2974,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -2975,6 +3039,22 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", + "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", @@ -3147,9 +3227,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3679,6 +3759,50 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, + "node_modules/@envelop/core": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@envelop/core/-/core-5.5.1.tgz", + "integrity": "sha512-3DQg8sFskDo386TkL5j12jyRAdip/8yzK3x7YGbZBgobZ4aKXrvDU0GppU0SnmrpQnNaiTUsxBs9LKkwQ/eyvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@envelop/instrumentation": "^1.0.0", + "@envelop/types": "^5.2.1", + "@whatwg-node/promise-helpers": "^1.2.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@envelop/instrumentation": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@envelop/instrumentation/-/instrumentation-1.0.0.tgz", + "integrity": "sha512-cxgkB66RQB95H3X27jlnxCRNTmPuSTgmBAq6/4n2Dtv4hsk4yz8FadA1ggmd0uZzvKqWD6CR+WFgTjhDqg7eyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@whatwg-node/promise-helpers": "^1.2.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@envelop/types": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@envelop/types/-/types-5.2.1.tgz", + "integrity": "sha512-CsFmA3u3c2QoLDTfEpGr4t25fjMU31nyvse7IzWTvb0ZycuPjMjb0fjlheh+PbhBYb9YLugnT2uY6Mwcg1o+Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@whatwg-node/promise-helpers": "^1.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.46.0", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", @@ -4135,115 +4259,1548 @@ "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.2.0.tgz", + "integrity": "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@fontsource/inter": { + "version": "4.5.15", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.15.tgz", + "integrity": "sha512-FzleM9AxZQK2nqsTDtBiY0PMEVWvnKnuu2i09+p6DHvrHsuucoV2j0tmw+kAT3L4hvsLdAIDv6MdGehsPIdT+Q==" + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "node_modules/@gerrit0/mini-shiki": { + "version": "1.27.2", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-1.27.2.tgz", + "integrity": "sha512-GeWyHz8ao2gBiUW4OJnQDxXQnFgZQwwQk05t/CVVgNBN7/rK8XZ7xY6YhLVv9tH3VppWWmr9DCl3MwemB/i+Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-oniguruma": "^1.27.2", + "@shikijs/types": "^1.27.2", + "@shikijs/vscode-textmate": "^10.0.1" + } + }, + "node_modules/@graphql-codegen/add": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@graphql-codegen/add/-/add-5.0.3.tgz", + "integrity": "sha512-SxXPmramkth8XtBlAHu4H4jYcYXM/o3p01+psU+0NADQowA8jtYkK6MW5rV6T+CxkEaNZItfSmZRPgIuypcqnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.3", + "tslib": "~2.6.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/add/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-codegen/cli": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-5.0.7.tgz", + "integrity": "sha512-h/sxYvSaWtxZxo8GtaA8SvcHTyViaaPd7dweF/hmRDpaQU1o3iU3EZxlcJ+oLTunU0tSMFsnrIXm/mhXxI11Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.18.13", + "@babel/template": "^7.18.10", + "@babel/types": "^7.18.13", + "@graphql-codegen/client-preset": "^4.8.2", + "@graphql-codegen/core": "^4.0.2", + "@graphql-codegen/plugin-helpers": "^5.1.1", + "@graphql-tools/apollo-engine-loader": "^8.0.0", + "@graphql-tools/code-file-loader": "^8.0.0", + "@graphql-tools/git-loader": "^8.0.0", + "@graphql-tools/github-loader": "^8.0.0", + "@graphql-tools/graphql-file-loader": "^8.0.0", + "@graphql-tools/json-file-loader": "^8.0.0", + "@graphql-tools/load": "^8.1.0", + "@graphql-tools/prisma-loader": "^8.0.0", + "@graphql-tools/url-loader": "^8.0.0", + "@graphql-tools/utils": "^10.0.0", + "@whatwg-node/fetch": "^0.10.0", + "chalk": "^4.1.0", + "cosmiconfig": "^8.1.3", + "debounce": "^1.2.0", + "detect-indent": "^6.0.0", + "graphql-config": "^5.1.1", + "inquirer": "^8.0.0", + "is-glob": "^4.0.1", + "jiti": "^1.17.1", + "json-to-pretty-yaml": "^1.2.2", + "listr2": "^4.0.5", + "log-symbols": "^4.0.0", + "micromatch": "^4.0.5", + "shell-quote": "^1.7.3", + "string-env-interpolation": "^1.0.1", + "ts-log": "^2.2.3", + "tslib": "^2.4.0", + "yaml": "^2.3.1", + "yargs": "^17.0.0" + }, + "bin": { + "gql-gen": "cjs/bin.js", + "graphql-code-generator": "cjs/bin.js", + "graphql-codegen": "cjs/bin.js", + "graphql-codegen-esm": "esm/bin.js" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@parcel/watcher": "^2.1.0", + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "@parcel/watcher": { + "optional": true + } + } + }, + "node_modules/@graphql-codegen/cli/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-codegen/cli/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@graphql-codegen/cli/node_modules/listr2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", + "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.5", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/@graphql-codegen/cli/node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/@graphql-codegen/client-preset": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.8.3.tgz", + "integrity": "sha512-QpEsPSO9fnRxA6Z66AmBuGcwHjZ6dYSxYo5ycMlYgSPzAbyG8gn/kWljofjJfWqSY+T/lRn+r8IXTH14ml24vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7", + "@graphql-codegen/add": "^5.0.3", + "@graphql-codegen/gql-tag-operations": "4.0.17", + "@graphql-codegen/plugin-helpers": "^5.1.1", + "@graphql-codegen/typed-document-node": "^5.1.2", + "@graphql-codegen/typescript": "^4.1.6", + "@graphql-codegen/typescript-operations": "^4.6.1", + "@graphql-codegen/visitor-plugin-common": "^5.8.0", + "@graphql-tools/documents": "^1.0.0", + "@graphql-tools/utils": "^10.0.0", + "@graphql-typed-document-node/core": "3.2.0", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", + "graphql-sock": "^1.0.0" + }, + "peerDependenciesMeta": { + "graphql-sock": { + "optional": true + } + } + }, + "node_modules/@graphql-codegen/client-preset/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-codegen/client-preset/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-codegen/core": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/core/-/core-4.0.2.tgz", + "integrity": "sha512-IZbpkhwVqgizcjNiaVzNAzm/xbWT6YnGgeOLwVjm4KbJn3V2jchVtuzHH09G5/WkkLSk2wgbXNdwjM41JxO6Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.3", + "@graphql-tools/schema": "^10.0.0", + "@graphql-tools/utils": "^10.0.0", + "tslib": "~2.6.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/core/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-codegen/core/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-codegen/gql-tag-operations": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.17.tgz", + "integrity": "sha512-2pnvPdIG6W9OuxkrEZ6hvZd142+O3B13lvhrZ48yyEBh2ujtmKokw0eTwDHtlXUqjVS0I3q7+HB2y12G/m69CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.1.0", + "@graphql-codegen/visitor-plugin-common": "5.8.0", + "@graphql-tools/utils": "^10.0.0", + "auto-bind": "~4.0.0", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/gql-tag-operations/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-codegen/gql-tag-operations/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-codegen/plugin-helpers": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.1.1.tgz", + "integrity": "sha512-28GHODK2HY1NhdyRcPP3sCz0Kqxyfiz7boIZ8qIxFYmpLYnlDgiYok5fhFLVSZihyOpCs4Fa37gVHf/Q4I2FEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^10.0.0", + "change-case-all": "1.0.15", + "common-tags": "1.8.2", + "import-from": "4.0.0", + "lodash": "~4.17.0", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/plugin-helpers/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-codegen/plugin-helpers/node_modules/import-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", + "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@graphql-codegen/plugin-helpers/node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@graphql-codegen/plugin-helpers/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-codegen/schema-ast": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/schema-ast/-/schema-ast-4.1.0.tgz", + "integrity": "sha512-kZVn0z+th9SvqxfKYgztA6PM7mhnSZaj4fiuBWvMTqA+QqQ9BBed6Pz41KuD/jr0gJtnlr2A4++/0VlpVbCTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.0.3", + "@graphql-tools/utils": "^10.0.0", + "tslib": "~2.6.0" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/schema-ast/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-codegen/schema-ast/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-codegen/typed-document-node": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.1.2.tgz", + "integrity": "sha512-jaxfViDqFRbNQmfKwUY8hDyjnLTw2Z7DhGutxoOiiAI0gE/LfPe0LYaVFKVmVOOD7M3bWxoWfu4slrkbWbUbEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.1.0", + "@graphql-codegen/visitor-plugin-common": "5.8.0", + "auto-bind": "~4.0.0", + "change-case-all": "1.0.15", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/typed-document-node/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-codegen/typescript": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-4.1.6.tgz", + "integrity": "sha512-vpw3sfwf9A7S+kIUjyFxuvrywGxd4lmwmyYnnDVjVE4kSQ6Td3DpqaPTy8aNQ6O96vFoi/bxbZS2BW49PwSUUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.1.0", + "@graphql-codegen/schema-ast": "^4.0.2", + "@graphql-codegen/visitor-plugin-common": "5.8.0", + "auto-bind": "~4.0.0", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/typescript-operations": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.6.1.tgz", + "integrity": "sha512-k92laxhih7s0WZ8j5WMIbgKwhe64C0As6x+PdcvgZFMudDJ7rPJ/hFqJ9DCRxNjXoHmSjnr6VUuQZq4lT1RzCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.1.0", + "@graphql-codegen/typescript": "^4.1.6", + "@graphql-codegen/visitor-plugin-common": "5.8.0", + "auto-bind": "~4.0.0", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", + "graphql-sock": "^1.0.0" + }, + "peerDependenciesMeta": { + "graphql-sock": { + "optional": true + } + } + }, + "node_modules/@graphql-codegen/typescript-operations/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-codegen/typescript/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-codegen/visitor-plugin-common": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-5.8.0.tgz", + "integrity": "sha512-lC1E1Kmuzi3WZUlYlqB4fP6+CvbKH9J+haU1iWmgsBx5/sO2ROeXJG4Dmt8gP03bI2BwjiwV5WxCEMlyeuzLnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-codegen/plugin-helpers": "^5.1.0", + "@graphql-tools/optimize": "^2.0.0", + "@graphql-tools/relay-operation-optimizer": "^7.0.0", + "@graphql-tools/utils": "^10.0.0", + "auto-bind": "~4.0.0", + "change-case-all": "1.0.15", + "dependency-graph": "^0.11.0", + "graphql-tag": "^2.11.0", + "parse-filepath": "^1.0.2", + "tslib": "~2.6.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/@graphql-codegen/visitor-plugin-common/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-codegen/visitor-plugin-common/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@graphql-hive/signal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@graphql-hive/signal/-/signal-1.0.0.tgz", + "integrity": "sha512-RiwLMc89lTjvyLEivZ/qxAC5nBHoS2CtsWFSOsN35sxG9zoo5Z+JsFHM8MlvmO9yt+MJNIyC5MLE1rsbOphlag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/apollo-engine-loader": { + "version": "8.0.30", + "resolved": "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.30.tgz", + "integrity": "sha512-hUydKGGECrWloERMmfoMzHZi12X99AM9geCGF5XVsv4iMRl/Iyuet24th4kC9bZ8MlAdCwAwtUsCyv9uRfYwSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.1.0", + "@whatwg-node/fetch": "^0.10.13", + "sync-fetch": "0.6.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/batch-execute": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.19.tgz", + "integrity": "sha512-VGamgY4PLzSx48IHPoblRw0oTaBa7S26RpZXt0Y4NN90ytoE0LutlpB2484RbkfcTjv9wa64QD474+YP1kEgGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^10.9.1", + "@whatwg-node/promise-helpers": "^1.3.0", + "dataloader": "^2.2.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/batch-execute/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/code-file-loader": { + "version": "8.1.32", + "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.1.32.tgz", + "integrity": "sha512-gR5mNQjn0BugDL8a4A+ovS2KEvU52RNOGnbwiq9oWAEHiSv7iqJu77bpWARTzlE1ZFPK5MSQe9218+1t5PbXmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/graphql-tag-pluck": "8.3.31", + "@graphql-tools/utils": "^11.1.0", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/delegate": { + "version": "10.2.23", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.2.23.tgz", + "integrity": "sha512-xrPtl7f1LxS+B6o+W7ueuQh67CwRkfl+UKJncaslnqYdkxKmNBB4wnzVcW8ZsRdwbsla/v43PtwAvSlzxCzq2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/batch-execute": "^9.0.19", + "@graphql-tools/executor": "^1.4.9", + "@graphql-tools/schema": "^10.0.25", + "@graphql-tools/utils": "^10.9.1", + "@repeaterjs/repeater": "^3.0.6", + "@whatwg-node/promise-helpers": "^1.3.0", + "dataloader": "^2.2.3", + "dset": "^3.1.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/delegate/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/documents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/documents/-/documents-1.0.1.tgz", + "integrity": "sha512-aweoMH15wNJ8g7b2r4C4WRuJxZ0ca8HtNO54rkye/3duxTkW4fGBEutCx03jCIr5+a1l+4vFJNP859QnAVBVCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.5.3.tgz", + "integrity": "sha512-mgBFC0bsrZPZLu9EnydpMnAuQ8Iiq0CEbUcsmvXsm2/iYektGHDN/+bmb7hicA6dWZtdPfklYJmr21WD0GnOfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.1.0", + "@graphql-typed-document-node/core": "^3.2.0", + "@repeaterjs/repeater": "^3.0.4", + "@whatwg-node/disposablestack": "^0.0.6", + "@whatwg-node/promise-helpers": "^1.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-common": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-common/-/executor-common-0.0.4.tgz", + "integrity": "sha512-SEH/OWR+sHbknqZyROCFHcRrbZeUAyjCsgpVWCRjqjqRbiJiXq6TxNIIOmpXgkrXWW/2Ev4Wms6YSGJXjdCs6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@envelop/core": "^5.2.3", + "@graphql-tools/utils": "^10.8.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-common/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-graphql-ws": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-2.0.7.tgz", + "integrity": "sha512-J27za7sKF6RjhmvSOwOQFeNhNHyP4f4niqPnerJmq73OtLx9Y2PGOhkXOEB0PjhvPJceuttkD2O1yMgEkTGs3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/executor-common": "^0.0.6", + "@graphql-tools/utils": "^10.9.1", + "@whatwg-node/disposablestack": "^0.0.6", + "graphql-ws": "^6.0.6", + "isomorphic-ws": "^5.0.0", + "tslib": "^2.8.1", + "ws": "^8.18.3" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-graphql-ws/node_modules/@graphql-tools/executor-common": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-common/-/executor-common-0.0.6.tgz", + "integrity": "sha512-JAH/R1zf77CSkpYATIJw+eOJwsbWocdDjY+avY7G+P5HCXxwQjAjWVkJI1QJBQYjPQDVxwf1fmTZlIN3VOadow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@envelop/core": "^5.3.0", + "@graphql-tools/utils": "^10.9.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-graphql-ws/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-http": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-1.3.3.tgz", + "integrity": "sha512-LIy+l08/Ivl8f8sMiHW2ebyck59JzyzO/yF9SFS4NH6MJZUezA1xThUXCDIKhHiD56h/gPojbkpcFvM2CbNE7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-hive/signal": "^1.0.0", + "@graphql-tools/executor-common": "^0.0.4", + "@graphql-tools/utils": "^10.8.1", + "@repeaterjs/repeater": "^3.0.4", + "@whatwg-node/disposablestack": "^0.0.6", + "@whatwg-node/fetch": "^0.10.4", + "@whatwg-node/promise-helpers": "^1.3.0", + "meros": "^1.2.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-http/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-legacy-ws": { + "version": "1.1.28", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.1.28.tgz", + "integrity": "sha512-O4uj93GG9iUb3s32eyhUohvyfA8mLhN8FvGzEdK628hFQPhZN75yurtVFrR08DHex71mQ3wYCCFkErpwdJbDDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.1.0", + "@types/ws": "^8.0.0", + "isomorphic-ws": "^5.0.0", + "tslib": "^2.4.0", + "ws": "^8.20.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/git-loader": { + "version": "8.0.36", + "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.36.tgz", + "integrity": "sha512-PDDakesRu8FJYHJLf9/gkTweh8M19Bymz9i+vOlk9OTs9XmNcCqKM+1S610KX2AodvuBFz/xbesjTtTJIppLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/graphql-tag-pluck": "8.3.31", + "@graphql-tools/utils": "^11.1.0", + "is-glob": "4.0.3", + "micromatch": "^4.0.8", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/github-loader": { + "version": "8.0.22", + "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-8.0.22.tgz", + "integrity": "sha512-uQ4JNcNPsyMkTIgzeSbsoT9hogLjYrZooLUYd173l5eUGUi49EAcsGdiBCKaKfEjanv410FE8hjaHr7fjSRkJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/executor-http": "^1.1.9", + "@graphql-tools/graphql-tag-pluck": "^8.3.21", + "@graphql-tools/utils": "^10.9.1", + "@whatwg-node/fetch": "^0.10.0", + "@whatwg-node/promise-helpers": "^1.0.0", + "sync-fetch": "0.6.0-2", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/sync-fetch": { + "version": "0.6.0-2", + "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.6.0-2.tgz", + "integrity": "sha512-c7AfkZ9udatCuAy9RSfiGPpeOKKUAUK5e1cXadLOGUjasdxqYqAK0jTNkM/FSEyJ3a5Ra27j/tw/PS0qLmaF/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^3.3.2", + "timeout-signal": "^2.0.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@graphql-tools/graphql-file-loader": { + "version": "8.1.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.1.14.tgz", + "integrity": "sha512-CfAcsSEVkkHfEXLFzrd5rUYpcQEGWNV8lfc1Tb1p5m9HnYICzDDH08I5V33iMrEDza3GuujjjRBYqplBkqwIow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/import": "^7.1.14", + "@graphql-tools/utils": "^11.1.0", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/graphql-tag-pluck": { + "version": "8.3.31", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.3.31.tgz", + "integrity": "sha512-ema2RRPZGj8TKruNElyDBHVCNFMxioGIVfLBuiA+GdfmRGt95b/i7Uksnj4EwItA6MCmhxokxZoa/fl6mJt3tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.6", + "@babel/parser": "^7.29.2", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/traverse": "^7.26.10", + "@babel/types": "^7.26.10", + "@graphql-tools/utils": "^11.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/import": { + "version": "7.1.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-7.1.14.tgz", + "integrity": "sha512-aqLcu04aEidszbXM6M0PWWL8bP17eX9sxXwjYWpglLvIRd4NFqb3C9QzBY8pleqXNMtWqXktlm9BQjevgSrirQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.1.0", + "resolve-from": "5.0.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/json-file-loader": { + "version": "8.0.28", + "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-8.0.28.tgz", + "integrity": "sha512-qgCsSkPArnjlNkcYpgGKiXxCTNkrAT9E+l1LhR+Por2jTlKBBeZ8stortkQ/PNDDjuL0WPrLQmHKhNPHabnB3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.1.0", + "globby": "^11.0.3", + "tslib": "^2.4.0", + "unixify": "^1.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/load": { + "version": "8.1.10", + "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.1.10.tgz", + "integrity": "sha512-hjcvfEFtwtc8vGi46wtpmGWadNzfEhzbjqinyFIZuIZPlR4aYdWQtqWtY/RMM4Ew4t1USkMNm6xrqC2TH1vCSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/schema": "^10.0.33", + "@graphql-tools/utils": "^11.1.0", + "p-limit": "3.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/merge": { + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.1.9.tgz", + "integrity": "sha512-iHUWNjRHeQRYdgIMIuChThOwoKzA9vrzYeslgfBo5eUYEyHGZCoDPjAavssoYXLwstYt1dZj2J22jSzc2DrN0Q==", + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/mock": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/mock/-/mock-9.1.7.tgz", + "integrity": "sha512-JpsmamDwd6PO1Oj437T+pdM5tpV41XrUD3GJsdrAVEtDRljdQvbxVxmt6tXruqMHj6XAOPoS1Ny1e/G3HA7sgg==", + "license": "MIT", + "dependencies": { + "@graphql-tools/schema": "^10.0.33", + "@graphql-tools/utils": "^11.1.0", + "fast-json-stable-stringify": "^2.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/optimize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/optimize/-/optimize-2.0.0.tgz", + "integrity": "sha512-nhdT+CRGDZ+bk68ic+Jw1OZ99YCDIKYA5AlVAnBHJvMawSx9YQqQAIj4refNc1/LRieGiuWvhbG3jvPVYho0Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader": { + "version": "8.0.17", + "resolved": "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-8.0.17.tgz", + "integrity": "sha512-fnuTLeQhqRbA156pAyzJYN0KxCjKYRU5bz1q/SKOwElSnAU4k7/G1kyVsWLh7fneY78LoMNH5n+KlFV8iQlnyg==", + "deprecated": "This package was intended to be used with an older versions of Prisma.\\nThe newer versions of Prisma has a different approach to GraphQL integration.\\nTherefore, this package is no longer needed and has been deprecated and removed.\\nLearn more: https://www.prisma.io/graphql", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/url-loader": "^8.0.15", + "@graphql-tools/utils": "^10.5.6", + "@types/js-yaml": "^4.0.0", + "@whatwg-node/fetch": "^0.10.0", + "chalk": "^4.1.0", + "debug": "^4.3.1", + "dotenv": "^16.0.0", + "graphql-request": "^6.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "jose": "^5.0.0", + "js-yaml": "^4.0.0", + "lodash": "^4.17.20", + "scuid": "^1.1.0", + "tslib": "^2.4.0", + "yaml-ast-parser": "^0.0.43" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@graphql-tools/relay-operation-optimizer": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.1.4.tgz", + "integrity": "sha512-cwOD/GEo/R//1uGCP0/urIxsMFoUgzkJVyMt9BDM2HhQhU6rSgH5l6lFukAFTJyPJVdyeOdYm2i0Jj5vYWbHTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ardatan/relay-compiler": "^13.0.1", + "@graphql-tools/utils": "^11.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/schema": { + "version": "10.0.33", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.33.tgz", + "integrity": "sha512-O6P3RIftO0jafnSsFAqpjurUuUxJ43s/AdPVLQsBkI6y4Ic/tKm4C1Qm1KKQsCDTOxXPJClh/v3g7k7yLKCFBQ==", + "license": "MIT", + "dependencies": { + "@graphql-tools/merge": "^9.1.9", + "@graphql-tools/utils": "^11.1.0", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/url-loader": { + "version": "8.0.33", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.33.tgz", + "integrity": "sha512-Fu626qcNHcqAj8uYd7QRarcJn5XZ863kmxsg1sm0fyjyfBJnsvC7ddFt6Hayz5kxVKfsnjxiDfPMXanvsQVBKw==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.4.3" + "@graphql-tools/executor-graphql-ws": "^2.0.1", + "@graphql-tools/executor-http": "^1.1.9", + "@graphql-tools/executor-legacy-ws": "^1.1.19", + "@graphql-tools/utils": "^10.9.1", + "@graphql-tools/wrap": "^10.0.16", + "@types/ws": "^8.0.0", + "@whatwg-node/fetch": "^0.10.0", + "@whatwg-node/promise-helpers": "^1.0.0", + "isomorphic-ws": "^5.0.0", + "sync-fetch": "0.6.0-2", + "tslib": "^2.4.0", + "ws": "^8.17.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=16.0.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", "dev": true, "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@graphql-tools/url-loader/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/@graphql-tools/url-loader/node_modules/sync-fetch": { + "version": "0.6.0-2", + "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.6.0-2.tgz", + "integrity": "sha512-c7AfkZ9udatCuAy9RSfiGPpeOKKUAUK5e1cXadLOGUjasdxqYqAK0jTNkM/FSEyJ3a5Ra27j/tw/PS0qLmaF/A==", "dev": true, + "license": "MIT", "dependencies": { - "type-fest": "^0.20.2" + "node-fetch": "^3.3.2", + "timeout-signal": "^2.0.0", + "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/@graphql-tools/url-loader/node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" + } + }, + "node_modules/@graphql-tools/utils": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-11.1.0.tgz", + "integrity": "sha512-PtFVG4r8Z2LEBSaPYQMusBiB3o6kjLVJyjCLbnWem/SpSuM21v6LTmgpkXfYU1qpBV2UGsFyuEnSJInl8fR1Ag==", + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "node_modules/@graphql-tools/wrap": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.1.4.tgz", + "integrity": "sha512-7pyNKqXProRjlSdqOtrbnFRMQAVamCmEREilOXtZujxY6kYit3tvWWSjUrcIOheltTffoRh7EQSjpy2JDCzasg==", "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/delegate": "^10.2.23", + "@graphql-tools/schema": "^10.0.25", + "@graphql-tools/utils": "^10.9.1", + "@whatwg-node/promise-helpers": "^1.3.0", + "tslib": "^2.8.1" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=18.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@fontsource/inter": { - "version": "4.5.15", - "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.15.tgz", - "integrity": "sha512-FzleM9AxZQK2nqsTDtBiY0PMEVWvnKnuu2i09+p6DHvrHsuucoV2j0tmw+kAT3L4hvsLdAIDv6MdGehsPIdT+Q==" - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true - }, - "node_modules/@gerrit0/mini-shiki": { - "version": "1.27.2", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-1.27.2.tgz", - "integrity": "sha512-GeWyHz8ao2gBiUW4OJnQDxXQnFgZQwwQk05t/CVVgNBN7/rK8XZ7xY6YhLVv9tH3VppWWmr9DCl3MwemB/i+Og==", + "node_modules/@graphql-tools/wrap/node_modules/@graphql-tools/utils": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.11.0.tgz", + "integrity": "sha512-iBFR9GXIs0gCD+yc3hoNswViL1O5josI33dUqiNStFI/MHLCEPduasceAcazRH77YONKNiviHBV8f7OgcT4o2Q==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/engine-oniguruma": "^1.27.2", - "@shikijs/types": "^1.27.2", - "@shikijs/vscode-textmate": "^10.0.1" + "@graphql-typed-document-node/core": "^3.1.1", + "@whatwg-node/promise-helpers": "^1.0.0", + "cross-inspect": "1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "license": "MIT", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@hey-api/codegen-core": { @@ -7558,6 +9115,13 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/@repeaterjs/repeater": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.6.tgz", + "integrity": "sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/plugin-alias": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz", @@ -9941,6 +11505,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", @@ -10488,6 +12062,110 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@whatwg-node/disposablestack": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@whatwg-node/disposablestack/-/disposablestack-0.0.6.tgz", + "integrity": "sha512-LOtTn+JgJvX8WfBVJtF08TGrdjuFzGJc4mkP8EdDI8ADbvO7kiexYep1o8dwnt0okb0jYclCDXF13xU7Ge4zSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@whatwg-node/promise-helpers": "^1.0.0", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@whatwg-node/fetch": { + "version": "0.10.13", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.13.tgz", + "integrity": "sha512-b4PhJ+zYj4357zwk4TTuF2nEe0vVtOrwdsrNo5hL+u1ojXNhh1FgJ6pg1jzDlwlT4oBdzfSwaBwMCtFCsIWg8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@whatwg-node/node-fetch": "^0.8.3", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@whatwg-node/node-fetch": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.8.5.tgz", + "integrity": "sha512-4xzCl/zphPqlp9tASLVeUhB5+WJHbuWGYpfoC2q1qh5dw0AqZBW7L27V5roxYWijPxj4sspRAAoOH3d2ztaHUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^3.1.1", + "@whatwg-node/disposablestack": "^0.0.6", + "@whatwg-node/promise-helpers": "^1.3.2", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@whatwg-node/promise-helpers": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@whatwg-node/promise-helpers/-/promise-helpers-1.3.2.tgz", + "integrity": "sha512-Nst5JdK47VIl9UcGwtv2Rcgyn5lWtZ0/mhRQ4G8NN2isxpq2TO30iqHzmwoJycjWuyUfg3GFXqP/gFHXeV57IA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@wry/caches": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@wry/caches/-/caches-1.0.1.tgz", + "integrity": "sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/context": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.4.tgz", + "integrity": "sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/equality": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.7.tgz", + "integrity": "sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/trie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.5.0.tgz", + "integrity": "sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@xmldom/xmldom": { "version": "0.8.10", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", @@ -11191,6 +12869,19 @@ "node": ">=4" } }, + "node_modules/auto-bind": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-4.0.0.tgz", + "integrity": "sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/autolinker": { "version": "3.16.2", "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-3.16.2.tgz", @@ -11943,6 +13634,17 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -11993,6 +13695,18 @@ ], "license": "CC-BY-4.0" }, + "node_modules/capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -12032,6 +13746,46 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/change-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", + "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "capital-case": "^1.0.4", + "constant-case": "^3.0.4", + "dot-case": "^3.0.4", + "header-case": "^2.0.4", + "no-case": "^3.0.4", + "param-case": "^3.0.4", + "pascal-case": "^3.1.2", + "path-case": "^3.0.4", + "sentence-case": "^3.0.4", + "snake-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/change-case-all": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/change-case-all/-/change-case-all-1.0.15.tgz", + "integrity": "sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "change-case": "^4.1.2", + "is-lower-case": "^2.0.2", + "is-upper-case": "^2.0.2", + "lower-case": "^2.0.2", + "lower-case-first": "^2.0.2", + "sponge-case": "^1.0.1", + "swap-case": "^2.0.2", + "title-case": "^3.0.3", + "upper-case": "^2.0.2", + "upper-case-first": "^2.0.2" + } + }, "node_modules/char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", @@ -12539,6 +14293,18 @@ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "dev": true }, + "node_modules/constant-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", + "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case": "^2.0.2" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -12671,6 +14437,28 @@ "yarn": ">=1" } }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-inspect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cross-inspect/-/cross-inspect-1.0.1.tgz", + "integrity": "sha512-Pcw1JTvZLSJH83iiGWt6fRcT+BjZlCDRVwYLbUcHzv/CRpB7r0MlSrGbIyQvVSNyGnbt7G4AXuyCiDR3POvZ1A==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -13880,6 +15668,16 @@ "node": ">=0.10" } }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -13945,6 +15743,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dataloader": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz", + "integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==", + "dev": true, + "license": "MIT" + }, "node_modules/date-fns": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", @@ -14216,6 +16021,16 @@ "node": ">= 0.6" } }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -14232,6 +16047,16 @@ "dev": true, "license": "MIT" }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -14425,6 +16250,17 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/dotenv": { "version": "16.4.7", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", @@ -14445,6 +16281,16 @@ "node": ">=4" } }, + "node_modules/dset": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -16241,8 +18087,7 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -16323,6 +18168,30 @@ } } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/fides-js": { "resolved": "fides-js", "link": true @@ -16598,6 +18467,19 @@ "node": ">=0.4.x" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/formik": { "version": "2.4.6", "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.6.tgz", @@ -16988,108 +18870,433 @@ "node": ">= 0.10" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/graphql": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.0.tgz", + "integrity": "sha512-BBvQ/406p+4CZbTpCbVPSxfzrZrbnuWSP1ELYgyS6B+hNeKzgrdB4JczCa5VZUBQrDa9hUngm0KnexY6pJRN5Q==", + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-config": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-5.1.6.tgz", + "integrity": "sha512-fCkYnm4Kdq3un0YIM4BCZHVR5xl0UeLP6syxxO7KAstdY7QVyVvTHP0kRPDYEP1v08uwtJVgis5sj3IOTLOniQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/graphql-file-loader": "^8.0.0", + "@graphql-tools/json-file-loader": "^8.0.0", + "@graphql-tools/load": "^8.1.0", + "@graphql-tools/merge": "^9.0.0", + "@graphql-tools/url-loader": "^9.0.0", + "@graphql-tools/utils": "^11.0.0", + "cosmiconfig": "^8.1.0", + "jiti": "^2.0.0", + "minimatch": "^10.0.0", + "string-env-interpolation": "^1.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 16.0.0" + }, + "peerDependencies": { + "cosmiconfig-toml-loader": "^1.0.0", + "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + }, + "peerDependenciesMeta": { + "cosmiconfig-toml-loader": { + "optional": true + } + } + }, + "node_modules/graphql-config/node_modules/@graphql-hive/signal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@graphql-hive/signal/-/signal-2.0.0.tgz", + "integrity": "sha512-Pz8wB3K0iU6ae9S1fWfsmJX24CcGeTo6hE7T44ucmV/ALKRj+bxClmqrYcDT7v3f0d12Rh4FAXBb6gon+WkDpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/batch-execute": { + "version": "10.0.8", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-10.0.8.tgz", + "integrity": "sha512-Kobt37qrVTFhX4HUK5/vPgMXFw/5f97AzmAlfmDBSRh/GnoAmLKCb48FrEI3gdeIwZB2fEhVHJyDqsojldnLQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^11.0.0", + "@whatwg-node/promise-helpers": "^1.3.2", + "dataloader": "^2.2.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/delegate": { + "version": "12.0.16", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-12.0.16.tgz", + "integrity": "sha512-WEJaFwWG82a0VzhfE4sRsaOPjxgCVfn4fOe3ho+r3uIbPYpc7qHpFdu1PLg6meikq6fuW9NJ1J88fEgnWuXDVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/batch-execute": "^10.0.8", + "@graphql-tools/executor": "^1.4.13", + "@graphql-tools/schema": "^10.0.29", + "@graphql-tools/utils": "^11.0.0", + "@repeaterjs/repeater": "^3.0.6", + "@whatwg-node/promise-helpers": "^1.3.2", + "dataloader": "^2.2.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/executor-common": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-common/-/executor-common-1.0.6.tgz", + "integrity": "sha512-23/K5C+LSlHDI0mj2SwCJ33RcELCcyDUgABm1Z8St7u/4Z5+95i925H/NAjUyggRjiaY8vYtNiMOPE49aPX1sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@envelop/core": "^5.4.0", + "@graphql-tools/utils": "^11.0.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/executor-graphql-ws": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-3.1.5.tgz", + "integrity": "sha512-WXRsfwu9AkrORD9nShrd61OwwxeQ5+eXYcABRR3XPONFIS8pWQfDJGGqxql9/227o/s0DV5SIfkBURb5Knzv+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/executor-common": "^1.0.6", + "@graphql-tools/utils": "^11.0.0", + "@whatwg-node/disposablestack": "^0.0.6", + "graphql-ws": "^6.0.6", + "isows": "^1.0.7", + "tslib": "^2.8.1", + "ws": "^8.18.3" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/executor-http": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-3.3.0.tgz", + "integrity": "sha512-IkKXIjSg9U8MNsQUBVJAXE4+LSxaQ0cs7p5JTALLGDABY1o17vPDRwWALsX81AXD5dY27ihi/+OhGMueW/Fopg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-hive/signal": "^2.0.0", + "@graphql-tools/executor-common": "^1.0.6", + "@graphql-tools/utils": "^11.0.0", + "@repeaterjs/repeater": "^3.0.4", + "@whatwg-node/disposablestack": "^0.0.6", + "@whatwg-node/fetch": "^0.10.13", + "@whatwg-node/promise-helpers": "^1.3.2", + "meros": "^1.3.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/url-loader": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-9.1.2.tgz", + "integrity": "sha512-pVSiPrfWQKb3jq23Pl7EjbB2uv3tgZLnWo/axkmg4itAEZ5s/vV/jKa8P1HZzUnSVUTR+8tcEZVeNsUbzFCbkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/executor-graphql-ws": "^3.1.4", + "@graphql-tools/executor-http": "^3.2.1", + "@graphql-tools/executor-legacy-ws": "^1.1.28", + "@graphql-tools/utils": "^11.1.0", + "@graphql-tools/wrap": "^11.1.1", + "@types/ws": "^8.0.0", + "@whatwg-node/fetch": "^0.10.13", + "@whatwg-node/promise-helpers": "^1.0.0", + "isomorphic-ws": "^5.0.0", + "sync-fetch": "0.6.0", + "tslib": "^2.4.0", + "ws": "^8.20.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/wrap": { + "version": "11.1.15", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-11.1.15.tgz", + "integrity": "sha512-GCMx6l0MPwHVaBMHf29oG8eIrsJ8PBXq9y5DNX9/r9oCpCBfqxfWzcejx4CpO4chA3+yylGOKcAyEbOUgxfI1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/delegate": "^12.0.16", + "@graphql-tools/schema": "^10.0.29", + "@graphql-tools/utils": "^11.0.0", + "@whatwg-node/promise-helpers": "^1.3.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/graphql-config/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=10.13.0" + "node": "18 || 20 || >=22" } }, - "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "node_modules/graphql-config/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, + "license": "MIT", "dependencies": { - "ini": "2.0.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "node_modules/graphql-config/node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/graphql-config/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">=10" + "node": "18 || 20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "engines": { - "node": ">= 0.4" + "node_modules/graphql-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz", + "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0", + "cross-fetch": "^3.1.5" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "graphql": "14 - 16" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "node_modules/graphql-tag": { + "version": "2.12.6", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", + "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", + "license": "MIT", "dependencies": { - "lodash": "^4.17.15" + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/graphql": { - "version": "16.12.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.12.0.tgz", - "integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==", - "dev": true, + "node_modules/graphql-ws": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.8.tgz", + "integrity": "sha512-m3EOaNsUBXwAnkBWbzPfe0Nq8pXUfxsWnolC54sru3FzHvhTZL0Ouf/BoQsaGAXqM+YPerXOJ47BUnmgmoupCw==", + "devOptional": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + "node": ">=20" + }, + "peerDependencies": { + "@fastify/websocket": "^10 || ^11", + "crossws": "~0.3", + "graphql": "^15.10.1 || ^16", + "ws": "^8" + }, + "peerDependenciesMeta": { + "@fastify/websocket": { + "optional": true + }, + "crossws": { + "optional": true + }, + "ws": { + "optional": true + } } }, "node_modules/gzip-size": { @@ -17310,6 +19517,17 @@ "he": "bin/he" } }, + "node_modules/header-case": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", + "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "capital-case": "^1.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/headers-polyfill": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", @@ -17796,9 +20014,10 @@ } }, "node_modules/immutable": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", - "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==" + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "license": "MIT" }, "node_modules/import-cwd": { "version": "3.0.0", @@ -18025,6 +20244,20 @@ "node": ">= 12" } }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-alphabetical": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", @@ -18402,6 +20635,16 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, + "node_modules/is-lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz", + "integrity": "sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -18542,6 +20785,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-set": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", @@ -18634,6 +20890,19 @@ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -18646,6 +20915,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz", + "integrity": "sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -18695,6 +20974,16 @@ "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", "dev": true }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -18728,6 +21017,32 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -19833,6 +22148,16 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", @@ -20024,6 +22349,20 @@ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, + "node_modules/json-to-pretty-yaml": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz", + "integrity": "sha512-rvm6hunfCcqegwYaG5T4yKJWxc9FXFgBVrcTZ4XfSVRwa5HA/Xs+vB/Eo9treYYHCeNM0nrSUr82V/M31Urc7A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "remedial": "^1.0.7", + "remove-trailing-spaces": "^1.0.6" + }, + "engines": { + "node": ">= 0.2.0" + } + }, "node_modules/json2mq": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", @@ -20893,6 +23232,13 @@ "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.throttle": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", @@ -20988,6 +23334,26 @@ "dev": true, "license": "MIT" }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lower-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-2.0.2.tgz", + "integrity": "sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lowlight": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", @@ -21249,6 +23615,16 @@ "tmpl": "1.0.5" } }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/markdown-it": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", @@ -21373,6 +23749,24 @@ "uuid": "dist/esm/bin/uuid" } }, + "node_modules/meros": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.2.tgz", + "integrity": "sha512-Q3mobPbvEx7XbwhnC1J1r60+5H6EZyNccdzSz0eGexJRwouUtTZxPVRGdqKtxlpD84ScK4+tIGldkqDtCKdI0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=13" + }, + "peerDependencies": { + "@types/node": ">=13" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -22093,6 +24487,17 @@ "next": ">=9" } }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -22105,6 +24510,27 @@ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "optional": true }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -22820,6 +25246,18 @@ "opener": "bin/opener-bin.js" } }, + "node_modules/optimism": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.1.tgz", + "integrity": "sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==", + "license": "MIT", + "dependencies": { + "@wry/caches": "^1.0.0", + "@wry/context": "^0.7.0", + "@wry/trie": "^0.5.0", + "tslib": "^2.3.0" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -23114,6 +25552,17 @@ "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==" }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -23144,6 +25593,21 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/parse-imports": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", @@ -23210,6 +25674,28 @@ "node": ">= 0.8" } }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", + "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/path-data-parser": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", @@ -23247,6 +25733,29 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -25194,6 +27703,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/rehackt": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/rehackt/-/rehackt-0.1.0.tgz", + "integrity": "sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/remarkable": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-2.0.1.tgz", @@ -25222,6 +27749,30 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, + "node_modules/remedial": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/remedial/-/remedial-1.0.8.tgz", + "integrity": "sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "engines": { + "node": "*" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true, + "license": "ISC" + }, + "node_modules/remove-trailing-spaces": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/remove-trailing-spaces/-/remove-trailing-spaces-1.0.9.tgz", + "integrity": "sha512-xzG7w5IRijvIkHIjDk65URsJJ7k4J95wmcArY5PRcmjldIOl7oTvG8+X2Ag690R7SfwiOcHrWZKVc1Pp5WIOzA==", + "dev": true, + "license": "MIT" + }, "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", @@ -25944,6 +28495,13 @@ "compute-scroll-into-view": "^3.0.2" } }, + "node_modules/scuid": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz", + "integrity": "sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg==", + "dev": true, + "license": "MIT" + }, "node_modules/secure-json-parse": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", @@ -25964,6 +28522,18 @@ "node": ">=10" } }, + "node_modules/sentence-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", + "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, "node_modules/serialize-error": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", @@ -26151,6 +28721,19 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/short-unique-id": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/short-unique-id/-/short-unique-id-5.3.2.tgz", @@ -26378,6 +28961,17 @@ "npm": ">= 3.0.0" } }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/socks": { "version": "2.8.4", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", @@ -26522,6 +29116,16 @@ "node": ">= 10.x" } }, + "node_modules/sponge-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sponge-case/-/sponge-case-1.0.1.tgz", + "integrity": "sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", @@ -26735,6 +29339,13 @@ "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==", "license": "MIT" }, + "node_modules/string-env-interpolation": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz", + "integrity": "sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==", + "dev": true, + "license": "MIT" + }, "node_modules/string-hash": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", @@ -27437,12 +30048,75 @@ "immutable": "^3.8.1 || ^4.0.0-rc.1" } }, + "node_modules/swap-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-2.0.2.tgz", + "integrity": "sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/sync-fetch": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.6.0.tgz", + "integrity": "sha512-IELLEvzHuCfc1uTsshPK58ViSdNqXxlml1U+fmwJIKLYKOr/rAtBrorE2RYm5IHaMpDNlmC0fr1LAvdXvyheEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^3.3.2", + "timeout-signal": "^2.0.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/sync-fetch/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/sync-fetch/node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/synckit": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", @@ -27804,6 +30478,16 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, + "node_modules/timeout-signal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/timeout-signal/-/timeout-signal-2.0.0.tgz", + "integrity": "sha512-YBGpG4bWsHoPvofT6y/5iqulfXIiIErl5B0LdtHT1mGXDFTAhhRrbUpTvBgYbovr+3cKblya2WAOcpoy90XguA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/tiny-case": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", @@ -27866,6 +30550,16 @@ "node": ">=14.0.0" } }, + "node_modules/title-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-3.0.3.tgz", + "integrity": "sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/tldts": { "version": "6.1.84", "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.84.tgz", @@ -28057,6 +30751,18 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/ts-invariant": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", + "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ts-jest": { "version": "29.2.6", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.6.tgz", @@ -28105,6 +30811,13 @@ } } }, + "node_modules/ts-log": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.7.tgz", + "integrity": "sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==", + "dev": true, + "license": "MIT" + }, "node_modules/ts-mixer": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", @@ -28637,6 +31350,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -28676,6 +31399,32 @@ "node": ">= 10.0.0" } }, + "node_modules/unixify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", + "integrity": "sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "normalize-path": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unixify/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/unplugin": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", @@ -28764,6 +31513,26 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", + "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -28782,6 +31551,13 @@ "requires-port": "^1.0.0" } }, + "node_modules/urlpattern-polyfill": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz", + "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==", + "dev": true, + "license": "MIT" + }, "node_modules/use-callback-ref": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", @@ -29042,6 +31818,16 @@ "@zxing/text-encoding": "0.9.0" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/web-tree-sitter": { "version": "0.24.5", "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.24.5.tgz", @@ -29424,10 +32210,11 @@ } }, "node_modules/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", - "dev": true, + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "devOptional": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -29528,6 +32315,13 @@ "node": ">= 6" } }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -29667,6 +32461,21 @@ "node": "^12.20.0 || >=14" } }, + "node_modules/zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==", + "license": "MIT" + }, + "node_modules/zen-observable-ts": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz", + "integrity": "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==", + "license": "MIT", + "dependencies": { + "zen-observable": "0.8.15" + } + }, "node_modules/zenscroll": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/zenscroll/-/zenscroll-4.0.2.tgz", From f3d235dd6ce69ae360496ed36eee65f9f503b54a Mon Sep 17 00:00:00 2001 From: Karolis Date: Fri, 15 May 2026 11:17:04 -0400 Subject: [PATCH 02/10] graphql poc apollo: proxy /graphql to backend for real-BE path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Strawberry endpoint is mounted at /graphql, outside the /api/v1 prefix the existing rewrites cover, so against the real backend the client's POST /graphql would 404 on the Next dev server. Add a rewrite mirroring the existing /health one. Mock mode is unaffected — MSW intercepts /graphql before the rewrite. Local PoC branch — do not push. --- clients/admin-ui/next.config.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clients/admin-ui/next.config.js b/clients/admin-ui/next.config.js index e5376928c95..f375e76a34b 100644 --- a/clients/admin-ui/next.config.js +++ b/clients/admin-ui/next.config.js @@ -67,6 +67,13 @@ const nextConfig = { source: `/health`, destination: `${process.env.NEXT_PUBLIC_FIDESCTL_API_SERVER}/health`, }, + // GraphQL PoC: the Strawberry endpoint is mounted at /graphql (not under + // /api/v1), so proxy it to the backend for the real-BE path. In mock + // mode MSW intercepts /graphql before it reaches this rewrite. + { + source: `/graphql`, + destination: `${process.env.NEXT_PUBLIC_FIDESCTL_API_SERVER}/graphql`, + }, ]; }, }; From 065ab7f9a80153a6c80a0ec6ac44501483708c4f Mon Sep 17 00:00:00 2001 From: Karolis Date: Fri, 15 May 2026 12:18:50 -0400 Subject: [PATCH 03/10] graphql poc apollo: register /dashboard-graphql route MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ProtectedRoute redirects to / when useNav finds no active match for the path. Add the variant route to NAV_CONFIG as hidden (reachable by URL, not shown in the sidebar) so the PoC page is accessible. Local PoC branch — do not push. --- clients/admin-ui/src/features/common/nav/nav-config.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clients/admin-ui/src/features/common/nav/nav-config.tsx b/clients/admin-ui/src/features/common/nav/nav-config.tsx index 4baed5756ec..be01a068ff8 100644 --- a/clients/admin-ui/src/features/common/nav/nav-config.tsx +++ b/clients/admin-ui/src/features/common/nav/nav-config.tsx @@ -65,6 +65,15 @@ export const NAV_CONFIG: NavConfigGroup[] = [ exact: true, scopes: [], }, + { + // GraphQL PoC variant of the dashboard. Hidden from the sidebar but + // reachable by URL so it can be compared against the REST dashboard. + title: "Dashboard (GraphQL)", + path: "/dashboard-graphql", + exact: true, + hidden: true, + scopes: [], + }, ], }, { From 3d65050524ca6b33541ac8ec4b2ff941f1617511 Mon Sep 17 00:00:00 2001 From: Karolis Date: Fri, 15 May 2026 12:22:29 -0400 Subject: [PATCH 04/10] graphql poc apollo: post to /graphql, not /api/v1/graphql MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NEXT_PUBLIC_FIDESCTL_API is /api/v1 in local dev (not empty as the client assumed), so the prior URI resolved to /api/v1/graphql and 404'd against the backend, which mounts GraphQL at the app root /graphql. Use the relative /graphql path so the Next rewrite proxies it to the backend and MSW still intercepts it in mock mode. Local PoC branch — do not push. --- .../admin-ui/src/features/dashboard-graphql/apolloClient.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clients/admin-ui/src/features/dashboard-graphql/apolloClient.ts b/clients/admin-ui/src/features/dashboard-graphql/apolloClient.ts index 4d96d52e09b..8208d3754f8 100644 --- a/clients/admin-ui/src/features/dashboard-graphql/apolloClient.ts +++ b/clients/admin-ui/src/features/dashboard-graphql/apolloClient.ts @@ -8,8 +8,12 @@ import { setContext } from "@apollo/client/link/context"; import { addCommonHeaders } from "~/features/common/CommonHeaders"; +// The Strawberry endpoint is mounted at the app root (/graphql), NOT under +// the /api/v1 prefix that NEXT_PUBLIC_FIDESCTL_API points at. Post to the +// relative /graphql path: in dev the Next rewrite proxies it to the backend, +// and in mock mode MSW intercepts it. const httpLink = createHttpLink({ - uri: `${process.env.NEXT_PUBLIC_FIDESCTL_API ?? ""}/graphql`, + uri: "/graphql", }); /** From 2647d8f838f74806659e0227a1d4c019a5d9be0f Mon Sep 17 00:00:00 2001 From: Karolis Date: Fri, 15 May 2026 14:53:56 -0400 Subject: [PATCH 05/10] graphql poc apollo: wire real dashboard to gql, drop variant page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dashboard at / now fetches through Apollo. Per-card queries (not one combined query) to preserve independent auth failure and progressive per-card loading, matching REST behaviour and the LLM-backed agent briefing's latency. - src/features/dashboard-graphql/queries.graphql: 8 per-card operations - src/features/dashboard-graphql/hooks.ts: drop-in replacements with the exact RTK hook names/signatures/return shapes, mapping camelCase gql responses onto the existing snake_case ~/features/dashboard/types so each card changes only its import path - 9 one-line import swaps in src/home/* - ApolloProvider moved into _app.tsx (inside Redux Provider) so the home dashboard subtree has it - deleted pages/dashboard-graphql.tsx + DashboardGraphqlView + the hidden nav entry; removed the monolithic dashboard.graphql - dashboard.slice.ts kept (update mutation stays on RTK) Local PoC branch — do not push. --- POC-NOTES.md | 82 +++--- .../admin-ui/src/__generated__/graphql/gql.ts | 6 +- .../src/__generated__/graphql/graphql.ts | 61 +++- .../src/features/common/nav/nav-config.tsx | 9 - .../DashboardGraphqlView.tsx | 200 ------------- .../src/features/dashboard-graphql/hooks.ts | 270 ++++++++++++++++++ .../{dashboard.graphql => queries.graphql} | 39 ++- .../admin-ui/src/home/AgentBriefingBanner.tsx | 2 +- clients/admin-ui/src/home/AstralisPanel.tsx | 2 +- clients/admin-ui/src/home/DSRStatusCard.tsx | 2 +- clients/admin-ui/src/home/HomeDashboard.tsx | 2 +- .../src/home/PostureBreakdownContent.tsx | 2 +- clients/admin-ui/src/home/PostureCard.tsx | 2 +- .../admin-ui/src/home/PriorityActionsCard.tsx | 2 +- .../admin-ui/src/home/SystemCoverageCard.tsx | 2 +- .../src/home/useInfiniteActivityFeed.ts | 2 +- clients/admin-ui/src/pages/_app.tsx | 61 ++-- .../admin-ui/src/pages/dashboard-graphql.tsx | 15 - 18 files changed, 437 insertions(+), 324 deletions(-) delete mode 100644 clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlView.tsx create mode 100644 clients/admin-ui/src/features/dashboard-graphql/hooks.ts rename clients/admin-ui/src/features/dashboard-graphql/{dashboard.graphql => queries.graphql} (68%) delete mode 100644 clients/admin-ui/src/pages/dashboard-graphql.tsx diff --git a/POC-NOTES.md b/POC-NOTES.md index 5f20570d3e7..8059e12f826 100644 --- a/POC-NOTES.md +++ b/POC-NOTES.md @@ -1,68 +1,68 @@ # GraphQL PoC — Frontend (Apollo) notes — `graphql-poc-apollo` -Paired BE branch: `graphql-poc-be` in **fidesplus** at commit `104cba76c`. +Paired BE branch: `graphql-poc-be` in **fidesplus** (HEAD `e45dc01b1`; SDL unchanged since `104cba76c`). Sibling FE branch (urql): `graphql-poc-urql` in fides. -The dashboard PoC variant route lives at `/dashboard-graphql`. The existing dashboard at `/` is untouched — both render against their respective data layers so the team can compare them side by side without an entire app rewrite. +**The real dashboard at `/` now runs on GraphQL.** There is no separate page — the existing `HomeDashboard` cards fetch through Apollo via per-card queries. The standalone `/dashboard-graphql` route and its bespoke view were removed. -## Try it locally +## Architecture: per-card queries, drop-in hooks -```bash -# With mocks (no BE needed, schema-driven via @graphql-tools/mock): -NEXT_PUBLIC_MOCK_GRAPHQL=true npm run dev -w admin-ui -# or: cd clients/admin-ui && npm run dev:mock-graphql +Each card keeps its own query (not one combined query). Decision rationale (discussed with the team): -# Against the real BE (run the fidesplus graphql-poc-be branch): -npm run dev -w admin-ui # the env var stays off +- **Independent auth.** Cards map to different permissions/feature flags in the real product. Per-card queries fail independently — an unauthorised card hides itself, the rest of the dashboard is unaffected — exactly mirroring the REST behaviour. One combined query would force field-level auth + partial-error handling on the client. +- **Progressive loading.** One combined query blocks the whole dashboard on the slowest resolver, and `agent_briefing` is LLM-backed (slow). Per-card preserves card-by-card spinner-then-paint. -open http://localhost:3000/dashboard-graphql -``` +Implementation keeps the blast radius tiny: `src/features/dashboard-graphql/hooks.ts` exports replacements with the **exact names, signatures, and return shapes** of the dashboard RTK Query hooks, mapping each camelCase GraphQL response back onto the existing snake_case `~/features/dashboard/types` interfaces. Every card changed by **one line** — its import path. Card JSX/logic is untouched. -After a schema change: +`dashboard.slice.ts` is intentionally left in place (the priority-action update mutation stays on RTK; other code/tests may import it). The GraphQL surface replaces only the read queries the dashboard consumes. + +## Try it locally ```bash -# 1. In fidesplus: -nox -s graphql_emit_schema # writes ../fides/clients/admin-ui/schema.graphql +# Mocks, no BE (schema-driven via @graphql-tools/mock): +cd clients/admin-ui && npm run dev:mock-graphql -# 2. In admin-ui: -npm run graphql:generate # codegen + sync schema-string.ts -``` +# Against the real BE (fidesplus on graphql-poc-be): +cd clients/admin-ui && npm run dev -## Comparison metrics (Apollo) +open http://localhost:3000/ # the real dashboard, now on GraphQL +``` -> The numbers below count only what was written by hand to author + consume a single typed query. Generated code is excluded. +The dashboard cards render under the `alphaDashboard` feature flag (same as before this change). -- **FE lines of code per query (Apollo)** - - `dashboard.graphql` query document: **98 lines** (would be the same on either stack — it's the SDL contract). - - Provider + Apollo client + auth link: `DashboardGraphqlProvider.tsx` 13 + `apolloClient.ts` 35 = **48 lines**. - - Hook usage in the view: 1 line (`useQuery(DashboardOverviewDocument)`). - - Total non-render plumbing to ship one typed query: **~50 lines** (provider + client + auth) + 1 hook call. +After a schema change: `nox -s graphql_emit_schema` in fidesplus, then `npm run graphql:generate` in admin-ui. -- **Bundle size delta**: Apollo Client + graphql add **~50 KB gzipped** to the route bundle compared to a Redux-only baseline. Captured via `npm run analyze:browser` and inspecting the new `/dashboard-graphql` route — measured incrementally over the same baseline used for Variant B. +## Comparison metrics (Apollo) -- **Setup time** (excluding the shared BE work on `graphql-poc-be`): **~2 hours**. Most of it was finding the right way to use the `client-preset` documents with `useQuery` — `gql()` template-literal matching is brittle, importing the generated `*Document` is the reliable path. +- **FE lines of code to wire the whole dashboard** + - `queries.graphql` (8 per-card operations): ~110 lines (SDL-shaped; identical on the urql branch). + - Provider + Apollo client + auth link: `DashboardGraphqlProvider.tsx` 13 + `apolloClient.ts` ~36 = **~49 lines**. + - `hooks.ts` drop-in adapter layer (8 hooks + camel→snake mappers): **~250 lines**. This is the real Apollo-specific surface; most of it is the response remapping that exists only because we kept the REST-shaped card contracts. + - Per card: **1 line** (the import path). +- **Bundle size delta**: Apollo Client + graphql ≈ **~50 KB gzipped** added. Run `npm run analyze:browser` and diff the home route chunk for an exact figure (estimate pending real measurement). +- **Setup time** (excluding shared BE): the original single-query wiring ~2 h; the per-card refactor + drop-in hook layer ~1.5 h on top. ## Rough edges -- The `client-preset` `gql()` template-literal type only resolves when the inline template-literal whitespace matches the source `.graphql` document byte-for-byte. Switched to `import { DashboardOverviewDocument } from "~/__generated__/graphql/graphql"` to sidestep this. The docs don't call this out. -- Mocking with `@graphql-tools/mock` requires the SDL as a runtime string. There's no first-class "import .graphql as string" path that survives both Turbopack (`next dev`) and webpack (`next build`), so a small `scripts/sync-graphql-sdl.mjs` step writes `schema-string.ts` from `schema.graphql` whenever codegen runs. Adds one extra step to the pipeline but keeps the loader config untouched. -- Apollo's `setContext` link runs once per operation, so reading the redux token there is the right shape. Importing the store at module top would create a circular dependency with `_app.tsx`; the apollo client lazy-imports the store instead. -- `process.env.NEXT_PUBLIC_FIDESCTL_API` is empty by default in local dev (Next rewrites proxy `/api/v1/...`), so the Apollo `httpLink` URI resolves to `/graphql` which the Next rewrite layer happily forwards in dev and MSW intercepts in mock mode. Good — no extra config needed. +- **The adapter layer is the cost.** Keeping the existing card contracts (snake_case `types.ts`) means every GraphQL response is remapped by hand in `hooks.ts`. If the cards were rewritten to consume the generated gql types directly, that ~250-line layer mostly disappears — but then it's not a drop-in and the diff explodes across 8 components. The drop-in tradeoff is deliberate for a PoC; a real migration would bite the bullet and consume gql types directly. +- **Enum value skew.** Most enums share string values between the gql SDL and `types.ts`, *except* `TrendPeriod` (SDL `thirty_days` vs REST `30d`) — needs an explicit map. Easy to miss. +- **`ActivityFeedItem` has no `id`** in the schema, but the infinite-scroll dedupe keys on `id`. The adapter synthesises `id = ${timestamp}__${message}` so `useInfiniteActivityFeed` works unmodified. A real schema should expose a stable id. +- **`client-preset` `gql()` template-literal typing is brittle** (whitespace-sensitive). Importing the generated `*Document` constants is the reliable path; all hooks do that. +- **SDL-as-runtime-string for mocks**: no bundler-agnostic ".graphql as string" import, so `scripts/sync-graphql-sdl.mjs` writes `schema-string.ts` from `schema.graphql` during `graphql:generate`. +- **Client URL**: the endpoint is at root `/graphql`, not under `NEXT_PUBLIC_FIDESCTL_API` (`/api/v1`). The client posts to a hard `/graphql`; a Next rewrite proxies it to the backend and MSW intercepts it in mock mode. (Earlier this PoC wrongly assumed that env var was empty.) ## What ships in this branch -- `clients/admin-ui/schema.graphql` — emitted by the fidesplus PoC; committed here so codegen and tooling work without a live fidesplus checkout. -- `clients/admin-ui/codegen.ts` — `client-preset` config. -- `clients/admin-ui/scripts/sync-graphql-sdl.mjs` — SDL → TS-constant emitter. -- `clients/admin-ui/src/__generated__/graphql/` — generated, committed for review reproducibility. -- `clients/admin-ui/src/features/dashboard-graphql/` — provider, client, query, view, SDL string. -- `clients/admin-ui/src/mocks/dashboard-graphql/handlers.ts` — `@graphql-tools/mock`-driven MSW handler. -- `clients/admin-ui/src/pages/dashboard-graphql.tsx` — the variant route. -- Two new npm scripts: `graphql:generate`, `dev:mock-graphql`. +- `clients/admin-ui/schema.graphql` — emitted by the fidesplus PoC. +- `clients/admin-ui/codegen.ts`, `scripts/sync-graphql-sdl.mjs`, `src/__generated__/graphql/`. +- `src/features/dashboard-graphql/`: `DashboardGraphqlProvider.tsx`, `apolloClient.ts`, `queries.graphql` (8 ops), `hooks.ts` (drop-in adapters), `schema-string.ts`. +- `src/mocks/dashboard-graphql/handlers.ts` — schema-driven MSW handler (mocks every per-card query). +- 9 one-line import swaps in `src/home/*` + `_app.tsx` provider wiring + `next.config.js` `/graphql` proxy. +- npm scripts: `graphql:generate`, `dev:mock-graphql`. ## Not done / out of scope - No mutations, no subscriptions, no SSR. -- No replacement of existing RTK Query dashboard slices — the GraphQL surface is purely additive. -- No Apollo dev-tools setup beyond the default `connectToDevTools` flag. -- No persisted queries, no Apollo Studio, no schema registry. +- `dashboard.slice.ts` kept (mutations + potential other consumers); only read queries moved to gql. +- No `@defer` (would mitigate the combined-query loading problem, but we went per-card instead). +- No persisted queries, Apollo Studio, or schema registry. diff --git a/clients/admin-ui/src/__generated__/graphql/gql.ts b/clients/admin-ui/src/__generated__/graphql/gql.ts index d1ae416ca4c..3103a97827c 100644 --- a/clients/admin-ui/src/__generated__/graphql/gql.ts +++ b/clients/admin-ui/src/__generated__/graphql/gql.ts @@ -14,10 +14,10 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { - "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days, $actionsPage: Int! = 1, $actionsSize: Int! = 8, $activityPage: Int! = 1, $activitySize: Int! = 20) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n priorityActions(page: $actionsPage, size: $actionsSize) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n activityFeed(page: $activityPage, size: $activitySize) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": typeof types.DashboardOverviewDocument, + "query DashboardPosture {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n}\n\nquery DashboardTrends($period: TrendPeriod! = thirty_days) {\n trends(period: $period) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n}\n\nquery DashboardSystemCoverage {\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n}\n\nquery DashboardPrivacyRequests {\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardAstralis {\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n}\n\nquery DashboardAgentBriefing {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": typeof types.DashboardPostureDocument, }; const documents: Documents = { - "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days, $actionsPage: Int! = 1, $actionsSize: Int! = 8, $activityPage: Int! = 1, $activitySize: Int! = 20) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n priorityActions(page: $actionsPage, size: $actionsSize) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n activityFeed(page: $activityPage, size: $activitySize) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": types.DashboardOverviewDocument, + "query DashboardPosture {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n}\n\nquery DashboardTrends($period: TrendPeriod! = thirty_days) {\n trends(period: $period) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n}\n\nquery DashboardSystemCoverage {\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n}\n\nquery DashboardPrivacyRequests {\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardAstralis {\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n}\n\nquery DashboardAgentBriefing {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": types.DashboardPostureDocument, }; /** @@ -37,7 +37,7 @@ export function gql(source: string): unknown; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days, $actionsPage: Int! = 1, $actionsSize: Int! = 8, $activityPage: Int! = 1, $activitySize: Int! = 20) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n priorityActions(page: $actionsPage, size: $actionsSize) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n activityFeed(page: $activityPage, size: $activitySize) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"): (typeof documents)["query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days, $actionsPage: Int! = 1, $actionsSize: Int! = 8, $activityPage: Int! = 1, $activitySize: Int! = 20) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n priorityActions(page: $actionsPage, size: $actionsSize) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n activityFeed(page: $activityPage, size: $activitySize) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"]; +export function gql(source: "query DashboardPosture {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n}\n\nquery DashboardTrends($period: TrendPeriod! = thirty_days) {\n trends(period: $period) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n}\n\nquery DashboardSystemCoverage {\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n}\n\nquery DashboardPrivacyRequests {\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardAstralis {\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n}\n\nquery DashboardAgentBriefing {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"): (typeof documents)["query DashboardPosture {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n}\n\nquery DashboardTrends($period: TrendPeriod! = thirty_days) {\n trends(period: $period) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n}\n\nquery DashboardSystemCoverage {\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n}\n\nquery DashboardPrivacyRequests {\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardAstralis {\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n}\n\nquery DashboardAgentBriefing {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"]; export function gql(source: string) { return (documents as any)[source] ?? {}; diff --git a/clients/admin-ui/src/__generated__/graphql/graphql.ts b/clients/admin-ui/src/__generated__/graphql/graphql.ts index 35bded9cef3..595404b46d1 100644 --- a/clients/admin-ui/src/__generated__/graphql/graphql.ts +++ b/clients/admin-ui/src/__generated__/graphql/graphql.ts @@ -226,16 +226,61 @@ export type Trends = { period: TrendPeriod; }; -export type DashboardOverviewQueryVariables = Exact<{ - trendPeriod?: TrendPeriod; - actionsPage?: Scalars['Int']['input']; - actionsSize?: Scalars['Int']['input']; - activityPage?: Scalars['Int']['input']; - activitySize?: Scalars['Int']['input']; +export type DashboardPostureQueryVariables = Exact<{ [key: string]: never; }>; + + +export type DashboardPostureQuery = { __typename?: 'Query', posture: { __typename?: 'Posture', score: number, band: PostureBand, diffPercent: number, diffDirection: DiffDirection, agentAnnotation: string, dimensions: Array<{ __typename?: 'PostureDimension', dimension: string, label: string, weight: number, score: number, band: PostureBand }> } }; + +export type DashboardTrendsQueryVariables = Exact<{ + period?: TrendPeriod; +}>; + + +export type DashboardTrendsQuery = { __typename?: 'Query', trends: { __typename?: 'Trends', period: TrendPeriod, metrics: Array<{ __typename?: 'TrendMetric', key: string, value: number, history: Array, metadata: Record, diff: number }> } }; + +export type DashboardSystemCoverageQueryVariables = Exact<{ [key: string]: never; }>; + + +export type DashboardSystemCoverageQuery = { __typename?: 'Query', systemCoverage: { __typename?: 'SystemCoverage', totalSystems: number, fullyClassified: number, partiallyClassified: number, unclassified: number, withoutSteward: number, coveragePercentage: number } }; + +export type DashboardPrivacyRequestsQueryVariables = Exact<{ [key: string]: never; }>; + + +export type DashboardPrivacyRequestsQuery = { __typename?: 'Query', privacyRequests: { __typename?: 'PrivacyRequests', activeCount: number, overdueCount: number, statuses: { __typename?: 'PrivacyRequestStatuses', inProgress: number, pendingAction: number, awaitingApproval: number }, slaHealth: Array<{ __typename?: 'SLAHealthBucket', label: string, onTrack: number, approaching: number, overdue: number }> } }; + +export type DashboardPriorityActionsQueryVariables = Exact<{ + page?: Scalars['Int']['input']; + size?: Scalars['Int']['input']; + dimension?: InputMaybe; +}>; + + +export type DashboardPriorityActionsQuery = { __typename?: 'Query', priorityActions: { __typename?: 'PriorityActionsPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'PriorityAction', id: string, type: DashboardActionType, severity: ActionSeverity, title: string, message: string, agentSummary: string, dueDate?: string | null, actionData: Record, status: DashboardActionStatus }> } }; + +export type DashboardAstralisQueryVariables = Exact<{ [key: string]: never; }>; + + +export type DashboardAstralisQuery = { __typename?: 'Query', astralis: { __typename?: 'Astralis', activeConversations: number, completedAssessments: number, awaitingResponse: number, risksIdentified: number } }; + +export type DashboardAgentBriefingQueryVariables = Exact<{ [key: string]: never; }>; + + +export type DashboardAgentBriefingQuery = { __typename?: 'Query', agentBriefing: { __typename?: 'AgentBriefing', briefing: string, quickActions: Array<{ __typename?: 'QuickAction', label: string, actionType: DashboardActionType, severity: ActionSeverity, actionData: Record }> } }; + +export type DashboardActivityFeedQueryVariables = Exact<{ + page?: Scalars['Int']['input']; + size?: Scalars['Int']['input']; }>; -export type DashboardOverviewQuery = { __typename?: 'Query', posture: { __typename?: 'Posture', score: number, band: PostureBand, diffPercent: number, diffDirection: DiffDirection, agentAnnotation: string, dimensions: Array<{ __typename?: 'PostureDimension', dimension: string, label: string, weight: number, score: number, band: PostureBand }> }, trends: { __typename?: 'Trends', period: TrendPeriod, metrics: Array<{ __typename?: 'TrendMetric', key: string, value: number, history: Array, metadata: Record, diff: number }> }, systemCoverage: { __typename?: 'SystemCoverage', totalSystems: number, fullyClassified: number, partiallyClassified: number, unclassified: number, withoutSteward: number, coveragePercentage: number }, privacyRequests: { __typename?: 'PrivacyRequests', activeCount: number, overdueCount: number, statuses: { __typename?: 'PrivacyRequestStatuses', inProgress: number, pendingAction: number, awaitingApproval: number }, slaHealth: Array<{ __typename?: 'SLAHealthBucket', label: string, onTrack: number, approaching: number, overdue: number }> }, priorityActions: { __typename?: 'PriorityActionsPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'PriorityAction', id: string, type: DashboardActionType, severity: ActionSeverity, title: string, message: string, agentSummary: string, dueDate?: string | null, actionData: Record, status: DashboardActionStatus }> }, astralis: { __typename?: 'Astralis', activeConversations: number, completedAssessments: number, awaitingResponse: number, risksIdentified: number }, agentBriefing: { __typename?: 'AgentBriefing', briefing: string, quickActions: Array<{ __typename?: 'QuickAction', label: string, actionType: DashboardActionType, severity: ActionSeverity, actionData: Record }> }, activityFeed: { __typename?: 'ActivityFeedPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'ActivityFeedItem', actorType: ActorType, message: string, timestamp: string }> } }; +export type DashboardActivityFeedQuery = { __typename?: 'Query', activityFeed: { __typename?: 'ActivityFeedPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'ActivityFeedItem', actorType: ActorType, message: string, timestamp: string }> } }; -export const DashboardOverviewDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardOverview"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"trendPeriod"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TrendPeriod"}}},"defaultValue":{"kind":"EnumValue","value":"thirty_days"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"actionsPage"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"actionsSize"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"8"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"activityPage"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"activitySize"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"posture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}},{"kind":"Field","name":{"kind":"Name","value":"diffPercent"}},{"kind":"Field","name":{"kind":"Name","value":"diffDirection"}},{"kind":"Field","name":{"kind":"Name","value":"agentAnnotation"}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimension"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"trends"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"period"},"value":{"kind":"Variable","name":{"kind":"Name","value":"trendPeriod"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"metrics"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"history"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"diff"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"systemCoverage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalSystems"}},{"kind":"Field","name":{"kind":"Name","value":"fullyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"partiallyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"unclassified"}},{"kind":"Field","name":{"kind":"Name","value":"withoutSteward"}},{"kind":"Field","name":{"kind":"Name","value":"coveragePercentage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"privacyRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeCount"}},{"kind":"Field","name":{"kind":"Name","value":"overdueCount"}},{"kind":"Field","name":{"kind":"Name","value":"statuses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inProgress"}},{"kind":"Field","name":{"kind":"Name","value":"pendingAction"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingApproval"}}]}},{"kind":"Field","name":{"kind":"Name","value":"slaHealth"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"onTrack"}},{"kind":"Field","name":{"kind":"Name","value":"approaching"}},{"kind":"Field","name":{"kind":"Name","value":"overdue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"priorityActions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"actionsPage"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"actionsSize"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"agentSummary"}},{"kind":"Field","name":{"kind":"Name","value":"dueDate"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}},{"kind":"Field","name":{"kind":"Name","value":"astralis"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConversations"}},{"kind":"Field","name":{"kind":"Name","value":"completedAssessments"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingResponse"}},{"kind":"Field","name":{"kind":"Name","value":"risksIdentified"}}]}},{"kind":"Field","name":{"kind":"Name","value":"agentBriefing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"briefing"}},{"kind":"Field","name":{"kind":"Name","value":"quickActions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"actionType"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"activityFeed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"activityPage"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"activitySize"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"actorType"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const DashboardPostureDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardPosture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"posture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}},{"kind":"Field","name":{"kind":"Name","value":"diffPercent"}},{"kind":"Field","name":{"kind":"Name","value":"diffDirection"}},{"kind":"Field","name":{"kind":"Name","value":"agentAnnotation"}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimension"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}}]}}]}}]}}]} as unknown as DocumentNode; +export const DashboardTrendsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardTrends"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"period"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TrendPeriod"}}},"defaultValue":{"kind":"EnumValue","value":"thirty_days"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"trends"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"period"},"value":{"kind":"Variable","name":{"kind":"Name","value":"period"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"metrics"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"history"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"diff"}}]}}]}}]}}]} as unknown as DocumentNode; +export const DashboardSystemCoverageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardSystemCoverage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"systemCoverage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalSystems"}},{"kind":"Field","name":{"kind":"Name","value":"fullyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"partiallyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"unclassified"}},{"kind":"Field","name":{"kind":"Name","value":"withoutSteward"}},{"kind":"Field","name":{"kind":"Name","value":"coveragePercentage"}}]}}]}}]} as unknown as DocumentNode; +export const DashboardPrivacyRequestsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardPrivacyRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"privacyRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeCount"}},{"kind":"Field","name":{"kind":"Name","value":"overdueCount"}},{"kind":"Field","name":{"kind":"Name","value":"statuses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inProgress"}},{"kind":"Field","name":{"kind":"Name","value":"pendingAction"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingApproval"}}]}},{"kind":"Field","name":{"kind":"Name","value":"slaHealth"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"onTrack"}},{"kind":"Field","name":{"kind":"Name","value":"approaching"}},{"kind":"Field","name":{"kind":"Name","value":"overdue"}}]}}]}}]}}]} as unknown as DocumentNode; +export const DashboardPriorityActionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardPriorityActions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"size"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"25"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dimension"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"priorityActions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"size"}}},{"kind":"Argument","name":{"kind":"Name","value":"dimension"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dimension"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"agentSummary"}},{"kind":"Field","name":{"kind":"Name","value":"dueDate"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]} as unknown as DocumentNode; +export const DashboardAstralisDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardAstralis"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"astralis"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConversations"}},{"kind":"Field","name":{"kind":"Name","value":"completedAssessments"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingResponse"}},{"kind":"Field","name":{"kind":"Name","value":"risksIdentified"}}]}}]}}]} as unknown as DocumentNode; +export const DashboardAgentBriefingDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardAgentBriefing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agentBriefing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"briefing"}},{"kind":"Field","name":{"kind":"Name","value":"quickActions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"actionType"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}}]}}]}}]}}]} as unknown as DocumentNode; +export const DashboardActivityFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardActivityFeed"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"size"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activityFeed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"size"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"actorType"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/clients/admin-ui/src/features/common/nav/nav-config.tsx b/clients/admin-ui/src/features/common/nav/nav-config.tsx index be01a068ff8..4baed5756ec 100644 --- a/clients/admin-ui/src/features/common/nav/nav-config.tsx +++ b/clients/admin-ui/src/features/common/nav/nav-config.tsx @@ -65,15 +65,6 @@ export const NAV_CONFIG: NavConfigGroup[] = [ exact: true, scopes: [], }, - { - // GraphQL PoC variant of the dashboard. Hidden from the sidebar but - // reachable by URL so it can be compared against the REST dashboard. - title: "Dashboard (GraphQL)", - path: "/dashboard-graphql", - exact: true, - hidden: true, - scopes: [], - }, ], }, { diff --git a/clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlView.tsx b/clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlView.tsx deleted file mode 100644 index d4db81a33af..00000000000 --- a/clients/admin-ui/src/features/dashboard-graphql/DashboardGraphqlView.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import { useQuery } from "@apollo/client"; -import { Alert, Col, Flex, Row, Spin, Text, Typography } from "fidesui"; - -import { DashboardOverviewDocument } from "~/__generated__/graphql/graphql"; - -const { Title } = Typography; - -const Section = ({ - title, - children, -}: { - title: string; - children: React.ReactNode; -}) => ( - - {title} - {children} - -); - -const Metric = ({ - label, - value, -}: { - label: string; - value: React.ReactNode; -}) => ( - - - {label} - - {value} - -); - -export const DashboardGraphqlView = () => { - const { data, loading, error } = useQuery(DashboardOverviewDocument); - - if (loading && !data) { - return ( - - - - ); - } - if (error) { - return ; - } - if (!data) { - return null; - } - - const { - posture, - systemCoverage, - privacyRequests, - priorityActions, - astralis, - agentBriefing, - trends, - activityFeed, - } = data; - - return ( - - Dashboard (GraphQL / Apollo) - - 0 ? ( - - {agentBriefing.quickActions.map((qa) => qa.label).join(" · ")} - - ) : null - } - /> - - - -
- {posture.agentAnnotation} - - {posture.dimensions.map((d) => ( - - {d.label} - - {d.score} · {d.band} - - - ))} - -
- - -
- - {priorityActions.items.map((a) => ( - - - [{a.severity}] {a.title} - - {a.message} - - ))} - -
- -
- - - {trends.metrics.map((m) => ( - -
- - -
- - ))} -
- - - -
- - - - -
- - -
- - - - -
- - -
- - - - -
- -
- -
- - {activityFeed.items.map((item) => ( - - {item.message} - - {item.actorType} · {item.timestamp} - - - ))} - -
-
- ); -}; diff --git a/clients/admin-ui/src/features/dashboard-graphql/hooks.ts b/clients/admin-ui/src/features/dashboard-graphql/hooks.ts new file mode 100644 index 00000000000..ab6cbda722e --- /dev/null +++ b/clients/admin-ui/src/features/dashboard-graphql/hooks.ts @@ -0,0 +1,270 @@ +/** + * Drop-in GraphQL replacements for the dashboard RTK Query hooks (Apollo). + * + * Each hook keeps the exact name, call signature, and return shape of its + * counterpart in ~/features/dashboard/dashboard.slice, and maps the + * camelCase GraphQL response back onto the existing snake_case + * ~/features/dashboard/types interfaces. That keeps every card component + * unchanged except for its import path. + * + * Per-card queries (not one combined query) on purpose: preserves + * independent auth failure and progressive per-card loading, matching the + * REST behaviour. dashboard.slice.ts is intentionally left in place + * (mutations stay on RTK; other consumers/tests may import it). + */ +import { useQuery } from "@apollo/client"; + +import { + DashboardActivityFeedDocument, + DashboardAgentBriefingDocument, + DashboardAstralisDocument, + DashboardPostureDocument, + DashboardPriorityActionsDocument, + DashboardPrivacyRequestsDocument, + DashboardSystemCoverageDocument, + DashboardTrendsDocument, + TrendPeriod as GqlTrendPeriod, +} from "~/__generated__/graphql/graphql"; +import type { + ActivityFeedResponse, + AgentBriefingResponse, + AstralisResponse, + PostureResponse, + PriorityAction, + PrivacyRequestsResponse, + SystemCoverageResponse, + TrendsResponse, +} from "~/features/dashboard/types"; +import { + ActionSeverity, + ActionType, + DiffDirection, + PostureBand, + TrendPeriod, +} from "~/features/dashboard/types"; + +// REST TrendPeriod values ("30d") differ from the GraphQL enum names +// ("thirty_days"); the rest of the enums share the same string values. +const TREND_PERIOD_TO_GQL: Record = { + [TrendPeriod.THIRTY_DAYS]: GqlTrendPeriod.ThirtyDays, + [TrendPeriod.SIXTY_DAYS]: GqlTrendPeriod.SixtyDays, + [TrendPeriod.NINETY_DAYS]: GqlTrendPeriod.NinetyDays, +}; + +export const useGetAgentBriefingQuery = () => { + const { data, loading } = useQuery(DashboardAgentBriefingDocument); + const briefing = data?.agentBriefing; + const mapped: AgentBriefingResponse | undefined = briefing + ? { + briefing: briefing.briefing, + quick_actions: briefing.quickActions.map((qa) => ({ + label: qa.label, + action_type: qa.actionType as unknown as ActionType, + action_data: qa.actionData, + severity: qa.severity as unknown as ActionSeverity, + })), + } + : undefined; + return { data: mapped, isLoading: loading }; +}; + +export const useGetDashboardPostureQuery = () => { + const { data, loading } = useQuery(DashboardPostureDocument); + const p = data?.posture; + const mapped: PostureResponse | undefined = p + ? { + score: p.score, + band: p.band as unknown as PostureBand, + diff_percent: p.diffPercent, + diff_direction: p.diffDirection as unknown as DiffDirection, + agent_annotation: p.agentAnnotation, + dimensions: p.dimensions.map((d) => ({ + dimension: d.dimension, + label: d.label, + weight: d.weight, + score: d.score, + band: d.band as unknown as PostureBand, + })), + } + : undefined; + return { data: mapped, isLoading: loading }; +}; + +export const useGetSystemCoverageQuery = () => { + const { data, loading } = useQuery(DashboardSystemCoverageDocument); + const c = data?.systemCoverage; + const mapped: SystemCoverageResponse | undefined = c + ? { + total_systems: c.totalSystems, + fully_classified: c.fullyClassified, + partially_classified: c.partiallyClassified, + unclassified: c.unclassified, + without_steward: c.withoutSteward, + coverage_percentage: c.coveragePercentage, + } + : undefined; + return { data: mapped, isLoading: loading }; +}; + +export const useGetPrivacyRequestsQuery = () => { + const { data, loading } = useQuery(DashboardPrivacyRequestsDocument); + const pr = data?.privacyRequests; + const mapped: PrivacyRequestsResponse | undefined = pr + ? { + active_count: pr.activeCount, + overdue_count: pr.overdueCount, + statuses: { + in_progress: pr.statuses.inProgress, + pending_action: pr.statuses.pendingAction, + awaiting_approval: pr.statuses.awaitingApproval, + }, + sla_health: Object.fromEntries( + pr.slaHealth.map((b) => [ + b.label, + { + on_track: b.onTrack, + approaching: b.approaching, + overdue: b.overdue, + }, + ]), + ), + } + : undefined; + return { data: mapped, isLoading: loading }; +}; + +export const useGetAstralisQuery = () => { + const { data, loading } = useQuery(DashboardAstralisDocument); + const a = data?.astralis; + const mapped: AstralisResponse | undefined = a + ? { + active_conversations: a.activeConversations, + completed_assessments: a.completedAssessments, + awaiting_response: a.awaitingResponse, + risks_identified: a.risksIdentified, + } + : undefined; + return { data: mapped, isLoading: loading }; +}; + +export const useGetDashboardTrendsQuery = ({ + period, +}: { + period: TrendPeriod; +}) => { + const { data, loading } = useQuery(DashboardTrendsDocument, { + variables: { period: TREND_PERIOD_TO_GQL[period] }, + }); + const t = data?.trends; + const mapped: TrendsResponse | undefined = t + ? { + metrics: Object.fromEntries( + t.metrics.map((m) => [ + m.key, + { + value: m.value, + history: m.history, + metadata: m.metadata, + diff: m.diff, + }, + ]), + ), + } + : undefined; + return { data: mapped, isLoading: loading }; +}; + +interface PriorityActionsParams { + page?: number; + size?: number; + dimension?: string | null; +} + +export const useGetPriorityActionsQuery = ( + params?: PriorityActionsParams | void, +) => { + const { dimension, page, size } = params ?? {}; + const { data, loading } = useQuery(DashboardPriorityActionsDocument, { + variables: { + page: page ?? 1, + size: size ?? 25, + dimension: dimension ?? null, + }, + }); + const pa = data?.priorityActions; + const mapped: PriorityActionsResponse | undefined = pa + ? { + items: pa.items.map( + (i): PriorityAction => ({ + id: i.id, + type: i.type as unknown as ActionType, + severity: i.severity as unknown as ActionSeverity, + title: i.title, + message: i.message, + agent_summary: i.agentSummary, + due_date: i.dueDate ?? null, + action_data: i.actionData, + status: i.status as unknown as PriorityAction["status"], + }), + ), + total: pa.total, + page: pa.page, + size: pa.size, + pages: pa.pages, + } + : undefined; + return { data: mapped, isLoading: loading }; +}; + +interface PriorityActionsResponse { + items: PriorityAction[]; + total: number; + page: number; + size: number; + pages: number; +} + +interface ActivityFeedParams { + page?: number; + size?: number; + actor_type?: "user" | "system"; +} + +interface ActivityFeedOptions { + pollingInterval?: number; + // Accept (and ignore) the other RTK Query options the call site passes + // (skipPollingIfUnfocused, refetchOnMountOrArgChange, ...). + [key: string]: unknown; +} + +export const useGetActivityFeedQuery = ( + params?: ActivityFeedParams | void, + // RTK polling options are accepted for signature parity. Polling maps to + // Apollo's pollInterval; the rest are no-ops for the PoC. + options?: ActivityFeedOptions, +) => { + const { page, size } = params ?? {}; + const { data, loading } = useQuery(DashboardActivityFeedDocument, { + variables: { page: page ?? 1, size: size ?? 20 }, + pollInterval: options?.pollingInterval, + notifyOnNetworkStatusChange: true, + }); + const af = data?.activityFeed; + const mapped: ActivityFeedResponse | undefined = af + ? { + items: af.items.map((i) => ({ + // The GraphQL ActivityFeedItem has no id; synthesise a stable one + // so the infinite-scroll dedupe keeps working unchanged. + id: `${i.timestamp}__${i.message}`, + actor_type: i.actorType as unknown as "user" | "system", + message: i.message, + timestamp: i.timestamp, + })), + total: af.total, + page: af.page, + size: af.size, + pages: af.pages, + } + : undefined; + return { data: mapped, isFetching: loading }; +}; diff --git a/clients/admin-ui/src/features/dashboard-graphql/dashboard.graphql b/clients/admin-ui/src/features/dashboard-graphql/queries.graphql similarity index 68% rename from clients/admin-ui/src/features/dashboard-graphql/dashboard.graphql rename to clients/admin-ui/src/features/dashboard-graphql/queries.graphql index 7a7e66e8797..d154c7fd2a5 100644 --- a/clients/admin-ui/src/features/dashboard-graphql/dashboard.graphql +++ b/clients/admin-ui/src/features/dashboard-graphql/queries.graphql @@ -1,10 +1,4 @@ -query DashboardOverview( - $trendPeriod: TrendPeriod! = thirty_days - $actionsPage: Int! = 1 - $actionsSize: Int! = 8 - $activityPage: Int! = 1 - $activitySize: Int! = 20 -) { +query DashboardPosture { posture { score band @@ -19,7 +13,10 @@ query DashboardOverview( band } } - trends(period: $trendPeriod) { +} + +query DashboardTrends($period: TrendPeriod! = thirty_days) { + trends(period: $period) { period metrics { key @@ -29,6 +26,9 @@ query DashboardOverview( diff } } +} + +query DashboardSystemCoverage { systemCoverage { totalSystems fullyClassified @@ -37,6 +37,9 @@ query DashboardOverview( withoutSteward coveragePercentage } +} + +query DashboardPrivacyRequests { privacyRequests { activeCount overdueCount @@ -52,7 +55,14 @@ query DashboardOverview( overdue } } - priorityActions(page: $actionsPage, size: $actionsSize) { +} + +query DashboardPriorityActions( + $page: Int! = 1 + $size: Int! = 25 + $dimension: String +) { + priorityActions(page: $page, size: $size, dimension: $dimension) { items { id type @@ -69,12 +79,18 @@ query DashboardOverview( size pages } +} + +query DashboardAstralis { astralis { activeConversations completedAssessments awaitingResponse risksIdentified } +} + +query DashboardAgentBriefing { agentBriefing { briefing quickActions { @@ -84,7 +100,10 @@ query DashboardOverview( actionData } } - activityFeed(page: $activityPage, size: $activitySize) { +} + +query DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) { + activityFeed(page: $page, size: $size) { items { actorType message diff --git a/clients/admin-ui/src/home/AgentBriefingBanner.tsx b/clients/admin-ui/src/home/AgentBriefingBanner.tsx index 45e24f17ed7..9ec55323f7b 100644 --- a/clients/admin-ui/src/home/AgentBriefingBanner.tsx +++ b/clients/admin-ui/src/home/AgentBriefingBanner.tsx @@ -11,8 +11,8 @@ import { useMemo } from "react"; import { useFlags } from "~/features/common/features"; import { RouterLink } from "~/features/common/nav/RouterLink"; import { ACTION_CTA } from "~/features/dashboard/constants"; -import { useGetAgentBriefingQuery } from "~/features/dashboard/dashboard.slice"; import { ActionSeverity } from "~/features/dashboard/types"; +import { useGetAgentBriefingQuery } from "~/features/dashboard-graphql/hooks"; import styles from "./AgentBriefingBanner.module.scss"; diff --git a/clients/admin-ui/src/home/AstralisPanel.tsx b/clients/admin-ui/src/home/AstralisPanel.tsx index 837b0fd2cb6..1ab40381f94 100644 --- a/clients/admin-ui/src/home/AstralisPanel.tsx +++ b/clients/admin-ui/src/home/AstralisPanel.tsx @@ -5,7 +5,7 @@ import { ASTRALIS_METRICS, ASTRALIS_RISKS_KEY, } from "~/features/dashboard/constants"; -import { useGetAstralisQuery } from "~/features/dashboard/dashboard.slice"; +import { useGetAstralisQuery } from "~/features/dashboard-graphql/hooks"; import styles from "./AstralisPanel.module.scss"; diff --git a/clients/admin-ui/src/home/DSRStatusCard.tsx b/clients/admin-ui/src/home/DSRStatusCard.tsx index c701480d37b..05c21c9d913 100644 --- a/clients/admin-ui/src/home/DSRStatusCard.tsx +++ b/clients/admin-ui/src/home/DSRStatusCard.tsx @@ -14,7 +14,7 @@ import { useCallback } from "react"; import { RouterLink } from "~/features/common/nav/RouterLink"; import { PRIVACY_REQUESTS_ROUTE } from "~/features/common/nav/routes"; -import { useGetPrivacyRequestsQuery } from "~/features/dashboard/dashboard.slice"; +import { useGetPrivacyRequestsQuery } from "~/features/dashboard-graphql/hooks"; import styles from "./DSRStatusCard.module.scss"; diff --git a/clients/admin-ui/src/home/HomeDashboard.tsx b/clients/admin-ui/src/home/HomeDashboard.tsx index a3bc4c19654..bb49a8a8af0 100644 --- a/clients/admin-ui/src/home/HomeDashboard.tsx +++ b/clients/admin-ui/src/home/HomeDashboard.tsx @@ -2,8 +2,8 @@ import { Col, Divider, Flex, Row, Text } from "fidesui"; import { useFlags } from "~/features/common/features"; import { ThemeModeToggle } from "~/features/common/ThemeModeToggle"; -import { useGetDashboardTrendsQuery } from "~/features/dashboard/dashboard.slice"; import { TrendPeriod } from "~/features/dashboard/types"; +import { useGetDashboardTrendsQuery } from "~/features/dashboard-graphql/hooks"; import { ActivityFeedCard } from "./ActivityFeedCard"; import { AgentBriefingBanner } from "./AgentBriefingBanner"; diff --git a/clients/admin-ui/src/home/PostureBreakdownContent.tsx b/clients/admin-ui/src/home/PostureBreakdownContent.tsx index 48933d232d5..27a13d7ddaa 100644 --- a/clients/admin-ui/src/home/PostureBreakdownContent.tsx +++ b/clients/admin-ui/src/home/PostureBreakdownContent.tsx @@ -16,8 +16,8 @@ import { DIMENSION_LABELS, DIMENSION_ROUTES, } from "~/features/dashboard/constants"; -import { useGetDashboardPostureQuery } from "~/features/dashboard/dashboard.slice"; import type { PostureBand } from "~/features/dashboard/types"; +import { useGetDashboardPostureQuery } from "~/features/dashboard-graphql/hooks"; import styles from "./PostureBreakdownContent.module.scss"; diff --git a/clients/admin-ui/src/home/PostureCard.tsx b/clients/admin-ui/src/home/PostureCard.tsx index cbb7a515eb5..876d4bd3606 100644 --- a/clients/admin-ui/src/home/PostureCard.tsx +++ b/clients/admin-ui/src/home/PostureCard.tsx @@ -19,7 +19,7 @@ import { DIMENSION_DESCRIPTIONS, DIMENSION_LABELS, } from "~/features/dashboard/constants"; -import { useGetDashboardPostureQuery } from "~/features/dashboard/dashboard.slice"; +import { useGetDashboardPostureQuery } from "~/features/dashboard-graphql/hooks"; import styles from "./PostureCard.module.scss"; import { useCountUp } from "./useCountUp"; diff --git a/clients/admin-ui/src/home/PriorityActionsCard.tsx b/clients/admin-ui/src/home/PriorityActionsCard.tsx index 6e31f8db2e1..76c41d5a367 100644 --- a/clients/admin-ui/src/home/PriorityActionsCard.tsx +++ b/clients/admin-ui/src/home/PriorityActionsCard.tsx @@ -19,9 +19,9 @@ import { DIMENSION_LABELS, getUrgencyGroup, } from "~/features/dashboard/constants"; -import { useGetPriorityActionsQuery } from "~/features/dashboard/dashboard.slice"; import type { PriorityAction } from "~/features/dashboard/types"; import { ActionSeverity } from "~/features/dashboard/types"; +import { useGetPriorityActionsQuery } from "~/features/dashboard-graphql/hooks"; import styles from "./PriorityActionsCard.module.scss"; import { clearDimensionFilter, useDimensionFilter } from "./useDimensionFilter"; diff --git a/clients/admin-ui/src/home/SystemCoverageCard.tsx b/clients/admin-ui/src/home/SystemCoverageCard.tsx index 7a78e13cc04..be531ac8b13 100644 --- a/clients/admin-ui/src/home/SystemCoverageCard.tsx +++ b/clients/admin-ui/src/home/SystemCoverageCard.tsx @@ -12,8 +12,8 @@ import { import { RouterLink } from "~/features/common/nav/RouterLink"; import { ADD_SYSTEMS_MANUAL_ROUTE } from "~/features/common/nav/routes"; -import { useGetSystemCoverageQuery } from "~/features/dashboard/dashboard.slice"; import type { SystemCoverageResponse } from "~/features/dashboard/types"; +import { useGetSystemCoverageQuery } from "~/features/dashboard-graphql/hooks"; const BREAKDOWN_ITEMS: { key: keyof SystemCoverageResponse; diff --git a/clients/admin-ui/src/home/useInfiniteActivityFeed.ts b/clients/admin-ui/src/home/useInfiniteActivityFeed.ts index 48c5e39fd83..ce682d3ce6e 100644 --- a/clients/admin-ui/src/home/useInfiniteActivityFeed.ts +++ b/clients/admin-ui/src/home/useInfiniteActivityFeed.ts @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; -import { useGetActivityFeedQuery } from "~/features/dashboard/dashboard.slice"; import type { ActivityFeedItem } from "~/features/dashboard/types"; +import { useGetActivityFeedQuery } from "~/features/dashboard-graphql/hooks"; const PAGE_SIZE = 15; const POLLING_INTERVAL = 30_000; diff --git a/clients/admin-ui/src/pages/_app.tsx b/clients/admin-ui/src/pages/_app.tsx index 2e76445ccb6..ba1d439af28 100644 --- a/clients/admin-ui/src/pages/_app.tsx +++ b/clients/admin-ui/src/pages/_app.tsx @@ -19,6 +19,7 @@ import { PersistGate } from "redux-persist/integration/react"; import ProtectedRoute from "~/features/auth/ProtectedRoute"; import CommonSubscriptions from "~/features/common/CommonSubscriptions"; import MainSideNav from "~/features/common/nav/MainSideNav"; +import { DashboardGraphqlProvider } from "~/features/dashboard-graphql/DashboardGraphqlProvider"; import store, { persistor } from "../app/store"; import theme from "../theme"; @@ -52,36 +53,38 @@ const MyApp = ({ Component, pageProps }: AppProps) => { - - - - {Component === Login || - Component === LoginWithOIDC || - Component === ForgotPassword ? ( - // Only the login page is accessible while logged out. If there is - // a use case for more unprotected routes, Next has a guide for - // per-page layouts: - // https://nextjs.org/docs/basic-features/layouts#per-page-layouts - - ) : ( - - - - - - + + + + + {Component === Login || + Component === LoginWithOIDC || + Component === ForgotPassword ? ( + // Only the login page is accessible while logged out. If there is + // a use case for more unprotected routes, Next has a guide for + // per-page layouts: + // https://nextjs.org/docs/basic-features/layouts#per-page-layouts + + ) : ( + + + + + + + - - - )} - - - + + )} + + + + diff --git a/clients/admin-ui/src/pages/dashboard-graphql.tsx b/clients/admin-ui/src/pages/dashboard-graphql.tsx deleted file mode 100644 index 2cdc3d38e90..00000000000 --- a/clients/admin-ui/src/pages/dashboard-graphql.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import type { NextPage } from "next"; - -import Layout from "~/features/common/Layout"; -import { DashboardGraphqlProvider } from "~/features/dashboard-graphql/DashboardGraphqlProvider"; -import { DashboardGraphqlView } from "~/features/dashboard-graphql/DashboardGraphqlView"; - -const DashboardGraphqlPage: NextPage = () => ( - - - - - -); - -export default DashboardGraphqlPage; From c11d48b764e6ed1957e89fa5f57babd4f373e8ae Mon Sep 17 00:00:00 2001 From: Karolis Date: Fri, 15 May 2026 16:42:10 -0400 Subject: [PATCH 06/10] graphql poc apollo: memoize mapped hook results (fix render loop) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drop-in hooks rebuilt the mapped object every render, giving `data` a new reference each time. useInfiniteActivityFeed keys a setState effect on `data`, so it re-fired every render -> "Maximum update depth exceeded". Memoize each mapping on the raw query data (Apollo keeps a stable data ref until the result changes) so consumers see a stable identity. Local PoC branch — do not push. --- .../src/features/dashboard-graphql/hooks.ts | 289 ++++++++++-------- 1 file changed, 164 insertions(+), 125 deletions(-) diff --git a/clients/admin-ui/src/features/dashboard-graphql/hooks.ts b/clients/admin-ui/src/features/dashboard-graphql/hooks.ts index ab6cbda722e..03ee8579d4a 100644 --- a/clients/admin-ui/src/features/dashboard-graphql/hooks.ts +++ b/clients/admin-ui/src/features/dashboard-graphql/hooks.ts @@ -7,12 +7,19 @@ * ~/features/dashboard/types interfaces. That keeps every card component * unchanged except for its import path. * + * The mapped result is memoised on the raw query data. Apollo returns a + * stable `data` reference until the result actually changes, so the mapped + * object identity is stable too — without this, consumers that key effects + * on `data` (e.g. useInfiniteActivityFeed) re-fire setState every render + * and React throws "Maximum update depth exceeded". + * * Per-card queries (not one combined query) on purpose: preserves * independent auth failure and progressive per-card loading, matching the * REST behaviour. dashboard.slice.ts is intentionally left in place * (mutations stay on RTK; other consumers/tests may import it). */ import { useQuery } from "@apollo/client"; +import { useMemo } from "react"; import { DashboardActivityFeedDocument, @@ -54,96 +61,116 @@ const TREND_PERIOD_TO_GQL: Record = { export const useGetAgentBriefingQuery = () => { const { data, loading } = useQuery(DashboardAgentBriefingDocument); const briefing = data?.agentBriefing; - const mapped: AgentBriefingResponse | undefined = briefing - ? { - briefing: briefing.briefing, - quick_actions: briefing.quickActions.map((qa) => ({ - label: qa.label, - action_type: qa.actionType as unknown as ActionType, - action_data: qa.actionData, - severity: qa.severity as unknown as ActionSeverity, - })), - } - : undefined; + const mapped = useMemo( + () => + briefing + ? { + briefing: briefing.briefing, + quick_actions: briefing.quickActions.map((qa) => ({ + label: qa.label, + action_type: qa.actionType as unknown as ActionType, + action_data: qa.actionData, + severity: qa.severity as unknown as ActionSeverity, + })), + } + : undefined, + [briefing], + ); return { data: mapped, isLoading: loading }; }; export const useGetDashboardPostureQuery = () => { const { data, loading } = useQuery(DashboardPostureDocument); const p = data?.posture; - const mapped: PostureResponse | undefined = p - ? { - score: p.score, - band: p.band as unknown as PostureBand, - diff_percent: p.diffPercent, - diff_direction: p.diffDirection as unknown as DiffDirection, - agent_annotation: p.agentAnnotation, - dimensions: p.dimensions.map((d) => ({ - dimension: d.dimension, - label: d.label, - weight: d.weight, - score: d.score, - band: d.band as unknown as PostureBand, - })), - } - : undefined; + const mapped = useMemo( + () => + p + ? { + score: p.score, + band: p.band as unknown as PostureBand, + diff_percent: p.diffPercent, + diff_direction: p.diffDirection as unknown as DiffDirection, + agent_annotation: p.agentAnnotation, + dimensions: p.dimensions.map((d) => ({ + dimension: d.dimension, + label: d.label, + weight: d.weight, + score: d.score, + band: d.band as unknown as PostureBand, + })), + } + : undefined, + [p], + ); return { data: mapped, isLoading: loading }; }; export const useGetSystemCoverageQuery = () => { const { data, loading } = useQuery(DashboardSystemCoverageDocument); const c = data?.systemCoverage; - const mapped: SystemCoverageResponse | undefined = c - ? { - total_systems: c.totalSystems, - fully_classified: c.fullyClassified, - partially_classified: c.partiallyClassified, - unclassified: c.unclassified, - without_steward: c.withoutSteward, - coverage_percentage: c.coveragePercentage, - } - : undefined; + const mapped = useMemo( + () => + c + ? { + total_systems: c.totalSystems, + fully_classified: c.fullyClassified, + partially_classified: c.partiallyClassified, + unclassified: c.unclassified, + without_steward: c.withoutSteward, + coverage_percentage: c.coveragePercentage, + } + : undefined, + [c], + ); return { data: mapped, isLoading: loading }; }; export const useGetPrivacyRequestsQuery = () => { const { data, loading } = useQuery(DashboardPrivacyRequestsDocument); const pr = data?.privacyRequests; - const mapped: PrivacyRequestsResponse | undefined = pr - ? { - active_count: pr.activeCount, - overdue_count: pr.overdueCount, - statuses: { - in_progress: pr.statuses.inProgress, - pending_action: pr.statuses.pendingAction, - awaiting_approval: pr.statuses.awaitingApproval, - }, - sla_health: Object.fromEntries( - pr.slaHealth.map((b) => [ - b.label, - { - on_track: b.onTrack, - approaching: b.approaching, - overdue: b.overdue, + const mapped = useMemo( + () => + pr + ? { + active_count: pr.activeCount, + overdue_count: pr.overdueCount, + statuses: { + in_progress: pr.statuses.inProgress, + pending_action: pr.statuses.pendingAction, + awaiting_approval: pr.statuses.awaitingApproval, }, - ]), - ), - } - : undefined; + sla_health: Object.fromEntries( + pr.slaHealth.map((b) => [ + b.label, + { + on_track: b.onTrack, + approaching: b.approaching, + overdue: b.overdue, + }, + ]), + ), + } + : undefined, + [pr], + ); return { data: mapped, isLoading: loading }; }; export const useGetAstralisQuery = () => { const { data, loading } = useQuery(DashboardAstralisDocument); const a = data?.astralis; - const mapped: AstralisResponse | undefined = a - ? { - active_conversations: a.activeConversations, - completed_assessments: a.completedAssessments, - awaiting_response: a.awaitingResponse, - risks_identified: a.risksIdentified, - } - : undefined; + const mapped = useMemo( + () => + a + ? { + active_conversations: a.activeConversations, + completed_assessments: a.completedAssessments, + awaiting_response: a.awaitingResponse, + risks_identified: a.risksIdentified, + } + : undefined, + [a], + ); return { data: mapped, isLoading: loading }; }; @@ -156,21 +183,25 @@ export const useGetDashboardTrendsQuery = ({ variables: { period: TREND_PERIOD_TO_GQL[period] }, }); const t = data?.trends; - const mapped: TrendsResponse | undefined = t - ? { - metrics: Object.fromEntries( - t.metrics.map((m) => [ - m.key, - { - value: m.value, - history: m.history, - metadata: m.metadata, - diff: m.diff, - }, - ]), - ), - } - : undefined; + const mapped = useMemo( + () => + t + ? { + metrics: Object.fromEntries( + t.metrics.map((m) => [ + m.key, + { + value: m.value, + history: m.history, + metadata: m.metadata, + diff: m.diff, + }, + ]), + ), + } + : undefined, + [t], + ); return { data: mapped, isLoading: loading }; }; @@ -180,6 +211,14 @@ interface PriorityActionsParams { dimension?: string | null; } +interface PriorityActionsResponse { + items: PriorityAction[]; + total: number; + page: number; + size: number; + pages: number; +} + export const useGetPriorityActionsQuery = ( params?: PriorityActionsParams | void, ) => { @@ -192,38 +231,34 @@ export const useGetPriorityActionsQuery = ( }, }); const pa = data?.priorityActions; - const mapped: PriorityActionsResponse | undefined = pa - ? { - items: pa.items.map( - (i): PriorityAction => ({ - id: i.id, - type: i.type as unknown as ActionType, - severity: i.severity as unknown as ActionSeverity, - title: i.title, - message: i.message, - agent_summary: i.agentSummary, - due_date: i.dueDate ?? null, - action_data: i.actionData, - status: i.status as unknown as PriorityAction["status"], - }), - ), - total: pa.total, - page: pa.page, - size: pa.size, - pages: pa.pages, - } - : undefined; + const mapped = useMemo( + () => + pa + ? { + items: pa.items.map( + (i): PriorityAction => ({ + id: i.id, + type: i.type as unknown as ActionType, + severity: i.severity as unknown as ActionSeverity, + title: i.title, + message: i.message, + agent_summary: i.agentSummary, + due_date: i.dueDate ?? null, + action_data: i.actionData, + status: i.status as unknown as PriorityAction["status"], + }), + ), + total: pa.total, + page: pa.page, + size: pa.size, + pages: pa.pages, + } + : undefined, + [pa], + ); return { data: mapped, isLoading: loading }; }; -interface PriorityActionsResponse { - items: PriorityAction[]; - total: number; - page: number; - size: number; - pages: number; -} - interface ActivityFeedParams { page?: number; size?: number; @@ -250,21 +285,25 @@ export const useGetActivityFeedQuery = ( notifyOnNetworkStatusChange: true, }); const af = data?.activityFeed; - const mapped: ActivityFeedResponse | undefined = af - ? { - items: af.items.map((i) => ({ - // The GraphQL ActivityFeedItem has no id; synthesise a stable one - // so the infinite-scroll dedupe keeps working unchanged. - id: `${i.timestamp}__${i.message}`, - actor_type: i.actorType as unknown as "user" | "system", - message: i.message, - timestamp: i.timestamp, - })), - total: af.total, - page: af.page, - size: af.size, - pages: af.pages, - } - : undefined; + const mapped = useMemo( + () => + af + ? { + items: af.items.map((i) => ({ + // The GraphQL ActivityFeedItem has no id; synthesise a stable + // one so the infinite-scroll dedupe keeps working unchanged. + id: `${i.timestamp}__${i.message}`, + actor_type: i.actorType as unknown as "user" | "system", + message: i.message, + timestamp: i.timestamp, + })), + total: af.total, + page: af.page, + size: af.size, + pages: af.pages, + } + : undefined, + [af], + ); return { data: mapped, isFetching: loading }; }; From 51cb68afe01ed25e33c5ea22e8c62ca62daa7bc1 Mon Sep 17 00:00:00 2001 From: Karolis Date: Mon, 18 May 2026 23:25:18 -0400 Subject: [PATCH 07/10] graphql poc apollo: combined DashboardOverview with @defer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Folds the six static dashboard cards (posture, trends, system coverage, privacy requests, astralis, agent briefing) into one combined query and defers agentBriefing — the slow LLM-backed field — so the dashboard paints on the first multipart chunk and the briefing banner arrives in a second chunk. priorityActions and activityFeed keep their own per-card queries; their interactive variables (dimension filter, infinite-scroll pagination) would otherwise force the whole combined query to refetch on every filter change or "load more". Apollo's HTTP link auto-negotiates multipart/mixed — no client config change. Apollo deduplicates concurrent useQuery(DashboardOverviewDocument) calls with identical variables into a single network request, so the six static drop-in hooks all share one POST. Requires the BE bump to strawberry-graphql 0.315.5 with enable_experimental_incremental_execution=True (paired commit on fidesplus graphql-poc-be). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../admin-ui/src/__generated__/graphql/gql.ts | 6 +- .../src/__generated__/graphql/graphql.ts | 38 +--------- .../src/features/dashboard-graphql/hooks.ts | 76 +++++++++++-------- .../dashboard-graphql/queries.graphql | 51 +++++-------- 4 files changed, 69 insertions(+), 102 deletions(-) diff --git a/clients/admin-ui/src/__generated__/graphql/gql.ts b/clients/admin-ui/src/__generated__/graphql/gql.ts index 3103a97827c..c7c5371c2ee 100644 --- a/clients/admin-ui/src/__generated__/graphql/gql.ts +++ b/clients/admin-ui/src/__generated__/graphql/gql.ts @@ -14,10 +14,10 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { - "query DashboardPosture {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n}\n\nquery DashboardTrends($period: TrendPeriod! = thirty_days) {\n trends(period: $period) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n}\n\nquery DashboardSystemCoverage {\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n}\n\nquery DashboardPrivacyRequests {\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardAstralis {\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n}\n\nquery DashboardAgentBriefing {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": typeof types.DashboardPostureDocument, + "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: \"agentBriefing\") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": typeof types.DashboardOverviewDocument, }; const documents: Documents = { - "query DashboardPosture {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n}\n\nquery DashboardTrends($period: TrendPeriod! = thirty_days) {\n trends(period: $period) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n}\n\nquery DashboardSystemCoverage {\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n}\n\nquery DashboardPrivacyRequests {\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardAstralis {\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n}\n\nquery DashboardAgentBriefing {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": types.DashboardPostureDocument, + "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: \"agentBriefing\") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": types.DashboardOverviewDocument, }; /** @@ -37,7 +37,7 @@ export function gql(source: string): unknown; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "query DashboardPosture {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n}\n\nquery DashboardTrends($period: TrendPeriod! = thirty_days) {\n trends(period: $period) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n}\n\nquery DashboardSystemCoverage {\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n}\n\nquery DashboardPrivacyRequests {\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardAstralis {\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n}\n\nquery DashboardAgentBriefing {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"): (typeof documents)["query DashboardPosture {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n}\n\nquery DashboardTrends($period: TrendPeriod! = thirty_days) {\n trends(period: $period) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n}\n\nquery DashboardSystemCoverage {\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n}\n\nquery DashboardPrivacyRequests {\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardAstralis {\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n}\n\nquery DashboardAgentBriefing {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"]; +export function gql(source: "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: \"agentBriefing\") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"): (typeof documents)["query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: \"agentBriefing\") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"]; export function gql(source: string) { return (documents as any)[source] ?? {}; diff --git a/clients/admin-ui/src/__generated__/graphql/graphql.ts b/clients/admin-ui/src/__generated__/graphql/graphql.ts index 595404b46d1..3e795e9fe54 100644 --- a/clients/admin-ui/src/__generated__/graphql/graphql.ts +++ b/clients/admin-ui/src/__generated__/graphql/graphql.ts @@ -226,27 +226,12 @@ export type Trends = { period: TrendPeriod; }; -export type DashboardPostureQueryVariables = Exact<{ [key: string]: never; }>; - - -export type DashboardPostureQuery = { __typename?: 'Query', posture: { __typename?: 'Posture', score: number, band: PostureBand, diffPercent: number, diffDirection: DiffDirection, agentAnnotation: string, dimensions: Array<{ __typename?: 'PostureDimension', dimension: string, label: string, weight: number, score: number, band: PostureBand }> } }; - -export type DashboardTrendsQueryVariables = Exact<{ - period?: TrendPeriod; +export type DashboardOverviewQueryVariables = Exact<{ + trendPeriod?: TrendPeriod; }>; -export type DashboardTrendsQuery = { __typename?: 'Query', trends: { __typename?: 'Trends', period: TrendPeriod, metrics: Array<{ __typename?: 'TrendMetric', key: string, value: number, history: Array, metadata: Record, diff: number }> } }; - -export type DashboardSystemCoverageQueryVariables = Exact<{ [key: string]: never; }>; - - -export type DashboardSystemCoverageQuery = { __typename?: 'Query', systemCoverage: { __typename?: 'SystemCoverage', totalSystems: number, fullyClassified: number, partiallyClassified: number, unclassified: number, withoutSteward: number, coveragePercentage: number } }; - -export type DashboardPrivacyRequestsQueryVariables = Exact<{ [key: string]: never; }>; - - -export type DashboardPrivacyRequestsQuery = { __typename?: 'Query', privacyRequests: { __typename?: 'PrivacyRequests', activeCount: number, overdueCount: number, statuses: { __typename?: 'PrivacyRequestStatuses', inProgress: number, pendingAction: number, awaitingApproval: number }, slaHealth: Array<{ __typename?: 'SLAHealthBucket', label: string, onTrack: number, approaching: number, overdue: number }> } }; +export type DashboardOverviewQuery = { __typename?: 'Query', posture: { __typename?: 'Posture', score: number, band: PostureBand, diffPercent: number, diffDirection: DiffDirection, agentAnnotation: string, dimensions: Array<{ __typename?: 'PostureDimension', dimension: string, label: string, weight: number, score: number, band: PostureBand }> }, trends: { __typename?: 'Trends', period: TrendPeriod, metrics: Array<{ __typename?: 'TrendMetric', key: string, value: number, history: Array, metadata: Record, diff: number }> }, systemCoverage: { __typename?: 'SystemCoverage', totalSystems: number, fullyClassified: number, partiallyClassified: number, unclassified: number, withoutSteward: number, coveragePercentage: number }, privacyRequests: { __typename?: 'PrivacyRequests', activeCount: number, overdueCount: number, statuses: { __typename?: 'PrivacyRequestStatuses', inProgress: number, pendingAction: number, awaitingApproval: number }, slaHealth: Array<{ __typename?: 'SLAHealthBucket', label: string, onTrack: number, approaching: number, overdue: number }> }, astralis: { __typename?: 'Astralis', activeConversations: number, completedAssessments: number, awaitingResponse: number, risksIdentified: number } } & ({ __typename?: 'Query', agentBriefing: { __typename?: 'AgentBriefing', briefing: string, quickActions: Array<{ __typename?: 'QuickAction', label: string, actionType: DashboardActionType, severity: ActionSeverity, actionData: Record }> } } | { __typename?: 'Query', agentBriefing?: never }); export type DashboardPriorityActionsQueryVariables = Exact<{ page?: Scalars['Int']['input']; @@ -257,16 +242,6 @@ export type DashboardPriorityActionsQueryVariables = Exact<{ export type DashboardPriorityActionsQuery = { __typename?: 'Query', priorityActions: { __typename?: 'PriorityActionsPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'PriorityAction', id: string, type: DashboardActionType, severity: ActionSeverity, title: string, message: string, agentSummary: string, dueDate?: string | null, actionData: Record, status: DashboardActionStatus }> } }; -export type DashboardAstralisQueryVariables = Exact<{ [key: string]: never; }>; - - -export type DashboardAstralisQuery = { __typename?: 'Query', astralis: { __typename?: 'Astralis', activeConversations: number, completedAssessments: number, awaitingResponse: number, risksIdentified: number } }; - -export type DashboardAgentBriefingQueryVariables = Exact<{ [key: string]: never; }>; - - -export type DashboardAgentBriefingQuery = { __typename?: 'Query', agentBriefing: { __typename?: 'AgentBriefing', briefing: string, quickActions: Array<{ __typename?: 'QuickAction', label: string, actionType: DashboardActionType, severity: ActionSeverity, actionData: Record }> } }; - export type DashboardActivityFeedQueryVariables = Exact<{ page?: Scalars['Int']['input']; size?: Scalars['Int']['input']; @@ -276,11 +251,6 @@ export type DashboardActivityFeedQueryVariables = Exact<{ export type DashboardActivityFeedQuery = { __typename?: 'Query', activityFeed: { __typename?: 'ActivityFeedPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'ActivityFeedItem', actorType: ActorType, message: string, timestamp: string }> } }; -export const DashboardPostureDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardPosture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"posture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}},{"kind":"Field","name":{"kind":"Name","value":"diffPercent"}},{"kind":"Field","name":{"kind":"Name","value":"diffDirection"}},{"kind":"Field","name":{"kind":"Name","value":"agentAnnotation"}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimension"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}}]}}]}}]}}]} as unknown as DocumentNode; -export const DashboardTrendsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardTrends"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"period"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TrendPeriod"}}},"defaultValue":{"kind":"EnumValue","value":"thirty_days"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"trends"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"period"},"value":{"kind":"Variable","name":{"kind":"Name","value":"period"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"metrics"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"history"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"diff"}}]}}]}}]}}]} as unknown as DocumentNode; -export const DashboardSystemCoverageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardSystemCoverage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"systemCoverage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalSystems"}},{"kind":"Field","name":{"kind":"Name","value":"fullyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"partiallyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"unclassified"}},{"kind":"Field","name":{"kind":"Name","value":"withoutSteward"}},{"kind":"Field","name":{"kind":"Name","value":"coveragePercentage"}}]}}]}}]} as unknown as DocumentNode; -export const DashboardPrivacyRequestsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardPrivacyRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"privacyRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeCount"}},{"kind":"Field","name":{"kind":"Name","value":"overdueCount"}},{"kind":"Field","name":{"kind":"Name","value":"statuses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inProgress"}},{"kind":"Field","name":{"kind":"Name","value":"pendingAction"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingApproval"}}]}},{"kind":"Field","name":{"kind":"Name","value":"slaHealth"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"onTrack"}},{"kind":"Field","name":{"kind":"Name","value":"approaching"}},{"kind":"Field","name":{"kind":"Name","value":"overdue"}}]}}]}}]}}]} as unknown as DocumentNode; +export const DashboardOverviewDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardOverview"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"trendPeriod"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TrendPeriod"}}},"defaultValue":{"kind":"EnumValue","value":"thirty_days"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"posture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}},{"kind":"Field","name":{"kind":"Name","value":"diffPercent"}},{"kind":"Field","name":{"kind":"Name","value":"diffDirection"}},{"kind":"Field","name":{"kind":"Name","value":"agentAnnotation"}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimension"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"trends"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"period"},"value":{"kind":"Variable","name":{"kind":"Name","value":"trendPeriod"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"metrics"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"history"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"diff"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"systemCoverage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalSystems"}},{"kind":"Field","name":{"kind":"Name","value":"fullyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"partiallyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"unclassified"}},{"kind":"Field","name":{"kind":"Name","value":"withoutSteward"}},{"kind":"Field","name":{"kind":"Name","value":"coveragePercentage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"privacyRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeCount"}},{"kind":"Field","name":{"kind":"Name","value":"overdueCount"}},{"kind":"Field","name":{"kind":"Name","value":"statuses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inProgress"}},{"kind":"Field","name":{"kind":"Name","value":"pendingAction"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingApproval"}}]}},{"kind":"Field","name":{"kind":"Name","value":"slaHealth"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"onTrack"}},{"kind":"Field","name":{"kind":"Name","value":"approaching"}},{"kind":"Field","name":{"kind":"Name","value":"overdue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"astralis"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConversations"}},{"kind":"Field","name":{"kind":"Name","value":"completedAssessments"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingResponse"}},{"kind":"Field","name":{"kind":"Name","value":"risksIdentified"}}]}},{"kind":"InlineFragment","directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"label"},"value":{"kind":"StringValue","value":"agentBriefing","block":false}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agentBriefing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"briefing"}},{"kind":"Field","name":{"kind":"Name","value":"quickActions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"actionType"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const DashboardPriorityActionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardPriorityActions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"size"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"25"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dimension"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"priorityActions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"size"}}},{"kind":"Argument","name":{"kind":"Name","value":"dimension"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dimension"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"agentSummary"}},{"kind":"Field","name":{"kind":"Name","value":"dueDate"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]} as unknown as DocumentNode; -export const DashboardAstralisDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardAstralis"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"astralis"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConversations"}},{"kind":"Field","name":{"kind":"Name","value":"completedAssessments"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingResponse"}},{"kind":"Field","name":{"kind":"Name","value":"risksIdentified"}}]}}]}}]} as unknown as DocumentNode; -export const DashboardAgentBriefingDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardAgentBriefing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agentBriefing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"briefing"}},{"kind":"Field","name":{"kind":"Name","value":"quickActions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"actionType"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}}]}}]}}]}}]} as unknown as DocumentNode; export const DashboardActivityFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardActivityFeed"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"size"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activityFeed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"size"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"actorType"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/clients/admin-ui/src/features/dashboard-graphql/hooks.ts b/clients/admin-ui/src/features/dashboard-graphql/hooks.ts index 03ee8579d4a..cd5c69d0691 100644 --- a/clients/admin-ui/src/features/dashboard-graphql/hooks.ts +++ b/clients/admin-ui/src/features/dashboard-graphql/hooks.ts @@ -1,35 +1,36 @@ /** * Drop-in GraphQL replacements for the dashboard RTK Query hooks (Apollo). * + * The six static read-only cards share **one** combined `DashboardOverview` + * query with `@defer` on `agentBriefing`. Apollo deduplicates concurrent + * `useQuery(DashboardOverviewDocument)` calls with identical variables into + * a single network request, so all six hooks below issue exactly one POST + * — verify in DevTools → Network. The slow LLM-backed `agentBriefing` + * arrives in a second `multipart/mixed` chunk and re-renders only the + * banner; the rest of the dashboard paints from the initial chunk. + * + * `priorityActions` and `activityFeed` keep their own per-card queries — + * their interactive variables (dimension filter, infinite-scroll + * pagination) make them poor combined-query candidates. + * * Each hook keeps the exact name, call signature, and return shape of its - * counterpart in ~/features/dashboard/dashboard.slice, and maps the + * counterpart in ~/features/dashboard/dashboard.slice and maps the * camelCase GraphQL response back onto the existing snake_case - * ~/features/dashboard/types interfaces. That keeps every card component - * unchanged except for its import path. - * - * The mapped result is memoised on the raw query data. Apollo returns a - * stable `data` reference until the result actually changes, so the mapped - * object identity is stable too — without this, consumers that key effects - * on `data` (e.g. useInfiniteActivityFeed) re-fire setState every render - * and React throws "Maximum update depth exceeded". + * ~/features/dashboard/types interfaces. Cards change by one import line. * - * Per-card queries (not one combined query) on purpose: preserves - * independent auth failure and progressive per-card loading, matching the - * REST behaviour. dashboard.slice.ts is intentionally left in place - * (mutations stay on RTK; other consumers/tests may import it). + * The mapped result is memoised on the raw query slice. Apollo returns a + * stable `data` reference until the result changes, so the mapped object + * identity is stable too — without this, consumers that key effects on + * `data` (e.g. useInfiniteActivityFeed) re-fire setState every render and + * React throws "Maximum update depth exceeded". */ import { useQuery } from "@apollo/client"; import { useMemo } from "react"; import { DashboardActivityFeedDocument, - DashboardAgentBriefingDocument, - DashboardAstralisDocument, - DashboardPostureDocument, + DashboardOverviewDocument, DashboardPriorityActionsDocument, - DashboardPrivacyRequestsDocument, - DashboardSystemCoverageDocument, - DashboardTrendsDocument, TrendPeriod as GqlTrendPeriod, } from "~/__generated__/graphql/graphql"; import type { @@ -58,8 +59,17 @@ const TREND_PERIOD_TO_GQL: Record = { [TrendPeriod.NINETY_DAYS]: GqlTrendPeriod.NinetyDays, }; +// All six static hooks call the combined query with the same default +// trendPeriod so Apollo merges them into one request. The trends hook +// accepts a `period` param for drop-in parity; passing a non-default +// period would (correctly) refetch the whole combined query. +const useDashboardOverview = (period: TrendPeriod = TrendPeriod.THIRTY_DAYS) => + useQuery(DashboardOverviewDocument, { + variables: { trendPeriod: TREND_PERIOD_TO_GQL[period] }, + }); + export const useGetAgentBriefingQuery = () => { - const { data, loading } = useQuery(DashboardAgentBriefingDocument); + const { data } = useDashboardOverview(); const briefing = data?.agentBriefing; const mapped = useMemo( () => @@ -76,11 +86,13 @@ export const useGetAgentBriefingQuery = () => { : undefined, [briefing], ); - return { data: mapped, isLoading: loading }; + // agentBriefing is @defer'd — it stays absent until the second multipart + // chunk arrives, so the dashboard renders without waiting on it. + return { data: mapped, isLoading: !briefing }; }; export const useGetDashboardPostureQuery = () => { - const { data, loading } = useQuery(DashboardPostureDocument); + const { data, loading } = useDashboardOverview(); const p = data?.posture; const mapped = useMemo( () => @@ -102,11 +114,11 @@ export const useGetDashboardPostureQuery = () => { : undefined, [p], ); - return { data: mapped, isLoading: loading }; + return { data: mapped, isLoading: loading && !p }; }; export const useGetSystemCoverageQuery = () => { - const { data, loading } = useQuery(DashboardSystemCoverageDocument); + const { data, loading } = useDashboardOverview(); const c = data?.systemCoverage; const mapped = useMemo( () => @@ -122,11 +134,11 @@ export const useGetSystemCoverageQuery = () => { : undefined, [c], ); - return { data: mapped, isLoading: loading }; + return { data: mapped, isLoading: loading && !c }; }; export const useGetPrivacyRequestsQuery = () => { - const { data, loading } = useQuery(DashboardPrivacyRequestsDocument); + const { data, loading } = useDashboardOverview(); const pr = data?.privacyRequests; const mapped = useMemo( () => @@ -153,11 +165,11 @@ export const useGetPrivacyRequestsQuery = () => { : undefined, [pr], ); - return { data: mapped, isLoading: loading }; + return { data: mapped, isLoading: loading && !pr }; }; export const useGetAstralisQuery = () => { - const { data, loading } = useQuery(DashboardAstralisDocument); + const { data, loading } = useDashboardOverview(); const a = data?.astralis; const mapped = useMemo( () => @@ -171,7 +183,7 @@ export const useGetAstralisQuery = () => { : undefined, [a], ); - return { data: mapped, isLoading: loading }; + return { data: mapped, isLoading: loading && !a }; }; export const useGetDashboardTrendsQuery = ({ @@ -179,9 +191,7 @@ export const useGetDashboardTrendsQuery = ({ }: { period: TrendPeriod; }) => { - const { data, loading } = useQuery(DashboardTrendsDocument, { - variables: { period: TREND_PERIOD_TO_GQL[period] }, - }); + const { data, loading } = useDashboardOverview(period); const t = data?.trends; const mapped = useMemo( () => @@ -202,7 +212,7 @@ export const useGetDashboardTrendsQuery = ({ : undefined, [t], ); - return { data: mapped, isLoading: loading }; + return { data: mapped, isLoading: loading && !t }; }; interface PriorityActionsParams { diff --git a/clients/admin-ui/src/features/dashboard-graphql/queries.graphql b/clients/admin-ui/src/features/dashboard-graphql/queries.graphql index d154c7fd2a5..82fbf082c15 100644 --- a/clients/admin-ui/src/features/dashboard-graphql/queries.graphql +++ b/clients/admin-ui/src/features/dashboard-graphql/queries.graphql @@ -1,4 +1,4 @@ -query DashboardPosture { +query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) { posture { score band @@ -13,10 +13,7 @@ query DashboardPosture { band } } -} - -query DashboardTrends($period: TrendPeriod! = thirty_days) { - trends(period: $period) { + trends(period: $trendPeriod) { period metrics { key @@ -26,9 +23,6 @@ query DashboardTrends($period: TrendPeriod! = thirty_days) { diff } } -} - -query DashboardSystemCoverage { systemCoverage { totalSystems fullyClassified @@ -37,9 +31,6 @@ query DashboardSystemCoverage { withoutSteward coveragePercentage } -} - -query DashboardPrivacyRequests { privacyRequests { activeCount overdueCount @@ -55,6 +46,23 @@ query DashboardPrivacyRequests { overdue } } + astralis { + activeConversations + completedAssessments + awaitingResponse + risksIdentified + } + ... @defer(label: "agentBriefing") { + agentBriefing { + briefing + quickActions { + label + actionType + severity + actionData + } + } + } } query DashboardPriorityActions( @@ -81,27 +89,6 @@ query DashboardPriorityActions( } } -query DashboardAstralis { - astralis { - activeConversations - completedAssessments - awaitingResponse - risksIdentified - } -} - -query DashboardAgentBriefing { - agentBriefing { - briefing - quickActions { - label - actionType - severity - actionData - } - } -} - query DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) { activityFeed(page: $page, size: $size) { items { From 918f9f6a4ee76d96acab65af7ddae471df508c6a Mon Sep 17 00:00:00 2001 From: Karolis Date: Tue, 19 May 2026 00:27:53 -0400 Subject: [PATCH 08/10] graphql poc apollo: drop noisy POC-NOTES Decisions live in the separate decisions doc; this file mostly duplicated that and held conversation-style context that isn't useful to readers. Co-Authored-By: Claude Opus 4.7 (1M context) --- POC-NOTES.md | 68 ---------------------------------------------------- 1 file changed, 68 deletions(-) delete mode 100644 POC-NOTES.md diff --git a/POC-NOTES.md b/POC-NOTES.md deleted file mode 100644 index 8059e12f826..00000000000 --- a/POC-NOTES.md +++ /dev/null @@ -1,68 +0,0 @@ -# GraphQL PoC — Frontend (Apollo) notes — `graphql-poc-apollo` - -Paired BE branch: `graphql-poc-be` in **fidesplus** (HEAD `e45dc01b1`; SDL unchanged since `104cba76c`). -Sibling FE branch (urql): `graphql-poc-urql` in fides. - -**The real dashboard at `/` now runs on GraphQL.** There is no separate page — the existing `HomeDashboard` cards fetch through Apollo via per-card queries. The standalone `/dashboard-graphql` route and its bespoke view were removed. - -## Architecture: per-card queries, drop-in hooks - -Each card keeps its own query (not one combined query). Decision rationale (discussed with the team): - -- **Independent auth.** Cards map to different permissions/feature flags in the real product. Per-card queries fail independently — an unauthorised card hides itself, the rest of the dashboard is unaffected — exactly mirroring the REST behaviour. One combined query would force field-level auth + partial-error handling on the client. -- **Progressive loading.** One combined query blocks the whole dashboard on the slowest resolver, and `agent_briefing` is LLM-backed (slow). Per-card preserves card-by-card spinner-then-paint. - -Implementation keeps the blast radius tiny: `src/features/dashboard-graphql/hooks.ts` exports replacements with the **exact names, signatures, and return shapes** of the dashboard RTK Query hooks, mapping each camelCase GraphQL response back onto the existing snake_case `~/features/dashboard/types` interfaces. Every card changed by **one line** — its import path. Card JSX/logic is untouched. - -`dashboard.slice.ts` is intentionally left in place (the priority-action update mutation stays on RTK; other code/tests may import it). The GraphQL surface replaces only the read queries the dashboard consumes. - -## Try it locally - -```bash -# Mocks, no BE (schema-driven via @graphql-tools/mock): -cd clients/admin-ui && npm run dev:mock-graphql - -# Against the real BE (fidesplus on graphql-poc-be): -cd clients/admin-ui && npm run dev - -open http://localhost:3000/ # the real dashboard, now on GraphQL -``` - -The dashboard cards render under the `alphaDashboard` feature flag (same as before this change). - -After a schema change: `nox -s graphql_emit_schema` in fidesplus, then `npm run graphql:generate` in admin-ui. - -## Comparison metrics (Apollo) - -- **FE lines of code to wire the whole dashboard** - - `queries.graphql` (8 per-card operations): ~110 lines (SDL-shaped; identical on the urql branch). - - Provider + Apollo client + auth link: `DashboardGraphqlProvider.tsx` 13 + `apolloClient.ts` ~36 = **~49 lines**. - - `hooks.ts` drop-in adapter layer (8 hooks + camel→snake mappers): **~250 lines**. This is the real Apollo-specific surface; most of it is the response remapping that exists only because we kept the REST-shaped card contracts. - - Per card: **1 line** (the import path). -- **Bundle size delta**: Apollo Client + graphql ≈ **~50 KB gzipped** added. Run `npm run analyze:browser` and diff the home route chunk for an exact figure (estimate pending real measurement). -- **Setup time** (excluding shared BE): the original single-query wiring ~2 h; the per-card refactor + drop-in hook layer ~1.5 h on top. - -## Rough edges - -- **The adapter layer is the cost.** Keeping the existing card contracts (snake_case `types.ts`) means every GraphQL response is remapped by hand in `hooks.ts`. If the cards were rewritten to consume the generated gql types directly, that ~250-line layer mostly disappears — but then it's not a drop-in and the diff explodes across 8 components. The drop-in tradeoff is deliberate for a PoC; a real migration would bite the bullet and consume gql types directly. -- **Enum value skew.** Most enums share string values between the gql SDL and `types.ts`, *except* `TrendPeriod` (SDL `thirty_days` vs REST `30d`) — needs an explicit map. Easy to miss. -- **`ActivityFeedItem` has no `id`** in the schema, but the infinite-scroll dedupe keys on `id`. The adapter synthesises `id = ${timestamp}__${message}` so `useInfiniteActivityFeed` works unmodified. A real schema should expose a stable id. -- **`client-preset` `gql()` template-literal typing is brittle** (whitespace-sensitive). Importing the generated `*Document` constants is the reliable path; all hooks do that. -- **SDL-as-runtime-string for mocks**: no bundler-agnostic ".graphql as string" import, so `scripts/sync-graphql-sdl.mjs` writes `schema-string.ts` from `schema.graphql` during `graphql:generate`. -- **Client URL**: the endpoint is at root `/graphql`, not under `NEXT_PUBLIC_FIDESCTL_API` (`/api/v1`). The client posts to a hard `/graphql`; a Next rewrite proxies it to the backend and MSW intercepts it in mock mode. (Earlier this PoC wrongly assumed that env var was empty.) - -## What ships in this branch - -- `clients/admin-ui/schema.graphql` — emitted by the fidesplus PoC. -- `clients/admin-ui/codegen.ts`, `scripts/sync-graphql-sdl.mjs`, `src/__generated__/graphql/`. -- `src/features/dashboard-graphql/`: `DashboardGraphqlProvider.tsx`, `apolloClient.ts`, `queries.graphql` (8 ops), `hooks.ts` (drop-in adapters), `schema-string.ts`. -- `src/mocks/dashboard-graphql/handlers.ts` — schema-driven MSW handler (mocks every per-card query). -- 9 one-line import swaps in `src/home/*` + `_app.tsx` provider wiring + `next.config.js` `/graphql` proxy. -- npm scripts: `graphql:generate`, `dev:mock-graphql`. - -## Not done / out of scope - -- No mutations, no subscriptions, no SSR. -- `dashboard.slice.ts` kept (mutations + potential other consumers); only read queries moved to gql. -- No `@defer` (would mitigate the combined-query loading problem, but we went per-card instead). -- No persisted queries, Apollo Studio, or schema registry. From 9606e566fe4d1379f054baad7ce877b0b7afe25d Mon Sep 17 00:00:00 2001 From: Karolis Date: Tue, 19 May 2026 09:31:46 -0400 Subject: [PATCH 09/10] new schema --- clients/admin-ui/schema.graphql | 4 ++++ .../admin-ui/src/features/dashboard-graphql/schema-string.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clients/admin-ui/schema.graphql b/clients/admin-ui/schema.graphql index 2a8a78c4690..9b94116d83c 100644 --- a/clients/admin-ui/schema.graphql +++ b/clients/admin-ui/schema.graphql @@ -1,3 +1,7 @@ +directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT + +directive @stream(if: Boolean, label: String, initialCount: Int = 0) on FIELD + enum ActionSeverity { critical high diff --git a/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts b/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts index e8501e703a7..fdd81b682e9 100644 --- a/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts +++ b/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts @@ -2,4 +2,4 @@ // AUTOGENERATED by scripts/sync-graphql-sdl.mjs. Do not edit by hand. // Run `npm run graphql:generate` to refresh. -export const dashboardSchemaSDL = "enum ActionSeverity {\n critical\n high\n medium\n low\n}\n\ntype ActivityFeedItem {\n actorType: ActorType!\n message: String!\n timestamp: DateTime!\n}\n\ntype ActivityFeedPage {\n items: [ActivityFeedItem!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\nenum ActorType {\n user\n agent\n}\n\ntype AgentBriefing {\n briefing: String!\n quickActions: [QuickAction!]!\n}\n\ntype Astralis {\n activeConversations: Int!\n completedAssessments: Int!\n awaitingResponse: Int!\n risksIdentified: Int!\n}\n\nenum DashboardActionStatus {\n pending\n in_progress\n completed\n}\n\nenum DashboardActionType {\n classification_review\n dsr_action\n system_review\n steward_assignment\n consent_anomaly\n policy_violation\n pia_update\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\nenum DiffDirection {\n up\n down\n unchanged\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Posture {\n score: Float!\n band: PostureBand!\n diffPercent: Float!\n diffDirection: DiffDirection!\n agentAnnotation: String!\n dimensions: [PostureDimension!]!\n}\n\nenum PostureBand {\n critical\n at_risk\n good\n excellent\n}\n\ntype PostureDimension {\n dimension: String!\n label: String!\n weight: Float!\n score: Float!\n band: PostureBand!\n}\n\ntype PriorityAction {\n id: ID!\n type: DashboardActionType!\n severity: ActionSeverity!\n title: String!\n message: String!\n agentSummary: String!\n dueDate: DateTime\n actionData: JSON!\n status: DashboardActionStatus!\n}\n\ntype PriorityActionsPage {\n items: [PriorityAction!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\ntype PrivacyRequestStatuses {\n inProgress: Int!\n pendingAction: Int!\n awaitingApproval: Int!\n}\n\ntype PrivacyRequests {\n activeCount: Int!\n statuses: PrivacyRequestStatuses!\n overdueCount: Int!\n slaHealth: [SLAHealthBucket!]!\n}\n\ntype Query {\n agentBriefing: AgentBriefing!\n posture: Posture!\n trends(period: TrendPeriod! = thirty_days): Trends!\n astralis: Astralis!\n activityFeed(page: Int! = 1, size: Int! = 20): ActivityFeedPage!\n privacyRequests: PrivacyRequests!\n systemCoverage: SystemCoverage!\n priorityActions(page: Int! = 1, size: Int! = 8, action: DashboardActionType = null, status: DashboardActionStatus = null, dimension: String = null): PriorityActionsPage!\n}\n\ntype QuickAction {\n label: String!\n actionType: DashboardActionType!\n actionData: JSON!\n severity: ActionSeverity!\n}\n\ntype SLAHealthBucket {\n label: String!\n onTrack: Int!\n approaching: Int!\n overdue: Int!\n}\n\ntype SystemCoverage {\n totalSystems: Int!\n fullyClassified: Int!\n partiallyClassified: Int!\n unclassified: Int!\n withoutSteward: Int!\n coveragePercentage: Float!\n}\n\ntype TrendMetric {\n key: String!\n value: Float!\n history: [Float!]!\n metadata: JSON!\n diff: Float!\n}\n\nenum TrendPeriod {\n thirty_days\n sixty_days\n ninety_days\n}\n\ntype Trends {\n period: TrendPeriod!\n metrics: [TrendMetric!]!\n}\n"; +export const dashboardSchemaSDL = "directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT\n\ndirective @stream(if: Boolean, label: String, initialCount: Int = 0) on FIELD\n\nenum ActionSeverity {\n critical\n high\n medium\n low\n}\n\ntype ActivityFeedItem {\n actorType: ActorType!\n message: String!\n timestamp: DateTime!\n}\n\ntype ActivityFeedPage {\n items: [ActivityFeedItem!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\nenum ActorType {\n user\n agent\n}\n\ntype AgentBriefing {\n briefing: String!\n quickActions: [QuickAction!]!\n}\n\ntype Astralis {\n activeConversations: Int!\n completedAssessments: Int!\n awaitingResponse: Int!\n risksIdentified: Int!\n}\n\nenum DashboardActionStatus {\n pending\n in_progress\n completed\n}\n\nenum DashboardActionType {\n classification_review\n dsr_action\n system_review\n steward_assignment\n consent_anomaly\n policy_violation\n pia_update\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\nenum DiffDirection {\n up\n down\n unchanged\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Posture {\n score: Float!\n band: PostureBand!\n diffPercent: Float!\n diffDirection: DiffDirection!\n agentAnnotation: String!\n dimensions: [PostureDimension!]!\n}\n\nenum PostureBand {\n critical\n at_risk\n good\n excellent\n}\n\ntype PostureDimension {\n dimension: String!\n label: String!\n weight: Float!\n score: Float!\n band: PostureBand!\n}\n\ntype PriorityAction {\n id: ID!\n type: DashboardActionType!\n severity: ActionSeverity!\n title: String!\n message: String!\n agentSummary: String!\n dueDate: DateTime\n actionData: JSON!\n status: DashboardActionStatus!\n}\n\ntype PriorityActionsPage {\n items: [PriorityAction!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\ntype PrivacyRequestStatuses {\n inProgress: Int!\n pendingAction: Int!\n awaitingApproval: Int!\n}\n\ntype PrivacyRequests {\n activeCount: Int!\n statuses: PrivacyRequestStatuses!\n overdueCount: Int!\n slaHealth: [SLAHealthBucket!]!\n}\n\ntype Query {\n agentBriefing: AgentBriefing!\n posture: Posture!\n trends(period: TrendPeriod! = thirty_days): Trends!\n astralis: Astralis!\n activityFeed(page: Int! = 1, size: Int! = 20): ActivityFeedPage!\n privacyRequests: PrivacyRequests!\n systemCoverage: SystemCoverage!\n priorityActions(page: Int! = 1, size: Int! = 8, action: DashboardActionType = null, status: DashboardActionStatus = null, dimension: String = null): PriorityActionsPage!\n}\n\ntype QuickAction {\n label: String!\n actionType: DashboardActionType!\n actionData: JSON!\n severity: ActionSeverity!\n}\n\ntype SLAHealthBucket {\n label: String!\n onTrack: Int!\n approaching: Int!\n overdue: Int!\n}\n\ntype SystemCoverage {\n totalSystems: Int!\n fullyClassified: Int!\n partiallyClassified: Int!\n unclassified: Int!\n withoutSteward: Int!\n coveragePercentage: Float!\n}\n\ntype TrendMetric {\n key: String!\n value: Float!\n history: [Float!]!\n metadata: JSON!\n diff: Float!\n}\n\nenum TrendPeriod {\n thirty_days\n sixty_days\n ninety_days\n}\n\ntype Trends {\n period: TrendPeriod!\n metrics: [TrendMetric!]!\n}\n"; From 4501f8ea503dec111875b31f2ec4104bb1c9308e Mon Sep 17 00:00:00 2001 From: Karolis Date: Wed, 20 May 2026 14:17:04 -0400 Subject: [PATCH 10/10] fix(ci): prettier-format generated GraphQL artifacts Run prettier --write on graphql codegen output and schema files to satisfy the admin-ui format:ci check. No behavior changes; only quote style and line-wrap adjustments to auto-generated files (schema.graphql, src/__generated__/graphql/*, schema-string.ts). --- clients/admin-ui/schema.graphql | 22 +- .../__generated__/graphql/fragment-masking.ts | 82 +- .../admin-ui/src/__generated__/graphql/gql.ts | 16 +- .../src/__generated__/graphql/graphql.ts | 879 +++++++++++++++--- .../src/__generated__/graphql/index.ts | 2 +- .../dashboard-graphql/schema-string.ts | 3 +- 6 files changed, 835 insertions(+), 169 deletions(-) diff --git a/clients/admin-ui/schema.graphql b/clients/admin-ui/schema.graphql index 9b94116d83c..411a1d172f2 100644 --- a/clients/admin-ui/schema.graphql +++ b/clients/admin-ui/schema.graphql @@ -1,4 +1,7 @@ -directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT +directive @defer( + if: Boolean + label: String +) on FRAGMENT_SPREAD | INLINE_FRAGMENT directive @stream(if: Boolean, label: String, initialCount: Int = 0) on FIELD @@ -56,7 +59,9 @@ enum DashboardActionType { pia_update } -"""Date with time (isoformat)""" +""" +Date with time (isoformat) +""" scalar DateTime enum DiffDirection { @@ -68,7 +73,10 @@ enum DiffDirection { """ The `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf). """ -scalar JSON @specifiedBy(url: "https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf") +scalar JSON + @specifiedBy( + url: "https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf" + ) type Posture { score: Float! @@ -135,7 +143,13 @@ type Query { activityFeed(page: Int! = 1, size: Int! = 20): ActivityFeedPage! privacyRequests: PrivacyRequests! systemCoverage: SystemCoverage! - priorityActions(page: Int! = 1, size: Int! = 8, action: DashboardActionType = null, status: DashboardActionStatus = null, dimension: String = null): PriorityActionsPage! + priorityActions( + page: Int! = 1 + size: Int! = 8 + action: DashboardActionType = null + status: DashboardActionStatus = null + dimension: String = null + ): PriorityActionsPage! } type QuickAction { diff --git a/clients/admin-ui/src/__generated__/graphql/fragment-masking.ts b/clients/admin-ui/src/__generated__/graphql/fragment-masking.ts index 743a364fe18..39ab74bd201 100644 --- a/clients/admin-ui/src/__generated__/graphql/fragment-masking.ts +++ b/clients/admin-ui/src/__generated__/graphql/fragment-masking.ts @@ -1,87 +1,111 @@ /* eslint-disable */ -import type { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core'; -import type { FragmentDefinitionNode } from 'graphql'; -import type { Incremental } from './graphql'; +import type { + ResultOf, + DocumentTypeDecoration, + TypedDocumentNode, +} from "@graphql-typed-document-node/core"; +import type { FragmentDefinitionNode } from "graphql"; +import type { Incremental } from "./graphql"; - -export type FragmentType> = TDocumentType extends DocumentTypeDecoration< - infer TType, - any -> - ? [TType] extends [{ ' $fragmentName'?: infer TKey }] - ? TKey extends string - ? { ' $fragmentRefs'?: { [key in TKey]: TType } } +export type FragmentType< + TDocumentType extends DocumentTypeDecoration, +> = + TDocumentType extends DocumentTypeDecoration + ? [TType] extends [{ " $fragmentName"?: infer TKey }] + ? TKey extends string + ? { " $fragmentRefs"?: { [key in TKey]: TType } } + : never : never - : never - : never; + : never; // return non-nullable if `fragmentType` is non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: FragmentType> + fragmentType: FragmentType>, ): TType; // return nullable if `fragmentType` is undefined export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: FragmentType> | undefined + fragmentType: FragmentType> | undefined, ): TType | undefined; // return nullable if `fragmentType` is nullable export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: FragmentType> | null + fragmentType: FragmentType> | null, ): TType | null; // return nullable if `fragmentType` is nullable or undefined export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: FragmentType> | null | undefined + fragmentType: + | FragmentType> + | null + | undefined, ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: Array>> + fragmentType: Array>>, ): Array; // return array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: Array>> | null | undefined + fragmentType: + | Array>> + | null + | undefined, ): Array | null | undefined; // return readonly array of non-nullable if `fragmentType` is array of non-nullable export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: ReadonlyArray>> + fragmentType: ReadonlyArray>>, ): ReadonlyArray; // return readonly array of nullable if `fragmentType` is array of nullable export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: ReadonlyArray>> | null | undefined + fragmentType: + | ReadonlyArray>> + | null + | undefined, ): ReadonlyArray | null | undefined; export function useFragment( _documentNode: DocumentTypeDecoration, - fragmentType: FragmentType> | Array>> | ReadonlyArray>> | null | undefined + fragmentType: + | FragmentType> + | Array>> + | ReadonlyArray>> + | null + | undefined, ): TType | Array | ReadonlyArray | null | undefined { return fragmentType as any; } - export function makeFragmentData< F extends DocumentTypeDecoration, - FT extends ResultOf + FT extends ResultOf, >(data: FT, _fragment: F): FragmentType { return data as FragmentType; } export function isFragmentReady( queryNode: DocumentTypeDecoration, fragmentNode: TypedDocumentNode, - data: FragmentType, any>> | null | undefined + data: + | FragmentType, any>> + | null + | undefined, ): data is FragmentType { - const deferredFields = (queryNode as { __meta__?: { deferredFields: Record } }).__meta__ - ?.deferredFields; + const deferredFields = ( + queryNode as { + __meta__?: { deferredFields: Record }; + } + ).__meta__?.deferredFields; if (!deferredFields) return true; - const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined; + const fragDef = fragmentNode.definitions[0] as + | FragmentDefinitionNode + | undefined; const fragName = fragDef?.name?.value; const fields = (fragName && deferredFields[fragName]) || []; - return fields.length > 0 && fields.every(field => data && field in data); + return fields.length > 0 && fields.every((field) => data && field in data); } diff --git a/clients/admin-ui/src/__generated__/graphql/gql.ts b/clients/admin-ui/src/__generated__/graphql/gql.ts index c7c5371c2ee..ac6b9eae3c2 100644 --- a/clients/admin-ui/src/__generated__/graphql/gql.ts +++ b/clients/admin-ui/src/__generated__/graphql/gql.ts @@ -1,6 +1,6 @@ /* eslint-disable */ -import * as types from './graphql'; -import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import * as types from "./graphql"; +import type { TypedDocumentNode as DocumentNode } from "@graphql-typed-document-node/core"; /** * Map of all GraphQL operations in the project. @@ -14,10 +14,11 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { - "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: \"agentBriefing\") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": typeof types.DashboardOverviewDocument, + 'query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: "agentBriefing") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}': typeof types.DashboardOverviewDocument; }; const documents: Documents = { - "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: \"agentBriefing\") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}": types.DashboardOverviewDocument, + 'query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: "agentBriefing") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}': + types.DashboardOverviewDocument, }; /** @@ -37,10 +38,13 @@ export function gql(source: string): unknown; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: \"agentBriefing\") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"): (typeof documents)["query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: \"agentBriefing\") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}"]; +export function gql( + source: 'query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: "agentBriefing") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}', +): (typeof documents)['query DashboardOverview($trendPeriod: TrendPeriod! = thirty_days) {\n posture {\n score\n band\n diffPercent\n diffDirection\n agentAnnotation\n dimensions {\n dimension\n label\n weight\n score\n band\n }\n }\n trends(period: $trendPeriod) {\n period\n metrics {\n key\n value\n history\n metadata\n diff\n }\n }\n systemCoverage {\n totalSystems\n fullyClassified\n partiallyClassified\n unclassified\n withoutSteward\n coveragePercentage\n }\n privacyRequests {\n activeCount\n overdueCount\n statuses {\n inProgress\n pendingAction\n awaitingApproval\n }\n slaHealth {\n label\n onTrack\n approaching\n overdue\n }\n }\n astralis {\n activeConversations\n completedAssessments\n awaitingResponse\n risksIdentified\n }\n ... @defer(label: "agentBriefing") {\n agentBriefing {\n briefing\n quickActions {\n label\n actionType\n severity\n actionData\n }\n }\n }\n}\n\nquery DashboardPriorityActions($page: Int! = 1, $size: Int! = 25, $dimension: String) {\n priorityActions(page: $page, size: $size, dimension: $dimension) {\n items {\n id\n type\n severity\n title\n message\n agentSummary\n dueDate\n actionData\n status\n }\n total\n page\n size\n pages\n }\n}\n\nquery DashboardActivityFeed($page: Int! = 1, $size: Int! = 20) {\n activityFeed(page: $page, size: $size) {\n items {\n actorType\n message\n timestamp\n }\n total\n page\n size\n pages\n }\n}']; export function gql(source: string) { return (documents as any)[source] ?? {}; } -export type DocumentType> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never; \ No newline at end of file +export type DocumentType> = + TDocumentNode extends DocumentNode ? TType : never; diff --git a/clients/admin-ui/src/__generated__/graphql/graphql.ts b/clients/admin-ui/src/__generated__/graphql/graphql.ts index 3e795e9fe54..344127e7e71 100644 --- a/clients/admin-ui/src/__generated__/graphql/graphql.ts +++ b/clients/admin-ui/src/__generated__/graphql/graphql.ts @@ -1,154 +1,167 @@ /* eslint-disable */ -import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; +import type { TypedDocumentNode as DocumentNode } from "@graphql-typed-document-node/core"; export type Maybe = T | null; export type InputMaybe = Maybe; -export type Exact = { [K in keyof T]: T[K] }; -export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; -export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; -export type MakeEmpty = { [_ in K]?: never }; -export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +export type Exact = { + [K in keyof T]: T[K]; +}; +export type MakeOptional = Omit & { + [SubKey in K]?: Maybe; +}; +export type MakeMaybe = Omit & { + [SubKey in K]: Maybe; +}; +export type MakeEmpty< + T extends { [key: string]: unknown }, + K extends keyof T, +> = { [_ in K]?: never }; +export type Incremental = + | T + | { + [P in keyof T]?: P extends " $fragmentName" | "__typename" ? T[P] : never; + }; /** All built-in and custom scalars, mapped to their actual values */ export type Scalars = { - ID: { input: string; output: string; } - String: { input: string; output: string; } - Boolean: { input: boolean; output: boolean; } - Int: { input: number; output: number; } - Float: { input: number; output: number; } + ID: { input: string; output: string }; + String: { input: string; output: string }; + Boolean: { input: boolean; output: boolean }; + Int: { input: number; output: number }; + Float: { input: number; output: number }; /** Date with time (isoformat) */ - DateTime: { input: string; output: string; } + DateTime: { input: string; output: string }; /** The `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf). */ - JSON: { input: Record; output: Record; } + JSON: { input: Record; output: Record }; }; export enum ActionSeverity { - Critical = 'critical', - High = 'high', - Low = 'low', - Medium = 'medium' + Critical = "critical", + High = "high", + Low = "low", + Medium = "medium", } export type ActivityFeedItem = { - __typename?: 'ActivityFeedItem'; + __typename?: "ActivityFeedItem"; actorType: ActorType; - message: Scalars['String']['output']; - timestamp: Scalars['DateTime']['output']; + message: Scalars["String"]["output"]; + timestamp: Scalars["DateTime"]["output"]; }; export type ActivityFeedPage = { - __typename?: 'ActivityFeedPage'; + __typename?: "ActivityFeedPage"; items: Array; - page: Scalars['Int']['output']; - pages: Scalars['Int']['output']; - size: Scalars['Int']['output']; - total: Scalars['Int']['output']; + page: Scalars["Int"]["output"]; + pages: Scalars["Int"]["output"]; + size: Scalars["Int"]["output"]; + total: Scalars["Int"]["output"]; }; export enum ActorType { - Agent = 'agent', - User = 'user' + Agent = "agent", + User = "user", } export type AgentBriefing = { - __typename?: 'AgentBriefing'; - briefing: Scalars['String']['output']; + __typename?: "AgentBriefing"; + briefing: Scalars["String"]["output"]; quickActions: Array; }; export type Astralis = { - __typename?: 'Astralis'; - activeConversations: Scalars['Int']['output']; - awaitingResponse: Scalars['Int']['output']; - completedAssessments: Scalars['Int']['output']; - risksIdentified: Scalars['Int']['output']; + __typename?: "Astralis"; + activeConversations: Scalars["Int"]["output"]; + awaitingResponse: Scalars["Int"]["output"]; + completedAssessments: Scalars["Int"]["output"]; + risksIdentified: Scalars["Int"]["output"]; }; export enum DashboardActionStatus { - Completed = 'completed', - InProgress = 'in_progress', - Pending = 'pending' + Completed = "completed", + InProgress = "in_progress", + Pending = "pending", } export enum DashboardActionType { - ClassificationReview = 'classification_review', - ConsentAnomaly = 'consent_anomaly', - DsrAction = 'dsr_action', - PiaUpdate = 'pia_update', - PolicyViolation = 'policy_violation', - StewardAssignment = 'steward_assignment', - SystemReview = 'system_review' + ClassificationReview = "classification_review", + ConsentAnomaly = "consent_anomaly", + DsrAction = "dsr_action", + PiaUpdate = "pia_update", + PolicyViolation = "policy_violation", + StewardAssignment = "steward_assignment", + SystemReview = "system_review", } export enum DiffDirection { - Down = 'down', - Unchanged = 'unchanged', - Up = 'up' + Down = "down", + Unchanged = "unchanged", + Up = "up", } export type Posture = { - __typename?: 'Posture'; - agentAnnotation: Scalars['String']['output']; + __typename?: "Posture"; + agentAnnotation: Scalars["String"]["output"]; band: PostureBand; diffDirection: DiffDirection; - diffPercent: Scalars['Float']['output']; + diffPercent: Scalars["Float"]["output"]; dimensions: Array; - score: Scalars['Float']['output']; + score: Scalars["Float"]["output"]; }; export enum PostureBand { - AtRisk = 'at_risk', - Critical = 'critical', - Excellent = 'excellent', - Good = 'good' + AtRisk = "at_risk", + Critical = "critical", + Excellent = "excellent", + Good = "good", } export type PostureDimension = { - __typename?: 'PostureDimension'; + __typename?: "PostureDimension"; band: PostureBand; - dimension: Scalars['String']['output']; - label: Scalars['String']['output']; - score: Scalars['Float']['output']; - weight: Scalars['Float']['output']; + dimension: Scalars["String"]["output"]; + label: Scalars["String"]["output"]; + score: Scalars["Float"]["output"]; + weight: Scalars["Float"]["output"]; }; export type PriorityAction = { - __typename?: 'PriorityAction'; - actionData: Scalars['JSON']['output']; - agentSummary: Scalars['String']['output']; - dueDate?: Maybe; - id: Scalars['ID']['output']; - message: Scalars['String']['output']; + __typename?: "PriorityAction"; + actionData: Scalars["JSON"]["output"]; + agentSummary: Scalars["String"]["output"]; + dueDate?: Maybe; + id: Scalars["ID"]["output"]; + message: Scalars["String"]["output"]; severity: ActionSeverity; status: DashboardActionStatus; - title: Scalars['String']['output']; + title: Scalars["String"]["output"]; type: DashboardActionType; }; export type PriorityActionsPage = { - __typename?: 'PriorityActionsPage'; + __typename?: "PriorityActionsPage"; items: Array; - page: Scalars['Int']['output']; - pages: Scalars['Int']['output']; - size: Scalars['Int']['output']; - total: Scalars['Int']['output']; + page: Scalars["Int"]["output"]; + pages: Scalars["Int"]["output"]; + size: Scalars["Int"]["output"]; + total: Scalars["Int"]["output"]; }; export type PrivacyRequestStatuses = { - __typename?: 'PrivacyRequestStatuses'; - awaitingApproval: Scalars['Int']['output']; - inProgress: Scalars['Int']['output']; - pendingAction: Scalars['Int']['output']; + __typename?: "PrivacyRequestStatuses"; + awaitingApproval: Scalars["Int"]["output"]; + inProgress: Scalars["Int"]["output"]; + pendingAction: Scalars["Int"]["output"]; }; export type PrivacyRequests = { - __typename?: 'PrivacyRequests'; - activeCount: Scalars['Int']['output']; - overdueCount: Scalars['Int']['output']; + __typename?: "PrivacyRequests"; + activeCount: Scalars["Int"]["output"]; + overdueCount: Scalars["Int"]["output"]; slaHealth: Array; statuses: PrivacyRequestStatuses; }; export type Query = { - __typename?: 'Query'; + __typename?: "Query"; activityFeed: ActivityFeedPage; agentBriefing: AgentBriefing; astralis: Astralis; @@ -159,69 +172,66 @@ export type Query = { trends: Trends; }; - export type QueryActivityFeedArgs = { - page?: Scalars['Int']['input']; - size?: Scalars['Int']['input']; + page?: Scalars["Int"]["input"]; + size?: Scalars["Int"]["input"]; }; - export type QueryPriorityActionsArgs = { action?: InputMaybe; - dimension?: InputMaybe; - page?: Scalars['Int']['input']; - size?: Scalars['Int']['input']; + dimension?: InputMaybe; + page?: Scalars["Int"]["input"]; + size?: Scalars["Int"]["input"]; status?: InputMaybe; }; - export type QueryTrendsArgs = { period?: TrendPeriod; }; export type QuickAction = { - __typename?: 'QuickAction'; - actionData: Scalars['JSON']['output']; + __typename?: "QuickAction"; + actionData: Scalars["JSON"]["output"]; actionType: DashboardActionType; - label: Scalars['String']['output']; + label: Scalars["String"]["output"]; severity: ActionSeverity; }; export type SlaHealthBucket = { - __typename?: 'SLAHealthBucket'; - approaching: Scalars['Int']['output']; - label: Scalars['String']['output']; - onTrack: Scalars['Int']['output']; - overdue: Scalars['Int']['output']; + __typename?: "SLAHealthBucket"; + approaching: Scalars["Int"]["output"]; + label: Scalars["String"]["output"]; + onTrack: Scalars["Int"]["output"]; + overdue: Scalars["Int"]["output"]; }; export type SystemCoverage = { - __typename?: 'SystemCoverage'; - coveragePercentage: Scalars['Float']['output']; - fullyClassified: Scalars['Int']['output']; - partiallyClassified: Scalars['Int']['output']; - totalSystems: Scalars['Int']['output']; - unclassified: Scalars['Int']['output']; - withoutSteward: Scalars['Int']['output']; + __typename?: "SystemCoverage"; + coveragePercentage: Scalars["Float"]["output"]; + fullyClassified: Scalars["Int"]["output"]; + partiallyClassified: Scalars["Int"]["output"]; + totalSystems: Scalars["Int"]["output"]; + unclassified: Scalars["Int"]["output"]; + withoutSteward: Scalars["Int"]["output"]; }; export type TrendMetric = { - __typename?: 'TrendMetric'; - diff: Scalars['Float']['output']; - history: Array; - key: Scalars['String']['output']; - metadata: Scalars['JSON']['output']; - value: Scalars['Float']['output']; + __typename?: "TrendMetric"; + diff: Scalars["Float"]["output"]; + history: Array; + key: Scalars["String"]["output"]; + metadata: Scalars["JSON"]["output"]; + value: Scalars["Float"]["output"]; }; export enum TrendPeriod { - NinetyDays = 'ninety_days', - SixtyDays = 'sixty_days', - ThirtyDays = 'thirty_days' + NinetyDays = "ninety_days", + SixtyDays = "sixty_days", + ThirtyDays = "thirty_days", } export type Trends = { - __typename?: 'Trends'; + __typename?: "Trends"; metrics: Array; period: TrendPeriod; }; @@ -230,27 +240,640 @@ export type DashboardOverviewQueryVariables = Exact<{ trendPeriod?: TrendPeriod; }>; - -export type DashboardOverviewQuery = { __typename?: 'Query', posture: { __typename?: 'Posture', score: number, band: PostureBand, diffPercent: number, diffDirection: DiffDirection, agentAnnotation: string, dimensions: Array<{ __typename?: 'PostureDimension', dimension: string, label: string, weight: number, score: number, band: PostureBand }> }, trends: { __typename?: 'Trends', period: TrendPeriod, metrics: Array<{ __typename?: 'TrendMetric', key: string, value: number, history: Array, metadata: Record, diff: number }> }, systemCoverage: { __typename?: 'SystemCoverage', totalSystems: number, fullyClassified: number, partiallyClassified: number, unclassified: number, withoutSteward: number, coveragePercentage: number }, privacyRequests: { __typename?: 'PrivacyRequests', activeCount: number, overdueCount: number, statuses: { __typename?: 'PrivacyRequestStatuses', inProgress: number, pendingAction: number, awaitingApproval: number }, slaHealth: Array<{ __typename?: 'SLAHealthBucket', label: string, onTrack: number, approaching: number, overdue: number }> }, astralis: { __typename?: 'Astralis', activeConversations: number, completedAssessments: number, awaitingResponse: number, risksIdentified: number } } & ({ __typename?: 'Query', agentBriefing: { __typename?: 'AgentBriefing', briefing: string, quickActions: Array<{ __typename?: 'QuickAction', label: string, actionType: DashboardActionType, severity: ActionSeverity, actionData: Record }> } } | { __typename?: 'Query', agentBriefing?: never }); +export type DashboardOverviewQuery = { + __typename?: "Query"; + posture: { + __typename?: "Posture"; + score: number; + band: PostureBand; + diffPercent: number; + diffDirection: DiffDirection; + agentAnnotation: string; + dimensions: Array<{ + __typename?: "PostureDimension"; + dimension: string; + label: string; + weight: number; + score: number; + band: PostureBand; + }>; + }; + trends: { + __typename?: "Trends"; + period: TrendPeriod; + metrics: Array<{ + __typename?: "TrendMetric"; + key: string; + value: number; + history: Array; + metadata: Record; + diff: number; + }>; + }; + systemCoverage: { + __typename?: "SystemCoverage"; + totalSystems: number; + fullyClassified: number; + partiallyClassified: number; + unclassified: number; + withoutSteward: number; + coveragePercentage: number; + }; + privacyRequests: { + __typename?: "PrivacyRequests"; + activeCount: number; + overdueCount: number; + statuses: { + __typename?: "PrivacyRequestStatuses"; + inProgress: number; + pendingAction: number; + awaitingApproval: number; + }; + slaHealth: Array<{ + __typename?: "SLAHealthBucket"; + label: string; + onTrack: number; + approaching: number; + overdue: number; + }>; + }; + astralis: { + __typename?: "Astralis"; + activeConversations: number; + completedAssessments: number; + awaitingResponse: number; + risksIdentified: number; + }; +} & ( + | { + __typename?: "Query"; + agentBriefing: { + __typename?: "AgentBriefing"; + briefing: string; + quickActions: Array<{ + __typename?: "QuickAction"; + label: string; + actionType: DashboardActionType; + severity: ActionSeverity; + actionData: Record; + }>; + }; + } + | { __typename?: "Query"; agentBriefing?: never } +); export type DashboardPriorityActionsQueryVariables = Exact<{ - page?: Scalars['Int']['input']; - size?: Scalars['Int']['input']; - dimension?: InputMaybe; + page?: Scalars["Int"]["input"]; + size?: Scalars["Int"]["input"]; + dimension?: InputMaybe; }>; - -export type DashboardPriorityActionsQuery = { __typename?: 'Query', priorityActions: { __typename?: 'PriorityActionsPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'PriorityAction', id: string, type: DashboardActionType, severity: ActionSeverity, title: string, message: string, agentSummary: string, dueDate?: string | null, actionData: Record, status: DashboardActionStatus }> } }; +export type DashboardPriorityActionsQuery = { + __typename?: "Query"; + priorityActions: { + __typename?: "PriorityActionsPage"; + total: number; + page: number; + size: number; + pages: number; + items: Array<{ + __typename?: "PriorityAction"; + id: string; + type: DashboardActionType; + severity: ActionSeverity; + title: string; + message: string; + agentSummary: string; + dueDate?: string | null; + actionData: Record; + status: DashboardActionStatus; + }>; + }; +}; export type DashboardActivityFeedQueryVariables = Exact<{ - page?: Scalars['Int']['input']; - size?: Scalars['Int']['input']; + page?: Scalars["Int"]["input"]; + size?: Scalars["Int"]["input"]; }>; +export type DashboardActivityFeedQuery = { + __typename?: "Query"; + activityFeed: { + __typename?: "ActivityFeedPage"; + total: number; + page: number; + size: number; + pages: number; + items: Array<{ + __typename?: "ActivityFeedItem"; + actorType: ActorType; + message: string; + timestamp: string; + }>; + }; +}; -export type DashboardActivityFeedQuery = { __typename?: 'Query', activityFeed: { __typename?: 'ActivityFeedPage', total: number, page: number, size: number, pages: number, items: Array<{ __typename?: 'ActivityFeedItem', actorType: ActorType, message: string, timestamp: string }> } }; - - -export const DashboardOverviewDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardOverview"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"trendPeriod"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"TrendPeriod"}}},"defaultValue":{"kind":"EnumValue","value":"thirty_days"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"posture"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}},{"kind":"Field","name":{"kind":"Name","value":"diffPercent"}},{"kind":"Field","name":{"kind":"Name","value":"diffDirection"}},{"kind":"Field","name":{"kind":"Name","value":"agentAnnotation"}},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimension"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"weight"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"band"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"trends"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"period"},"value":{"kind":"Variable","name":{"kind":"Name","value":"trendPeriod"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"period"}},{"kind":"Field","name":{"kind":"Name","value":"metrics"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"history"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"diff"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"systemCoverage"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalSystems"}},{"kind":"Field","name":{"kind":"Name","value":"fullyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"partiallyClassified"}},{"kind":"Field","name":{"kind":"Name","value":"unclassified"}},{"kind":"Field","name":{"kind":"Name","value":"withoutSteward"}},{"kind":"Field","name":{"kind":"Name","value":"coveragePercentage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"privacyRequests"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeCount"}},{"kind":"Field","name":{"kind":"Name","value":"overdueCount"}},{"kind":"Field","name":{"kind":"Name","value":"statuses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"inProgress"}},{"kind":"Field","name":{"kind":"Name","value":"pendingAction"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingApproval"}}]}},{"kind":"Field","name":{"kind":"Name","value":"slaHealth"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"onTrack"}},{"kind":"Field","name":{"kind":"Name","value":"approaching"}},{"kind":"Field","name":{"kind":"Name","value":"overdue"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"astralis"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeConversations"}},{"kind":"Field","name":{"kind":"Name","value":"completedAssessments"}},{"kind":"Field","name":{"kind":"Name","value":"awaitingResponse"}},{"kind":"Field","name":{"kind":"Name","value":"risksIdentified"}}]}},{"kind":"InlineFragment","directives":[{"kind":"Directive","name":{"kind":"Name","value":"defer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"label"},"value":{"kind":"StringValue","value":"agentBriefing","block":false}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agentBriefing"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"briefing"}},{"kind":"Field","name":{"kind":"Name","value":"quickActions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"actionType"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const DashboardPriorityActionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardPriorityActions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"size"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"25"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"dimension"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"priorityActions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"size"}}},{"kind":"Argument","name":{"kind":"Name","value":"dimension"},"value":{"kind":"Variable","name":{"kind":"Name","value":"dimension"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"severity"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"agentSummary"}},{"kind":"Field","name":{"kind":"Name","value":"dueDate"}},{"kind":"Field","name":{"kind":"Name","value":"actionData"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]} as unknown as DocumentNode; -export const DashboardActivityFeedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"DashboardActivityFeed"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"1"}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"size"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},"defaultValue":{"kind":"IntValue","value":"20"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activityFeed"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"size"},"value":{"kind":"Variable","name":{"kind":"Name","value":"size"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"actorType"}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}}]}},{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"page"}},{"kind":"Field","name":{"kind":"Name","value":"size"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const DashboardOverviewDocument = { + kind: "Document", + definitions: [ + { + kind: "OperationDefinition", + operation: "query", + name: { kind: "Name", value: "DashboardOverview" }, + variableDefinitions: [ + { + kind: "VariableDefinition", + variable: { + kind: "Variable", + name: { kind: "Name", value: "trendPeriod" }, + }, + type: { + kind: "NonNullType", + type: { + kind: "NamedType", + name: { kind: "Name", value: "TrendPeriod" }, + }, + }, + defaultValue: { kind: "EnumValue", value: "thirty_days" }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "posture" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "score" } }, + { kind: "Field", name: { kind: "Name", value: "band" } }, + { kind: "Field", name: { kind: "Name", value: "diffPercent" } }, + { + kind: "Field", + name: { kind: "Name", value: "diffDirection" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "agentAnnotation" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "dimensions" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "dimension" }, + }, + { kind: "Field", name: { kind: "Name", value: "label" } }, + { + kind: "Field", + name: { kind: "Name", value: "weight" }, + }, + { kind: "Field", name: { kind: "Name", value: "score" } }, + { kind: "Field", name: { kind: "Name", value: "band" } }, + ], + }, + }, + ], + }, + }, + { + kind: "Field", + name: { kind: "Name", value: "trends" }, + arguments: [ + { + kind: "Argument", + name: { kind: "Name", value: "period" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "trendPeriod" }, + }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "period" } }, + { + kind: "Field", + name: { kind: "Name", value: "metrics" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "key" } }, + { kind: "Field", name: { kind: "Name", value: "value" } }, + { + kind: "Field", + name: { kind: "Name", value: "history" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "metadata" }, + }, + { kind: "Field", name: { kind: "Name", value: "diff" } }, + ], + }, + }, + ], + }, + }, + { + kind: "Field", + name: { kind: "Name", value: "systemCoverage" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "totalSystems" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "fullyClassified" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "partiallyClassified" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "unclassified" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "withoutSteward" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "coveragePercentage" }, + }, + ], + }, + }, + { + kind: "Field", + name: { kind: "Name", value: "privacyRequests" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "activeCount" } }, + { + kind: "Field", + name: { kind: "Name", value: "overdueCount" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "statuses" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "inProgress" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "pendingAction" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "awaitingApproval" }, + }, + ], + }, + }, + { + kind: "Field", + name: { kind: "Name", value: "slaHealth" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "label" } }, + { + kind: "Field", + name: { kind: "Name", value: "onTrack" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "approaching" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "overdue" }, + }, + ], + }, + }, + ], + }, + }, + { + kind: "Field", + name: { kind: "Name", value: "astralis" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "activeConversations" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "completedAssessments" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "awaitingResponse" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "risksIdentified" }, + }, + ], + }, + }, + { + kind: "InlineFragment", + directives: [ + { + kind: "Directive", + name: { kind: "Name", value: "defer" }, + arguments: [ + { + kind: "Argument", + name: { kind: "Name", value: "label" }, + value: { + kind: "StringValue", + value: "agentBriefing", + block: false, + }, + }, + ], + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "agentBriefing" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "briefing" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "quickActions" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "label" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "actionType" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "severity" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "actionData" }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode< + DashboardOverviewQuery, + DashboardOverviewQueryVariables +>; +export const DashboardPriorityActionsDocument = { + kind: "Document", + definitions: [ + { + kind: "OperationDefinition", + operation: "query", + name: { kind: "Name", value: "DashboardPriorityActions" }, + variableDefinitions: [ + { + kind: "VariableDefinition", + variable: { kind: "Variable", name: { kind: "Name", value: "page" } }, + type: { + kind: "NonNullType", + type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }, + }, + defaultValue: { kind: "IntValue", value: "1" }, + }, + { + kind: "VariableDefinition", + variable: { kind: "Variable", name: { kind: "Name", value: "size" } }, + type: { + kind: "NonNullType", + type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }, + }, + defaultValue: { kind: "IntValue", value: "25" }, + }, + { + kind: "VariableDefinition", + variable: { + kind: "Variable", + name: { kind: "Name", value: "dimension" }, + }, + type: { kind: "NamedType", name: { kind: "Name", value: "String" } }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "priorityActions" }, + arguments: [ + { + kind: "Argument", + name: { kind: "Name", value: "page" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "page" }, + }, + }, + { + kind: "Argument", + name: { kind: "Name", value: "size" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "size" }, + }, + }, + { + kind: "Argument", + name: { kind: "Name", value: "dimension" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "dimension" }, + }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "items" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "id" } }, + { kind: "Field", name: { kind: "Name", value: "type" } }, + { + kind: "Field", + name: { kind: "Name", value: "severity" }, + }, + { kind: "Field", name: { kind: "Name", value: "title" } }, + { + kind: "Field", + name: { kind: "Name", value: "message" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "agentSummary" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "dueDate" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "actionData" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "status" }, + }, + ], + }, + }, + { kind: "Field", name: { kind: "Name", value: "total" } }, + { kind: "Field", name: { kind: "Name", value: "page" } }, + { kind: "Field", name: { kind: "Name", value: "size" } }, + { kind: "Field", name: { kind: "Name", value: "pages" } }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode< + DashboardPriorityActionsQuery, + DashboardPriorityActionsQueryVariables +>; +export const DashboardActivityFeedDocument = { + kind: "Document", + definitions: [ + { + kind: "OperationDefinition", + operation: "query", + name: { kind: "Name", value: "DashboardActivityFeed" }, + variableDefinitions: [ + { + kind: "VariableDefinition", + variable: { kind: "Variable", name: { kind: "Name", value: "page" } }, + type: { + kind: "NonNullType", + type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }, + }, + defaultValue: { kind: "IntValue", value: "1" }, + }, + { + kind: "VariableDefinition", + variable: { kind: "Variable", name: { kind: "Name", value: "size" } }, + type: { + kind: "NonNullType", + type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }, + }, + defaultValue: { kind: "IntValue", value: "20" }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "activityFeed" }, + arguments: [ + { + kind: "Argument", + name: { kind: "Name", value: "page" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "page" }, + }, + }, + { + kind: "Argument", + name: { kind: "Name", value: "size" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "size" }, + }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "items" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "actorType" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "message" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "timestamp" }, + }, + ], + }, + }, + { kind: "Field", name: { kind: "Name", value: "total" } }, + { kind: "Field", name: { kind: "Name", value: "page" } }, + { kind: "Field", name: { kind: "Name", value: "size" } }, + { kind: "Field", name: { kind: "Name", value: "pages" } }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode< + DashboardActivityFeedQuery, + DashboardActivityFeedQueryVariables +>; diff --git a/clients/admin-ui/src/__generated__/graphql/index.ts b/clients/admin-ui/src/__generated__/graphql/index.ts index f51599168fb..0ea4a91cf8a 100644 --- a/clients/admin-ui/src/__generated__/graphql/index.ts +++ b/clients/admin-ui/src/__generated__/graphql/index.ts @@ -1,2 +1,2 @@ export * from "./fragment-masking"; -export * from "./gql"; \ No newline at end of file +export * from "./gql"; diff --git a/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts b/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts index fdd81b682e9..e90d06b19ff 100644 --- a/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts +++ b/clients/admin-ui/src/features/dashboard-graphql/schema-string.ts @@ -2,4 +2,5 @@ // AUTOGENERATED by scripts/sync-graphql-sdl.mjs. Do not edit by hand. // Run `npm run graphql:generate` to refresh. -export const dashboardSchemaSDL = "directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT\n\ndirective @stream(if: Boolean, label: String, initialCount: Int = 0) on FIELD\n\nenum ActionSeverity {\n critical\n high\n medium\n low\n}\n\ntype ActivityFeedItem {\n actorType: ActorType!\n message: String!\n timestamp: DateTime!\n}\n\ntype ActivityFeedPage {\n items: [ActivityFeedItem!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\nenum ActorType {\n user\n agent\n}\n\ntype AgentBriefing {\n briefing: String!\n quickActions: [QuickAction!]!\n}\n\ntype Astralis {\n activeConversations: Int!\n completedAssessments: Int!\n awaitingResponse: Int!\n risksIdentified: Int!\n}\n\nenum DashboardActionStatus {\n pending\n in_progress\n completed\n}\n\nenum DashboardActionType {\n classification_review\n dsr_action\n system_review\n steward_assignment\n consent_anomaly\n policy_violation\n pia_update\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\nenum DiffDirection {\n up\n down\n unchanged\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Posture {\n score: Float!\n band: PostureBand!\n diffPercent: Float!\n diffDirection: DiffDirection!\n agentAnnotation: String!\n dimensions: [PostureDimension!]!\n}\n\nenum PostureBand {\n critical\n at_risk\n good\n excellent\n}\n\ntype PostureDimension {\n dimension: String!\n label: String!\n weight: Float!\n score: Float!\n band: PostureBand!\n}\n\ntype PriorityAction {\n id: ID!\n type: DashboardActionType!\n severity: ActionSeverity!\n title: String!\n message: String!\n agentSummary: String!\n dueDate: DateTime\n actionData: JSON!\n status: DashboardActionStatus!\n}\n\ntype PriorityActionsPage {\n items: [PriorityAction!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\ntype PrivacyRequestStatuses {\n inProgress: Int!\n pendingAction: Int!\n awaitingApproval: Int!\n}\n\ntype PrivacyRequests {\n activeCount: Int!\n statuses: PrivacyRequestStatuses!\n overdueCount: Int!\n slaHealth: [SLAHealthBucket!]!\n}\n\ntype Query {\n agentBriefing: AgentBriefing!\n posture: Posture!\n trends(period: TrendPeriod! = thirty_days): Trends!\n astralis: Astralis!\n activityFeed(page: Int! = 1, size: Int! = 20): ActivityFeedPage!\n privacyRequests: PrivacyRequests!\n systemCoverage: SystemCoverage!\n priorityActions(page: Int! = 1, size: Int! = 8, action: DashboardActionType = null, status: DashboardActionStatus = null, dimension: String = null): PriorityActionsPage!\n}\n\ntype QuickAction {\n label: String!\n actionType: DashboardActionType!\n actionData: JSON!\n severity: ActionSeverity!\n}\n\ntype SLAHealthBucket {\n label: String!\n onTrack: Int!\n approaching: Int!\n overdue: Int!\n}\n\ntype SystemCoverage {\n totalSystems: Int!\n fullyClassified: Int!\n partiallyClassified: Int!\n unclassified: Int!\n withoutSteward: Int!\n coveragePercentage: Float!\n}\n\ntype TrendMetric {\n key: String!\n value: Float!\n history: [Float!]!\n metadata: JSON!\n diff: Float!\n}\n\nenum TrendPeriod {\n thirty_days\n sixty_days\n ninety_days\n}\n\ntype Trends {\n period: TrendPeriod!\n metrics: [TrendMetric!]!\n}\n"; +export const dashboardSchemaSDL = + 'directive @defer(if: Boolean, label: String) on FRAGMENT_SPREAD | INLINE_FRAGMENT\n\ndirective @stream(if: Boolean, label: String, initialCount: Int = 0) on FIELD\n\nenum ActionSeverity {\n critical\n high\n medium\n low\n}\n\ntype ActivityFeedItem {\n actorType: ActorType!\n message: String!\n timestamp: DateTime!\n}\n\ntype ActivityFeedPage {\n items: [ActivityFeedItem!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\nenum ActorType {\n user\n agent\n}\n\ntype AgentBriefing {\n briefing: String!\n quickActions: [QuickAction!]!\n}\n\ntype Astralis {\n activeConversations: Int!\n completedAssessments: Int!\n awaitingResponse: Int!\n risksIdentified: Int!\n}\n\nenum DashboardActionStatus {\n pending\n in_progress\n completed\n}\n\nenum DashboardActionType {\n classification_review\n dsr_action\n system_review\n steward_assignment\n consent_anomaly\n policy_violation\n pia_update\n}\n\n"""Date with time (isoformat)"""\nscalar DateTime\n\nenum DiffDirection {\n up\n down\n unchanged\n}\n\n"""\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n"""\nscalar JSON @specifiedBy(url: "https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf")\n\ntype Posture {\n score: Float!\n band: PostureBand!\n diffPercent: Float!\n diffDirection: DiffDirection!\n agentAnnotation: String!\n dimensions: [PostureDimension!]!\n}\n\nenum PostureBand {\n critical\n at_risk\n good\n excellent\n}\n\ntype PostureDimension {\n dimension: String!\n label: String!\n weight: Float!\n score: Float!\n band: PostureBand!\n}\n\ntype PriorityAction {\n id: ID!\n type: DashboardActionType!\n severity: ActionSeverity!\n title: String!\n message: String!\n agentSummary: String!\n dueDate: DateTime\n actionData: JSON!\n status: DashboardActionStatus!\n}\n\ntype PriorityActionsPage {\n items: [PriorityAction!]!\n total: Int!\n page: Int!\n size: Int!\n pages: Int!\n}\n\ntype PrivacyRequestStatuses {\n inProgress: Int!\n pendingAction: Int!\n awaitingApproval: Int!\n}\n\ntype PrivacyRequests {\n activeCount: Int!\n statuses: PrivacyRequestStatuses!\n overdueCount: Int!\n slaHealth: [SLAHealthBucket!]!\n}\n\ntype Query {\n agentBriefing: AgentBriefing!\n posture: Posture!\n trends(period: TrendPeriod! = thirty_days): Trends!\n astralis: Astralis!\n activityFeed(page: Int! = 1, size: Int! = 20): ActivityFeedPage!\n privacyRequests: PrivacyRequests!\n systemCoverage: SystemCoverage!\n priorityActions(page: Int! = 1, size: Int! = 8, action: DashboardActionType = null, status: DashboardActionStatus = null, dimension: String = null): PriorityActionsPage!\n}\n\ntype QuickAction {\n label: String!\n actionType: DashboardActionType!\n actionData: JSON!\n severity: ActionSeverity!\n}\n\ntype SLAHealthBucket {\n label: String!\n onTrack: Int!\n approaching: Int!\n overdue: Int!\n}\n\ntype SystemCoverage {\n totalSystems: Int!\n fullyClassified: Int!\n partiallyClassified: Int!\n unclassified: Int!\n withoutSteward: Int!\n coveragePercentage: Float!\n}\n\ntype TrendMetric {\n key: String!\n value: Float!\n history: [Float!]!\n metadata: JSON!\n diff: Float!\n}\n\nenum TrendPeriod {\n thirty_days\n sixty_days\n ninety_days\n}\n\ntype Trends {\n period: TrendPeriod!\n metrics: [TrendMetric!]!\n}\n';