Move console to a relay multi project config

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2025-12-30 10:37:23 +01:00
committed by Bryan Frimin
parent c1df98cec1
commit 6b2864e160
572 changed files with 6400 additions and 4263 deletions

View File

@@ -2,8 +2,13 @@ import { IconClock } from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { useLazyLoadQuery, graphql } from "react-relay";
import { useLocation } from "react-router";
import type { SnapshotBannerQuery } from "./__generated__/SnapshotBannerQuery.graphql";
import { getSnapshotTypeUrlPath, getSnapshotTypeLabel, sprintf, formatDate } from "@probo/helpers";
import type { SnapshotBannerQuery } from "/__generated__/core/SnapshotBannerQuery.graphql";
import {
getSnapshotTypeUrlPath,
getSnapshotTypeLabel,
sprintf,
formatDate,
} from "@probo/helpers";
const snapshotQuery = graphql`
query SnapshotBannerQuery($snapshotId: ID!) {
@@ -31,14 +36,19 @@ export function SnapshotBanner({ snapshotId }: Props) {
const { __ } = useTranslate();
const location = useLocation();
const data = useLazyLoadQuery<SnapshotBannerQuery>(snapshotQuery, { snapshotId });
const data = useLazyLoadQuery<SnapshotBannerQuery>(snapshotQuery, {
snapshotId,
});
const snapshot = data.node;
if (!snapshot) {
return null;
}
if (snapshot.type && !isSnapshotTypeValidForUrl(snapshot.type, location.pathname)) {
if (
snapshot.type &&
!isSnapshotTypeValidForUrl(snapshot.type, location.pathname)
) {
throw new Error("PAGE_NOT_FOUND");
}
@@ -47,13 +57,15 @@ export function SnapshotBanner({ snapshotId }: Props) {
<IconClock className="text-warning-600 flex-shrink-0" size={20} />
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<span className="font-medium text-warning-800">{__("Snapshot")} {snapshot.name}</span>
<span className="font-medium text-warning-800">
{__("Snapshot")} {snapshot.name}
</span>
</div>
<p className="text-sm text-warning-700">
{sprintf(
__("You are viewing a %s snapshot from %s"),
getSnapshotTypeLabel(__, snapshot.type).toLocaleLowerCase(),
formatDate(snapshot.createdAt)
formatDate(snapshot.createdAt),
)}
</p>
</div>

View File

@@ -1,155 +0,0 @@
/**
* @generated SignedSource<<a62993ad367f0d977f346e507dd6b572>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type SnapshotsType = "ASSETS" | "CONTINUAL_IMPROVEMENTS" | "DATA" | "NONCONFORMITIES" | "OBLIGATIONS" | "PROCESSING_ACTIVITIES" | "RISKS" | "STATES_OF_APPLICABILITY" | "VENDORS";
export type SnapshotBannerQuery$variables = {
snapshotId: string;
};
export type SnapshotBannerQuery$data = {
readonly node: {
readonly createdAt?: any;
readonly id?: string;
readonly name?: string;
readonly type?: SnapshotsType;
};
};
export type SnapshotBannerQuery = {
response: SnapshotBannerQuery$data;
variables: SnapshotBannerQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "snapshotId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "snapshotId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "type",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "SnapshotBannerQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"kind": "InlineFragment",
"selections": [
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/)
],
"type": "Snapshot",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "SnapshotBannerQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/)
],
"type": "Snapshot",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "7e026c7c030cd116b4794260934c394f",
"id": null,
"metadata": {},
"name": "SnapshotBannerQuery",
"operationKind": "query",
"text": "query SnapshotBannerQuery(\n $snapshotId: ID!\n) {\n node(id: $snapshotId) {\n __typename\n ... on Snapshot {\n id\n name\n type\n createdAt\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "e50a4bb5133d8e918b8b2b9d2a42f1d1";
export default node;

View File

@@ -1,6 +1,19 @@
import { getAssetTypeVariant, promisifyMutation, sprintf } from "@probo/helpers";
import {
getAssetTypeVariant,
promisifyMutation,
sprintf,
} from "@probo/helpers";
import { useTranslate } from "@probo/i18n";
import { ActionDropdown, Badge, DropdownItem, IconPencil, IconTrashCan, SelectCell, TextCell, useConfirm } from "@probo/ui";
import {
ActionDropdown,
Badge,
DropdownItem,
IconPencil,
IconTrashCan,
SelectCell,
TextCell,
useConfirm,
} from "@probo/ui";
import { useMutation } from "react-relay";
import type { usePaginationFragmentHookType } from "react-relay/relay-hooks/usePaginationFragment";
import { Link } from "react-router";
@@ -8,9 +21,16 @@ import { z } from "zod";
import { EditableTable } from "../table/EditableTable";
import { PeopleCell } from "../table/PeopleCell";
import { VendorsCell } from "../table/VendorsCell";
import { createAssetMutation, deleteAssetMutation, updateAssetMutation } from "/hooks/graph/AssetGraph";
import type { AssetGraphDeleteMutation } from "/hooks/graph/__generated__/AssetGraphDeleteMutation.graphql";
import type { AssetsPageFragment$data, AssetsPageFragment$key } from "/pages/organizations/assets/__generated__/AssetsPageFragment.graphql";
import {
createAssetMutation,
deleteAssetMutation,
updateAssetMutation,
} from "/hooks/graph/AssetGraph";
import type { AssetGraphDeleteMutation } from "/__generated__/core/AssetGraphDeleteMutation.graphql";
import type {
AssetsPageFragment$data,
AssetsPageFragment$key,
} from "/__generated__/core/AssetsPageFragment.graphql";
import type { OperationType } from "relay-runtime";
import { useOrganizationId } from "/hooks/useOrganizationId";
@@ -73,7 +93,7 @@ export function AssetsTable(props: Props) {
...defaultValue,
organizationId,
}}
action={({ item }) =>
action={({ item }) => (
<ActionDropdown>
<DropdownItem asChild>
<Link to={`/organizations/${organizationId}/assets/${item.id}`}>
@@ -89,7 +109,7 @@ export function AssetsTable(props: Props) {
{__("Delete")}
</DropdownItem>
</ActionDropdown>
}
)}
row={({ item }) => (
<>
<TextCell name="name" defaultValue={item?.name ?? ""} required />
@@ -105,9 +125,7 @@ export function AssetsTable(props: Props) {
/>
<TextCell
name="dataTypesStored"
defaultValue={
item?.dataTypesStored ?? defaultValue.dataTypesStored
}
defaultValue={item?.dataTypesStored ?? defaultValue.dataTypesStored}
required
/>
<TextCell
@@ -123,9 +141,7 @@ export function AssetsTable(props: Props) {
<VendorsCell
name="vendorIds"
organizationId={organizationId}
defaultValue={
item?.vendors?.edges?.map((edge) => edge.node) ?? []
}
defaultValue={item?.vendors?.edges?.map((edge) => edge.node) ?? []}
/>
</>
)}
@@ -162,4 +178,4 @@ const useDeleteAsset = (connectionId: string) => {
},
);
};
};
};

View File

@@ -2,7 +2,10 @@ import { Avatar, Badge, Tbody, Td, Th, Thead, Tr } from "@probo/ui";
import { SortableTable } from "../SortableTable";
import { useTranslate } from "@probo/i18n";
import type { usePaginationFragmentHookType } from "react-relay/relay-hooks/usePaginationFragment";
import type { AssetsPageFragment$data, AssetsPageFragment$key } from "/pages/organizations/assets/__generated__/AssetsPageFragment.graphql";
import type {
AssetsPageFragment$data,
AssetsPageFragment$key,
} from "/__generated__/core/AssetsPageFragment.graphql";
import type { OperationType } from "relay-runtime";
import type { NodeOf } from "/types";
import { useOrganizationId } from "/hooks/useOrganizationId";
@@ -26,32 +29,25 @@ export function ReadOnlyAssetsTable(props: Props) {
return (
<SortableTable {...pagination} pageSize={10}>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
<Th>{__("Type")}</Th>
<Th>{__("Amount")}</Th>
<Th>{__("Owner")}</Th>
<Th>{__("Vendors")}</Th>
</Tr>
</Thead>
<Tbody>
{assets.map((entry) => (
<AssetRow
key={entry.id}
entry={entry}
/>
))}
</Tbody>
</SortableTable>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
<Th>{__("Type")}</Th>
<Th>{__("Amount")}</Th>
<Th>{__("Owner")}</Th>
<Th>{__("Vendors")}</Th>
</Tr>
</Thead>
<Tbody>
{assets.map((entry) => (
<AssetRow key={entry.id} entry={entry} />
))}
</Tbody>
</SortableTable>
);
}
function AssetRow({
entry,
}: {
entry: AssetEntry;
}) {
function AssetRow({ entry }: { entry: AssetEntry }) {
const organizationId = useOrganizationId();
const { __ } = useTranslate();
const { snapshotId } = useParams<{ snapshotId?: string }>();
@@ -60,8 +56,9 @@ function AssetRow({
return (
<Tr
to={
snapshotId ?
`/organizations/${organizationId}/snapshots/${snapshotId}/assets/${entry.id}` : `/organizations/${organizationId}/assets/${entry.id}`
snapshotId
? `/organizations/${organizationId}/snapshots/${snapshotId}/assets/${entry.id}`
: `/organizations/${organizationId}/assets/${entry.id}`
}
>
<Td>{entry.name}</Td>
@@ -101,4 +98,4 @@ function AssetRow({
</Td>
</Tr>
);
}
}

View File

@@ -15,7 +15,7 @@ import {
TrButton,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { LinkedAuditsCardFragment$key } from "./__generated__/LinkedAuditsCardFragment.graphql";
import type { LinkedAuditsCardFragment$key } from "/__generated__/core/LinkedAuditsCardFragment.graphql";
import { useFragment } from "react-relay";
import { useMemo, useState } from "react";
import { sprintf, getAuditStateVariant } from "@probo/helpers";
@@ -123,7 +123,10 @@ export function LinkedAuditsCard<Params>(props: Props<Params>) {
<Tbody>
{audits.length === 0 && (
<Tr>
<Td colSpan={props.readOnly ? 2 : 3} className="text-center text-txt-secondary">
<Td
colSpan={props.readOnly ? 2 : 3}
className="text-center text-txt-secondary"
>
{__("No audits linked")}
</Td>
</Tr>
@@ -177,13 +180,9 @@ function AuditRow(props: {
<Tr to={`/organizations/${organizationId}/audits/${audit.id}`}>
<Td>
<div className="flex flex-col">
<div className="font-medium">
{audit.framework?.name}
</div>
<div className="font-medium">{audit.framework?.name}</div>
{audit.name && (
<div className="text-sm text-txt-secondary">
{audit.name}
</div>
<div className="text-sm text-txt-secondary">{audit.name}</div>
)}
</div>
</Td>

View File

@@ -16,13 +16,13 @@ import { getAuditStateVariant } from "@probo/helpers";
import { Suspense, useMemo, useState, type ReactNode } from "react";
import { graphql } from "relay-runtime";
import { useLazyLoadQuery, usePaginationFragment } from "react-relay";
import type { LinkedAuditsDialogQuery } from "./__generated__/LinkedAuditsDialogQuery.graphql";
import type { LinkedAuditsDialogQuery } from "/__generated__/core/LinkedAuditsDialogQuery.graphql";
import { useOrganizationId } from "/hooks/useOrganizationId";
import type { NodeOf } from "/types";
import type {
LinkedAuditsDialogFragment$data,
LinkedAuditsDialogFragment$key,
} from "./__generated__/LinkedAuditsDialogFragment.graphql";
} from "/__generated__/core/LinkedAuditsDialogFragment.graphql";
const auditsQuery = graphql`
query LinkedAuditsDialogQuery($organizationId: ID!) {
@@ -53,17 +53,17 @@ const auditsFragment = graphql`
orderBy: $order
) @connection(key: "LinkedAuditsDialogQuery_audits") {
edges {
node {
id
name
state
validFrom
validUntil
framework {
id
name
}
}
node {
id
name
state
validFrom
validUntil
framework {
id
name
}
}
}
}
}
@@ -99,18 +99,21 @@ function LinkedAuditsDialogContent(props: Omit<Props, "children">) {
});
const { data, loadNext, hasNext, isLoadingNext } = usePaginationFragment(
auditsFragment,
query.organization as LinkedAuditsDialogFragment$key
query.organization as LinkedAuditsDialogFragment$key,
);
const { __ } = useTranslate();
const [search, setSearch] = useState("");
const audits = useMemo(() => data.audits?.edges?.map((edge) => edge.node) ?? [], [data.audits]);
const audits = useMemo(
() => data.audits?.edges?.map((edge) => edge.node) ?? [],
[data.audits],
);
const linkedIds = useMemo(() => {
return new Set(props.linkedAudits?.map((a) => a.id) ?? []);
}, [props.linkedAudits]);
const filteredAudits = useMemo(() => {
return audits.filter((audit) =>
(audit.name || "").toLowerCase().includes(search.toLowerCase())
(audit.name || "").toLowerCase().includes(search.toLowerCase()),
);
}, [audits, search]);
@@ -168,13 +171,9 @@ function AuditRow(props: RowProps) {
onClick={() => onClick(props.audit.id)}
>
<div className="flex flex-col items-start gap-1">
<div className="font-medium">
{props.audit.framework?.name}
</div>
<div className="font-medium">{props.audit.framework?.name}</div>
{props.audit.name && (
<div className="text-sm text-txt-secondary">
{props.audit.name}
</div>
<div className="text-sm text-txt-secondary">{props.audit.name}</div>
)}
</div>
<Badge color={getAuditStateVariant(props.audit.state)}>

View File

@@ -1,104 +0,0 @@
/**
* @generated SignedSource<<eb9ce92b73884420f07e71096665149f>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type AuditState = "COMPLETED" | "IN_PROGRESS" | "NOT_STARTED" | "OUTDATED" | "REJECTED";
import { FragmentRefs } from "relay-runtime";
export type LinkedAuditsCardFragment$data = {
readonly createdAt: any;
readonly framework: {
readonly id: string;
readonly name: string;
};
readonly id: string;
readonly name: string | null | undefined;
readonly state: AuditState;
readonly validFrom: any | null | undefined;
readonly validUntil: any | null | undefined;
readonly " $fragmentType": "LinkedAuditsCardFragment";
};
export type LinkedAuditsCardFragment$key = {
readonly " $data"?: LinkedAuditsCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedAuditsCardFragment">;
};
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "LinkedAuditsCardFragment",
"selections": [
(v0/*: any*/),
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validFrom",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validUntil",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v0/*: any*/),
(v1/*: any*/)
],
"storageKey": null
}
],
"type": "Audit",
"abstractKey": null
};
})();
(node as any).hash = "9ff9367a1f0668a8537bdd5bf5c7233d";
export default node;

View File

@@ -1,257 +0,0 @@
/**
* @generated SignedSource<<72efdb68c08c793ff724c9a16d91d29a>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type AuditState = "COMPLETED" | "IN_PROGRESS" | "NOT_STARTED" | "OUTDATED" | "REJECTED";
import { FragmentRefs } from "relay-runtime";
export type LinkedAuditsDialogFragment$data = {
readonly audits: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly framework: {
readonly id: string;
readonly name: string;
};
readonly id: string;
readonly name: string | null | undefined;
readonly state: AuditState;
readonly validFrom: any | null | undefined;
readonly validUntil: any | null | undefined;
};
}>;
};
readonly id: string;
readonly " $fragmentType": "LinkedAuditsDialogFragment";
};
export type LinkedAuditsDialogFragment$key = {
readonly " $data"?: LinkedAuditsDialogFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedAuditsDialogFragment">;
};
import LinkedAuditsDialogQuery_fragment_graphql from './LinkedAuditsDialogQuery_fragment.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"audits"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
{
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "bidirectional",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "first",
"cursor": "after"
},
"backward": {
"count": "last",
"cursor": "before"
},
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": LinkedAuditsDialogQuery_fragment_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "LinkedAuditsDialogFragment",
"selections": [
{
"alias": "audits",
"args": [
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
"concreteType": "AuditConnection",
"kind": "LinkedField",
"name": "__LinkedAuditsDialogQuery_audits_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "AuditEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validFrom",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validUntil",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v1/*: any*/),
(v2/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "Organization",
"abstractKey": null
};
})();
(node as any).hash = "d58fca9b4fb36a24ded1858b632f5acf";
export default node;

View File

@@ -1,273 +0,0 @@
/**
* @generated SignedSource<<1f9d92c4803d49c216fef6447a59c779>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type LinkedAuditsDialogQuery$variables = {
organizationId: string;
};
export type LinkedAuditsDialogQuery$data = {
readonly organization: {
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"LinkedAuditsDialogFragment">;
};
};
export type LinkedAuditsDialogQuery = {
response: LinkedAuditsDialogQuery$data;
variables: LinkedAuditsDialogQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = [
{
"kind": "Literal",
"name": "first",
"value": 20
}
],
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "LinkedAuditsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "LinkedAuditsDialogFragment"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "LinkedAuditsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": "AuditConnection",
"kind": "LinkedField",
"name": "audits",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "AuditEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validFrom",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validUntil",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v2/*: any*/),
(v5/*: any*/)
],
"storageKey": null
},
(v3/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "audits(first:20)"
},
{
"alias": null,
"args": (v4/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "LinkedAuditsDialogQuery_audits",
"kind": "LinkedHandle",
"name": "audits"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "0daa6dc9bebd2677cc0c36e819631f9c",
"id": null,
"metadata": {},
"name": "LinkedAuditsDialogQuery",
"operationKind": "query",
"text": "query LinkedAuditsDialogQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n ...LinkedAuditsDialogFragment\n }\n }\n}\n\nfragment LinkedAuditsDialogFragment on Organization {\n audits(first: 20) {\n edges {\n node {\n id\n name\n state\n validFrom\n validUntil\n framework {\n id\n name\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "a6f87b771862cc24fee101cc924a57b2";
export default node;

View File

@@ -1,346 +0,0 @@
/**
* @generated SignedSource<<64f01ce9caaee3040df3df201bb608f8>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type AuditOrderField = "CREATED_AT" | "STATE" | "VALID_FROM" | "VALID_UNTIL";
export type OrderDirection = "ASC" | "DESC";
export type AuditOrder = {
direction: OrderDirection;
field: AuditOrderField;
};
export type LinkedAuditsDialogQuery_fragment$variables = {
after?: any | null | undefined;
before?: any | null | undefined;
first?: number | null | undefined;
id: string;
last?: number | null | undefined;
order?: AuditOrder | null | undefined;
};
export type LinkedAuditsDialogQuery_fragment$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"LinkedAuditsDialogFragment">;
};
};
export type LinkedAuditsDialogQuery_fragment = {
response: LinkedAuditsDialogQuery_fragment$data;
variables: LinkedAuditsDialogQuery_fragment$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
v2 = {
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
v3 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
},
v4 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
v5 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
},
v6 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v7 = {
"kind": "Variable",
"name": "after",
"variableName": "after"
},
v8 = {
"kind": "Variable",
"name": "before",
"variableName": "before"
},
v9 = {
"kind": "Variable",
"name": "first",
"variableName": "first"
},
v10 = {
"kind": "Variable",
"name": "last",
"variableName": "last"
},
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v13 = [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
v14 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "LinkedAuditsDialogQuery_fragment",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "order",
"variableName": "order"
}
],
"kind": "FragmentSpread",
"name": "LinkedAuditsDialogFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v3/*: any*/)
],
"kind": "Operation",
"name": "LinkedAuditsDialogQuery_fragment",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v11/*: any*/),
(v12/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v13/*: any*/),
"concreteType": "AuditConnection",
"kind": "LinkedField",
"name": "audits",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "AuditEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v12/*: any*/),
(v14/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validFrom",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validUntil",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v12/*: any*/),
(v14/*: any*/)
],
"storageKey": null
},
(v11/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": (v13/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "LinkedAuditsDialogQuery_audits",
"kind": "LinkedHandle",
"name": "audits"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "26f1cad4cab5157a2d9e10d4b89114ec",
"id": null,
"metadata": {},
"name": "LinkedAuditsDialogQuery_fragment",
"operationKind": "query",
"text": "query LinkedAuditsDialogQuery_fragment(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: AuditOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...LinkedAuditsDialogFragment_16fISc\n id\n }\n}\n\nfragment LinkedAuditsDialogFragment_16fISc on Organization {\n audits(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n name\n state\n validFrom\n validUntil\n framework {\n id\n name\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "d58fca9b4fb36a24ded1858b632f5acf";
export default node;

View File

@@ -11,7 +11,7 @@ import {
TrButton,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { LinkedControlsCardFragment$key } from "./__generated__/LinkedControlsCardFragment.graphql";
import type { LinkedControlsCardFragment$key } from "/__generated__/core/LinkedControlsCardFragment.graphql";
import { useFragment } from "react-relay";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { LinkedControlsDialog } from "./LinkedControlsDialog";
@@ -103,7 +103,10 @@ export function LinkedControlsCard<Params>(props: Props<Params>) {
<Tbody>
{controls.length === 0 && (
<Tr>
<Td colSpan={props.readOnly ? 2 : 3} className="text-center text-txt-secondary">
<Td
colSpan={props.readOnly ? 2 : 3}
className="text-center text-txt-secondary"
>
{__("No controls linked")}
</Td>
</Tr>

View File

@@ -22,11 +22,11 @@ import { useTranslate } from "@probo/i18n";
import { graphql } from "relay-runtime";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { useLazyLoadQuery, usePaginationFragment } from "react-relay";
import type { LinkedControlsDialogQuery } from "./__generated__/LinkedControlsDialogQuery.graphql";
import type { LinkedControlsDialogQuery } from "/__generated__/core/LinkedControlsDialogQuery.graphql";
import type {
LinkedControlsDialogFragment$data,
LinkedControlsDialogFragment$key,
} from "./__generated__/LinkedControlsDialogFragment.graphql";
} from "/__generated__/core/LinkedControlsDialogFragment.graphql";
import type { NodeOf } from "/types";
import { useDebounceCallback } from "usehooks-ts";
@@ -126,7 +126,7 @@ function LinkedControlsDialogContent(props: Props & { ref: SearchRef }) {
const { data, loadNext, hasNext, isLoadingNext, refetch } =
usePaginationFragment(
controlsFragment,
mainData.organization as LinkedControlsDialogFragment$key
mainData.organization as LinkedControlsDialogFragment$key,
);
const controls = data.controls?.edges?.map((edge) => edge.node) ?? [];
@@ -171,7 +171,7 @@ function ControlRow(
props: {
control: NodeOf<LinkedControlsDialogFragment$data["controls"]>;
controlIds: Set<string>;
} & Props
} & Props,
) {
const { __ } = useTranslate();
const isLinked = props.controlIds.has(props.control.id);

View File

@@ -1,79 +0,0 @@
/**
* @generated SignedSource<<780834b432440afd9363100bb20f2529>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type LinkedControlsCardFragment$data = {
readonly framework: {
readonly id: string;
readonly name: string;
};
readonly id: string;
readonly name: string;
readonly sectionTitle: string;
readonly " $fragmentType": "LinkedControlsCardFragment";
};
export type LinkedControlsCardFragment$key = {
readonly " $data"?: LinkedControlsCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedControlsCardFragment">;
};
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "LinkedControlsCardFragment",
"selections": [
(v0/*: any*/),
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "sectionTitle",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v0/*: any*/),
(v1/*: any*/)
],
"storageKey": null
}
],
"type": "Control",
"abstractKey": null
};
})();
(node as any).hash = "741820c65c4317cac48693023c3f9bcc";
export default node;

View File

@@ -1,351 +0,0 @@
/**
* @generated SignedSource<<68d29ea810c69f34b0da8d3e66b4eb5e>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ControlOrderField = "CREATED_AT" | "SECTION_TITLE";
export type OrderDirection = "ASC" | "DESC";
export type ControlFilter = {
query?: string | null | undefined;
};
export type ControlOrder = {
direction: OrderDirection;
field: ControlOrderField;
};
export type LinkedControlsDialogControlsQuery$variables = {
after?: any | null | undefined;
before?: any | null | undefined;
filter?: ControlFilter | null | undefined;
first?: number | null | undefined;
id: string;
last?: number | null | undefined;
order?: ControlOrder | null | undefined;
};
export type LinkedControlsDialogControlsQuery$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"LinkedControlsDialogFragment">;
};
};
export type LinkedControlsDialogControlsQuery = {
response: LinkedControlsDialogControlsQuery$data;
variables: LinkedControlsDialogControlsQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
v2 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "filter"
},
v3 = {
"defaultValue": 1,
"kind": "LocalArgument",
"name": "first"
},
v4 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
},
v5 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
v6 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
},
v7 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v8 = {
"kind": "Variable",
"name": "after",
"variableName": "after"
},
v9 = {
"kind": "Variable",
"name": "before",
"variableName": "before"
},
v10 = {
"kind": "Variable",
"name": "filter",
"variableName": "filter"
},
v11 = {
"kind": "Variable",
"name": "first",
"variableName": "first"
},
v12 = {
"kind": "Variable",
"name": "last",
"variableName": "last"
},
v13 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v14 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v15 = [
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v11/*: any*/),
(v12/*: any*/),
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
v16 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "LinkedControlsDialogControlsQuery",
"selections": [
{
"alias": null,
"args": (v7/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": [
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v11/*: any*/),
(v12/*: any*/),
{
"kind": "Variable",
"name": "order",
"variableName": "order"
}
],
"kind": "FragmentSpread",
"name": "LinkedControlsDialogFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v5/*: any*/),
(v6/*: any*/),
(v4/*: any*/)
],
"kind": "Operation",
"name": "LinkedControlsDialogControlsQuery",
"selections": [
{
"alias": null,
"args": (v7/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v13/*: any*/),
(v14/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v15/*: any*/),
"concreteType": "ControlConnection",
"kind": "LinkedField",
"name": "controls",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ControlEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Control",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v14/*: any*/),
(v16/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "sectionTitle",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v16/*: any*/),
(v14/*: any*/)
],
"storageKey": null
},
(v13/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": (v15/*: any*/),
"filters": [
"orderBy",
"filter"
],
"handle": "connection",
"key": "LinkedControlsDialogControlsQuery_controls",
"kind": "LinkedHandle",
"name": "controls"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "e9bcdc36129e6a05c59f344433459b66",
"id": null,
"metadata": {},
"name": "LinkedControlsDialogControlsQuery",
"operationKind": "query",
"text": "query LinkedControlsDialogControlsQuery(\n $after: CursorKey\n $before: CursorKey = null\n $filter: ControlFilter = null\n $first: Int = 1\n $last: Int = null\n $order: ControlOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...LinkedControlsDialogFragment_4cFWzS\n id\n }\n}\n\nfragment LinkedControlsDialogFragment_4cFWzS on Organization {\n controls(first: $first, after: $after, last: $last, before: $before, orderBy: $order, filter: $filter) {\n edges {\n node {\n id\n name\n sectionTitle\n framework {\n name\n id\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "9fc0bfbfc461d56748750b180bc232fc";
export default node;

View File

@@ -1,248 +0,0 @@
/**
* @generated SignedSource<<06b39b49e82019064bd42a03c903fd93>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type LinkedControlsDialogFragment$data = {
readonly controls: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly framework: {
readonly name: string;
};
readonly id: string;
readonly name: string;
readonly sectionTitle: string;
};
}>;
};
readonly id: string;
readonly " $fragmentType": "LinkedControlsDialogFragment";
};
export type LinkedControlsDialogFragment$key = {
readonly " $data"?: LinkedControlsDialogFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedControlsDialogFragment">;
};
import LinkedControlsDialogControlsQuery_graphql from './LinkedControlsDialogControlsQuery.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"controls"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "filter"
},
{
"defaultValue": 1,
"kind": "LocalArgument",
"name": "first"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "bidirectional",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "first",
"cursor": "after"
},
"backward": {
"count": "last",
"cursor": "before"
},
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": LinkedControlsDialogControlsQuery_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "LinkedControlsDialogFragment",
"selections": [
{
"alias": "controls",
"args": [
{
"kind": "Variable",
"name": "filter",
"variableName": "filter"
},
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
"concreteType": "ControlConnection",
"kind": "LinkedField",
"name": "__LinkedControlsDialogControlsQuery_controls_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ControlEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Control",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "sectionTitle",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v2/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "Organization",
"abstractKey": null
};
})();
(node as any).hash = "9fc0bfbfc461d56748750b180bc232fc";
export default node;

View File

@@ -1,253 +0,0 @@
/**
* @generated SignedSource<<f8a28e26c1260135c13f22f9d35019c2>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type LinkedControlsDialogQuery$variables = {
organizationId: string;
};
export type LinkedControlsDialogQuery$data = {
readonly organization: {
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"LinkedControlsDialogFragment">;
};
};
export type LinkedControlsDialogQuery = {
response: LinkedControlsDialogQuery$data;
variables: LinkedControlsDialogQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = [
{
"kind": "Literal",
"name": "first",
"value": 1
}
],
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "LinkedControlsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "LinkedControlsDialogFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "LinkedControlsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": "ControlConnection",
"kind": "LinkedField",
"name": "controls",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ControlEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Control",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "sectionTitle",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v5/*: any*/),
(v2/*: any*/)
],
"storageKey": null
},
(v3/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "controls(first:1)"
},
{
"alias": null,
"args": (v4/*: any*/),
"filters": [
"orderBy",
"filter"
],
"handle": "connection",
"key": "LinkedControlsDialogControlsQuery_controls",
"kind": "LinkedHandle",
"name": "controls"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "a36d424a3b8a087dbb40149bdbc2b6a2",
"id": null,
"metadata": {},
"name": "LinkedControlsDialogQuery",
"operationKind": "query",
"text": "query LinkedControlsDialogQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ...LinkedControlsDialogFragment\n }\n}\n\nfragment LinkedControlsDialogFragment on Organization {\n controls(first: 1) {\n edges {\n node {\n id\n name\n sectionTitle\n framework {\n name\n id\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "1be60a2dc1efbd8992472862ca32910e";
export default node;

View File

@@ -16,7 +16,7 @@ import {
TrButton,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { LinkedDocumentsCardFragment$key } from "./__generated__/LinkedDocumentsCardFragment.graphql";
import type { LinkedDocumentsCardFragment$key } from "/__generated__/core/LinkedDocumentsCardFragment.graphql";
import { useFragment } from "react-relay";
import { useMemo, useState } from "react";
import { sprintf } from "@probo/helpers";
@@ -137,7 +137,10 @@ export function LinkedDocumentsCard<Params>(props: Props<Params>) {
<Tbody>
{documents.length === 0 && (
<Tr>
<Td colSpan={props.readOnly ? 3 : 4} className="text-center text-txt-secondary">
<Td
colSpan={props.readOnly ? 3 : 4}
className="text-center text-txt-secondary"
>
{__("No documents linked")}
</Td>
</Tr>

View File

@@ -15,13 +15,13 @@ import { useTranslate } from "@probo/i18n";
import { Suspense, useMemo, useState, type ReactNode } from "react";
import { graphql } from "relay-runtime";
import { useLazyLoadQuery, usePaginationFragment } from "react-relay";
import type { LinkedDocumentsDialogQuery } from "./__generated__/LinkedDocumentsDialogQuery.graphql";
import type { LinkedDocumentsDialogQuery } from "/__generated__/core/LinkedDocumentsDialogQuery.graphql";
import { useOrganizationId } from "/hooks/useOrganizationId";
import type { NodeOf } from "/types";
import type {
LinkedDocumentsDialogFragment$data,
LinkedDocumentsDialogFragment$key,
} from "./__generated__/LinkedDocumentsDialogFragment.graphql";
} from "/__generated__/core/LinkedDocumentsDialogFragment.graphql";
const documentsQuery = graphql`
query LinkedDocumentsDialogQuery($organizationId: ID!) {
@@ -88,23 +88,30 @@ export function LinkedDocumentDialog({ children, ...props }: Props) {
function LinkedDocumentsDialogContent(props: Omit<Props, "children">) {
const organizationId = useOrganizationId();
const query = useLazyLoadQuery<LinkedDocumentsDialogQuery>(documentsQuery, {
organizationId,
}, { fetchPolicy: "network-only" });
const query = useLazyLoadQuery<LinkedDocumentsDialogQuery>(
documentsQuery,
{
organizationId,
},
{ fetchPolicy: "network-only" },
);
const { data, loadNext, hasNext, isLoadingNext } = usePaginationFragment(
documentsFragment,
query.organization as LinkedDocumentsDialogFragment$key
query.organization as LinkedDocumentsDialogFragment$key,
);
const { __ } = useTranslate();
const [search, setSearch] = useState("");
const documents = useMemo(() => data.documents?.edges?.map((edge) => edge.node) ?? [], [data.documents]);
const documents = useMemo(
() => data.documents?.edges?.map((edge) => edge.node) ?? [],
[data.documents],
);
const linkedIds = useMemo(() => {
return new Set(props.linkedDocuments?.map((m) => m.id) ?? []);
}, [props.linkedDocuments]);
const filteredDocuments = useMemo(() => {
return documents.filter((document) =>
document.title.toLowerCase().includes(search.toLowerCase())
document.title.toLowerCase().includes(search.toLowerCase()),
);
}, [documents, search]);

View File

@@ -1,126 +0,0 @@
/**
* @generated SignedSource<<0f8cdaa2d7380a1128e7c42004b7d506>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type DocumentStatus = "DRAFT" | "PUBLISHED";
export type DocumentType = "ISMS" | "OTHER" | "POLICY" | "PROCEDURE";
import { FragmentRefs } from "relay-runtime";
export type LinkedDocumentsCardFragment$data = {
readonly createdAt: any;
readonly documentType: DocumentType;
readonly id: string;
readonly title: string;
readonly versions: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly status: DocumentStatus;
};
}>;
};
readonly " $fragmentType": "LinkedDocumentsCardFragment";
};
export type LinkedDocumentsCardFragment$key = {
readonly " $data"?: LinkedDocumentsCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedDocumentsCardFragment">;
};
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "LinkedDocumentsCardFragment",
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
},
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 1
}
],
"concreteType": "DocumentVersionConnection",
"kind": "LinkedField",
"name": "versions",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "versions(first:1)"
}
],
"type": "Document",
"abstractKey": null
};
})();
(node as any).hash = "952e653849ce0b1b693de8d7e3086e3f";
export default node;

View File

@@ -1,223 +0,0 @@
/**
* @generated SignedSource<<096eea04ea39ac931b8627aee0ebb26c>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type DocumentType = "ISMS" | "OTHER" | "POLICY" | "PROCEDURE";
import { FragmentRefs } from "relay-runtime";
export type LinkedDocumentsDialogFragment$data = {
readonly documents: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly documentType: DocumentType;
readonly id: string;
readonly title: string;
};
}>;
};
readonly id: string;
readonly " $fragmentType": "LinkedDocumentsDialogFragment";
};
export type LinkedDocumentsDialogFragment$key = {
readonly " $data"?: LinkedDocumentsDialogFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedDocumentsDialogFragment">;
};
import LinkedDocumentsDialogQuery_fragment_graphql from './LinkedDocumentsDialogQuery_fragment.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"documents"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
{
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "bidirectional",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "first",
"cursor": "after"
},
"backward": {
"count": "last",
"cursor": "before"
},
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": LinkedDocumentsDialogQuery_fragment_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "LinkedDocumentsDialogFragment",
"selections": [
{
"alias": "documents",
"args": [
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "__LinkedDocumentsDialogQuery_documents_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "Organization",
"abstractKey": null
};
})();
(node as any).hash = "392d33b379a58cb3da08ab783c1cda5d";
export default node;

View File

@@ -1,245 +0,0 @@
/**
* @generated SignedSource<<6316cd819a27efb5989750b5f8de0444>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type LinkedDocumentsDialogQuery$variables = {
organizationId: string;
};
export type LinkedDocumentsDialogQuery$data = {
readonly organization: {
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"LinkedDocumentsDialogFragment">;
};
};
export type LinkedDocumentsDialogQuery = {
response: LinkedDocumentsDialogQuery$data;
variables: LinkedDocumentsDialogQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = [
{
"kind": "Literal",
"name": "first",
"value": 20
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "LinkedDocumentsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "LinkedDocumentsDialogFragment"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "LinkedDocumentsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "documents",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
},
(v3/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documents(first:20)"
},
{
"alias": null,
"args": (v4/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "LinkedDocumentsDialogQuery_documents",
"kind": "LinkedHandle",
"name": "documents"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "fd4ab41131ead5f74dceb4610ef3f2c5",
"id": null,
"metadata": {},
"name": "LinkedDocumentsDialogQuery",
"operationKind": "query",
"text": "query LinkedDocumentsDialogQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n ...LinkedDocumentsDialogFragment\n }\n }\n}\n\nfragment LinkedDocumentsDialogFragment on Organization {\n documents(first: 20) {\n edges {\n node {\n id\n title\n documentType\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "f97a3016285b1a39cc6925ac39d82acc";
export default node;

View File

@@ -1,318 +0,0 @@
/**
* @generated SignedSource<<25880ab79f8b6ae18f3ead4431a90329>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type DocumentOrderField = "CREATED_AT" | "DOCUMENT_TYPE" | "TITLE";
export type OrderDirection = "ASC" | "DESC";
export type DocumentOrder = {
direction: OrderDirection;
field: DocumentOrderField;
};
export type LinkedDocumentsDialogQuery_fragment$variables = {
after?: any | null | undefined;
before?: any | null | undefined;
first?: number | null | undefined;
id: string;
last?: number | null | undefined;
order?: DocumentOrder | null | undefined;
};
export type LinkedDocumentsDialogQuery_fragment$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"LinkedDocumentsDialogFragment">;
};
};
export type LinkedDocumentsDialogQuery_fragment = {
response: LinkedDocumentsDialogQuery_fragment$data;
variables: LinkedDocumentsDialogQuery_fragment$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
v2 = {
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
v3 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
},
v4 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
v5 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
},
v6 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v7 = {
"kind": "Variable",
"name": "after",
"variableName": "after"
},
v8 = {
"kind": "Variable",
"name": "before",
"variableName": "before"
},
v9 = {
"kind": "Variable",
"name": "first",
"variableName": "first"
},
v10 = {
"kind": "Variable",
"name": "last",
"variableName": "last"
},
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v13 = [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
];
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "LinkedDocumentsDialogQuery_fragment",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "order",
"variableName": "order"
}
],
"kind": "FragmentSpread",
"name": "LinkedDocumentsDialogFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v3/*: any*/)
],
"kind": "Operation",
"name": "LinkedDocumentsDialogQuery_fragment",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v11/*: any*/),
(v12/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v13/*: any*/),
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "documents",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v12/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
},
(v11/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": (v13/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "LinkedDocumentsDialogQuery_documents",
"kind": "LinkedHandle",
"name": "documents"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "e72639ede26aa4300b69ba3181de482b",
"id": null,
"metadata": {},
"name": "LinkedDocumentsDialogQuery_fragment",
"operationKind": "query",
"text": "query LinkedDocumentsDialogQuery_fragment(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: DocumentOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...LinkedDocumentsDialogFragment_16fISc\n id\n }\n}\n\nfragment LinkedDocumentsDialogFragment_16fISc on Organization {\n documents(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n title\n documentType\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "392d33b379a58cb3da08ab783c1cda5d";
export default node;

View File

@@ -1,10 +1,15 @@
import { Field, Option, Select, Badge } from "@probo/ui";
import { Suspense, type ComponentProps } from "react";
import { useTranslate } from "@probo/i18n";
import { type Control, Controller, type FieldValues, type Path } from "react-hook-form";
import {
type Control,
Controller,
type FieldValues,
type Path,
} from "react-hook-form";
import { useLazyLoadQuery, graphql } from "react-relay";
import { getAuditStateVariant, getAuditStateLabel } from "@probo/helpers";
import type { AuditSelectFieldQuery } from "./__generated__/AuditSelectFieldQuery.graphql";
import type { AuditSelectFieldQuery } from "/__generated__/core/AuditSelectFieldQuery.graphql";
const auditsQuery = graphql`
query AuditSelectFieldQuery($organizationId: ID!) {
@@ -60,12 +65,19 @@ export function AuditSelectField<T extends FieldValues = FieldValues>({
}
function AuditSelectWithQuery<T extends FieldValues = FieldValues>(
props: Pick<Props<T>, "organizationId" | "control" | "name" | "disabled">
props: Pick<Props<T>, "organizationId" | "control" | "name" | "disabled">,
) {
const { __ } = useTranslate();
const { name, organizationId, control } = props;
const data = useLazyLoadQuery<AuditSelectFieldQuery>(auditsQuery, { organizationId }, { fetchPolicy: "network-only" });
const audits = data?.organization?.audits?.edges?.map((edge) => edge.node).filter((node) => node !== null) ?? [];
const data = useLazyLoadQuery<AuditSelectFieldQuery>(
auditsQuery,
{ organizationId },
{ fetchPolicy: "network-only" },
);
const audits =
data?.organization?.audits?.edges
?.map((edge) => edge.node)
.filter((node) => node !== null) ?? [];
const NONE_VALUE = "__NONE__";
@@ -79,7 +91,9 @@ function AuditSelectWithQuery<T extends FieldValues = FieldValues>(
id={name}
variant="editor"
placeholder={__("Select an audit")}
onValueChange={(value) => field.onChange(value === NONE_VALUE ? "" : value)}
onValueChange={(value) =>
field.onChange(value === NONE_VALUE ? "" : value)
}
key={audits?.length.toString() ?? "0"}
{...field}
className="w-full"
@@ -94,8 +108,7 @@ function AuditSelectWithQuery<T extends FieldValues = FieldValues>(
<span>
{audit.name
? `${audit.framework.name} - ${audit.name}`
: audit.framework.name
}
: audit.framework.name}
</span>
<div className="ml-3">
<Badge variant={getAuditStateVariant(audit.state)}>

View File

@@ -5,7 +5,7 @@ import type {
ProcessingActivityLawfulBasis,
ProcessingActivityDataProtectionImpactAssessment,
ProcessingActivityTransferImpactAssessment,
} from "../../hooks/graph/__generated__/ProcessingActivityGraphCreateMutation.graphql";
} from "/__generated__/core/ProcessingActivityGraphCreateMutation.graphql";
export function SpecialOrCriminalDataOptions() {
const { __ } = useTranslate();
@@ -58,7 +58,7 @@ export function LawfulBasisOptions() {
export function getLawfulBasisLabel(
value: ProcessingActivityLawfulBasis | null | undefined,
__: (key: string) => string
__: (key: string) => string,
): string {
if (!value) return "-";
@@ -76,7 +76,7 @@ export function getLawfulBasisLabel(
export function getResidualRiskLabel(
value: "LOW" | "MEDIUM" | "HIGH" | null | undefined,
__: (key: string) => string
__: (key: string) => string,
): string {
if (!value) return "-";

View File

@@ -1,215 +0,0 @@
/**
* @generated SignedSource<<21026731cd2ebaf80c8c2e251b9a57f8>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type AuditState = "COMPLETED" | "IN_PROGRESS" | "NOT_STARTED" | "OUTDATED" | "REJECTED";
export type AuditSelectFieldQuery$variables = {
organizationId: string;
};
export type AuditSelectFieldQuery$data = {
readonly organization: {
readonly audits?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly framework: {
readonly id: string;
readonly name: string;
};
readonly id: string;
readonly name: string | null | undefined;
readonly state: AuditState;
readonly validFrom: any | null | undefined;
readonly validUntil: any | null | undefined;
};
}>;
};
};
};
export type AuditSelectFieldQuery = {
response: AuditSelectFieldQuery$data;
variables: AuditSelectFieldQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v4 = {
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 100
}
],
"concreteType": "AuditConnection",
"kind": "LinkedField",
"name": "audits",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "AuditEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validFrom",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validUntil",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "audits(first:100)"
}
],
"type": "Organization",
"abstractKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "AuditSelectFieldQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/)
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "AuditSelectFieldQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v4/*: any*/),
(v2/*: any*/)
],
"storageKey": null
}
]
},
"params": {
"cacheID": "339c5438bb684c44887cc9cb53fb2c6a",
"id": null,
"metadata": {},
"name": "AuditSelectFieldQuery",
"operationKind": "query",
"text": "query AuditSelectFieldQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n audits(first: 100) {\n edges {\n node {\n id\n name\n framework {\n id\n name\n }\n state\n validFrom\n validUntil\n }\n }\n }\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "2bde1a04326144fe1b133672870807eb";
export default node;

View File

@@ -1,197 +0,0 @@
/**
* @generated SignedSource<<760a4c9ef58d487ab996d36a6cf1aa21>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type StateOfApplicabilityControlsFieldFrameworkControlsQuery$variables = {
frameworkId: string;
};
export type StateOfApplicabilityControlsFieldFrameworkControlsQuery$data = {
readonly framework: {
readonly controls?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly name: string;
readonly sectionTitle: string;
};
}>;
};
readonly id?: string;
};
};
export type StateOfApplicabilityControlsFieldFrameworkControlsQuery = {
response: StateOfApplicabilityControlsFieldFrameworkControlsQuery$data;
variables: StateOfApplicabilityControlsFieldFrameworkControlsQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "frameworkId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "frameworkId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 500
},
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "ASC",
"field": "SECTION_TITLE"
}
}
],
"concreteType": "ControlConnection",
"kind": "LinkedField",
"name": "controls",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ControlEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Control",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "sectionTitle",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "controls(first:500,orderBy:{\"direction\":\"ASC\",\"field\":\"SECTION_TITLE\"})"
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "StateOfApplicabilityControlsFieldFrameworkControlsQuery",
"selections": [
{
"alias": "framework",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"kind": "InlineFragment",
"selections": [
(v2/*: any*/),
(v3/*: any*/)
],
"type": "Framework",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "StateOfApplicabilityControlsFieldFrameworkControlsQuery",
"selections": [
{
"alias": "framework",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
(v3/*: any*/)
],
"type": "Framework",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "4e57853f9452f6167ef9dd2521f0b998",
"id": null,
"metadata": {},
"name": "StateOfApplicabilityControlsFieldFrameworkControlsQuery",
"operationKind": "query",
"text": "query StateOfApplicabilityControlsFieldFrameworkControlsQuery(\n $frameworkId: ID!\n) {\n framework: node(id: $frameworkId) {\n __typename\n ... on Framework {\n id\n controls(first: 500, orderBy: {field: SECTION_TITLE, direction: ASC}) {\n edges {\n node {\n id\n sectionTitle\n name\n }\n }\n }\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "2817a6951ce5ad1efdee9951636916ff";
export default node;

View File

@@ -1,172 +0,0 @@
/**
* @generated SignedSource<<09147ad036a4ae9295cd5fc5242f6ee7>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type StateOfApplicabilityControlsFieldFrameworksQuery$variables = {
organizationId: string;
};
export type StateOfApplicabilityControlsFieldFrameworksQuery$data = {
readonly organization: {
readonly frameworks?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly name: string;
};
}>;
};
};
};
export type StateOfApplicabilityControlsFieldFrameworksQuery = {
response: StateOfApplicabilityControlsFieldFrameworksQuery$data;
variables: StateOfApplicabilityControlsFieldFrameworksQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 100
}
],
"concreteType": "FrameworkConnection",
"kind": "LinkedField",
"name": "frameworks",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "FrameworkEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "frameworks(first:100)"
}
],
"type": "Organization",
"abstractKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "StateOfApplicabilityControlsFieldFrameworksQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/)
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "StateOfApplicabilityControlsFieldFrameworksQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v3/*: any*/),
(v2/*: any*/)
],
"storageKey": null
}
]
},
"params": {
"cacheID": "88fe75a1aeca2c9971693ed79bf82afe",
"id": null,
"metadata": {},
"name": "StateOfApplicabilityControlsFieldFrameworksQuery",
"operationKind": "query",
"text": "query StateOfApplicabilityControlsFieldFrameworksQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n frameworks(first: 100) {\n edges {\n node {\n id\n name\n }\n }\n }\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "5a0adc0c46445f40980fdb8edb8122ce";
export default node;

View File

@@ -10,13 +10,12 @@ import {
Tbody,
Th,
IconChevronDown,
IconTrashCan,
TrButton,
} from "@probo/ui";
import { MeasureBadge } from "@probo/ui/src/Molecules/Badge/MeasureBadge";
import { useTranslate } from "@probo/i18n";
import type { LinkedMeasuresCardFragment$key } from "./__generated__/LinkedMeasuresCardFragment.graphql";
import type { LinkedMeasuresCardFragment$key } from "/__generated__/core/LinkedMeasuresCardFragment.graphql";
import { useFragment } from "react-relay";
import { useMemo, useState } from "react";
import { sprintf } from "@probo/helpers";
@@ -64,7 +63,7 @@ type Props<Params> = {
export function LinkedMeasuresCard<Params>(props: Props<Params>) {
const { __ } = useTranslate();
const [limit, setLimit] = useState<number | null>(
props.variant === "card" ? 4 : null
props.variant === "card" ? 4 : null,
);
const measures = useMemo(() => {
return limit ? props.measures.slice(0, limit) : props.measures;
@@ -129,13 +128,21 @@ export function LinkedMeasuresCard<Params>(props: Props<Params>) {
<Tbody>
{measures.length === 0 && (
<Tr>
<Td colSpan={props.readOnly ? 2 : 3} className="text-center text-txt-secondary">
<Td
colSpan={props.readOnly ? 2 : 3}
className="text-center text-txt-secondary"
>
{__("No measures linked")}
</Td>
</Tr>
)}
{measures.map((measure) => (
<MeasureRow key={measure.id} measure={measure} onClick={onDetach} readOnly={props.readOnly} />
<MeasureRow
key={measure.id}
measure={measure}
onClick={onDetach}
readOnly={props.readOnly}
/>
))}
{variant === "table" && !props.readOnly && (
<LinkedMeasureDialog

View File

@@ -1,59 +0,0 @@
/**
* @generated SignedSource<<b7482b43ce0f4dfab470c35e806acf50>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED";
import { FragmentRefs } from "relay-runtime";
export type LinkedMeasuresCardFragment$data = {
readonly id: string;
readonly name: string;
readonly state: MeasureState;
readonly " $fragmentType": "LinkedMeasuresCardFragment";
};
export type LinkedMeasuresCardFragment$key = {
readonly " $data"?: LinkedMeasuresCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedMeasuresCardFragment">;
};
const node: ReaderFragment = {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "LinkedMeasuresCardFragment",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
}
],
"type": "Measure",
"abstractKey": null
};
(node as any).hash = "741a216c02732c1ff97b265ac8dbf39b";
export default node;

View File

@@ -15,10 +15,14 @@ import {
Badge,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { LinkedObligationsCardFragment$key } from "./__generated__/LinkedObligationsCardFragment.graphql";
import type { LinkedObligationsCardFragment$key } from "/__generated__/core/LinkedObligationsCardFragment.graphql";
import { useFragment } from "react-relay";
import { useMemo, useState } from "react";
import { sprintf, getObligationStatusVariant, getObligationStatusLabel } from "@probo/helpers";
import {
sprintf,
getObligationStatusVariant,
getObligationStatusLabel,
} from "@probo/helpers";
import { LinkedObligationDialog } from "./LinkedObligationsDialog";
import clsx from "clsx";
import { useParams } from "react-router";
@@ -62,7 +66,7 @@ type Props<Params> = {
export function LinkedObligationsCard<Params>(props: Props<Params>) {
const { __ } = useTranslate();
const [limit, setLimit] = useState<number | null>(
props.variant === "card" ? 4 : null
props.variant === "card" ? 4 : null,
);
const onAttach = (obligationId: string) => {
@@ -131,13 +135,21 @@ export function LinkedObligationsCard<Params>(props: Props<Params>) {
<Tbody>
{obligations.length === 0 && (
<Tr>
<Td colSpan={props.readOnly ? 4 : 5} className="text-center text-txt-secondary">
<Td
colSpan={props.readOnly ? 4 : 5}
className="text-center text-txt-secondary"
>
{__("No obligations linked")}
</Td>
</Tr>
)}
{obligations.map((obligation) => (
<ObligationRow key={obligation.id} obligation={obligation} onClick={onDetach} readOnly={props.readOnly} />
<ObligationRow
key={obligation.id}
obligation={obligation}
onClick={onDetach}
readOnly={props.readOnly}
/>
))}
{variant === "table" && !props.readOnly && (
<LinkedObligationDialog
@@ -189,27 +201,17 @@ function ObligationRow(props: {
return (
<Tr to={detailsUrl}>
<Td>
{obligation.area || __("No area specified")}
</Td>
<Td>
{obligation.source || __("No source specified")}
</Td>
<Td>{obligation.area || __("No area specified")}</Td>
<Td>{obligation.source || __("No source specified")}</Td>
<Td>
<Badge variant={getObligationStatusVariant(obligation.status)}>
{getObligationStatusLabel(obligation.status)}
</Badge>
</Td>
<Td>
{obligation.owner?.fullName || __("Unassigned")}
</Td>
<Td>{obligation.owner?.fullName || __("Unassigned")}</Td>
{!props.readOnly && (
<Td noLink width={50} className="text-end">
<Button
variant="secondary"
icon={IconTrashCan}
onClick={onDetach}
>
<Button variant="secondary" icon={IconTrashCan} onClick={onDetach}>
{__("Unlink")}
</Button>
</Td>

View File

@@ -12,17 +12,20 @@ import {
Badge,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { getObligationStatusVariant, getObligationStatusLabel } from "@probo/helpers";
import {
getObligationStatusVariant,
getObligationStatusLabel,
} from "@probo/helpers";
import { Suspense, useMemo, useState, type ReactNode } from "react";
import { graphql } from "relay-runtime";
import { useLazyLoadQuery, usePaginationFragment } from "react-relay";
import type { LinkedObligationsDialogQuery } from "./__generated__/LinkedObligationsDialogQuery.graphql";
import type { LinkedObligationsDialogQuery } from "/__generated__/core/LinkedObligationsDialogQuery.graphql";
import { useOrganizationId } from "/hooks/useOrganizationId";
import type { NodeOf } from "/types";
import type {
LinkedObligationsDialogFragment$data,
LinkedObligationsDialogFragment$key,
} from "./__generated__/LinkedObligationsDialogFragment.graphql";
} from "/__generated__/core/LinkedObligationsDialogFragment.graphql";
const obligationsQuery = graphql`
query LinkedObligationsDialogQuery($organizationId: ID!) {
@@ -94,25 +97,35 @@ export function LinkedObligationDialog({ children, ...props }: Props) {
function LinkedObligationsDialogContent(props: Omit<Props, "children">) {
const organizationId = useOrganizationId();
const query = useLazyLoadQuery<LinkedObligationsDialogQuery>(obligationsQuery, {
organizationId,
}, { fetchPolicy: "network-only" });
const query = useLazyLoadQuery<LinkedObligationsDialogQuery>(
obligationsQuery,
{
organizationId,
},
{ fetchPolicy: "network-only" },
);
const { data, loadNext, hasNext, isLoadingNext } = usePaginationFragment(
obligationsFragment,
query.organization as LinkedObligationsDialogFragment$key
query.organization as LinkedObligationsDialogFragment$key,
);
const { __ } = useTranslate();
const [search, setSearch] = useState("");
const obligations = useMemo(() => data.obligations?.edges?.map((edge) => edge.node) ?? [], [data.obligations]);
const obligations = useMemo(
() => data.obligations?.edges?.map((edge) => edge.node) ?? [],
[data.obligations],
);
const linkedIds = useMemo(() => {
return new Set(props.linkedObligations?.map((o) => o.id) ?? []);
}, [props.linkedObligations]);
const filteredObligations = useMemo(() => {
return obligations.filter((obligation) =>
obligation.area?.toLowerCase().includes(search.toLowerCase()) ||
obligation.source?.toLowerCase().includes(search.toLowerCase()) ||
obligation.owner?.fullName?.toLowerCase().includes(search.toLowerCase())
return obligations.filter(
(obligation) =>
obligation.area?.toLowerCase().includes(search.toLowerCase()) ||
obligation.source?.toLowerCase().includes(search.toLowerCase()) ||
obligation.owner?.fullName
?.toLowerCase()
.includes(search.toLowerCase()),
);
}, [obligations, search]);

View File

@@ -1,96 +0,0 @@
/**
* @generated SignedSource<<1126620dba70ca7a331c00347217eaa8>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type ObligationStatus = "COMPLIANT" | "NON_COMPLIANT" | "PARTIALLY_COMPLIANT";
import { FragmentRefs } from "relay-runtime";
export type LinkedObligationsCardFragment$data = {
readonly area: string | null | undefined;
readonly id: string;
readonly owner: {
readonly fullName: string;
};
readonly requirement: string | null | undefined;
readonly source: string | null | undefined;
readonly status: ObligationStatus;
readonly " $fragmentType": "LinkedObligationsCardFragment";
};
export type LinkedObligationsCardFragment$key = {
readonly " $data"?: LinkedObligationsCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedObligationsCardFragment">;
};
const node: ReaderFragment = {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "LinkedObligationsCardFragment",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "requirement",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "area",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "source",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
}
],
"storageKey": null
}
],
"type": "Obligation",
"abstractKey": null
};
(node as any).hash = "67ae0e6b0df090bb5a708bf7e029f4c5";
export default node;

View File

@@ -1,260 +0,0 @@
/**
* @generated SignedSource<<4569a09dbc9fbf80fb787da46d0d058f>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type ObligationStatus = "COMPLIANT" | "NON_COMPLIANT" | "PARTIALLY_COMPLIANT";
import { FragmentRefs } from "relay-runtime";
export type LinkedObligationsDialogFragment$data = {
readonly id: string;
readonly obligations: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly area: string | null | undefined;
readonly id: string;
readonly owner: {
readonly fullName: string;
};
readonly requirement: string | null | undefined;
readonly source: string | null | undefined;
readonly status: ObligationStatus;
};
}>;
};
readonly " $fragmentType": "LinkedObligationsDialogFragment";
};
export type LinkedObligationsDialogFragment$key = {
readonly " $data"?: LinkedObligationsDialogFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedObligationsDialogFragment">;
};
import LinkedObligationsDialogQuery_fragment_graphql from './LinkedObligationsDialogQuery_fragment.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"obligations"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
{
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "bidirectional",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "first",
"cursor": "after"
},
"backward": {
"count": "last",
"cursor": "before"
},
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": LinkedObligationsDialogQuery_fragment_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "LinkedObligationsDialogFragment",
"selections": [
{
"alias": "obligations",
"args": [
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
"concreteType": "ObligationConnection",
"kind": "LinkedField",
"name": "__LinkedObligationsDialogQuery_obligations_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ObligationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Obligation",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "requirement",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "area",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "source",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "Organization",
"abstractKey": null
};
})();
(node as any).hash = "6e686f2a4bce776146b1985df2863e73";
export default node;

View File

@@ -1,278 +0,0 @@
/**
* @generated SignedSource<<44ee1c9c1b8d060d03736d1703d2a68a>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type LinkedObligationsDialogQuery$variables = {
organizationId: string;
};
export type LinkedObligationsDialogQuery$data = {
readonly organization: {
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"LinkedObligationsDialogFragment">;
};
};
export type LinkedObligationsDialogQuery = {
response: LinkedObligationsDialogQuery$data;
variables: LinkedObligationsDialogQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = [
{
"kind": "Literal",
"name": "first",
"value": 20
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "LinkedObligationsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "LinkedObligationsDialogFragment"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "LinkedObligationsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": "ObligationConnection",
"kind": "LinkedField",
"name": "obligations",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ObligationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Obligation",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "requirement",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "area",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "source",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
(v2/*: any*/)
],
"storageKey": null
},
(v3/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "obligations(first:20)"
},
{
"alias": null,
"args": (v4/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "LinkedObligationsDialogQuery_obligations",
"kind": "LinkedHandle",
"name": "obligations"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "8d4a5e57f79ae207dd1e27c436e49bd5",
"id": null,
"metadata": {},
"name": "LinkedObligationsDialogQuery",
"operationKind": "query",
"text": "query LinkedObligationsDialogQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n ...LinkedObligationsDialogFragment\n }\n }\n}\n\nfragment LinkedObligationsDialogFragment on Organization {\n obligations(first: 20) {\n edges {\n node {\n id\n requirement\n area\n source\n status\n owner {\n fullName\n id\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "afd36a8a7dbe29044d2aefc3e3820fc8";
export default node;

View File

@@ -1,351 +0,0 @@
/**
* @generated SignedSource<<3d2709f51866093bcc78ec14501dae31>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type ObligationOrderField = "CREATED_AT" | "DUE_DATE" | "LAST_REVIEW_DATE" | "STATUS";
export type OrderDirection = "ASC" | "DESC";
export type ObligationOrder = {
direction: OrderDirection;
field: ObligationOrderField;
};
export type LinkedObligationsDialogQuery_fragment$variables = {
after?: any | null | undefined;
before?: any | null | undefined;
first?: number | null | undefined;
id: string;
last?: number | null | undefined;
order?: ObligationOrder | null | undefined;
};
export type LinkedObligationsDialogQuery_fragment$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"LinkedObligationsDialogFragment">;
};
};
export type LinkedObligationsDialogQuery_fragment = {
response: LinkedObligationsDialogQuery_fragment$data;
variables: LinkedObligationsDialogQuery_fragment$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
v2 = {
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
v3 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
},
v4 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
v5 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
},
v6 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v7 = {
"kind": "Variable",
"name": "after",
"variableName": "after"
},
v8 = {
"kind": "Variable",
"name": "before",
"variableName": "before"
},
v9 = {
"kind": "Variable",
"name": "first",
"variableName": "first"
},
v10 = {
"kind": "Variable",
"name": "last",
"variableName": "last"
},
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v13 = [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
];
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "LinkedObligationsDialogQuery_fragment",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "order",
"variableName": "order"
}
],
"kind": "FragmentSpread",
"name": "LinkedObligationsDialogFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v3/*: any*/)
],
"kind": "Operation",
"name": "LinkedObligationsDialogQuery_fragment",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v11/*: any*/),
(v12/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v13/*: any*/),
"concreteType": "ObligationConnection",
"kind": "LinkedField",
"name": "obligations",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "ObligationEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Obligation",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v12/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "requirement",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "area",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "source",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
(v12/*: any*/)
],
"storageKey": null
},
(v11/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": (v13/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "LinkedObligationsDialogQuery_obligations",
"kind": "LinkedHandle",
"name": "obligations"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "a4640b163a373e0420a9fb1108ce7b3a",
"id": null,
"metadata": {},
"name": "LinkedObligationsDialogQuery_fragment",
"operationKind": "query",
"text": "query LinkedObligationsDialogQuery_fragment(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: ObligationOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...LinkedObligationsDialogFragment_16fISc\n id\n }\n}\n\nfragment LinkedObligationsDialogFragment_16fISc on Organization {\n obligations(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n requirement\n area\n source\n status\n owner {\n fullName\n id\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "6e686f2a4bce776146b1985df2863e73";
export default node;

View File

@@ -1,16 +1,21 @@
import { Badge, Button, Card } from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { sprintf } from "@probo/helpers";
import type { TrustCenterGraphQuery$data } from "/hooks/graph/__generated__/TrustCenterGraphQuery.graphql";
import type { TrustCenterGraphQuery$data } from "/__generated__/core/TrustCenterGraphQuery.graphql";
import { use } from "react";
import { PermissionsContext } from "/providers/PermissionsContext";
type Props = {
organizationId: string;
slackConnections: NonNullable<TrustCenterGraphQuery$data["organization"]["slackConnections"]>["edges"][number]["node"][];
slackConnections: NonNullable<
TrustCenterGraphQuery$data["organization"]["slackConnections"]
>["edges"][number]["node"][];
};
export function SlackConnections({ organizationId, slackConnections: connectedSlackConnections }: Props) {
export function SlackConnections({
organizationId,
slackConnections: connectedSlackConnections,
}: Props) {
const { __, dateTimeFormat } = useTranslate();
const { isAuthorized } = use(PermissionsContext);
const slackConnectionDefinitions = [
@@ -46,7 +51,11 @@ export function SlackConnections({ organizationId, slackConnections: connectedSl
return (
<div className="space-y-2">
{slackConnections.map((slackConnection) => (
<Card key={slackConnection.id} padded className="flex items-center gap-3">
<Card
key={slackConnection.id}
padded
className="flex items-center gap-3"
>
<div>
<img src={`/${slackConnection.id.toLowerCase()}.png`} alt="" />
</div>
@@ -57,7 +66,7 @@ export function SlackConnections({ organizationId, slackConnections: connectedSl
<>
{sprintf(
__("Connected on %s"),
dateTimeFormat(slackConnection.createdAt)
dateTimeFormat(slackConnection.createdAt),
)}
{slackConnection.channel && (
<>

View File

@@ -12,7 +12,7 @@ import {
TrButton,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { LinkedRisksCardFragment$key } from "./__generated__/LinkedRisksCardFragment.graphql";
import type { LinkedRisksCardFragment$key } from "/__generated__/core/LinkedRisksCardFragment.graphql";
import { useFragment } from "react-relay";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { LinkedRisksDialog } from "./LinkedRisksDialog.tsx";
@@ -95,13 +95,21 @@ export function LinkedRisksCard<Params>(props: Props<Params>) {
<Tbody>
{props.risks.length === 0 && (
<Tr>
<Td colSpan={props.readOnly ? 3 : 4} className="text-center text-txt-secondary">
<Td
colSpan={props.readOnly ? 3 : 4}
className="text-center text-txt-secondary"
>
{__("No risks linked")}
</Td>
</Tr>
)}
{props.risks.map((risk) => (
<RiskRow key={risk.id} risk={risk} onClick={onDetach} readOnly={props.readOnly} />
<RiskRow
key={risk.id}
risk={risk}
onClick={onDetach}
readOnly={props.readOnly}
/>
))}
{!props.readOnly && (
<LinkedRisksDialog

View File

@@ -16,7 +16,7 @@ import { useTranslate } from "@probo/i18n";
import { Suspense, useMemo, useState, type ReactNode } from "react";
import { graphql } from "relay-runtime";
import { useLazyLoadQuery } from "react-relay";
import type { LinkedRisksDialogQuery } from "./__generated__/LinkedRisksDialogQuery.graphql";
import type { LinkedRisksDialogQuery } from "/__generated__/core/LinkedRisksDialogQuery.graphql";
import { useOrganizationId } from "/hooks/useOrganizationId";
const risksQuery = graphql`
@@ -73,7 +73,10 @@ function LinkedRisksDialogContent(props: Omit<Props, "children">) {
const { __ } = useTranslate();
const [search, setSearch] = useState("");
const [category, setCategory] = useState<string | null>(null);
const risks = useMemo(() => data.organization?.risks?.edges?.map((edge) => edge.node) ?? [], [data.organization?.risks]);
const risks = useMemo(
() => data.organization?.risks?.edges?.map((edge) => edge.node) ?? [],
[data.organization?.risks],
);
const linkedIds = useMemo(() => {
return new Set(props.linkedRisks?.map((r) => r.id) ?? []);
}, [props.linkedRisks]);
@@ -83,13 +86,13 @@ function LinkedRisksDialogContent(props: Omit<Props, "children">) {
(risk) =>
(category === null || risk.category === category) &&
(risk.name.toLowerCase().includes(search.toLowerCase()) ||
risk.description?.toLowerCase().includes(search.toLowerCase()))
risk.description?.toLowerCase().includes(search.toLowerCase())),
);
}, [risks, search, category]);
const categories = useMemo(
() => Array.from(new Set(risks.map((r) => r.category))),
[risks]
[risks],
);
return (

View File

@@ -1,66 +0,0 @@
/**
* @generated SignedSource<<6e092be20526b76ee767836880803c34>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type LinkedRisksCardFragment$data = {
readonly id: string;
readonly inherentRiskScore: number;
readonly name: string;
readonly residualRiskScore: number;
readonly " $fragmentType": "LinkedRisksCardFragment";
};
export type LinkedRisksCardFragment$key = {
readonly " $data"?: LinkedRisksCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedRisksCardFragment">;
};
const node: ReaderFragment = {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "LinkedRisksCardFragment",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "inherentRiskScore",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "residualRiskScore",
"storageKey": null
}
],
"type": "Risk",
"abstractKey": null
};
(node as any).hash = "32a84445ae1cc071f56139fa44d67690";
export default node;

View File

@@ -1,206 +0,0 @@
/**
* @generated SignedSource<<b39754dc6d5d5f02e4310f0db334add3>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type LinkedRisksDialogQuery$variables = {
organizationId: string;
};
export type LinkedRisksDialogQuery$data = {
readonly organization: {
readonly id: string;
readonly risks?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly category: string;
readonly description: string | null | undefined;
readonly id: string;
readonly inherentRiskScore: number;
readonly name: string;
readonly residualRiskScore: number;
};
}>;
};
};
};
export type LinkedRisksDialogQuery = {
response: LinkedRisksDialogQuery$data;
variables: LinkedRisksDialogQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 100
}
],
"concreteType": "RiskConnection",
"kind": "LinkedField",
"name": "risks",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "RiskEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Risk",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "inherentRiskScore",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "residualRiskScore",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "risks(first:100)"
}
],
"type": "Organization",
"abstractKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "LinkedRisksDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/)
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "LinkedRisksDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v2/*: any*/),
(v3/*: any*/)
],
"storageKey": null
}
]
},
"params": {
"cacheID": "ccac9f72628186de135aeb2ee176207d",
"id": null,
"metadata": {},
"name": "LinkedRisksDialogQuery",
"operationKind": "query",
"text": "query LinkedRisksDialogQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n risks(first: 100) {\n edges {\n node {\n id\n name\n category\n description\n inherentRiskScore\n residualRiskScore\n }\n }\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "a0a7e39135cc4c1a4a74c4728902f944";
export default node;

View File

@@ -15,10 +15,15 @@ import {
TrButton,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { LinkedSnapshotsCardFragment$key } from "./__generated__/LinkedSnapshotsCardFragment.graphql";
import type { LinkedSnapshotsCardFragment$key } from "/__generated__/core/LinkedSnapshotsCardFragment.graphql";
import { useFragment } from "react-relay";
import { useMemo, useState } from "react";
import { sprintf, getSnapshotTypeLabel, getSnapshotTypeUrlPath, formatDate } from "@probo/helpers";
import {
sprintf,
getSnapshotTypeLabel,
getSnapshotTypeUrlPath,
formatDate,
} from "@probo/helpers";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { LinkedSnapshotsDialog } from "./LinkedSnapshotsDialog";
import clsx from "clsx";
@@ -123,7 +128,10 @@ export function LinkedSnapshotsCard<Params>(props: Props<Params>) {
<Tbody>
{snapshots.length === 0 && (
<Tr>
<Td colSpan={variant === "table" ? colSpanTable : colSpanCard} className="text-center text-txt-secondary">
<Td
colSpan={variant === "table" ? colSpanTable : colSpanCard}
className="text-center text-txt-secondary"
>
{__("No snapshots linked")}
</Td>
</Tr>
@@ -191,9 +199,7 @@ function SnapshotRow(props: {
{snapshot.description || __("No description")}
</Td>
)}
<Td className="text-txt-tertiary">
{formatDate(snapshot.createdAt)}
</Td>
<Td className="text-txt-tertiary">{formatDate(snapshot.createdAt)}</Td>
{!props.readOnly && (
<Td noLink width={50} className="text-end">
<Button

View File

@@ -16,13 +16,13 @@ import { getSnapshotTypeLabel, formatDate } from "@probo/helpers";
import { Suspense, useMemo, useState, type ReactNode } from "react";
import { graphql } from "relay-runtime";
import { useLazyLoadQuery, usePaginationFragment } from "react-relay";
import type { LinkedSnapshotsDialogQuery } from "./__generated__/LinkedSnapshotsDialogQuery.graphql";
import type { LinkedSnapshotsDialogQuery } from "/__generated__/core/LinkedSnapshotsDialogQuery.graphql";
import { useOrganizationId } from "/hooks/useOrganizationId";
import type { NodeOf } from "/types";
import type {
LinkedSnapshotsDialogFragment$data,
LinkedSnapshotsDialogFragment$key,
} from "./__generated__/LinkedSnapshotsDialogFragment.graphql";
} from "/__generated__/core/LinkedSnapshotsDialogFragment.graphql";
const snapshotsQuery = graphql`
query LinkedSnapshotsDialogQuery($organizationId: ID!) {
@@ -95,21 +95,22 @@ function LinkedSnapshotsDialogContent(props: Omit<Props, "children">) {
});
const { data, loadNext, hasNext, isLoadingNext } = usePaginationFragment<
LinkedSnapshotsDialogQuery,
LinkedSnapshotsDialogFragment$key>(
snapshotsFragment,
query.organization
);
LinkedSnapshotsDialogFragment$key
>(snapshotsFragment, query.organization);
const { __ } = useTranslate();
const [search, setSearch] = useState("");
const snapshots = useMemo(() => data.snapshots?.edges?.map((edge) => edge.node) ?? [], [data.snapshots]);
const snapshots = useMemo(
() => data.snapshots?.edges?.map((edge) => edge.node) ?? [],
[data.snapshots],
);
const linkedIds = useMemo(() => {
return new Set(props.linkedSnapshots?.map((s) => s.id) ?? []);
}, [props.linkedSnapshots]);
const filteredSnapshots = useMemo(() => {
return snapshots.filter((snapshot) =>
snapshot.name.toLowerCase().includes(search.toLowerCase())
snapshot.name.toLowerCase().includes(search.toLowerCase()),
);
}, [snapshots, search]);

View File

@@ -1,75 +0,0 @@
/**
* @generated SignedSource<<18ad235cee2891b222acb016b8986050>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type SnapshotsType = "ASSETS" | "CONTINUAL_IMPROVEMENTS" | "DATA" | "NONCONFORMITIES" | "OBLIGATIONS" | "PROCESSING_ACTIVITIES" | "RISKS" | "STATES_OF_APPLICABILITY" | "VENDORS";
import { FragmentRefs } from "relay-runtime";
export type LinkedSnapshotsCardFragment$data = {
readonly createdAt: any;
readonly description: string | null | undefined;
readonly id: string;
readonly name: string;
readonly type: SnapshotsType;
readonly " $fragmentType": "LinkedSnapshotsCardFragment";
};
export type LinkedSnapshotsCardFragment$key = {
readonly " $data"?: LinkedSnapshotsCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedSnapshotsCardFragment">;
};
const node: ReaderFragment = {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "LinkedSnapshotsCardFragment",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "type",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
}
],
"type": "Snapshot",
"abstractKey": null
};
(node as any).hash = "b9b682f8e57082c98d8b0460155757fb";
export default node;

View File

@@ -1,239 +0,0 @@
/**
* @generated SignedSource<<4b2fe0335336a1c3888d8da35ffd8e58>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type SnapshotsType = "ASSETS" | "CONTINUAL_IMPROVEMENTS" | "DATA" | "NONCONFORMITIES" | "OBLIGATIONS" | "PROCESSING_ACTIVITIES" | "RISKS" | "STATES_OF_APPLICABILITY" | "VENDORS";
import { FragmentRefs } from "relay-runtime";
export type LinkedSnapshotsDialogFragment$data = {
readonly id: string;
readonly snapshots: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: any;
readonly description: string | null | undefined;
readonly id: string;
readonly name: string;
readonly type: SnapshotsType;
};
}>;
};
readonly " $fragmentType": "LinkedSnapshotsDialogFragment";
};
export type LinkedSnapshotsDialogFragment$key = {
readonly " $data"?: LinkedSnapshotsDialogFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedSnapshotsDialogFragment">;
};
import LinkedSnapshotsDialogQuery_fragment_graphql from './LinkedSnapshotsDialogQuery_fragment.graphql';
const node: ReaderFragment = (function(){
var v0 = [
"snapshots"
],
v1 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
{
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
}
],
"kind": "Fragment",
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "bidirectional",
"path": (v0/*: any*/)
}
],
"refetch": {
"connection": {
"forward": {
"count": "first",
"cursor": "after"
},
"backward": {
"count": "last",
"cursor": "before"
},
"path": (v0/*: any*/)
},
"fragmentPathInResult": [
"node"
],
"operation": LinkedSnapshotsDialogQuery_fragment_graphql,
"identifierInfo": {
"identifierField": "id",
"identifierQueryVariableName": "id"
}
}
},
"name": "LinkedSnapshotsDialogFragment",
"selections": [
{
"alias": "snapshots",
"args": [
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
],
"concreteType": "SnapshotConnection",
"kind": "LinkedField",
"name": "__LinkedSnapshotsDialogQuery_snapshots_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "SnapshotEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Snapshot",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "type",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v1/*: any*/)
],
"type": "Organization",
"abstractKey": null
};
})();
(node as any).hash = "bdc77ee756ac59c099caa8765403cd22";
export default node;

View File

@@ -1,259 +0,0 @@
/**
* @generated SignedSource<<78d7f0f48f20187e9eef7744a19d8e1e>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type LinkedSnapshotsDialogQuery$variables = {
organizationId: string;
};
export type LinkedSnapshotsDialogQuery$data = {
readonly organization: {
readonly id: string;
readonly " $fragmentSpreads": FragmentRefs<"LinkedSnapshotsDialogFragment">;
};
};
export type LinkedSnapshotsDialogQuery = {
response: LinkedSnapshotsDialogQuery$data;
variables: LinkedSnapshotsDialogQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = [
{
"kind": "Literal",
"name": "first",
"value": 20
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "LinkedSnapshotsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "LinkedSnapshotsDialogFragment"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "LinkedSnapshotsDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v4/*: any*/),
"concreteType": "SnapshotConnection",
"kind": "LinkedField",
"name": "snapshots",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "SnapshotEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Snapshot",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "type",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
(v3/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "snapshots(first:20)"
},
{
"alias": null,
"args": (v4/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "LinkedSnapshotsDialogQuery_snapshots",
"kind": "LinkedHandle",
"name": "snapshots"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "200a82b795d348f0d8a63a3b2b779d7c",
"id": null,
"metadata": {},
"name": "LinkedSnapshotsDialogQuery",
"operationKind": "query",
"text": "query LinkedSnapshotsDialogQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n ...LinkedSnapshotsDialogFragment\n }\n }\n}\n\nfragment LinkedSnapshotsDialogFragment on Organization {\n snapshots(first: 20) {\n edges {\n node {\n id\n name\n description\n type\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "b91ff32883e1f6e83d9b43251fc83001";
export default node;

View File

@@ -1,332 +0,0 @@
/**
* @generated SignedSource<<da66b640f5bf710bb086e806a82b03e6>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type OrderDirection = "ASC" | "DESC";
export type SnapshotOrderField = "CREATED_AT" | "NAME" | "TYPE";
export type SnapshotOrder = {
direction: OrderDirection;
field: SnapshotOrderField;
};
export type LinkedSnapshotsDialogQuery_fragment$variables = {
after?: any | null | undefined;
before?: any | null | undefined;
first?: number | null | undefined;
id: string;
last?: number | null | undefined;
order?: SnapshotOrder | null | undefined;
};
export type LinkedSnapshotsDialogQuery_fragment$data = {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"LinkedSnapshotsDialogFragment">;
};
};
export type LinkedSnapshotsDialogQuery_fragment = {
response: LinkedSnapshotsDialogQuery_fragment$data;
variables: LinkedSnapshotsDialogQuery_fragment$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "after"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "before"
},
v2 = {
"defaultValue": 20,
"kind": "LocalArgument",
"name": "first"
},
v3 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "id"
},
v4 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "last"
},
v5 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "order"
},
v6 = [
{
"kind": "Variable",
"name": "id",
"variableName": "id"
}
],
v7 = {
"kind": "Variable",
"name": "after",
"variableName": "after"
},
v8 = {
"kind": "Variable",
"name": "before",
"variableName": "before"
},
v9 = {
"kind": "Variable",
"name": "first",
"variableName": "first"
},
v10 = {
"kind": "Variable",
"name": "last",
"variableName": "last"
},
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v12 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v13 = [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "orderBy",
"variableName": "order"
}
];
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "LinkedSnapshotsDialogQuery_fragment",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": [
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"kind": "Variable",
"name": "order",
"variableName": "order"
}
],
"kind": "FragmentSpread",
"name": "LinkedSnapshotsDialogFragment"
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/),
(v2/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v3/*: any*/)
],
"kind": "Operation",
"name": "LinkedSnapshotsDialogQuery_fragment",
"selections": [
{
"alias": null,
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v11/*: any*/),
(v12/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v13/*: any*/),
"concreteType": "SnapshotConnection",
"kind": "LinkedField",
"name": "snapshots",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "SnapshotEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Snapshot",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v12/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "type",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
(v11/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "PageInfo",
"kind": "LinkedField",
"name": "pageInfo",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasPreviousPage",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "startCursor",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": (v13/*: any*/),
"filters": [
"orderBy"
],
"handle": "connection",
"key": "LinkedSnapshotsDialogQuery_snapshots",
"kind": "LinkedHandle",
"name": "snapshots"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "e4c40c765a5b6ef4ba63a6343c76e6e0",
"id": null,
"metadata": {},
"name": "LinkedSnapshotsDialogQuery_fragment",
"operationKind": "query",
"text": "query LinkedSnapshotsDialogQuery_fragment(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 20\n $last: Int = null\n $order: SnapshotOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...LinkedSnapshotsDialogFragment_16fISc\n id\n }\n}\n\nfragment LinkedSnapshotsDialogFragment_16fISc on Organization {\n snapshots(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n name\n description\n type\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "bdc77ee756ac59c099caa8765403cd22";
export default node;

View File

@@ -1,21 +1,21 @@
import { graphql } from "relay-runtime";
import {
Card,
IconPlusLarge,
Button,
Tr,
Td,
Table,
Thead,
Tbody,
Th,
IconChevronDown,
IconTrashCan,
TrButton,
Badge,
Card,
IconPlusLarge,
Button,
Tr,
Td,
Table,
Thead,
Tbody,
Th,
IconChevronDown,
IconTrashCan,
TrButton,
Badge,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { LinkedStatesOfApplicabilityCardFragment$key } from "./__generated__/LinkedStatesOfApplicabilityCardFragment.graphql";
import type { LinkedStatesOfApplicabilityCardFragment$key } from "/__generated__/core/LinkedStatesOfApplicabilityCardFragment.graphql";
import { useFragment } from "react-relay";
import { useMemo, useState, useEffect } from "react";
import { sprintf } from "@probo/helpers";
@@ -24,225 +24,271 @@ import { LinkedStatesOfApplicabilityDialog } from "./LinkedStatesOfApplicability
import clsx from "clsx";
const linkedStateOfApplicabilityFragment = graphql`
fragment LinkedStatesOfApplicabilityCardFragment on StateOfApplicabilityControl {
id
stateOfApplicabilityId
controlId
stateOfApplicability {
id
name
fragment LinkedStatesOfApplicabilityCardFragment on StateOfApplicabilityControl {
id
stateOfApplicabilityId
controlId
stateOfApplicability {
id
name
}
applicability
justification
}
applicability
justification
}
`;
type AttachMutation<Params> = (p: {
variables: {
input: {
stateOfApplicabilityId: string;
applicability: boolean;
justification: string | null;
} & Params;
connections: string[];
};
variables: {
input: {
stateOfApplicabilityId: string;
applicability: boolean;
justification: string | null;
} & Params;
connections: string[];
};
}) => void;
type DetachMutation = (p: {
variables: {
input: {
stateOfApplicabilityId: string;
controlId: string;
variables: {
input: {
stateOfApplicabilityId: string;
controlId: string;
};
connections: string[];
};
connections: string[];
};
}) => void;
type Props<Params> = {
statesOfApplicability: readonly (LinkedStatesOfApplicabilityCardFragment$key & { id: string })[];
params: Params;
disabled?: boolean;
connectionId: string;
onAttach: AttachMutation<Params>;
onDetach: DetachMutation;
variant?: "card" | "table";
readOnly?: boolean;
statesOfApplicability: readonly (LinkedStatesOfApplicabilityCardFragment$key & {
id: string;
})[];
params: Params;
disabled?: boolean;
connectionId: string;
onAttach: AttachMutation<Params>;
onDetach: DetachMutation;
variant?: "card" | "table";
readOnly?: boolean;
};
export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
const { __ } = useTranslate();
const { __ } = useTranslate();
const [limit, setLimit] = useState<number | null>(
props.variant === "card" ? 4 : null
);
const [limit, setLimit] = useState<number | null>(
props.variant === "card" ? 4 : null,
);
const [linkedInfo, setLinkedInfo] = useState<{ stateOfApplicabilityId: string; controlId: string }[]>([]);
const [linkedInfo, setLinkedInfo] = useState<
{ stateOfApplicabilityId: string; controlId: string }[]
>([]);
const statesOfApplicability = useMemo(() => {
return limit ? props.statesOfApplicability.slice(0, limit) : props.statesOfApplicability;
}, [props.statesOfApplicability, limit]);
const statesOfApplicability = useMemo(() => {
return limit
? props.statesOfApplicability.slice(0, limit)
: props.statesOfApplicability;
}, [props.statesOfApplicability, limit]);
const showMoreButton = limit !== null && props.statesOfApplicability.length > limit;
const variant = props.variant ?? "table";
const showMoreButton =
limit !== null && props.statesOfApplicability.length > limit;
const variant = props.variant ?? "table";
const linkedData = linkedInfo;
const linkedData = linkedInfo;
const onAttach = (stateOfApplicabilityId: string, applicability: boolean, justification: string | null) => {
props.onAttach({
variables: {
input: {
stateOfApplicabilityId,
applicability,
justification,
...props.params,
},
connections: [props.connectionId],
},
});
};
const onAttach = (
stateOfApplicabilityId: string,
applicability: boolean,
justification: string | null,
) => {
props.onAttach({
variables: {
input: {
stateOfApplicabilityId,
applicability,
justification,
...props.params,
},
connections: [props.connectionId],
},
});
};
const onDetach = (stateOfApplicabilityId: string, controlId: string) => {
props.onDetach({
variables: {
input: {
stateOfApplicabilityId,
controlId,
},
connections: [props.connectionId],
},
});
};
const onDetach = (stateOfApplicabilityId: string, controlId: string) => {
props.onDetach({
variables: {
input: {
stateOfApplicabilityId,
controlId,
},
connections: [props.connectionId],
},
});
};
const Wrapper = variant === "card" ? Card : "div";
const Wrapper = variant === "card" ? Card : "div";
return (
<Wrapper padded className="space-y-[10px]">
{props.statesOfApplicability.map((soa, idx) => (
<LinkedInfoExtractor
key={idx}
fragment={soa}
onExtracted={(info) => {
setLinkedInfo(prev => {
const exists = prev.some(p =>
p.stateOfApplicabilityId === info.stateOfApplicabilityId &&
p.controlId === info.controlId
);
return exists ? prev : [...prev, info];
});
}}
/>
))}
{variant === "card" && (
<div className="flex justify-between">
<div className="text-lg font-semibold">{__("States of Applicability")}</div>
{!props.readOnly && (
<LinkedStatesOfApplicabilityDialog
connectionId={props.connectionId}
disabled={props.disabled}
linkedStatesOfApplicability={linkedData}
onLink={onAttach}
onUnlink={onDetach}
>
<Button variant="tertiary" icon={IconPlusLarge}>
{__("Link state of applicability")}
</Button>
</LinkedStatesOfApplicabilityDialog>
)}
</div>
)}
<Table className={clsx(variant === "card" && "bg-invert")}>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
<Th>{__("Applicability")}</Th>
<Th>{__("Justification")}</Th>
{!props.readOnly && <Th></Th>}
</Tr>
</Thead>
<Tbody>
{statesOfApplicability.length === 0 && (
<Tr>
<Td colSpan={props.readOnly ? 3 : 4} className="text-center text-txt-secondary">
{__("No states of applicability linked")}
</Td>
</Tr>
)}
{statesOfApplicability.map((soa) => (
<StateOfApplicabilityRow key={soa.id} stateOfApplicability={soa} onClick={onDetach} readOnly={props.readOnly} />
))}
{variant === "table" && !props.readOnly && (
<LinkedStatesOfApplicabilityDialog
connectionId={props.connectionId}
disabled={props.disabled}
linkedStatesOfApplicability={linkedData}
onLink={onAttach}
onUnlink={onDetach}
>
<TrButton colspan={4} icon={IconPlusLarge}>
{__("Link state of applicability")}
</TrButton>
</LinkedStatesOfApplicabilityDialog>
)}
</Tbody>
</Table>
{showMoreButton && (
<Button
variant="tertiary"
icon={IconChevronDown}
onClick={() => setLimit(null)}
>
{sprintf(__("Show %d more"), props.statesOfApplicability.length - limit!)}
</Button>
)}
</Wrapper>
);
return (
<Wrapper padded className="space-y-[10px]">
{props.statesOfApplicability.map((soa, idx) => (
<LinkedInfoExtractor
key={idx}
fragment={soa}
onExtracted={(info) => {
setLinkedInfo((prev) => {
const exists = prev.some(
(p) =>
p.stateOfApplicabilityId ===
info.stateOfApplicabilityId &&
p.controlId === info.controlId,
);
return exists ? prev : [...prev, info];
});
}}
/>
))}
{variant === "card" && (
<div className="flex justify-between">
<div className="text-lg font-semibold">
{__("States of Applicability")}
</div>
{!props.readOnly && (
<LinkedStatesOfApplicabilityDialog
connectionId={props.connectionId}
disabled={props.disabled}
linkedStatesOfApplicability={linkedData}
onLink={onAttach}
onUnlink={onDetach}
>
<Button variant="tertiary" icon={IconPlusLarge}>
{__("Link state of applicability")}
</Button>
</LinkedStatesOfApplicabilityDialog>
)}
</div>
)}
<Table className={clsx(variant === "card" && "bg-invert")}>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
<Th>{__("Applicability")}</Th>
<Th>{__("Justification")}</Th>
{!props.readOnly && <Th></Th>}
</Tr>
</Thead>
<Tbody>
{statesOfApplicability.length === 0 && (
<Tr>
<Td
colSpan={props.readOnly ? 3 : 4}
className="text-center text-txt-secondary"
>
{__("No states of applicability linked")}
</Td>
</Tr>
)}
{statesOfApplicability.map((soa) => (
<StateOfApplicabilityRow
key={soa.id}
stateOfApplicability={soa}
onClick={onDetach}
readOnly={props.readOnly}
/>
))}
{variant === "table" && !props.readOnly && (
<LinkedStatesOfApplicabilityDialog
connectionId={props.connectionId}
disabled={props.disabled}
linkedStatesOfApplicability={linkedData}
onLink={onAttach}
onUnlink={onDetach}
>
<TrButton colspan={4} icon={IconPlusLarge}>
{__("Link state of applicability")}
</TrButton>
</LinkedStatesOfApplicabilityDialog>
)}
</Tbody>
</Table>
{showMoreButton && (
<Button
variant="tertiary"
icon={IconChevronDown}
onClick={() => setLimit(null)}
>
{sprintf(
__("Show %d more"),
props.statesOfApplicability.length - limit!,
)}
</Button>
)}
</Wrapper>
);
}
function LinkedInfoExtractor(props: {
fragment: LinkedStatesOfApplicabilityCardFragment$key;
onExtracted: (info: { stateOfApplicabilityId: string; controlId: string }) => void;
fragment: LinkedStatesOfApplicabilityCardFragment$key;
onExtracted: (info: {
stateOfApplicabilityId: string;
controlId: string;
}) => void;
}) {
const data = useFragment(linkedStateOfApplicabilityFragment, props.fragment);
const data = useFragment(
linkedStateOfApplicabilityFragment,
props.fragment,
);
useEffect(() => {
props.onExtracted({
stateOfApplicabilityId: data.stateOfApplicabilityId,
controlId: data.controlId,
});
}, [data.stateOfApplicabilityId, data.controlId, props.onExtracted]);
useEffect(() => {
props.onExtracted({
stateOfApplicabilityId: data.stateOfApplicabilityId,
controlId: data.controlId,
});
}, [data.stateOfApplicabilityId, data.controlId, props.onExtracted]);
return null;
return null;
}
function StateOfApplicabilityRow(props: {
stateOfApplicability: LinkedStatesOfApplicabilityCardFragment$key & { id: string };
onClick: (stateOfApplicabilityId: string, controlId: string) => void;
readOnly?: boolean;
stateOfApplicability: LinkedStatesOfApplicabilityCardFragment$key & {
id: string;
};
onClick: (stateOfApplicabilityId: string, controlId: string) => void;
readOnly?: boolean;
}) {
const soa = useFragment(linkedStateOfApplicabilityFragment, props.stateOfApplicability);
const organizationId = useOrganizationId();
const { __ } = useTranslate();
const soa = useFragment(
linkedStateOfApplicabilityFragment,
props.stateOfApplicability,
);
const organizationId = useOrganizationId();
const { __ } = useTranslate();
return (
<Tr to={`/organizations/${organizationId}/states-of-applicability/${soa.stateOfApplicabilityId}`}>
<Td>{soa.stateOfApplicability.name}</Td>
<Td>
<Badge variant={soa.applicability ? "success" : "danger"}>
{soa.applicability ? __("Applicable") : __("Not Applicable")}
</Badge>
</Td>
<Td>{soa.justification || "-"}</Td>
{!props.readOnly && (
<Td noLink width={50} className="text-end">
<Button
variant="secondary"
onClick={() => props.onClick(soa.stateOfApplicabilityId, soa.controlId)}
icon={IconTrashCan}
>
{__("Unlink")}
</Button>
</Td>
)}
</Tr>
);
return (
<Tr
to={`/organizations/${organizationId}/states-of-applicability/${soa.stateOfApplicabilityId}`}
>
<Td>{soa.stateOfApplicability.name}</Td>
<Td>
<Badge variant={soa.applicability ? "success" : "danger"}>
{soa.applicability
? __("Applicable")
: __("Not Applicable")}
</Badge>
</Td>
<Td>{soa.justification || "-"}</Td>
{!props.readOnly && (
<Td noLink width={50} className="text-end">
<Button
variant="secondary"
onClick={() =>
props.onClick(
soa.stateOfApplicabilityId,
soa.controlId,
)
}
icon={IconTrashCan}
>
{__("Unlink")}
</Button>
</Td>
)}
</Tr>
);
}

View File

@@ -1,180 +1,265 @@
import { useTranslate } from "@probo/i18n";
import { Dialog, DialogContent, DialogFooter, Button, Checkbox, Textarea, Badge } from "@probo/ui";
import {
Dialog,
DialogContent,
DialogFooter,
Button,
Checkbox,
Textarea,
Badge,
} from "@probo/ui";
import { Suspense, useState, useRef } from "react";
import type { ReactNode } from "react";
import { useLazyLoadQuery } from "react-relay";
import { graphql } from "relay-runtime";
import { useOrganizationId } from "/hooks/useOrganizationId";
import type { LinkedStatesOfApplicabilityDialogQuery } from "./__generated__/LinkedStatesOfApplicabilityDialogQuery.graphql";
import type { LinkedStatesOfApplicabilityDialogQuery } from "/__generated__/core/LinkedStatesOfApplicabilityDialogQuery.graphql";
const query = graphql`
query LinkedStatesOfApplicabilityDialogQuery($organizationId: ID!) {
organization: node(id: $organizationId) {
... on Organization {
statesOfApplicability(first: 100) {
edges {
node {
id
name
query LinkedStatesOfApplicabilityDialogQuery($organizationId: ID!) {
organization: node(id: $organizationId) {
... on Organization {
statesOfApplicability(first: 100) {
edges {
node {
id
name
}
}
}
}
}
}
}
}
}
`;
type LinkedSOAInfo = {
stateOfApplicabilityId: string;
controlId: string;
stateOfApplicabilityId: string;
controlId: string;
};
type Props = {
children: ReactNode;
connectionId: string;
disabled?: boolean;
linkedStatesOfApplicability: readonly LinkedSOAInfo[];
onLink: (stateOfApplicabilityId: string, applicability: boolean, justification: string | null) => void;
onUnlink: (stateOfApplicabilityId: string, controlId: string) => void;
children: ReactNode;
connectionId: string;
disabled?: boolean;
linkedStatesOfApplicability: readonly LinkedSOAInfo[];
onLink: (
stateOfApplicabilityId: string,
applicability: boolean,
justification: string | null,
) => void;
onUnlink: (stateOfApplicabilityId: string, controlId: string) => void;
};
export function LinkedStatesOfApplicabilityDialog({ children, ...props }: Props) {
const dialogRef = useRef<{ open: () => void; close: () => void }>(null);
export function LinkedStatesOfApplicabilityDialog({
children,
...props
}: Props) {
const dialogRef = useRef<{ open: () => void; close: () => void }>(null);
return (
<Dialog ref={dialogRef} trigger={children} title="Link State of Applicability">
<Suspense fallback={<div>Loading...</div>}>
<LinkedStatesOfApplicabilityDialogContent {...props} onClose={() => dialogRef.current?.close()} />
</Suspense>
</Dialog>
);
return (
<Dialog
ref={dialogRef}
trigger={children}
title="Link State of Applicability"
>
<Suspense fallback={<div>Loading...</div>}>
<LinkedStatesOfApplicabilityDialogContent
{...props}
onClose={() => dialogRef.current?.close()}
/>
</Suspense>
</Dialog>
);
}
function LinkedStatesOfApplicabilityDialogContent(props: Omit<Props, "children"> & { onClose: () => void }) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const [selectedSOA, setSelectedSOA] = useState<{ id: string; name: string } | null>(null);
const [applicability, setApplicability] = useState(true);
const [justification, setJustification] = useState("");
function LinkedStatesOfApplicabilityDialogContent(
props: Omit<Props, "children"> & { onClose: () => void },
) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
const [selectedSOA, setSelectedSOA] = useState<{
id: string;
name: string;
} | null>(null);
const [applicability, setApplicability] = useState(true);
const [justification, setJustification] = useState("");
const data = useLazyLoadQuery<LinkedStatesOfApplicabilityDialogQuery>(query, {
organizationId,
}, { fetchPolicy: "network-only" });
const data = useLazyLoadQuery<LinkedStatesOfApplicabilityDialogQuery>(
query,
{
organizationId,
},
{ fetchPolicy: "network-only" },
);
const linkedSOAIds = new Set(props.linkedStatesOfApplicability.map((soa) => soa.stateOfApplicabilityId));
const linkedSOAMap = new Map(props.linkedStatesOfApplicability.map((soa) => [soa.stateOfApplicabilityId, soa]));
const statesOfApplicability = data.organization?.statesOfApplicability?.edges.map((edge) => edge.node) ?? [];
const linkedSOAIds = new Set(
props.linkedStatesOfApplicability.map(
(soa) => soa.stateOfApplicabilityId,
),
);
const linkedSOAMap = new Map(
props.linkedStatesOfApplicability.map((soa) => [
soa.stateOfApplicabilityId,
soa,
]),
);
const statesOfApplicability =
data.organization?.statesOfApplicability?.edges.map(
(edge) => edge.node,
) ?? [];
const handleSelectSOA = (soa: { id: string; name: string }) => {
setSelectedSOA(soa);
setApplicability(true);
setJustification("");
};
const handleSelectSOA = (soa: { id: string; name: string }) => {
setSelectedSOA(soa);
setApplicability(true);
setJustification("");
};
const handleLink = () => {
if (selectedSOA) {
props.onLink(selectedSOA.id, applicability, justification.trim() || null);
props.onClose();
}
};
const handleLink = () => {
if (selectedSOA) {
props.onLink(
selectedSOA.id,
applicability,
justification.trim() || null,
);
props.onClose();
}
};
const handleUnlink = (stateOfApplicabilityId: string) => {
const linkedSOA = linkedSOAMap.get(stateOfApplicabilityId);
if (linkedSOA) {
props.onUnlink(linkedSOA.stateOfApplicabilityId, linkedSOA.controlId);
}
};
const handleUnlink = (stateOfApplicabilityId: string) => {
const linkedSOA = linkedSOAMap.get(stateOfApplicabilityId);
if (linkedSOA) {
props.onUnlink(
linkedSOA.stateOfApplicabilityId,
linkedSOA.controlId,
);
}
};
return (
<>
<DialogContent padded className="space-y-4">
{statesOfApplicability.length === 0 ? (
<div className="flex flex-col items-center justify-center py-12 text-center">
<div className="text-txt-secondary text-base mb-2">
{__("No states of applicability available")}
</div>
<div className="text-txt-tertiary text-sm">
{__("Create a state of applicability first to link it to this control")}
</div>
</div>
) : !selectedSOA ? (
<div className="space-y-2">
<div className="text-sm font-medium mb-2">{__("Select a state of applicability:")}</div>
{statesOfApplicability.map((soa) => {
const isLinked = linkedSOAIds.has(soa.id);
return (
<div
key={soa.id}
className={`border border-border-low rounded-lg p-3 flex items-center justify-between ${!isLinked ? 'hover:bg-hover cursor-pointer' : ''}`}
onClick={() => !isLinked && handleSelectSOA(soa)}
>
<div className="font-medium">{soa.name}</div>
{isLinked ? (
<div className="flex items-center gap-2" onClick={(e) => e.stopPropagation()}>
<Badge variant="success">{__("Linked")}</Badge>
<Button
variant="danger"
onClick={() => handleUnlink(soa.id)}
disabled={props.disabled}
>
{__("Unlink")}
</Button>
return (
<>
<DialogContent padded className="space-y-4">
{statesOfApplicability.length === 0 ? (
<div className="flex flex-col items-center justify-center py-12 text-center">
<div className="text-txt-secondary text-base mb-2">
{__("No states of applicability available")}
</div>
<div className="text-txt-tertiary text-sm">
{__(
"Create a state of applicability first to link it to this control",
)}
</div>
</div>
) : null}
</div>
);
})}
</div>
) : (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<div className="text-sm text-txt-secondary mb-1">{__("Selected:")}</div>
<div className="text-lg font-medium">{selectedSOA.name}</div>
</div>
<Button variant="tertiary" onClick={() => setSelectedSOA(null)}>
{__("Change")}
</Button>
</div>
) : !selectedSOA ? (
<div className="space-y-2">
<div className="text-sm font-medium mb-2">
{__("Select a state of applicability:")}
</div>
{statesOfApplicability.map((soa) => {
const isLinked = linkedSOAIds.has(soa.id);
return (
<div
key={soa.id}
className={`border border-border-low rounded-lg p-3 flex items-center justify-between ${!isLinked ? "hover:bg-hover cursor-pointer" : ""}`}
onClick={() =>
!isLinked && handleSelectSOA(soa)
}
>
<div className="font-medium">
{soa.name}
</div>
{isLinked ? (
<div
className="flex items-center gap-2"
onClick={(e) => e.stopPropagation()}
>
<Badge variant="success">
{__("Linked")}
</Badge>
<Button
variant="danger"
onClick={() =>
handleUnlink(soa.id)
}
disabled={props.disabled}
>
{__("Unlink")}
</Button>
</div>
) : null}
</div>
);
})}
</div>
) : (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<div className="text-sm text-txt-secondary mb-1">
{__("Selected:")}
</div>
<div className="text-lg font-medium">
{selectedSOA.name}
</div>
</div>
<Button
variant="tertiary"
onClick={() => setSelectedSOA(null)}
>
{__("Change")}
</Button>
</div>
<div className="border-t border-border-low pt-4 space-y-3">
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
checked={applicability}
onChange={(checked) => setApplicability(checked)}
/>
<span className="font-medium">{__("Applicable")}</span>
</label>
<div className="border-t border-border-low pt-4 space-y-3">
<label className="flex items-center gap-2 cursor-pointer">
<Checkbox
checked={applicability}
onChange={(checked) =>
setApplicability(checked)
}
/>
<span className="font-medium">
{__("Applicable")}
</span>
</label>
<div>
<label className="text-sm font-medium mb-1 block">
{__("Justification (optional)")}
</label>
<Textarea
placeholder={__("Add a justification...")}
value={justification}
onChange={(e) => setJustification(e.target.value)}
rows={3}
/>
</div>
</div>
</div>
)}
</DialogContent>
<DialogFooter exitLabel={__("Close")}>
{selectedSOA ? (
<>
<Button variant="secondary" onClick={() => setSelectedSOA(null)}>
{__("Back")}
</Button>
<Button variant="primary" onClick={handleLink} disabled={props.disabled}>
{__("Link")}
</Button>
</>
) : (
<></>
)}
</DialogFooter>
</>
);
<div>
<label className="text-sm font-medium mb-1 block">
{__("Justification (optional)")}
</label>
<Textarea
placeholder={__("Add a justification...")}
value={justification}
onChange={(e) =>
setJustification(e.target.value)
}
rows={3}
/>
</div>
</div>
</div>
)}
</DialogContent>
<DialogFooter exitLabel={__("Close")}>
{selectedSOA ? (
<>
<Button
variant="secondary"
onClick={() => setSelectedSOA(null)}
>
{__("Back")}
</Button>
<Button
variant="primary"
onClick={handleLink}
disabled={props.disabled}
>
{__("Link")}
</Button>
</>
) : (
<></>
)}
</DialogFooter>
</>
);
}

View File

@@ -1,100 +0,0 @@
/**
* @generated SignedSource<<fa19c3e1b91d31188625e48b8b6db7e9>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type LinkedStatesOfApplicabilityCardFragment$data = {
readonly applicability: boolean;
readonly controlId: string;
readonly id: string;
readonly justification: string | null | undefined;
readonly stateOfApplicability: {
readonly id: string;
readonly name: string;
};
readonly stateOfApplicabilityId: string;
readonly " $fragmentType": "LinkedStatesOfApplicabilityCardFragment";
};
export type LinkedStatesOfApplicabilityCardFragment$key = {
readonly " $data"?: LinkedStatesOfApplicabilityCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"LinkedStatesOfApplicabilityCardFragment">;
};
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "LinkedStatesOfApplicabilityCardFragment",
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "stateOfApplicabilityId",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "controlId",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "StateOfApplicability",
"kind": "LinkedField",
"name": "stateOfApplicability",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "applicability",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "justification",
"storageKey": null
}
],
"type": "StateOfApplicabilityControl",
"abstractKey": null
};
})();
(node as any).hash = "b9a9922b27f277a769025f11b0829bdc";
export default node;

View File

@@ -1,172 +0,0 @@
/**
* @generated SignedSource<<a49fb511ab396ea46b199b2ae08edfff>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type LinkedStatesOfApplicabilityDialogQuery$variables = {
organizationId: string;
};
export type LinkedStatesOfApplicabilityDialogQuery$data = {
readonly organization: {
readonly statesOfApplicability?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly name: string;
};
}>;
};
};
};
export type LinkedStatesOfApplicabilityDialogQuery = {
response: LinkedStatesOfApplicabilityDialogQuery$data;
variables: LinkedStatesOfApplicabilityDialogQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 100
}
],
"concreteType": "StateOfApplicabilityConnection",
"kind": "LinkedField",
"name": "statesOfApplicability",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "StateOfApplicabilityEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "StateOfApplicability",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "statesOfApplicability(first:100)"
}
],
"type": "Organization",
"abstractKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "LinkedStatesOfApplicabilityDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/)
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "LinkedStatesOfApplicabilityDialogQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v3/*: any*/),
(v2/*: any*/)
],
"storageKey": null
}
]
},
"params": {
"cacheID": "b36c3216f309865885892fce0d52eac9",
"id": null,
"metadata": {},
"name": "LinkedStatesOfApplicabilityDialogQuery",
"operationKind": "query",
"text": "query LinkedStatesOfApplicabilityDialogQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n statesOfApplicability(first: 100) {\n edges {\n node {\n id\n name\n }\n }\n }\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "a6ed2cd0171d834480319779e11fce99";
export default node;

View File

@@ -1,5 +1,5 @@
import { GraphQLCell } from "/components/table/GraphQLCell.tsx";
import type { PeopleGraphQuery } from "/hooks/graph/__generated__/PeopleGraphQuery.graphql.ts";
import type { PeopleGraphQuery } from "/__generated__/core/PeopleGraphQuery.graphql.ts";
import { peopleQuery } from "/hooks/graph/PeopleGraph.ts";
import { Avatar } from "@probo/ui";

View File

@@ -7,7 +7,7 @@ type Vendor = {
name: string;
websiteUrl: string | null | undefined;
};
import type { VendorGraphSelectQuery } from "/hooks/graph/__generated__/VendorGraphSelectQuery.graphql.ts";
import type { VendorGraphSelectQuery } from "/__generated__/core/VendorGraphSelectQuery.graphql.ts";
type Props = {
name: string;

View File

@@ -21,7 +21,7 @@ import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { PeopleSelectField } from "/components/form/PeopleSelectField";
import type { TaskFormDialogFragment$key } from "./__generated__/TaskFormDialogFragment.graphql";
import type { TaskFormDialogFragment$key } from "/__generated__/core/TaskFormDialogFragment.graphql";
import { MeasureSelectField } from "/components/form/MeasureSelectField";
import { Controller } from "react-hook-form";
import { updateStoreCounter } from "/hooks/useMutationWithIncrement";
@@ -76,7 +76,7 @@ const createTaskSchema = z.object({
assignedToId: z.string().optional().nullable(),
measureId: z.preprocess(
(val) => (val === "" || val == null ? null : val),
z.string().nullable().optional()
z.string().nullable().optional(),
),
deadline: z.string().optional().nullable(),
});
@@ -87,11 +87,11 @@ const updateTaskSchema = z.object({
timeEstimate: z.string().optional().nullable(),
assignedToId: z.preprocess(
(val) => (val === "" || val == null ? null : val),
z.string().nullable().optional()
z.string().nullable().optional(),
),
measureId: z.preprocess(
(val) => (val === "" || val == null ? null : val),
z.string().nullable().optional()
z.string().nullable().optional(),
),
deadline: z.string().optional().nullable(),
});
@@ -111,10 +111,13 @@ export default function TaskFormDialog(props: Props) {
const organizationId = useOrganizationId();
const task = useFragment(taskFragment, props.task);
const relayEnv = useRelayEnvironment();
const [mutate] = useMutationWithToasts(task? taskUpdateMutation : taskCreateMutation, {
successMessage: __(`Task ${task ? "updated" : "created"} successfully.`),
errorMessage: __(`Failed to ${task ? "update" : "create"} task`),
})
const [mutate] = useMutationWithToasts(
task ? taskUpdateMutation : taskCreateMutation,
{
successMessage: __(`Task ${task ? "updated" : "created"} successfully.`),
errorMessage: __(`Failed to ${task ? "update" : "create"} task`),
},
);
const isUpdating = !!task;

View File

@@ -20,7 +20,7 @@ import {
import { Fragment, use } from "react";
import { graphql, useMutation, useRelayEnvironment } from "react-relay";
import { Link, useLocation, useParams } from "react-router";
import type { TaskFormDialogFragment$key } from "./__generated__/TaskFormDialogFragment.graphql";
import type { TaskFormDialogFragment$key } from "/__generated__/core/TaskFormDialogFragment.graphql";
import TaskFormDialog, {
taskUpdateMutation,
} from "/components/tasks/TaskFormDialog";
@@ -71,8 +71,8 @@ export default function TasksCard({ tasks, connectionId }: Props) {
const { isAuthorized } = use(PermissionsContext);
const hasAnyAction = isAuthorized("Task", "updateTask") ||
isAuthorized("Task", "deleteTask");
const hasAnyAction =
isAuthorized("Task", "updateTask") || isAuthorized("Task", "deleteTask");
return (
<div className="space-y-6">
@@ -182,14 +182,14 @@ function TaskRow(props: TaskRowProps) {
relayEnv,
params.measureId,
"tasks(first:0)",
-1
-1,
);
}
},
}),
{
message: "Are you sure you want to delete this task?",
}
},
);
};

View File

@@ -1,249 +0,0 @@
/**
* @generated SignedSource<<c196829e8365168f07614d741242296c>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type CreateTaskInput = {
assignedToId?: string | null | undefined;
deadline?: any | null | undefined;
description?: string | null | undefined;
measureId?: string | null | undefined;
name: string;
organizationId: string;
timeEstimate?: any | null | undefined;
};
export type TaskFormDialogCreateMutation$variables = {
connections: ReadonlyArray<string>;
input: CreateTaskInput;
};
export type TaskFormDialogCreateMutation$data = {
readonly createTask: {
readonly taskEdge: {
readonly node: {
readonly " $fragmentSpreads": FragmentRefs<"TaskFormDialogFragment">;
};
};
};
};
export type TaskFormDialogCreateMutation = {
response: TaskFormDialogCreateMutation$data;
variables: TaskFormDialogCreateMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "connections"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
},
v2 = [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v4 = [
(v3/*: any*/)
];
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "TaskFormDialogCreateMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "CreateTaskPayload",
"kind": "LinkedField",
"name": "createTask",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TaskEdge",
"kind": "LinkedField",
"name": "taskEdge",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Task",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "TaskFormDialogFragment"
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v1/*: any*/),
(v0/*: any*/)
],
"kind": "Operation",
"name": "TaskFormDialogCreateMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "CreateTaskPayload",
"kind": "LinkedField",
"name": "createTask",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TaskEdge",
"kind": "LinkedField",
"name": "taskEdge",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Task",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "timeEstimate",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "assignedTo",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Measure",
"kind": "LinkedField",
"name": "measure",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"filters": null,
"handle": "prependEdge",
"key": "",
"kind": "LinkedHandle",
"name": "taskEdge",
"handleArgs": [
{
"kind": "Variable",
"name": "connections",
"variableName": "connections"
}
]
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "f605aed8a6f83a622d32e9b42f52f524",
"id": null,
"metadata": {},
"name": "TaskFormDialogCreateMutation",
"operationKind": "mutation",
"text": "mutation TaskFormDialogCreateMutation(\n $input: CreateTaskInput!\n) {\n createTask(input: $input) {\n taskEdge {\n node {\n ...TaskFormDialogFragment\n id\n }\n }\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n"
}
};
})();
(node as any).hash = "3a5194da3b1d57be836ca5e3405b2c3a";
export default node;

View File

@@ -1,115 +0,0 @@
/**
* @generated SignedSource<<1778d9b73cc75e2097e9c24fdfe83631>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type TaskState = "DONE" | "TODO";
import { FragmentRefs } from "relay-runtime";
export type TaskFormDialogFragment$data = {
readonly assignedTo: {
readonly id: string;
} | null | undefined;
readonly deadline: any | null | undefined;
readonly description: string | null | undefined;
readonly id: string;
readonly measure: {
readonly id: string;
} | null | undefined;
readonly name: string;
readonly state: TaskState;
readonly timeEstimate: any | null | undefined;
readonly " $fragmentType": "TaskFormDialogFragment";
};
export type TaskFormDialogFragment$key = {
readonly " $data"?: TaskFormDialogFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"TaskFormDialogFragment">;
};
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v1 = [
(v0/*: any*/)
];
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "TaskFormDialogFragment",
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "timeEstimate",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "assignedTo",
"plural": false,
"selections": (v1/*: any*/),
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Measure",
"kind": "LinkedField",
"name": "measure",
"plural": false,
"selections": (v1/*: any*/),
"storageKey": null
}
],
"type": "Task",
"abstractKey": null
};
})();
(node as any).hash = "3a4bede2199df797a20a6d87358d41cf";
export default node;

View File

@@ -1,201 +0,0 @@
/**
* @generated SignedSource<<8efad26dafbead83a13b59703edc7493>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type TaskState = "DONE" | "TODO";
export type UpdateTaskInput = {
assignedToId?: string | null | undefined;
deadline?: any | null | undefined;
description?: string | null | undefined;
measureId?: string | null | undefined;
name?: string | null | undefined;
state?: TaskState | null | undefined;
taskId: string;
timeEstimate?: any | null | undefined;
};
export type TaskFormDialogUpdateMutation$variables = {
input: UpdateTaskInput;
};
export type TaskFormDialogUpdateMutation$data = {
readonly updateTask: {
readonly task: {
readonly " $fragmentSpreads": FragmentRefs<"TaskFormDialogFragment">;
};
};
};
export type TaskFormDialogUpdateMutation = {
response: TaskFormDialogUpdateMutation$data;
variables: TaskFormDialogUpdateMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = [
(v2/*: any*/)
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "TaskFormDialogUpdateMutation",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": "UpdateTaskPayload",
"kind": "LinkedField",
"name": "updateTask",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Task",
"kind": "LinkedField",
"name": "task",
"plural": false,
"selections": [
{
"args": null,
"kind": "FragmentSpread",
"name": "TaskFormDialogFragment"
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "TaskFormDialogUpdateMutation",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": "UpdateTaskPayload",
"kind": "LinkedField",
"name": "updateTask",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Task",
"kind": "LinkedField",
"name": "task",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "timeEstimate",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deadline",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "assignedTo",
"plural": false,
"selections": (v3/*: any*/),
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Measure",
"kind": "LinkedField",
"name": "measure",
"plural": false,
"selections": (v3/*: any*/),
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "bfcbdf0470627b6f7b9a98a1722f7dca",
"id": null,
"metadata": {},
"name": "TaskFormDialogUpdateMutation",
"operationKind": "mutation",
"text": "mutation TaskFormDialogUpdateMutation(\n $input: UpdateTaskInput!\n) {\n updateTask(input: $input) {\n task {\n ...TaskFormDialogFragment\n id\n }\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n"
}
};
})();
(node as any).hash = "7c174671b0235b09cfe0fa98d4b3e629";
export default node;

View File

@@ -1,132 +0,0 @@
/**
* @generated SignedSource<<2866738fc7aeb6abd91cf4ed4ae72727>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DeleteTaskInput = {
taskId: string;
};
export type TasksCardDeleteMutation$variables = {
connections: ReadonlyArray<string>;
input: DeleteTaskInput;
};
export type TasksCardDeleteMutation$data = {
readonly deleteTask: {
readonly deletedTaskId: string;
};
};
export type TasksCardDeleteMutation = {
response: TasksCardDeleteMutation$data;
variables: TasksCardDeleteMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "connections"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
},
v2 = [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deletedTaskId",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "TasksCardDeleteMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DeleteTaskPayload",
"kind": "LinkedField",
"name": "deleteTask",
"plural": false,
"selections": [
(v3/*: any*/)
],
"storageKey": null
}
],
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v1/*: any*/),
(v0/*: any*/)
],
"kind": "Operation",
"name": "TasksCardDeleteMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DeleteTaskPayload",
"kind": "LinkedField",
"name": "deleteTask",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"filters": null,
"handle": "deleteEdge",
"key": "",
"kind": "ScalarHandle",
"name": "deletedTaskId",
"handleArgs": [
{
"kind": "Variable",
"name": "connections",
"variableName": "connections"
}
]
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "1ab085f9650841990644d2c106effac7",
"id": null,
"metadata": {},
"name": "TasksCardDeleteMutation",
"operationKind": "mutation",
"text": "mutation TasksCardDeleteMutation(\n $input: DeleteTaskInput!\n) {\n deleteTask(input: $input) {\n deletedTaskId\n }\n}\n"
}
};
})();
(node as any).hash = "803ffe0cb54f7fa5c840f6d3e4f2592b";
export default node;

View File

@@ -15,9 +15,15 @@ import {
import { useTranslate } from "@probo/i18n";
import { useFragment } from "react-relay";
import { useMemo, useState, useCallback, useEffect, use } from "react";
import { sprintf, getAuditStateVariant, getAuditStateLabel, formatDate, getTrustCenterVisibilityOptions } from "@probo/helpers";
import {
sprintf,
getAuditStateVariant,
getAuditStateLabel,
formatDate,
getTrustCenterVisibilityOptions,
} from "@probo/helpers";
import { useOrganizationId } from "/hooks/useOrganizationId";
import type { TrustCenterAuditsCardFragment$key } from "./__generated__/TrustCenterAuditsCardFragment.graphql";
import type { TrustCenterAuditsCardFragment$key } from "/__generated__/core/TrustCenterAuditsCardFragment.graphql";
import { PermissionsContext } from "/providers/PermissionsContext";
const trustCenterAuditFragment = graphql`
@@ -59,7 +65,10 @@ export function TrustCenterAuditsCard<Params>(props: Props<Params>) {
}, [props.audits, limit]);
const showMoreButton = limit !== null && props.audits.length > limit;
const onChangeVisibility = (auditId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => {
const onChangeVisibility = (
auditId: string,
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC",
) => {
props.onChangeVisibility({
variables: {
input: {
@@ -117,7 +126,10 @@ export function TrustCenterAuditsCard<Params>(props: Props<Params>) {
function AuditRow(props: {
auditFragmentRef: TrustCenterAuditsCardFragment$key;
onChangeVisibility: (auditId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => void;
onChangeVisibility: (
auditId: string,
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC",
) => void;
disabled?: boolean;
}) {
const { auditFragmentRef, onChangeVisibility, disabled } = props;
@@ -126,14 +138,19 @@ function AuditRow(props: {
const { __ } = useTranslate();
const [optimisticValue, setOptimisticValue] = useState<string | null>(null);
const { isAuthorized } = use(PermissionsContext);
const canUpdate = organizationId ? isAuthorized("TrustCenter", "updateTrustCenter") : false;
const canUpdate = organizationId
? isAuthorized("TrustCenter", "updateTrustCenter")
: false;
const handleValueChange = useCallback((value: string) => {
const stringValue = typeof value === 'string' ? value : '';
const typedValue = stringValue as "NONE" | "PRIVATE" | "PUBLIC";
setOptimisticValue(typedValue);
onChangeVisibility(audit.id, typedValue);
}, [audit.id, onChangeVisibility]);
const handleValueChange = useCallback(
(value: string) => {
const stringValue = typeof value === "string" ? value : "";
const typedValue = stringValue as "NONE" | "PRIVATE" | "PUBLIC";
setOptimisticValue(typedValue);
onChangeVisibility(audit.id, typedValue);
},
[audit.id, onChangeVisibility],
);
useEffect(() => {
if (optimisticValue && audit.trustCenterVisibility === optimisticValue) {
@@ -152,9 +169,7 @@ function AuditRow(props: {
return (
<Tr to={`/organizations/${organizationId}/audits/${audit.id}`}>
<Td>
<div className="flex gap-4 items-center">
{audit.framework.name}
</div>
<div className="flex gap-4 items-center">{audit.framework.name}</div>
</Td>
<Td>{audit.name || __("Untitled")}</Td>
<Td>{validUntilFormatted}</Td>
@@ -174,9 +189,7 @@ function AuditRow(props: {
{visibilityOptions.map((option) => (
<Option key={option.value} value={option.value}>
<div className="flex items-center justify-between w-full">
<Badge variant={option.variant}>
{option.label}
</Badge>
<Badge variant={option.variant}>{option.label}</Badge>
</div>
</Option>
))}

View File

@@ -15,7 +15,7 @@ import {
Badge,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { TrustCenterDocumentsCardFragment$key } from "./__generated__/TrustCenterDocumentsCardFragment.graphql";
import type { TrustCenterDocumentsCardFragment$key } from "/__generated__/core/TrustCenterDocumentsCardFragment.graphql";
import { useFragment } from "react-relay";
import { useMemo, useState, useCallback, useEffect, use } from "react";
import { sprintf, getTrustCenterVisibilityOptions } from "@probo/helpers";
@@ -64,7 +64,10 @@ export function TrustCenterDocumentsCard<Params>(props: Props<Params>) {
}, [props.documents, limit]);
const showMoreButton = limit !== null && props.documents.length > limit;
const onChangeVisibility = (documentId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => {
const onChangeVisibility = (
documentId: string,
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC",
) => {
props.onChangeVisibility({
variables: {
input: {
@@ -103,7 +106,6 @@ export function TrustCenterDocumentsCard<Params>(props: Props<Params>) {
disabled={props.disabled}
/>
))}
</Tbody>
</Table>
{showMoreButton && (
@@ -122,23 +124,32 @@ export function TrustCenterDocumentsCard<Params>(props: Props<Params>) {
function DocumentRow(props: {
documentFragmentRef: TrustCenterDocumentsCardFragment$key;
onChangeVisibility: (documentId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => void;
onChangeVisibility: (
documentId: string,
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC",
) => void;
disabled?: boolean;
}) {
const { documentFragmentRef, onChangeVisibility, disabled } = props;
const document = useFragment(trustCenterDocumentFragment, documentFragmentRef);
const document = useFragment(
trustCenterDocumentFragment,
documentFragmentRef,
);
const organizationId = useOrganizationId();
const { __ } = useTranslate();
const [optimisticValue, setOptimisticValue] = useState<string | null>(null);
const { isAuthorized } = use(PermissionsContext);
const canUpdate = isAuthorized("TrustCenter", "updateTrustCenter");
const handleValueChange = useCallback((value: string) => {
const stringValue = typeof value === 'string' ? value : '';
const typedValue = stringValue as "NONE" | "PRIVATE" | "PUBLIC";
setOptimisticValue(typedValue);
onChangeVisibility(document.id, typedValue);
}, [document.id, onChangeVisibility]);
const handleValueChange = useCallback(
(value: string) => {
const stringValue = typeof value === "string" ? value : "";
const typedValue = stringValue as "NONE" | "PRIVATE" | "PUBLIC";
setOptimisticValue(typedValue);
onChangeVisibility(document.id, typedValue);
},
[document.id, onChangeVisibility],
);
useEffect(() => {
if (optimisticValue && document.trustCenterVisibility === optimisticValue) {
@@ -153,15 +164,15 @@ function DocumentRow(props: {
return (
<Tr to={`/organizations/${organizationId}/documents/${document.id}`}>
<Td>
<div className="flex gap-4 items-center">
{document.title}
</div>
<div className="flex gap-4 items-center">{document.title}</div>
</Td>
<Td>
<DocumentTypeBadge type={document.documentType} />
</Td>
<Td>
<DocumentVersionBadge state={document.versions?.edges?.[0]?.node?.status} />
<DocumentVersionBadge
state={document.versions?.edges?.[0]?.node?.status}
/>
</Td>
<Td noLink width={130} className="pr-0">
<Field
@@ -174,9 +185,7 @@ function DocumentRow(props: {
{visibilityOptions.map((option) => (
<Option key={option.value} value={option.value}>
<div className="flex items-center justify-between w-full">
<Badge variant={option.variant}>
{option.label}
</Badge>
<Badge variant={option.variant}>{option.label}</Badge>
</div>
</Option>
))}

View File

@@ -16,7 +16,10 @@ import {
IconArrowLink,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import type { TrustCenterFilesCardFragment$key, TrustCenterFilesCardFragment$data } from "./__generated__/TrustCenterFilesCardFragment.graphql";
import type {
TrustCenterFilesCardFragment$key,
TrustCenterFilesCardFragment$data,
} from "/__generated__/core/TrustCenterFilesCardFragment.graphql";
import { useFragment } from "react-relay";
import { useMemo, useState, useCallback, useEffect, use } from "react";
import { sprintf, getTrustCenterVisibilityOptions } from "@probo/helpers";
@@ -61,7 +64,10 @@ export function TrustCenterFilesCard<Params>(props: Props<Params>) {
}, [props.files, limit]);
const showMoreButton = limit !== null && props.files.length > limit;
const onChangeVisibility = (fileId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => {
const onChangeVisibility = (
fileId: string,
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC",
) => {
props.onChangeVisibility({
variables: {
input: {
@@ -121,7 +127,10 @@ export function TrustCenterFilesCard<Params>(props: Props<Params>) {
function FileRowWrapper(props: {
fileFragmentRef: TrustCenterFilesCardFragment$key;
onChangeVisibility: (fileId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => void;
onChangeVisibility: (
fileId: string,
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC",
) => void;
onEdit: (file: { id: string; name: string; category: string }) => void;
onDelete: (id: string) => void;
disabled?: boolean;
@@ -140,7 +149,10 @@ function FileRowWrapper(props: {
function FileRow(props: {
file: TrustCenterFilesCardFragment$data;
onChangeVisibility: (fileId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => void;
onChangeVisibility: (
fileId: string,
trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC",
) => void;
onEdit: (file: { id: string; name: string; category: string }) => void;
onDelete: (id: string) => void;
disabled?: boolean;
@@ -151,12 +163,15 @@ function FileRow(props: {
const { isAuthorized } = use(PermissionsContext);
const canUpdate = isAuthorized("TrustCenter", "updateTrustCenter");
const handleValueChange = useCallback((value: string) => {
const stringValue = typeof value === 'string' ? value : '';
const typedValue = stringValue as "NONE" | "PRIVATE" | "PUBLIC";
setOptimisticValue(typedValue);
onChangeVisibility(file.id, typedValue);
}, [file.id, onChangeVisibility]);
const handleValueChange = useCallback(
(value: string) => {
const stringValue = typeof value === "string" ? value : "";
const typedValue = stringValue as "NONE" | "PRIVATE" | "PUBLIC";
setOptimisticValue(typedValue);
onChangeVisibility(file.id, typedValue);
},
[file.id, onChangeVisibility],
);
useEffect(() => {
if (optimisticValue && file.trustCenterVisibility === optimisticValue) {
@@ -171,9 +186,7 @@ function FileRow(props: {
return (
<Tr>
<Td>
<div className="flex gap-4 items-center">
{file.name}
</div>
<div className="flex gap-4 items-center">{file.name}</div>
</Td>
<Td>{file.category}</Td>
<Td>{formatDate(file.createdAt)}</Td>
@@ -188,9 +201,7 @@ function FileRow(props: {
{visibilityOptions.map((option) => (
<Option key={option.value} value={option.value}>
<div className="flex items-center justify-between w-full">
<Badge variant={option.variant}>
{option.label}
</Badge>
<Badge variant={option.variant}>{option.label}</Badge>
</div>
</Option>
))}
@@ -201,14 +212,22 @@ function FileRow(props: {
<Button
variant="secondary"
icon={IconArrowLink}
onClick={() => window.open(file.fileUrl, '_blank', 'noopener,noreferrer')}
onClick={() =>
window.open(file.fileUrl, "_blank", "noopener,noreferrer")
}
title={__("Download")}
/>
{isAuthorized("TrustCenterFile", "updateTrustCenterFile") && (
<Button
variant="secondary"
icon={IconPencil}
onClick={() => onEdit({ id: file.id, name: file.name, category: file.category })}
onClick={() =>
onEdit({
id: file.id,
name: file.name,
category: file.category,
})
}
disabled={disabled}
title={__("Edit")}
/>

View File

@@ -17,7 +17,7 @@ import { useFragment } from "react-relay";
import { useMemo, useState, use } from "react";
import { sprintf } from "@probo/helpers";
import { useOrganizationId } from "/hooks/useOrganizationId";
import type { TrustCenterVendorsCardFragment$key } from "./__generated__/TrustCenterVendorsCardFragment.graphql";
import type { TrustCenterVendorsCardFragment$key } from "/__generated__/core/TrustCenterVendorsCardFragment.graphql";
import { PermissionsContext } from "/providers/PermissionsContext";
const trustCenterVendorFragment = graphql`
@@ -83,7 +83,10 @@ export function TrustCenterVendorsCard<Params>(props: Props<Params>) {
<Tbody>
{vendors.length === 0 && (
<Tr>
<Td colSpan={canUpdate ? 4 : 3} className="text-center text-txt-secondary">
<Td
colSpan={canUpdate ? 4 : 3}
className="text-center text-txt-secondary"
>
{__("No vendors available")}
</Td>
</Tr>
@@ -126,14 +129,10 @@ function VendorRow(props: {
return (
<Tr to={`/organizations/${organizationId}/vendors/${vendor.id}/overview`}>
<Td>
<div className="flex gap-4 items-center">
{vendor.name}
</div>
<div className="flex gap-4 items-center">{vendor.name}</div>
</Td>
<Td>
<Badge variant="neutral">
{vendor.category}
</Badge>
<Badge variant="neutral">{vendor.category}</Badge>
</Td>
<Td>
<Badge variant={vendor.showOnTrustCenter ? "success" : "danger"}>
@@ -144,7 +143,9 @@ function VendorRow(props: {
<Td noLink width={100} className="text-end">
<Button
variant="secondary"
onClick={() => props.onToggleVisibility(vendor.id, !vendor.showOnTrustCenter)}
onClick={() =>
props.onToggleVisibility(vendor.id, !vendor.showOnTrustCenter)
}
icon={vendor.showOnTrustCenter ? IconCrossLargeX : IconCheckmark1}
disabled={props.disabled}
>

View File

@@ -1,110 +0,0 @@
/**
* @generated SignedSource<<155c0b8eda88507e66eb65e060ded192>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type AuditState = "COMPLETED" | "IN_PROGRESS" | "NOT_STARTED" | "OUTDATED" | "REJECTED";
export type TrustCenterVisibility = "NONE" | "PRIVATE" | "PUBLIC";
import { FragmentRefs } from "relay-runtime";
export type TrustCenterAuditsCardFragment$data = {
readonly createdAt: any;
readonly framework: {
readonly name: string;
};
readonly id: string;
readonly name: string | null | undefined;
readonly state: AuditState;
readonly trustCenterVisibility: TrustCenterVisibility;
readonly validFrom: any | null | undefined;
readonly validUntil: any | null | undefined;
readonly " $fragmentType": "TrustCenterAuditsCardFragment";
};
export type TrustCenterAuditsCardFragment$key = {
readonly " $data"?: TrustCenterAuditsCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"TrustCenterAuditsCardFragment">;
};
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "TrustCenterAuditsCardFragment",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
(v0/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v0/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validFrom",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "validUntil",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "state",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "trustCenterVisibility",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
}
],
"type": "Audit",
"abstractKey": null
};
})();
(node as any).hash = "c0f615fcad79ad39f60b48daacabdbbd";
export default node;

View File

@@ -1,135 +0,0 @@
/**
* @generated SignedSource<<40e45041dd8b72c58f1059d9cad3c15c>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type DocumentStatus = "DRAFT" | "PUBLISHED";
export type DocumentType = "ISMS" | "OTHER" | "POLICY" | "PROCEDURE";
export type TrustCenterVisibility = "NONE" | "PRIVATE" | "PUBLIC";
import { FragmentRefs } from "relay-runtime";
export type TrustCenterDocumentsCardFragment$data = {
readonly createdAt: any;
readonly documentType: DocumentType;
readonly id: string;
readonly title: string;
readonly trustCenterVisibility: TrustCenterVisibility;
readonly versions: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly status: DocumentStatus;
};
}>;
};
readonly " $fragmentType": "TrustCenterDocumentsCardFragment";
};
export type TrustCenterDocumentsCardFragment$key = {
readonly " $data"?: TrustCenterDocumentsCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"TrustCenterDocumentsCardFragment">;
};
const node: ReaderFragment = (function(){
var v0 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
};
return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "TrustCenterDocumentsCardFragment",
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "trustCenterVisibility",
"storageKey": null
},
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 1
}
],
"concreteType": "DocumentVersionConnection",
"kind": "LinkedField",
"name": "versions",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v0/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "versions(first:1)"
}
],
"type": "Document",
"abstractKey": null
};
})();
(node as any).hash = "a90715444be8a289eae6615ce44e244d";
export default node;

View File

@@ -1,91 +0,0 @@
/**
* @generated SignedSource<<0defaaf1ce3544420e8fbd9c9f3af139>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type TrustCenterVisibility = "NONE" | "PRIVATE" | "PUBLIC";
import { FragmentRefs } from "relay-runtime";
export type TrustCenterFilesCardFragment$data = {
readonly category: string;
readonly createdAt: any;
readonly fileUrl: string;
readonly id: string;
readonly name: string;
readonly trustCenterVisibility: TrustCenterVisibility;
readonly updatedAt: any;
readonly " $fragmentType": "TrustCenterFilesCardFragment";
};
export type TrustCenterFilesCardFragment$key = {
readonly " $data"?: TrustCenterFilesCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"TrustCenterFilesCardFragment">;
};
const node: ReaderFragment = {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "TrustCenterFilesCardFragment",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fileUrl",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "trustCenterVisibility",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
}
],
"type": "TrustCenterFile",
"abstractKey": null
};
(node as any).hash = "33cb01782ca37fc776cd8e5dfde20f76";
export default node;

View File

@@ -1,83 +0,0 @@
/**
* @generated SignedSource<<b3d65d827fc901aa002b24df72f79ee2>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL";
import { FragmentRefs } from "relay-runtime";
export type TrustCenterVendorsCardFragment$data = {
readonly category: VendorCategory;
readonly createdAt: any;
readonly description: string | null | undefined;
readonly id: string;
readonly name: string;
readonly showOnTrustCenter: boolean;
readonly " $fragmentType": "TrustCenterVendorsCardFragment";
};
export type TrustCenterVendorsCardFragment$key = {
readonly " $data"?: TrustCenterVendorsCardFragment$data;
readonly " $fragmentSpreads": FragmentRefs<"TrustCenterVendorsCardFragment">;
};
const node: ReaderFragment = {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "TrustCenterVendorsCardFragment",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "showOnTrustCenter",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
}
],
"type": "Vendor",
"abstractKey": null
};
(node as any).hash = "72b637589fd9299b5e982450fccbfd12";
export default node;