Rename State of Applicability to Statement of Applicability
Rename the entity across the full stack: database table (states_of_applicability → statements_of_applicability), Go model, GraphQL types, MCP specification, CLI commands, frontend components, routes, and display labels. Includes a migration to rename the table and its foreign key column. Widen sidebar from 260px to 280px to fit the longer label. Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -34,15 +34,15 @@ import { useEffect, useMemo, useState } from "react";
|
|||||||
import { useFragment } from "react-relay";
|
import { useFragment } from "react-relay";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import type { LinkedStatesOfApplicabilityCardFragment$key } from "#/__generated__/core/LinkedStatesOfApplicabilityCardFragment.graphql";
|
import type { LinkedStatementsOfApplicabilityCardFragment$key } from "#/__generated__/core/LinkedStatementsOfApplicabilityCardFragment.graphql";
|
||||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
|
||||||
import { LinkedStatesOfApplicabilityDialog } from "./LinkedStatesOfApplicabilityDialog";
|
import { LinkedStatementsOfApplicabilityDialog } from "./LinkedStatementsOfApplicabilityDialog";
|
||||||
|
|
||||||
const linkedStateOfApplicabilityFragment = graphql`
|
const linkedStatementOfApplicabilityFragment = graphql`
|
||||||
fragment LinkedStatesOfApplicabilityCardFragment on ApplicabilityStatement {
|
fragment LinkedStatementsOfApplicabilityCardFragment on ApplicabilityStatement {
|
||||||
id
|
id
|
||||||
stateOfApplicability {
|
statementOfApplicability {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ const linkedStateOfApplicabilityFragment = graphql`
|
|||||||
type AttachMutation<Params> = (p: {
|
type AttachMutation<Params> = (p: {
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId: string;
|
statementOfApplicabilityId: string;
|
||||||
applicability: boolean;
|
applicability: boolean;
|
||||||
justification: string | null;
|
justification: string | null;
|
||||||
} & Params;
|
} & Params;
|
||||||
@@ -68,7 +68,7 @@ type AttachMutation<Params> = (p: {
|
|||||||
type DetachMutation = (p: {
|
type DetachMutation = (p: {
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId: string;
|
statementOfApplicabilityId: string;
|
||||||
controlId: string;
|
controlId: string;
|
||||||
};
|
};
|
||||||
connections: string[];
|
connections: string[];
|
||||||
@@ -76,7 +76,7 @@ type DetachMutation = (p: {
|
|||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
type Props<Params> = {
|
type Props<Params> = {
|
||||||
statesOfApplicability: readonly (LinkedStatesOfApplicabilityCardFragment$key & {
|
statementsOfApplicability: readonly (LinkedStatementsOfApplicabilityCardFragment$key & {
|
||||||
id: string;
|
id: string;
|
||||||
})[];
|
})[];
|
||||||
params: Params;
|
params: Params;
|
||||||
@@ -88,7 +88,7 @@ type Props<Params> = {
|
|||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
|
export function LinkedStatementsOfApplicabilityCard<Params>(props: Props<Params>) {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
|
|
||||||
const [limit, setLimit] = useState<number | null>(
|
const [limit, setLimit] = useState<number | null>(
|
||||||
@@ -96,30 +96,30 @@ export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const [linkedInfo, setLinkedInfo] = useState<
|
const [linkedInfo, setLinkedInfo] = useState<
|
||||||
{ stateOfApplicabilityId: string; controlId: string }[]
|
{ statementOfApplicabilityId: string; controlId: string }[]
|
||||||
>([]);
|
>([]);
|
||||||
|
|
||||||
const statesOfApplicability = useMemo(() => {
|
const statementsOfApplicability = useMemo(() => {
|
||||||
return limit
|
return limit
|
||||||
? props.statesOfApplicability.slice(0, limit)
|
? props.statementsOfApplicability.slice(0, limit)
|
||||||
: props.statesOfApplicability;
|
: props.statementsOfApplicability;
|
||||||
}, [props.statesOfApplicability, limit]);
|
}, [props.statementsOfApplicability, limit]);
|
||||||
|
|
||||||
const showMoreButton
|
const showMoreButton
|
||||||
= limit !== null && props.statesOfApplicability.length > limit;
|
= limit !== null && props.statementsOfApplicability.length > limit;
|
||||||
const variant = props.variant ?? "table";
|
const variant = props.variant ?? "table";
|
||||||
|
|
||||||
const linkedData = linkedInfo;
|
const linkedData = linkedInfo;
|
||||||
|
|
||||||
const onAttach = (
|
const onAttach = (
|
||||||
stateOfApplicabilityId: string,
|
statementOfApplicabilityId: string,
|
||||||
applicability: boolean,
|
applicability: boolean,
|
||||||
justification: string | null,
|
justification: string | null,
|
||||||
) => {
|
) => {
|
||||||
props.onAttach({
|
props.onAttach({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
applicability,
|
applicability,
|
||||||
justification,
|
justification,
|
||||||
...props.params,
|
...props.params,
|
||||||
@@ -129,11 +129,11 @@ export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDetach = (stateOfApplicabilityId: string, controlId: string) => {
|
const onDetach = (statementOfApplicabilityId: string, controlId: string) => {
|
||||||
props.onDetach({
|
props.onDetach({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
controlId,
|
controlId,
|
||||||
},
|
},
|
||||||
connections: [props.connectionId],
|
connections: [props.connectionId],
|
||||||
@@ -145,7 +145,7 @@ export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper padded className="space-y-[10px]">
|
<Wrapper padded className="space-y-[10px]">
|
||||||
{props.statesOfApplicability.map((soa, idx) => (
|
{props.statementsOfApplicability.map((soa, idx) => (
|
||||||
<LinkedInfoExtractor
|
<LinkedInfoExtractor
|
||||||
key={idx}
|
key={idx}
|
||||||
fragment={soa}
|
fragment={soa}
|
||||||
@@ -153,8 +153,8 @@ export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
|
|||||||
setLinkedInfo((prev) => {
|
setLinkedInfo((prev) => {
|
||||||
const exists = prev.some(
|
const exists = prev.some(
|
||||||
p =>
|
p =>
|
||||||
p.stateOfApplicabilityId
|
p.statementOfApplicabilityId
|
||||||
=== info.stateOfApplicabilityId
|
=== info.statementOfApplicabilityId
|
||||||
&& p.controlId === info.controlId,
|
&& p.controlId === info.controlId,
|
||||||
);
|
);
|
||||||
return exists ? prev : [...prev, info];
|
return exists ? prev : [...prev, info];
|
||||||
@@ -165,20 +165,20 @@ export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
|
|||||||
{variant === "card" && (
|
{variant === "card" && (
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<div className="text-lg font-semibold">
|
<div className="text-lg font-semibold">
|
||||||
{__("States of Applicability")}
|
{__("Statements of Applicability")}
|
||||||
</div>
|
</div>
|
||||||
{!props.readOnly && (
|
{!props.readOnly && (
|
||||||
<LinkedStatesOfApplicabilityDialog
|
<LinkedStatementsOfApplicabilityDialog
|
||||||
connectionId={props.connectionId}
|
connectionId={props.connectionId}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
linkedStatesOfApplicability={linkedData}
|
linkedStatementsOfApplicability={linkedData}
|
||||||
onLink={onAttach}
|
onLink={onAttach}
|
||||||
onUnlink={onDetach}
|
onUnlink={onDetach}
|
||||||
>
|
>
|
||||||
<Button variant="tertiary" icon={IconPlusLarge}>
|
<Button variant="tertiary" icon={IconPlusLarge}>
|
||||||
{__("Link state of applicability")}
|
{__("Link statement of applicability")}
|
||||||
</Button>
|
</Button>
|
||||||
</LinkedStatesOfApplicabilityDialog>
|
</LinkedStatementsOfApplicabilityDialog>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -192,36 +192,36 @@ export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
|
|||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{statesOfApplicability.length === 0 && (
|
{statementsOfApplicability.length === 0 && (
|
||||||
<Tr>
|
<Tr>
|
||||||
<Td
|
<Td
|
||||||
colSpan={props.readOnly ? 3 : 4}
|
colSpan={props.readOnly ? 3 : 4}
|
||||||
className="text-center text-txt-secondary"
|
className="text-center text-txt-secondary"
|
||||||
>
|
>
|
||||||
{__("No states of applicability linked")}
|
{__("No statements of applicability linked")}
|
||||||
</Td>
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
)}
|
)}
|
||||||
{statesOfApplicability.map(soa => (
|
{statementsOfApplicability.map(soa => (
|
||||||
<StateOfApplicabilityRow
|
<StatementOfApplicabilityRow
|
||||||
key={soa.id}
|
key={soa.id}
|
||||||
stateOfApplicability={soa}
|
statementOfApplicability={soa}
|
||||||
onClick={onDetach}
|
onClick={onDetach}
|
||||||
readOnly={props.readOnly}
|
readOnly={props.readOnly}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{variant === "table" && !props.readOnly && (
|
{variant === "table" && !props.readOnly && (
|
||||||
<LinkedStatesOfApplicabilityDialog
|
<LinkedStatementsOfApplicabilityDialog
|
||||||
connectionId={props.connectionId}
|
connectionId={props.connectionId}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
linkedStatesOfApplicability={linkedData}
|
linkedStatementsOfApplicability={linkedData}
|
||||||
onLink={onAttach}
|
onLink={onAttach}
|
||||||
onUnlink={onDetach}
|
onUnlink={onDetach}
|
||||||
>
|
>
|
||||||
<TrButton colspan={4} icon={IconPlusLarge}>
|
<TrButton colspan={4} icon={IconPlusLarge}>
|
||||||
{__("Link state of applicability")}
|
{__("Link statement of applicability")}
|
||||||
</TrButton>
|
</TrButton>
|
||||||
</LinkedStatesOfApplicabilityDialog>
|
</LinkedStatementsOfApplicabilityDialog>
|
||||||
)}
|
)}
|
||||||
</Tbody>
|
</Tbody>
|
||||||
</Table>
|
</Table>
|
||||||
@@ -233,7 +233,7 @@ export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
|
|||||||
>
|
>
|
||||||
{sprintf(
|
{sprintf(
|
||||||
__("Show %d more"),
|
__("Show %d more"),
|
||||||
props.statesOfApplicability.length - limit,
|
props.statementsOfApplicability.length - limit,
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
@@ -242,48 +242,48 @@ export function LinkedStatesOfApplicabilityCard<Params>(props: Props<Params>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function LinkedInfoExtractor(props: {
|
function LinkedInfoExtractor(props: {
|
||||||
fragment: LinkedStatesOfApplicabilityCardFragment$key;
|
fragment: LinkedStatementsOfApplicabilityCardFragment$key;
|
||||||
onExtracted: (info: {
|
onExtracted: (info: {
|
||||||
stateOfApplicabilityId: string;
|
statementOfApplicabilityId: string;
|
||||||
controlId: string;
|
controlId: string;
|
||||||
}) => void;
|
}) => void;
|
||||||
}) {
|
}) {
|
||||||
const { onExtracted, fragment } = props;
|
const { onExtracted, fragment } = props;
|
||||||
|
|
||||||
const data = useFragment(
|
const data = useFragment(
|
||||||
linkedStateOfApplicabilityFragment,
|
linkedStatementOfApplicabilityFragment,
|
||||||
fragment,
|
fragment,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onExtracted({
|
onExtracted({
|
||||||
stateOfApplicabilityId: data.stateOfApplicability.id,
|
statementOfApplicabilityId: data.statementOfApplicability.id,
|
||||||
controlId: data.control.id,
|
controlId: data.control.id,
|
||||||
});
|
});
|
||||||
}, [data.stateOfApplicability.id, data.control.id, onExtracted]);
|
}, [data.statementOfApplicability.id, data.control.id, onExtracted]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function StateOfApplicabilityRow(props: {
|
function StatementOfApplicabilityRow(props: {
|
||||||
stateOfApplicability: LinkedStatesOfApplicabilityCardFragment$key & {
|
statementOfApplicability: LinkedStatementsOfApplicabilityCardFragment$key & {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
onClick: (stateOfApplicabilityId: string, controlId: string) => void;
|
onClick: (statementOfApplicabilityId: string, controlId: string) => void;
|
||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const soa = useFragment(
|
const soa = useFragment(
|
||||||
linkedStateOfApplicabilityFragment,
|
linkedStatementOfApplicabilityFragment,
|
||||||
props.stateOfApplicability,
|
props.statementOfApplicability,
|
||||||
);
|
);
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tr
|
<Tr
|
||||||
to={`/organizations/${organizationId}/states-of-applicability/${soa.stateOfApplicability.id}`}
|
to={`/organizations/${organizationId}/statements-of-applicability/${soa.statementOfApplicability.id}`}
|
||||||
>
|
>
|
||||||
<Td>{soa.stateOfApplicability.name}</Td>
|
<Td>{soa.statementOfApplicability.name}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
<Badge variant={soa.applicability ? "success" : "danger"}>
|
<Badge variant={soa.applicability ? "success" : "danger"}>
|
||||||
{soa.applicability
|
{soa.applicability
|
||||||
@@ -298,7 +298,7 @@ function StateOfApplicabilityRow(props: {
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
props.onClick(
|
props.onClick(
|
||||||
soa.stateOfApplicability.id,
|
soa.statementOfApplicability.id,
|
||||||
soa.control.id,
|
soa.control.id,
|
||||||
)}
|
)}
|
||||||
icon={IconTrashCan}
|
icon={IconTrashCan}
|
||||||
@@ -27,14 +27,14 @@ import { Suspense, useRef, useState } from "react";
|
|||||||
import { useLazyLoadQuery } from "react-relay";
|
import { useLazyLoadQuery } from "react-relay";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import type { LinkedStatesOfApplicabilityDialogQuery } from "#/__generated__/core/LinkedStatesOfApplicabilityDialogQuery.graphql";
|
import type { LinkedStatementsOfApplicabilityDialogQuery } from "#/__generated__/core/LinkedStatementsOfApplicabilityDialogQuery.graphql";
|
||||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
|
||||||
const query = graphql`
|
const query = graphql`
|
||||||
query LinkedStatesOfApplicabilityDialogQuery($organizationId: ID!) {
|
query LinkedStatementsOfApplicabilityDialogQuery($organizationId: ID!) {
|
||||||
organization: node(id: $organizationId) {
|
organization: node(id: $organizationId) {
|
||||||
... on Organization {
|
... on Organization {
|
||||||
statesOfApplicability(first: 100) {
|
statementsOfApplicability(first: 100) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
@@ -48,7 +48,7 @@ const query = graphql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
type LinkedSOAInfo = {
|
type LinkedSOAInfo = {
|
||||||
stateOfApplicabilityId: string;
|
statementOfApplicabilityId: string;
|
||||||
controlId: string;
|
controlId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,16 +56,16 @@ type Props = {
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
connectionId: string;
|
connectionId: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
linkedStatesOfApplicability: readonly LinkedSOAInfo[];
|
linkedStatementsOfApplicability: readonly LinkedSOAInfo[];
|
||||||
onLink: (
|
onLink: (
|
||||||
stateOfApplicabilityId: string,
|
statementOfApplicabilityId: string,
|
||||||
applicability: boolean,
|
applicability: boolean,
|
||||||
justification: string | null,
|
justification: string | null,
|
||||||
) => void;
|
) => void;
|
||||||
onUnlink: (stateOfApplicabilityId: string, controlId: string) => void;
|
onUnlink: (statementOfApplicabilityId: string, controlId: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function LinkedStatesOfApplicabilityDialog({
|
export function LinkedStatementsOfApplicabilityDialog({
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: Props) {
|
}: Props) {
|
||||||
@@ -75,10 +75,10 @@ export function LinkedStatesOfApplicabilityDialog({
|
|||||||
<Dialog
|
<Dialog
|
||||||
ref={dialogRef}
|
ref={dialogRef}
|
||||||
trigger={children}
|
trigger={children}
|
||||||
title="Link State of Applicability"
|
title="Link Statement of Applicability"
|
||||||
>
|
>
|
||||||
<Suspense fallback={<div>Loading...</div>}>
|
<Suspense fallback={<div>Loading...</div>}>
|
||||||
<LinkedStatesOfApplicabilityDialogContent
|
<LinkedStatementsOfApplicabilityDialogContent
|
||||||
{...props}
|
{...props}
|
||||||
onClose={() => dialogRef.current?.close()}
|
onClose={() => dialogRef.current?.close()}
|
||||||
/>
|
/>
|
||||||
@@ -87,7 +87,7 @@ export function LinkedStatesOfApplicabilityDialog({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function LinkedStatesOfApplicabilityDialogContent(
|
function LinkedStatementsOfApplicabilityDialogContent(
|
||||||
props: Omit<Props, "children"> & { onClose: () => void },
|
props: Omit<Props, "children"> & { onClose: () => void },
|
||||||
) {
|
) {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
@@ -99,7 +99,7 @@ function LinkedStatesOfApplicabilityDialogContent(
|
|||||||
const [applicability, setApplicability] = useState(true);
|
const [applicability, setApplicability] = useState(true);
|
||||||
const [justification, setJustification] = useState("");
|
const [justification, setJustification] = useState("");
|
||||||
|
|
||||||
const data = useLazyLoadQuery<LinkedStatesOfApplicabilityDialogQuery>(
|
const data = useLazyLoadQuery<LinkedStatementsOfApplicabilityDialogQuery>(
|
||||||
query,
|
query,
|
||||||
{
|
{
|
||||||
organizationId,
|
organizationId,
|
||||||
@@ -108,18 +108,18 @@ function LinkedStatesOfApplicabilityDialogContent(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const linkedSOAIds = new Set(
|
const linkedSOAIds = new Set(
|
||||||
props.linkedStatesOfApplicability.map(
|
props.linkedStatementsOfApplicability.map(
|
||||||
soa => soa.stateOfApplicabilityId,
|
soa => soa.statementOfApplicabilityId,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const linkedSOAMap = new Map(
|
const linkedSOAMap = new Map(
|
||||||
props.linkedStatesOfApplicability.map(soa => [
|
props.linkedStatementsOfApplicability.map(soa => [
|
||||||
soa.stateOfApplicabilityId,
|
soa.statementOfApplicabilityId,
|
||||||
soa,
|
soa,
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
const statesOfApplicability
|
const statementsOfApplicability
|
||||||
= data.organization?.statesOfApplicability?.edges.map(
|
= data.organization?.statementsOfApplicability?.edges.map(
|
||||||
edge => edge.node,
|
edge => edge.node,
|
||||||
) ?? [];
|
) ?? [];
|
||||||
|
|
||||||
@@ -140,11 +140,11 @@ function LinkedStatesOfApplicabilityDialogContent(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUnlink = (stateOfApplicabilityId: string) => {
|
const handleUnlink = (statementOfApplicabilityId: string) => {
|
||||||
const linkedSOA = linkedSOAMap.get(stateOfApplicabilityId);
|
const linkedSOA = linkedSOAMap.get(statementOfApplicabilityId);
|
||||||
if (linkedSOA) {
|
if (linkedSOA) {
|
||||||
props.onUnlink(
|
props.onUnlink(
|
||||||
linkedSOA.stateOfApplicabilityId,
|
linkedSOA.statementOfApplicabilityId,
|
||||||
linkedSOA.controlId,
|
linkedSOA.controlId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -153,15 +153,15 @@ function LinkedStatesOfApplicabilityDialogContent(
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DialogContent padded className="space-y-4">
|
<DialogContent padded className="space-y-4">
|
||||||
{statesOfApplicability.length === 0
|
{statementsOfApplicability.length === 0
|
||||||
? (
|
? (
|
||||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||||
<div className="text-txt-secondary text-base mb-2">
|
<div className="text-txt-secondary text-base mb-2">
|
||||||
{__("No states of applicability available")}
|
{__("No statements of applicability available")}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-txt-tertiary text-sm">
|
<div className="text-txt-tertiary text-sm">
|
||||||
{__(
|
{__(
|
||||||
"Create a state of applicability first to link it to this control",
|
"Create a statement of applicability first to link it to this control",
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -170,9 +170,9 @@ function LinkedStatesOfApplicabilityDialogContent(
|
|||||||
? (
|
? (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="text-sm font-medium mb-2">
|
<div className="text-sm font-medium mb-2">
|
||||||
{__("Select a state of applicability:")}
|
{__("Select a statement of applicability:")}
|
||||||
</div>
|
</div>
|
||||||
{statesOfApplicability.map((soa) => {
|
{statementsOfApplicability.map((soa) => {
|
||||||
const isLinked = linkedSOAIds.has(soa.id);
|
const isLinked = linkedSOAIds.has(soa.id);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -64,8 +64,8 @@ const fragment = graphql`
|
|||||||
canListSnapshots: permission(action: "core:snapshot:list")
|
canListSnapshots: permission(action: "core:snapshot:list")
|
||||||
canGetTrustCenter: permission(action: "core:trust-center:get")
|
canGetTrustCenter: permission(action: "core:trust-center:get")
|
||||||
canUpdateOrganization: permission(action: "iam:organization:update")
|
canUpdateOrganization: permission(action: "iam:organization:update")
|
||||||
canListStatesOfApplicability: permission(
|
canListStatementsOfApplicability: permission(
|
||||||
action: "core:state-of-applicability:list"
|
action: "core:statement-of-applicability:list"
|
||||||
)
|
)
|
||||||
canListAccessReviewCampaigns: permission(
|
canListAccessReviewCampaigns: permission(
|
||||||
action: "core:access-review-campaign:list"
|
action: "core:access-review-campaign:list"
|
||||||
@@ -183,11 +183,11 @@ export function Sidebar(props: { fKey: SidebarFragment$key }) {
|
|||||||
to={`${prefix}/processing-activities`}
|
to={`${prefix}/processing-activities`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{organization.canListStatesOfApplicability && (
|
{organization.canListStatementsOfApplicability && (
|
||||||
<SidebarItem
|
<SidebarItem
|
||||||
label={__("States of Applicability")}
|
label={__("Statements of Applicability")}
|
||||||
icon={IconPageCheck}
|
icon={IconPageCheck}
|
||||||
to={`${prefix}/states-of-applicability`}
|
to={`${prefix}/statements-of-applicability`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{organization.canListRightsRequests && (
|
{organization.canListRightsRequests && (
|
||||||
|
|||||||
@@ -42,56 +42,56 @@ import {
|
|||||||
import { useNavigate, useParams } from "react-router";
|
import { useNavigate, useParams } from "react-router";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import type { StateOfApplicabilityDetailPageDeleteMutation } from "#/__generated__/core/StateOfApplicabilityDetailPageDeleteMutation.graphql";
|
import type { StatementOfApplicabilityDetailPageDeleteMutation } from "#/__generated__/core/StatementOfApplicabilityDetailPageDeleteMutation.graphql";
|
||||||
import type { StateOfApplicabilityDetailPageExportMutation } from "#/__generated__/core/StateOfApplicabilityDetailPageExportMutation.graphql";
|
import type { StatementOfApplicabilityDetailPageExportMutation } from "#/__generated__/core/StatementOfApplicabilityDetailPageExportMutation.graphql";
|
||||||
import type { StateOfApplicabilityDetailPageQuery } from "#/__generated__/core/StateOfApplicabilityDetailPageQuery.graphql";
|
import type { StatementOfApplicabilityDetailPageQuery } from "#/__generated__/core/StatementOfApplicabilityDetailPageQuery.graphql";
|
||||||
import type { StateOfApplicabilityDetailPageUpdateMutation } from "#/__generated__/core/StateOfApplicabilityDetailPageUpdateMutation.graphql";
|
import type { StatementOfApplicabilityDetailPageUpdateMutation } from "#/__generated__/core/StatementOfApplicabilityDetailPageUpdateMutation.graphql";
|
||||||
import { PeopleSelectField } from "#/components/form/PeopleSelectField";
|
import { PeopleSelectField } from "#/components/form/PeopleSelectField";
|
||||||
import { SnapshotBanner } from "#/components/SnapshotBanner";
|
import { SnapshotBanner } from "#/components/SnapshotBanner";
|
||||||
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
||||||
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
|
||||||
import StateOfApplicabilityControlsTab from "./tabs/StateOfApplicabilityControlsTab";
|
import StatementOfApplicabilityControlsTab from "./tabs/StatementOfApplicabilityControlsTab";
|
||||||
|
|
||||||
export const stateOfApplicabilityDetailPageQuery = graphql`
|
export const statementOfApplicabilityDetailPageQuery = graphql`
|
||||||
query StateOfApplicabilityDetailPageQuery($stateOfApplicabilityId: ID!) {
|
query StatementOfApplicabilityDetailPageQuery($statementOfApplicabilityId: ID!) {
|
||||||
node(id: $stateOfApplicabilityId) {
|
node(id: $statementOfApplicabilityId) {
|
||||||
... on StateOfApplicability {
|
... on StatementOfApplicability {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
snapshotId
|
snapshotId
|
||||||
createdAt
|
createdAt
|
||||||
updatedAt
|
updatedAt
|
||||||
canUpdate: permission(action: "core:state-of-applicability:update")
|
canUpdate: permission(action: "core:statement-of-applicability:update")
|
||||||
canDelete: permission(action: "core:state-of-applicability:delete")
|
canDelete: permission(action: "core:statement-of-applicability:delete")
|
||||||
canExport: permission(action: "core:state-of-applicability:export")
|
canExport: permission(action: "core:statement-of-applicability:export")
|
||||||
owner {
|
owner {
|
||||||
id
|
id
|
||||||
fullName
|
fullName
|
||||||
}
|
}
|
||||||
...StateOfApplicabilityControlsTabFragment
|
...StatementOfApplicabilityControlsTabFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const exportMutation = graphql`
|
const exportMutation = graphql`
|
||||||
mutation StateOfApplicabilityDetailPageExportMutation(
|
mutation StatementOfApplicabilityDetailPageExportMutation(
|
||||||
$input: ExportStateOfApplicabilityPDFInput!
|
$input: ExportStatementOfApplicabilityPDFInput!
|
||||||
) {
|
) {
|
||||||
exportStateOfApplicabilityPDF(input: $input) {
|
exportStatementOfApplicabilityPDF(input: $input) {
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const updateMutation = graphql`
|
const updateMutation = graphql`
|
||||||
mutation StateOfApplicabilityDetailPageUpdateMutation(
|
mutation StatementOfApplicabilityDetailPageUpdateMutation(
|
||||||
$input: UpdateStateOfApplicabilityInput!
|
$input: UpdateStatementOfApplicabilityInput!
|
||||||
) {
|
) {
|
||||||
updateStateOfApplicability(input: $input) {
|
updateStatementOfApplicability(input: $input) {
|
||||||
stateOfApplicability {
|
statementOfApplicability {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
sourceId
|
sourceId
|
||||||
@@ -108,74 +108,75 @@ const updateMutation = graphql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const deleteMutation = graphql`
|
const deleteMutation = graphql`
|
||||||
mutation StateOfApplicabilityDetailPageDeleteMutation(
|
mutation StatementOfApplicabilityDetailPageDeleteMutation(
|
||||||
$input: DeleteStateOfApplicabilityInput!
|
$input: DeleteStatementOfApplicabilityInput!
|
||||||
$connections: [ID!]!
|
$connections: [ID!]!
|
||||||
) {
|
) {
|
||||||
deleteStateOfApplicability(input: $input) {
|
deleteStatementOfApplicability(input: $input) {
|
||||||
deletedStateOfApplicabilityId @deleteEdge(connections: $connections)
|
deletedStatementOfApplicabilityId @deleteEdge(connections: $connections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StateOfApplicabilityConnectionKey = "StatesOfApplicabilityPage_statesOfApplicability";
|
const StatementOfApplicabilityConnectionKey = "StatementsOfApplicabilityPage_statementsOfApplicability";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
queryRef: PreloadedQuery<StateOfApplicabilityDetailPageQuery>;
|
queryRef: PreloadedQuery<StatementOfApplicabilityDetailPageQuery>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function StateOfApplicabilityDetailPage(props: Props) {
|
export default function StatementOfApplicabilityDetailPage(props: Props) {
|
||||||
const { stateOfApplicabilityId, snapshotId } = useParams<{
|
const { statementOfApplicabilityId, snapshotId } = useParams<{
|
||||||
stateOfApplicabilityId: string;
|
statementOfApplicabilityId: string;
|
||||||
snapshotId?: string;
|
snapshotId?: string;
|
||||||
}>();
|
}>();
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const data = usePreloadedQuery(stateOfApplicabilityDetailPageQuery, props.queryRef);
|
const data = usePreloadedQuery(statementOfApplicabilityDetailPageQuery, props.queryRef);
|
||||||
const stateOfApplicability = data.node;
|
const statementOfApplicability = data.node;
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const isSnapshotMode = Boolean(snapshotId);
|
const isSnapshotMode = Boolean(snapshotId);
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
if (!stateOfApplicabilityId || !stateOfApplicability) {
|
if (!statementOfApplicabilityId || !statementOfApplicability) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Cannot load state of applicability detail page without stateOfApplicabilityId parameter",
|
"Cannot load statement of applicability detail page without statementOfApplicabilityId parameter",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateSnapshotConsistency(stateOfApplicability, snapshotId);
|
validateSnapshotConsistency(statementOfApplicability, snapshotId);
|
||||||
|
|
||||||
const connectionId = ConnectionHandler.getConnectionID(
|
const connectionId = ConnectionHandler.getConnectionID(
|
||||||
organizationId,
|
organizationId,
|
||||||
StateOfApplicabilityConnectionKey,
|
StatementOfApplicabilityConnectionKey,
|
||||||
{ filter: { snapshotId: snapshotId ?? null } },
|
{ filter: { snapshotId: snapshotId ?? null } },
|
||||||
);
|
);
|
||||||
|
|
||||||
const [deleteStateOfApplicability] = useMutation<StateOfApplicabilityDetailPageDeleteMutation>(deleteMutation);
|
const [deleteStatementOfApplicability]
|
||||||
|
= useMutation<StatementOfApplicabilityDetailPageDeleteMutation>(deleteMutation);
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
if (!stateOfApplicability.id || !stateOfApplicability.name) {
|
if (!statementOfApplicability.id || !statementOfApplicability.name) {
|
||||||
return alert(__("Failed to delete state of applicability: missing id or name"));
|
return alert(__("Failed to delete statement of applicability: missing id or name"));
|
||||||
}
|
}
|
||||||
confirm(
|
confirm(
|
||||||
() =>
|
() =>
|
||||||
promisifyMutation(deleteStateOfApplicability)({
|
promisifyMutation(deleteStatementOfApplicability)({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId: stateOfApplicability.id!,
|
statementOfApplicabilityId: statementOfApplicability.id!,
|
||||||
},
|
},
|
||||||
connections: [connectionId],
|
connections: [connectionId],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
void navigate(`/organizations/${organizationId}/states-of-applicability`);
|
void navigate(`/organizations/${organizationId}/statements-of-applicability`);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
toast({
|
toast({
|
||||||
title: __("Error"),
|
title: __("Error"),
|
||||||
description: formatError(
|
description: formatError(
|
||||||
__("Failed to delete state of applicability"),
|
__("Failed to delete statement of applicability"),
|
||||||
error as GraphQLError,
|
error as GraphQLError,
|
||||||
),
|
),
|
||||||
variant: "error",
|
variant: "error",
|
||||||
@@ -186,52 +187,53 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
__(
|
__(
|
||||||
"This will permanently delete \"%s\". This action cannot be undone.",
|
"This will permanently delete \"%s\". This action cannot be undone.",
|
||||||
),
|
),
|
||||||
stateOfApplicability.name,
|
statementOfApplicability.name,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
usePageTitle(stateOfApplicability.name || __("State of Applicability"));
|
usePageTitle(statementOfApplicability.name || __("Statement of Applicability"));
|
||||||
|
|
||||||
const [isEditingName, setIsEditingName] = useState(false);
|
const [isEditingName, setIsEditingName] = useState(false);
|
||||||
const [isEditingOwner, setIsEditingOwner] = useState(false);
|
const [isEditingOwner, setIsEditingOwner] = useState(false);
|
||||||
const [updateStateOfApplicability, isUpdating] = useMutationWithToasts<StateOfApplicabilityDetailPageUpdateMutation>(
|
const [updateStatementOfApplicability, isUpdating]
|
||||||
updateMutation,
|
= useMutationWithToasts<StatementOfApplicabilityDetailPageUpdateMutation>(
|
||||||
{
|
updateMutation,
|
||||||
successMessage: __("State of Applicability updated successfully."),
|
{
|
||||||
errorMessage: __("Failed to update State of Applicability"),
|
successMessage: __("Statement of Applicability updated successfully."),
|
||||||
},
|
errorMessage: __("Failed to update Statement of Applicability"),
|
||||||
);
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const canUpdate = !isSnapshotMode && stateOfApplicability.canUpdate;
|
const canUpdate = !isSnapshotMode && statementOfApplicability.canUpdate;
|
||||||
const canDelete = !isSnapshotMode && stateOfApplicability.canDelete;
|
const canDelete = !isSnapshotMode && statementOfApplicability.canDelete;
|
||||||
|
|
||||||
const [exportStateOfApplicabilityPDF, isExporting]
|
const [exportStatementOfApplicabilityPDF, isExporting]
|
||||||
= useMutationWithToasts<StateOfApplicabilityDetailPageExportMutation>(
|
= useMutationWithToasts<StatementOfApplicabilityDetailPageExportMutation>(
|
||||||
exportMutation,
|
exportMutation,
|
||||||
{
|
{
|
||||||
successMessage: __(
|
successMessage: __(
|
||||||
"State of Applicability exported successfully.",
|
"Statement of Applicability exported successfully.",
|
||||||
),
|
),
|
||||||
errorMessage: __("Failed to export State of Applicability"),
|
errorMessage: __("Failed to export Statement of Applicability"),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleExport = async () => {
|
const handleExport = async () => {
|
||||||
if (!stateOfApplicability.id) return;
|
if (!statementOfApplicability.id) return;
|
||||||
|
|
||||||
await exportStateOfApplicabilityPDF({
|
await exportStatementOfApplicabilityPDF({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId: stateOfApplicability.id,
|
statementOfApplicabilityId: statementOfApplicability.id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onCompleted: (data) => {
|
onCompleted: (data) => {
|
||||||
if (data.exportStateOfApplicabilityPDF?.data) {
|
if (data.exportStatementOfApplicabilityPDF?.data) {
|
||||||
const link = window.document.createElement("a");
|
const link = window.document.createElement("a");
|
||||||
link.href = data.exportStateOfApplicabilityPDF.data;
|
link.href = data.exportStatementOfApplicabilityPDF.data;
|
||||||
link.download = `${stateOfApplicability.name || "state-of-applicability"}.pdf`;
|
link.download = `${statementOfApplicability.name || "statement-of-applicability"}.pdf`;
|
||||||
window.document.body.appendChild(link);
|
window.document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
window.document.body.removeChild(link);
|
window.document.body.removeChild(link);
|
||||||
@@ -254,7 +256,7 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
reset: resetName,
|
reset: resetName,
|
||||||
} = useFormWithSchema(nameSchema, {
|
} = useFormWithSchema(nameSchema, {
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: stateOfApplicability.name || "",
|
name: statementOfApplicability.name || "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -264,17 +266,17 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
reset: resetOwner,
|
reset: resetOwner,
|
||||||
} = useFormWithSchema(ownerSchema, {
|
} = useFormWithSchema(ownerSchema, {
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
ownerId: stateOfApplicability.owner?.id || "",
|
ownerId: statementOfApplicability.owner?.id || "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleUpdateName = handleSubmitName(async (data) => {
|
const handleUpdateName = handleSubmitName(async (data) => {
|
||||||
if (!stateOfApplicability.id) return;
|
if (!statementOfApplicability.id) return;
|
||||||
|
|
||||||
await updateStateOfApplicability({
|
await updateStatementOfApplicability({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
id: stateOfApplicability.id,
|
id: statementOfApplicability.id,
|
||||||
name: data.name,
|
name: data.name,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -286,12 +288,12 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleUpdateOwner = handleSubmitOwner(async (data) => {
|
const handleUpdateOwner = handleSubmitOwner(async (data) => {
|
||||||
if (!stateOfApplicability.id) return;
|
if (!statementOfApplicability.id) return;
|
||||||
|
|
||||||
await updateStateOfApplicability({
|
await updateStatementOfApplicability({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
id: stateOfApplicability.id,
|
id: statementOfApplicability.id,
|
||||||
ownerId: data.ownerId,
|
ownerId: data.ownerId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -305,20 +307,20 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
const handleCancelNameEdit = () => {
|
const handleCancelNameEdit = () => {
|
||||||
setIsEditingName(false);
|
setIsEditingName(false);
|
||||||
resetName({
|
resetName({
|
||||||
name: stateOfApplicability.name || "",
|
name: statementOfApplicability.name || "",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelOwnerEdit = () => {
|
const handleCancelOwnerEdit = () => {
|
||||||
setIsEditingOwner(false);
|
setIsEditingOwner(false);
|
||||||
resetOwner({
|
resetOwner({
|
||||||
ownerId: stateOfApplicability.owner?.id || "",
|
ownerId: statementOfApplicability.owner?.id || "",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const listUrl = snapshotId
|
const listUrl = snapshotId
|
||||||
? `/organizations/${organizationId}/snapshots/${snapshotId}/states-of-applicability`
|
? `/organizations/${organizationId}/snapshots/${snapshotId}/statements-of-applicability`
|
||||||
: `/organizations/${organizationId}/states-of-applicability`;
|
: `/organizations/${organizationId}/statements-of-applicability`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
@@ -326,13 +328,13 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
label: __("States of Applicability"),
|
label: __("Statements of Applicability"),
|
||||||
to: listUrl,
|
to: listUrl,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:
|
label:
|
||||||
stateOfApplicability.name
|
statementOfApplicability.name
|
||||||
|| __("State of Applicability detail"),
|
|| __("Statement of Applicability detail"),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
@@ -371,7 +373,7 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span>{stateOfApplicability.name || ""}</span>
|
<span>{statementOfApplicability.name || ""}</span>
|
||||||
{canUpdate && (
|
{canUpdate && (
|
||||||
<Button
|
<Button
|
||||||
variant="quaternary"
|
variant="quaternary"
|
||||||
@@ -383,7 +385,7 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{stateOfApplicability.canExport && (
|
{statementOfApplicability.canExport && (
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
icon={IconArrowDown}
|
icon={IconArrowDown}
|
||||||
@@ -445,7 +447,7 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
: (
|
: (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="text-sm text-txt-primary">
|
<div className="text-sm text-txt-primary">
|
||||||
{stateOfApplicability.owner
|
{statementOfApplicability.owner
|
||||||
?.fullName || "-"}
|
?.fullName || "-"}
|
||||||
</div>
|
</div>
|
||||||
{canUpdate && (
|
{canUpdate && (
|
||||||
@@ -466,7 +468,7 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
{__("Created at")}
|
{__("Created at")}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-txt-primary">
|
<div className="text-sm text-txt-primary">
|
||||||
{formatDate(stateOfApplicability.createdAt)}
|
{formatDate(statementOfApplicability.createdAt)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -474,21 +476,21 @@ export default function StateOfApplicabilityDetailPage(props: Props) {
|
|||||||
{__("Updated at")}
|
{__("Updated at")}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-txt-primary">
|
<div className="text-sm text-txt-primary">
|
||||||
{formatDate(stateOfApplicability.updatedAt)}
|
{formatDate(statementOfApplicability.updatedAt)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{stateOfApplicability.id && (
|
{statementOfApplicability.id && (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<h2 className="text-base font-medium">
|
<h2 className="text-base font-medium">
|
||||||
{__("Statements")}
|
{__("Statements")}
|
||||||
</h2>
|
</h2>
|
||||||
<StateOfApplicabilityControlsTab
|
<StatementOfApplicabilityControlsTab
|
||||||
stateOfApplicability={
|
statementOfApplicability={
|
||||||
stateOfApplicability as typeof stateOfApplicability & {
|
statementOfApplicability as typeof statementOfApplicability & {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,21 +16,21 @@ import { Suspense, useEffect } from "react";
|
|||||||
import { useQueryLoader } from "react-relay";
|
import { useQueryLoader } from "react-relay";
|
||||||
import { useParams } from "react-router";
|
import { useParams } from "react-router";
|
||||||
|
|
||||||
import type { StateOfApplicabilityDetailPageQuery } from "#/__generated__/core/StateOfApplicabilityDetailPageQuery.graphql";
|
import type { StatementOfApplicabilityDetailPageQuery } from "#/__generated__/core/StatementOfApplicabilityDetailPageQuery.graphql";
|
||||||
import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
|
import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
|
||||||
|
|
||||||
import StateOfApplicabilityDetailPage, { stateOfApplicabilityDetailPageQuery } from "./StateOfApplicabilityDetailPage";
|
import StatementOfApplicabilityDetailPage, { statementOfApplicabilityDetailPageQuery } from "./StatementOfApplicabilityDetailPage";
|
||||||
|
|
||||||
export default function StateOfApplicabilityDetailPageLoader() {
|
export default function StatementOfApplicabilityDetailPageLoader() {
|
||||||
const { stateOfApplicabilityId } = useParams<{ stateOfApplicabilityId: string }>();
|
const { statementOfApplicabilityId } = useParams<{ statementOfApplicabilityId: string }>();
|
||||||
const [queryRef, loadQuery]
|
const [queryRef, loadQuery]
|
||||||
= useQueryLoader<StateOfApplicabilityDetailPageQuery>(stateOfApplicabilityDetailPageQuery);
|
= useQueryLoader<StatementOfApplicabilityDetailPageQuery>(statementOfApplicabilityDetailPageQuery);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (stateOfApplicabilityId) {
|
if (statementOfApplicabilityId) {
|
||||||
loadQuery({ stateOfApplicabilityId });
|
loadQuery({ statementOfApplicabilityId });
|
||||||
}
|
}
|
||||||
}, [loadQuery, stateOfApplicabilityId]);
|
}, [loadQuery, statementOfApplicabilityId]);
|
||||||
|
|
||||||
if (!queryRef) {
|
if (!queryRef) {
|
||||||
return <PageSkeleton />;
|
return <PageSkeleton />;
|
||||||
@@ -38,7 +38,7 @@ export default function StateOfApplicabilityDetailPageLoader() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<PageSkeleton />}>
|
<Suspense fallback={<PageSkeleton />}>
|
||||||
<StateOfApplicabilityDetailPage queryRef={queryRef} />
|
<StatementOfApplicabilityDetailPage queryRef={queryRef} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -34,86 +34,86 @@ import {
|
|||||||
} from "react-relay";
|
} from "react-relay";
|
||||||
import { useParams } from "react-router";
|
import { useParams } from "react-router";
|
||||||
|
|
||||||
import type { StatesOfApplicabilityPageFragment$key } from "#/__generated__/core/StatesOfApplicabilityPageFragment.graphql";
|
import type { StatementsOfApplicabilityPageFragment$key } from "#/__generated__/core/StatementsOfApplicabilityPageFragment.graphql";
|
||||||
import type { StatesOfApplicabilityPagePaginationQuery } from "#/__generated__/core/StatesOfApplicabilityPagePaginationQuery.graphql";
|
import type { StatementsOfApplicabilityPagePaginationQuery } from "#/__generated__/core/StatementsOfApplicabilityPagePaginationQuery.graphql";
|
||||||
import type { StatesOfApplicabilityPageQuery } from "#/__generated__/core/StatesOfApplicabilityPageQuery.graphql";
|
import type { StatementsOfApplicabilityPageQuery } from "#/__generated__/core/StatementsOfApplicabilityPageQuery.graphql";
|
||||||
import { SnapshotBanner } from "#/components/SnapshotBanner";
|
import { SnapshotBanner } from "#/components/SnapshotBanner";
|
||||||
|
|
||||||
import { StateOfApplicabilityRow } from "./_components/StateOfApplicabilityRow";
|
import { StatementOfApplicabilityRow } from "./_components/StatementOfApplicabilityRow";
|
||||||
import { CreateStateOfApplicabilityDialog } from "./dialogs/CreateStateOfApplicabilityDialog";
|
import { CreateStatementOfApplicabilityDialog } from "./dialogs/CreateStatementOfApplicabilityDialog";
|
||||||
|
|
||||||
export const statesOfApplicabilityPageQuery = graphql`
|
export const statementsOfApplicabilityPageQuery = graphql`
|
||||||
query StatesOfApplicabilityPageQuery($organizationId: ID!) {
|
query StatementsOfApplicabilityPageQuery($organizationId: ID!) {
|
||||||
organization: node(id: $organizationId) {
|
organization: node(id: $organizationId) {
|
||||||
__typename
|
__typename
|
||||||
... on Organization {
|
... on Organization {
|
||||||
id
|
id
|
||||||
canCreateStateOfApplicability: permission(action: "core:state-of-applicability:create")
|
canCreateStatementOfApplicability: permission(action: "core:statement-of-applicability:create")
|
||||||
...StatesOfApplicabilityPageFragment
|
...StatementsOfApplicabilityPageFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const paginatedFragment = graphql`
|
const paginatedFragment = graphql`
|
||||||
fragment StatesOfApplicabilityPageFragment on Organization
|
fragment StatementsOfApplicabilityPageFragment on Organization
|
||||||
@refetchable(queryName: "StatesOfApplicabilityPagePaginationQuery")
|
@refetchable(queryName: "StatementsOfApplicabilityPagePaginationQuery")
|
||||||
@argumentDefinitions(
|
@argumentDefinitions(
|
||||||
first: { type: "Int", defaultValue: 50 }
|
first: { type: "Int", defaultValue: 50 }
|
||||||
order: {
|
order: {
|
||||||
type: "StateOfApplicabilityOrder"
|
type: "StatementOfApplicabilityOrder"
|
||||||
defaultValue: { direction: DESC, field: CREATED_AT }
|
defaultValue: { direction: DESC, field: CREATED_AT }
|
||||||
}
|
}
|
||||||
after: { type: "CursorKey", defaultValue: null }
|
after: { type: "CursorKey", defaultValue: null }
|
||||||
before: { type: "CursorKey", defaultValue: null }
|
before: { type: "CursorKey", defaultValue: null }
|
||||||
last: { type: "Int", defaultValue: null }
|
last: { type: "Int", defaultValue: null }
|
||||||
filter: { type: "StateOfApplicabilityFilter", defaultValue: { snapshotId: null } }
|
filter: { type: "StatementOfApplicabilityFilter", defaultValue: { snapshotId: null } }
|
||||||
) {
|
) {
|
||||||
statesOfApplicability(
|
statementsOfApplicability(
|
||||||
first: $first
|
first: $first
|
||||||
after: $after
|
after: $after
|
||||||
last: $last
|
last: $last
|
||||||
before: $before
|
before: $before
|
||||||
orderBy: $order
|
orderBy: $order
|
||||||
filter: $filter
|
filter: $filter
|
||||||
) @connection(key: "StatesOfApplicabilityPage_statesOfApplicability", filters: ["filter"]) {
|
) @connection(key: "StatementsOfApplicabilityPage_statementsOfApplicability", filters: ["filter"]) {
|
||||||
__id
|
__id
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
...StateOfApplicabilityRowFragment
|
...StatementOfApplicabilityRowFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function StatesOfApplicabilityPage({
|
export default function StatementsOfApplicabilityPage({
|
||||||
queryRef,
|
queryRef,
|
||||||
}: {
|
}: {
|
||||||
queryRef: PreloadedQuery<StatesOfApplicabilityPageQuery>;
|
queryRef: PreloadedQuery<StatementsOfApplicabilityPageQuery>;
|
||||||
}) {
|
}) {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const { snapshotId } = useParams<{ snapshotId?: string }>();
|
const { snapshotId } = useParams<{ snapshotId?: string }>();
|
||||||
const isSnapshotMode = Boolean(snapshotId);
|
const isSnapshotMode = Boolean(snapshotId);
|
||||||
|
|
||||||
usePageTitle(__("States of Applicability"));
|
usePageTitle(__("Statements of Applicability"));
|
||||||
|
|
||||||
const { organization } = usePreloadedQuery(statesOfApplicabilityPageQuery, queryRef);
|
const { organization } = usePreloadedQuery(statementsOfApplicabilityPageQuery, queryRef);
|
||||||
|
|
||||||
if (organization.__typename !== "Organization") {
|
if (organization.__typename !== "Organization") {
|
||||||
throw new Error("Organization not found");
|
throw new Error("Organization not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { statesOfApplicability },
|
data: { statementsOfApplicability },
|
||||||
loadNext,
|
loadNext,
|
||||||
hasNext,
|
hasNext,
|
||||||
refetch,
|
refetch,
|
||||||
isLoadingNext,
|
isLoadingNext,
|
||||||
} = usePaginationFragment<
|
} = usePaginationFragment<
|
||||||
StatesOfApplicabilityPagePaginationQuery,
|
StatementsOfApplicabilityPagePaginationQuery,
|
||||||
StatesOfApplicabilityPageFragment$key
|
StatementsOfApplicabilityPageFragment$key
|
||||||
>(paginatedFragment, organization);
|
>(paginatedFragment, organization);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -129,24 +129,24 @@ export default function StatesOfApplicabilityPage({
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{snapshotId && <SnapshotBanner snapshotId={snapshotId} />}
|
{snapshotId && <SnapshotBanner snapshotId={snapshotId} />}
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title={__("States of Applicability")}
|
title={__("Statements of Applicability")}
|
||||||
description={__(
|
description={__(
|
||||||
"Manage states of applicability for your organization's frameworks.",
|
"Manage statements of applicability for your organization's frameworks.",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{!isSnapshotMode
|
{!isSnapshotMode
|
||||||
&& organization.canCreateStateOfApplicability && (
|
&& organization.canCreateStatementOfApplicability && (
|
||||||
<CreateStateOfApplicabilityDialog
|
<CreateStatementOfApplicabilityDialog
|
||||||
connectionId={statesOfApplicability.__id}
|
connectionId={statementsOfApplicability.__id}
|
||||||
>
|
>
|
||||||
<Button icon={IconPlusLarge}>
|
<Button icon={IconPlusLarge}>
|
||||||
{__("Add state of applicability")}
|
{__("Add statement of applicability")}
|
||||||
</Button>
|
</Button>
|
||||||
</CreateStateOfApplicabilityDialog>
|
</CreateStatementOfApplicabilityDialog>
|
||||||
)}
|
)}
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
|
|
||||||
{statesOfApplicability && statesOfApplicability.edges.length > 0
|
{statementsOfApplicability && statementsOfApplicability.edges.length > 0
|
||||||
? (
|
? (
|
||||||
<Card>
|
<Card>
|
||||||
<Table>
|
<Table>
|
||||||
@@ -158,11 +158,11 @@ export default function StatesOfApplicabilityPage({
|
|||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{statesOfApplicability.edges.map(edge => (
|
{statementsOfApplicability.edges.map(edge => (
|
||||||
<StateOfApplicabilityRow
|
<StatementOfApplicabilityRow
|
||||||
key={edge.node.id}
|
key={edge.node.id}
|
||||||
fKey={edge.node}
|
fKey={edge.node}
|
||||||
connectionId={statesOfApplicability.__id}
|
connectionId={statementsOfApplicability.__id}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Tbody>
|
</Tbody>
|
||||||
@@ -187,11 +187,11 @@ export default function StatesOfApplicabilityPage({
|
|||||||
<Card padded>
|
<Card padded>
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<h3 className="text-lg font-semibold mb-2">
|
<h3 className="text-lg font-semibold mb-2">
|
||||||
{__("No states of applicability yet")}
|
{__("No statements of applicability yet")}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-txt-tertiary mb-4">
|
<p className="text-txt-tertiary mb-4">
|
||||||
{__(
|
{__(
|
||||||
"Create your first state of applicability to get started.",
|
"Create your first statement of applicability to get started.",
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -15,16 +15,16 @@
|
|||||||
import { Suspense, useEffect } from "react";
|
import { Suspense, useEffect } from "react";
|
||||||
import { useQueryLoader } from "react-relay";
|
import { useQueryLoader } from "react-relay";
|
||||||
|
|
||||||
import type { StatesOfApplicabilityPageQuery } from "#/__generated__/core/StatesOfApplicabilityPageQuery.graphql";
|
import type { StatementsOfApplicabilityPageQuery } from "#/__generated__/core/StatementsOfApplicabilityPageQuery.graphql";
|
||||||
import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
|
import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
|
||||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
|
||||||
import StatesOfApplicabilityPage, { statesOfApplicabilityPageQuery } from "./StatesOfApplicabilityPage";
|
import StatementsOfApplicabilityPage, { statementsOfApplicabilityPageQuery } from "./StatementsOfApplicabilityPage";
|
||||||
|
|
||||||
export default function StatesOfApplicabilityPageLoader() {
|
export default function StatementsOfApplicabilityPageLoader() {
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const [queryRef, loadQuery]
|
const [queryRef, loadQuery]
|
||||||
= useQueryLoader<StatesOfApplicabilityPageQuery>(statesOfApplicabilityPageQuery);
|
= useQueryLoader<StatementsOfApplicabilityPageQuery>(statementsOfApplicabilityPageQuery);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadQuery({ organizationId });
|
loadQuery({ organizationId });
|
||||||
@@ -36,7 +36,7 @@ export default function StatesOfApplicabilityPageLoader() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<PageSkeleton />}>
|
<Suspense fallback={<PageSkeleton />}>
|
||||||
<StatesOfApplicabilityPage queryRef={queryRef} />
|
<StatementsOfApplicabilityPage queryRef={queryRef} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -27,16 +27,16 @@ import { useFragment, useMutation } from "react-relay";
|
|||||||
import { useParams } from "react-router";
|
import { useParams } from "react-router";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import type { StateOfApplicabilityRowDeleteMutation } from "#/__generated__/core/StateOfApplicabilityRowDeleteMutation.graphql";
|
import type { StatementOfApplicabilityRowDeleteMutation } from "#/__generated__/core/StatementOfApplicabilityRowDeleteMutation.graphql";
|
||||||
import type { StateOfApplicabilityRowFragment$key } from "#/__generated__/core/StateOfApplicabilityRowFragment.graphql";
|
import type { StatementOfApplicabilityRowFragment$key } from "#/__generated__/core/StatementOfApplicabilityRowFragment.graphql";
|
||||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
|
||||||
const fragment = graphql`
|
const fragment = graphql`
|
||||||
fragment StateOfApplicabilityRowFragment on StateOfApplicability {
|
fragment StatementOfApplicabilityRowFragment on StatementOfApplicability {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
createdAt
|
createdAt
|
||||||
canDelete: permission(action: "core:state-of-applicability:delete")
|
canDelete: permission(action: "core:statement-of-applicability:delete")
|
||||||
statementsInfo: applicabilityStatements {
|
statementsInfo: applicabilityStatements {
|
||||||
totalCount
|
totalCount
|
||||||
}
|
}
|
||||||
@@ -44,22 +44,22 @@ const fragment = graphql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const deleteMutation = graphql`
|
const deleteMutation = graphql`
|
||||||
mutation StateOfApplicabilityRowDeleteMutation(
|
mutation StatementOfApplicabilityRowDeleteMutation(
|
||||||
$input: DeleteStateOfApplicabilityInput!
|
$input: DeleteStatementOfApplicabilityInput!
|
||||||
$connections: [ID!]!
|
$connections: [ID!]!
|
||||||
) {
|
) {
|
||||||
deleteStateOfApplicability(input: $input) {
|
deleteStatementOfApplicability(input: $input) {
|
||||||
deletedStateOfApplicabilityId @deleteEdge(connections: $connections)
|
deletedStatementOfApplicabilityId @deleteEdge(connections: $connections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
fKey: StateOfApplicabilityRowFragment$key;
|
fKey: StatementOfApplicabilityRowFragment$key;
|
||||||
connectionId: string;
|
connectionId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function StateOfApplicabilityRow({ fKey, connectionId }: Props) {
|
export function StatementOfApplicabilityRow({ fKey, connectionId }: Props) {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const { snapshotId } = useParams<{ snapshotId?: string }>();
|
const { snapshotId } = useParams<{ snapshotId?: string }>();
|
||||||
@@ -67,21 +67,21 @@ export function StateOfApplicabilityRow({ fKey, connectionId }: Props) {
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const isSnapshotMode = Boolean(snapshotId);
|
const isSnapshotMode = Boolean(snapshotId);
|
||||||
|
|
||||||
const stateOfApplicability = useFragment(fragment, fKey);
|
const statementOfApplicability = useFragment(fragment, fKey);
|
||||||
const canDelete = !isSnapshotMode && stateOfApplicability.canDelete;
|
const canDelete = !isSnapshotMode && statementOfApplicability.canDelete;
|
||||||
|
|
||||||
const [deleteStateOfApplicability] = useMutation<StateOfApplicabilityRowDeleteMutation>(deleteMutation);
|
const [deleteStatementOfApplicability] = useMutation<StatementOfApplicabilityRowDeleteMutation>(deleteMutation);
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
if (!stateOfApplicability.id || !stateOfApplicability.name) {
|
if (!statementOfApplicability.id || !statementOfApplicability.name) {
|
||||||
return alert(__("Failed to delete state of applicability: missing id or name"));
|
return alert(__("Failed to delete statement of applicability: missing id or name"));
|
||||||
}
|
}
|
||||||
confirm(
|
confirm(
|
||||||
() =>
|
() =>
|
||||||
promisifyMutation(deleteStateOfApplicability)({
|
promisifyMutation(deleteStatementOfApplicability)({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId: stateOfApplicability.id,
|
statementOfApplicabilityId: statementOfApplicability.id,
|
||||||
},
|
},
|
||||||
connections: [connectionId],
|
connections: [connectionId],
|
||||||
},
|
},
|
||||||
@@ -89,7 +89,7 @@ export function StateOfApplicabilityRow({ fKey, connectionId }: Props) {
|
|||||||
toast({
|
toast({
|
||||||
title: __("Error"),
|
title: __("Error"),
|
||||||
description: formatError(
|
description: formatError(
|
||||||
__("Failed to delete state of applicability"),
|
__("Failed to delete statement of applicability"),
|
||||||
error as GraphQLError,
|
error as GraphQLError,
|
||||||
),
|
),
|
||||||
variant: "error",
|
variant: "error",
|
||||||
@@ -100,25 +100,25 @@ export function StateOfApplicabilityRow({ fKey, connectionId }: Props) {
|
|||||||
__(
|
__(
|
||||||
"This will permanently delete \"%s\". This action cannot be undone.",
|
"This will permanently delete \"%s\". This action cannot be undone.",
|
||||||
),
|
),
|
||||||
stateOfApplicability.name,
|
statementOfApplicability.name,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const detailUrl = snapshotId
|
const detailUrl = snapshotId
|
||||||
? `/organizations/${organizationId}/snapshots/${snapshotId}/states-of-applicability/${stateOfApplicability.id}`
|
? `/organizations/${organizationId}/snapshots/${snapshotId}/statements-of-applicability/${statementOfApplicability.id}`
|
||||||
: `/organizations/${organizationId}/states-of-applicability/${stateOfApplicability.id}`;
|
: `/organizations/${organizationId}/statements-of-applicability/${statementOfApplicability.id}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tr to={detailUrl}>
|
<Tr to={detailUrl}>
|
||||||
<Td>{stateOfApplicability.name}</Td>
|
<Td>{statementOfApplicability.name}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
<time dateTime={stateOfApplicability.createdAt}>
|
<time dateTime={statementOfApplicability.createdAt}>
|
||||||
{formatDate(stateOfApplicability.createdAt)}
|
{formatDate(statementOfApplicability.createdAt)}
|
||||||
</time>
|
</time>
|
||||||
</Td>
|
</Td>
|
||||||
<Td>{stateOfApplicability.statementsInfo?.totalCount ?? 0}</Td>
|
<Td>{statementOfApplicability.statementsInfo?.totalCount ?? 0}</Td>
|
||||||
{canDelete && (
|
{canDelete && (
|
||||||
<Td noLink width={50} className="text-end">
|
<Td noLink width={50} className="text-end">
|
||||||
<ActionDropdown>
|
<ActionDropdown>
|
||||||
@@ -38,9 +38,9 @@ import type { AddApplicabilityStatementDialogQuery } from "#/__generated__/core/
|
|||||||
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||||
|
|
||||||
const query = graphql`
|
const query = graphql`
|
||||||
query AddApplicabilityStatementDialogQuery($stateOfApplicabilityId: ID!, $organizationId: ID!) {
|
query AddApplicabilityStatementDialogQuery($statementOfApplicabilityId: ID!, $organizationId: ID!) {
|
||||||
stateOfApplicability: node(id: $stateOfApplicabilityId) {
|
statementOfApplicability: node(id: $statementOfApplicabilityId) {
|
||||||
... on StateOfApplicability {
|
... on StatementOfApplicability {
|
||||||
id
|
id
|
||||||
applicabilityStatements(first: 10000) {
|
applicabilityStatements(first: 10000) {
|
||||||
edges {
|
edges {
|
||||||
@@ -138,7 +138,7 @@ const updateApplicabilityStatementMutation = graphql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export type AddApplicabilityStatementDialogRef = {
|
export type AddApplicabilityStatementDialogRef = {
|
||||||
open: (stateOfApplicabilityId: string, organizationId: string, connectionId: string) => void;
|
open: (statementOfApplicabilityId: string, organizationId: string, connectionId: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ControlWithStatement = {
|
type ControlWithStatement = {
|
||||||
@@ -154,11 +154,11 @@ type ControlWithStatement = {
|
|||||||
|
|
||||||
function ControlRow({
|
function ControlRow({
|
||||||
control,
|
control,
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
connectionId,
|
connectionId,
|
||||||
}: {
|
}: {
|
||||||
control: ControlWithStatement;
|
control: ControlWithStatement;
|
||||||
stateOfApplicabilityId: string;
|
statementOfApplicabilityId: string;
|
||||||
connectionId: string;
|
connectionId: string;
|
||||||
}) {
|
}) {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
@@ -228,7 +228,7 @@ function ControlRow({
|
|||||||
await createApplicabilityStatement({
|
await createApplicabilityStatement({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
controlId: control.controlId,
|
controlId: control.controlId,
|
||||||
applicability: true,
|
applicability: true,
|
||||||
justification: null,
|
justification: null,
|
||||||
@@ -263,7 +263,7 @@ function ControlRow({
|
|||||||
await createApplicabilityStatement({
|
await createApplicabilityStatement({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
controlId: control.controlId,
|
controlId: control.controlId,
|
||||||
applicability: false,
|
applicability: false,
|
||||||
justification: justification || null,
|
justification: justification || null,
|
||||||
@@ -333,11 +333,11 @@ function ControlRow({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function AddApplicabilityStatementDialogContent({
|
function AddApplicabilityStatementDialogContent({
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
organizationId,
|
organizationId,
|
||||||
connectionId,
|
connectionId,
|
||||||
}: {
|
}: {
|
||||||
stateOfApplicabilityId: string;
|
statementOfApplicabilityId: string;
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
connectionId: string;
|
connectionId: string;
|
||||||
}) {
|
}) {
|
||||||
@@ -346,7 +346,7 @@ function AddApplicabilityStatementDialogContent({
|
|||||||
const [collapsedFrameworks, setCollapsedFrameworks] = useState<Set<string>>(new Set());
|
const [collapsedFrameworks, setCollapsedFrameworks] = useState<Set<string>>(new Set());
|
||||||
const data = useLazyLoadQuery<AddApplicabilityStatementDialogQuery>(
|
const data = useLazyLoadQuery<AddApplicabilityStatementDialogQuery>(
|
||||||
query,
|
query,
|
||||||
{ stateOfApplicabilityId, organizationId },
|
{ statementOfApplicabilityId, organizationId },
|
||||||
{ fetchPolicy: "store-or-network" },
|
{ fetchPolicy: "store-or-network" },
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -355,7 +355,7 @@ function AddApplicabilityStatementDialogContent({
|
|||||||
string,
|
string,
|
||||||
{ id: string; applicability: boolean; justification: string | null }
|
{ id: string; applicability: boolean; justification: string | null }
|
||||||
>();
|
>();
|
||||||
data.stateOfApplicability?.applicabilityStatements?.edges.forEach((edge) => {
|
data.statementOfApplicability?.applicabilityStatements?.edges.forEach((edge) => {
|
||||||
map.set(edge.node.control.id, {
|
map.set(edge.node.control.id, {
|
||||||
id: edge.node.id,
|
id: edge.node.id,
|
||||||
applicability: edge.node.applicability,
|
applicability: edge.node.applicability,
|
||||||
@@ -363,7 +363,7 @@ function AddApplicabilityStatementDialogContent({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
return map;
|
return map;
|
||||||
}, [data.stateOfApplicability?.applicabilityStatements]);
|
}, [data.statementOfApplicability?.applicabilityStatements]);
|
||||||
|
|
||||||
const allControls = useMemo(() => {
|
const allControls = useMemo(() => {
|
||||||
return (data.organization?.controls?.edges || []).map((edge) => {
|
return (data.organization?.controls?.edges || []).map((edge) => {
|
||||||
@@ -459,7 +459,7 @@ function AddApplicabilityStatementDialogContent({
|
|||||||
<ControlRow
|
<ControlRow
|
||||||
key={control.controlId}
|
key={control.controlId}
|
||||||
control={control}
|
control={control}
|
||||||
stateOfApplicabilityId={stateOfApplicabilityId}
|
statementOfApplicabilityId={statementOfApplicabilityId}
|
||||||
connectionId={connectionId}
|
connectionId={connectionId}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -488,7 +488,7 @@ export const AddApplicabilityStatementDialog = forwardRef<
|
|||||||
({ onClose }, ref) => {
|
({ onClose }, ref) => {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const dialogRef = useDialogRef();
|
const dialogRef = useDialogRef();
|
||||||
const [stateOfApplicabilityId, setStateOfApplicabilityId] = useState<string | null>(null);
|
const [statementOfApplicabilityId, setStatementOfApplicabilityId] = useState<string | null>(null);
|
||||||
const [organizationId, setOrganizationId] = useState<string | null>(null);
|
const [organizationId, setOrganizationId] = useState<string | null>(null);
|
||||||
const [connectionId, setConnectionId] = useState<string | null>(null);
|
const [connectionId, setConnectionId] = useState<string | null>(null);
|
||||||
|
|
||||||
@@ -496,7 +496,7 @@ export const AddApplicabilityStatementDialog = forwardRef<
|
|||||||
ref,
|
ref,
|
||||||
() => ({
|
() => ({
|
||||||
open: (soaId: string, orgId: string, connId: string) => {
|
open: (soaId: string, orgId: string, connId: string) => {
|
||||||
setStateOfApplicabilityId(soaId);
|
setStatementOfApplicabilityId(soaId);
|
||||||
setOrganizationId(orgId);
|
setOrganizationId(orgId);
|
||||||
setConnectionId(connId);
|
setConnectionId(connId);
|
||||||
dialogRef.current?.open();
|
dialogRef.current?.open();
|
||||||
@@ -506,7 +506,7 @@ export const AddApplicabilityStatementDialog = forwardRef<
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setStateOfApplicabilityId(null);
|
setStatementOfApplicabilityId(null);
|
||||||
setOrganizationId(null);
|
setOrganizationId(null);
|
||||||
setConnectionId(null);
|
setConnectionId(null);
|
||||||
onClose?.();
|
onClose?.();
|
||||||
@@ -518,12 +518,12 @@ export const AddApplicabilityStatementDialog = forwardRef<
|
|||||||
className="max-w-3xl"
|
className="max-w-3xl"
|
||||||
title={(
|
title={(
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
items={[__("States of Applicability"), __("Add Statement")]}
|
items={[__("Statements of Applicability"), __("Add Statement")]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
{stateOfApplicabilityId && organizationId && connectionId
|
{statementOfApplicabilityId && organizationId && connectionId
|
||||||
? (
|
? (
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={(
|
fallback={(
|
||||||
@@ -536,7 +536,7 @@ export const AddApplicabilityStatementDialog = forwardRef<
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<AddApplicabilityStatementDialogContent
|
<AddApplicabilityStatementDialogContent
|
||||||
stateOfApplicabilityId={stateOfApplicabilityId}
|
statementOfApplicabilityId={statementOfApplicabilityId}
|
||||||
organizationId={organizationId}
|
organizationId={organizationId}
|
||||||
connectionId={connectionId}
|
connectionId={connectionId}
|
||||||
/>
|
/>
|
||||||
@@ -28,19 +28,19 @@ import { graphql } from "react-relay";
|
|||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import type { CreateStateOfApplicabilityDialogMutation } from "#/__generated__/core/CreateStateOfApplicabilityDialogMutation.graphql";
|
import type { CreateStatementOfApplicabilityDialogMutation } from "#/__generated__/core/CreateStatementOfApplicabilityDialogMutation.graphql";
|
||||||
import { PeopleSelectField } from "#/components/form/PeopleSelectField";
|
import { PeopleSelectField } from "#/components/form/PeopleSelectField";
|
||||||
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
||||||
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
|
||||||
const createMutation = graphql`
|
const createMutation = graphql`
|
||||||
mutation CreateStateOfApplicabilityDialogMutation(
|
mutation CreateStatementOfApplicabilityDialogMutation(
|
||||||
$input: CreateStateOfApplicabilityInput!
|
$input: CreateStatementOfApplicabilityInput!
|
||||||
$connections: [ID!]!
|
$connections: [ID!]!
|
||||||
) {
|
) {
|
||||||
createStateOfApplicability(input: $input) {
|
createStatementOfApplicability(input: $input) {
|
||||||
stateOfApplicabilityEdge @prependEdge(connections: $connections) {
|
statementOfApplicabilityEdge @prependEdge(connections: $connections) {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@@ -48,8 +48,8 @@ const createMutation = graphql`
|
|||||||
snapshotId
|
snapshotId
|
||||||
createdAt
|
createdAt
|
||||||
updatedAt
|
updatedAt
|
||||||
canDelete: permission(action: "core:state-of-applicability:delete")
|
canDelete: permission(action: "core:statement-of-applicability:delete")
|
||||||
...StateOfApplicabilityRowFragment
|
...StatementOfApplicabilityRowFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ const schema = z.object({
|
|||||||
ownerId: z.string().min(1),
|
ownerId: z.string().min(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function CreateStateOfApplicabilityDialog({
|
export function CreateStatementOfApplicabilityDialog({
|
||||||
children,
|
children,
|
||||||
connectionId,
|
connectionId,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
@@ -84,19 +84,19 @@ export function CreateStateOfApplicabilityDialog({
|
|||||||
);
|
);
|
||||||
const ref = useDialogRef();
|
const ref = useDialogRef();
|
||||||
|
|
||||||
const [createStateOfApplicability, isCreating]
|
const [createStatementOfApplicability, isCreating]
|
||||||
= useMutationWithToasts<CreateStateOfApplicabilityDialogMutation>(
|
= useMutationWithToasts<CreateStatementOfApplicabilityDialogMutation>(
|
||||||
createMutation,
|
createMutation,
|
||||||
{
|
{
|
||||||
successMessage: __(
|
successMessage: __(
|
||||||
"State of applicability created successfully.",
|
"Statement of applicability created successfully.",
|
||||||
),
|
),
|
||||||
errorMessage: __("Failed to create state of applicability"),
|
errorMessage: __("Failed to create statement of applicability"),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSubmit = async (data: z.infer<typeof schema>) => {
|
const onSubmit = async (data: z.infer<typeof schema>) => {
|
||||||
await createStateOfApplicability({
|
await createStatementOfApplicability({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
@@ -108,11 +108,11 @@ export function CreateStateOfApplicabilityDialog({
|
|||||||
onCompleted: (response) => {
|
onCompleted: (response) => {
|
||||||
reset();
|
reset();
|
||||||
ref.current?.close();
|
ref.current?.close();
|
||||||
const stateOfApplicabilityId
|
const statementOfApplicabilityId
|
||||||
= response.createStateOfApplicability.stateOfApplicabilityEdge
|
= response.createStatementOfApplicability.statementOfApplicabilityEdge
|
||||||
.node.id;
|
.node.id;
|
||||||
void navigate(
|
void navigate(
|
||||||
`/organizations/${organizationId}/states-of-applicability/${stateOfApplicabilityId}`,
|
`/organizations/${organizationId}/statements-of-applicability/${statementOfApplicabilityId}`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -125,8 +125,8 @@ export function CreateStateOfApplicabilityDialog({
|
|||||||
title={(
|
title={(
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
items={[
|
items={[
|
||||||
__("States of Applicability"),
|
__("Statements of Applicability"),
|
||||||
__("New State of Applicability"),
|
__("New Statement of Applicability"),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -121,7 +121,7 @@ export const EditControlDialog = forwardRef<EditControlDialogRef>((_props, ref)
|
|||||||
ref={dialogRef}
|
ref={dialogRef}
|
||||||
className="max-w-lg"
|
className="max-w-lg"
|
||||||
title={
|
title={
|
||||||
<Breadcrumb items={[__("States of Applicability"), __("Edit Statement")]} />
|
<Breadcrumb items={[__("Statements of Applicability"), __("Edit Statement")]} />
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{control
|
{control
|
||||||
@@ -38,9 +38,9 @@ import type { LinkControlDialogQuery } from "#/__generated__/core/LinkControlDia
|
|||||||
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||||
|
|
||||||
const linkControlQuery = graphql`
|
const linkControlQuery = graphql`
|
||||||
query LinkControlDialogQuery($stateOfApplicabilityId: ID!, $organizationId: ID!) {
|
query LinkControlDialogQuery($statementOfApplicabilityId: ID!, $organizationId: ID!) {
|
||||||
stateOfApplicability: node(id: $stateOfApplicabilityId) {
|
statementOfApplicability: node(id: $statementOfApplicabilityId) {
|
||||||
... on StateOfApplicability {
|
... on StatementOfApplicability {
|
||||||
id
|
id
|
||||||
applicabilityStatements(first: 10000) {
|
applicabilityStatements(first: 10000) {
|
||||||
edges {
|
edges {
|
||||||
@@ -103,7 +103,7 @@ const unlinkControlMutation = graphql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export type LinkControlDialogRef = {
|
export type LinkControlDialogRef = {
|
||||||
open: (stateOfApplicabilityId: string, organizationId: string, onUpdate?: () => void) => void;
|
open: (statementOfApplicabilityId: string, organizationId: string, onUpdate?: () => void) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Control = {
|
type Control = {
|
||||||
@@ -119,12 +119,12 @@ type Control = {
|
|||||||
|
|
||||||
function ControlRow({
|
function ControlRow({
|
||||||
control,
|
control,
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
isLinked,
|
isLinked,
|
||||||
onUpdate,
|
onUpdate,
|
||||||
}: {
|
}: {
|
||||||
control: Control;
|
control: Control;
|
||||||
stateOfApplicabilityId: string;
|
statementOfApplicabilityId: string;
|
||||||
isLinked: boolean;
|
isLinked: boolean;
|
||||||
onUpdate?: () => void;
|
onUpdate?: () => void;
|
||||||
}) {
|
}) {
|
||||||
@@ -169,7 +169,7 @@ function ControlRow({
|
|||||||
await linkMutate({
|
await linkMutate({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
controlId: control.controlId,
|
controlId: control.controlId,
|
||||||
applicability: true,
|
applicability: true,
|
||||||
justification: null,
|
justification: null,
|
||||||
@@ -189,7 +189,7 @@ function ControlRow({
|
|||||||
await linkMutate({
|
await linkMutate({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
controlId: control.controlId,
|
controlId: control.controlId,
|
||||||
applicability: false,
|
applicability: false,
|
||||||
justification: justification || null,
|
justification: justification || null,
|
||||||
@@ -259,11 +259,11 @@ function ControlRow({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function LinkControlDialogContent({
|
function LinkControlDialogContent({
|
||||||
stateOfApplicabilityId,
|
statementOfApplicabilityId,
|
||||||
organizationId,
|
organizationId,
|
||||||
onUpdate,
|
onUpdate,
|
||||||
}: {
|
}: {
|
||||||
stateOfApplicabilityId: string;
|
statementOfApplicabilityId: string;
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
onUpdate?: () => void;
|
onUpdate?: () => void;
|
||||||
}) {
|
}) {
|
||||||
@@ -272,10 +272,10 @@ function LinkControlDialogContent({
|
|||||||
const [collapsedFrameworks, setCollapsedFrameworks] = useState<Set<string>>(new Set());
|
const [collapsedFrameworks, setCollapsedFrameworks] = useState<Set<string>>(new Set());
|
||||||
const data = useLazyLoadQuery<LinkControlDialogQuery>(
|
const data = useLazyLoadQuery<LinkControlDialogQuery>(
|
||||||
linkControlQuery,
|
linkControlQuery,
|
||||||
{ stateOfApplicabilityId, organizationId },
|
{ statementOfApplicabilityId, organizationId },
|
||||||
{ fetchPolicy: "store-or-network" },
|
{ fetchPolicy: "store-or-network" },
|
||||||
) as {
|
) as {
|
||||||
stateOfApplicability: {
|
statementOfApplicability: {
|
||||||
id: string;
|
id: string;
|
||||||
applicabilityStatements?: {
|
applicabilityStatements?: {
|
||||||
edges: Array<{
|
edges: Array<{
|
||||||
@@ -309,7 +309,7 @@ function LinkControlDialogContent({
|
|||||||
// Build a map of control ID -> applicability statement
|
// Build a map of control ID -> applicability statement
|
||||||
const applicabilityMap = useMemo(() => {
|
const applicabilityMap = useMemo(() => {
|
||||||
const map = new Map<string, { id: string; applicability: boolean; justification: string | null }>();
|
const map = new Map<string, { id: string; applicability: boolean; justification: string | null }>();
|
||||||
data.stateOfApplicability?.applicabilityStatements?.edges.forEach((edge) => {
|
data.statementOfApplicability?.applicabilityStatements?.edges.forEach((edge) => {
|
||||||
map.set(edge.node.control.id, {
|
map.set(edge.node.control.id, {
|
||||||
id: edge.node.id,
|
id: edge.node.id,
|
||||||
applicability: edge.node.applicability,
|
applicability: edge.node.applicability,
|
||||||
@@ -317,7 +317,7 @@ function LinkControlDialogContent({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
return map;
|
return map;
|
||||||
}, [data.stateOfApplicability?.applicabilityStatements]);
|
}, [data.statementOfApplicability?.applicabilityStatements]);
|
||||||
|
|
||||||
// Merge controls with applicability info
|
// Merge controls with applicability info
|
||||||
const allControls = useMemo(() => {
|
const allControls = useMemo(() => {
|
||||||
@@ -410,7 +410,7 @@ function LinkControlDialogContent({
|
|||||||
<ControlRow
|
<ControlRow
|
||||||
key={control.controlId}
|
key={control.controlId}
|
||||||
control={control}
|
control={control}
|
||||||
stateOfApplicabilityId={stateOfApplicabilityId}
|
statementOfApplicabilityId={statementOfApplicabilityId}
|
||||||
isLinked={control.applicabilityStatementId !== null}
|
isLinked={control.applicabilityStatementId !== null}
|
||||||
onUpdate={onUpdate}
|
onUpdate={onUpdate}
|
||||||
/>
|
/>
|
||||||
@@ -431,13 +431,13 @@ function LinkControlDialogContent({
|
|||||||
export const LinkControlDialog = forwardRef<LinkControlDialogRef>((_props, ref) => {
|
export const LinkControlDialog = forwardRef<LinkControlDialogRef>((_props, ref) => {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const dialogRef = useDialogRef();
|
const dialogRef = useDialogRef();
|
||||||
const [stateOfApplicabilityId, setStateOfApplicabilityId] = useState<string | null>(null);
|
const [statementOfApplicabilityId, setStatementOfApplicabilityId] = useState<string | null>(null);
|
||||||
const [organizationId, setOrganizationId] = useState<string | null>(null);
|
const [organizationId, setOrganizationId] = useState<string | null>(null);
|
||||||
const [onUpdateCallback, setOnUpdateCallback] = useState<(() => void) | undefined>(undefined);
|
const [onUpdateCallback, setOnUpdateCallback] = useState<(() => void) | undefined>(undefined);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
open: (soaId: string, orgId: string, callback?: () => void) => {
|
open: (soaId: string, orgId: string, callback?: () => void) => {
|
||||||
setStateOfApplicabilityId(soaId);
|
setStatementOfApplicabilityId(soaId);
|
||||||
setOrganizationId(orgId);
|
setOrganizationId(orgId);
|
||||||
setOnUpdateCallback(() => callback);
|
setOnUpdateCallback(() => callback);
|
||||||
dialogRef.current?.open();
|
dialogRef.current?.open();
|
||||||
@@ -445,7 +445,7 @@ export const LinkControlDialog = forwardRef<LinkControlDialogRef>((_props, ref)
|
|||||||
}), [dialogRef]);
|
}), [dialogRef]);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setStateOfApplicabilityId(null);
|
setStatementOfApplicabilityId(null);
|
||||||
setOrganizationId(null);
|
setOrganizationId(null);
|
||||||
setOnUpdateCallback(undefined);
|
setOnUpdateCallback(undefined);
|
||||||
};
|
};
|
||||||
@@ -456,12 +456,12 @@ export const LinkControlDialog = forwardRef<LinkControlDialogRef>((_props, ref)
|
|||||||
className="max-w-3xl"
|
className="max-w-3xl"
|
||||||
title={(
|
title={(
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
items={[__("States of Applicability"), __("Add Controls")]}
|
items={[__("Statements of Applicability"), __("Add Controls")]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
{stateOfApplicabilityId && organizationId
|
{statementOfApplicabilityId && organizationId
|
||||||
? (
|
? (
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={(
|
fallback={(
|
||||||
@@ -471,7 +471,7 @@ export const LinkControlDialog = forwardRef<LinkControlDialogRef>((_props, ref)
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<LinkControlDialogContent
|
<LinkControlDialogContent
|
||||||
stateOfApplicabilityId={stateOfApplicabilityId}
|
statementOfApplicabilityId={statementOfApplicabilityId}
|
||||||
organizationId={organizationId}
|
organizationId={organizationId}
|
||||||
onUpdate={onUpdateCallback}
|
onUpdate={onUpdateCallback}
|
||||||
/>
|
/>
|
||||||
@@ -32,7 +32,7 @@ import { Suspense, useCallback, useRef } from "react";
|
|||||||
import { graphql, useFragment, useRelayEnvironment } from "react-relay";
|
import { graphql, useFragment, useRelayEnvironment } from "react-relay";
|
||||||
import { fetchQuery } from "relay-runtime";
|
import { fetchQuery } from "relay-runtime";
|
||||||
|
|
||||||
import type { StateOfApplicabilityControlsTabFragment$key } from "#/__generated__/core/StateOfApplicabilityControlsTabFragment.graphql";
|
import type { StatementOfApplicabilityControlsTabFragment$key } from "#/__generated__/core/StatementOfApplicabilityControlsTabFragment.graphql";
|
||||||
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
|
||||||
@@ -46,17 +46,17 @@ import {
|
|||||||
} from "../dialogs/EditControlDialog";
|
} from "../dialogs/EditControlDialog";
|
||||||
|
|
||||||
const refetchStatementsQuery = graphql`
|
const refetchStatementsQuery = graphql`
|
||||||
query StateOfApplicabilityControlsTabRefetchQuery($stateOfApplicabilityId: ID!) {
|
query StatementOfApplicabilityControlsTabRefetchQuery($statementOfApplicabilityId: ID!) {
|
||||||
node(id: $stateOfApplicabilityId) {
|
node(id: $statementOfApplicabilityId) {
|
||||||
... on StateOfApplicability {
|
... on StatementOfApplicability {
|
||||||
...StateOfApplicabilityControlsTabFragment
|
...StatementOfApplicabilityControlsTabFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const controlsFragment = graphql`
|
export const controlsFragment = graphql`
|
||||||
fragment StateOfApplicabilityControlsTabFragment on StateOfApplicability {
|
fragment StatementOfApplicabilityControlsTabFragment on StatementOfApplicability {
|
||||||
id
|
id
|
||||||
organization {
|
organization {
|
||||||
id
|
id
|
||||||
@@ -73,7 +73,7 @@ export const controlsFragment = graphql`
|
|||||||
)
|
)
|
||||||
|
|
||||||
applicabilityStatements(first: 1000, orderBy: { direction: ASC, field: CONTROL_SECTION_TITLE })
|
applicabilityStatements(first: 1000, orderBy: { direction: ASC, field: CONTROL_SECTION_TITLE })
|
||||||
@connection(key: "StateOfApplicabilityControlsTab_applicabilityStatements") {
|
@connection(key: "StatementOfApplicabilityControlsTab_applicabilityStatements") {
|
||||||
__id
|
__id
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
@@ -105,7 +105,7 @@ export const controlsFragment = graphql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const deleteApplicabilityStatementMutation = graphql`
|
const deleteApplicabilityStatementMutation = graphql`
|
||||||
mutation StateOfApplicabilityControlsTabDeleteMutation(
|
mutation StatementOfApplicabilityControlsTabDeleteMutation(
|
||||||
$input: DeleteApplicabilityStatementInput!
|
$input: DeleteApplicabilityStatementInput!
|
||||||
$connections: [ID!]!
|
$connections: [ID!]!
|
||||||
) {
|
) {
|
||||||
@@ -115,17 +115,17 @@ const deleteApplicabilityStatementMutation = graphql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function StateOfApplicabilityControlsTab({
|
export default function StatementOfApplicabilityControlsTab({
|
||||||
stateOfApplicability,
|
statementOfApplicability,
|
||||||
isSnapshotMode = false,
|
isSnapshotMode = false,
|
||||||
}: {
|
}: {
|
||||||
stateOfApplicability: StateOfApplicabilityControlsTabFragment$key & {
|
statementOfApplicability: StatementOfApplicabilityControlsTabFragment$key & {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
isSnapshotMode?: boolean;
|
isSnapshotMode?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const data = useFragment(controlsFragment, stateOfApplicability);
|
const data = useFragment(controlsFragment, statementOfApplicability);
|
||||||
const environment = useRelayEnvironment();
|
const environment = useRelayEnvironment();
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const addStatementDialogRef = useRef<AddApplicabilityStatementDialogRef>(null);
|
const addStatementDialogRef = useRef<AddApplicabilityStatementDialogRef>(null);
|
||||||
@@ -134,7 +134,7 @@ export default function StateOfApplicabilityControlsTab({
|
|||||||
const handleDialogClose = useCallback(() => {
|
const handleDialogClose = useCallback(() => {
|
||||||
if (!data.id) return;
|
if (!data.id) return;
|
||||||
fetchQuery(environment, refetchStatementsQuery, {
|
fetchQuery(environment, refetchStatementsQuery, {
|
||||||
stateOfApplicabilityId: data.id,
|
statementOfApplicabilityId: data.id,
|
||||||
}).subscribe({});
|
}).subscribe({});
|
||||||
}, [environment, data.id]);
|
}, [environment, data.id]);
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ import { processingActivityRoutes } from "./routes/processingActivityRoutes";
|
|||||||
import { rightsRequestRoutes } from "./routes/rightsRequestRoutes";
|
import { rightsRequestRoutes } from "./routes/rightsRequestRoutes";
|
||||||
import { riskRoutes } from "./routes/riskRoutes";
|
import { riskRoutes } from "./routes/riskRoutes";
|
||||||
import { snapshotsRoutes } from "./routes/snapshotsRoutes";
|
import { snapshotsRoutes } from "./routes/snapshotsRoutes";
|
||||||
import { statesOfApplicabilityRoutes } from "./routes/statesOfApplicabilityRoutes";
|
import { statementsOfApplicabilityRoutes } from "./routes/statementsOfApplicabilityRoutes";
|
||||||
import { taskRoutes } from "./routes/taskRoutes";
|
import { taskRoutes } from "./routes/taskRoutes";
|
||||||
import { vendorRoutes } from "./routes/vendorRoutes";
|
import { vendorRoutes } from "./routes/vendorRoutes";
|
||||||
|
|
||||||
@@ -288,7 +288,7 @@ const routes = [
|
|||||||
...obligationRoutes,
|
...obligationRoutes,
|
||||||
...rightsRequestRoutes,
|
...rightsRequestRoutes,
|
||||||
...processingActivityRoutes,
|
...processingActivityRoutes,
|
||||||
...statesOfApplicabilityRoutes,
|
...statementsOfApplicabilityRoutes,
|
||||||
...accessReviewRoutes,
|
...accessReviewRoutes,
|
||||||
...compliancePageRoutes,
|
...compliancePageRoutes,
|
||||||
...snapshotsRoutes,
|
...snapshotsRoutes,
|
||||||
|
|||||||
@@ -17,33 +17,33 @@ import type { AppRoute } from "@probo/routes";
|
|||||||
|
|
||||||
import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
|
import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
|
||||||
|
|
||||||
export const statesOfApplicabilityRoutes = [
|
export const statementsOfApplicabilityRoutes = [
|
||||||
{
|
{
|
||||||
path: "states-of-applicability",
|
path: "statements-of-applicability",
|
||||||
Fallback: PageSkeleton,
|
Fallback: PageSkeleton,
|
||||||
Component: lazy(
|
Component: lazy(
|
||||||
() => import("#/pages/organizations/states-of-applicability/StatesOfApplicabilityPageLoader"),
|
() => import("#/pages/organizations/statements-of-applicability/StatementsOfApplicabilityPageLoader"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "snapshots/:snapshotId/states-of-applicability",
|
path: "snapshots/:snapshotId/statements-of-applicability",
|
||||||
Fallback: PageSkeleton,
|
Fallback: PageSkeleton,
|
||||||
Component: lazy(
|
Component: lazy(
|
||||||
() => import("#/pages/organizations/states-of-applicability/StatesOfApplicabilityPageLoader"),
|
() => import("#/pages/organizations/statements-of-applicability/StatementsOfApplicabilityPageLoader"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "states-of-applicability/:stateOfApplicabilityId",
|
path: "statements-of-applicability/:statementOfApplicabilityId",
|
||||||
Fallback: PageSkeleton,
|
Fallback: PageSkeleton,
|
||||||
Component: lazy(
|
Component: lazy(
|
||||||
() => import("#/pages/organizations/states-of-applicability/StateOfApplicabilityDetailPageLoader"),
|
() => import("#/pages/organizations/statements-of-applicability/StatementOfApplicabilityDetailPageLoader"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "snapshots/:snapshotId/states-of-applicability/:stateOfApplicabilityId",
|
path: "snapshots/:snapshotId/statements-of-applicability/:statementOfApplicabilityId",
|
||||||
Fallback: PageSkeleton,
|
Fallback: PageSkeleton,
|
||||||
Component: lazy(
|
Component: lazy(
|
||||||
() => import("#/pages/organizations/states-of-applicability/StateOfApplicabilityDetailPageLoader"),
|
() => import("#/pages/organizations/statements-of-applicability/StatementOfApplicabilityDetailPageLoader"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
] satisfies AppRoute[];
|
] satisfies AppRoute[];
|
||||||
@@ -22,7 +22,7 @@ export const snapshotTypes = [
|
|||||||
"FINDINGS",
|
"FINDINGS",
|
||||||
"OBLIGATIONS",
|
"OBLIGATIONS",
|
||||||
"PROCESSING_ACTIVITIES",
|
"PROCESSING_ACTIVITIES",
|
||||||
"STATES_OF_APPLICABILITY",
|
"STATEMENTS_OF_APPLICABILITY",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export function getSnapshotTypeLabel(__: Translator, type: string | null | undefined) {
|
export function getSnapshotTypeLabel(__: Translator, type: string | null | undefined) {
|
||||||
@@ -47,8 +47,8 @@ export function getSnapshotTypeLabel(__: Translator, type: string | null | undef
|
|||||||
return __("Obligations");
|
return __("Obligations");
|
||||||
case "PROCESSING_ACTIVITIES":
|
case "PROCESSING_ACTIVITIES":
|
||||||
return __("Processing Activities");
|
return __("Processing Activities");
|
||||||
case "STATES_OF_APPLICABILITY":
|
case "STATEMENTS_OF_APPLICABILITY":
|
||||||
return __("States of Applicability");
|
return __("Statements of Applicability");
|
||||||
default:
|
default:
|
||||||
return __("Unknown");
|
return __("Unknown");
|
||||||
}
|
}
|
||||||
@@ -72,8 +72,8 @@ export function getSnapshotTypeUrlPath(type?: string): string {
|
|||||||
return "/obligations";
|
return "/obligations";
|
||||||
case "PROCESSING_ACTIVITIES":
|
case "PROCESSING_ACTIVITIES":
|
||||||
return "/processing-activities";
|
return "/processing-activities";
|
||||||
case "STATES_OF_APPLICABILITY":
|
case "STATEMENTS_OF_APPLICABILITY":
|
||||||
return "/states-of-applicability";
|
return "/statements-of-applicability";
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function Sidebar({ children }: PropsWithChildren) {
|
|||||||
<aside
|
<aside
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"border-r border-border-solid relative pt-16 flex-none",
|
"border-r border-border-solid relative pt-16 flex-none",
|
||||||
open ? "px-4 w-[260px]" : "px-2",
|
open ? "px-4 w-[280px]" : "px-2",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const createMutation = `
|
const createMutation = `
|
||||||
mutation($input: CreateStateOfApplicabilityInput!) {
|
mutation($input: CreateStatementOfApplicabilityInput!) {
|
||||||
createStateOfApplicability(input: $input) {
|
createStatementOfApplicability(input: $input) {
|
||||||
stateOfApplicabilityEdge {
|
statementOfApplicabilityEdge {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@@ -38,15 +38,15 @@ mutation($input: CreateStateOfApplicabilityInput!) {
|
|||||||
`
|
`
|
||||||
|
|
||||||
type createResponse struct {
|
type createResponse struct {
|
||||||
CreateStateOfApplicability struct {
|
CreateStatementOfApplicability struct {
|
||||||
StateOfApplicabilityEdge struct {
|
StatementOfApplicabilityEdge struct {
|
||||||
Node struct {
|
Node struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
CreatedAt string `json:"createdAt"`
|
CreatedAt string `json:"createdAt"`
|
||||||
} `json:"node"`
|
} `json:"node"`
|
||||||
} `json:"stateOfApplicabilityEdge"`
|
} `json:"statementOfApplicabilityEdge"`
|
||||||
} `json:"createStateOfApplicability"`
|
} `json:"createStatementOfApplicability"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdCreate(f *cmdutil.Factory) *cobra.Command {
|
func NewCmdCreate(f *cmdutil.Factory) *cobra.Command {
|
||||||
@@ -107,7 +107,7 @@ func NewCmdCreate(f *cmdutil.Factory) *cobra.Command {
|
|||||||
return fmt.Errorf("cannot parse response: %w", err)
|
return fmt.Errorf("cannot parse response: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := resp.CreateStateOfApplicability.StateOfApplicabilityEdge.Node
|
s := resp.CreateStatementOfApplicability.StatementOfApplicabilityEdge.Node
|
||||||
_, _ = fmt.Fprintf(
|
_, _ = fmt.Fprintf(
|
||||||
f.IOStreams.Out,
|
f.IOStreams.Out,
|
||||||
"Created statement of applicability %s (%s)\n",
|
"Created statement of applicability %s (%s)\n",
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const deleteMutation = `
|
const deleteMutation = `
|
||||||
mutation($input: DeleteStateOfApplicabilityInput!) {
|
mutation($input: DeleteStatementOfApplicabilityInput!) {
|
||||||
deleteStateOfApplicability(input: $input) {
|
deleteStatementOfApplicability(input: $input) {
|
||||||
deletedStateOfApplicabilityId
|
deletedStatementOfApplicabilityId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@@ -78,7 +78,7 @@ func NewCmdDelete(f *cmdutil.Factory) *cobra.Command {
|
|||||||
deleteMutation,
|
deleteMutation,
|
||||||
map[string]any{
|
map[string]any{
|
||||||
"input": map[string]any{
|
"input": map[string]any{
|
||||||
"stateOfApplicabilityId": args[0],
|
"statementOfApplicabilityId": args[0],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const listQuery = `
|
const listQuery = `
|
||||||
query($id: ID!, $first: Int, $after: CursorKey, $orderBy: StateOfApplicabilityOrder) {
|
query($id: ID!, $first: Int, $after: CursorKey, $orderBy: StatementOfApplicabilityOrder) {
|
||||||
node(id: $id) {
|
node(id: $id) {
|
||||||
__typename
|
__typename
|
||||||
... on Organization {
|
... on Organization {
|
||||||
statesOfApplicability(first: $first, after: $after, orderBy: $orderBy) {
|
statementsOfApplicability(first: $first, after: $after, orderBy: $orderBy) {
|
||||||
totalCount
|
totalCount
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
@@ -48,7 +48,7 @@ query($id: ID!, $first: Int, $after: CursorKey, $orderBy: StateOfApplicabilityOr
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
type stateOfApplicability struct {
|
type statementOfApplicability struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
CreatedAt string `json:"createdAt"`
|
CreatedAt string `json:"createdAt"`
|
||||||
@@ -118,11 +118,11 @@ func NewCmdList(f *cmdutil.Factory) *cobra.Command {
|
|||||||
listQuery,
|
listQuery,
|
||||||
variables,
|
variables,
|
||||||
flagLimit,
|
flagLimit,
|
||||||
func(data json.RawMessage) (*api.Connection[stateOfApplicability], error) {
|
func(data json.RawMessage) (*api.Connection[statementOfApplicability], error) {
|
||||||
var resp struct {
|
var resp struct {
|
||||||
Node *struct {
|
Node *struct {
|
||||||
Typename string `json:"__typename"`
|
Typename string `json:"__typename"`
|
||||||
StatesOfApplicability api.Connection[stateOfApplicability] `json:"statesOfApplicability"`
|
StatementsOfApplicability api.Connection[statementOfApplicability] `json:"statementsOfApplicability"`
|
||||||
} `json:"node"`
|
} `json:"node"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(data, &resp); err != nil {
|
if err := json.Unmarshal(data, &resp); err != nil {
|
||||||
@@ -134,7 +134,7 @@ func NewCmdList(f *cmdutil.Factory) *cobra.Command {
|
|||||||
if resp.Node.Typename != "Organization" {
|
if resp.Node.Typename != "Organization" {
|
||||||
return nil, fmt.Errorf("expected Organization node, got %s", resp.Node.Typename)
|
return nil, fmt.Errorf("expected Organization node, got %s", resp.Node.Typename)
|
||||||
}
|
}
|
||||||
return &resp.Node.StatesOfApplicability, nil
|
return &resp.Node.StatementsOfApplicability, nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -143,7 +143,7 @@ func NewCmdList(f *cmdutil.Factory) *cobra.Command {
|
|||||||
|
|
||||||
if *flagOutput == cmdutil.OutputJSON {
|
if *flagOutput == cmdutil.OutputJSON {
|
||||||
if soas == nil {
|
if soas == nil {
|
||||||
soas = []stateOfApplicability{}
|
soas = []statementOfApplicability{}
|
||||||
}
|
}
|
||||||
return cmdutil.PrintJSON(f.IOStreams.Out, soas)
|
return cmdutil.PrintJSON(f.IOStreams.Out, soas)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,9 +130,9 @@ func NewCmdAdd(f *cmdutil.Factory) *cobra.Command {
|
|||||||
)
|
)
|
||||||
|
|
||||||
input := map[string]any{
|
input := map[string]any{
|
||||||
"stateOfApplicabilityId": flagSoA,
|
"statementOfApplicabilityId": flagSoA,
|
||||||
"controlId": flagControl,
|
"controlId": flagControl,
|
||||||
"applicability": flagApplicable,
|
"applicability": flagApplicable,
|
||||||
}
|
}
|
||||||
|
|
||||||
if flagJustification != "" {
|
if flagJustification != "" {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const listQuery = `
|
|||||||
query($id: ID!, $first: Int, $after: CursorKey, $orderBy: ApplicabilityStatementOrder) {
|
query($id: ID!, $first: Int, $after: CursorKey, $orderBy: ApplicabilityStatementOrder) {
|
||||||
node(id: $id) {
|
node(id: $id) {
|
||||||
__typename
|
__typename
|
||||||
... on StateOfApplicability {
|
... on StatementOfApplicability {
|
||||||
applicabilityStatements(first: $first, after: $after, orderBy: $orderBy) {
|
applicabilityStatements(first: $first, after: $after, orderBy: $orderBy) {
|
||||||
totalCount
|
totalCount
|
||||||
edges {
|
edges {
|
||||||
@@ -130,8 +130,8 @@ func NewCmdList(f *cmdutil.Factory) *cobra.Command {
|
|||||||
if resp.Node == nil {
|
if resp.Node == nil {
|
||||||
return nil, fmt.Errorf("statement of applicability %s not found", args[0])
|
return nil, fmt.Errorf("statement of applicability %s not found", args[0])
|
||||||
}
|
}
|
||||||
if resp.Node.Typename != "StateOfApplicability" {
|
if resp.Node.Typename != "StatementOfApplicability" {
|
||||||
return nil, fmt.Errorf("expected StateOfApplicability node, got %s", resp.Node.Typename)
|
return nil, fmt.Errorf("expected StatementOfApplicability node, got %s", resp.Node.Typename)
|
||||||
}
|
}
|
||||||
return &resp.Node.ApplicabilityStatements, nil
|
return &resp.Node.ApplicabilityStatements, nil
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const updateMutation = `
|
const updateMutation = `
|
||||||
mutation($input: UpdateStateOfApplicabilityInput!) {
|
mutation($input: UpdateStatementOfApplicabilityInput!) {
|
||||||
updateStateOfApplicability(input: $input) {
|
updateStatementOfApplicability(input: $input) {
|
||||||
stateOfApplicability {
|
statementOfApplicability {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
@@ -35,12 +35,12 @@ mutation($input: UpdateStateOfApplicabilityInput!) {
|
|||||||
`
|
`
|
||||||
|
|
||||||
type updateResponse struct {
|
type updateResponse struct {
|
||||||
UpdateStateOfApplicability struct {
|
UpdateStatementOfApplicability struct {
|
||||||
StateOfApplicability struct {
|
StatementOfApplicability struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
} `json:"stateOfApplicability"`
|
} `json:"statementOfApplicability"`
|
||||||
} `json:"updateStateOfApplicability"`
|
} `json:"updateStatementOfApplicability"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command {
|
func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command {
|
||||||
@@ -103,7 +103,7 @@ func NewCmdUpdate(f *cmdutil.Factory) *cobra.Command {
|
|||||||
return fmt.Errorf("cannot parse response: %w", err)
|
return fmt.Errorf("cannot parse response: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := resp.UpdateStateOfApplicability.StateOfApplicability
|
s := resp.UpdateStatementOfApplicability.StatementOfApplicability
|
||||||
_, _ = fmt.Fprintf(
|
_, _ = fmt.Fprintf(
|
||||||
f.IOStreams.Out,
|
f.IOStreams.Out,
|
||||||
"Updated statement of applicability %s (%s)\n",
|
"Updated statement of applicability %s (%s)\n",
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const viewQuery = `
|
|||||||
query($id: ID!) {
|
query($id: ID!) {
|
||||||
node(id: $id) {
|
node(id: $id) {
|
||||||
__typename
|
__typename
|
||||||
... on StateOfApplicability {
|
... on StatementOfApplicability {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
owner {
|
owner {
|
||||||
@@ -104,8 +104,8 @@ func NewCmdView(f *cmdutil.Factory) *cobra.Command {
|
|||||||
return fmt.Errorf("statement of applicability %s not found", args[0])
|
return fmt.Errorf("statement of applicability %s not found", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Node.Typename != "StateOfApplicability" {
|
if resp.Node.Typename != "StatementOfApplicability" {
|
||||||
return fmt.Errorf("expected StateOfApplicability node, got %s", resp.Node.Typename)
|
return fmt.Errorf("expected StatementOfApplicability node, got %s", resp.Node.Typename)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flagOutput == cmdutil.OutputJSON {
|
if *flagOutput == cmdutil.OutputJSON {
|
||||||
|
|||||||
@@ -30,15 +30,15 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
ApplicabilityStatement struct {
|
ApplicabilityStatement struct {
|
||||||
ID gid.GID `db:"id"`
|
ID gid.GID `db:"id"`
|
||||||
StateOfApplicabilityID gid.GID `db:"state_of_applicability_id"`
|
StatementOfApplicabilityID gid.GID `db:"statement_of_applicability_id"`
|
||||||
ControlID gid.GID `db:"control_id"`
|
ControlID gid.GID `db:"control_id"`
|
||||||
OrganizationID gid.GID `db:"organization_id"`
|
OrganizationID gid.GID `db:"organization_id"`
|
||||||
SnapshotID *gid.GID `db:"snapshot_id"`
|
SnapshotID *gid.GID `db:"snapshot_id"`
|
||||||
Applicability bool `db:"applicability"`
|
Applicability bool `db:"applicability"`
|
||||||
Justification *string `db:"justification"`
|
Justification *string `db:"justification"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `db:"created_at"`
|
||||||
UpdatedAt time.Time `db:"updated_at"`
|
UpdatedAt time.Time `db:"updated_at"`
|
||||||
|
|
||||||
// Ordering only.
|
// Ordering only.
|
||||||
SectionTitle string `db:"section_title"`
|
SectionTitle string `db:"section_title"`
|
||||||
@@ -82,7 +82,7 @@ func (sac *ApplicabilityStatement) LoadByID(
|
|||||||
WITH stmt AS (
|
WITH stmt AS (
|
||||||
SELECT
|
SELECT
|
||||||
a.id,
|
a.id,
|
||||||
a.state_of_applicability_id,
|
a.statement_of_applicability_id,
|
||||||
a.control_id,
|
a.control_id,
|
||||||
a.organization_id,
|
a.organization_id,
|
||||||
a.snapshot_id,
|
a.snapshot_id,
|
||||||
@@ -104,7 +104,7 @@ WITH stmt AS (
|
|||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
state_of_applicability_id,
|
statement_of_applicability_id,
|
||||||
control_id,
|
control_id,
|
||||||
organization_id,
|
organization_id,
|
||||||
snapshot_id,
|
snapshot_id,
|
||||||
@@ -142,25 +142,25 @@ LIMIT 1;
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sac *ApplicabilityStatement) LoadByStateOfApplicabilityIDAndControlID(
|
func (sac *ApplicabilityStatement) LoadByStatementOfApplicabilityIDAndControlID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
controlID gid.GID,
|
controlID gid.GID,
|
||||||
) error {
|
) error {
|
||||||
q := `
|
q := `
|
||||||
WITH current_soa AS (
|
WITH current_soa AS (
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM states_of_applicability
|
FROM statements_of_applicability
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND id = @state_of_applicability_id
|
AND id = @statement_of_applicability_id
|
||||||
AND snapshot_id IS NULL
|
AND snapshot_id IS NULL
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
soac.id,
|
soac.id,
|
||||||
soac.state_of_applicability_id,
|
soac.statement_of_applicability_id,
|
||||||
soac.control_id,
|
soac.control_id,
|
||||||
soac.organization_id,
|
soac.organization_id,
|
||||||
soac.snapshot_id,
|
soac.snapshot_id,
|
||||||
@@ -172,7 +172,7 @@ SELECT
|
|||||||
FROM
|
FROM
|
||||||
applicability_statements soac
|
applicability_statements soac
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
current_soa ON soac.state_of_applicability_id = current_soa.id
|
current_soa ON soac.statement_of_applicability_id = current_soa.id
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
controls c ON c.id = soac.control_id
|
controls c ON c.id = soac.control_id
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
@@ -184,8 +184,8 @@ LIMIT 1;
|
|||||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"state_of_applicability_id": stateOfApplicabilityID,
|
"statement_of_applicability_id": statementOfApplicabilityID,
|
||||||
"control_id": controlID,
|
"control_id": controlID,
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
@@ -215,7 +215,7 @@ func (sac *ApplicabilityStatement) Insert(
|
|||||||
INSERT INTO
|
INSERT INTO
|
||||||
applicability_statements (
|
applicability_statements (
|
||||||
id,
|
id,
|
||||||
state_of_applicability_id,
|
statement_of_applicability_id,
|
||||||
control_id,
|
control_id,
|
||||||
organization_id,
|
organization_id,
|
||||||
tenant_id,
|
tenant_id,
|
||||||
@@ -227,7 +227,7 @@ INSERT INTO
|
|||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
@id,
|
@id,
|
||||||
@state_of_applicability_id,
|
@statement_of_applicability_id,
|
||||||
@control_id,
|
@control_id,
|
||||||
@organization_id,
|
@organization_id,
|
||||||
@tenant_id,
|
@tenant_id,
|
||||||
@@ -240,16 +240,16 @@ VALUES (
|
|||||||
`
|
`
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"id": sac.ID,
|
"id": sac.ID,
|
||||||
"state_of_applicability_id": sac.StateOfApplicabilityID,
|
"statement_of_applicability_id": sac.StatementOfApplicabilityID,
|
||||||
"control_id": sac.ControlID,
|
"control_id": sac.ControlID,
|
||||||
"organization_id": sac.OrganizationID,
|
"organization_id": sac.OrganizationID,
|
||||||
"tenant_id": scope.GetTenantID(),
|
"tenant_id": scope.GetTenantID(),
|
||||||
"snapshot_id": sac.SnapshotID,
|
"snapshot_id": sac.SnapshotID,
|
||||||
"applicability": sac.Applicability,
|
"applicability": sac.Applicability,
|
||||||
"justification": sac.Justification,
|
"justification": sac.Justification,
|
||||||
"created_at": sac.CreatedAt,
|
"created_at": sac.CreatedAt,
|
||||||
"updated_at": sac.UpdatedAt,
|
"updated_at": sac.UpdatedAt,
|
||||||
}
|
}
|
||||||
_, err := conn.Exec(ctx, q, args)
|
_, err := conn.Exec(ctx, q, args)
|
||||||
|
|
||||||
@@ -280,17 +280,17 @@ SET
|
|||||||
updated_at = @updated_at
|
updated_at = @updated_at
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND state_of_applicability_id = @state_of_applicability_id
|
AND statement_of_applicability_id = @statement_of_applicability_id
|
||||||
AND control_id = @control_id
|
AND control_id = @control_id
|
||||||
`
|
`
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"state_of_applicability_id": sac.StateOfApplicabilityID,
|
"statement_of_applicability_id": sac.StatementOfApplicabilityID,
|
||||||
"control_id": sac.ControlID,
|
"control_id": sac.ControlID,
|
||||||
"applicability": sac.Applicability,
|
"applicability": sac.Applicability,
|
||||||
"justification": sac.Justification,
|
"justification": sac.Justification,
|
||||||
"updated_at": sac.UpdatedAt,
|
"updated_at": sac.UpdatedAt,
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
@@ -347,20 +347,20 @@ func (sac *ApplicabilityStatement) Delete(
|
|||||||
q := `
|
q := `
|
||||||
WITH current_soa AS (
|
WITH current_soa AS (
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM states_of_applicability
|
FROM statements_of_applicability
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND id = @state_of_applicability_id
|
AND id = @statement_of_applicability_id
|
||||||
AND snapshot_id IS NULL
|
AND snapshot_id IS NULL
|
||||||
)
|
)
|
||||||
DELETE FROM applicability_statements
|
DELETE FROM applicability_statements
|
||||||
WHERE state_of_applicability_id IN (SELECT id FROM current_soa)
|
WHERE statement_of_applicability_id IN (SELECT id FROM current_soa)
|
||||||
AND control_id = @control_id;
|
AND control_id = @control_id;
|
||||||
`
|
`
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"state_of_applicability_id": sac.StateOfApplicabilityID,
|
"statement_of_applicability_id": sac.StatementOfApplicabilityID,
|
||||||
"control_id": sac.ControlID,
|
"control_id": sac.ControlID,
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||||
@@ -398,18 +398,18 @@ WHERE
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sacs *ApplicabilityStatements) LoadByStateOfApplicabilityID(
|
func (sacs *ApplicabilityStatements) LoadByStatementOfApplicabilityID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
cursor *page.Cursor[ApplicabilityStatementOrderField],
|
cursor *page.Cursor[ApplicabilityStatementOrderField],
|
||||||
) error {
|
) error {
|
||||||
q := `
|
q := `
|
||||||
WITH stmt AS (
|
WITH stmt AS (
|
||||||
SELECT
|
SELECT
|
||||||
a.id,
|
a.id,
|
||||||
a.state_of_applicability_id,
|
a.statement_of_applicability_id,
|
||||||
a.control_id,
|
a.control_id,
|
||||||
a.organization_id,
|
a.organization_id,
|
||||||
a.snapshot_id,
|
a.snapshot_id,
|
||||||
@@ -427,11 +427,11 @@ WITH stmt AS (
|
|||||||
frameworks f ON f.id = c.framework_id
|
frameworks f ON f.id = c.framework_id
|
||||||
WHERE
|
WHERE
|
||||||
a.%[1]s
|
a.%[1]s
|
||||||
AND a.state_of_applicability_id = @state_of_applicability_id
|
AND a.statement_of_applicability_id = @statement_of_applicability_id
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
state_of_applicability_id,
|
statement_of_applicability_id,
|
||||||
control_id,
|
control_id,
|
||||||
organization_id,
|
organization_id,
|
||||||
snapshot_id,
|
snapshot_id,
|
||||||
@@ -448,7 +448,7 @@ WHERE
|
|||||||
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
|
||||||
|
|
||||||
args := pgx.NamedArgs{
|
args := pgx.NamedArgs{
|
||||||
"state_of_applicability_id": stateOfApplicabilityID,
|
"statement_of_applicability_id": statementOfApplicabilityID,
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
maps.Copy(args, cursor.SQLArguments())
|
maps.Copy(args, cursor.SQLArguments())
|
||||||
@@ -467,11 +467,11 @@ WHERE
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sacs *ApplicabilityStatements) CountByStateOfApplicabilityID(
|
func (sacs *ApplicabilityStatements) CountByStatementOfApplicabilityID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
q := `
|
q := `
|
||||||
SELECT
|
SELECT
|
||||||
@@ -480,11 +480,11 @@ FROM
|
|||||||
applicability_statements
|
applicability_statements
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND state_of_applicability_id = @state_of_applicability_id;
|
AND statement_of_applicability_id = @statement_of_applicability_id;
|
||||||
`
|
`
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||||
|
|
||||||
args := pgx.NamedArgs{"state_of_applicability_id": stateOfApplicabilityID}
|
args := pgx.NamedArgs{"statement_of_applicability_id": statementOfApplicabilityID}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
@@ -506,7 +506,7 @@ func (sacs *ApplicabilityStatements) LoadByControlID(
|
|||||||
WITH soac_ctrl AS (
|
WITH soac_ctrl AS (
|
||||||
SELECT
|
SELECT
|
||||||
soac.id,
|
soac.id,
|
||||||
soac.state_of_applicability_id,
|
soac.statement_of_applicability_id,
|
||||||
soac.control_id,
|
soac.control_id,
|
||||||
soac.organization_id,
|
soac.organization_id,
|
||||||
soac.snapshot_id,
|
soac.snapshot_id,
|
||||||
@@ -519,7 +519,7 @@ WITH soac_ctrl AS (
|
|||||||
FROM
|
FROM
|
||||||
applicability_statements soac
|
applicability_statements soac
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
states_of_applicability soa ON soac.state_of_applicability_id = soa.id
|
statements_of_applicability soa ON soac.statement_of_applicability_id = soa.id
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
controls c ON c.id = soac.control_id
|
controls c ON c.id = soac.control_id
|
||||||
INNER JOIN
|
INNER JOIN
|
||||||
@@ -531,7 +531,7 @@ WITH soac_ctrl AS (
|
|||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
state_of_applicability_id,
|
statement_of_applicability_id,
|
||||||
control_id,
|
control_id,
|
||||||
organization_id,
|
organization_id,
|
||||||
snapshot_id,
|
snapshot_id,
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ func ResourceTypeName(entityType uint16) string {
|
|||||||
return "TransferImpactAssessment"
|
return "TransferImpactAssessment"
|
||||||
case RightsRequestEntityType:
|
case RightsRequestEntityType:
|
||||||
return "RightsRequest"
|
return "RightsRequest"
|
||||||
case StateOfApplicabilityEntityType:
|
case StatementOfApplicabilityEntityType:
|
||||||
return "StateOfApplicability"
|
return "StatementOfApplicability"
|
||||||
case ApplicabilityStatementEntityType:
|
case ApplicabilityStatementEntityType:
|
||||||
return "ApplicabilityStatement"
|
return "ApplicabilityStatement"
|
||||||
case WebhookSubscriptionEntityType:
|
case WebhookSubscriptionEntityType:
|
||||||
|
|||||||
@@ -1041,11 +1041,11 @@ WHERE %s
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controls) CountByStateOfApplicabilityID(
|
func (c *Controls) CountByStatementOfApplicabilityID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
filter *ControlFilter,
|
filter *ControlFilter,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
q := `
|
q := `
|
||||||
@@ -1059,7 +1059,7 @@ WITH ctrl AS (
|
|||||||
INNER JOIN
|
INNER JOIN
|
||||||
applicability_statements soac ON c.id = soac.control_id
|
applicability_statements soac ON c.id = soac.control_id
|
||||||
WHERE
|
WHERE
|
||||||
soac.state_of_applicability_id = @state_of_applicability_id
|
soac.statement_of_applicability_id = @statement_of_applicability_id
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(id)
|
COUNT(id)
|
||||||
@@ -1070,7 +1070,7 @@ WHERE %s
|
|||||||
`
|
`
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment())
|
||||||
|
|
||||||
args := pgx.NamedArgs{"state_of_applicability_id": stateOfApplicabilityID}
|
args := pgx.NamedArgs{"statement_of_applicability_id": statementOfApplicabilityID}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
maps.Copy(args, filter.SQLArguments())
|
maps.Copy(args, filter.SQLArguments())
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ const (
|
|||||||
DataProtectionImpactAssessmentEntityType uint16 = 46
|
DataProtectionImpactAssessmentEntityType uint16 = 46
|
||||||
TransferImpactAssessmentEntityType uint16 = 47
|
TransferImpactAssessmentEntityType uint16 = 47
|
||||||
RightsRequestEntityType uint16 = 48
|
RightsRequestEntityType uint16 = 48
|
||||||
StateOfApplicabilityEntityType uint16 = 49
|
StatementOfApplicabilityEntityType uint16 = 49
|
||||||
ApplicabilityStatementEntityType uint16 = 50
|
ApplicabilityStatementEntityType uint16 = 50
|
||||||
MembershipProfileEntityType uint16 = 51
|
MembershipProfileEntityType uint16 = 51
|
||||||
SCIMConfigurationEntityType uint16 = 52
|
SCIMConfigurationEntityType uint16 = 52
|
||||||
@@ -194,8 +194,8 @@ func NewEntityFromID(id gid.GID) (any, bool) {
|
|||||||
return &TransferImpactAssessment{ID: id}, true
|
return &TransferImpactAssessment{ID: id}, true
|
||||||
case RightsRequestEntityType:
|
case RightsRequestEntityType:
|
||||||
return &RightsRequest{ID: id}, true
|
return &RightsRequest{ID: id}, true
|
||||||
case StateOfApplicabilityEntityType:
|
case StatementOfApplicabilityEntityType:
|
||||||
return &StateOfApplicability{ID: id}, true
|
return &StatementOfApplicability{ID: id}, true
|
||||||
case ApplicabilityStatementEntityType:
|
case ApplicabilityStatementEntityType:
|
||||||
return &ApplicabilityStatement{ID: id}, true
|
return &ApplicabilityStatement{ID: id}, true
|
||||||
case MembershipProfileEntityType:
|
case MembershipProfileEntityType:
|
||||||
|
|||||||
19
pkg/coredata/migrations/20260409T120000Z.sql
Normal file
19
pkg/coredata/migrations/20260409T120000Z.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
-- Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
|
||||||
|
--
|
||||||
|
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
-- purpose with or without fee is hereby granted, provided that the above
|
||||||
|
-- copyright notice and this permission notice appear in all copies.
|
||||||
|
--
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
-- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
-- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
-- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
-- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
-- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
-- PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
-- Rename states_of_applicability to statements_of_applicability
|
||||||
|
ALTER TABLE states_of_applicability RENAME TO statements_of_applicability;
|
||||||
|
ALTER TABLE applicability_statements RENAME COLUMN state_of_applicability_id TO statement_of_applicability_id;
|
||||||
|
|
||||||
|
ALTER TYPE snapshots_type RENAME VALUE 'STATES_OF_APPLICABILITY' TO 'STATEMENTS_OF_APPLICABILITY';
|
||||||
@@ -24,14 +24,14 @@ type (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SnapshotsTypeRisks SnapshotsType = "RISKS"
|
SnapshotsTypeRisks SnapshotsType = "RISKS"
|
||||||
SnapshotsTypeVendors SnapshotsType = "VENDORS"
|
SnapshotsTypeVendors SnapshotsType = "VENDORS"
|
||||||
SnapshotsTypeAssets SnapshotsType = "ASSETS"
|
SnapshotsTypeAssets SnapshotsType = "ASSETS"
|
||||||
SnapshotsTypeData SnapshotsType = "DATA"
|
SnapshotsTypeData SnapshotsType = "DATA"
|
||||||
SnapshotsTypeFindings SnapshotsType = "FINDINGS"
|
SnapshotsTypeFindings SnapshotsType = "FINDINGS"
|
||||||
SnapshotsTypeObligations SnapshotsType = "OBLIGATIONS"
|
SnapshotsTypeObligations SnapshotsType = "OBLIGATIONS"
|
||||||
SnapshotsTypeProcessingActivities SnapshotsType = "PROCESSING_ACTIVITIES"
|
SnapshotsTypeProcessingActivities SnapshotsType = "PROCESSING_ACTIVITIES"
|
||||||
SnapshotsTypeStatesOfApplicability SnapshotsType = "STATES_OF_APPLICABILITY"
|
SnapshotsTypeStatementsOfApplicability SnapshotsType = "STATEMENTS_OF_APPLICABILITY"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SnapshotsTypes() []SnapshotsType {
|
func SnapshotsTypes() []SnapshotsType {
|
||||||
@@ -43,7 +43,7 @@ func SnapshotsTypes() []SnapshotsType {
|
|||||||
SnapshotsTypeFindings,
|
SnapshotsTypeFindings,
|
||||||
SnapshotsTypeObligations,
|
SnapshotsTypeObligations,
|
||||||
SnapshotsTypeProcessingActivities,
|
SnapshotsTypeProcessingActivities,
|
||||||
SnapshotsTypeStatesOfApplicability,
|
SnapshotsTypeStatementsOfApplicability,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,8 +77,8 @@ func (st *SnapshotsType) Scan(value any) error {
|
|||||||
*st = SnapshotsTypeObligations
|
*st = SnapshotsTypeObligations
|
||||||
case SnapshotsTypeProcessingActivities.String():
|
case SnapshotsTypeProcessingActivities.String():
|
||||||
*st = SnapshotsTypeProcessingActivities
|
*st = SnapshotsTypeProcessingActivities
|
||||||
case SnapshotsTypeStatesOfApplicability.String():
|
case SnapshotsTypeStatementsOfApplicability.String():
|
||||||
*st = SnapshotsTypeStatesOfApplicability
|
*st = SnapshotsTypeStatementsOfApplicability
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("invalid SnapshotsType value: %q", s)
|
return fmt.Errorf("invalid SnapshotsType value: %q", s)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ func GetSnapshottable(snapshotType SnapshotsType) (Snapshottable, error) {
|
|||||||
return ProcessingActivities{}, nil
|
return ProcessingActivities{}, nil
|
||||||
case SnapshotsTypeVendors:
|
case SnapshotsTypeVendors:
|
||||||
return Vendors{}, nil
|
return Vendors{}, nil
|
||||||
case SnapshotsTypeStatesOfApplicability:
|
case SnapshotsTypeStatementsOfApplicability:
|
||||||
return StatesOfApplicability{}, nil
|
return StatementsOfApplicability{}, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported snapshot type: %s", snapshotType)
|
return nil, fmt.Errorf("unsupported snapshot type: %s", snapshotType)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
StateOfApplicability struct {
|
StatementOfApplicability struct {
|
||||||
ID gid.GID `db:"id"`
|
ID gid.GID `db:"id"`
|
||||||
OrganizationID gid.GID `db:"organization_id"`
|
OrganizationID gid.GID `db:"organization_id"`
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
@@ -40,39 +40,39 @@ type (
|
|||||||
UpdatedAt time.Time `db:"updated_at"`
|
UpdatedAt time.Time `db:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
StatesOfApplicability []*StateOfApplicability
|
StatementsOfApplicability []*StatementOfApplicability
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s StateOfApplicability) CursorKey(orderBy StateOfApplicabilityOrderField) page.CursorKey {
|
func (s StatementOfApplicability) CursorKey(orderBy StatementOfApplicabilityOrderField) page.CursorKey {
|
||||||
switch orderBy {
|
switch orderBy {
|
||||||
case StateOfApplicabilityOrderFieldCreatedAt:
|
case StatementOfApplicabilityOrderFieldCreatedAt:
|
||||||
return page.NewCursorKey(s.ID, s.CreatedAt)
|
return page.NewCursorKey(s.ID, s.CreatedAt)
|
||||||
case StateOfApplicabilityOrderFieldName:
|
case StatementOfApplicabilityOrderFieldName:
|
||||||
return page.NewCursorKey(s.ID, s.Name)
|
return page.NewCursorKey(s.ID, s.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateOfApplicability) AuthorizationAttributes(ctx context.Context, conn pg.Querier) (map[string]string, error) {
|
func (s *StatementOfApplicability) AuthorizationAttributes(ctx context.Context, conn pg.Querier) (map[string]string, error) {
|
||||||
q := `SELECT organization_id FROM states_of_applicability WHERE id = $1 LIMIT 1;`
|
q := `SELECT organization_id FROM statements_of_applicability WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
var organizationID gid.GID
|
var organizationID gid.GID
|
||||||
if err := conn.QueryRow(ctx, q, s.ID).Scan(&organizationID); err != nil {
|
if err := conn.QueryRow(ctx, q, s.ID).Scan(&organizationID); err != nil {
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
return nil, ErrResourceNotFound
|
return nil, ErrResourceNotFound
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("cannot query state of applicability authorization attributes: %w", err)
|
return nil, fmt.Errorf("cannot query statement of applicability authorization attributes: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[string]string{"organization_id": organizationID.String()}, nil
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateOfApplicability) LoadByID(
|
func (s *StatementOfApplicability) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
) error {
|
) error {
|
||||||
q := `
|
q := `
|
||||||
SELECT
|
SELECT
|
||||||
@@ -85,43 +85,43 @@ SELECT
|
|||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
FROM
|
FROM
|
||||||
states_of_applicability
|
statements_of_applicability
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND id = @state_of_applicability_id
|
AND id = @statement_of_applicability_id
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
`
|
`
|
||||||
|
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{"state_of_applicability_id": stateOfApplicabilityID}
|
args := pgx.StrictNamedArgs{"statement_of_applicability_id": statementOfApplicabilityID}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
rows, err := conn.Query(ctx, q, args)
|
rows, err := conn.Query(ctx, q, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot query states_of_applicability: %w", err)
|
return fmt.Errorf("cannot query statements_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stateOfApplicability, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[StateOfApplicability])
|
statementOfApplicability, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[StatementOfApplicability])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
return ErrResourceNotFound
|
return ErrResourceNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("cannot collect state_of_applicability: %w", err)
|
return fmt.Errorf("cannot collect statement_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
*s = stateOfApplicability
|
*s = statementOfApplicability
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StatesOfApplicability) LoadByOrganizationID(
|
func (s *StatementsOfApplicability) LoadByOrganizationID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
organizationID gid.GID,
|
organizationID gid.GID,
|
||||||
cursor *page.Cursor[StateOfApplicabilityOrderField],
|
cursor *page.Cursor[StatementOfApplicabilityOrderField],
|
||||||
filter *StateOfApplicabilityFilter,
|
filter *StatementOfApplicabilityFilter,
|
||||||
) error {
|
) error {
|
||||||
q := `
|
q := `
|
||||||
SELECT
|
SELECT
|
||||||
@@ -134,7 +134,7 @@ SELECT
|
|||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
FROM
|
FROM
|
||||||
states_of_applicability
|
statements_of_applicability
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND organization_id = @organization_id
|
AND organization_id = @organization_id
|
||||||
@@ -150,30 +150,30 @@ WHERE
|
|||||||
|
|
||||||
rows, err := conn.Query(ctx, q, args)
|
rows, err := conn.Query(ctx, q, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot query states_of_applicability: %w", err)
|
return fmt.Errorf("cannot query statements_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
statesOfApplicability, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[StateOfApplicability])
|
statementsOfApplicability, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[StatementOfApplicability])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot collect states_of_applicability: %w", err)
|
return fmt.Errorf("cannot collect statements_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
*s = statesOfApplicability
|
*s = statementsOfApplicability
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StatesOfApplicability) CountByOrganizationID(
|
func (s *StatementsOfApplicability) CountByOrganizationID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
organizationID gid.GID,
|
organizationID gid.GID,
|
||||||
filter *StateOfApplicabilityFilter,
|
filter *StatementOfApplicabilityFilter,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
q := `
|
q := `
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
FROM
|
FROM
|
||||||
states_of_applicability
|
statements_of_applicability
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND organization_id = @organization_id
|
AND organization_id = @organization_id
|
||||||
@@ -190,20 +190,20 @@ WHERE
|
|||||||
row := conn.QueryRow(ctx, q, args)
|
row := conn.QueryRow(ctx, q, args)
|
||||||
var count int
|
var count int
|
||||||
if err := row.Scan(&count); err != nil {
|
if err := row.Scan(&count); err != nil {
|
||||||
return 0, fmt.Errorf("cannot count states_of_applicability: %w", err)
|
return 0, fmt.Errorf("cannot count statements_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateOfApplicability) Insert(
|
func (s *StatementOfApplicability) Insert(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Tx,
|
conn pg.Tx,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
) error {
|
) error {
|
||||||
q := `
|
q := `
|
||||||
INSERT INTO
|
INSERT INTO
|
||||||
states_of_applicability (
|
statements_of_applicability (
|
||||||
tenant_id,
|
tenant_id,
|
||||||
id,
|
id,
|
||||||
organization_id,
|
organization_id,
|
||||||
@@ -216,7 +216,7 @@ INSERT INTO
|
|||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
@tenant_id,
|
@tenant_id,
|
||||||
@state_of_applicability_id,
|
@statement_of_applicability_id,
|
||||||
@organization_id,
|
@organization_id,
|
||||||
@name,
|
@name,
|
||||||
@source_id,
|
@source_id,
|
||||||
@@ -228,15 +228,15 @@ VALUES (
|
|||||||
`
|
`
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"tenant_id": scope.GetTenantID(),
|
"tenant_id": scope.GetTenantID(),
|
||||||
"state_of_applicability_id": s.ID,
|
"statement_of_applicability_id": s.ID,
|
||||||
"organization_id": s.OrganizationID,
|
"organization_id": s.OrganizationID,
|
||||||
"name": s.Name,
|
"name": s.Name,
|
||||||
"source_id": s.SourceID,
|
"source_id": s.SourceID,
|
||||||
"snapshot_id": s.SnapshotID,
|
"snapshot_id": s.SnapshotID,
|
||||||
"owner_profile_id": s.OwnerID,
|
"owner_profile_id": s.OwnerID,
|
||||||
"created_at": s.CreatedAt,
|
"created_at": s.CreatedAt,
|
||||||
"updated_at": s.UpdatedAt,
|
"updated_at": s.UpdatedAt,
|
||||||
}
|
}
|
||||||
_, err := conn.Exec(ctx, q, args)
|
_, err := conn.Exec(ctx, q, args)
|
||||||
|
|
||||||
@@ -247,35 +247,35 @@ VALUES (
|
|||||||
return ErrResourceAlreadyExists
|
return ErrResourceAlreadyExists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Errorf("cannot insert state_of_applicability: %w", err)
|
return fmt.Errorf("cannot insert statement_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateOfApplicability) Update(
|
func (s *StatementOfApplicability) Update(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Tx,
|
conn pg.Tx,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
) error {
|
) error {
|
||||||
q := `
|
q := `
|
||||||
UPDATE states_of_applicability
|
UPDATE statements_of_applicability
|
||||||
SET
|
SET
|
||||||
name = @name,
|
name = @name,
|
||||||
owner_profile_id = @owner_profile_id,
|
owner_profile_id = @owner_profile_id,
|
||||||
updated_at = @updated_at
|
updated_at = @updated_at
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND id = @state_of_applicability_id
|
AND id = @statement_of_applicability_id
|
||||||
`
|
`
|
||||||
|
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"state_of_applicability_id": s.ID,
|
"statement_of_applicability_id": s.ID,
|
||||||
"name": s.Name,
|
"name": s.Name,
|
||||||
"owner_profile_id": s.OwnerID,
|
"owner_profile_id": s.OwnerID,
|
||||||
"updated_at": s.UpdatedAt,
|
"updated_at": s.UpdatedAt,
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ WHERE
|
|||||||
return ErrResourceAlreadyExists
|
return ErrResourceAlreadyExists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Errorf("cannot update state_of_applicability: %w", err)
|
return fmt.Errorf("cannot update statement_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.RowsAffected() == 0 {
|
if result.RowsAffected() == 0 {
|
||||||
@@ -297,27 +297,27 @@ WHERE
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateOfApplicability) Delete(
|
func (s *StatementOfApplicability) Delete(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Tx,
|
conn pg.Tx,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
) error {
|
) error {
|
||||||
q := `
|
q := `
|
||||||
DELETE FROM states_of_applicability
|
DELETE FROM statements_of_applicability
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND id = @state_of_applicability_id
|
AND id = @statement_of_applicability_id
|
||||||
`
|
`
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"state_of_applicability_id": s.ID,
|
"statement_of_applicability_id": s.ID,
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
result, err := conn.Exec(ctx, q, args)
|
result, err := conn.Exec(ctx, q, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot delete state_of_applicability: %w", err)
|
return fmt.Errorf("cannot delete statement_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.RowsAffected() == 0 {
|
if result.RowsAffected() == 0 {
|
||||||
@@ -327,19 +327,19 @@ WHERE
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (soas StatesOfApplicability) Snapshot(ctx context.Context, conn pg.Tx, scope Scoper, organizationID, snapshotID gid.GID) error {
|
func (soas StatementsOfApplicability) Snapshot(ctx context.Context, conn pg.Tx, scope Scoper, organizationID, snapshotID gid.GID) error {
|
||||||
if err := soas.insertStateOfApplicabilitySnapshots(ctx, conn, scope, organizationID, snapshotID); err != nil {
|
if err := soas.insertStatementOfApplicabilitySnapshots(ctx, conn, scope, organizationID, snapshotID); err != nil {
|
||||||
return fmt.Errorf("cannot insert state_of_applicability snapshots: %w", err)
|
return fmt.Errorf("cannot insert statement_of_applicability snapshots: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := soas.insertStateOfApplicabilityControlSnapshots(ctx, conn, scope, organizationID, snapshotID); err != nil {
|
if err := soas.insertStatementOfApplicabilityControlSnapshots(ctx, conn, scope, organizationID, snapshotID); err != nil {
|
||||||
return fmt.Errorf("cannot insert state_of_applicability_control snapshots: %w", err)
|
return fmt.Errorf("cannot insert statement_of_applicability_control snapshots: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (soas StatesOfApplicability) insertStateOfApplicabilitySnapshots(
|
func (soas StatementsOfApplicability) insertStatementOfApplicabilitySnapshots(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
@@ -347,7 +347,7 @@ func (soas StatesOfApplicability) insertStateOfApplicabilitySnapshots(
|
|||||||
snapshotID gid.GID,
|
snapshotID gid.GID,
|
||||||
) error {
|
) error {
|
||||||
query := `
|
query := `
|
||||||
INSERT INTO states_of_applicability (
|
INSERT INTO statements_of_applicability (
|
||||||
id,
|
id,
|
||||||
tenant_id,
|
tenant_id,
|
||||||
organization_id,
|
organization_id,
|
||||||
@@ -359,7 +359,7 @@ INSERT INTO states_of_applicability (
|
|||||||
updated_at
|
updated_at
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
generate_gid(decode_base64_unpadded(@tenant_id), @state_of_applicability_entity_type),
|
generate_gid(decode_base64_unpadded(@tenant_id), @statement_of_applicability_entity_type),
|
||||||
@tenant_id,
|
@tenant_id,
|
||||||
soa.organization_id,
|
soa.organization_id,
|
||||||
soa.name,
|
soa.name,
|
||||||
@@ -368,7 +368,7 @@ SELECT
|
|||||||
soa.owner_profile_id,
|
soa.owner_profile_id,
|
||||||
soa.created_at,
|
soa.created_at,
|
||||||
soa.updated_at
|
soa.updated_at
|
||||||
FROM states_of_applicability soa
|
FROM statements_of_applicability soa
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND soa.organization_id = @organization_id
|
AND soa.organization_id = @organization_id
|
||||||
@@ -378,22 +378,22 @@ WHERE
|
|||||||
query = fmt.Sprintf(query, scope.SQLFragment())
|
query = fmt.Sprintf(query, scope.SQLFragment())
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"tenant_id": scope.GetTenantID(),
|
"tenant_id": scope.GetTenantID(),
|
||||||
"snapshot_id": snapshotID,
|
"snapshot_id": snapshotID,
|
||||||
"organization_id": organizationID,
|
"organization_id": organizationID,
|
||||||
"state_of_applicability_entity_type": StateOfApplicabilityEntityType,
|
"statement_of_applicability_entity_type": StatementOfApplicabilityEntityType,
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
_, err := conn.Exec(ctx, query, args)
|
_, err := conn.Exec(ctx, query, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot insert state_of_applicability snapshots: %w", err)
|
return fmt.Errorf("cannot insert statement_of_applicability snapshots: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (soas StatesOfApplicability) insertStateOfApplicabilityControlSnapshots(
|
func (soas StatementsOfApplicability) insertStatementOfApplicabilityControlSnapshots(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
@@ -403,7 +403,7 @@ func (soas StatesOfApplicability) insertStateOfApplicabilityControlSnapshots(
|
|||||||
query := `
|
query := `
|
||||||
WITH source_soa AS (
|
WITH source_soa AS (
|
||||||
SELECT id, organization_id
|
SELECT id, organization_id
|
||||||
FROM states_of_applicability
|
FROM statements_of_applicability
|
||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND organization_id = @organization_id
|
AND organization_id = @organization_id
|
||||||
@@ -411,12 +411,12 @@ WITH source_soa AS (
|
|||||||
),
|
),
|
||||||
snapshot_soa AS (
|
snapshot_soa AS (
|
||||||
SELECT id, source_id
|
SELECT id, source_id
|
||||||
FROM states_of_applicability
|
FROM statements_of_applicability
|
||||||
WHERE snapshot_id = @snapshot_id
|
WHERE snapshot_id = @snapshot_id
|
||||||
)
|
)
|
||||||
INSERT INTO applicability_statements (
|
INSERT INTO applicability_statements (
|
||||||
id,
|
id,
|
||||||
state_of_applicability_id,
|
statement_of_applicability_id,
|
||||||
control_id,
|
control_id,
|
||||||
organization_id,
|
organization_id,
|
||||||
tenant_id,
|
tenant_id,
|
||||||
@@ -439,7 +439,7 @@ SELECT
|
|||||||
soac.updated_at
|
soac.updated_at
|
||||||
FROM applicability_statements soac
|
FROM applicability_statements soac
|
||||||
INNER JOIN source_soa
|
INNER JOIN source_soa
|
||||||
ON soac.state_of_applicability_id = source_soa.id
|
ON soac.statement_of_applicability_id = source_soa.id
|
||||||
INNER JOIN snapshot_soa
|
INNER JOIN snapshot_soa
|
||||||
ON snapshot_soa.source_id = source_soa.id
|
ON snapshot_soa.source_id = source_soa.id
|
||||||
WHERE soac.snapshot_id IS NULL
|
WHERE soac.snapshot_id IS NULL
|
||||||
@@ -457,7 +457,7 @@ WHERE soac.snapshot_id IS NULL
|
|||||||
|
|
||||||
_, err := conn.Exec(ctx, query, args)
|
_, err := conn.Exec(ctx, query, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot insert state_of_applicability_control snapshots: %w", err)
|
return fmt.Errorf("cannot insert statement_of_applicability_control snapshots: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -20,18 +20,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
StateOfApplicabilityFilter struct {
|
StatementOfApplicabilityFilter struct {
|
||||||
snapshotID **gid.GID
|
snapshotID **gid.GID
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewStateOfApplicabilityFilter(snapshotID **gid.GID) *StateOfApplicabilityFilter {
|
func NewStatementOfApplicabilityFilter(snapshotID **gid.GID) *StatementOfApplicabilityFilter {
|
||||||
return &StateOfApplicabilityFilter{
|
return &StatementOfApplicabilityFilter{
|
||||||
snapshotID: snapshotID,
|
snapshotID: snapshotID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *StateOfApplicabilityFilter) SQLArguments() pgx.StrictNamedArgs {
|
func (f *StatementOfApplicabilityFilter) SQLArguments() pgx.StrictNamedArgs {
|
||||||
args := pgx.StrictNamedArgs{}
|
args := pgx.StrictNamedArgs{}
|
||||||
|
|
||||||
if f.snapshotID == nil {
|
if f.snapshotID == nil {
|
||||||
@@ -48,7 +48,7 @@ func (f *StateOfApplicabilityFilter) SQLArguments() pgx.StrictNamedArgs {
|
|||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *StateOfApplicabilityFilter) SQLFragment() string {
|
func (f *StatementOfApplicabilityFilter) SQLFragment() string {
|
||||||
return `
|
return `
|
||||||
CASE
|
CASE
|
||||||
WHEN @has_snapshot_filter::boolean = false THEN TRUE
|
WHEN @has_snapshot_filter::boolean = false THEN TRUE
|
||||||
@@ -19,44 +19,44 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
StateOfApplicabilityOrderField string
|
StatementOfApplicabilityOrderField string
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StateOfApplicabilityOrderFieldName StateOfApplicabilityOrderField = "NAME"
|
StatementOfApplicabilityOrderFieldName StatementOfApplicabilityOrderField = "NAME"
|
||||||
StateOfApplicabilityOrderFieldCreatedAt StateOfApplicabilityOrderField = "CREATED_AT"
|
StatementOfApplicabilityOrderFieldCreatedAt StatementOfApplicabilityOrderField = "CREATED_AT"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s StateOfApplicabilityOrderField) Column() string {
|
func (s StatementOfApplicabilityOrderField) Column() string {
|
||||||
switch s {
|
switch s {
|
||||||
case StateOfApplicabilityOrderFieldName:
|
case StatementOfApplicabilityOrderFieldName:
|
||||||
return "name"
|
return "name"
|
||||||
case StateOfApplicabilityOrderFieldCreatedAt:
|
case StatementOfApplicabilityOrderFieldCreatedAt:
|
||||||
return "created_at"
|
return "created_at"
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("unsupported order by: %s", s))
|
panic(fmt.Sprintf("unsupported order by: %s", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityOrderField) String() string {
|
func (s StatementOfApplicabilityOrderField) String() string {
|
||||||
return string(s)
|
return string(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityOrderField) IsValid() bool {
|
func (s StatementOfApplicabilityOrderField) IsValid() bool {
|
||||||
switch s {
|
switch s {
|
||||||
case StateOfApplicabilityOrderFieldName, StateOfApplicabilityOrderFieldCreatedAt:
|
case StatementOfApplicabilityOrderFieldName, StatementOfApplicabilityOrderFieldCreatedAt:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityOrderField) MarshalText() ([]byte, error) {
|
func (s StatementOfApplicabilityOrderField) MarshalText() ([]byte, error) {
|
||||||
return []byte(s.String()), nil
|
return []byte(s.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateOfApplicabilityOrderField) UnmarshalText(text []byte) error {
|
func (s *StatementOfApplicabilityOrderField) UnmarshalText(text []byte) error {
|
||||||
*s = StateOfApplicabilityOrderField(text)
|
*s = StatementOfApplicabilityOrderField(text)
|
||||||
if !s.IsValid() {
|
if !s.IsValid() {
|
||||||
return fmt.Errorf("%s is not a valid StateOfApplicabilityOrderField", string(text))
|
return fmt.Errorf("%s is not a valid StatementOfApplicabilityOrderField", string(text))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -187,7 +187,7 @@ var (
|
|||||||
|
|
||||||
transferImpactAssessmentsTemplate = template.Must(template.New("transferImpactAssessments").Funcs(templateFuncs).Parse(transferImpactAssessmentsTemplateContent))
|
transferImpactAssessmentsTemplate = template.Must(template.New("transferImpactAssessments").Funcs(templateFuncs).Parse(transferImpactAssessmentsTemplateContent))
|
||||||
|
|
||||||
stateOfApplicabilityTemplate = template.Must(template.New("state-of-applicability").Funcs(templateFuncs).Parse(soaTemplateContent))
|
statementOfApplicabilityTemplate = template.Must(template.New("statement-of-applicability").Funcs(templateFuncs).Parse(soaTemplateContent))
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -279,7 +279,7 @@ type (
|
|||||||
SupplementaryMeasures *string
|
SupplementaryMeasures *string
|
||||||
}
|
}
|
||||||
|
|
||||||
StateOfApplicabilityData struct {
|
StatementOfApplicabilityData struct {
|
||||||
Title string
|
Title string
|
||||||
OrganizationName string
|
OrganizationName string
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
@@ -382,9 +382,9 @@ func RenderTransferImpactAssessmentsTableHTML(data TransferImpactAssessmentTable
|
|||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenderStateOfApplicabilityHTML(data StateOfApplicabilityData) ([]byte, error) {
|
func RenderStatementOfApplicabilityHTML(data StatementOfApplicabilityData) ([]byte, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := stateOfApplicabilityTemplate.Execute(&buf, data); err != nil {
|
if err := statementOfApplicabilityTemplate.Execute(&buf, data); err != nil {
|
||||||
return nil, fmt.Errorf("cannot execute SOA template: %w", err)
|
return nil, fmt.Errorf("cannot execute SOA template: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>State of Applicability</title>
|
<title>Statement of Applicability</title>
|
||||||
<style>
|
<style>
|
||||||
@page {
|
@page {
|
||||||
size: A4 landscape;
|
size: A4 landscape;
|
||||||
@@ -254,7 +254,7 @@
|
|||||||
{{- end}}
|
{{- end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 class="export-title">State of Applicability</h1>
|
<h1 class="export-title">Statement of Applicability</h1>
|
||||||
<h2 class="export-subtitle">{{.Title}}</h2>
|
<h2 class="export-subtitle">{{.Title}}</h2>
|
||||||
|
|
||||||
<div class="document-meta">
|
<div class="document-meta">
|
||||||
@@ -283,7 +283,7 @@
|
|||||||
<div class="purpose-section">
|
<div class="purpose-section">
|
||||||
<div class="purpose-title">1. Purpose</div>
|
<div class="purpose-title">1. Purpose</div>
|
||||||
<div class="purpose-text">
|
<div class="purpose-text">
|
||||||
This document provides a comprehensive overview of the state of applicability for controls within the organization.
|
This document provides a comprehensive overview of the statement of applicability for controls within the organization.
|
||||||
It serves as a record of which controls are applicable or not applicable to the organization, along with their
|
It serves as a record of which controls are applicable or not applicable to the organization, along with their
|
||||||
relationships to regulatory requirements, contractual obligations, risk assessments, and best practices.
|
relationships to regulatory requirements, contractual obligations, risk assessments, and best practices.
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -340,13 +340,13 @@ const (
|
|||||||
ActionRightsRequestUpdate = "core:rights-request:update"
|
ActionRightsRequestUpdate = "core:rights-request:update"
|
||||||
ActionRightsRequestDelete = "core:rights-request:delete"
|
ActionRightsRequestDelete = "core:rights-request:delete"
|
||||||
|
|
||||||
// StateOfApplicability actions
|
// StatementOfApplicability actions
|
||||||
ActionStateOfApplicabilityList = "core:state-of-applicability:list"
|
ActionStatementOfApplicabilityList = "core:statement-of-applicability:list"
|
||||||
ActionStateOfApplicabilityGet = "core:state-of-applicability:get"
|
ActionStatementOfApplicabilityGet = "core:statement-of-applicability:get"
|
||||||
ActionStateOfApplicabilityCreate = "core:state-of-applicability:create"
|
ActionStatementOfApplicabilityCreate = "core:statement-of-applicability:create"
|
||||||
ActionStateOfApplicabilityUpdate = "core:state-of-applicability:update"
|
ActionStatementOfApplicabilityUpdate = "core:statement-of-applicability:update"
|
||||||
ActionStateOfApplicabilityDelete = "core:state-of-applicability:delete"
|
ActionStatementOfApplicabilityDelete = "core:statement-of-applicability:delete"
|
||||||
ActionStateOfApplicabilityExport = "core:state-of-applicability:export"
|
ActionStatementOfApplicabilityExport = "core:statement-of-applicability:export"
|
||||||
|
|
||||||
ActionApplicabilityStatementGet = "core:applicability-statement:get"
|
ActionApplicabilityStatementGet = "core:applicability-statement:get"
|
||||||
ActionApplicabilityStatementList = "core:applicability-statement:list"
|
ActionApplicabilityStatementList = "core:applicability-statement:list"
|
||||||
|
|||||||
@@ -816,9 +816,9 @@ func (s ControlService) ListForSnapshotID(
|
|||||||
return page.NewPage([]*coredata.Control(controls), cursor), nil
|
return page.NewPage([]*coredata.Control(controls), cursor), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s ControlService) CountForStateOfApplicabilityID(
|
func (s ControlService) CountForStatementOfApplicabilityID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
filter *coredata.ControlFilter,
|
filter *coredata.ControlFilter,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
var count int
|
var count int
|
||||||
@@ -827,7 +827,7 @@ func (s ControlService) CountForStateOfApplicabilityID(
|
|||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Querier) (err error) {
|
func(ctx context.Context, conn pg.Querier) (err error) {
|
||||||
controls := &coredata.Controls{}
|
controls := &coredata.Controls{}
|
||||||
count, err = controls.CountByStateOfApplicabilityID(ctx, conn, s.svc.scope, stateOfApplicabilityID, filter)
|
count, err = controls.CountByStatementOfApplicabilityID(ctx, conn, s.svc.scope, statementOfApplicabilityID, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot count controls: %w", err)
|
return fmt.Errorf("cannot count controls: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ var ViewerPolicy = policy.NewPolicy(
|
|||||||
ActionFileGet, ActionFileDownloadUrl,
|
ActionFileGet, ActionFileDownloadUrl,
|
||||||
ActionSlackConnectionList, ActionConnectorList,
|
ActionSlackConnectionList, ActionConnectorList,
|
||||||
ActionRightsRequestGet, ActionRightsRequestList,
|
ActionRightsRequestGet, ActionRightsRequestList,
|
||||||
ActionStateOfApplicabilityGet, ActionStateOfApplicabilityList,
|
ActionStatementOfApplicabilityGet, ActionStatementOfApplicabilityList,
|
||||||
ActionApplicabilityStatementGet, ActionApplicabilityStatementList,
|
ActionApplicabilityStatementGet, ActionApplicabilityStatementList,
|
||||||
ActionWebhookSubscriptionGet, ActionWebhookSubscriptionList,
|
ActionWebhookSubscriptionGet, ActionWebhookSubscriptionList,
|
||||||
ActionAccessReviewCampaignGet, ActionAccessReviewCampaignList,
|
ActionAccessReviewCampaignGet, ActionAccessReviewCampaignList,
|
||||||
@@ -222,7 +222,7 @@ var AuditorPolicy = policy.NewPolicy(
|
|||||||
ActionTransferImpactAssessmentGet, ActionTransferImpactAssessmentList,
|
ActionTransferImpactAssessmentGet, ActionTransferImpactAssessmentList,
|
||||||
ActionSnapshotGet, ActionSnapshotList,
|
ActionSnapshotGet, ActionSnapshotList,
|
||||||
ActionFileGet, ActionFileDownloadUrl,
|
ActionFileGet, ActionFileDownloadUrl,
|
||||||
ActionStateOfApplicabilityGet, ActionStateOfApplicabilityList,
|
ActionStatementOfApplicabilityGet, ActionStatementOfApplicabilityList,
|
||||||
ActionApplicabilityStatementGet, ActionApplicabilityStatementList,
|
ActionApplicabilityStatementGet, ActionApplicabilityStatementList,
|
||||||
).WithSID("entity-read-access").When(organizationCondition),
|
).WithSID("entity-read-access").When(organizationCondition),
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ var AuditorPolicy = policy.NewPolicy(
|
|||||||
).WithSID("employee-document-access").When(organizationCondition),
|
).WithSID("employee-document-access").When(organizationCondition),
|
||||||
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionStateOfApplicabilityExport,
|
ActionStatementOfApplicabilityExport,
|
||||||
).WithSID("soa-export").When(organizationCondition),
|
).WithSID("soa-export").When(organizationCondition),
|
||||||
).WithDescription("Read-only probo access for auditors (excludes internal/employee content)")
|
).WithDescription("Read-only probo access for auditors (excludes internal/employee content)")
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ type (
|
|||||||
ProcessingActivities *ProcessingActivityService
|
ProcessingActivities *ProcessingActivityService
|
||||||
DataProtectionImpactAssessments *DataProtectionImpactAssessmentService
|
DataProtectionImpactAssessments *DataProtectionImpactAssessmentService
|
||||||
TransferImpactAssessments *TransferImpactAssessmentService
|
TransferImpactAssessments *TransferImpactAssessmentService
|
||||||
StatesOfApplicability *StateOfApplicabilityService
|
StatementsOfApplicability *StatementOfApplicabilityService
|
||||||
Files *FileService
|
Files *FileService
|
||||||
CustomDomains *CustomDomainService
|
CustomDomains *CustomDomainService
|
||||||
SlackMessages *slack.SlackMessageService
|
SlackMessages *slack.SlackMessageService
|
||||||
@@ -283,7 +283,7 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
|||||||
svc: tenantService,
|
svc: tenantService,
|
||||||
html2pdfConverter: s.html2pdfConverter,
|
html2pdfConverter: s.html2pdfConverter,
|
||||||
}
|
}
|
||||||
tenantService.StatesOfApplicability = &StateOfApplicabilityService{
|
tenantService.StatementsOfApplicability = &StatementOfApplicabilityService{
|
||||||
svc: tenantService,
|
svc: tenantService,
|
||||||
html2pdfConverter: s.html2pdfConverter,
|
html2pdfConverter: s.html2pdfConverter,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,26 +29,26 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/validator"
|
"go.probo.inc/probo/pkg/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StateOfApplicabilityService struct {
|
type StatementOfApplicabilityService struct {
|
||||||
svc *TenantService
|
svc *TenantService
|
||||||
html2pdfConverter *html2pdf.Converter
|
html2pdfConverter *html2pdf.Converter
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
CreateStateOfApplicabilityRequest struct {
|
CreateStatementOfApplicabilityRequest struct {
|
||||||
OrganizationID gid.GID
|
OrganizationID gid.GID
|
||||||
Name string
|
Name string
|
||||||
OwnerID gid.GID
|
OwnerID gid.GID
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateStateOfApplicabilityRequest struct {
|
UpdateStatementOfApplicabilityRequest struct {
|
||||||
StateOfApplicabilityID gid.GID
|
StatementOfApplicabilityID gid.GID
|
||||||
Name *string
|
Name *string
|
||||||
OwnerID *gid.GID
|
OwnerID *gid.GID
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (csr *CreateStateOfApplicabilityRequest) Validate() error {
|
func (csr *CreateStatementOfApplicabilityRequest) Validate() error {
|
||||||
v := validator.New()
|
v := validator.New()
|
||||||
|
|
||||||
v.Check(csr.OrganizationID, "organization_id", validator.Required(), validator.GID(coredata.OrganizationEntityType))
|
v.Check(csr.OrganizationID, "organization_id", validator.Required(), validator.GID(coredata.OrganizationEntityType))
|
||||||
@@ -58,23 +58,23 @@ func (csr *CreateStateOfApplicabilityRequest) Validate() error {
|
|||||||
return v.Error()
|
return v.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (usr *UpdateStateOfApplicabilityRequest) Validate() error {
|
func (usr *UpdateStatementOfApplicabilityRequest) Validate() error {
|
||||||
v := validator.New()
|
v := validator.New()
|
||||||
|
|
||||||
v.Check(usr.StateOfApplicabilityID, "state_of_applicability_id", validator.Required(), validator.GID(coredata.StateOfApplicabilityEntityType))
|
v.Check(usr.StatementOfApplicabilityID, "statement_of_applicability_id", validator.Required(), validator.GID(coredata.StatementOfApplicabilityEntityType))
|
||||||
v.Check(usr.Name, "name", validator.SafeTextNoNewLine(TitleMaxLength))
|
v.Check(usr.Name, "name", validator.SafeTextNoNewLine(TitleMaxLength))
|
||||||
v.Check(usr.OwnerID, "owner_id", validator.GID(coredata.MembershipProfileEntityType))
|
v.Check(usr.OwnerID, "owner_id", validator.GID(coredata.MembershipProfileEntityType))
|
||||||
|
|
||||||
return v.Error()
|
return v.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) ListForOrganizationID(
|
func (s StatementOfApplicabilityService) ListForOrganizationID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
organizationID gid.GID,
|
organizationID gid.GID,
|
||||||
cursor *page.Cursor[coredata.StateOfApplicabilityOrderField],
|
cursor *page.Cursor[coredata.StatementOfApplicabilityOrderField],
|
||||||
filter *coredata.StateOfApplicabilityFilter,
|
filter *coredata.StatementOfApplicabilityFilter,
|
||||||
) (*page.Page[*coredata.StateOfApplicability, coredata.StateOfApplicabilityOrderField], error) {
|
) (*page.Page[*coredata.StatementOfApplicability, coredata.StatementOfApplicabilityOrderField], error) {
|
||||||
var statesOfApplicability coredata.StatesOfApplicability
|
var statementsOfApplicability coredata.StatementsOfApplicability
|
||||||
organization := &coredata.Organization{}
|
organization := &coredata.Organization{}
|
||||||
|
|
||||||
err := s.svc.pg.WithConn(
|
err := s.svc.pg.WithConn(
|
||||||
@@ -84,7 +84,7 @@ func (s StateOfApplicabilityService) ListForOrganizationID(
|
|||||||
return fmt.Errorf("cannot load organization: %w", err)
|
return fmt.Errorf("cannot load organization: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := statesOfApplicability.LoadByOrganizationID(
|
err := statementsOfApplicability.LoadByOrganizationID(
|
||||||
ctx,
|
ctx,
|
||||||
conn,
|
conn,
|
||||||
s.svc.scope,
|
s.svc.scope,
|
||||||
@@ -93,7 +93,7 @@ func (s StateOfApplicabilityService) ListForOrganizationID(
|
|||||||
filter,
|
filter,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot load states_of_applicability: %w", err)
|
return fmt.Errorf("cannot load statements_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -104,23 +104,23 @@ func (s StateOfApplicabilityService) ListForOrganizationID(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return page.NewPage(statesOfApplicability, cursor), nil
|
return page.NewPage(statementsOfApplicability, cursor), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) CountForOrganizationID(
|
func (s StatementOfApplicabilityService) CountForOrganizationID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
organizationID gid.GID,
|
organizationID gid.GID,
|
||||||
filter *coredata.StateOfApplicabilityFilter,
|
filter *coredata.StatementOfApplicabilityFilter,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
var count int
|
var count int
|
||||||
|
|
||||||
err := s.svc.pg.WithConn(
|
err := s.svc.pg.WithConn(
|
||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Querier) (err error) {
|
func(ctx context.Context, conn pg.Querier) (err error) {
|
||||||
statesOfApplicability := &coredata.StatesOfApplicability{}
|
statementsOfApplicability := &coredata.StatementsOfApplicability{}
|
||||||
count, err = statesOfApplicability.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID, filter)
|
count, err = statementsOfApplicability.CountByOrganizationID(ctx, conn, s.svc.scope, organizationID, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot count states_of_applicability: %w", err)
|
return fmt.Errorf("cannot count statements_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -134,16 +134,16 @@ func (s StateOfApplicabilityService) CountForOrganizationID(
|
|||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) Get(
|
func (s StatementOfApplicabilityService) Get(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
) (*coredata.StateOfApplicability, error) {
|
) (*coredata.StatementOfApplicability, error) {
|
||||||
stateOfApplicability := &coredata.StateOfApplicability{}
|
statementOfApplicability := &coredata.StatementOfApplicability{}
|
||||||
|
|
||||||
err := s.svc.pg.WithConn(
|
err := s.svc.pg.WithConn(
|
||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Querier) error {
|
func(ctx context.Context, conn pg.Querier) error {
|
||||||
return stateOfApplicability.LoadByID(ctx, conn, s.svc.scope, stateOfApplicabilityID)
|
return statementOfApplicability.LoadByID(ctx, conn, s.svc.scope, statementOfApplicabilityID)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -151,13 +151,13 @@ func (s StateOfApplicabilityService) Get(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateOfApplicability, nil
|
return statementOfApplicability, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) Create(
|
func (s StatementOfApplicabilityService) Create(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req CreateStateOfApplicabilityRequest,
|
req CreateStatementOfApplicabilityRequest,
|
||||||
) (*coredata.StateOfApplicability, error) {
|
) (*coredata.StatementOfApplicability, error) {
|
||||||
if err := req.Validate(); err != nil {
|
if err := req.Validate(); err != nil {
|
||||||
return nil, fmt.Errorf("invalid request: %w", err)
|
return nil, fmt.Errorf("invalid request: %w", err)
|
||||||
}
|
}
|
||||||
@@ -175,9 +175,9 @@ func (s StateOfApplicabilityService) Create(
|
|||||||
return nil, fmt.Errorf("cannot load organization: %w", err)
|
return nil, fmt.Errorf("cannot load organization: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stateOfApplicabilityID := gid.New(organization.ID.TenantID(), coredata.StateOfApplicabilityEntityType)
|
statementOfApplicabilityID := gid.New(organization.ID.TenantID(), coredata.StatementOfApplicabilityEntityType)
|
||||||
stateOfApplicability := &coredata.StateOfApplicability{
|
statementOfApplicability := &coredata.StatementOfApplicability{
|
||||||
ID: stateOfApplicabilityID,
|
ID: statementOfApplicabilityID,
|
||||||
OrganizationID: organization.ID,
|
OrganizationID: organization.ID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
OwnerID: req.OwnerID,
|
OwnerID: req.OwnerID,
|
||||||
@@ -188,8 +188,8 @@ func (s StateOfApplicabilityService) Create(
|
|||||||
err = s.svc.pg.WithTx(
|
err = s.svc.pg.WithTx(
|
||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Tx) error {
|
func(ctx context.Context, conn pg.Tx) error {
|
||||||
if err := stateOfApplicability.Insert(ctx, conn, s.svc.scope); err != nil {
|
if err := statementOfApplicability.Insert(ctx, conn, s.svc.scope); err != nil {
|
||||||
return fmt.Errorf("cannot insert state_of_applicability: %w", err)
|
return fmt.Errorf("cannot insert statement_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -200,37 +200,37 @@ func (s StateOfApplicabilityService) Create(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateOfApplicability, nil
|
return statementOfApplicability, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) Update(
|
func (s StatementOfApplicabilityService) Update(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req UpdateStateOfApplicabilityRequest,
|
req UpdateStatementOfApplicabilityRequest,
|
||||||
) (*coredata.StateOfApplicability, error) {
|
) (*coredata.StatementOfApplicability, error) {
|
||||||
if err := req.Validate(); err != nil {
|
if err := req.Validate(); err != nil {
|
||||||
return nil, fmt.Errorf("invalid request: %w", err)
|
return nil, fmt.Errorf("invalid request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stateOfApplicability := &coredata.StateOfApplicability{}
|
statementOfApplicability := &coredata.StatementOfApplicability{}
|
||||||
|
|
||||||
err := s.svc.pg.WithTx(
|
err := s.svc.pg.WithTx(
|
||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Tx) error {
|
func(ctx context.Context, conn pg.Tx) error {
|
||||||
if err := stateOfApplicability.LoadByID(ctx, conn, s.svc.scope, req.StateOfApplicabilityID); err != nil {
|
if err := statementOfApplicability.LoadByID(ctx, conn, s.svc.scope, req.StatementOfApplicabilityID); err != nil {
|
||||||
return fmt.Errorf("cannot load state_of_applicability: %w", err)
|
return fmt.Errorf("cannot load statement_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Name != nil {
|
if req.Name != nil {
|
||||||
stateOfApplicability.Name = *req.Name
|
statementOfApplicability.Name = *req.Name
|
||||||
}
|
}
|
||||||
if req.OwnerID != nil {
|
if req.OwnerID != nil {
|
||||||
stateOfApplicability.OwnerID = *req.OwnerID
|
statementOfApplicability.OwnerID = *req.OwnerID
|
||||||
}
|
}
|
||||||
|
|
||||||
stateOfApplicability.UpdatedAt = time.Now()
|
statementOfApplicability.UpdatedAt = time.Now()
|
||||||
|
|
||||||
if err := stateOfApplicability.Update(ctx, conn, s.svc.scope); err != nil {
|
if err := statementOfApplicability.Update(ctx, conn, s.svc.scope); err != nil {
|
||||||
return fmt.Errorf("cannot update state_of_applicability: %w", err)
|
return fmt.Errorf("cannot update statement_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -241,24 +241,24 @@ func (s StateOfApplicabilityService) Update(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateOfApplicability, nil
|
return statementOfApplicability, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) Delete(
|
func (s StatementOfApplicabilityService) Delete(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
) error {
|
) error {
|
||||||
stateOfApplicability := &coredata.StateOfApplicability{ID: stateOfApplicabilityID}
|
statementOfApplicability := &coredata.StatementOfApplicability{ID: statementOfApplicabilityID}
|
||||||
|
|
||||||
err := s.svc.pg.WithTx(
|
err := s.svc.pg.WithTx(
|
||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Tx) error {
|
func(ctx context.Context, conn pg.Tx) error {
|
||||||
if err := stateOfApplicability.LoadByID(ctx, conn, s.svc.scope, stateOfApplicabilityID); err != nil {
|
if err := statementOfApplicability.LoadByID(ctx, conn, s.svc.scope, statementOfApplicabilityID); err != nil {
|
||||||
return fmt.Errorf("cannot load state_of_applicability: %w", err)
|
return fmt.Errorf("cannot load statement_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := stateOfApplicability.Delete(ctx, conn, s.svc.scope); err != nil {
|
if err := statementOfApplicability.Delete(ctx, conn, s.svc.scope); err != nil {
|
||||||
return fmt.Errorf("cannot delete state_of_applicability: %w", err)
|
return fmt.Errorf("cannot delete statement_of_applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -272,7 +272,7 @@ func (s StateOfApplicabilityService) Delete(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) GetApplicabilityStatement(
|
func (s StatementOfApplicabilityService) GetApplicabilityStatement(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
applicabilityStatementID gid.GID,
|
applicabilityStatementID gid.GID,
|
||||||
) (*coredata.ApplicabilityStatement, error) {
|
) (*coredata.ApplicabilityStatement, error) {
|
||||||
@@ -291,9 +291,9 @@ func (s StateOfApplicabilityService) GetApplicabilityStatement(
|
|||||||
return applicabilityStatement, nil
|
return applicabilityStatement, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) ListApplicabilityStatements(
|
func (s StatementOfApplicabilityService) ListApplicabilityStatements(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
cursor *page.Cursor[coredata.ApplicabilityStatementOrderField],
|
cursor *page.Cursor[coredata.ApplicabilityStatementOrderField],
|
||||||
) (*page.Page[*coredata.ApplicabilityStatement, coredata.ApplicabilityStatementOrderField], error) {
|
) (*page.Page[*coredata.ApplicabilityStatement, coredata.ApplicabilityStatementOrderField], error) {
|
||||||
var statements coredata.ApplicabilityStatements
|
var statements coredata.ApplicabilityStatements
|
||||||
@@ -301,7 +301,7 @@ func (s StateOfApplicabilityService) ListApplicabilityStatements(
|
|||||||
err := s.svc.pg.WithConn(
|
err := s.svc.pg.WithConn(
|
||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Querier) error {
|
func(ctx context.Context, conn pg.Querier) error {
|
||||||
if err := statements.LoadByStateOfApplicabilityID(ctx, conn, s.svc.scope, stateOfApplicabilityID, cursor); err != nil {
|
if err := statements.LoadByStatementOfApplicabilityID(ctx, conn, s.svc.scope, statementOfApplicabilityID, cursor); err != nil {
|
||||||
return fmt.Errorf("cannot load applicability statements: %w", err)
|
return fmt.Errorf("cannot load applicability statements: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -315,9 +315,9 @@ func (s StateOfApplicabilityService) ListApplicabilityStatements(
|
|||||||
return page.NewPage(statements, cursor), nil
|
return page.NewPage(statements, cursor), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) CountApplicabilityStatements(
|
func (s StatementOfApplicabilityService) CountApplicabilityStatements(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
) (int, error) {
|
) (int, error) {
|
||||||
var count int
|
var count int
|
||||||
|
|
||||||
@@ -325,7 +325,7 @@ func (s StateOfApplicabilityService) CountApplicabilityStatements(
|
|||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Querier) (err error) {
|
func(ctx context.Context, conn pg.Querier) (err error) {
|
||||||
statements := &coredata.ApplicabilityStatements{}
|
statements := &coredata.ApplicabilityStatements{}
|
||||||
count, err = statements.CountByStateOfApplicabilityID(ctx, conn, s.svc.scope, stateOfApplicabilityID)
|
count, err = statements.CountByStatementOfApplicabilityID(ctx, conn, s.svc.scope, statementOfApplicabilityID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot count applicability statements: %w", err)
|
return fmt.Errorf("cannot count applicability statements: %w", err)
|
||||||
}
|
}
|
||||||
@@ -340,35 +340,35 @@ func (s StateOfApplicabilityService) CountApplicabilityStatements(
|
|||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) CreateApplicabilityStatement(
|
func (s StatementOfApplicabilityService) CreateApplicabilityStatement(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
controlID gid.GID,
|
controlID gid.GID,
|
||||||
applicability bool,
|
applicability bool,
|
||||||
justification *string,
|
justification *string,
|
||||||
) (*coredata.ApplicabilityStatement, error) {
|
) (*coredata.ApplicabilityStatement, error) {
|
||||||
var (
|
var (
|
||||||
stateOfApplicability = &coredata.StateOfApplicability{}
|
statementOfApplicability = &coredata.StatementOfApplicability{}
|
||||||
applicabilityStatement = &coredata.ApplicabilityStatement{}
|
applicabilityStatement = &coredata.ApplicabilityStatement{}
|
||||||
now = time.Now()
|
now = time.Now()
|
||||||
)
|
)
|
||||||
|
|
||||||
err := s.svc.pg.WithTx(
|
err := s.svc.pg.WithTx(
|
||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Tx) error {
|
func(ctx context.Context, conn pg.Tx) error {
|
||||||
if err := stateOfApplicability.LoadByID(ctx, conn, s.svc.scope, stateOfApplicabilityID); err != nil {
|
if err := statementOfApplicability.LoadByID(ctx, conn, s.svc.scope, statementOfApplicabilityID); err != nil {
|
||||||
return fmt.Errorf("cannot load state of applicability: %w", err)
|
return fmt.Errorf("cannot load statement of applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
applicabilityStatement = &coredata.ApplicabilityStatement{
|
applicabilityStatement = &coredata.ApplicabilityStatement{
|
||||||
ID: gid.New(s.svc.scope.GetTenantID(), coredata.ApplicabilityStatementEntityType),
|
ID: gid.New(s.svc.scope.GetTenantID(), coredata.ApplicabilityStatementEntityType),
|
||||||
StateOfApplicabilityID: stateOfApplicabilityID,
|
StatementOfApplicabilityID: statementOfApplicabilityID,
|
||||||
ControlID: controlID,
|
ControlID: controlID,
|
||||||
OrganizationID: stateOfApplicability.OrganizationID,
|
OrganizationID: statementOfApplicability.OrganizationID,
|
||||||
Applicability: applicability,
|
Applicability: applicability,
|
||||||
Justification: justification,
|
Justification: justification,
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
UpdatedAt: now,
|
UpdatedAt: now,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := applicabilityStatement.Insert(ctx, conn, s.svc.scope); err != nil {
|
if err := applicabilityStatement.Insert(ctx, conn, s.svc.scope); err != nil {
|
||||||
@@ -385,7 +385,7 @@ func (s StateOfApplicabilityService) CreateApplicabilityStatement(
|
|||||||
return applicabilityStatement, nil
|
return applicabilityStatement, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) UpdateApplicabilityStatement(
|
func (s StatementOfApplicabilityService) UpdateApplicabilityStatement(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
applicabilityStatementID gid.GID,
|
applicabilityStatementID gid.GID,
|
||||||
applicability bool,
|
applicability bool,
|
||||||
@@ -414,7 +414,7 @@ func (s StateOfApplicabilityService) UpdateApplicabilityStatement(
|
|||||||
return applicabilityStatement, nil
|
return applicabilityStatement, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) DeleteApplicabilityStatement(
|
func (s StatementOfApplicabilityService) DeleteApplicabilityStatement(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
applicabilityStatementID gid.GID,
|
applicabilityStatementID gid.GID,
|
||||||
) error {
|
) error {
|
||||||
@@ -428,7 +428,7 @@ func (s StateOfApplicabilityService) DeleteApplicabilityStatement(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) ListControlLinks(
|
func (s StatementOfApplicabilityService) ListControlLinks(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
controlID gid.GID,
|
controlID gid.GID,
|
||||||
cursor *page.Cursor[coredata.ApplicabilityStatementOrderField],
|
cursor *page.Cursor[coredata.ApplicabilityStatementOrderField],
|
||||||
@@ -445,27 +445,27 @@ func (s StateOfApplicabilityService) ListControlLinks(
|
|||||||
return page.NewPage(controls, cursor), nil
|
return page.NewPage(controls, cursor), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StateOfApplicabilityService) ExportPDF(
|
func (s StatementOfApplicabilityService) ExportPDF(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
stateOfApplicabilityID gid.GID,
|
statementOfApplicabilityID gid.GID,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
var documentData docgen.StateOfApplicabilityData
|
var documentData docgen.StatementOfApplicabilityData
|
||||||
|
|
||||||
err := s.svc.pg.WithConn(
|
err := s.svc.pg.WithConn(
|
||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Querier) error {
|
func(ctx context.Context, conn pg.Querier) error {
|
||||||
stateOfApplicability := &coredata.StateOfApplicability{}
|
statementOfApplicability := &coredata.StatementOfApplicability{}
|
||||||
if err := stateOfApplicability.LoadByID(ctx, conn, s.svc.scope, stateOfApplicabilityID); err != nil {
|
if err := statementOfApplicability.LoadByID(ctx, conn, s.svc.scope, statementOfApplicabilityID); err != nil {
|
||||||
return fmt.Errorf("cannot load state of applicability: %w", err)
|
return fmt.Errorf("cannot load statement of applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
organization := &coredata.Organization{}
|
organization := &coredata.Organization{}
|
||||||
if err := organization.LoadByID(ctx, conn, s.svc.scope, stateOfApplicability.OrganizationID); err != nil {
|
if err := organization.LoadByID(ctx, conn, s.svc.scope, statementOfApplicability.OrganizationID); err != nil {
|
||||||
return fmt.Errorf("cannot load organization: %w", err)
|
return fmt.Errorf("cannot load organization: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
owner := &coredata.MembershipProfile{}
|
owner := &coredata.MembershipProfile{}
|
||||||
if err := owner.LoadByID(ctx, conn, s.svc.scope, stateOfApplicability.OwnerID); err != nil {
|
if err := owner.LoadByID(ctx, conn, s.svc.scope, statementOfApplicability.OwnerID); err != nil {
|
||||||
return fmt.Errorf("cannot load owner profile: %w", err)
|
return fmt.Errorf("cannot load owner profile: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,16 +480,16 @@ func (s StateOfApplicabilityService) ExportPDF(
|
|||||||
Direction: page.OrderDirectionAsc,
|
Direction: page.OrderDirectionAsc,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err := applicabilityStatements.LoadByStateOfApplicabilityID(ctx, conn, s.svc.scope, stateOfApplicabilityID, cursor); err != nil {
|
if err := applicabilityStatements.LoadByStatementOfApplicabilityID(ctx, conn, s.svc.scope, statementOfApplicabilityID, cursor); err != nil {
|
||||||
return fmt.Errorf("cannot load applicability statements: %w", err)
|
return fmt.Errorf("cannot load applicability statements: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(applicabilityStatements) == 0 {
|
if len(applicabilityStatements) == 0 {
|
||||||
// No linked controls, skip loading additional data
|
// No linked controls, skip loading additional data
|
||||||
documentData = docgen.StateOfApplicabilityData{
|
documentData = docgen.StatementOfApplicabilityData{
|
||||||
Title: stateOfApplicability.Name,
|
Title: statementOfApplicability.Name,
|
||||||
OrganizationName: organization.Name,
|
OrganizationName: organization.Name,
|
||||||
CreatedAt: stateOfApplicability.CreatedAt,
|
CreatedAt: statementOfApplicability.CreatedAt,
|
||||||
TotalControls: 0,
|
TotalControls: 0,
|
||||||
FrameworkGroups: []docgen.FrameworkControlGroup{},
|
FrameworkGroups: []docgen.FrameworkControlGroup{},
|
||||||
}
|
}
|
||||||
@@ -602,19 +602,19 @@ func (s StateOfApplicabilityService) ExportPDF(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var snapshots coredata.Snapshots
|
var snapshots coredata.Snapshots
|
||||||
snapshotType := coredata.SnapshotsTypeStatesOfApplicability
|
snapshotType := coredata.SnapshotsTypeStatementsOfApplicability
|
||||||
|
|
||||||
var version int
|
var version int
|
||||||
var publishedAt time.Time
|
var publishedAt time.Time
|
||||||
|
|
||||||
if stateOfApplicability.SnapshotID != nil {
|
if statementOfApplicability.SnapshotID != nil {
|
||||||
snapshot := &coredata.Snapshot{}
|
snapshot := &coredata.Snapshot{}
|
||||||
if err := snapshot.LoadByID(ctx, conn, s.svc.scope, *stateOfApplicability.SnapshotID); err != nil {
|
if err := snapshot.LoadByID(ctx, conn, s.svc.scope, *statementOfApplicability.SnapshotID); err != nil {
|
||||||
return fmt.Errorf("cannot load snapshot: %w", err)
|
return fmt.Errorf("cannot load snapshot: %w", err)
|
||||||
}
|
}
|
||||||
publishedAt = snapshot.CreatedAt
|
publishedAt = snapshot.CreatedAt
|
||||||
snapshotFilter := coredata.NewSnapshotFilter(&snapshotType).WithBeforeDate(&snapshot.CreatedAt)
|
snapshotFilter := coredata.NewSnapshotFilter(&snapshotType).WithBeforeDate(&snapshot.CreatedAt)
|
||||||
snapshotCount, err := snapshots.CountByOrganizationID(ctx, conn, s.svc.scope, stateOfApplicability.OrganizationID, snapshotFilter)
|
snapshotCount, err := snapshots.CountByOrganizationID(ctx, conn, s.svc.scope, statementOfApplicability.OrganizationID, snapshotFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot count states of applicability snapshots: %w", err)
|
return fmt.Errorf("cannot count states of applicability snapshots: %w", err)
|
||||||
}
|
}
|
||||||
@@ -622,7 +622,7 @@ func (s StateOfApplicabilityService) ExportPDF(
|
|||||||
} else {
|
} else {
|
||||||
publishedAt = time.Now()
|
publishedAt = time.Now()
|
||||||
snapshotFilter := coredata.NewSnapshotFilter(&snapshotType)
|
snapshotFilter := coredata.NewSnapshotFilter(&snapshotType)
|
||||||
snapshotCount, err := snapshots.CountByOrganizationID(ctx, conn, s.svc.scope, stateOfApplicability.OrganizationID, snapshotFilter)
|
snapshotCount, err := snapshots.CountByOrganizationID(ctx, conn, s.svc.scope, statementOfApplicability.OrganizationID, snapshotFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot count states of applicability snapshots: %w", err)
|
return fmt.Errorf("cannot count states of applicability snapshots: %w", err)
|
||||||
}
|
}
|
||||||
@@ -641,10 +641,10 @@ func (s StateOfApplicabilityService) ExportPDF(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
documentData = docgen.StateOfApplicabilityData{
|
documentData = docgen.StatementOfApplicabilityData{
|
||||||
Title: stateOfApplicability.Name,
|
Title: statementOfApplicability.Name,
|
||||||
OrganizationName: organization.Name,
|
OrganizationName: organization.Name,
|
||||||
CreatedAt: stateOfApplicability.CreatedAt,
|
CreatedAt: statementOfApplicability.CreatedAt,
|
||||||
TotalControls: len(applicabilityStatements),
|
TotalControls: len(applicabilityStatements),
|
||||||
FrameworkGroups: frameworkGroups,
|
FrameworkGroups: frameworkGroups,
|
||||||
CompanyHorizontalLogoBase64: horizontalLogoBase64,
|
CompanyHorizontalLogoBase64: horizontalLogoBase64,
|
||||||
@@ -661,7 +661,7 @@ func (s StateOfApplicabilityService) ExportPDF(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlData, err := docgen.RenderStateOfApplicabilityHTML(documentData)
|
htmlData, err := docgen.RenderStatementOfApplicabilityHTML(documentData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot render HTML: %w", err)
|
return nil, fmt.Errorf("cannot render HTML: %w", err)
|
||||||
}
|
}
|
||||||
@@ -1398,9 +1398,9 @@ enum SnapshotsType
|
|||||||
@goEnum(
|
@goEnum(
|
||||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeProcessingActivities"
|
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeProcessingActivities"
|
||||||
)
|
)
|
||||||
STATES_OF_APPLICABILITY
|
STATEMENTS_OF_APPLICABILITY
|
||||||
@goEnum(
|
@goEnum(
|
||||||
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeStatesOfApplicability"
|
value: "go.probo.inc/probo/pkg/coredata.SnapshotsTypeStatementsOfApplicability"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1690,7 +1690,7 @@ input DatumFilter {
|
|||||||
snapshotId: ID
|
snapshotId: ID
|
||||||
}
|
}
|
||||||
|
|
||||||
input StateOfApplicabilityFilter {
|
input StatementOfApplicabilityFilter {
|
||||||
snapshotId: ID
|
snapshotId: ID
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1955,14 +1955,14 @@ type Organization implements Node {
|
|||||||
orderBy: MeetingOrder
|
orderBy: MeetingOrder
|
||||||
): MeetingConnection! @goField(forceResolver: true)
|
): MeetingConnection! @goField(forceResolver: true)
|
||||||
|
|
||||||
statesOfApplicability(
|
statementsOfApplicability(
|
||||||
first: Int
|
first: Int
|
||||||
after: CursorKey
|
after: CursorKey
|
||||||
last: Int
|
last: Int
|
||||||
before: CursorKey
|
before: CursorKey
|
||||||
orderBy: StateOfApplicabilityOrder
|
orderBy: StatementOfApplicabilityOrder
|
||||||
filter: StateOfApplicabilityFilter = { snapshotId: null }
|
filter: StatementOfApplicabilityFilter = { snapshotId: null }
|
||||||
): StateOfApplicabilityConnection! @goField(forceResolver: true)
|
): StatementOfApplicabilityConnection! @goField(forceResolver: true)
|
||||||
|
|
||||||
measureCategories: [String!]! @goField(forceResolver: true)
|
measureCategories: [String!]! @goField(forceResolver: true)
|
||||||
|
|
||||||
@@ -2756,7 +2756,7 @@ type WebhookEventEdge {
|
|||||||
node: WebhookEvent!
|
node: WebhookEvent!
|
||||||
}
|
}
|
||||||
|
|
||||||
type StateOfApplicability implements Node {
|
type StatementOfApplicability implements Node {
|
||||||
id: ID!
|
id: ID!
|
||||||
name: String!
|
name: String!
|
||||||
sourceId: ID
|
sourceId: ID
|
||||||
@@ -2793,7 +2793,7 @@ type ApplicabilityStatementEdge {
|
|||||||
|
|
||||||
type ApplicabilityStatement implements Node {
|
type ApplicabilityStatement implements Node {
|
||||||
id: ID!
|
id: ID!
|
||||||
stateOfApplicability: StateOfApplicability! @goField(forceResolver: true)
|
statementOfApplicability: StatementOfApplicability! @goField(forceResolver: true)
|
||||||
control: Control! @goField(forceResolver: true)
|
control: Control! @goField(forceResolver: true)
|
||||||
applicability: Boolean!
|
applicability: Boolean!
|
||||||
justification: String!
|
justification: String!
|
||||||
@@ -3427,18 +3427,18 @@ type MeetingEdge {
|
|||||||
node: Meeting!
|
node: Meeting!
|
||||||
}
|
}
|
||||||
|
|
||||||
type StateOfApplicabilityConnection
|
type StatementOfApplicabilityConnection
|
||||||
@goModel(
|
@goModel(
|
||||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.StateOfApplicabilityConnection"
|
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.StatementOfApplicabilityConnection"
|
||||||
) {
|
) {
|
||||||
totalCount: Int! @goField(forceResolver: true)
|
totalCount: Int! @goField(forceResolver: true)
|
||||||
edges: [StateOfApplicabilityEdge!]!
|
edges: [StatementOfApplicabilityEdge!]!
|
||||||
pageInfo: PageInfo!
|
pageInfo: PageInfo!
|
||||||
}
|
}
|
||||||
|
|
||||||
type StateOfApplicabilityEdge {
|
type StatementOfApplicabilityEdge {
|
||||||
cursor: CursorKey!
|
cursor: CursorKey!
|
||||||
node: StateOfApplicability!
|
node: StatementOfApplicability!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3906,19 +3906,19 @@ type Mutation {
|
|||||||
deleteWebhookSubscription(
|
deleteWebhookSubscription(
|
||||||
input: DeleteWebhookSubscriptionInput!
|
input: DeleteWebhookSubscriptionInput!
|
||||||
): DeleteWebhookSubscriptionPayload!
|
): DeleteWebhookSubscriptionPayload!
|
||||||
# StateOfApplicability mutations
|
# StatementOfApplicability mutations
|
||||||
createStateOfApplicability(
|
createStatementOfApplicability(
|
||||||
input: CreateStateOfApplicabilityInput!
|
input: CreateStatementOfApplicabilityInput!
|
||||||
): CreateStateOfApplicabilityPayload!
|
): CreateStatementOfApplicabilityPayload!
|
||||||
updateStateOfApplicability(
|
updateStatementOfApplicability(
|
||||||
input: UpdateStateOfApplicabilityInput!
|
input: UpdateStatementOfApplicabilityInput!
|
||||||
): UpdateStateOfApplicabilityPayload!
|
): UpdateStatementOfApplicabilityPayload!
|
||||||
deleteStateOfApplicability(
|
deleteStatementOfApplicability(
|
||||||
input: DeleteStateOfApplicabilityInput!
|
input: DeleteStatementOfApplicabilityInput!
|
||||||
): DeleteStateOfApplicabilityPayload!
|
): DeleteStatementOfApplicabilityPayload!
|
||||||
exportStateOfApplicabilityPDF(
|
exportStatementOfApplicabilityPDF(
|
||||||
input: ExportStateOfApplicabilityPDFInput!
|
input: ExportStatementOfApplicabilityPDFInput!
|
||||||
): ExportStateOfApplicabilityPDFPayload!
|
): ExportStatementOfApplicabilityPDFPayload!
|
||||||
publishMajorDocumentVersion(
|
publishMajorDocumentVersion(
|
||||||
input: PublishMajorDocumentVersionInput!
|
input: PublishMajorDocumentVersionInput!
|
||||||
): PublishDocumentVersionPayload!
|
): PublishDocumentVersionPayload!
|
||||||
@@ -4491,7 +4491,7 @@ input DeleteControlDocumentMappingInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input CreateApplicabilityStatementInput {
|
input CreateApplicabilityStatementInput {
|
||||||
stateOfApplicabilityId: ID!
|
statementOfApplicabilityId: ID!
|
||||||
controlId: ID!
|
controlId: ID!
|
||||||
applicability: Boolean!
|
applicability: Boolean!
|
||||||
justification: String
|
justification: String
|
||||||
@@ -4735,13 +4735,13 @@ input DeleteMeetingInput {
|
|||||||
meetingId: ID!
|
meetingId: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
input CreateStateOfApplicabilityInput {
|
input CreateStatementOfApplicabilityInput {
|
||||||
organizationId: ID!
|
organizationId: ID!
|
||||||
name: String!
|
name: String!
|
||||||
ownerId: ID!
|
ownerId: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateStateOfApplicabilityInput {
|
input UpdateStatementOfApplicabilityInput {
|
||||||
id: ID!
|
id: ID!
|
||||||
name: String
|
name: String
|
||||||
ownerId: ID
|
ownerId: ID
|
||||||
@@ -4753,37 +4753,37 @@ input ApplicabilityStatementInput {
|
|||||||
justification: String
|
justification: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input DeleteStateOfApplicabilityInput {
|
input DeleteStatementOfApplicabilityInput {
|
||||||
stateOfApplicabilityId: ID!
|
statementOfApplicabilityId: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
input ExportStateOfApplicabilityPDFInput {
|
input ExportStatementOfApplicabilityPDFInput {
|
||||||
stateOfApplicabilityId: ID!
|
statementOfApplicabilityId: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExportStateOfApplicabilityPDFPayload {
|
type ExportStatementOfApplicabilityPDFPayload {
|
||||||
data: String!
|
data: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input StateOfApplicabilityOrder
|
input StatementOfApplicabilityOrder
|
||||||
@goModel(
|
@goModel(
|
||||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.StateOfApplicabilityOrderBy"
|
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.StatementOfApplicabilityOrderBy"
|
||||||
) {
|
) {
|
||||||
direction: OrderDirection!
|
direction: OrderDirection!
|
||||||
field: StateOfApplicabilityOrderField!
|
field: StatementOfApplicabilityOrderField!
|
||||||
}
|
}
|
||||||
|
|
||||||
enum StateOfApplicabilityOrderField
|
enum StatementOfApplicabilityOrderField
|
||||||
@goModel(
|
@goModel(
|
||||||
model: "go.probo.inc/probo/pkg/coredata.StateOfApplicabilityOrderField"
|
model: "go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderField"
|
||||||
) {
|
) {
|
||||||
NAME
|
NAME
|
||||||
@goEnum(
|
@goEnum(
|
||||||
value: "go.probo.inc/probo/pkg/coredata.StateOfApplicabilityOrderFieldName"
|
value: "go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderFieldName"
|
||||||
)
|
)
|
||||||
CREATED_AT
|
CREATED_AT
|
||||||
@goEnum(
|
@goEnum(
|
||||||
value: "go.probo.inc/probo/pkg/coredata.StateOfApplicabilityOrderFieldCreatedAt"
|
value: "go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderFieldCreatedAt"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
input CreateControlInput {
|
input CreateControlInput {
|
||||||
@@ -5496,16 +5496,16 @@ type DeleteWebhookSubscriptionPayload {
|
|||||||
deletedWebhookSubscriptionId: ID!
|
deletedWebhookSubscriptionId: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateStateOfApplicabilityPayload {
|
type CreateStatementOfApplicabilityPayload {
|
||||||
stateOfApplicabilityEdge: StateOfApplicabilityEdge!
|
statementOfApplicabilityEdge: StatementOfApplicabilityEdge!
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateStateOfApplicabilityPayload {
|
type UpdateStatementOfApplicabilityPayload {
|
||||||
stateOfApplicability: StateOfApplicability!
|
statementOfApplicability: StatementOfApplicability!
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteStateOfApplicabilityPayload {
|
type DeleteStatementOfApplicabilityPayload {
|
||||||
deletedStateOfApplicabilityId: ID!
|
deletedStatementOfApplicabilityId: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
input VendorRiskAssessmentOrder {
|
input VendorRiskAssessmentOrder {
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ func NewApplicabilityStatement(as *coredata.ApplicabilityStatement) *Applicabili
|
|||||||
|
|
||||||
return &ApplicabilityStatement{
|
return &ApplicabilityStatement{
|
||||||
ID: as.ID,
|
ID: as.ID,
|
||||||
StateOfApplicability: &StateOfApplicability{
|
StatementOfApplicability: &StatementOfApplicability{
|
||||||
ID: as.StateOfApplicabilityID,
|
ID: as.StatementOfApplicabilityID,
|
||||||
},
|
},
|
||||||
Control: &Control{
|
Control: &Control{
|
||||||
ID: as.ControlID,
|
ID: as.ControlID,
|
||||||
|
|||||||
@@ -21,32 +21,32 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
StateOfApplicabilityOrderBy OrderBy[coredata.StateOfApplicabilityOrderField]
|
StatementOfApplicabilityOrderBy OrderBy[coredata.StatementOfApplicabilityOrderField]
|
||||||
|
|
||||||
StateOfApplicabilityConnection struct {
|
StatementOfApplicabilityConnection struct {
|
||||||
TotalCount int
|
TotalCount int
|
||||||
Edges []*StateOfApplicabilityEdge
|
Edges []*StatementOfApplicabilityEdge
|
||||||
PageInfo PageInfo
|
PageInfo PageInfo
|
||||||
|
|
||||||
Resolver any
|
Resolver any
|
||||||
ParentID gid.GID
|
ParentID gid.GID
|
||||||
Filters *coredata.StateOfApplicabilityFilter
|
Filters *coredata.StatementOfApplicabilityFilter
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewStateOfApplicabilityConnection(
|
func NewStatementOfApplicabilityConnection(
|
||||||
p *page.Page[*coredata.StateOfApplicability, coredata.StateOfApplicabilityOrderField],
|
p *page.Page[*coredata.StatementOfApplicability, coredata.StatementOfApplicabilityOrderField],
|
||||||
parentType any,
|
parentType any,
|
||||||
parentID gid.GID,
|
parentID gid.GID,
|
||||||
filters *coredata.StateOfApplicabilityFilter,
|
filters *coredata.StatementOfApplicabilityFilter,
|
||||||
) *StateOfApplicabilityConnection {
|
) *StatementOfApplicabilityConnection {
|
||||||
var edges = make([]*StateOfApplicabilityEdge, len(p.Data))
|
var edges = make([]*StatementOfApplicabilityEdge, len(p.Data))
|
||||||
|
|
||||||
for i := range edges {
|
for i := range edges {
|
||||||
edges[i] = NewStateOfApplicabilityEdge(p.Data[i], p.Cursor.OrderBy.Field)
|
edges[i] = NewStatementOfApplicabilityEdge(p.Data[i], p.Cursor.OrderBy.Field)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &StateOfApplicabilityConnection{
|
return &StatementOfApplicabilityConnection{
|
||||||
Edges: edges,
|
Edges: edges,
|
||||||
PageInfo: *NewPageInfo(p),
|
PageInfo: *NewPageInfo(p),
|
||||||
|
|
||||||
@@ -56,15 +56,15 @@ func NewStateOfApplicabilityConnection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateOfApplicabilityEdge(soa *coredata.StateOfApplicability, orderBy coredata.StateOfApplicabilityOrderField) *StateOfApplicabilityEdge {
|
func NewStatementOfApplicabilityEdge(soa *coredata.StatementOfApplicability, orderBy coredata.StatementOfApplicabilityOrderField) *StatementOfApplicabilityEdge {
|
||||||
return &StateOfApplicabilityEdge{
|
return &StatementOfApplicabilityEdge{
|
||||||
Cursor: soa.CursorKey(orderBy),
|
Cursor: soa.CursorKey(orderBy),
|
||||||
Node: NewStateOfApplicability(soa),
|
Node: NewStatementOfApplicability(soa),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateOfApplicability(soa *coredata.StateOfApplicability) *StateOfApplicability {
|
func NewStatementOfApplicability(soa *coredata.StatementOfApplicability) *StatementOfApplicability {
|
||||||
return &StateOfApplicability{
|
return &StatementOfApplicability{
|
||||||
ID: soa.ID,
|
ID: soa.ID,
|
||||||
Organization: &Organization{
|
Organization: &Organization{
|
||||||
ID: soa.OrganizationID,
|
ID: soa.OrganizationID,
|
||||||
@@ -543,21 +543,21 @@ func (r *accessSourceConnectionResolver) TotalCount(ctx context.Context, obj *ty
|
|||||||
panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver))
|
panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver))
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateOfApplicability is the resolver for the stateOfApplicability field.
|
// StatementOfApplicability is the resolver for the statementOfApplicability field.
|
||||||
func (r *applicabilityStatementResolver) StateOfApplicability(ctx context.Context, obj *types.ApplicabilityStatement) (*types.StateOfApplicability, error) {
|
func (r *applicabilityStatementResolver) StatementOfApplicability(ctx context.Context, obj *types.ApplicabilityStatement) (*types.StatementOfApplicability, error) {
|
||||||
if err := r.authorize(ctx, obj.StateOfApplicability.ID, probo.ActionStateOfApplicabilityGet); err != nil {
|
if err := r.authorize(ctx, obj.StatementOfApplicability.ID, probo.ActionStatementOfApplicabilityGet); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
prb := r.ProboService(ctx, obj.StateOfApplicability.ID.TenantID())
|
prb := r.ProboService(ctx, obj.StatementOfApplicability.ID.TenantID())
|
||||||
|
|
||||||
soa, err := prb.StatesOfApplicability.Get(ctx, obj.StateOfApplicability.ID)
|
soa, err := prb.StatementsOfApplicability.Get(ctx, obj.StatementOfApplicability.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot get state of applicability", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot get statement of applicability", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.NewStateOfApplicability(soa), nil
|
return types.NewStatementOfApplicability(soa), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Control is the resolver for the control field.
|
// Control is the resolver for the control field.
|
||||||
@@ -595,8 +595,8 @@ func (r *applicabilityStatementConnectionResolver) TotalCount(ctx context.Contex
|
|||||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||||
|
|
||||||
switch obj.Resolver.(type) {
|
switch obj.Resolver.(type) {
|
||||||
case *stateOfApplicabilityResolver:
|
case *statementOfApplicabilityResolver:
|
||||||
count, err := prb.StatesOfApplicability.CountApplicabilityStatements(ctx, obj.ParentID)
|
count, err := prb.StatementsOfApplicability.CountApplicabilityStatements(ctx, obj.ParentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot count applicability statements", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot count applicability statements", log.Error(err))
|
||||||
return 0, gqlutils.Internal(ctx)
|
return 0, gqlutils.Internal(ctx)
|
||||||
@@ -1289,8 +1289,8 @@ func (r *controlConnectionResolver) TotalCount(ctx context.Context, obj *types.C
|
|||||||
return 0, gqlutils.Internal(ctx)
|
return 0, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
return count, nil
|
return count, nil
|
||||||
case *stateOfApplicabilityResolver:
|
case *statementOfApplicabilityResolver:
|
||||||
count, err := prb.Controls.CountForStateOfApplicabilityID(ctx, obj.ParentID, obj.Filters)
|
count, err := prb.Controls.CountForStatementOfApplicabilityID(ctx, obj.ParentID, obj.Filters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot count controls", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot count controls", log.Error(err))
|
||||||
return 0, gqlutils.Internal(ctx)
|
return 0, gqlutils.Internal(ctx)
|
||||||
@@ -4440,9 +4440,9 @@ func (r *mutationResolver) CreateApplicabilityStatement(ctx context.Context, inp
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
prb := r.ProboService(ctx, input.StateOfApplicabilityID.TenantID())
|
prb := r.ProboService(ctx, input.StatementOfApplicabilityID.TenantID())
|
||||||
|
|
||||||
applicabilityStatement, err := prb.StatesOfApplicability.CreateApplicabilityStatement(ctx, input.StateOfApplicabilityID, input.ControlID, input.Applicability, input.Justification)
|
applicabilityStatement, err := prb.StatementsOfApplicability.CreateApplicabilityStatement(ctx, input.StatementOfApplicabilityID, input.ControlID, input.Applicability, input.Justification)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot create applicability statement", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot create applicability statement", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
@@ -4461,7 +4461,7 @@ func (r *mutationResolver) UpdateApplicabilityStatement(ctx context.Context, inp
|
|||||||
|
|
||||||
prb := r.ProboService(ctx, input.ApplicabilityStatementID.TenantID())
|
prb := r.ProboService(ctx, input.ApplicabilityStatementID.TenantID())
|
||||||
|
|
||||||
applicabilityStatement, err := prb.StatesOfApplicability.UpdateApplicabilityStatement(ctx, input.ApplicabilityStatementID, input.Applicability, input.Justification)
|
applicabilityStatement, err := prb.StatementsOfApplicability.UpdateApplicabilityStatement(ctx, input.ApplicabilityStatementID, input.Applicability, input.Justification)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot update applicability statement", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot update applicability statement", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
@@ -4480,7 +4480,7 @@ func (r *mutationResolver) DeleteApplicabilityStatement(ctx context.Context, inp
|
|||||||
|
|
||||||
prb := r.ProboService(ctx, input.ApplicabilityStatementID.TenantID())
|
prb := r.ProboService(ctx, input.ApplicabilityStatementID.TenantID())
|
||||||
|
|
||||||
err := prb.StatesOfApplicability.DeleteApplicabilityStatement(ctx, input.ApplicabilityStatementID)
|
err := prb.StatementsOfApplicability.DeleteApplicabilityStatement(ctx, input.ApplicabilityStatementID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot delete applicability statement", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot delete applicability statement", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
@@ -5526,17 +5526,17 @@ func (r *mutationResolver) DeleteWebhookSubscription(ctx context.Context, input
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateStateOfApplicability is the resolver for the createStateOfApplicability field.
|
// CreateStatementOfApplicability is the resolver for the createStatementOfApplicability field.
|
||||||
func (r *mutationResolver) CreateStateOfApplicability(ctx context.Context, input types.CreateStateOfApplicabilityInput) (*types.CreateStateOfApplicabilityPayload, error) {
|
func (r *mutationResolver) CreateStatementOfApplicability(ctx context.Context, input types.CreateStatementOfApplicabilityInput) (*types.CreateStatementOfApplicabilityPayload, error) {
|
||||||
if err := r.authorize(ctx, input.OrganizationID, probo.ActionStateOfApplicabilityCreate); err != nil {
|
if err := r.authorize(ctx, input.OrganizationID, probo.ActionStatementOfApplicabilityCreate); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
|
||||||
|
|
||||||
stateOfApplicability, err := prb.StatesOfApplicability.Create(
|
statementOfApplicability, err := prb.StatementsOfApplicability.Create(
|
||||||
ctx,
|
ctx,
|
||||||
probo.CreateStateOfApplicabilityRequest{
|
probo.CreateStatementOfApplicabilityRequest{
|
||||||
OrganizationID: input.OrganizationID,
|
OrganizationID: input.OrganizationID,
|
||||||
Name: input.Name,
|
Name: input.Name,
|
||||||
OwnerID: input.OwnerID,
|
OwnerID: input.OwnerID,
|
||||||
@@ -5549,18 +5549,18 @@ func (r *mutationResolver) CreateStateOfApplicability(ctx context.Context, input
|
|||||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||||
}
|
}
|
||||||
r.logger.ErrorCtx(ctx, "cannot create state_of_applicability", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot create statement_of_applicability", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.CreateStateOfApplicabilityPayload{
|
return &types.CreateStatementOfApplicabilityPayload{
|
||||||
StateOfApplicabilityEdge: types.NewStateOfApplicabilityEdge(stateOfApplicability, coredata.StateOfApplicabilityOrderFieldCreatedAt),
|
StatementOfApplicabilityEdge: types.NewStatementOfApplicabilityEdge(statementOfApplicability, coredata.StatementOfApplicabilityOrderFieldCreatedAt),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStateOfApplicability is the resolver for the updateStateOfApplicability field.
|
// UpdateStatementOfApplicability is the resolver for the updateStatementOfApplicability field.
|
||||||
func (r *mutationResolver) UpdateStateOfApplicability(ctx context.Context, input types.UpdateStateOfApplicabilityInput) (*types.UpdateStateOfApplicabilityPayload, error) {
|
func (r *mutationResolver) UpdateStatementOfApplicability(ctx context.Context, input types.UpdateStatementOfApplicabilityInput) (*types.UpdateStatementOfApplicabilityPayload, error) {
|
||||||
if err := r.authorize(ctx, input.ID, probo.ActionStateOfApplicabilityUpdate); err != nil {
|
if err := r.authorize(ctx, input.ID, probo.ActionStatementOfApplicabilityUpdate); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5571,12 +5571,12 @@ func (r *mutationResolver) UpdateStateOfApplicability(ctx context.Context, input
|
|||||||
name = input.Name
|
name = input.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
stateOfApplicability, err := prb.StatesOfApplicability.Update(
|
statementOfApplicability, err := prb.StatementsOfApplicability.Update(
|
||||||
ctx,
|
ctx,
|
||||||
probo.UpdateStateOfApplicabilityRequest{
|
probo.UpdateStatementOfApplicabilityRequest{
|
||||||
StateOfApplicabilityID: input.ID,
|
StatementOfApplicabilityID: input.ID,
|
||||||
Name: name,
|
Name: name,
|
||||||
OwnerID: input.OwnerID,
|
OwnerID: input.OwnerID,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -5586,52 +5586,52 @@ func (r *mutationResolver) UpdateStateOfApplicability(ctx context.Context, input
|
|||||||
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
|
||||||
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
|
||||||
}
|
}
|
||||||
r.logger.ErrorCtx(ctx, "cannot update state_of_applicability", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot update statement_of_applicability", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.UpdateStateOfApplicabilityPayload{
|
return &types.UpdateStatementOfApplicabilityPayload{
|
||||||
StateOfApplicability: types.NewStateOfApplicability(stateOfApplicability),
|
StatementOfApplicability: types.NewStatementOfApplicability(statementOfApplicability),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteStateOfApplicability is the resolver for the deleteStateOfApplicability field.
|
// DeleteStatementOfApplicability is the resolver for the deleteStatementOfApplicability field.
|
||||||
func (r *mutationResolver) DeleteStateOfApplicability(ctx context.Context, input types.DeleteStateOfApplicabilityInput) (*types.DeleteStateOfApplicabilityPayload, error) {
|
func (r *mutationResolver) DeleteStatementOfApplicability(ctx context.Context, input types.DeleteStatementOfApplicabilityInput) (*types.DeleteStatementOfApplicabilityPayload, error) {
|
||||||
if err := r.authorize(ctx, input.StateOfApplicabilityID, probo.ActionStateOfApplicabilityDelete); err != nil {
|
if err := r.authorize(ctx, input.StatementOfApplicabilityID, probo.ActionStatementOfApplicabilityDelete); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
prb := r.ProboService(ctx, input.StateOfApplicabilityID.TenantID())
|
prb := r.ProboService(ctx, input.StatementOfApplicabilityID.TenantID())
|
||||||
|
|
||||||
err := prb.StatesOfApplicability.Delete(ctx, input.StateOfApplicabilityID)
|
err := prb.StatementsOfApplicability.Delete(ctx, input.StatementOfApplicabilityID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot delete state_of_applicability", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot delete statement_of_applicability", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.DeleteStateOfApplicabilityPayload{
|
return &types.DeleteStatementOfApplicabilityPayload{
|
||||||
DeletedStateOfApplicabilityID: input.StateOfApplicabilityID,
|
DeletedStatementOfApplicabilityID: input.StatementOfApplicabilityID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportStateOfApplicabilityPDF is the resolver for the exportStateOfApplicabilityPDF field.
|
// ExportStatementOfApplicabilityPDF is the resolver for the exportStatementOfApplicabilityPDF field.
|
||||||
func (r *mutationResolver) ExportStateOfApplicabilityPDF(ctx context.Context, input types.ExportStateOfApplicabilityPDFInput) (*types.ExportStateOfApplicabilityPDFPayload, error) {
|
func (r *mutationResolver) ExportStatementOfApplicabilityPDF(ctx context.Context, input types.ExportStatementOfApplicabilityPDFInput) (*types.ExportStatementOfApplicabilityPDFPayload, error) {
|
||||||
if err := r.authorize(ctx, input.StateOfApplicabilityID, probo.ActionStateOfApplicabilityExport); err != nil {
|
if err := r.authorize(ctx, input.StatementOfApplicabilityID, probo.ActionStatementOfApplicabilityExport); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
prb := r.ProboService(ctx, input.StateOfApplicabilityID.TenantID())
|
prb := r.ProboService(ctx, input.StatementOfApplicabilityID.TenantID())
|
||||||
|
|
||||||
pdfData, err := prb.StatesOfApplicability.ExportPDF(ctx, input.StateOfApplicabilityID)
|
pdfData, err := prb.StatementsOfApplicability.ExportPDF(ctx, input.StatementOfApplicabilityID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot export state of applicability PDF", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot export statement of applicability PDF", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
base64Data := base64.StdEncoding.EncodeToString(pdfData)
|
base64Data := base64.StdEncoding.EncodeToString(pdfData)
|
||||||
dataURI := fmt.Sprintf("data:application/pdf;base64,%s", base64Data)
|
dataURI := fmt.Sprintf("data:application/pdf;base64,%s", base64Data)
|
||||||
|
|
||||||
return &types.ExportStateOfApplicabilityPDFPayload{
|
return &types.ExportStatementOfApplicabilityPDFPayload{
|
||||||
Data: dataURI,
|
Data: dataURI,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -8522,20 +8522,20 @@ func (r *organizationResolver) Meetings(ctx context.Context, obj *types.Organiza
|
|||||||
return types.NewMeetingConnection(page, r, obj.ID), nil
|
return types.NewMeetingConnection(page, r, obj.ID), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatesOfApplicability is the resolver for the statesOfApplicability field.
|
// StatementsOfApplicability is the resolver for the statementsOfApplicability field.
|
||||||
func (r *organizationResolver) StatesOfApplicability(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.StateOfApplicabilityOrderBy, filter *types.StateOfApplicabilityFilter) (*types.StateOfApplicabilityConnection, error) {
|
func (r *organizationResolver) StatementsOfApplicability(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.StatementOfApplicabilityOrderBy, filter *types.StatementOfApplicabilityFilter) (*types.StatementOfApplicabilityConnection, error) {
|
||||||
if err := r.authorize(ctx, obj.ID, probo.ActionStateOfApplicabilityList); err != nil {
|
if err := r.authorize(ctx, obj.ID, probo.ActionStatementOfApplicabilityList); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||||
|
|
||||||
pageOrderBy := page.OrderBy[coredata.StateOfApplicabilityOrderField]{
|
pageOrderBy := page.OrderBy[coredata.StatementOfApplicabilityOrderField]{
|
||||||
Field: coredata.StateOfApplicabilityOrderFieldCreatedAt,
|
Field: coredata.StatementOfApplicabilityOrderFieldCreatedAt,
|
||||||
Direction: page.OrderDirectionDesc,
|
Direction: page.OrderDirectionDesc,
|
||||||
}
|
}
|
||||||
if orderBy != nil {
|
if orderBy != nil {
|
||||||
pageOrderBy = page.OrderBy[coredata.StateOfApplicabilityOrderField]{
|
pageOrderBy = page.OrderBy[coredata.StatementOfApplicabilityOrderField]{
|
||||||
Field: orderBy.Field,
|
Field: orderBy.Field,
|
||||||
Direction: orderBy.Direction,
|
Direction: orderBy.Direction,
|
||||||
}
|
}
|
||||||
@@ -8543,18 +8543,18 @@ func (r *organizationResolver) StatesOfApplicability(ctx context.Context, obj *t
|
|||||||
|
|
||||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||||
|
|
||||||
var stateOfApplicabilityFilter = coredata.NewStateOfApplicabilityFilter(nil)
|
var statementOfApplicabilityFilter = coredata.NewStatementOfApplicabilityFilter(nil)
|
||||||
if filter != nil {
|
if filter != nil {
|
||||||
stateOfApplicabilityFilter = coredata.NewStateOfApplicabilityFilter(&filter.SnapshotID)
|
statementOfApplicabilityFilter = coredata.NewStatementOfApplicabilityFilter(&filter.SnapshotID)
|
||||||
}
|
}
|
||||||
|
|
||||||
page, err := prb.StatesOfApplicability.ListForOrganizationID(ctx, obj.ID, cursor, stateOfApplicabilityFilter)
|
page, err := prb.StatementsOfApplicability.ListForOrganizationID(ctx, obj.ID, cursor, statementOfApplicabilityFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot list organization states_of_applicability", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot list organization statements_of_applicability", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.NewStateOfApplicabilityConnection(page, r, obj.ID, stateOfApplicabilityFilter), nil
|
return types.NewStatementOfApplicabilityConnection(page, r, obj.ID, statementOfApplicabilityFilter), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MeasureCategories is the resolver for the measureCategories field.
|
// MeasureCategories is the resolver for the measureCategories field.
|
||||||
@@ -9695,14 +9695,14 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
|
|||||||
}
|
}
|
||||||
return types.NewRightsRequest(rightsRequest), nil
|
return types.NewRightsRequest(rightsRequest), nil
|
||||||
}
|
}
|
||||||
case coredata.StateOfApplicabilityEntityType:
|
case coredata.StatementOfApplicabilityEntityType:
|
||||||
action = probo.ActionStateOfApplicabilityGet
|
action = probo.ActionStatementOfApplicabilityGet
|
||||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||||
stateOfApplicability, err := prb.StatesOfApplicability.Get(ctx, id)
|
statementOfApplicability, err := prb.StatementsOfApplicability.Get(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return types.NewStateOfApplicability(stateOfApplicability), nil
|
return types.NewStatementOfApplicability(statementOfApplicability), nil
|
||||||
}
|
}
|
||||||
case coredata.WebhookSubscriptionEntityType:
|
case coredata.WebhookSubscriptionEntityType:
|
||||||
action = probo.ActionWebhookSubscriptionGet
|
action = probo.ActionWebhookSubscriptionGet
|
||||||
@@ -10191,7 +10191,7 @@ func (r *snapshotConnectionResolver) TotalCount(ctx context.Context, obj *types.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Organization is the resolver for the organization field.
|
// Organization is the resolver for the organization field.
|
||||||
func (r *stateOfApplicabilityResolver) Organization(ctx context.Context, obj *types.StateOfApplicability) (*types.Organization, error) {
|
func (r *statementOfApplicabilityResolver) Organization(ctx context.Context, obj *types.StatementOfApplicability) (*types.Organization, error) {
|
||||||
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
if err := r.authorize(ctx, obj.ID, probo.ActionOrganizationGet); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -10211,7 +10211,7 @@ func (r *stateOfApplicabilityResolver) Organization(ctx context.Context, obj *ty
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Owner is the resolver for the owner field.
|
// Owner is the resolver for the owner field.
|
||||||
func (r *stateOfApplicabilityResolver) Owner(ctx context.Context, obj *types.StateOfApplicability) (*types.Profile, error) {
|
func (r *statementOfApplicabilityResolver) Owner(ctx context.Context, obj *types.StatementOfApplicability) (*types.Profile, error) {
|
||||||
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
if err := r.authorize(ctx, obj.ID, iam.ActionMembershipProfileGet); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -10231,7 +10231,7 @@ func (r *stateOfApplicabilityResolver) Owner(ctx context.Context, obj *types.Sta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ApplicabilityStatements is the resolver for the applicabilityStatements field.
|
// ApplicabilityStatements is the resolver for the applicabilityStatements field.
|
||||||
func (r *stateOfApplicabilityResolver) ApplicabilityStatements(ctx context.Context, obj *types.StateOfApplicability, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ApplicabilityStatementOrderBy) (*types.ApplicabilityStatementConnection, error) {
|
func (r *statementOfApplicabilityResolver) ApplicabilityStatements(ctx context.Context, obj *types.StatementOfApplicability, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ApplicabilityStatementOrderBy) (*types.ApplicabilityStatementConnection, error) {
|
||||||
if err := r.authorize(ctx, obj.ID, probo.ActionApplicabilityStatementList); err != nil {
|
if err := r.authorize(ctx, obj.ID, probo.ActionApplicabilityStatementList); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -10251,7 +10251,7 @@ func (r *stateOfApplicabilityResolver) ApplicabilityStatements(ctx context.Conte
|
|||||||
|
|
||||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||||
|
|
||||||
p, err := prb.StatesOfApplicability.ListApplicabilityStatements(ctx, obj.ID, cursor)
|
p, err := prb.StatementsOfApplicability.ListApplicabilityStatements(ctx, obj.ID, cursor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot list applicability statements", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot list applicability statements", log.Error(err))
|
||||||
return nil, gqlutils.Internal(ctx)
|
return nil, gqlutils.Internal(ctx)
|
||||||
@@ -10261,19 +10261,19 @@ func (r *stateOfApplicabilityResolver) ApplicabilityStatements(ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Permission is the resolver for the permission field.
|
// Permission is the resolver for the permission field.
|
||||||
func (r *stateOfApplicabilityResolver) Permission(ctx context.Context, obj *types.StateOfApplicability, action string) (bool, error) {
|
func (r *statementOfApplicabilityResolver) Permission(ctx context.Context, obj *types.StatementOfApplicability, action string) (bool, error) {
|
||||||
return r.Resolver.Permission(ctx, obj, action)
|
return r.Resolver.Permission(ctx, obj, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalCount is the resolver for the totalCount field.
|
// TotalCount is the resolver for the totalCount field.
|
||||||
func (r *stateOfApplicabilityConnectionResolver) TotalCount(ctx context.Context, obj *types.StateOfApplicabilityConnection) (int, error) {
|
func (r *statementOfApplicabilityConnectionResolver) TotalCount(ctx context.Context, obj *types.StatementOfApplicabilityConnection) (int, error) {
|
||||||
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
prb := r.ProboService(ctx, obj.ParentID.TenantID())
|
||||||
|
|
||||||
switch obj.Resolver.(type) {
|
switch obj.Resolver.(type) {
|
||||||
case *organizationResolver:
|
case *organizationResolver:
|
||||||
count, err := prb.StatesOfApplicability.CountForOrganizationID(ctx, obj.ParentID, obj.Filters)
|
count, err := prb.StatementsOfApplicability.CountForOrganizationID(ctx, obj.ParentID, obj.Filters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot count states_of_applicability", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot count statements_of_applicability", log.Error(err))
|
||||||
return 0, gqlutils.Internal(ctx)
|
return 0, gqlutils.Internal(ctx)
|
||||||
}
|
}
|
||||||
return count, nil
|
return count, nil
|
||||||
@@ -12081,14 +12081,14 @@ func (r *Resolver) SnapshotConnection() schema.SnapshotConnectionResolver {
|
|||||||
return &snapshotConnectionResolver{r}
|
return &snapshotConnectionResolver{r}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateOfApplicability returns schema.StateOfApplicabilityResolver implementation.
|
// StatementOfApplicability returns schema.StatementOfApplicabilityResolver implementation.
|
||||||
func (r *Resolver) StateOfApplicability() schema.StateOfApplicabilityResolver {
|
func (r *Resolver) StatementOfApplicability() schema.StatementOfApplicabilityResolver {
|
||||||
return &stateOfApplicabilityResolver{r}
|
return &statementOfApplicabilityResolver{r}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateOfApplicabilityConnection returns schema.StateOfApplicabilityConnectionResolver implementation.
|
// StatementOfApplicabilityConnection returns schema.StatementOfApplicabilityConnectionResolver implementation.
|
||||||
func (r *Resolver) StateOfApplicabilityConnection() schema.StateOfApplicabilityConnectionResolver {
|
func (r *Resolver) StatementOfApplicabilityConnection() schema.StatementOfApplicabilityConnectionResolver {
|
||||||
return &stateOfApplicabilityConnectionResolver{r}
|
return &statementOfApplicabilityConnectionResolver{r}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Task returns schema.TaskResolver implementation.
|
// Task returns schema.TaskResolver implementation.
|
||||||
@@ -12267,8 +12267,8 @@ type riskConnectionResolver struct{ *Resolver }
|
|||||||
type slackConnectionResolver struct{ *Resolver }
|
type slackConnectionResolver struct{ *Resolver }
|
||||||
type snapshotResolver struct{ *Resolver }
|
type snapshotResolver struct{ *Resolver }
|
||||||
type snapshotConnectionResolver struct{ *Resolver }
|
type snapshotConnectionResolver struct{ *Resolver }
|
||||||
type stateOfApplicabilityResolver struct{ *Resolver }
|
type statementOfApplicabilityResolver struct{ *Resolver }
|
||||||
type stateOfApplicabilityConnectionResolver struct{ *Resolver }
|
type statementOfApplicabilityConnectionResolver struct{ *Resolver }
|
||||||
type taskResolver struct{ *Resolver }
|
type taskResolver struct{ *Resolver }
|
||||||
type taskConnectionResolver struct{ *Resolver }
|
type taskConnectionResolver struct{ *Resolver }
|
||||||
type transferImpactAssessmentResolver struct{ *Resolver }
|
type transferImpactAssessmentResolver struct{ *Resolver }
|
||||||
|
|||||||
@@ -2844,17 +2844,17 @@ func (r *Resolver) DeleteDataProtectionImpactAssessmentTool(ctx context.Context,
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) ListStatesOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListStatesOfApplicabilityInput) (*mcp.CallToolResult, types.ListStatesOfApplicabilityOutput, error) {
|
func (r *Resolver) ListStatementsOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListStatementsOfApplicabilityInput) (*mcp.CallToolResult, types.ListStatementsOfApplicabilityOutput, error) {
|
||||||
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionStateOfApplicabilityList)
|
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionStatementOfApplicabilityList)
|
||||||
|
|
||||||
prb := r.ProboService(ctx, input.OrganizationID)
|
prb := r.ProboService(ctx, input.OrganizationID)
|
||||||
|
|
||||||
pageOrderBy := page.OrderBy[coredata.StateOfApplicabilityOrderField]{
|
pageOrderBy := page.OrderBy[coredata.StatementOfApplicabilityOrderField]{
|
||||||
Field: coredata.StateOfApplicabilityOrderFieldCreatedAt,
|
Field: coredata.StatementOfApplicabilityOrderFieldCreatedAt,
|
||||||
Direction: page.OrderDirectionDesc,
|
Direction: page.OrderDirectionDesc,
|
||||||
}
|
}
|
||||||
if input.OrderBy != nil {
|
if input.OrderBy != nil {
|
||||||
pageOrderBy = page.OrderBy[coredata.StateOfApplicabilityOrderField]{
|
pageOrderBy = page.OrderBy[coredata.StatementOfApplicabilityOrderField]{
|
||||||
Field: input.OrderBy.Field,
|
Field: input.OrderBy.Field,
|
||||||
Direction: input.OrderBy.Direction,
|
Direction: input.OrderBy.Direction,
|
||||||
}
|
}
|
||||||
@@ -2862,107 +2862,107 @@ func (r *Resolver) ListStatesOfApplicabilityTool(ctx context.Context, req *mcp.C
|
|||||||
|
|
||||||
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||||
|
|
||||||
pg, err := prb.StatesOfApplicability.ListForOrganizationID(ctx, input.OrganizationID, cursor, coredata.NewStateOfApplicabilityFilter(nil))
|
pg, err := prb.StatementsOfApplicability.ListForOrganizationID(ctx, input.OrganizationID, cursor, coredata.NewStatementOfApplicabilityFilter(nil))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.ListStatesOfApplicabilityOutput{}, fmt.Errorf("failed to list states of applicability: %w", err)
|
return nil, types.ListStatementsOfApplicabilityOutput{}, fmt.Errorf("failed to list statements of applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, types.NewListStatesOfApplicabilityOutput(pg), nil
|
return nil, types.NewListStatementsOfApplicabilityOutput(pg), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) GetStateOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetStateOfApplicabilityInput) (*mcp.CallToolResult, types.GetStateOfApplicabilityOutput, error) {
|
func (r *Resolver) GetStatementOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetStatementOfApplicabilityInput) (*mcp.CallToolResult, types.GetStatementOfApplicabilityOutput, error) {
|
||||||
r.MustAuthorize(ctx, input.ID, probo.ActionStateOfApplicabilityGet)
|
r.MustAuthorize(ctx, input.ID, probo.ActionStatementOfApplicabilityGet)
|
||||||
|
|
||||||
prb := r.ProboService(ctx, input.ID)
|
prb := r.ProboService(ctx, input.ID)
|
||||||
|
|
||||||
soa, err := prb.StatesOfApplicability.Get(ctx, input.ID)
|
soa, err := prb.StatementsOfApplicability.Get(ctx, input.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.GetStateOfApplicabilityOutput{}, fmt.Errorf("failed to get state of applicability: %w", err)
|
return nil, types.GetStatementOfApplicabilityOutput{}, fmt.Errorf("failed to get statement of applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, types.GetStateOfApplicabilityOutput{
|
return nil, types.GetStatementOfApplicabilityOutput{
|
||||||
StateOfApplicability: types.NewStateOfApplicability(soa),
|
StatementOfApplicability: types.NewStatementOfApplicability(soa),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) AddStateOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddStateOfApplicabilityInput) (*mcp.CallToolResult, types.AddStateOfApplicabilityOutput, error) {
|
func (r *Resolver) AddStatementOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddStatementOfApplicabilityInput) (*mcp.CallToolResult, types.AddStatementOfApplicabilityOutput, error) {
|
||||||
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionStateOfApplicabilityCreate)
|
r.MustAuthorize(ctx, input.OrganizationID, probo.ActionStatementOfApplicabilityCreate)
|
||||||
|
|
||||||
svc := r.ProboService(ctx, input.OrganizationID)
|
svc := r.ProboService(ctx, input.OrganizationID)
|
||||||
|
|
||||||
soa, err := svc.StatesOfApplicability.Create(ctx, probo.CreateStateOfApplicabilityRequest{
|
soa, err := svc.StatementsOfApplicability.Create(ctx, probo.CreateStatementOfApplicabilityRequest{
|
||||||
OrganizationID: input.OrganizationID,
|
OrganizationID: input.OrganizationID,
|
||||||
Name: input.Name,
|
Name: input.Name,
|
||||||
OwnerID: input.OwnerID,
|
OwnerID: input.OwnerID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.AddStateOfApplicabilityOutput{}, fmt.Errorf("failed to create state of applicability: %w", err)
|
return nil, types.AddStatementOfApplicabilityOutput{}, fmt.Errorf("failed to create statement of applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, types.AddStateOfApplicabilityOutput{
|
return nil, types.AddStatementOfApplicabilityOutput{
|
||||||
StateOfApplicability: types.NewStateOfApplicability(soa),
|
StatementOfApplicability: types.NewStatementOfApplicability(soa),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) UpdateStateOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateStateOfApplicabilityInput) (*mcp.CallToolResult, types.UpdateStateOfApplicabilityOutput, error) {
|
func (r *Resolver) UpdateStatementOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateStatementOfApplicabilityInput) (*mcp.CallToolResult, types.UpdateStatementOfApplicabilityOutput, error) {
|
||||||
r.MustAuthorize(ctx, input.ID, probo.ActionStateOfApplicabilityUpdate)
|
r.MustAuthorize(ctx, input.ID, probo.ActionStatementOfApplicabilityUpdate)
|
||||||
|
|
||||||
svc := r.ProboService(ctx, input.ID)
|
svc := r.ProboService(ctx, input.ID)
|
||||||
|
|
||||||
soa, err := svc.StatesOfApplicability.Update(ctx, probo.UpdateStateOfApplicabilityRequest{
|
soa, err := svc.StatementsOfApplicability.Update(ctx, probo.UpdateStatementOfApplicabilityRequest{
|
||||||
StateOfApplicabilityID: input.ID,
|
StatementOfApplicabilityID: input.ID,
|
||||||
Name: input.Name,
|
Name: input.Name,
|
||||||
OwnerID: input.OwnerID,
|
OwnerID: input.OwnerID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.UpdateStateOfApplicabilityOutput{}, fmt.Errorf("failed to update state of applicability: %w", err)
|
return nil, types.UpdateStatementOfApplicabilityOutput{}, fmt.Errorf("failed to update statement of applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, types.UpdateStateOfApplicabilityOutput{
|
return nil, types.UpdateStatementOfApplicabilityOutput{
|
||||||
StateOfApplicability: types.NewStateOfApplicability(soa),
|
StatementOfApplicability: types.NewStatementOfApplicability(soa),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) DeleteStateOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteStateOfApplicabilityInput) (*mcp.CallToolResult, types.DeleteStateOfApplicabilityOutput, error) {
|
func (r *Resolver) DeleteStatementOfApplicabilityTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteStatementOfApplicabilityInput) (*mcp.CallToolResult, types.DeleteStatementOfApplicabilityOutput, error) {
|
||||||
r.MustAuthorize(ctx, input.ID, probo.ActionStateOfApplicabilityDelete)
|
r.MustAuthorize(ctx, input.ID, probo.ActionStatementOfApplicabilityDelete)
|
||||||
|
|
||||||
svc := r.ProboService(ctx, input.ID)
|
svc := r.ProboService(ctx, input.ID)
|
||||||
|
|
||||||
err := svc.StatesOfApplicability.Delete(ctx, input.ID)
|
err := svc.StatementsOfApplicability.Delete(ctx, input.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.DeleteStateOfApplicabilityOutput{}, fmt.Errorf("failed to delete state of applicability: %w", err)
|
return nil, types.DeleteStatementOfApplicabilityOutput{}, fmt.Errorf("failed to delete statement of applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, types.DeleteStateOfApplicabilityOutput{
|
return nil, types.DeleteStatementOfApplicabilityOutput{
|
||||||
DeletedStateOfApplicabilityID: input.ID,
|
DeletedStatementOfApplicabilityID: input.ID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) ExportStateOfApplicabilityPDFTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ExportStateOfApplicabilityPDFInput) (*mcp.CallToolResult, types.ExportStateOfApplicabilityPDFOutput, error) {
|
func (r *Resolver) ExportStatementOfApplicabilityPDFTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ExportStatementOfApplicabilityPDFInput) (*mcp.CallToolResult, types.ExportStatementOfApplicabilityPDFOutput, error) {
|
||||||
r.MustAuthorize(ctx, input.ID, probo.ActionStateOfApplicabilityExport)
|
r.MustAuthorize(ctx, input.ID, probo.ActionStatementOfApplicabilityExport)
|
||||||
|
|
||||||
svc := r.ProboService(ctx, input.ID)
|
svc := r.ProboService(ctx, input.ID)
|
||||||
|
|
||||||
soa, err := svc.StatesOfApplicability.Get(ctx, input.ID)
|
soa, err := svc.StatementsOfApplicability.Get(ctx, input.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.ExportStateOfApplicabilityPDFOutput{}, fmt.Errorf("failed to get state of applicability: %w", err)
|
return nil, types.ExportStatementOfApplicabilityPDFOutput{}, fmt.Errorf("failed to get statement of applicability: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfData, err := svc.StatesOfApplicability.ExportPDF(ctx, input.ID)
|
pdfData, err := svc.StatementsOfApplicability.ExportPDF(ctx, input.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.ExportStateOfApplicabilityPDFOutput{}, fmt.Errorf("failed to export state of applicability PDF: %w", err)
|
return nil, types.ExportStatementOfApplicabilityPDFOutput{}, fmt.Errorf("failed to export statement of applicability PDF: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, types.ExportStateOfApplicabilityPDFOutput{
|
return nil, types.ExportStatementOfApplicabilityPDFOutput{
|
||||||
PdfBase64: base64.StdEncoding.EncodeToString(pdfData),
|
PdfBase64: base64.StdEncoding.EncodeToString(pdfData),
|
||||||
Filename: soa.Name + ".pdf",
|
Filename: soa.Name + ".pdf",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) ListApplicabilityStatementsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListApplicabilityStatementsInput) (*mcp.CallToolResult, types.ListApplicabilityStatementsOutput, error) {
|
func (r *Resolver) ListApplicabilityStatementsTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListApplicabilityStatementsInput) (*mcp.CallToolResult, types.ListApplicabilityStatementsOutput, error) {
|
||||||
r.MustAuthorize(ctx, input.StateOfApplicabilityID, probo.ActionApplicabilityStatementList)
|
r.MustAuthorize(ctx, input.StatementOfApplicabilityID, probo.ActionApplicabilityStatementList)
|
||||||
|
|
||||||
prb := r.ProboService(ctx, input.StateOfApplicabilityID)
|
prb := r.ProboService(ctx, input.StatementOfApplicabilityID)
|
||||||
|
|
||||||
pageOrderBy := page.OrderBy[coredata.ApplicabilityStatementOrderField]{
|
pageOrderBy := page.OrderBy[coredata.ApplicabilityStatementOrderField]{
|
||||||
Field: coredata.ApplicabilityStatementOrderFieldControlSectionTitle,
|
Field: coredata.ApplicabilityStatementOrderFieldControlSectionTitle,
|
||||||
@@ -2977,7 +2977,7 @@ func (r *Resolver) ListApplicabilityStatementsTool(ctx context.Context, req *mcp
|
|||||||
|
|
||||||
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||||
|
|
||||||
pg, err := prb.StatesOfApplicability.ListApplicabilityStatements(ctx, input.StateOfApplicabilityID, cursor)
|
pg, err := prb.StatementsOfApplicability.ListApplicabilityStatements(ctx, input.StatementOfApplicabilityID, cursor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.ListApplicabilityStatementsOutput{}, fmt.Errorf("failed to list applicability statements: %w", err)
|
return nil, types.ListApplicabilityStatementsOutput{}, fmt.Errorf("failed to list applicability statements: %w", err)
|
||||||
}
|
}
|
||||||
@@ -2990,7 +2990,7 @@ func (r *Resolver) GetApplicabilityStatementTool(ctx context.Context, req *mcp.C
|
|||||||
|
|
||||||
prb := r.ProboService(ctx, input.ID)
|
prb := r.ProboService(ctx, input.ID)
|
||||||
|
|
||||||
stmt, err := prb.StatesOfApplicability.GetApplicabilityStatement(ctx, input.ID)
|
stmt, err := prb.StatementsOfApplicability.GetApplicabilityStatement(ctx, input.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.GetApplicabilityStatementOutput{}, fmt.Errorf("failed to get applicability statement: %w", err)
|
return nil, types.GetApplicabilityStatementOutput{}, fmt.Errorf("failed to get applicability statement: %w", err)
|
||||||
}
|
}
|
||||||
@@ -3001,13 +3001,13 @@ func (r *Resolver) GetApplicabilityStatementTool(ctx context.Context, req *mcp.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) AddApplicabilityStatementTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddApplicabilityStatementInput) (*mcp.CallToolResult, types.AddApplicabilityStatementOutput, error) {
|
func (r *Resolver) AddApplicabilityStatementTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddApplicabilityStatementInput) (*mcp.CallToolResult, types.AddApplicabilityStatementOutput, error) {
|
||||||
r.MustAuthorize(ctx, input.StateOfApplicabilityID, probo.ActionApplicabilityStatementCreate)
|
r.MustAuthorize(ctx, input.StatementOfApplicabilityID, probo.ActionApplicabilityStatementCreate)
|
||||||
|
|
||||||
svc := r.ProboService(ctx, input.StateOfApplicabilityID)
|
svc := r.ProboService(ctx, input.StatementOfApplicabilityID)
|
||||||
|
|
||||||
stmt, err := svc.StatesOfApplicability.CreateApplicabilityStatement(
|
stmt, err := svc.StatementsOfApplicability.CreateApplicabilityStatement(
|
||||||
ctx,
|
ctx,
|
||||||
input.StateOfApplicabilityID,
|
input.StatementOfApplicabilityID,
|
||||||
input.ControlID,
|
input.ControlID,
|
||||||
input.Applicability,
|
input.Applicability,
|
||||||
input.Justification,
|
input.Justification,
|
||||||
@@ -3026,7 +3026,7 @@ func (r *Resolver) UpdateApplicabilityStatementTool(ctx context.Context, req *mc
|
|||||||
|
|
||||||
svc := r.ProboService(ctx, input.ID)
|
svc := r.ProboService(ctx, input.ID)
|
||||||
|
|
||||||
stmt, err := svc.StatesOfApplicability.UpdateApplicabilityStatement(
|
stmt, err := svc.StatementsOfApplicability.UpdateApplicabilityStatement(
|
||||||
ctx,
|
ctx,
|
||||||
input.ID,
|
input.ID,
|
||||||
input.Applicability,
|
input.Applicability,
|
||||||
@@ -3046,7 +3046,7 @@ func (r *Resolver) DeleteApplicabilityStatementTool(ctx context.Context, req *mc
|
|||||||
|
|
||||||
svc := r.ProboService(ctx, input.ID)
|
svc := r.ProboService(ctx, input.ID)
|
||||||
|
|
||||||
err := svc.StatesOfApplicability.DeleteApplicabilityStatement(ctx, input.ID)
|
err := svc.StatementsOfApplicability.DeleteApplicabilityStatement(ctx, input.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.DeleteApplicabilityStatementOutput{}, fmt.Errorf("failed to delete applicability statement: %w", err)
|
return nil, types.DeleteApplicabilityStatementOutput{}, fmt.Errorf("failed to delete applicability statement: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6076,27 +6076,27 @@ components:
|
|||||||
$ref: "#/components/schemas/Profile"
|
$ref: "#/components/schemas/Profile"
|
||||||
description: List of attendee profiles
|
description: List of attendee profiles
|
||||||
|
|
||||||
StateOfApplicabilityOrderField:
|
StatementOfApplicabilityOrderField:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- CREATED_AT
|
- CREATED_AT
|
||||||
- NAME
|
- NAME
|
||||||
go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.StateOfApplicabilityOrderField
|
go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.StatementOfApplicabilityOrderField
|
||||||
|
|
||||||
StateOfApplicabilityOrderBy:
|
StatementOfApplicabilityOrderBy:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- field
|
- field
|
||||||
- direction
|
- direction
|
||||||
properties:
|
properties:
|
||||||
field:
|
field:
|
||||||
$ref: "#/components/schemas/StateOfApplicabilityOrderField"
|
$ref: "#/components/schemas/StatementOfApplicabilityOrderField"
|
||||||
description: State of applicability order field
|
description: Statement of applicability order field
|
||||||
direction:
|
direction:
|
||||||
$ref: "#/components/schemas/OrderDirection"
|
$ref: "#/components/schemas/OrderDirection"
|
||||||
description: Order direction
|
description: Order direction
|
||||||
|
|
||||||
StateOfApplicability:
|
StatementOfApplicability:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
@@ -6108,13 +6108,13 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: State of applicability ID
|
description: Statement of applicability ID
|
||||||
organization_id:
|
organization_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: Organization ID
|
description: Organization ID
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
description: State of applicability name
|
description: Statement of applicability name
|
||||||
owner_id:
|
owner_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: Owner profile ID
|
description: Owner profile ID
|
||||||
@@ -6132,7 +6132,7 @@ components:
|
|||||||
format: date-time
|
format: date-time
|
||||||
description: Update timestamp
|
description: Update timestamp
|
||||||
|
|
||||||
ListStatesOfApplicabilityInput:
|
ListStatementsOfApplicabilityInput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- organization_id
|
- organization_id
|
||||||
@@ -6141,7 +6141,7 @@ components:
|
|||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: Organization ID
|
description: Organization ID
|
||||||
order_by:
|
order_by:
|
||||||
$ref: "#/components/schemas/StateOfApplicabilityOrderBy"
|
$ref: "#/components/schemas/StatementOfApplicabilityOrderBy"
|
||||||
description: Order by
|
description: Order by
|
||||||
size:
|
size:
|
||||||
type: integer
|
type: integer
|
||||||
@@ -6150,37 +6150,37 @@ components:
|
|||||||
$ref: "#/components/schemas/CursorKey"
|
$ref: "#/components/schemas/CursorKey"
|
||||||
description: Page cursor
|
description: Page cursor
|
||||||
|
|
||||||
ListStatesOfApplicabilityOutput:
|
ListStatementsOfApplicabilityOutput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- states_of_applicability
|
- statements_of_applicability
|
||||||
properties:
|
properties:
|
||||||
next_cursor:
|
next_cursor:
|
||||||
$ref: "#/components/schemas/CursorKey"
|
$ref: "#/components/schemas/CursorKey"
|
||||||
description: Next cursor
|
description: Next cursor
|
||||||
states_of_applicability:
|
statements_of_applicability:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/StateOfApplicability"
|
$ref: "#/components/schemas/StatementOfApplicability"
|
||||||
|
|
||||||
GetStateOfApplicabilityInput:
|
GetStatementOfApplicabilityInput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: State of applicability ID
|
description: Statement of applicability ID
|
||||||
|
|
||||||
GetStateOfApplicabilityOutput:
|
GetStatementOfApplicabilityOutput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- state_of_applicability
|
- statement_of_applicability
|
||||||
properties:
|
properties:
|
||||||
state_of_applicability:
|
statement_of_applicability:
|
||||||
$ref: "#/components/schemas/StateOfApplicability"
|
$ref: "#/components/schemas/StatementOfApplicability"
|
||||||
|
|
||||||
AddStateOfApplicabilityInput:
|
AddStatementOfApplicabilityInput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- organization_id
|
- organization_id
|
||||||
@@ -6192,70 +6192,70 @@ components:
|
|||||||
description: Organization ID
|
description: Organization ID
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
description: State of applicability name
|
description: Statement of applicability name
|
||||||
owner_id:
|
owner_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: Owner profile ID
|
description: Owner profile ID
|
||||||
|
|
||||||
AddStateOfApplicabilityOutput:
|
AddStatementOfApplicabilityOutput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- state_of_applicability
|
- statement_of_applicability
|
||||||
properties:
|
properties:
|
||||||
state_of_applicability:
|
statement_of_applicability:
|
||||||
$ref: "#/components/schemas/StateOfApplicability"
|
$ref: "#/components/schemas/StatementOfApplicability"
|
||||||
|
|
||||||
UpdateStateOfApplicabilityInput:
|
UpdateStatementOfApplicabilityInput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: State of applicability ID
|
description: Statement of applicability ID
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
description: State of applicability name
|
description: Statement of applicability name
|
||||||
owner_id:
|
owner_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: Owner profile ID
|
description: Owner profile ID
|
||||||
|
|
||||||
UpdateStateOfApplicabilityOutput:
|
UpdateStatementOfApplicabilityOutput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- state_of_applicability
|
- statement_of_applicability
|
||||||
properties:
|
properties:
|
||||||
state_of_applicability:
|
statement_of_applicability:
|
||||||
$ref: "#/components/schemas/StateOfApplicability"
|
$ref: "#/components/schemas/StatementOfApplicability"
|
||||||
|
|
||||||
DeleteStateOfApplicabilityInput:
|
DeleteStatementOfApplicabilityInput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: State of applicability ID
|
description: Statement of applicability ID
|
||||||
|
|
||||||
DeleteStateOfApplicabilityOutput:
|
DeleteStatementOfApplicabilityOutput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- deleted_state_of_applicability_id
|
- deleted_statement_of_applicability_id
|
||||||
properties:
|
properties:
|
||||||
deleted_state_of_applicability_id:
|
deleted_statement_of_applicability_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: Deleted state of applicability ID
|
description: Deleted statement of applicability ID
|
||||||
|
|
||||||
ExportStateOfApplicabilityPDFInput:
|
ExportStatementOfApplicabilityPDFInput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: State of applicability ID
|
description: Statement of applicability ID
|
||||||
|
|
||||||
ExportStateOfApplicabilityPDFOutput:
|
ExportStatementOfApplicabilityPDFOutput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- pdf_base64
|
- pdf_base64
|
||||||
@@ -6292,7 +6292,7 @@ components:
|
|||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- state_of_applicability_id
|
- statement_of_applicability_id
|
||||||
- control_id
|
- control_id
|
||||||
- organization_id
|
- organization_id
|
||||||
- applicability
|
- applicability
|
||||||
@@ -6302,9 +6302,9 @@ components:
|
|||||||
id:
|
id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: Applicability statement ID
|
description: Applicability statement ID
|
||||||
state_of_applicability_id:
|
statement_of_applicability_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: State of applicability ID
|
description: Statement of applicability ID
|
||||||
control_id:
|
control_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: Control ID
|
description: Control ID
|
||||||
@@ -6336,11 +6336,11 @@ components:
|
|||||||
ListApplicabilityStatementsInput:
|
ListApplicabilityStatementsInput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- state_of_applicability_id
|
- statement_of_applicability_id
|
||||||
properties:
|
properties:
|
||||||
state_of_applicability_id:
|
statement_of_applicability_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: State of applicability ID
|
description: Statement of applicability ID
|
||||||
order_by:
|
order_by:
|
||||||
$ref: "#/components/schemas/ApplicabilityStatementOrderBy"
|
$ref: "#/components/schemas/ApplicabilityStatementOrderBy"
|
||||||
description: Order by
|
description: Order by
|
||||||
@@ -6384,13 +6384,13 @@ components:
|
|||||||
AddApplicabilityStatementInput:
|
AddApplicabilityStatementInput:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- state_of_applicability_id
|
- statement_of_applicability_id
|
||||||
- control_id
|
- control_id
|
||||||
- applicability
|
- applicability
|
||||||
properties:
|
properties:
|
||||||
state_of_applicability_id:
|
statement_of_applicability_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: State of applicability ID
|
description: Statement of applicability ID
|
||||||
control_id:
|
control_id:
|
||||||
$ref: "#/components/schemas/GID"
|
$ref: "#/components/schemas/GID"
|
||||||
description: Control ID
|
description: Control ID
|
||||||
@@ -8526,60 +8526,60 @@ tools:
|
|||||||
$ref: "#/components/schemas/ListMeetingAttendeesInput"
|
$ref: "#/components/schemas/ListMeetingAttendeesInput"
|
||||||
outputSchema:
|
outputSchema:
|
||||||
$ref: "#/components/schemas/ListMeetingAttendeesOutput"
|
$ref: "#/components/schemas/ListMeetingAttendeesOutput"
|
||||||
- name: listStatesOfApplicability
|
- name: listStatementsOfApplicability
|
||||||
description: List all states of applicability for the organization
|
description: List all statements of applicability for the organization
|
||||||
hints:
|
hints:
|
||||||
readonly: true
|
readonly: true
|
||||||
idempotent: true
|
idempotent: true
|
||||||
inputSchema:
|
inputSchema:
|
||||||
$ref: "#/components/schemas/ListStatesOfApplicabilityInput"
|
$ref: "#/components/schemas/ListStatementsOfApplicabilityInput"
|
||||||
outputSchema:
|
outputSchema:
|
||||||
$ref: "#/components/schemas/ListStatesOfApplicabilityOutput"
|
$ref: "#/components/schemas/ListStatementsOfApplicabilityOutput"
|
||||||
- name: getStateOfApplicability
|
- name: getStatementOfApplicability
|
||||||
description: Get a state of applicability by ID
|
description: Get a statement of applicability by ID
|
||||||
hints:
|
hints:
|
||||||
readonly: true
|
readonly: true
|
||||||
idempotent: true
|
idempotent: true
|
||||||
inputSchema:
|
inputSchema:
|
||||||
$ref: "#/components/schemas/GetStateOfApplicabilityInput"
|
$ref: "#/components/schemas/GetStatementOfApplicabilityInput"
|
||||||
outputSchema:
|
outputSchema:
|
||||||
$ref: "#/components/schemas/GetStateOfApplicabilityOutput"
|
$ref: "#/components/schemas/GetStatementOfApplicabilityOutput"
|
||||||
- name: addStateOfApplicability
|
- name: addStatementOfApplicability
|
||||||
description: Add a new state of applicability to the organization
|
description: Add a new statement of applicability to the organization
|
||||||
hints:
|
hints:
|
||||||
readonly: false
|
readonly: false
|
||||||
inputSchema:
|
inputSchema:
|
||||||
$ref: "#/components/schemas/AddStateOfApplicabilityInput"
|
$ref: "#/components/schemas/AddStatementOfApplicabilityInput"
|
||||||
outputSchema:
|
outputSchema:
|
||||||
$ref: "#/components/schemas/AddStateOfApplicabilityOutput"
|
$ref: "#/components/schemas/AddStatementOfApplicabilityOutput"
|
||||||
- name: updateStateOfApplicability
|
- name: updateStatementOfApplicability
|
||||||
description: Update an existing state of applicability
|
description: Update an existing statement of applicability
|
||||||
hints:
|
hints:
|
||||||
readonly: false
|
readonly: false
|
||||||
inputSchema:
|
inputSchema:
|
||||||
$ref: "#/components/schemas/UpdateStateOfApplicabilityInput"
|
$ref: "#/components/schemas/UpdateStatementOfApplicabilityInput"
|
||||||
outputSchema:
|
outputSchema:
|
||||||
$ref: "#/components/schemas/UpdateStateOfApplicabilityOutput"
|
$ref: "#/components/schemas/UpdateStatementOfApplicabilityOutput"
|
||||||
- name: deleteStateOfApplicability
|
- name: deleteStatementOfApplicability
|
||||||
description: Delete a state of applicability
|
description: Delete a statement of applicability
|
||||||
hints:
|
hints:
|
||||||
readonly: false
|
readonly: false
|
||||||
destructive: true
|
destructive: true
|
||||||
inputSchema:
|
inputSchema:
|
||||||
$ref: "#/components/schemas/DeleteStateOfApplicabilityInput"
|
$ref: "#/components/schemas/DeleteStatementOfApplicabilityInput"
|
||||||
outputSchema:
|
outputSchema:
|
||||||
$ref: "#/components/schemas/DeleteStateOfApplicabilityOutput"
|
$ref: "#/components/schemas/DeleteStatementOfApplicabilityOutput"
|
||||||
- name: exportStateOfApplicabilityPDF
|
- name: exportStatementOfApplicabilityPDF
|
||||||
description: Export a state of applicability as a PDF document
|
description: Export a statement of applicability as a PDF document
|
||||||
hints:
|
hints:
|
||||||
readonly: true
|
readonly: true
|
||||||
idempotent: true
|
idempotent: true
|
||||||
inputSchema:
|
inputSchema:
|
||||||
$ref: "#/components/schemas/ExportStateOfApplicabilityPDFInput"
|
$ref: "#/components/schemas/ExportStatementOfApplicabilityPDFInput"
|
||||||
outputSchema:
|
outputSchema:
|
||||||
$ref: "#/components/schemas/ExportStateOfApplicabilityPDFOutput"
|
$ref: "#/components/schemas/ExportStatementOfApplicabilityPDFOutput"
|
||||||
- name: listApplicabilityStatements
|
- name: listApplicabilityStatements
|
||||||
description: List all applicability statements for a state of applicability
|
description: List all applicability statements for a statement of applicability
|
||||||
hints:
|
hints:
|
||||||
readonly: true
|
readonly: true
|
||||||
idempotent: true
|
idempotent: true
|
||||||
@@ -8597,7 +8597,7 @@ tools:
|
|||||||
outputSchema:
|
outputSchema:
|
||||||
$ref: "#/components/schemas/GetApplicabilityStatementOutput"
|
$ref: "#/components/schemas/GetApplicabilityStatementOutput"
|
||||||
- name: addApplicabilityStatement
|
- name: addApplicabilityStatement
|
||||||
description: Add a control to a state of applicability with an applicability decision
|
description: Add a control to a statement of applicability with an applicability decision
|
||||||
hints:
|
hints:
|
||||||
readonly: false
|
readonly: false
|
||||||
inputSchema:
|
inputSchema:
|
||||||
@@ -8613,7 +8613,7 @@ tools:
|
|||||||
outputSchema:
|
outputSchema:
|
||||||
$ref: "#/components/schemas/UpdateApplicabilityStatementOutput"
|
$ref: "#/components/schemas/UpdateApplicabilityStatementOutput"
|
||||||
- name: deleteApplicabilityStatement
|
- name: deleteApplicabilityStatement
|
||||||
description: Delete an applicability statement from a state of applicability
|
description: Delete an applicability statement from a statement of applicability
|
||||||
hints:
|
hints:
|
||||||
readonly: false
|
readonly: false
|
||||||
destructive: true
|
destructive: true
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/page"
|
"go.probo.inc/probo/pkg/page"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewStateOfApplicability(s *coredata.StateOfApplicability) *StateOfApplicability {
|
func NewStatementOfApplicability(s *coredata.StatementOfApplicability) *StatementOfApplicability {
|
||||||
return &StateOfApplicability{
|
return &StatementOfApplicability{
|
||||||
ID: s.ID,
|
ID: s.ID,
|
||||||
OrganizationID: s.OrganizationID,
|
OrganizationID: s.OrganizationID,
|
||||||
Name: s.Name,
|
Name: s.Name,
|
||||||
@@ -30,33 +30,33 @@ func NewStateOfApplicability(s *coredata.StateOfApplicability) *StateOfApplicabi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewListStatesOfApplicabilityOutput(pg *page.Page[*coredata.StateOfApplicability, coredata.StateOfApplicabilityOrderField]) ListStatesOfApplicabilityOutput {
|
func NewListStatementsOfApplicabilityOutput(pg *page.Page[*coredata.StatementOfApplicability, coredata.StatementOfApplicabilityOrderField]) ListStatementsOfApplicabilityOutput {
|
||||||
items := make([]*StateOfApplicability, 0, len(pg.Data))
|
items := make([]*StatementOfApplicability, 0, len(pg.Data))
|
||||||
for _, v := range pg.Data {
|
for _, v := range pg.Data {
|
||||||
items = append(items, NewStateOfApplicability(v))
|
items = append(items, NewStatementOfApplicability(v))
|
||||||
}
|
}
|
||||||
var nextCursor *page.CursorKey
|
var nextCursor *page.CursorKey
|
||||||
if len(pg.Data) > 0 {
|
if len(pg.Data) > 0 {
|
||||||
cursorKey := pg.Data[len(pg.Data)-1].CursorKey(pg.Cursor.OrderBy.Field)
|
cursorKey := pg.Data[len(pg.Data)-1].CursorKey(pg.Cursor.OrderBy.Field)
|
||||||
nextCursor = &cursorKey
|
nextCursor = &cursorKey
|
||||||
}
|
}
|
||||||
return ListStatesOfApplicabilityOutput{
|
return ListStatementsOfApplicabilityOutput{
|
||||||
NextCursor: nextCursor,
|
NextCursor: nextCursor,
|
||||||
StatesOfApplicability: items,
|
StatementsOfApplicability: items,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApplicabilityStatement(a *coredata.ApplicabilityStatement) *ApplicabilityStatement {
|
func NewApplicabilityStatement(a *coredata.ApplicabilityStatement) *ApplicabilityStatement {
|
||||||
return &ApplicabilityStatement{
|
return &ApplicabilityStatement{
|
||||||
ID: a.ID,
|
ID: a.ID,
|
||||||
StateOfApplicabilityID: a.StateOfApplicabilityID,
|
StatementOfApplicabilityID: a.StatementOfApplicabilityID,
|
||||||
ControlID: a.ControlID,
|
ControlID: a.ControlID,
|
||||||
OrganizationID: a.OrganizationID,
|
OrganizationID: a.OrganizationID,
|
||||||
SnapshotID: a.SnapshotID,
|
SnapshotID: a.SnapshotID,
|
||||||
Applicability: a.Applicability,
|
Applicability: a.Applicability,
|
||||||
Justification: a.Justification,
|
Justification: a.Justification,
|
||||||
CreatedAt: a.CreatedAt,
|
CreatedAt: a.CreatedAt,
|
||||||
UpdatedAt: a.UpdatedAt,
|
UpdatedAt: a.UpdatedAt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user