Rename registries

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-09-03 16:51:21 +02:00
parent e177108b19
commit d9001215f6
118 changed files with 9556 additions and 9520 deletions

View File

@@ -4,11 +4,11 @@ import {
type PreloadedQuery,
} from "react-relay";
import {
continualImprovementRegistryNodeQuery,
useDeleteContinualImprovementRegistry,
useUpdateContinualImprovementRegistry,
ContinualImprovementRegistriesConnectionKey,
} from "../../../hooks/graph/ContinualImprovementRegistryGraph";
continualImprovementNodeQuery,
useDeleteContinualImprovement,
useUpdateContinualImprovement,
ContinualImprovementsConnectionKey,
} from "../../../hooks/graph/ContinualImprovementGraph";
import {
ActionDropdown,
Badge,
@@ -33,9 +33,9 @@ import { Controller } from "react-hook-form";
import z from "zod";
import { getStatusVariant, getStatusLabel, formatDatetime, validateSnapshotConsistency } from "@probo/helpers";
import { SnapshotBanner } from "/components/SnapshotBanner";
import type { ContinualImprovementRegistryGraphNodeQuery } from "/hooks/graph/__generated__/ContinualImprovementRegistryGraphNodeQuery.graphql";
import type { ContinualImprovementGraphNodeQuery } from "/hooks/graph/__generated__/ContinualImprovementGraphNodeQuery.graphql";
const updateRegistrySchema = z.object({
const updateImprovementSchema = z.object({
referenceId: z.string().min(1, "Reference ID is required"),
description: z.string().optional(),
source: z.string().optional(),
@@ -46,55 +46,55 @@ const updateRegistrySchema = z.object({
});
type Props = {
queryRef: PreloadedQuery<ContinualImprovementRegistryGraphNodeQuery>;
queryRef: PreloadedQuery<ContinualImprovementGraphNodeQuery>;
};
export default function ContinualImprovementRegistryDetailsPage(props: Props) {
const data = usePreloadedQuery<ContinualImprovementRegistryGraphNodeQuery>(continualImprovementRegistryNodeQuery, props.queryRef);
const registry = data.node;
export default function ContinualImprovementDetailsPage(props: Props) {
const data = usePreloadedQuery<ContinualImprovementGraphNodeQuery>(continualImprovementNodeQuery, props.queryRef);
const improvement = data.node;
const { __ } = useTranslate();
const { toast } = useToast();
const organizationId = useOrganizationId();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
if (!registry) {
return <div>{__("Continual improvement registry entry not found")}</div>;
if (!improvement) {
return <div>{__("Continual improvement entry not found")}</div>;
}
validateSnapshotConsistency(registry, snapshotId);
validateSnapshotConsistency(improvement, snapshotId);
const updateRegistry = useUpdateContinualImprovementRegistry();
const updateImprovement = useUpdateContinualImprovement();
const connectionId = ConnectionHandler.getConnectionID(
organizationId,
ContinualImprovementRegistriesConnectionKey,
ContinualImprovementsConnectionKey,
{ filter: { snapshotId: snapshotId || null } }
);
const deleteRegistry = useDeleteContinualImprovementRegistry({ id: registry.id!, referenceId: registry.referenceId! }, connectionId);
const deleteImprovement = useDeleteContinualImprovement({ id: improvement.id!, referenceId: improvement.referenceId! }, connectionId);
const { register, handleSubmit, formState, control } = useFormWithSchema(
updateRegistrySchema,
updateImprovementSchema,
{
defaultValues: {
referenceId: registry.referenceId || "",
description: registry.description || "",
source: registry.source || "",
targetDate: registry.targetDate
? new Date(registry.targetDate).toISOString().split("T")[0]
referenceId: improvement.referenceId || "",
description: improvement.description || "",
source: improvement.source || "",
targetDate: improvement.targetDate
? new Date(improvement.targetDate).toISOString().split("T")[0]
: "",
status: registry.status || "OPEN",
priority: registry.priority || "MEDIUM",
ownerId: registry.owner?.id || "",
status: improvement.status || "OPEN",
priority: improvement.priority || "MEDIUM",
ownerId: improvement.owner?.id || "",
},
}
);
const onSubmit = handleSubmit(async (formData) => {
try {
await updateRegistry({
id: registry.id!,
await updateImprovement({
id: improvement.id!,
referenceId: formData.referenceId,
description: formData.description || undefined,
source: formData.source || undefined,
@@ -107,13 +107,13 @@ export default function ContinualImprovementRegistryDetailsPage(props: Props) {
toast({
title: __("Success"),
description: __("Continual improvement registry entry updated successfully"),
description: __("Continual improvement entry updated successfully"),
variant: "success",
});
} catch (error) {
toast({
title: __("Error"),
description: __("Failed to update continual improvement registry entry"),
description: __("Failed to update continual improvement entry"),
variant: "error",
});
}
@@ -131,9 +131,9 @@ export default function ContinualImprovementRegistryDetailsPage(props: Props) {
{ value: "HIGH", label: __("High") },
];
const breadcrumbRegistriesUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/continual-improvement-registries`
: `/organizations/${organizationId}/continual-improvement-registries`;
const breadcrumbImprovementsUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/continual-improvements`
: `/organizations/${organizationId}/continual-improvements`;
return (
<div className="space-y-6">
@@ -143,13 +143,13 @@ export default function ContinualImprovementRegistryDetailsPage(props: Props) {
<div className="flex items-center justify-between">
<Breadcrumb
items={[
{ label: __("Continual Improvement Registries"), to: breadcrumbRegistriesUrl },
{ label: registry.referenceId! },
{ label: __("Continual Improvements"), to: breadcrumbImprovementsUrl },
{ label: improvement.referenceId! },
]}
/>
{!isSnapshotMode && (
<ActionDropdown>
<DropdownItem onClick={deleteRegistry} variant="danger">
<DropdownItem onClick={deleteImprovement} variant="danger">
{__("Delete")}
</DropdownItem>
</ActionDropdown>
@@ -160,12 +160,12 @@ export default function ContinualImprovementRegistryDetailsPage(props: Props) {
<div className="p-6">
<div className="mb-6">
<div className="flex items-center gap-4">
<h1 className="text-2xl font-bold">{registry.referenceId}</h1>
<Badge variant={getStatusVariant(registry.status || "OPEN")}>
{getStatusLabel(registry.status || "OPEN")}
<h1 className="text-2xl font-bold">{improvement.referenceId}</h1>
<Badge variant={getStatusVariant(improvement.status || "OPEN")}>
{getStatusLabel(improvement.status || "OPEN")}
</Badge>
<Badge variant={registry.priority === "HIGH" ? "danger" : registry.priority === "MEDIUM" ? "warning" : "success"}>
{registry.priority === "HIGH" ? __("High") : registry.priority === "MEDIUM" ? __("Medium") : __("Low")}
<Badge variant={improvement.priority === "HIGH" ? "danger" : improvement.priority === "MEDIUM" ? "warning" : "success"}>
{improvement.priority === "HIGH" ? __("High") : improvement.priority === "MEDIUM" ? __("Medium") : __("Low")}
</Badge>
</div>
</div>

View File

@@ -27,36 +27,36 @@ import {
} from "react-relay";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { useParams } from "react-router";
import { CreateContinualImprovementRegistryDialog } from "./dialogs/CreateContinualImprovementRegistryDialog";
import { deleteContinualImprovementRegistryMutation, ContinualImprovementRegistriesConnectionKey } from "../../../hooks/graph/ContinualImprovementRegistryGraph";
import { CreateContinualImprovementDialog } from "./dialogs/CreateContinualImprovementDialog";
import { deleteContinualImprovementMutation, ContinualImprovementsConnectionKey } from "../../../hooks/graph/ContinualImprovementGraph";
import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel } from "@probo/helpers";
import { SnapshotBanner } from "/components/SnapshotBanner";
import type { NodeOf } from "/types";
import type { ContinualImprovementRegistriesPageQuery } from "./__generated__/ContinualImprovementRegistriesPageQuery.graphql";
import type { ContinualImprovementsPageQuery } from "./__generated__/ContinualImprovementsPageQuery.graphql";
import type {
ContinualImprovementRegistriesPageFragment$key,
ContinualImprovementRegistriesPageFragment$data,
} from "./__generated__/ContinualImprovementRegistriesPageFragment.graphql";
ContinualImprovementsPageFragment$key,
ContinualImprovementsPageFragment$data,
} from "./__generated__/ContinualImprovementsPageFragment.graphql";
interface ContinualImprovementRegistriesPageProps {
queryRef: PreloadedQuery<ContinualImprovementRegistriesPageQuery>;
interface ContinualImprovementsPageProps {
queryRef: PreloadedQuery<ContinualImprovementsPageQuery>;
}
const continualImprovementRegistriesPageFragment = graphql`
fragment ContinualImprovementRegistriesPageFragment on Organization
@refetchable(queryName: "ContinualImprovementRegistriesPageRefetchQuery")
const continualImprovementsPageFragment = graphql`
fragment ContinualImprovementsPageFragment on Organization
@refetchable(queryName: "ContinualImprovementsPageRefetchQuery")
@argumentDefinitions(
first: { type: "Int", defaultValue: 10 }
after: { type: "CursorKey" }
snapshotId: { type: "ID", defaultValue: null }
) {
id
continualImprovementRegistries(
continualImprovements(
first: $first
after: $after
filter: { snapshotId: $snapshotId }
)
@connection(key: "ContinualImprovementRegistriesPage_continualImprovementRegistries", filters: ["filter"]) {
@connection(key: "ContinualImprovementsPage_continualImprovements", filters: ["filter"]) {
__id
totalCount
edges {
@@ -86,20 +86,20 @@ const continualImprovementRegistriesPageFragment = graphql`
}
`;
export default function ContinualImprovementRegistriesPage({ queryRef }: ContinualImprovementRegistriesPageProps) {
export default function ContinualImprovementsPage({ queryRef }: ContinualImprovementsPageProps) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
usePageTitle(__("Continual Improvement Registries"));
usePageTitle(__("Continual Improvements"));
const organization = usePreloadedQuery(
graphql`
query ContinualImprovementRegistriesPageQuery($organizationId: ID!, $snapshotId: ID) {
query ContinualImprovementsPageQuery($organizationId: ID!, $snapshotId: ID) {
node(id: $organizationId) {
... on Organization {
...ContinualImprovementRegistriesPageFragment @arguments(snapshotId: $snapshotId)
...ContinualImprovementsPageFragment @arguments(snapshotId: $snapshotId)
}
}
}
@@ -113,39 +113,39 @@ export default function ContinualImprovementRegistriesPage({ queryRef }: Continu
hasNext,
isLoadingNext,
} = usePaginationFragment<
ContinualImprovementRegistriesPageQuery,
ContinualImprovementRegistriesPageFragment$key
>(continualImprovementRegistriesPageFragment, organization.node);
ContinualImprovementsPageQuery,
ContinualImprovementsPageFragment$key
>(continualImprovementsPageFragment, organization.node);
if (!data) {
return <div>{__("Organization not found")}</div>;
}
const connectionId = ConnectionHandler.getConnectionID(
organizationId,
ContinualImprovementRegistriesConnectionKey,
ContinualImprovementsConnectionKey,
{ filter: { snapshotId: snapshotId || null } }
);
const registries = data?.continualImprovementRegistries?.edges?.map((edge) => edge.node) ?? [];
const improvements = data?.continualImprovements?.edges?.map((edge) => edge.node) ?? [];
return (
<div className="space-y-6">
{isSnapshotMode && snapshotId && (
<SnapshotBanner snapshotId={snapshotId} />
)}
<PageHeader title={__("Continual Improvement Registries")} description={__("Manage your continual improvement registry entries")}>
<PageHeader title={__("Continual Improvements")} description={__("Manage your continual improvements.")}>
{!isSnapshotMode && (
<CreateContinualImprovementRegistryDialog
<CreateContinualImprovementDialog
organizationId={organizationId}
connectionId={connectionId}
>
<Button icon={IconPlusLarge}>
{__("Add continual improvement registry")}
{__("Add continual improvement")}
</Button>
</CreateContinualImprovementRegistryDialog>
</CreateContinualImprovementDialog>
)}
</PageHeader>
{registries.length > 0 ? (
{improvements.length > 0 ? (
<Card>
<Table>
<Thead>
@@ -160,10 +160,10 @@ export default function ContinualImprovementRegistriesPage({ queryRef }: Continu
</Tr>
</Thead>
<Tbody>
{registries.map((registry) => (
<RegistryRow
key={registry.id}
registry={registry}
{improvements.map((improvement) => (
<ImprovementRow
key={improvement.id}
improvement={improvement}
connectionId={connectionId}
snapshotId={snapshotId}
/>
@@ -187,10 +187,10 @@ export default function ContinualImprovementRegistriesPage({ queryRef }: Continu
<Card padded>
<div className="text-center py-12">
<h3 className="text-lg font-semibold mb-2">
{__("No continual improvement registry entries yet")}
{__("No continual improvements yet")}
</h3>
<p className="text-txt-tertiary mb-4">
{__("Create your first continual improvement registry entry to get started.")}
{__("Create your first continual improvement to get started.")}
</p>
</div>
</Card>
@@ -199,18 +199,18 @@ export default function ContinualImprovementRegistriesPage({ queryRef }: Continu
);
}
function RegistryRow({
registry,
function ImprovementRow({
improvement,
connectionId,
snapshotId,
}: {
registry: NodeOf<NonNullable<ContinualImprovementRegistriesPageFragment$data['continualImprovementRegistries']>>;
improvement: NodeOf<NonNullable<ContinualImprovementsPageFragment$data['continualImprovements']>>;
connectionId: string;
snapshotId?: string;
}) {
const organizationId = useOrganizationId();
const { __ } = useTranslate();
const [deleteRegistry] = useMutation(deleteContinualImprovementRegistryMutation);
const [deleteImprovement] = useMutation(deleteContinualImprovementMutation);
const confirm = useConfirm();
const isSnapshotMode = Boolean(snapshotId);
@@ -221,10 +221,10 @@ function RegistryRow({
const handleDelete = () => {
confirm(
() =>
promisifyMutation(deleteRegistry)({
promisifyMutation(deleteImprovement)({
variables: {
input: {
continualImprovementRegistryId: registry.id,
continualImprovementId: improvement.id,
},
connections: [connectionId],
},
@@ -232,39 +232,39 @@ function RegistryRow({
{
message: sprintf(
__(
"This will permanently delete the continual improvement registry entry %s. This action cannot be undone."
"This will permanently delete the continual improvement entry %s. This action cannot be undone."
),
registry.referenceId
improvement.referenceId
),
}
);
};
const detailsUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/continual-improvement-registries/${registry.id}`
: `/organizations/${organizationId}/continual-improvement-registries/${registry.id}`;
? `/organizations/${organizationId}/snapshots/${snapshotId}/continual-improvements/${improvement.id}`
: `/organizations/${organizationId}/continual-improvements/${improvement.id}`;
return (
<Tr to={detailsUrl}>
<Td>
<span className="font-mono text-sm">{registry.referenceId}</span>
<span className="font-mono text-sm">{improvement.referenceId}</span>
</Td>
<Td>{registry.description || "-"}</Td>
<Td>{improvement.description || "-"}</Td>
<Td>
<Badge variant={getStatusVariant(registry.status)}>
{getStatusLabel(registry.status)}
<Badge variant={getStatusVariant(improvement.status)}>
{getStatusLabel(improvement.status)}
</Badge>
</Td>
<Td>
<Badge variant={registry.priority === "HIGH" ? "danger" : registry.priority === "MEDIUM" ? "warning" : "success"}>
{registry.priority === "HIGH" ? __("High") : registry.priority === "MEDIUM" ? __("Medium") : __("Low")}
<Badge variant={improvement.priority === "HIGH" ? "danger" : improvement.priority === "MEDIUM" ? "warning" : "success"}>
{improvement.priority === "HIGH" ? __("High") : improvement.priority === "MEDIUM" ? __("Medium") : __("Low")}
</Badge>
</Td>
<Td>{registry.owner?.fullName || "-"}</Td>
<Td>{improvement.owner?.fullName || "-"}</Td>
<Td>
{registry.targetDate ? (
<time dateTime={registry.targetDate}>
{formatDate(registry.targetDate)}
{improvement.targetDate ? (
<time dateTime={improvement.targetDate}>
{formatDate(improvement.targetDate)}
</time>
) : (
<span className="text-txt-tertiary">{__("No target date")}</span>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<a7cefedfe9ee9d485354882888556f20>>
* @generated SignedSource<<3065b6b41135aa2dcbb45cdafae94503>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,11 +9,11 @@
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type ContinualImprovementRegistriesPriority = "HIGH" | "LOW" | "MEDIUM";
export type ContinualImprovementRegistriesStatus = "CLOSED" | "IN_PROGRESS" | "OPEN";
export type ContinualImprovementPriority = "HIGH" | "LOW" | "MEDIUM";
export type ContinualImprovementStatus = "CLOSED" | "IN_PROGRESS" | "OPEN";
import { FragmentRefs } from "relay-runtime";
export type ContinualImprovementRegistriesPageFragment$data = {
readonly continualImprovementRegistries: {
export type ContinualImprovementsPageFragment$data = {
readonly continualImprovements: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
@@ -24,12 +24,12 @@ export type ContinualImprovementRegistriesPageFragment$data = {
readonly fullName: string;
readonly id: string;
};
readonly priority: ContinualImprovementRegistriesPriority;
readonly priority: ContinualImprovementPriority;
readonly referenceId: string;
readonly snapshotId: string | null | undefined;
readonly source: string | null | undefined;
readonly sourceId: string | null | undefined;
readonly status: ContinualImprovementRegistriesStatus;
readonly status: ContinualImprovementStatus;
readonly targetDate: any | null | undefined;
readonly updatedAt: any;
};
@@ -41,18 +41,18 @@ export type ContinualImprovementRegistriesPageFragment$data = {
readonly totalCount: number;
};
readonly id: string;
readonly " $fragmentType": "ContinualImprovementRegistriesPageFragment";
readonly " $fragmentType": "ContinualImprovementsPageFragment";
};
export type ContinualImprovementRegistriesPageFragment$key = {
readonly " $data"?: ContinualImprovementRegistriesPageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"ContinualImprovementRegistriesPageFragment">;
export type ContinualImprovementsPageFragment$key = {
readonly " $data"?: ContinualImprovementsPageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"ContinualImprovementsPageFragment">;
};
import ContinualImprovementRegistriesPageRefetchQuery_graphql from './ContinualImprovementRegistriesPageRefetchQuery.graphql';
import ContinualImprovementsPageRefetchQuery_graphql from './ContinualImprovementsPageRefetchQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"continualImprovementRegistries"
"continualImprovements"
],
v1 = {
"alias": null,
@@ -101,18 +101,18 @@ return {
"fragmentPathInResult": [
"node"
],
"operation": ContinualImprovementRegistriesPageRefetchQuery_graphql,
"operation": ContinualImprovementsPageRefetchQuery_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "ContinualImprovementRegistriesPageFragment",
"name": "ContinualImprovementsPageFragment",
"selections": [
(v1/*: any*/),
{
"alias": "continualImprovementRegistries",
"alias": "continualImprovements",
"args": [
{
"fields": [
@@ -126,9 +126,9 @@ return {
"name": "filter"
}
],
"concreteType": "ContinualImprovementRegistryConnection",
"concreteType": "ContinualImprovementConnection",
"kind": "LinkedField",
"name": "__ContinualImprovementRegistriesPage_continualImprovementRegistries_connection",
"name": "__ContinualImprovementsPage_continualImprovements_connection",
"plural": false,
"selections": [
{
@@ -141,7 +141,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ContinualImprovementRegistryEdge",
"concreteType": "ContinualImprovementEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -149,7 +149,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ContinualImprovementRegistry",
"concreteType": "ContinualImprovement",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -310,6 +310,6 @@ return {
};
})();
(node as any).hash = "9e11628f65527ac1ff8974faa1855280";
(node as any).hash = "44e30d3febc79c6df7236567d85e9ca8";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<32acc7b83177d41eb30081c290ba1393>>
* @generated SignedSource<<ea405e491a67747f288e05da62524468>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,18 +10,18 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ContinualImprovementRegistriesPageQuery$variables = {
export type ContinualImprovementsPageQuery$variables = {
organizationId: string;
snapshotId?: string | null | undefined;
};
export type ContinualImprovementRegistriesPageQuery$data = {
export type ContinualImprovementsPageQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"ContinualImprovementRegistriesPageFragment">;
readonly " $fragmentSpreads": FragmentRefs<"ContinualImprovementsPageFragment">;
};
};
export type ContinualImprovementRegistriesPageQuery = {
response: ContinualImprovementRegistriesPageQuery$data;
variables: ContinualImprovementRegistriesPageQuery$variables;
export type ContinualImprovementsPageQuery = {
response: ContinualImprovementsPageQuery$data;
variables: ContinualImprovementsPageQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -82,7 +82,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ContinualImprovementRegistriesPageQuery",
"name": "ContinualImprovementsPageQuery",
"selections": [
{
"alias": null,
@@ -98,7 +98,7 @@ return {
{
"args": (v2/*: any*/),
"kind": "FragmentSpread",
"name": "ContinualImprovementRegistriesPageFragment"
"name": "ContinualImprovementsPageFragment"
}
],
"type": "Organization",
@@ -115,7 +115,7 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ContinualImprovementRegistriesPageQuery",
"name": "ContinualImprovementsPageQuery",
"selections": [
{
"alias": null,
@@ -133,9 +133,9 @@ return {
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "ContinualImprovementRegistryConnection",
"concreteType": "ContinualImprovementConnection",
"kind": "LinkedField",
"name": "continualImprovementRegistries",
"name": "continualImprovements",
"plural": false,
"selections": [
{
@@ -148,7 +148,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ContinualImprovementRegistryEdge",
"concreteType": "ContinualImprovementEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -156,7 +156,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ContinualImprovementRegistry",
"concreteType": "ContinualImprovement",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -312,9 +312,9 @@ return {
"filter"
],
"handle": "connection",
"key": "ContinualImprovementRegistriesPage_continualImprovementRegistries",
"key": "ContinualImprovementsPage_continualImprovements",
"kind": "LinkedHandle",
"name": "continualImprovementRegistries"
"name": "continualImprovements"
}
],
"type": "Organization",
@@ -326,16 +326,16 @@ return {
]
},
"params": {
"cacheID": "8cf92f4e9c75b4a42350503ae2d30cae",
"cacheID": "7213a2ee3776522282ddbc3c46b4002b",
"id": null,
"metadata": {},
"name": "ContinualImprovementRegistriesPageQuery",
"name": "ContinualImprovementsPageQuery",
"operationKind": "query",
"text": "query ContinualImprovementRegistriesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ContinualImprovementRegistriesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ContinualImprovementRegistriesPageFragment_3iomuz on Organization {\n id\n continualImprovementRegistries(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n description\n source\n targetDate\n status\n priority\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
"text": "query ContinualImprovementsPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ContinualImprovementsPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ContinualImprovementsPageFragment_3iomuz on Organization {\n id\n continualImprovements(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n description\n source\n targetDate\n status\n priority\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
}
};
})();
(node as any).hash = "506a807c01116d1b5622ac2624d5bf1b";
(node as any).hash = "7baadd4791b1c26eb7315a7755e28a08";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<7edb3bd39c98d7799e4b5eabccb36175>>
* @generated SignedSource<<908fcf894c6d8a46a122991d388a4cb7>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,20 +10,20 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ContinualImprovementRegistriesPageRefetchQuery$variables = {
export type ContinualImprovementsPageRefetchQuery$variables = {
after?: any | null | undefined;
first?: number | null | undefined;
id: string;
snapshotId?: string | null | undefined;
};
export type ContinualImprovementRegistriesPageRefetchQuery$data = {
export type ContinualImprovementsPageRefetchQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"ContinualImprovementRegistriesPageFragment">;
readonly " $fragmentSpreads": FragmentRefs<"ContinualImprovementsPageFragment">;
};
};
export type ContinualImprovementRegistriesPageRefetchQuery = {
response: ContinualImprovementRegistriesPageRefetchQuery$data;
variables: ContinualImprovementRegistriesPageRefetchQuery$variables;
export type ContinualImprovementsPageRefetchQuery = {
response: ContinualImprovementsPageRefetchQuery$data;
variables: ContinualImprovementsPageRefetchQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -104,7 +104,7 @@ return {
],
"kind": "Fragment",
"metadata": null,
"name": "ContinualImprovementRegistriesPageRefetchQuery",
"name": "ContinualImprovementsPageRefetchQuery",
"selections": [
{
"alias": null,
@@ -121,7 +121,7 @@ return {
(v7/*: any*/)
],
"kind": "FragmentSpread",
"name": "ContinualImprovementRegistriesPageFragment"
"name": "ContinualImprovementsPageFragment"
}
],
"storageKey": null
@@ -139,7 +139,7 @@ return {
(v2/*: any*/)
],
"kind": "Operation",
"name": "ContinualImprovementRegistriesPageRefetchQuery",
"name": "ContinualImprovementsPageRefetchQuery",
"selections": [
{
"alias": null,
@@ -157,9 +157,9 @@ return {
{
"alias": null,
"args": (v10/*: any*/),
"concreteType": "ContinualImprovementRegistryConnection",
"concreteType": "ContinualImprovementConnection",
"kind": "LinkedField",
"name": "continualImprovementRegistries",
"name": "continualImprovements",
"plural": false,
"selections": [
{
@@ -172,7 +172,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ContinualImprovementRegistryEdge",
"concreteType": "ContinualImprovementEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -180,7 +180,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ContinualImprovementRegistry",
"concreteType": "ContinualImprovement",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -336,9 +336,9 @@ return {
"filter"
],
"handle": "connection",
"key": "ContinualImprovementRegistriesPage_continualImprovementRegistries",
"key": "ContinualImprovementsPage_continualImprovements",
"kind": "LinkedHandle",
"name": "continualImprovementRegistries"
"name": "continualImprovements"
}
],
"type": "Organization",
@@ -350,16 +350,16 @@ return {
]
},
"params": {
"cacheID": "eb4f60205ab9cae8aeb307e2fc1a8b68",
"cacheID": "277ed3aedb8b99e9ec291997ba0d0943",
"id": null,
"metadata": {},
"name": "ContinualImprovementRegistriesPageRefetchQuery",
"name": "ContinualImprovementsPageRefetchQuery",
"operationKind": "query",
"text": "query ContinualImprovementRegistriesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ContinualImprovementRegistriesPageFragment_35e0S5\n id\n }\n}\n\nfragment ContinualImprovementRegistriesPageFragment_35e0S5 on Organization {\n id\n continualImprovementRegistries(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n description\n source\n targetDate\n status\n priority\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
"text": "query ContinualImprovementsPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ContinualImprovementsPageFragment_35e0S5\n id\n }\n}\n\nfragment ContinualImprovementsPageFragment_35e0S5 on Organization {\n id\n continualImprovements(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n description\n source\n targetDate\n status\n priority\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
}
};
})();
(node as any).hash = "9e11628f65527ac1ff8974faa1855280";
(node as any).hash = "44e30d3febc79c6df7236567d85e9ca8";
export default node;

View File

@@ -17,7 +17,7 @@ import {
import { useTranslate } from "@probo/i18n";
import { z } from "zod";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { useCreateContinualImprovementRegistry } from "../../../../hooks/graph/ContinualImprovementRegistryGraph";
import { useCreateContinualImprovement } from "../../../../hooks/graph/ContinualImprovementGraph";
import { PeopleSelectField } from "/components/form/PeopleSelectField";
import { Controller } from "react-hook-form";
import { formatDatetime } from "@probo/helpers";
@@ -34,22 +34,22 @@ const schema = z.object({
type FormData = z.infer<typeof schema>;
interface CreateContinualImprovementRegistryDialogProps {
interface CreateContinualImprovementDialogProps {
children: ReactNode;
organizationId: string;
connectionId?: string;
}
export function CreateContinualImprovementRegistryDialog({
export function CreateContinualImprovementDialog({
children,
organizationId,
connectionId,
}: CreateContinualImprovementRegistryDialogProps) {
}: CreateContinualImprovementDialogProps) {
const { __ } = useTranslate();
const { toast } = useToast();
const dialogRef = useDialogRef();
const createRegistry = useCreateContinualImprovementRegistry(connectionId || "");
const createImprovement = useCreateContinualImprovement(connectionId || "");
const { register, handleSubmit, formState, reset, control } = useFormWithSchema(schema, {
defaultValues: {
@@ -65,7 +65,7 @@ export function CreateContinualImprovementRegistryDialog({
const onSubmit = handleSubmit(async (formData: FormData) => {
try {
await createRegistry({
await createImprovement({
organizationId,
referenceId: formData.referenceId,
description: formData.description || undefined,
@@ -78,7 +78,7 @@ export function CreateContinualImprovementRegistryDialog({
toast({
title: __("Success"),
description: __("Continual improvement registry entry created successfully"),
description: __("Continual improvement entry created successfully"),
variant: "success",
});
@@ -87,7 +87,7 @@ export function CreateContinualImprovementRegistryDialog({
} catch (error) {
toast({
title: __("Error"),
description: __("Failed to create continual improvement registry entry"),
description: __("Failed to create continual improvement entry"),
variant: "error",
});
}
@@ -109,7 +109,7 @@ export function CreateContinualImprovementRegistryDialog({
<Dialog
ref={dialogRef}
trigger={children}
title={<Breadcrumb items={[__("Registries"), __("Create Continual Improvement Entry")]} />}
title={<Breadcrumb items={[__("Continual Improvements"), __("Create Entry")]} />}
className="max-w-2xl"
>
<form onSubmit={onSubmit}>

View File

@@ -26,38 +26,38 @@ import {
type PreloadedQuery,
} from "react-relay";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { CreateNonconformityRegistryDialog } from "./dialogs/CreateNonconformityRegistryDialog";
import { deleteNonconformityRegistryMutation, RegistriesConnectionKey } from "../../../hooks/graph/NonconformityRegistryGraph";
import { CreateNonconformityDialog } from "./dialogs/CreateNonconformityDialog";
import { deleteNonconformityMutation, NonconformitiesConnectionKey } from "../../../hooks/graph/NonconformityGraph";
import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel } from "@probo/helpers";
import { SnapshotBanner } from "/components/SnapshotBanner";
import { useParams } from "react-router";
import type { NonconformityRegistriesPageQuery } from "./__generated__/NonconformityRegistriesPageQuery.graphql";
import type { NonconformitiesPageQuery } from "./__generated__/NonconformitiesPageQuery.graphql";
import type {
NonconformityRegistriesPageFragment$key,
NonconformityRegistriesPageFragment$data,
} from "./__generated__/NonconformityRegistriesPageFragment.graphql";
NonconformitiesPageFragment$key,
NonconformitiesPageFragment$data,
} from "./__generated__/NonconformitiesPageFragment.graphql";
type NonconformityRegistry = NonconformityRegistriesPageFragment$data['nonconformityRegistries']['edges'][number]['node'];
type Nonconformity = NonconformitiesPageFragment$data['nonconformities']['edges'][number]['node'];
interface NonconformityRegistriesPageProps {
queryRef: PreloadedQuery<NonconformityRegistriesPageQuery>;
interface NonconformitiesPageProps {
queryRef: PreloadedQuery<NonconformitiesPageQuery>;
}
const nonconformityRegistriesPageFragment = graphql`
fragment NonconformityRegistriesPageFragment on Organization
@refetchable(queryName: "NonconformityRegistriesPageRefetchQuery")
const nonconformitiesPageFragment = graphql`
fragment NonconformitiesPageFragment on Organization
@refetchable(queryName: "NonconformitiesPageRefetchQuery")
@argumentDefinitions(
first: { type: "Int", defaultValue: 10 }
after: { type: "CursorKey" }
snapshotId: { type: "ID", defaultValue: null }
) {
id
nonconformityRegistries(
nonconformities(
first: $first
after: $after
filter: { snapshotId: $snapshotId }
)
@connection(key: "RegistriesPage_nonconformityRegistries", filters: ["filter"]) {
@connection(key: "NonconformitiesPage_nonconformities", filters: ["filter"]) {
__id
totalCount
edges {
@@ -96,20 +96,20 @@ const nonconformityRegistriesPageFragment = graphql`
}
`;
export default function NonconformityRegistriesPage({ queryRef }: NonconformityRegistriesPageProps) {
export default function NonconformitiesPage({ queryRef }: NonconformitiesPageProps) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
usePageTitle(__("Nonconformity Registries"));
usePageTitle(__("Nonconformities"));
const organization = usePreloadedQuery(
graphql`
query NonconformityRegistriesPageQuery($organizationId: ID!, $snapshotId: ID) {
query NonconformitiesPageQuery($organizationId: ID!, $snapshotId: ID) {
node(id: $organizationId) {
... on Organization {
...NonconformityRegistriesPageFragment @arguments(snapshotId: $snapshotId)
...NonconformitiesPageFragment @arguments(snapshotId: $snapshotId)
}
}
}
@@ -117,17 +117,17 @@ export default function NonconformityRegistriesPage({ queryRef }: NonconformityR
queryRef
);
const { data: registriesData, loadNext, hasNext } = usePaginationFragment(
nonconformityRegistriesPageFragment,
organization.node as NonconformityRegistriesPageFragment$key
const { data: nonconformitiesData, loadNext, hasNext } = usePaginationFragment(
nonconformitiesPageFragment,
organization.node as NonconformitiesPageFragment$key
);
const connectionId = ConnectionHandler.getConnectionID(
organizationId,
RegistriesConnectionKey,
NonconformitiesConnectionKey,
{ filter: { snapshotId: snapshotId || null } }
);
const registries: NonconformityRegistry[] = registriesData?.nonconformityRegistries?.edges?.map((edge) => edge.node) ?? [];
const nonconformities: Nonconformity[] = nonconformitiesData?.nonconformities?.edges?.map((edge) => edge.node) ?? [];
return (
<div className="space-y-6">
@@ -135,26 +135,26 @@ export default function NonconformityRegistriesPage({ queryRef }: NonconformityR
<SnapshotBanner snapshotId={snapshotId!} />
)}
<PageHeader
title={__("Nonconformity Registries")}
title={__("Nonconformities")}
description={__(
"Manage your organization's non conformity registries."
"Manage your organization's non conformities."
)}
>
{!isSnapshotMode && (
<CreateNonconformityRegistryDialog organizationId={organizationId} connection={connectionId}>
<Button icon={IconPlusLarge}>{__("Add nonconformity registry")}</Button>
</CreateNonconformityRegistryDialog>
<CreateNonconformityDialog organizationId={organizationId} connection={connectionId}>
<Button icon={IconPlusLarge}>{__("Add nonconformity")}</Button>
</CreateNonconformityDialog>
)}
</PageHeader>
{registries.length === 0 ? (
{nonconformities.length === 0 ? (
<Card padded>
<div className="text-center py-12">
<h3 className="text-lg font-semibold mb-2">
{__("No nonconformity registry entries yet")}
{__("No nonconformities yet")}
</h3>
<p className="text-txt-tertiary mb-4">
{__("Create your first nonconformity registry entry to get started.")}
{__("Create your first nonconformity to get started.")}
</p>
</div>
</Card>
@@ -173,10 +173,10 @@ export default function NonconformityRegistriesPage({ queryRef }: NonconformityR
</Tr>
</Thead>
<Tbody>
{registries.map((registry) => (
<RegistryRow
key={registry.id}
registry={registry}
{nonconformities.map((nonconformity) => (
<NonconformityRow
key={nonconformity.id}
nonconformity={nonconformity}
connectionId={connectionId}
isSnapshotMode={isSnapshotMode}
snapshotId={snapshotId}
@@ -204,13 +204,13 @@ export default function NonconformityRegistriesPage({ queryRef }: NonconformityR
);
}
function RegistryRow({
registry,
function NonconformityRow({
nonconformity,
connectionId,
isSnapshotMode,
snapshotId,
}: {
registry: NonconformityRegistry;
nonconformity: Nonconformity;
connectionId: string;
isSnapshotMode: boolean;
snapshotId?: string;
@@ -218,25 +218,25 @@ function RegistryRow({
const organizationId = useOrganizationId();
const { __ } = useTranslate();
const confirm = useConfirm();
const [deleteRegistry] = useMutation(deleteNonconformityRegistryMutation);
const [deleteNonconformity] = useMutation(deleteNonconformityMutation);
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString();
};
const registryDetailUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/nonconformity-registries/${registry.id}`
: `/organizations/${organizationId}/nonconformity-registries/${registry.id}`;
const nonconformityDetailUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/nonconformities/${nonconformity.id}`
: `/organizations/${organizationId}/nonconformities/${nonconformity.id}`;
const handleDeleteRegistry = (registry: NonconformityRegistry) => {
const handleDeleteNonconformity = (nonconformity: Nonconformity) => {
if (!connectionId) return;
confirm(
() => {
return promisifyMutation(deleteRegistry)({
return promisifyMutation(deleteNonconformity)({
variables: {
input: {
nonconformityRegistryId: registry.id,
nonconformityId: nonconformity.id,
},
connections: [connectionId],
},
@@ -245,42 +245,42 @@ function RegistryRow({
{
message: sprintf(
__(
"This will permanently delete the registry entry %s. This action cannot be undone."
"This will permanently delete the nonconformity %s. This action cannot be undone."
),
registry.referenceId
nonconformity.referenceId
),
}
);
};
return (
<Tr to={registryDetailUrl}>
<Tr to={nonconformityDetailUrl}>
<Td>
<span className="font-mono text-sm">{registry.referenceId}</span>
<span className="font-mono text-sm">{nonconformity.referenceId}</span>
</Td>
<Td>
<div className="min-w-0">
<p className="whitespace-pre-wrap break-words">
{registry.description || __("No description")}
{nonconformity.description || __("No description")}
</p>
</div>
</Td>
<Td>
<Badge variant={getStatusVariant(registry.status)}>
{getStatusLabel(registry.status)}
<Badge variant={getStatusVariant(nonconformity.status)}>
{getStatusLabel(nonconformity.status)}
</Badge>
</Td>
<Td>
{registry.audit.name
? `${registry.audit.framework.name} - ${registry.audit.name}`
: registry.audit.framework.name
{nonconformity.audit.name
? `${nonconformity.audit.framework.name} - ${nonconformity.audit.name}`
: nonconformity.audit.framework.name
}
</Td>
<Td>{registry.owner.fullName}</Td>
<Td>{nonconformity.owner.fullName}</Td>
<Td>
{registry.dueDate ? (
<time dateTime={registry.dueDate}>
{formatDate(registry.dueDate)}
{nonconformity.dueDate ? (
<time dateTime={nonconformity.dueDate}>
{formatDate(nonconformity.dueDate)}
</time>
) : (
<span className="text-txt-tertiary">{__("No due date")}</span>
@@ -291,7 +291,7 @@ function RegistryRow({
<DropdownItem
icon={IconTrashCan}
variant="danger"
onSelect={() => handleDeleteRegistry(registry)}
onSelect={() => handleDeleteNonconformity(nonconformity)}
>
{__("Delete")}
</DropdownItem>

View File

@@ -4,11 +4,11 @@ import {
type PreloadedQuery,
} from "react-relay";
import {
nonconformityRegistryNodeQuery,
useDeleteNonconformityRegistry,
useUpdateNonconformityRegistry,
RegistriesConnectionKey,
} from "../../../hooks/graph/NonconformityRegistryGraph";
nonconformityNodeQuery,
useDeleteNonconformity,
useUpdateNonconformity,
NonconformitiesConnectionKey,
} from "../../../hooks/graph/NonconformityGraph";
import {
ActionDropdown,
Badge,
@@ -32,10 +32,10 @@ import { PeopleSelectField } from "/components/form/PeopleSelectField";
import { AuditSelectField } from "/components/form/AuditSelectField";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import z from "zod";
import { getStatusVariant, getStatusLabel, formatDatetime, getNonconformityRegistryStatusOptions, validateSnapshotConsistency } from "@probo/helpers";
import type { NonconformityRegistryGraphNodeQuery } from "/hooks/graph/__generated__/NonconformityRegistryGraphNodeQuery.graphql";
import { getStatusVariant, getStatusLabel, formatDatetime, validateSnapshotConsistency, getStatusOptions } from "@probo/helpers";
import type { NonconformityGraphNodeQuery } from "/hooks/graph/__generated__/NonconformityGraphNodeQuery.graphql";
const updateRegistrySchema = z.object({
const updateNonconformitySchema = z.object({
referenceId: z.string().min(1, "Reference ID is required"),
description: z.string().optional(),
dateIdentified: z.string().optional(),
@@ -49,58 +49,58 @@ const updateRegistrySchema = z.object({
});
type Props = {
queryRef: PreloadedQuery<NonconformityRegistryGraphNodeQuery>;
queryRef: PreloadedQuery<NonconformityGraphNodeQuery>;
};
export default function NonconformityRegistryDetailsPage(props: Props) {
const data = usePreloadedQuery<NonconformityRegistryGraphNodeQuery>(
nonconformityRegistryNodeQuery,
export default function NonconformityDetailsPage(props: Props) {
const data = usePreloadedQuery<NonconformityGraphNodeQuery>(
nonconformityNodeQuery,
props.queryRef
);
const registry = data.node;
const nonconformity = data.node;
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
validateSnapshotConsistency(registry, snapshotId);
validateSnapshotConsistency(nonconformity, snapshotId);
const deleteRegistry = useDeleteNonconformityRegistry(
{ id: registry.id!, referenceId: registry.referenceId! },
const deleteNonconformity = useDeleteNonconformity(
{ id: nonconformity.id!, referenceId: nonconformity.referenceId! },
ConnectionHandler.getConnectionID(
organizationId,
RegistriesConnectionKey,
NonconformitiesConnectionKey,
{ filter: { snapshotId: snapshotId || null } }
)
);
const { control, formState, handleSubmit, register, reset } = useFormWithSchema(
updateRegistrySchema,
updateNonconformitySchema,
{
defaultValues: {
referenceId: registry.referenceId || "",
description: registry.description || "",
dateIdentified: registry.dateIdentified?.split('T')[0] || "",
dueDate: registry.dueDate?.split('T')[0] || "",
rootCause: registry.rootCause || "",
correctiveAction: registry.correctiveAction || "",
effectivenessCheck: registry.effectivenessCheck || "",
status: registry.status || "OPEN",
ownerId: registry.owner?.id || "",
auditId: registry.audit?.id || "",
referenceId: nonconformity.referenceId || "",
description: nonconformity.description || "",
dateIdentified: nonconformity.dateIdentified?.split('T')[0] || "",
dueDate: nonconformity.dueDate?.split('T')[0] || "",
rootCause: nonconformity.rootCause || "",
correctiveAction: nonconformity.correctiveAction || "",
effectivenessCheck: nonconformity.effectivenessCheck || "",
status: nonconformity.status || "OPEN",
ownerId: nonconformity.owner?.id || "",
auditId: nonconformity.audit?.id || "",
},
}
);
const updateRegistry = useUpdateNonconformityRegistry();
const updateNonconformity = useUpdateNonconformity();
const { toast } = useToast();
const onSubmit = handleSubmit(async (formData) => {
if (!registry.id) return;
if (!nonconformity.id) return;
try {
await updateRegistry({
id: registry.id,
await updateNonconformity({
id: nonconformity.id,
referenceId: formData.referenceId,
description: formData.description,
dateIdentified: formatDatetime(formData.dateIdentified),
@@ -115,23 +115,23 @@ export default function NonconformityRegistryDetailsPage(props: Props) {
reset(formData);
toast({
title: __("Success"),
description: __("Non conformity registry entry updated successfully"),
description: __("Nonconformity updated successfully"),
variant: "success",
});
} catch (error) {
toast({
title: __("Error"),
description: error instanceof Error ? error.message : __("Failed to update non conformity registry entry"),
description: error instanceof Error ? error.message : __("Failed to update nonconformity"),
variant: "error",
});
}
});
const statusOptions = getNonconformityRegistryStatusOptions(__);
const statusOptions = getStatusOptions(__);
const breadcrumbNonconformityRegistriesUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/nonconformity-registries`
: `/organizations/${organizationId}/nonconformity-registries`;
const breadcrumbNonconformitiesUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/nonconformities`
: `/organizations/${organizationId}/nonconformities`;
return (
<div className="space-y-6">
@@ -141,11 +141,11 @@ export default function NonconformityRegistryDetailsPage(props: Props) {
<Breadcrumb
items={[
{
label: __("Nonconformity Registries"),
to: breadcrumbNonconformityRegistriesUrl,
label: __("Nonconformities"),
to: breadcrumbNonconformitiesUrl,
},
{
label: registry.referenceId || __("Unknown Nonconformity Registry"),
label: nonconformity.referenceId || __("Unknown Nonconformity"),
},
]}
/>
@@ -153,10 +153,10 @@ export default function NonconformityRegistryDetailsPage(props: Props) {
<div className="flex justify-between items-start">
<div className="flex items-center gap-4">
<div className="text-2xl font-semibold">
{registry.referenceId}
{nonconformity.referenceId}
</div>
<Badge variant={getStatusVariant(registry.status || "OPEN")}>
{getStatusLabel(registry.status || "OPEN")}
<Badge variant={getStatusVariant(nonconformity.status || "OPEN")}>
{getStatusLabel(nonconformity.status || "OPEN")}
</Badge>
</div>
{!isSnapshotMode && (
@@ -164,7 +164,7 @@ export default function NonconformityRegistryDetailsPage(props: Props) {
<DropdownItem
variant="danger"
icon={IconTrashCan}
onClick={deleteRegistry}
onClick={deleteNonconformity}
>
{__("Delete")}
</DropdownItem>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<7ec3fc6b9ecb6302152fe0031e791682>>
* @generated SignedSource<<b53ef2729d5b435baeb0d3b068be8cef>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,11 +9,11 @@
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type NonconformityRegistryStatus = "CLOSED" | "IN_PROGRESS" | "OPEN";
export type NonconformityStatus = "CLOSED" | "IN_PROGRESS" | "OPEN";
import { FragmentRefs } from "relay-runtime";
export type NonconformityRegistriesPageFragment$data = {
export type NonconformitiesPageFragment$data = {
readonly id: string;
readonly nonconformityRegistries: {
readonly nonconformities: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
@@ -39,7 +39,7 @@ export type NonconformityRegistriesPageFragment$data = {
readonly referenceId: string;
readonly rootCause: string;
readonly snapshotId: string | null | undefined;
readonly status: NonconformityRegistryStatus;
readonly status: NonconformityStatus;
readonly updatedAt: any;
};
}>;
@@ -49,18 +49,18 @@ export type NonconformityRegistriesPageFragment$data = {
};
readonly totalCount: number;
};
readonly " $fragmentType": "NonconformityRegistriesPageFragment";
readonly " $fragmentType": "NonconformitiesPageFragment";
};
export type NonconformityRegistriesPageFragment$key = {
readonly " $data"?: NonconformityRegistriesPageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"NonconformityRegistriesPageFragment">;
export type NonconformitiesPageFragment$key = {
readonly " $data"?: NonconformitiesPageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"NonconformitiesPageFragment">;
};
import NonconformityRegistriesPageRefetchQuery_graphql from './NonconformityRegistriesPageRefetchQuery.graphql';
import NonconformitiesPageRefetchQuery_graphql from './NonconformitiesPageRefetchQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"nonconformityRegistries"
"nonconformities"
],
v1 = {
"alias": null,
@@ -116,18 +116,18 @@ return {
"fragmentPathInResult": [
"node"
],
"operation": NonconformityRegistriesPageRefetchQuery_graphql,
"operation": NonconformitiesPageRefetchQuery_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "NonconformityRegistriesPageFragment",
"name": "NonconformitiesPageFragment",
"selections": [
(v1/*: any*/),
{
"alias": "nonconformityRegistries",
"alias": "nonconformities",
"args": [
{
"fields": [
@@ -141,9 +141,9 @@ return {
"name": "filter"
}
],
"concreteType": "NonconformityRegistryConnection",
"concreteType": "NonconformityConnection",
"kind": "LinkedField",
"name": "__RegistriesPage_nonconformityRegistries_connection",
"name": "__NonconformitiesPage_nonconformities_connection",
"plural": false,
"selections": [
{
@@ -156,7 +156,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "NonconformityRegistryEdge",
"concreteType": "NonconformityEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -164,7 +164,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "NonconformityRegistry",
"concreteType": "Nonconformity",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -358,6 +358,6 @@ return {
};
})();
(node as any).hash = "36f3622d63ddf02a2703a2c8428f4268";
(node as any).hash = "0043855d2410d9ab1fd8fceda53f7c5a";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<5e78749bb635e7aa478ad7efb8f5e01b>>
* @generated SignedSource<<3292b0059f82a3a5c1316f9312379621>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,18 +10,18 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type NonconformityRegistriesPageQuery$variables = {
export type NonconformitiesPageQuery$variables = {
organizationId: string;
snapshotId?: string | null | undefined;
};
export type NonconformityRegistriesPageQuery$data = {
export type NonconformitiesPageQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"NonconformityRegistriesPageFragment">;
readonly " $fragmentSpreads": FragmentRefs<"NonconformitiesPageFragment">;
};
};
export type NonconformityRegistriesPageQuery = {
response: NonconformityRegistriesPageQuery$data;
variables: NonconformityRegistriesPageQuery$variables;
export type NonconformitiesPageQuery = {
response: NonconformitiesPageQuery$data;
variables: NonconformitiesPageQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -89,7 +89,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "NonconformityRegistriesPageQuery",
"name": "NonconformitiesPageQuery",
"selections": [
{
"alias": null,
@@ -105,7 +105,7 @@ return {
{
"args": (v2/*: any*/),
"kind": "FragmentSpread",
"name": "NonconformityRegistriesPageFragment"
"name": "NonconformitiesPageFragment"
}
],
"type": "Organization",
@@ -122,7 +122,7 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "NonconformityRegistriesPageQuery",
"name": "NonconformitiesPageQuery",
"selections": [
{
"alias": null,
@@ -140,9 +140,9 @@ return {
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "NonconformityRegistryConnection",
"concreteType": "NonconformityConnection",
"kind": "LinkedField",
"name": "nonconformityRegistries",
"name": "nonconformities",
"plural": false,
"selections": [
{
@@ -155,7 +155,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "NonconformityRegistryEdge",
"concreteType": "NonconformityEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -163,7 +163,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "NonconformityRegistry",
"concreteType": "Nonconformity",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -352,9 +352,9 @@ return {
"filter"
],
"handle": "connection",
"key": "RegistriesPage_nonconformityRegistries",
"key": "NonconformitiesPage_nonconformities",
"kind": "LinkedHandle",
"name": "nonconformityRegistries"
"name": "nonconformities"
}
],
"type": "Organization",
@@ -366,16 +366,16 @@ return {
]
},
"params": {
"cacheID": "fc70ce5fd4a22cc2bc0d9a63d476008f",
"cacheID": "b4f53542e4ea747099f28629d5e8a0bb",
"id": null,
"metadata": {},
"name": "NonconformityRegistriesPageQuery",
"name": "NonconformitiesPageQuery",
"operationKind": "query",
"text": "query NonconformityRegistriesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...NonconformityRegistriesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment NonconformityRegistriesPageFragment_3iomuz on Organization {\n id\n nonconformityRegistries(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n referenceId\n snapshotId\n description\n status\n dateIdentified\n dueDate\n rootCause\n correctiveAction\n effectivenessCheck\n audit {\n id\n name\n framework {\n id\n name\n }\n }\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
"text": "query NonconformitiesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...NonconformitiesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment NonconformitiesPageFragment_3iomuz on Organization {\n id\n nonconformities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n referenceId\n snapshotId\n description\n status\n dateIdentified\n dueDate\n rootCause\n correctiveAction\n effectivenessCheck\n audit {\n id\n name\n framework {\n id\n name\n }\n }\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
}
};
})();
(node as any).hash = "180821c7fad7b6071d78444e1eac0742";
(node as any).hash = "af4a93239b6065756759b4958980b846";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<d47034189b16b400cc098c230ea062c1>>
* @generated SignedSource<<5e8c575bf254c267b0694d9c7dd20a82>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,20 +10,20 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type NonconformityRegistriesPageRefetchQuery$variables = {
export type NonconformitiesPageRefetchQuery$variables = {
after?: any | null | undefined;
first?: number | null | undefined;
id: string;
snapshotId?: string | null | undefined;
};
export type NonconformityRegistriesPageRefetchQuery$data = {
export type NonconformitiesPageRefetchQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"NonconformityRegistriesPageFragment">;
readonly " $fragmentSpreads": FragmentRefs<"NonconformitiesPageFragment">;
};
};
export type NonconformityRegistriesPageRefetchQuery = {
response: NonconformityRegistriesPageRefetchQuery$data;
variables: NonconformityRegistriesPageRefetchQuery$variables;
export type NonconformitiesPageRefetchQuery = {
response: NonconformitiesPageRefetchQuery$data;
variables: NonconformitiesPageRefetchQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -111,7 +111,7 @@ return {
],
"kind": "Fragment",
"metadata": null,
"name": "NonconformityRegistriesPageRefetchQuery",
"name": "NonconformitiesPageRefetchQuery",
"selections": [
{
"alias": null,
@@ -128,7 +128,7 @@ return {
(v7/*: any*/)
],
"kind": "FragmentSpread",
"name": "NonconformityRegistriesPageFragment"
"name": "NonconformitiesPageFragment"
}
],
"storageKey": null
@@ -146,7 +146,7 @@ return {
(v2/*: any*/)
],
"kind": "Operation",
"name": "NonconformityRegistriesPageRefetchQuery",
"name": "NonconformitiesPageRefetchQuery",
"selections": [
{
"alias": null,
@@ -164,9 +164,9 @@ return {
{
"alias": null,
"args": (v10/*: any*/),
"concreteType": "NonconformityRegistryConnection",
"concreteType": "NonconformityConnection",
"kind": "LinkedField",
"name": "nonconformityRegistries",
"name": "nonconformities",
"plural": false,
"selections": [
{
@@ -179,7 +179,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "NonconformityRegistryEdge",
"concreteType": "NonconformityEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -187,7 +187,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "NonconformityRegistry",
"concreteType": "Nonconformity",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -376,9 +376,9 @@ return {
"filter"
],
"handle": "connection",
"key": "RegistriesPage_nonconformityRegistries",
"key": "NonconformitiesPage_nonconformities",
"kind": "LinkedHandle",
"name": "nonconformityRegistries"
"name": "nonconformities"
}
],
"type": "Organization",
@@ -390,16 +390,16 @@ return {
]
},
"params": {
"cacheID": "c8a936f15b58d1f1d51984f692b0bba5",
"cacheID": "d0fe732fcd104cafd8dec7748d5f3971",
"id": null,
"metadata": {},
"name": "NonconformityRegistriesPageRefetchQuery",
"name": "NonconformitiesPageRefetchQuery",
"operationKind": "query",
"text": "query NonconformityRegistriesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...NonconformityRegistriesPageFragment_35e0S5\n id\n }\n}\n\nfragment NonconformityRegistriesPageFragment_35e0S5 on Organization {\n id\n nonconformityRegistries(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n referenceId\n snapshotId\n description\n status\n dateIdentified\n dueDate\n rootCause\n correctiveAction\n effectivenessCheck\n audit {\n id\n name\n framework {\n id\n name\n }\n }\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
"text": "query NonconformitiesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...NonconformitiesPageFragment_35e0S5\n id\n }\n}\n\nfragment NonconformitiesPageFragment_35e0S5 on Organization {\n id\n nonconformities(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n referenceId\n snapshotId\n description\n status\n dateIdentified\n dueDate\n rootCause\n correctiveAction\n effectivenessCheck\n audit {\n id\n name\n framework {\n id\n name\n }\n }\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
}
};
})();
(node as any).hash = "36f3622d63ddf02a2703a2c8428f4268";
(node as any).hash = "0043855d2410d9ab1fd8fceda53f7c5a";
export default node;

View File

@@ -17,13 +17,11 @@ import {
import { useTranslate } from "@probo/i18n";
import { z } from "zod";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { useCreateNonconformityRegistry } from "../../../../hooks/graph/NonconformityRegistryGraph";
import { useCreateNonconformity } from "../../../../hooks/graph/NonconformityGraph";
import { PeopleSelectField } from "/components/form/PeopleSelectField";
import { AuditSelectField } from "/components/form/AuditSelectField";
import { Controller } from "react-hook-form";
import { formatDatetime, getNonconformityRegistryStatusOptions } from "@probo/helpers";
import { formatDatetime, getStatusOptions } from "@probo/helpers";
const schema = z.object({
referenceId: z.string().min(1, "Reference ID is required"),
@@ -40,23 +38,23 @@ const schema = z.object({
type FormData = z.infer<typeof schema>;
interface CreateNonconformityRegistryDialogProps {
interface CreateNonconformityDialogProps {
children: ReactNode;
connection?: string;
organizationId: string;
}
export function CreateNonconformityRegistryDialog({
export function CreateNonconformityDialog({
children,
organizationId,
connection,
}: CreateNonconformityRegistryDialogProps) {
}: CreateNonconformityDialogProps) {
const { __ } = useTranslate();
const { toast } = useToast();
const dialogRef = useDialogRef();
const createRegistry = useCreateNonconformityRegistry(connection || "");
const statusOptions = getNonconformityRegistryStatusOptions(__);
const createNonconformity = useCreateNonconformity(connection || "");
const statusOptions = getStatusOptions(__);
const { register, handleSubmit, formState, reset, control } = useFormWithSchema(schema, {
defaultValues: {
@@ -75,7 +73,7 @@ export function CreateNonconformityRegistryDialog({
const onSubmit = handleSubmit(async (formData: FormData) => {
try {
await createRegistry({
await createNonconformity({
organizationId,
referenceId: formData.referenceId,
description: formData.description || undefined,
@@ -91,7 +89,7 @@ export function CreateNonconformityRegistryDialog({
toast({
title: __("Success"),
description: __("Non conformity registry entry created successfully"),
description: __("Nonconformity created successfully"),
variant: "success",
});
@@ -100,7 +98,7 @@ export function CreateNonconformityRegistryDialog({
} catch (error) {
toast({
title: __("Error"),
description: __("Failed to create non conformity registry entry"),
description: __("Failed to create nonconformity"),
variant: "error",
});
}
@@ -110,7 +108,7 @@ export function CreateNonconformityRegistryDialog({
<Dialog
ref={dialogRef}
trigger={children}
title={<Breadcrumb items={[__("Registries"), __("Create Entry")]} />}
title={<Breadcrumb items={[__("Nonconformities"), __("Create")]} />}
className="max-w-2xl"
>
<form onSubmit={onSubmit}>
@@ -240,7 +238,7 @@ export function CreateNonconformityRegistryDialog({
<DialogFooter>
<Button type="submit" disabled={formState.isSubmitting}>
{formState.isSubmitting ? __("Creating...") : __("Create Nonconformity Registry Entry")}
{formState.isSubmitting ? __("Creating...") : __("Create Nonconformity")}
</Button>
</DialogFooter>
</form>

View File

@@ -4,11 +4,11 @@ import {
type PreloadedQuery,
} from "react-relay";
import {
complianceRegistryNodeQuery,
useDeleteComplianceRegistry,
useUpdateComplianceRegistry,
ComplianceRegistriesConnectionKey,
} from "../../../hooks/graph/ComplianceRegistryGraph";
obligationNodeQuery,
useDeleteObligation,
useUpdateObligation,
ObligationsConnectionKey,
} from "../../../hooks/graph/ObligationGraph";
import {
ActionDropdown,
Badge,
@@ -31,11 +31,11 @@ import { PeopleSelectField } from "/components/form/PeopleSelectField";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { Controller } from "react-hook-form";
import z from "zod";
import { getStatusVariant, getStatusLabel, formatDatetime, getComplianceRegistryStatusOptions, validateSnapshotConsistency } from "@probo/helpers";
import { getStatusVariant, getStatusLabel, formatDatetime, getStatusOptions, validateSnapshotConsistency } from "@probo/helpers";
import { SnapshotBanner } from "/components/SnapshotBanner";
import type { ComplianceRegistryGraphNodeQuery } from "/hooks/graph/__generated__/ComplianceRegistryGraphNodeQuery.graphql";
import type { ObligationGraphNodeQuery } from "/hooks/graph/__generated__/ObligationGraphNodeQuery.graphql";
const updateRegistrySchema = z.object({
const updateObligationSchema = z.object({
referenceId: z.string().min(1, "Reference ID is required"),
area: z.string().optional(),
source: z.string().optional(),
@@ -49,60 +49,63 @@ const updateRegistrySchema = z.object({
});
type Props = {
queryRef: PreloadedQuery<ComplianceRegistryGraphNodeQuery>;
queryRef: PreloadedQuery<ObligationGraphNodeQuery>;
};
export default function ComplianceRegistryDetailsPage(props: Props) {
const data = usePreloadedQuery<ComplianceRegistryGraphNodeQuery>(complianceRegistryNodeQuery, props.queryRef);
const registry = data.node;
export default function ObligationDetailsPage(props: Props) {
const data = usePreloadedQuery<ObligationGraphNodeQuery>(obligationNodeQuery, props.queryRef);
const obligation = data.node;
const { __ } = useTranslate();
const { toast } = useToast();
const organizationId = useOrganizationId();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
if (!registry) {
return <div>{__("Compliance registry entry not found")}</div>;
if (!obligation) {
return <div>{__("Obligation not found")}</div>;
}
validateSnapshotConsistency(registry, snapshotId);
validateSnapshotConsistency(obligation, snapshotId);
const updateRegistry = useUpdateComplianceRegistry();
const statusOptions = getComplianceRegistryStatusOptions(__);
const updateObligation = useUpdateObligation();
const statusOptions = getStatusOptions(__);
const connectionId = ConnectionHandler.getConnectionID(
organizationId,
ComplianceRegistriesConnectionKey
ObligationsConnectionKey
);
const deleteRegistry = useDeleteComplianceRegistry({ id: registry.id!, referenceId: registry.referenceId! }, connectionId);
const deleteObligation = useDeleteObligation(
{ id: obligation?.id!, referenceId: obligation?.referenceId! },
connectionId
);
const { register, handleSubmit, formState, control } = useFormWithSchema(
updateRegistrySchema,
updateObligationSchema,
{
defaultValues: {
referenceId: registry.referenceId || "",
area: registry.area || "",
source: registry.source || "",
requirement: registry.requirement || "",
actionsToBeImplemented: registry.actionsToBeImplemented || "",
regulator: registry.regulator || "",
lastReviewDate: registry.lastReviewDate
? new Date(registry.lastReviewDate).toISOString().split("T")[0]
referenceId: obligation?.referenceId || "",
area: obligation?.area || "",
source: obligation?.source || "",
requirement: obligation?.requirement || "",
actionsToBeImplemented: obligation?.actionsToBeImplemented || "",
regulator: obligation?.regulator || "",
lastReviewDate: obligation?.lastReviewDate
? new Date(obligation.lastReviewDate).toISOString().split("T")[0]
: "",
dueDate: registry.dueDate
? new Date(registry.dueDate).toISOString().split("T")[0]
dueDate: obligation?.dueDate
? new Date(obligation.dueDate).toISOString().split("T")[0]
: "",
status: registry.status || "OPEN",
ownerId: registry.owner?.id || "",
status: obligation?.status || "OPEN",
ownerId: obligation?.owner?.id || "",
},
}
);
const onSubmit = handleSubmit(async (formData) => {
try {
await updateRegistry({
id: registry.id!,
await updateObligation({
id: obligation.id!,
referenceId: formData.referenceId,
area: formData.area || undefined,
source: formData.source || undefined,
@@ -118,21 +121,21 @@ export default function ComplianceRegistryDetailsPage(props: Props) {
toast({
title: __("Success"),
description: __("Compliance registry entry updated successfully"),
description: __("Obligation updated successfully"),
variant: "success",
});
} catch (error) {
} catch {
toast({
title: __("Error"),
description: __("Failed to update compliance registry entry"),
description: __("Failed to update obligation"),
variant: "error",
});
}
});
const breadcrumbComplianceRegistriesUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/compliance-registries`
: `/organizations/${organizationId}/compliance-registries`;
const breadcrumbObligationsUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/obligations`
: `/organizations/${organizationId}/obligations`;
return (
<div className="space-y-6">
@@ -143,21 +146,21 @@ export default function ComplianceRegistryDetailsPage(props: Props) {
<div>
<Breadcrumb
items={[
{ label: __("Compliance Registries"), to: breadcrumbComplianceRegistriesUrl },
{ label: registry.referenceId! },
{ label: __("Obligations"), to: breadcrumbObligationsUrl },
{ label: obligation.referenceId! },
]}
/>
<div className="flex items-center gap-3 mt-2">
<h1 className="text-2xl font-bold">{registry.referenceId}</h1>
<Badge variant={getStatusVariant(registry.status || "OPEN")}>
{getStatusLabel(registry.status || "OPEN")}
<h1 className="text-2xl font-bold">{obligation.referenceId}</h1>
<Badge variant={getStatusVariant(obligation.status || "OPEN")}>
{getStatusLabel(obligation.status || "OPEN")}
</Badge>
</div>
</div>
{!isSnapshotMode && (
<ActionDropdown>
<DropdownItem icon={IconTrashCan} onClick={deleteRegistry}>
<DropdownItem icon={IconTrashCan} onClick={deleteObligation}>
{__("Delete")}
</DropdownItem>
</ActionDropdown>

View File

@@ -26,37 +26,37 @@ import {
} from "react-relay";
import { useParams } from "react-router";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { CreateComplianceRegistryDialog } from "./dialogs/CreateComplianceRegistryDialog";
import { deleteComplianceRegistryMutation } from "../../../hooks/graph/ComplianceRegistryGraph";
import { CreateObligationDialog } from "./dialogs/CreateObligationDialog";
import { deleteObligationMutation } from "../../../hooks/graph/ObligationGraph";
import { sprintf, promisifyMutation, getStatusVariant, getStatusLabel } from "@probo/helpers";
import { SnapshotBanner } from "/components/SnapshotBanner";
import type { ComplianceRegistriesPageQuery } from "./__generated__/ComplianceRegistriesPageQuery.graphql";
import type { ObligationsPageQuery } from "./__generated__/ObligationsPageQuery.graphql";
import type {
ComplianceRegistriesPageFragment$key,
ComplianceRegistriesPageFragment$data,
} from "./__generated__/ComplianceRegistriesPageFragment.graphql";
ObligationsPageFragment$key,
ObligationsPageFragment$data,
} from "./__generated__/ObligationsPageFragment.graphql";
type ComplianceRegistry = ComplianceRegistriesPageFragment$data['complianceRegistries']['edges'][number]['node'];
type Obligation = ObligationsPageFragment$data['obligations']['edges'][number]['node'];
interface ComplianceRegistriesPageProps {
queryRef: PreloadedQuery<ComplianceRegistriesPageQuery>;
interface ObligationsPageProps {
queryRef: PreloadedQuery<ObligationsPageQuery>;
}
const complianceRegistriesPageFragment = graphql`
fragment ComplianceRegistriesPageFragment on Organization
@refetchable(queryName: "ComplianceRegistriesPageRefetchQuery")
const obligationsPageFragment = graphql`
fragment ObligationsPageFragment on Organization
@refetchable(queryName: "ObligationsPageRefetchQuery")
@argumentDefinitions(
first: { type: "Int", defaultValue: 10 }
after: { type: "CursorKey" }
snapshotId: { type: "ID", defaultValue: null }
) {
id
complianceRegistries(
obligations(
first: $first
after: $after
filter: { snapshotId: $snapshotId }
)
@connection(key: "ComplianceRegistriesPage_complianceRegistries", filters: ["filter"]) {
@connection(key: "ObligationsPage_obligations", filters: ["filter"]) {
__id
totalCount
edges {
@@ -89,20 +89,20 @@ const complianceRegistriesPageFragment = graphql`
}
`;
export default function ComplianceRegistriesPage({ queryRef }: ComplianceRegistriesPageProps) {
export default function ObligationsPage({ queryRef }: ObligationsPageProps) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
usePageTitle(__("Compliance Registries"));
usePageTitle(__("Obligations"));
const organization = usePreloadedQuery(
graphql`
query ComplianceRegistriesPageQuery($organizationId: ID!, $snapshotId: ID) {
query ObligationsPageQuery($organizationId: ID!, $snapshotId: ID) {
node(id: $organizationId) {
... on Organization {
...ComplianceRegistriesPageFragment @arguments(snapshotId: $snapshotId)
...ObligationsPageFragment @arguments(snapshotId: $snapshotId)
}
}
}
@@ -110,13 +110,13 @@ export default function ComplianceRegistriesPage({ queryRef }: ComplianceRegistr
queryRef
);
const { data: registriesData, loadNext, hasNext } = usePaginationFragment(
complianceRegistriesPageFragment,
organization.node as ComplianceRegistriesPageFragment$key
const { data: obligationsData, loadNext, hasNext } = usePaginationFragment(
obligationsPageFragment,
organization.node as ObligationsPageFragment$key
);
const connectionId = registriesData?.complianceRegistries?.__id || "";
const registries: ComplianceRegistry[] = registriesData?.complianceRegistries?.edges?.map((edge) => edge.node) ?? [];
const connectionId = obligationsData?.obligations?.__id || "";
const obligations: Obligation[] = obligationsData?.obligations?.edges?.map((edge) => edge.node) ?? [];
return (
<div className="space-y-6">
@@ -124,26 +124,26 @@ export default function ComplianceRegistriesPage({ queryRef }: ComplianceRegistr
<SnapshotBanner snapshotId={snapshotId} />
)}
<PageHeader
title={__("Compliance Registries")}
title={__("Obligations")}
description={__(
"Manage your organization's compliance registry entries."
"Manage your organization's obligations."
)}
>
{!snapshotId && (
<CreateComplianceRegistryDialog organizationId={organizationId} connection={connectionId}>
<Button icon={IconPlusLarge}>{__("Add compliance registry")}</Button>
</CreateComplianceRegistryDialog>
<CreateObligationDialog organizationId={organizationId} connection={connectionId}>
<Button icon={IconPlusLarge}>{__("Add obligation")}</Button>
</CreateObligationDialog>
)}
</PageHeader>
{registries.length === 0 ? (
{obligations.length === 0 ? (
<Card padded>
<div className="text-center py-12">
<h3 className="text-lg font-semibold mb-2">
{__("No compliance registry entries yet")}
{__("No obligations yet")}
</h3>
<p className="text-txt-tertiary mb-4">
{__("Create your first compliance registry entry to get started.")}
{__("Create your first obligation to get started.")}
</p>
</div>
</Card>
@@ -162,10 +162,10 @@ export default function ComplianceRegistriesPage({ queryRef }: ComplianceRegistr
</Tr>
</Thead>
<Tbody>
{registries.map((registry) => (
<RegistryRow
key={registry.id}
registry={registry}
{obligations.map((obligation) => (
<ObligationRow
key={obligation.id}
obligation={obligation}
connectionId={connectionId}
snapshotId={snapshotId}
/>
@@ -190,18 +190,18 @@ export default function ComplianceRegistriesPage({ queryRef }: ComplianceRegistr
);
}
function RegistryRow({
registry,
function ObligationRow({
obligation,
connectionId,
snapshotId,
}: {
registry: ComplianceRegistry;
obligation: Obligation;
connectionId: string;
snapshotId?: string;
}) {
const organizationId = useOrganizationId();
const { __ } = useTranslate();
const [deleteRegistry] = useMutation(deleteComplianceRegistryMutation);
const [deleteObligation] = useMutation(deleteObligationMutation);
const confirm = useConfirm();
const isSnapshotMode = Boolean(snapshotId);
@@ -212,10 +212,10 @@ function RegistryRow({
const handleDelete = () => {
confirm(
() =>
promisifyMutation(deleteRegistry)({
promisifyMutation(deleteObligation)({
variables: {
input: {
complianceRegistryId: registry.id,
obligationId: obligation.id,
},
connections: [connectionId],
},
@@ -223,35 +223,35 @@ function RegistryRow({
{
message: sprintf(
__(
"This will permanently delete the compliance registry entry %s. This action cannot be undone."
"This will permanently delete the obligation %s. This action cannot be undone."
),
registry.referenceId
obligation.referenceId
),
}
);
};
const detailsUrl = isSnapshotMode
? `/organizations/${organizationId}/snapshots/${snapshotId}/compliance-registries/${registry.id}`
: `/organizations/${organizationId}/compliance-registries/${registry.id}`;
? `/organizations/${organizationId}/snapshots/${snapshotId}/obligations/${obligation.id}`
: `/organizations/${organizationId}/obligations/${obligation.id}`;
return (
<Tr to={detailsUrl}>
<Td>
<span className="font-mono text-sm">{registry.referenceId}</span>
<span className="font-mono text-sm">{obligation.referenceId}</span>
</Td>
<Td>{registry.area || "-"}</Td>
<Td>{registry.source || "-"}</Td>
<Td>{obligation.area || "-"}</Td>
<Td>{obligation.source || "-"}</Td>
<Td>
<Badge variant={getStatusVariant(registry.status || "OPEN")}>
{getStatusLabel(registry.status || "OPEN")}
<Badge variant={getStatusVariant(obligation.status || "OPEN")}>
{getStatusLabel(obligation.status || "OPEN")}
</Badge>
</Td>
<Td>{registry.owner?.fullName || "-"}</Td>
<Td>{obligation.owner?.fullName || "-"}</Td>
<Td>
{registry.dueDate ? (
<time dateTime={registry.dueDate}>
{formatDate(registry.dueDate)}
{obligation.dueDate ? (
<time dateTime={obligation.dueDate}>
{formatDate(obligation.dueDate)}
</time>
) : (
<span className="text-txt-tertiary">{__("No due date")}</span>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<db8b4530d56ae89fa8e332555a85eb33>>
* @generated SignedSource<<5f839350ed835351175b07d38512ba37>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,10 +9,11 @@
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type ComplianceRegistryStatus = "CLOSED" | "IN_PROGRESS" | "OPEN";
export type ObligationStatus = "CLOSED" | "IN_PROGRESS" | "OPEN";
import { FragmentRefs } from "relay-runtime";
export type ComplianceRegistriesPageFragment$data = {
readonly complianceRegistries: {
export type ObligationsPageFragment$data = {
readonly id: string;
readonly obligations: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
@@ -32,7 +33,7 @@ export type ComplianceRegistriesPageFragment$data = {
readonly snapshotId: string | null | undefined;
readonly source: string | null | undefined;
readonly sourceId: string | null | undefined;
readonly status: ComplianceRegistryStatus;
readonly status: ObligationStatus;
readonly updatedAt: any;
};
}>;
@@ -42,19 +43,18 @@ export type ComplianceRegistriesPageFragment$data = {
};
readonly totalCount: number;
};
readonly id: string;
readonly " $fragmentType": "ComplianceRegistriesPageFragment";
readonly " $fragmentType": "ObligationsPageFragment";
};
export type ComplianceRegistriesPageFragment$key = {
readonly " $data"?: ComplianceRegistriesPageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"ComplianceRegistriesPageFragment">;
export type ObligationsPageFragment$key = {
readonly " $data"?: ObligationsPageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"ObligationsPageFragment">;
};
import ComplianceRegistriesPageRefetchQuery_graphql from './ComplianceRegistriesPageRefetchQuery.graphql';
import ObligationsPageRefetchQuery_graphql from './ObligationsPageRefetchQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"complianceRegistries"
"obligations"
],
v1 = {
"alias": null,
@@ -103,18 +103,18 @@ return {
"fragmentPathInResult": [
"node"
],
"operation": ComplianceRegistriesPageRefetchQuery_graphql,
"operation": ObligationsPageRefetchQuery_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "ComplianceRegistriesPageFragment",
"name": "ObligationsPageFragment",
"selections": [
(v1/*: any*/),
{
"alias": "complianceRegistries",
"alias": "obligations",
"args": [
{
"fields": [
@@ -128,9 +128,9 @@ return {
"name": "filter"
}
],
"concreteType": "ComplianceRegistryConnection",
"concreteType": "ObligationConnection",
"kind": "LinkedField",
"name": "__ComplianceRegistriesPage_complianceRegistries_connection",
"name": "__ObligationsPage_obligations_connection",
"plural": false,
"selections": [
{
@@ -143,7 +143,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ComplianceRegistryEdge",
"concreteType": "ObligationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -151,7 +151,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ComplianceRegistry",
"concreteType": "Obligation",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -333,6 +333,6 @@ return {
};
})();
(node as any).hash = "b22ac157b9ba89ab14fe8363e56957ef";
(node as any).hash = "0d7452faf6e02f97885a65819dfb112b";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<794221c1dbbf8fd2d1808863d55d2c05>>
* @generated SignedSource<<f54af2ebc7ab4d39662c5619a23532ac>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,18 +10,18 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ComplianceRegistriesPageQuery$variables = {
export type ObligationsPageQuery$variables = {
organizationId: string;
snapshotId?: string | null | undefined;
};
export type ComplianceRegistriesPageQuery$data = {
export type ObligationsPageQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"ComplianceRegistriesPageFragment">;
readonly " $fragmentSpreads": FragmentRefs<"ObligationsPageFragment">;
};
};
export type ComplianceRegistriesPageQuery = {
response: ComplianceRegistriesPageQuery$data;
variables: ComplianceRegistriesPageQuery$variables;
export type ObligationsPageQuery = {
response: ObligationsPageQuery$data;
variables: ObligationsPageQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -82,7 +82,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ComplianceRegistriesPageQuery",
"name": "ObligationsPageQuery",
"selections": [
{
"alias": null,
@@ -98,7 +98,7 @@ return {
{
"args": (v2/*: any*/),
"kind": "FragmentSpread",
"name": "ComplianceRegistriesPageFragment"
"name": "ObligationsPageFragment"
}
],
"type": "Organization",
@@ -115,7 +115,7 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ComplianceRegistriesPageQuery",
"name": "ObligationsPageQuery",
"selections": [
{
"alias": null,
@@ -133,9 +133,9 @@ return {
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "ComplianceRegistryConnection",
"concreteType": "ObligationConnection",
"kind": "LinkedField",
"name": "complianceRegistries",
"name": "obligations",
"plural": false,
"selections": [
{
@@ -148,7 +148,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ComplianceRegistryEdge",
"concreteType": "ObligationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -156,7 +156,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ComplianceRegistry",
"concreteType": "Obligation",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -333,9 +333,9 @@ return {
"filter"
],
"handle": "connection",
"key": "ComplianceRegistriesPage_complianceRegistries",
"key": "ObligationsPage_obligations",
"kind": "LinkedHandle",
"name": "complianceRegistries"
"name": "obligations"
}
],
"type": "Organization",
@@ -347,16 +347,16 @@ return {
]
},
"params": {
"cacheID": "b63e74cea7f47c7e4f735ad2b52e1765",
"cacheID": "7e61419b20d9cf30e5dd31b4500bc324",
"id": null,
"metadata": {},
"name": "ComplianceRegistriesPageQuery",
"name": "ObligationsPageQuery",
"operationKind": "query",
"text": "query ComplianceRegistriesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ComplianceRegistriesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ComplianceRegistriesPageFragment_3iomuz on Organization {\n id\n complianceRegistries(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
"text": "query ObligationsPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ObligationsPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ObligationsPageFragment_3iomuz on Organization {\n id\n obligations(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
}
};
})();
(node as any).hash = "f0064c0d6d6e628923be30edb4b249db";
(node as any).hash = "720209ab225ef7a42f1edb96e5d58aa1";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<af4b3139bff8ab757fa1876aa4be4bb1>>
* @generated SignedSource<<c1ff0a7d2abc83b2111d20abecaf6baf>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,20 +10,20 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ComplianceRegistriesPageRefetchQuery$variables = {
export type ObligationsPageRefetchQuery$variables = {
after?: any | null | undefined;
first?: number | null | undefined;
id: string;
snapshotId?: string | null | undefined;
};
export type ComplianceRegistriesPageRefetchQuery$data = {
export type ObligationsPageRefetchQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"ComplianceRegistriesPageFragment">;
readonly " $fragmentSpreads": FragmentRefs<"ObligationsPageFragment">;
};
};
export type ComplianceRegistriesPageRefetchQuery = {
response: ComplianceRegistriesPageRefetchQuery$data;
variables: ComplianceRegistriesPageRefetchQuery$variables;
export type ObligationsPageRefetchQuery = {
response: ObligationsPageRefetchQuery$data;
variables: ObligationsPageRefetchQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -104,7 +104,7 @@ return {
],
"kind": "Fragment",
"metadata": null,
"name": "ComplianceRegistriesPageRefetchQuery",
"name": "ObligationsPageRefetchQuery",
"selections": [
{
"alias": null,
@@ -121,7 +121,7 @@ return {
(v7/*: any*/)
],
"kind": "FragmentSpread",
"name": "ComplianceRegistriesPageFragment"
"name": "ObligationsPageFragment"
}
],
"storageKey": null
@@ -139,7 +139,7 @@ return {
(v2/*: any*/)
],
"kind": "Operation",
"name": "ComplianceRegistriesPageRefetchQuery",
"name": "ObligationsPageRefetchQuery",
"selections": [
{
"alias": null,
@@ -157,9 +157,9 @@ return {
{
"alias": null,
"args": (v10/*: any*/),
"concreteType": "ComplianceRegistryConnection",
"concreteType": "ObligationConnection",
"kind": "LinkedField",
"name": "complianceRegistries",
"name": "obligations",
"plural": false,
"selections": [
{
@@ -172,7 +172,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ComplianceRegistryEdge",
"concreteType": "ObligationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -180,7 +180,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ComplianceRegistry",
"concreteType": "Obligation",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -357,9 +357,9 @@ return {
"filter"
],
"handle": "connection",
"key": "ComplianceRegistriesPage_complianceRegistries",
"key": "ObligationsPage_obligations",
"kind": "LinkedHandle",
"name": "complianceRegistries"
"name": "obligations"
}
],
"type": "Organization",
@@ -371,16 +371,16 @@ return {
]
},
"params": {
"cacheID": "d14ed4a195ca3b570ad5ecd255cf17e8",
"cacheID": "f34cf1412b7ff3e92971dfac07ca06ac",
"id": null,
"metadata": {},
"name": "ComplianceRegistriesPageRefetchQuery",
"name": "ObligationsPageRefetchQuery",
"operationKind": "query",
"text": "query ComplianceRegistriesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ComplianceRegistriesPageFragment_35e0S5\n id\n }\n}\n\nfragment ComplianceRegistriesPageFragment_35e0S5 on Organization {\n id\n complianceRegistries(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
"text": "query ObligationsPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ObligationsPageFragment_35e0S5\n id\n }\n}\n\nfragment ObligationsPageFragment_35e0S5 on Organization {\n id\n obligations(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
}
};
})();
(node as any).hash = "b22ac157b9ba89ab14fe8363e56957ef";
(node as any).hash = "0d7452faf6e02f97885a65819dfb112b";
export default node;

View File

@@ -17,10 +17,10 @@ import {
import { useTranslate } from "@probo/i18n";
import { z } from "zod";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { useCreateComplianceRegistry } from "../../../../hooks/graph/ComplianceRegistryGraph";
import { useCreateObligation } from "../../../../hooks/graph/ObligationGraph";
import { PeopleSelectField } from "/components/form/PeopleSelectField";
import { Controller } from "react-hook-form";
import { formatDatetime, getComplianceRegistryStatusOptions } from "@probo/helpers";
import { formatDatetime, getStatusOptions } from "@probo/helpers";
const schema = z.object({
referenceId: z.string().min(1, "Reference ID is required"),
@@ -37,23 +37,23 @@ const schema = z.object({
type FormData = z.infer<typeof schema>;
interface CreateComplianceRegistryDialogProps {
interface CreateObligationDialogProps {
children: ReactNode;
organizationId: string;
connection?: string;
}
export function CreateComplianceRegistryDialog({
export function CreateObligationDialog({
children,
organizationId,
connection,
}: CreateComplianceRegistryDialogProps) {
}: CreateObligationDialogProps) {
const { __ } = useTranslate();
const { toast } = useToast();
const dialogRef = useDialogRef();
const createRegistry = useCreateComplianceRegistry(connection || "");
const statusOptions = getComplianceRegistryStatusOptions(__);
const createObligation = useCreateObligation(connection || "");
const statusOptions = getStatusOptions(__);
const { register, handleSubmit, formState, reset, control } = useFormWithSchema(schema, {
defaultValues: {
@@ -72,7 +72,7 @@ export function CreateComplianceRegistryDialog({
const onSubmit = handleSubmit(async (formData: FormData) => {
try {
await createRegistry({
await createObligation({
organizationId,
referenceId: formData.referenceId,
area: formData.area || undefined,
@@ -88,16 +88,16 @@ export function CreateComplianceRegistryDialog({
toast({
title: __("Success"),
description: __("Compliance registry entry created successfully"),
description: __("Obligation created successfully"),
variant: "success",
});
reset();
dialogRef.current?.close();
} catch (error) {
} catch {
toast({
title: __("Error"),
description: __("Failed to create compliance registry entry"),
description: __("Failed to create obligation"),
variant: "error",
});
}
@@ -107,7 +107,7 @@ export function CreateComplianceRegistryDialog({
<Dialog
ref={dialogRef}
trigger={children}
title={<Breadcrumb items={[__("Registries"), __("Create Compliance Entry")]} />}
title={<Breadcrumb items={[__("Obligations"), __("Create Obligation")]} />}
className="max-w-2xl"
>
<form onSubmit={onSubmit}>
@@ -230,7 +230,7 @@ export function CreateComplianceRegistryDialog({
<DialogFooter>
<Button type="submit" disabled={formState.isSubmitting}>
{formState.isSubmitting ? __("Creating...") : __("Create Compliance Registry Entry")}
{formState.isSubmitting ? __("Creating...") : __("Create Obligation")}
</Button>
</DialogFooter>
</form>

View File

@@ -17,7 +17,7 @@ import {
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { usePageTitle } from "@probo/hooks";
import { getLawfulBasisLabel } from "../../../components/form/ProcessingActivityRegistryEnumOptions";
import { getLawfulBasisLabel } from "../../../components/form/ProcessingActivityEnumOptions";
import {
ConnectionHandler,
graphql,
@@ -28,36 +28,36 @@ import {
} from "react-relay";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { useParams } from "react-router";
import { CreateProcessingActivityRegistryDialog } from "./dialogs/CreateProcessingActivityRegistryDialog";
import { deleteProcessingActivityRegistryMutation, ProcessingActivityRegistriesConnectionKey } from "../../../hooks/graph/ProcessingActivityRegistryGraph";
import { CreateProcessingActivityDialog } from "./dialogs/CreateProcessingActivityDialog";
import { deleteProcessingActivityMutation, ProcessingActivitiesConnectionKey } from "../../../hooks/graph/ProcessingActivityGraph";
import { sprintf, promisifyMutation } from "@probo/helpers";
import { SnapshotBanner } from "/components/SnapshotBanner";
import type { NodeOf } from "/types";
import type { ProcessingActivityRegistriesPageQuery } from "./__generated__/ProcessingActivityRegistriesPageQuery.graphql";
import type { ProcessingActivitiesPageQuery } from "./__generated__/ProcessingActivitiesPageQuery.graphql";
import type {
ProcessingActivityRegistriesPageFragment$key,
ProcessingActivityRegistriesPageFragment$data,
} from "./__generated__/ProcessingActivityRegistriesPageFragment.graphql";
ProcessingActivitiesPageFragment$key,
ProcessingActivitiesPageFragment$data,
} from "./__generated__/ProcessingActivitiesPageFragment.graphql";
interface ProcessingActivityRegistriesPageProps {
queryRef: PreloadedQuery<ProcessingActivityRegistriesPageQuery>;
interface ProcessingActivitiesPageProps {
queryRef: PreloadedQuery<ProcessingActivitiesPageQuery>;
}
const processingActivityRegistriesPageFragment = graphql`
fragment ProcessingActivityRegistriesPageFragment on Organization
@refetchable(queryName: "ProcessingActivityRegistriesPageRefetchQuery")
const processingActivitiesPageFragment = graphql`
fragment ProcessingActivitiesPageFragment on Organization
@refetchable(queryName: "ProcessingActivitiesPageRefetchQuery")
@argumentDefinitions(
first: { type: "Int", defaultValue: 10 }
after: { type: "CursorKey" }
snapshotId: { type: "ID", defaultValue: null }
) {
id
processingActivityRegistries(
processingActivities(
first: $first
after: $after
filter: { snapshotId: $snapshotId }
)
@connection(key: "ProcessingActivityRegistriesPage_processingActivityRegistries", filters: ["filter"]) {
@connection(key: "ProcessingActivitiesPage_processingActivities", filters: ["filter"]) {
__id
totalCount
edges {
@@ -84,21 +84,21 @@ const processingActivityRegistriesPageFragment = graphql`
}
`;
export default function ProcessingActivityRegistriesPage({ queryRef }: ProcessingActivityRegistriesPageProps) {
export default function ProcessingActivitiesPage({ queryRef }: ProcessingActivitiesPageProps) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
usePageTitle(__("Processing Activity Registries"));
usePageTitle(__("Processing Activities"));
const organization = usePreloadedQuery(
graphql`
query ProcessingActivityRegistriesPageQuery($organizationId: ID!, $snapshotId: ID) {
query ProcessingActivitiesPageQuery($organizationId: ID!, $snapshotId: ID) {
node(id: $organizationId) {
... on Organization {
...ProcessingActivityRegistriesPageFragment @arguments(snapshotId: $snapshotId)
...ProcessingActivitiesPageFragment @arguments(snapshotId: $snapshotId)
}
}
}
@@ -112,39 +112,39 @@ export default function ProcessingActivityRegistriesPage({ queryRef }: Processin
hasNext,
isLoadingNext,
} = usePaginationFragment<
ProcessingActivityRegistriesPageQuery,
ProcessingActivityRegistriesPageFragment$key
>(processingActivityRegistriesPageFragment, organization.node);
ProcessingActivitiesPageQuery,
ProcessingActivitiesPageFragment$key
>(processingActivitiesPageFragment, organization.node);
if (!data) {
return <div>{__("Organization not found")}</div>;
}
const connectionId = ConnectionHandler.getConnectionID(
organizationId,
ProcessingActivityRegistriesConnectionKey,
ProcessingActivitiesConnectionKey,
{ filter: { snapshotId: snapshotId || null } }
);
const registries = data?.processingActivityRegistries?.edges?.map((edge) => edge.node) ?? [];
const activities = data?.processingActivities?.edges?.map((edge) => edge.node) ?? [];
return (
<div className="space-y-6">
{isSnapshotMode && snapshotId && (
<SnapshotBanner snapshotId={snapshotId} />
)}
<PageHeader title={__("Processing Activity Registries")} description={__("Manage your processing activity registry entries under GDPR")}>
<PageHeader title={__("Processing Activities")} description={__("Manage your processing activities under GDPR")}>
{!isSnapshotMode && (
<CreateProcessingActivityRegistryDialog
<CreateProcessingActivityDialog
organizationId={organizationId}
connectionId={connectionId}
>
<Button icon={IconPlusLarge}>
{__("Add processing activity registry")}
{__("Add processing activity")}
</Button>
</CreateProcessingActivityRegistryDialog>
</CreateProcessingActivityDialog>
)}
</PageHeader>
{registries.length > 0 ? (
{activities.length > 0 ? (
<Card>
<Table>
<Thead>
@@ -159,10 +159,10 @@ export default function ProcessingActivityRegistriesPage({ queryRef }: Processin
</Tr>
</Thead>
<Tbody>
{registries.map((registry) => (
<RegistryRow
key={registry.id}
registry={registry}
{activities.map((activity) => (
<ActivityRow
key={activity.id}
activity={activity}
connectionId={connectionId}
/>
))}
@@ -185,10 +185,10 @@ export default function ProcessingActivityRegistriesPage({ queryRef }: Processin
<Card padded>
<div className="text-center py-12">
<h3 className="text-lg font-semibold mb-2">
{__("No processing activity registry entries yet")}
{__("No processing activities yet")}
</h3>
<p className="text-txt-tertiary mb-4">
{__("Create your first processing activity registry entry to get started with GDPR compliance.")}
{__("Create your first processing activity to get started with GDPR compliance.")}
</p>
</div>
</Card>
@@ -197,27 +197,27 @@ export default function ProcessingActivityRegistriesPage({ queryRef }: Processin
);
}
function RegistryRow({
registry,
function ActivityRow({
activity,
connectionId,
}: {
registry: NodeOf<NonNullable<ProcessingActivityRegistriesPageFragment$data['processingActivityRegistries']>>;
activity: NodeOf<NonNullable<ProcessingActivitiesPageFragment$data['processingActivities']>>;
connectionId: string;
}) {
const organizationId = useOrganizationId();
const { __ } = useTranslate();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
const [deleteRegistry] = useMutation(deleteProcessingActivityRegistryMutation);
const [deleteActivity] = useMutation(deleteProcessingActivityMutation);
const confirm = useConfirm();
const handleDelete = () => {
confirm(
() =>
promisifyMutation(deleteRegistry)({
promisifyMutation(deleteActivity)({
variables: {
input: {
processingActivityRegistryId: registry.id,
processingActivityId: activity.id,
},
connections: [connectionId],
},
@@ -225,34 +225,34 @@ function RegistryRow({
{
message: sprintf(
__(
"This will permanently delete the processing activity registry entry %s. This action cannot be undone."
"This will permanently delete the processing activity %s. This action cannot be undone."
),
registry.name
activity.name
),
}
);
};
const registryUrl = isSnapshotMode && snapshotId
? `/organizations/${organizationId}/snapshots/${snapshotId}/processing-activity-registries/${registry.id}`
: `/organizations/${organizationId}/processing-activity-registries/${registry.id}`;
const activityUrl = isSnapshotMode && snapshotId
? `/organizations/${organizationId}/snapshots/${snapshotId}/processing-activities/${activity.id}`
: `/organizations/${organizationId}/processing-activities/${activity.id}`;
return (
<Tr to={registryUrl}>
<Tr to={activityUrl}>
<Td>
<span className="font-semibold">{registry.name}</span>
<span className="font-semibold">{activity.name}</span>
</Td>
<Td>
<span className="text-sm text-txt-secondary">
{registry.purpose || "-"}
{activity.purpose || "-"}
</span>
</Td>
<Td>{registry.dataSubjectCategory || "-"}</Td>
<Td>{getLawfulBasisLabel(registry.lawfulBasis, __)}</Td>
<Td>{registry.location || "-"}</Td>
<Td>{activity.dataSubjectCategory || "-"}</Td>
<Td>{getLawfulBasisLabel(activity.lawfulBasis, __)}</Td>
<Td>{activity.location || "-"}</Td>
<Td>
<Badge variant={registry.internationalTransfers ? "warning" : "success"}>
{registry.internationalTransfers ? __("Yes") : __("No")}
<Badge variant={activity.internationalTransfers ? "warning" : "success"}>
{activity.internationalTransfers ? __("Yes") : __("No")}
</Badge>
</Td>
{!isSnapshotMode && (

View File

@@ -4,11 +4,11 @@ import {
type PreloadedQuery,
} from "react-relay";
import {
processingActivityRegistryNodeQuery,
useDeleteProcessingActivityRegistry,
useUpdateProcessingActivityRegistry,
ProcessingActivityRegistriesConnectionKey,
} from "../../../hooks/graph/ProcessingActivityRegistryGraph";
processingActivityNodeQuery,
useDeleteProcessingActivity,
useUpdateProcessingActivity,
ProcessingActivitiesConnectionKey,
} from "../../../hooks/graph/ProcessingActivityGraph";
import {
ActionDropdown,
Breadcrumb,
@@ -36,11 +36,11 @@ import {
TransferSafeguardsOptions,
DataProtectionImpactAssessmentOptions,
TransferImpactAssessmentOptions,
} from "../../../components/form/ProcessingActivityRegistryEnumOptions";
} from "../../../components/form/ProcessingActivityEnumOptions";
import type { ProcessingActivityRegistryGraphNodeQuery } from "/hooks/graph/__generated__/ProcessingActivityRegistryGraphNodeQuery.graphql";
import type { ProcessingActivityGraphNodeQuery } from "/hooks/graph/__generated__/ProcessingActivityGraphNodeQuery.graphql";
const updateRegistrySchema = z.object({
const updateProcessingActivitySchema = z.object({
name: z.string().min(1, "Name is required"),
purpose: z.string().optional(),
dataSubjectCategory: z.string().optional(),
@@ -59,61 +59,61 @@ const updateRegistrySchema = z.object({
});
type Props = {
queryRef: PreloadedQuery<ProcessingActivityRegistryGraphNodeQuery>;
queryRef: PreloadedQuery<ProcessingActivityGraphNodeQuery>;
};
export default function ProcessingActivityRegistryDetailsPage(props: Props) {
const data = usePreloadedQuery<ProcessingActivityRegistryGraphNodeQuery>(processingActivityRegistryNodeQuery, props.queryRef);
const registry = data.node;
export default function ProcessingActivityDetailsPage(props: Props) {
const data = usePreloadedQuery<ProcessingActivityGraphNodeQuery>(processingActivityNodeQuery, props.queryRef);
const activity = data.node;
const { __ } = useTranslate();
const { toast } = useToast();
const organizationId = useOrganizationId();
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
if (!registry) {
return <div>{__("Processing activity registry entry not found")}</div>;
if (!activity) {
return <div>{__("Processing activity not found")}</div>;
}
validateSnapshotConsistency(registry, snapshotId);
validateSnapshotConsistency(activity, snapshotId);
const updateRegistry = useUpdateProcessingActivityRegistry();
const updateActivity = useUpdateProcessingActivity();
const connectionId = ConnectionHandler.getConnectionID(
organizationId,
ProcessingActivityRegistriesConnectionKey,
ProcessingActivitiesConnectionKey,
{ filter: { snapshotId: snapshotId || null } }
);
const deleteRegistry = useDeleteProcessingActivityRegistry({ id: registry.id!, name: registry.name! }, connectionId);
const deleteActivity = useDeleteProcessingActivity({ id: activity.id!, name: activity.name! }, connectionId);
const { register, handleSubmit, formState, control } = useFormWithSchema(
updateRegistrySchema,
updateProcessingActivitySchema,
{
defaultValues: {
name: registry.name || "",
purpose: registry.purpose || "",
dataSubjectCategory: registry.dataSubjectCategory || "",
personalDataCategory: registry.personalDataCategory || "",
specialOrCriminalData: registry.specialOrCriminalData || "NO" as const,
consentEvidenceLink: registry.consentEvidenceLink || "",
lawfulBasis: registry.lawfulBasis || "LEGITIMATE_INTEREST" as const,
recipients: registry.recipients || "",
location: registry.location || "",
internationalTransfers: registry.internationalTransfers || false,
transferSafeguards: registry.transferSafeguards || "__NONE__",
retentionPeriod: registry.retentionPeriod || "",
securityMeasures: registry.securityMeasures || "",
dataProtectionImpactAssessment: registry.dataProtectionImpactAssessment || "NOT_NEEDED" as const,
transferImpactAssessment: registry.transferImpactAssessment || "NOT_NEEDED" as const,
name: activity.name || "",
purpose: activity.purpose || "",
dataSubjectCategory: activity.dataSubjectCategory || "",
personalDataCategory: activity.personalDataCategory || "",
specialOrCriminalData: activity.specialOrCriminalData || "NO" as const,
consentEvidenceLink: activity.consentEvidenceLink || "",
lawfulBasis: activity.lawfulBasis || "LEGITIMATE_INTEREST" as const,
recipients: activity.recipients || "",
location: activity.location || "",
internationalTransfers: activity.internationalTransfers || false,
transferSafeguards: activity.transferSafeguards || "__NONE__",
retentionPeriod: activity.retentionPeriod || "",
securityMeasures: activity.securityMeasures || "",
dataProtectionImpactAssessment: activity.dataProtectionImpactAssessment || "NOT_NEEDED" as const,
transferImpactAssessment: activity.transferImpactAssessment || "NOT_NEEDED" as const,
},
}
);
const onSubmit = handleSubmit(async (formData) => {
try {
await updateRegistry({
id: registry.id!,
await updateActivity({
id: activity.id!,
name: formData.name,
purpose: formData.purpose || undefined,
dataSubjectCategory: formData.dataSubjectCategory || undefined,
@@ -133,21 +133,21 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
toast({
title: __("Success"),
description: __("Processing activity registry entry updated successfully"),
description: __("Processing activity updated successfully"),
variant: "success",
});
} catch (error) {
toast({
title: __("Error"),
description: __("Failed to update processing activity registry entry"),
description: __("Failed to update processing activity"),
variant: "error",
});
}
});
const breadcrumbRegistriesUrl = isSnapshotMode && snapshotId
? `/organizations/${organizationId}/snapshots/${snapshotId}/processing-activity-registries`
: `/organizations/${organizationId}/processing-activity-registries`;
const breadcrumbProcessingActivitiesUrl = isSnapshotMode && snapshotId
? `/organizations/${organizationId}/snapshots/${snapshotId}/processing-activities`
: `/organizations/${organizationId}/processing-activities`;
return (
<div className="space-y-6">
@@ -157,13 +157,13 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
<div className="flex items-center justify-between">
<Breadcrumb
items={[
{ label: __("Processing Activity Registries"), to: breadcrumbRegistriesUrl },
{ label: registry.name! },
{ label: __("Processing Activities"), to: breadcrumbProcessingActivitiesUrl },
{ label: activity.name! },
]}
/>
{!isSnapshotMode && (
<ActionDropdown>
<DropdownItem onClick={deleteRegistry} variant="danger">
<DropdownItem onClick={deleteActivity} variant="danger">
{__("Delete")}
</DropdownItem>
</ActionDropdown>
@@ -174,7 +174,7 @@ export default function ProcessingActivityRegistryDetailsPage(props: Props) {
<div className="p-6">
<div className="mb-6">
<div className="flex items-center gap-4">
<h1 className="text-2xl font-bold">{registry.name}</h1>
<h1 className="text-2xl font-bold">{activity.name}</h1>
</div>
</div>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<138a897eea1aa78073db58d717fe2947>>
* @generated SignedSource<<720ca14096de267a177e9f8e4b549036>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,11 +9,11 @@
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type ProcessingActivityRegistryLawfulBasis = "CONSENT" | "CONTRACTUAL_NECESSITY" | "LEGAL_OBLIGATION" | "LEGITIMATE_INTEREST" | "PUBLIC_TASK" | "VITAL_INTERESTS";
export type ProcessingActivityLawfulBasis = "CONSENT" | "CONTRACTUAL_NECESSITY" | "LEGAL_OBLIGATION" | "LEGITIMATE_INTEREST" | "PUBLIC_TASK" | "VITAL_INTERESTS";
import { FragmentRefs } from "relay-runtime";
export type ProcessingActivityRegistriesPageFragment$data = {
export type ProcessingActivitiesPageFragment$data = {
readonly id: string;
readonly processingActivityRegistries: {
readonly processingActivities: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
@@ -21,7 +21,7 @@ export type ProcessingActivityRegistriesPageFragment$data = {
readonly dataSubjectCategory: string | null | undefined;
readonly id: string;
readonly internationalTransfers: boolean;
readonly lawfulBasis: ProcessingActivityRegistryLawfulBasis;
readonly lawfulBasis: ProcessingActivityLawfulBasis;
readonly location: string | null | undefined;
readonly name: string;
readonly personalDataCategory: string | null | undefined;
@@ -37,18 +37,18 @@ export type ProcessingActivityRegistriesPageFragment$data = {
};
readonly totalCount: number;
};
readonly " $fragmentType": "ProcessingActivityRegistriesPageFragment";
readonly " $fragmentType": "ProcessingActivitiesPageFragment";
};
export type ProcessingActivityRegistriesPageFragment$key = {
readonly " $data"?: ProcessingActivityRegistriesPageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivityRegistriesPageFragment">;
export type ProcessingActivitiesPageFragment$key = {
readonly " $data"?: ProcessingActivitiesPageFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivitiesPageFragment">;
};
import ProcessingActivityRegistriesPageRefetchQuery_graphql from './ProcessingActivityRegistriesPageRefetchQuery.graphql';
import ProcessingActivitiesPageRefetchQuery_graphql from './ProcessingActivitiesPageRefetchQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"processingActivityRegistries"
"processingActivities"
],
v1 = {
"alias": null,
@@ -97,18 +97,18 @@ return {
"fragmentPathInResult": [
"node"
],
"operation": ProcessingActivityRegistriesPageRefetchQuery_graphql,
"operation": ProcessingActivitiesPageRefetchQuery_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "ProcessingActivityRegistriesPageFragment",
"name": "ProcessingActivitiesPageFragment",
"selections": [
(v1/*: any*/),
{
"alias": "processingActivityRegistries",
"alias": "processingActivities",
"args": [
{
"fields": [
@@ -122,9 +122,9 @@ return {
"name": "filter"
}
],
"concreteType": "ProcessingActivityRegistryConnection",
"concreteType": "ProcessingActivityConnection",
"kind": "LinkedField",
"name": "__ProcessingActivityRegistriesPage_processingActivityRegistries_connection",
"name": "__ProcessingActivitiesPage_processingActivities_connection",
"plural": false,
"selections": [
{
@@ -137,7 +137,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ProcessingActivityRegistryEdge",
"concreteType": "ProcessingActivityEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -145,7 +145,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ProcessingActivityRegistry",
"concreteType": "ProcessingActivity",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -294,6 +294,6 @@ return {
};
})();
(node as any).hash = "a31cad7de09ddd436e7fa9068d53e05e";
(node as any).hash = "e60b3eb3cf3d172625c2873cb05039bd";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e77ebb6a609b6122e9c6927f4e00acc4>>
* @generated SignedSource<<f85f96db81638fcf82015c2a936d6ed0>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,18 +10,18 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ProcessingActivityRegistriesPageQuery$variables = {
export type ProcessingActivitiesPageQuery$variables = {
organizationId: string;
snapshotId?: string | null | undefined;
};
export type ProcessingActivityRegistriesPageQuery$data = {
export type ProcessingActivitiesPageQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivityRegistriesPageFragment">;
readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivitiesPageFragment">;
};
};
export type ProcessingActivityRegistriesPageQuery = {
response: ProcessingActivityRegistriesPageQuery$data;
variables: ProcessingActivityRegistriesPageQuery$variables;
export type ProcessingActivitiesPageQuery = {
response: ProcessingActivitiesPageQuery$data;
variables: ProcessingActivitiesPageQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -82,7 +82,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ProcessingActivityRegistriesPageQuery",
"name": "ProcessingActivitiesPageQuery",
"selections": [
{
"alias": null,
@@ -98,7 +98,7 @@ return {
{
"args": (v2/*: any*/),
"kind": "FragmentSpread",
"name": "ProcessingActivityRegistriesPageFragment"
"name": "ProcessingActivitiesPageFragment"
}
],
"type": "Organization",
@@ -115,7 +115,7 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ProcessingActivityRegistriesPageQuery",
"name": "ProcessingActivitiesPageQuery",
"selections": [
{
"alias": null,
@@ -133,9 +133,9 @@ return {
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "ProcessingActivityRegistryConnection",
"concreteType": "ProcessingActivityConnection",
"kind": "LinkedField",
"name": "processingActivityRegistries",
"name": "processingActivities",
"plural": false,
"selections": [
{
@@ -148,7 +148,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ProcessingActivityRegistryEdge",
"concreteType": "ProcessingActivityEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -156,7 +156,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ProcessingActivityRegistry",
"concreteType": "ProcessingActivity",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -300,9 +300,9 @@ return {
"filter"
],
"handle": "connection",
"key": "ProcessingActivityRegistriesPage_processingActivityRegistries",
"key": "ProcessingActivitiesPage_processingActivities",
"kind": "LinkedHandle",
"name": "processingActivityRegistries"
"name": "processingActivities"
}
],
"type": "Organization",
@@ -314,16 +314,16 @@ return {
]
},
"params": {
"cacheID": "2b5cf834c7b4f34bb4a8e74705d1e530",
"cacheID": "dfb1835056b3e318e7d1b8a9e351dcaf",
"id": null,
"metadata": {},
"name": "ProcessingActivityRegistriesPageQuery",
"name": "ProcessingActivitiesPageQuery",
"operationKind": "query",
"text": "query ProcessingActivityRegistriesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivityRegistriesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ProcessingActivityRegistriesPageFragment_3iomuz on Organization {\n id\n processingActivityRegistries(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
"text": "query ProcessingActivitiesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivitiesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ProcessingActivitiesPageFragment_3iomuz on Organization {\n id\n processingActivities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
}
};
})();
(node as any).hash = "a4030e6ab7ce0351b431ce90d0440135";
(node as any).hash = "68aa1223c7d37dec18879900c126bd42";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<fc4bc917b12579179eb09cc4919b1b57>>
* @generated SignedSource<<38414e52b180db9b290d16231a2c69ef>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,20 +10,20 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ProcessingActivityRegistriesPageRefetchQuery$variables = {
export type ProcessingActivitiesPageRefetchQuery$variables = {
after?: any | null | undefined;
first?: number | null | undefined;
id: string;
snapshotId?: string | null | undefined;
};
export type ProcessingActivityRegistriesPageRefetchQuery$data = {
export type ProcessingActivitiesPageRefetchQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivityRegistriesPageFragment">;
readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivitiesPageFragment">;
};
};
export type ProcessingActivityRegistriesPageRefetchQuery = {
response: ProcessingActivityRegistriesPageRefetchQuery$data;
variables: ProcessingActivityRegistriesPageRefetchQuery$variables;
export type ProcessingActivitiesPageRefetchQuery = {
response: ProcessingActivitiesPageRefetchQuery$data;
variables: ProcessingActivitiesPageRefetchQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -104,7 +104,7 @@ return {
],
"kind": "Fragment",
"metadata": null,
"name": "ProcessingActivityRegistriesPageRefetchQuery",
"name": "ProcessingActivitiesPageRefetchQuery",
"selections": [
{
"alias": null,
@@ -121,7 +121,7 @@ return {
(v7/*: any*/)
],
"kind": "FragmentSpread",
"name": "ProcessingActivityRegistriesPageFragment"
"name": "ProcessingActivitiesPageFragment"
}
],
"storageKey": null
@@ -139,7 +139,7 @@ return {
(v2/*: any*/)
],
"kind": "Operation",
"name": "ProcessingActivityRegistriesPageRefetchQuery",
"name": "ProcessingActivitiesPageRefetchQuery",
"selections": [
{
"alias": null,
@@ -157,9 +157,9 @@ return {
{
"alias": null,
"args": (v10/*: any*/),
"concreteType": "ProcessingActivityRegistryConnection",
"concreteType": "ProcessingActivityConnection",
"kind": "LinkedField",
"name": "processingActivityRegistries",
"name": "processingActivities",
"plural": false,
"selections": [
{
@@ -172,7 +172,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ProcessingActivityRegistryEdge",
"concreteType": "ProcessingActivityEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -180,7 +180,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "ProcessingActivityRegistry",
"concreteType": "ProcessingActivity",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -324,9 +324,9 @@ return {
"filter"
],
"handle": "connection",
"key": "ProcessingActivityRegistriesPage_processingActivityRegistries",
"key": "ProcessingActivitiesPage_processingActivities",
"kind": "LinkedHandle",
"name": "processingActivityRegistries"
"name": "processingActivities"
}
],
"type": "Organization",
@@ -338,16 +338,16 @@ return {
]
},
"params": {
"cacheID": "f6f29dda67221647df6a500c124091a2",
"cacheID": "bf2fb9a8eb709e64268710ca36f86a72",
"id": null,
"metadata": {},
"name": "ProcessingActivityRegistriesPageRefetchQuery",
"name": "ProcessingActivitiesPageRefetchQuery",
"operationKind": "query",
"text": "query ProcessingActivityRegistriesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ProcessingActivityRegistriesPageFragment_35e0S5\n id\n }\n}\n\nfragment ProcessingActivityRegistriesPageFragment_35e0S5 on Organization {\n id\n processingActivityRegistries(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
"text": "query ProcessingActivitiesPageRefetchQuery(\n $after: CursorKey\n $first: Int = 10\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...ProcessingActivitiesPageFragment_35e0S5\n id\n }\n}\n\nfragment ProcessingActivitiesPageFragment_35e0S5 on Organization {\n id\n processingActivities(first: $first, after: $after, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
}
};
})();
(node as any).hash = "a31cad7de09ddd436e7fa9068d53e05e";
(node as any).hash = "e60b3eb3cf3d172625c2873cb05039bd";
export default node;

View File

@@ -16,7 +16,7 @@ import {
import { useTranslate } from "@probo/i18n";
import { z } from "zod";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { useCreateProcessingActivityRegistry } from "../../../../hooks/graph/ProcessingActivityRegistryGraph";
import { useCreateProcessingActivity } from "../../../../hooks/graph/ProcessingActivityGraph";
import { Controller } from "react-hook-form";
import {
SpecialOrCriminalDataOptions,
@@ -24,7 +24,7 @@ import {
TransferSafeguardsOptions,
DataProtectionImpactAssessmentOptions,
TransferImpactAssessmentOptions,
} from "../../../../components/form/ProcessingActivityRegistryEnumOptions";
} from "../../../../components/form/ProcessingActivityEnumOptions";
const schema = z.object({
name: z.string().min(1, "Name is required"),
@@ -46,22 +46,22 @@ const schema = z.object({
type FormData = z.infer<typeof schema>;
interface CreateProcessingActivityRegistryDialogProps {
interface CreateProcessingActivityDialogProps {
children: ReactNode;
organizationId: string;
connectionId?: string;
}
export function CreateProcessingActivityRegistryDialog({
export function CreateProcessingActivityDialog({
children,
organizationId,
connectionId,
}: CreateProcessingActivityRegistryDialogProps) {
}: CreateProcessingActivityDialogProps) {
const { __ } = useTranslate();
const { toast } = useToast();
const dialogRef = useDialogRef();
const createRegistry = useCreateProcessingActivityRegistry(connectionId);
const createProcessingActivity = useCreateProcessingActivity(connectionId);
const { register, handleSubmit, formState, reset, control } = useFormWithSchema(schema, {
defaultValues: {
@@ -85,7 +85,7 @@ export function CreateProcessingActivityRegistryDialog({
const onSubmit = handleSubmit(async (formData: FormData) => {
try {
await createRegistry({
await createProcessingActivity({
organizationId,
name: formData.name,
purpose: formData.purpose || undefined,
@@ -106,7 +106,7 @@ export function CreateProcessingActivityRegistryDialog({
toast({
title: __("Success"),
description: __("Processing activity registry entry created successfully"),
description: __("Processing activity created successfully"),
variant: "success",
});
@@ -115,7 +115,7 @@ export function CreateProcessingActivityRegistryDialog({
} catch (error) {
toast({
title: __("Error"),
description: __("Failed to create processing activity registry entry"),
description: __("Failed to create processing activity"),
variant: "error",
});
}
@@ -125,7 +125,7 @@ export function CreateProcessingActivityRegistryDialog({
<Dialog
ref={dialogRef}
trigger={children}
title={<Breadcrumb items={[__("Registries"), __("Create Processing Activity Entry")]} />}
title={<Breadcrumb items={[__("Processing Activities"), __("Create Processing Activity")]} />}
className="max-w-4xl"
>
<form onSubmit={onSubmit}>
@@ -338,7 +338,7 @@ export function CreateProcessingActivityRegistryDialog({
variant="primary"
disabled={formState.isSubmitting}
>
{formState.isSubmitting ? __("Creating...") : __("Create Entry")}
{formState.isSubmitting ? __("Creating...") : __("Create Processing Activity")}
</Button>
</DialogFooter>
</form>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<dc710d55da977c21a12e3e21f29fbe94>>
* @generated SignedSource<<79d48ab0fd5b269022244b0777eac279>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,7 +9,7 @@
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "PROCESSING_ACTIVITY_REGISTRIES" | "RISKS" | "VENDORS";
export type SnapshotsType = "ASSETS" | "CONTINUAL_IMPROVEMENTS" | "DATA" | "NONCONFORMITIES" | "OBLIGATIONS" | "PROCESSING_ACTIVITIES" | "RISKS" | "VENDORS";
import { FragmentRefs } from "relay-runtime";
export type SnapshotsPageFragment$data = {
readonly snapshots: {

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<50dda5d856ca750f1e85a8c1d2935c9c>>
* @generated SignedSource<<4a28eec1f25c5d290bc070a534042521>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,7 +9,7 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type SnapshotsType = "ASSETS" | "COMPLIANCE_REGISTRIES" | "CONTINUAL_IMPROVEMENT_REGISTRIES" | "DATA" | "NONCONFORMITY_REGISTRIES" | "PROCESSING_ACTIVITY_REGISTRIES" | "RISKS" | "VENDORS";
export type SnapshotsType = "ASSETS" | "CONTINUAL_IMPROVEMENTS" | "DATA" | "NONCONFORMITIES" | "OBLIGATIONS" | "PROCESSING_ACTIVITIES" | "RISKS" | "VENDORS";
export type CreateSnapshotInput = {
description?: string | null | undefined;
name: string;