Order risks by owner name

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-09-18 13:20:26 +02:00
parent eabc34c3ac
commit 72a581b66b
16 changed files with 272 additions and 64 deletions

View File

@@ -21,7 +21,7 @@ type Order = {
field: string;
};
const SortableContext = createContext({
export const SortableContext = createContext({
order: {
direction: "DESC",
field: "CREATED_AT",

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<38b7fae585eb2c09409935db8ad3cfe9>>
* @generated SignedSource<<828d1e2364b7b8c540508d9fb7104b06>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -17,6 +17,7 @@ export type useRiskFormFragment$data = {
readonly id: string;
readonly inherentImpact: number;
readonly inherentLikelihood: number;
readonly inherentRiskScore: number;
readonly name: string;
readonly note: string;
readonly owner: {
@@ -24,6 +25,7 @@ export type useRiskFormFragment$data = {
} | null | undefined;
readonly residualImpact: number;
readonly residualLikelihood: number;
readonly residualRiskScore: number;
readonly treatment: RiskTreatment;
readonly " $fragmentType": "useRiskFormFragment";
};
@@ -103,6 +105,20 @@ return {
"name": "residualImpact",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "inherentRiskScore",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "residualRiskScore",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -128,6 +144,6 @@ return {
};
})();
(node as any).hash = "7ad9386b4049af3f139d7269bb5229c2";
(node as any).hash = "d9b52f879eadba5f7b1c18dcdbf85559";
export default node;

View File

@@ -18,6 +18,8 @@ const RiskFragment = graphql`
inherentImpact
residualLikelihood
residualImpact
inherentRiskScore
residualRiskScore
note
owner {
id

View File

@@ -1,10 +1,10 @@
import { ConnectionHandler, graphql } from "relay-runtime";
import { graphql } from "relay-runtime";
import { useTranslate } from "@probo/i18n";
import { useMutationWithToasts } from "../useMutationWithToasts.ts";
import type { RiskGraphDeleteMutation } from "./__generated__/RiskGraphDeleteMutation.graphql.ts";
import {
usePreloadedQuery,
useRefetchableFragment,
usePaginationFragment,
type PreloadedQuery,
} from "react-relay";
import type { RiskGraphListQuery } from "./__generated__/RiskGraphListQuery.graphql.ts";
@@ -44,7 +44,7 @@ const risksFragment = graphql`
@refetchable(queryName: "RisksListQuery")
@argumentDefinitions(
first: { type: "Int", defaultValue: 50 }
order: { type: "RiskOrder", defaultValue: null }
order: { type: "RiskOrder", defaultValue: { direction: DESC, field: CREATED_AT } }
after: { type: "CursorKey", defaultValue: null }
before: { type: "CursorKey", defaultValue: null }
last: { type: "Int", defaultValue: null }
@@ -58,6 +58,7 @@ const risksFragment = graphql`
orderBy: $order
filter: { snapshotId: $snapshotId }
) @connection(key: "RisksListQuery_risks", filters: ["filter"]) {
__id
edges {
node {
id
@@ -65,6 +66,10 @@ const risksFragment = graphql`
name
category
treatment
owner {
id
fullName
}
inherentLikelihood
inherentImpact
residualLikelihood
@@ -80,21 +85,18 @@ const risksFragment = graphql`
export const RisksConnectionKey = "RisksListQuery_risks";
export function useRisksQuery(queryRef: PreloadedQuery<RiskGraphListQuery>, snapshotId?: string | null) {
export function useRisksQuery(queryRef: PreloadedQuery<RiskGraphListQuery>) {
const data = usePreloadedQuery(risksQuery, queryRef);
const [dataFragment, refetch] = useRefetchableFragment(
const pagination = usePaginationFragment(
risksFragment,
data.organization as RiskGraphFragment$key,
);
const risks = dataFragment?.risks?.edges.map((edge) => edge.node);
const risks = pagination.data?.risks?.edges.map((edge) => edge.node);
return {
...pagination,
risks,
refetch,
connectionId: ConnectionHandler.getConnectionID(
data.organization.id,
RisksConnectionKey,
{ filter: { snapshotId: snapshotId || null } }
),
connectionId: pagination.data.risks.__id,
};
}

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<2b964bdee12b49230932678f583c7401>>
* @generated SignedSource<<c579c68998b3ded3e8833a7911f01a19>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -14,6 +14,7 @@ import { FragmentRefs } from "relay-runtime";
export type RiskGraphFragment$data = {
readonly id: string;
readonly risks: {
readonly __id: string;
readonly edges: ReadonlyArray<{
readonly node: {
readonly category: string;
@@ -22,6 +23,10 @@ export type RiskGraphFragment$data = {
readonly inherentLikelihood: number;
readonly inherentRiskScore: number;
readonly name: string;
readonly owner: {
readonly fullName: string;
readonly id: string;
} | null | undefined;
readonly residualImpact: number;
readonly residualLikelihood: number;
readonly residualRiskScore: number;
@@ -74,7 +79,10 @@ return {
"name": "last"
},
{
"defaultValue": null,
"defaultValue": {
"direction": "DESC",
"field": "CREATED_AT"
},
"kind": "LocalArgument",
"name": "order"
},
@@ -183,6 +191,25 @@ return {
"name": "treatment",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
(v1/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -288,6 +315,18 @@ return {
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": null
@@ -299,6 +338,6 @@ return {
};
})();
(node as any).hash = "95c68a022cbf075eede9b7417393a369";
(node as any).hash = "d8048ddb0ff8d4b08b7b9676d9b98f1a";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<af89b7b79cdb083497eabebd82b51991>>
* @generated SignedSource<<af4a12179ab70cae3cc3f8c434151de0>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -76,6 +76,14 @@ v5 = [
"kind": "Literal",
"name": "first",
"value": 50
},
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
}
];
return {
@@ -178,6 +186,25 @@ return {
"name": "treatment",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -234,18 +261,6 @@ return {
"name": "note",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
(v2/*: any*/)
],
"storageKey": null
},
(v4/*: any*/)
],
"storageKey": null
@@ -298,6 +313,18 @@ return {
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": null
@@ -323,12 +350,12 @@ return {
]
},
"params": {
"cacheID": "b2114c476ed7e095fc9d2317b6b1c554",
"cacheID": "225123bb702f2bce307ca69bea183e88",
"id": null,
"metadata": {},
"name": "RiskGraphListQuery",
"operationKind": "query",
"text": "query RiskGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ...RiskGraphFragment_3iomuz\n }\n}\n\nfragment RiskGraphFragment_3iomuz on Organization {\n risks(first: 50, filter: {snapshotId: $snapshotId}) {\n edges {\n node {\n id\n snapshotId\n name\n category\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n ...useRiskFormFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n owner {\n id\n }\n}\n"
"text": "query RiskGraphListQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ...RiskGraphFragment_3iomuz\n }\n}\n\nfragment RiskGraphFragment_3iomuz on Organization {\n risks(first: 50, orderBy: {direction: DESC, field: CREATED_AT}, filter: {snapshotId: $snapshotId}) {\n edges {\n node {\n id\n snapshotId\n name\n category\n treatment\n owner {\n id\n fullName\n }\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n ...useRiskFormFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n note\n owner {\n id\n }\n}\n"
}
};
})();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<494ff8512e4a50c2bbc2cb3453dbab1c>>
* @generated SignedSource<<9abcf06eed9cb70f62b2aed2b907e9e5>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -655,12 +655,12 @@ return {
]
},
"params": {
"cacheID": "03ef938803c52b572e23e691d50c4188",
"cacheID": "c3d393180d6273b2e910c7ebffb75df7",
"id": null,
"metadata": {},
"name": "RiskGraphNodeQuery",
"operationKind": "query",
"text": "query RiskGraphNodeQuery(\n $riskId: ID!\n) {\n node(id: $riskId) {\n __typename\n ... on Risk {\n id\n snapshotId\n name\n description\n treatment\n owner {\n id\n fullName\n }\n note\n inherentRiskScore\n residualRiskScore\n measuresInfo: measures(first: 0) {\n totalCount\n }\n documentsInfo: documents(first: 0) {\n totalCount\n }\n controlsInfo: controls(first: 0) {\n totalCount\n }\n ...useRiskFormFragment\n ...RiskOverviewTabFragment\n ...RiskMeasuresTabFragment\n ...RiskDocumentsTabFragment\n ...RiskControlsTabFragment\n }\n id\n }\n}\n\nfragment LinkedDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment LinkedMeasuresCardFragment on Measure {\n id\n name\n state\n}\n\nfragment RiskControlsTabFragment on Risk {\n id\n controls(first: 20) {\n edges {\n node {\n id\n sectionTitle\n name\n framework {\n id\n name\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment RiskDocumentsTabFragment on Risk {\n id\n documents(first: 100) {\n edges {\n node {\n id\n ...LinkedDocumentsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment RiskMeasuresTabFragment on Risk {\n id\n measures(first: 100) {\n edges {\n node {\n id\n ...LinkedMeasuresCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment RiskOverviewTabFragment on Risk {\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n owner {\n id\n }\n}\n"
"text": "query RiskGraphNodeQuery(\n $riskId: ID!\n) {\n node(id: $riskId) {\n __typename\n ... on Risk {\n id\n snapshotId\n name\n description\n treatment\n owner {\n id\n fullName\n }\n note\n inherentRiskScore\n residualRiskScore\n measuresInfo: measures(first: 0) {\n totalCount\n }\n documentsInfo: documents(first: 0) {\n totalCount\n }\n controlsInfo: controls(first: 0) {\n totalCount\n }\n ...useRiskFormFragment\n ...RiskOverviewTabFragment\n ...RiskMeasuresTabFragment\n ...RiskDocumentsTabFragment\n ...RiskControlsTabFragment\n }\n id\n }\n}\n\nfragment LinkedDocumentsCardFragment on Document {\n id\n title\n createdAt\n documentType\n versions(first: 1) {\n edges {\n node {\n id\n status\n }\n }\n }\n}\n\nfragment LinkedMeasuresCardFragment on Measure {\n id\n name\n state\n}\n\nfragment RiskControlsTabFragment on Risk {\n id\n controls(first: 20) {\n edges {\n node {\n id\n sectionTitle\n name\n framework {\n id\n name\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment RiskDocumentsTabFragment on Risk {\n id\n documents(first: 100) {\n edges {\n node {\n id\n ...LinkedDocumentsCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment RiskMeasuresTabFragment on Risk {\n id\n measures(first: 100) {\n edges {\n node {\n id\n ...LinkedMeasuresCardFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment RiskOverviewTabFragment on Risk {\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n note\n owner {\n id\n }\n}\n"
}
};
})();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<4a0922eabd4e20c574db91e75f45a562>>
* @generated SignedSource<<29125e9f2562c96a6076ed8b0504a4b1>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -11,7 +11,7 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type OrderDirection = "ASC" | "DESC";
export type RiskOrderField = "CATEGORY" | "CREATED_AT" | "INHERENT_RISK_SCORE" | "NAME" | "RESIDUAL_RISK_SCORE" | "TREATMENT" | "UPDATED_AT";
export type RiskOrderField = "CATEGORY" | "CREATED_AT" | "INHERENT_RISK_SCORE" | "NAME" | "OWNER_FULL_NAME" | "RESIDUAL_RISK_SCORE" | "TREATMENT" | "UPDATED_AT";
export type RiskOrder = {
direction: OrderDirection;
field: RiskOrderField;
@@ -62,7 +62,10 @@ v4 = {
"name": "last"
},
v5 = {
"defaultValue": null,
"defaultValue": {
"direction": "DESC",
"field": "CREATED_AT"
},
"kind": "LocalArgument",
"name": "order"
},
@@ -261,6 +264,25 @@ return {
"name": "treatment",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
(v14/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -317,18 +339,6 @@ return {
"name": "note",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
(v14/*: any*/)
],
"storageKey": null
},
(v13/*: any*/)
],
"storageKey": null
@@ -381,6 +391,18 @@ return {
}
],
"storageKey": null
},
{
"kind": "ClientExtension",
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__id",
"storageKey": null
}
]
}
],
"storageKey": null
@@ -406,16 +428,16 @@ return {
]
},
"params": {
"cacheID": "161eb78d1d5100120c68db5d8106aa7e",
"cacheID": "34a33dde7e4e7868a885b6b6317f506b",
"id": null,
"metadata": {},
"name": "RisksListQuery",
"operationKind": "query",
"text": "query RisksListQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 50\n $last: Int = null\n $order: RiskOrder = null\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...RiskGraphFragment_25MC8O\n id\n }\n}\n\nfragment RiskGraphFragment_25MC8O on Organization {\n risks(first: $first, after: $after, last: $last, before: $before, orderBy: $order, filter: {snapshotId: $snapshotId}) {\n edges {\n node {\n id\n snapshotId\n name\n category\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n ...useRiskFormFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n owner {\n id\n }\n}\n"
"text": "query RisksListQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 50\n $last: Int = null\n $order: RiskOrder = {direction: DESC, field: CREATED_AT}\n $snapshotId: ID = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...RiskGraphFragment_25MC8O\n id\n }\n}\n\nfragment RiskGraphFragment_25MC8O on Organization {\n risks(first: $first, after: $after, last: $last, before: $before, orderBy: $order, filter: {snapshotId: $snapshotId}) {\n edges {\n node {\n id\n snapshotId\n name\n category\n treatment\n owner {\n id\n fullName\n }\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n ...useRiskFormFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n note\n owner {\n id\n }\n}\n"
}
};
})();
(node as any).hash = "95c68a022cbf075eede9b7417393a369";
(node as any).hash = "d8048ddb0ff8d4b08b7b9676d9b98f1a";
export default node;

View File

@@ -41,6 +41,7 @@ type Props = {
risk?: RiskKey;
connection?: string;
ref?: ReturnType<typeof useDialogRef>;
onSuccess?: () => void;
};
type RiskTemplate = {
@@ -82,6 +83,7 @@ export default function FormRiskDialog({
risk,
connection,
ref: refProps,
onSuccess,
}: Props) {
const { __ } = useTranslate();
const organizationId = useOrganizationId();
@@ -131,6 +133,7 @@ export default function FormRiskDialog({
onSuccess: () => {
ref?.current?.close();
reset();
onSuccess?.();
},
});
});

View File

@@ -40,7 +40,17 @@ export default function RisksPage(props: Props) {
const { snapshotId } = useParams<{ snapshotId?: string }>();
const isSnapshotMode = Boolean(snapshotId);
const { connectionId, risks, refetch } = useRisksQuery(props.queryRef, snapshotId);
const { connectionId, risks, ...pagination } = useRisksQuery(props.queryRef);
const refetch = ({ order }: { order: { direction: string; field: string } }) => {
pagination.refetch({
snapshotId,
order: {
direction: order.direction as "ASC" | "DESC",
field: order.field as "NAME" | "CATEGORY" | "TREATMENT" | "INHERENT_RISK_SCORE" | "RESIDUAL_RISK_SCORE" | "OWNER_FULL_NAME" | "CREATED_AT"
}
}, { fetchPolicy: 'network-only' });
};
usePageTitle(__("Risks"));
@@ -56,6 +66,9 @@ export default function RisksPage(props: Props) {
{!isSnapshotMode && (
<FormRiskDialog
connection={connectionId}
onSuccess={() => {
pagination.refetch({ snapshotId });
}}
trigger={<Button icon={IconPlusLarge}>{__("New Risk")}</Button>}
/>
)}
@@ -73,7 +86,7 @@ export default function RisksPage(props: Props) {
risks={risks}
/>
</div>
<SortableTable refetch={refetch}>
<SortableTable {...pagination} refetch={refetch}>
<Thead>
<Tr>
<SortableTh field="NAME">{__("Risk name")}</SortableTh>
@@ -85,6 +98,9 @@ export default function RisksPage(props: Props) {
<SortableTh field="RESIDUAL_RISK_SCORE">
{__("Residual Risk")}
</SortableTh>
<SortableTh field="OWNER_FULL_NAME">
{__("Owner")}
</SortableTh>
<Th></Th>
</Tr>
</Thead>
@@ -163,6 +179,7 @@ function RiskRow(props: RowProps) {
<Td>
<SeverityBadge score={risk.residualRiskScore} />
</Td>
<Td>{risk.owner?.fullName || __("Unassigned")}</Td>
<Td noLink className="text-end">
{!isSnapshotMode && (
<ActionDropdown>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<7d5730a1c721f5256e6e0c07199aa0d2>>
* @generated SignedSource<<66f4e8603a811d1fb363ae88ea697b22>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -209,6 +209,20 @@ return {
"name": "residualImpact",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "inherentRiskScore",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "residualRiskScore",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -256,12 +270,12 @@ return {
]
},
"params": {
"cacheID": "e2131409b62d6cd6bd8a6d008f2ac1f5",
"cacheID": "a6ca4767b2443f6b4d02d6fdd1358600",
"id": null,
"metadata": {},
"name": "FormRiskDialogMutation",
"operationKind": "mutation",
"text": "mutation FormRiskDialogMutation(\n $input: CreateRiskInput!\n) {\n createRisk(input: $input) {\n riskEdge {\n node {\n ...useRiskFormFragment\n id\n }\n }\n }\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n owner {\n id\n }\n}\n"
"text": "mutation FormRiskDialogMutation(\n $input: CreateRiskInput!\n) {\n createRisk(input: $input) {\n riskEdge {\n node {\n ...useRiskFormFragment\n id\n }\n }\n }\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n note\n owner {\n id\n }\n}\n"
}
};
})();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<dc5427f9197a47414ed10738473fdca1>>
* @generated SignedSource<<4122b3e15107bc0f2c5f8b842b882603>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -178,6 +178,20 @@ return {
"name": "residualImpact",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "inherentRiskScore",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "residualRiskScore",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -206,12 +220,12 @@ return {
]
},
"params": {
"cacheID": "546b1e60a2e87bf71a1851ca76485767",
"cacheID": "59f586a59973ca023df027fdfb0d4bed",
"id": null,
"metadata": {},
"name": "FormRiskDialogUpdateRiskMutation",
"operationKind": "mutation",
"text": "mutation FormRiskDialogUpdateRiskMutation(\n $input: UpdateRiskInput!\n) {\n updateRisk(input: $input) {\n risk {\n ...useRiskFormFragment\n id\n }\n }\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n owner {\n id\n }\n}\n"
"text": "mutation FormRiskDialogUpdateRiskMutation(\n $input: UpdateRiskInput!\n) {\n updateRisk(input: $input) {\n risk {\n ...useRiskFormFragment\n id\n }\n }\n}\n\nfragment useRiskFormFragment on Risk {\n id\n name\n category\n description\n treatment\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n inherentRiskScore\n residualRiskScore\n note\n owner {\n id\n }\n}\n"
}
};
})();

View File

@@ -46,6 +46,9 @@ type (
SourceID *gid.GID `db:"source_id"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
// Ordering only
OwnerFullName *string `db:"owner_full_name"`
}
Risks []*Risk
@@ -69,6 +72,8 @@ func (r *Risk) CursorKey(orderBy RiskOrderField) page.CursorKey {
return page.CursorKey{ID: r.ID, Value: r.InherentRiskScore}
case RiskOrderFieldResidualRiskScore:
return page.CursorKey{ID: r.ID, Value: r.ResidualRiskScore}
case RiskOrderFieldOwnerFullName:
return page.CursorKey{ID: r.ID, Value: r.OwnerFullName}
}
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
@@ -136,6 +141,7 @@ WITH rsks AS (
r.description,
r.category,
r.owner_id,
p.full_name as owner_full_name,
r.treatment,
r.note,
r.inherent_likelihood,
@@ -153,6 +159,8 @@ WITH rsks AS (
risks r
INNER JOIN
risks_measures rm ON r.id = rm.risk_id
LEFT JOIN
peoples p ON r.owner_id = p.id
WHERE
rm.measure_id = @measure_id
)
@@ -163,6 +171,7 @@ SELECT
description,
category,
owner_id,
owner_full_name,
treatment,
note,
inherent_likelihood,
@@ -243,12 +252,43 @@ func (r *Risks) LoadByOrganizationID(
filter *RiskFilter,
) error {
q := `
WITH rsks AS (
SELECT
r.id,
r.tenant_id,
r.organization_id,
r.name,
r.description,
r.owner_id,
p.full_name as owner_full_name,
r.treatment,
r.note,
r.inherent_likelihood,
r.inherent_impact,
r.inherent_risk_score,
r.residual_likelihood,
r.residual_impact,
r.residual_risk_score,
r.category,
r.snapshot_id,
r.source_id,
r.search_vector,
r.created_at,
r.updated_at
FROM
risks r
LEFT JOIN
peoples p ON r.owner_id = p.id
WHERE
r.organization_id = @organization_id
)
SELECT
id,
organization_id,
name,
description,
owner_id,
owner_full_name,
treatment,
note,
inherent_likelihood,
@@ -262,9 +302,9 @@ SELECT
source_id,
created_at,
updated_at
FROM risks
FROM
rsks
WHERE %s
AND organization_id = @organization_id
AND %s
AND %s
`
@@ -304,6 +344,7 @@ SELECT
description,
category,
owner_id,
NULL as owner_full_name,
treatment,
note,
inherent_likelihood,

View File

@@ -26,6 +26,7 @@ const (
RiskOrderFieldTreatment RiskOrderField = "TREATMENT"
RiskOrderFieldInherentRiskScore RiskOrderField = "INHERENT_RISK_SCORE"
RiskOrderFieldResidualRiskScore RiskOrderField = "RESIDUAL_RISK_SCORE"
RiskOrderFieldOwnerFullName RiskOrderField = "OWNER_FULL_NAME"
)
func (p RiskOrderField) Column() string {

View File

@@ -431,6 +431,10 @@ enum RiskOrderField
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.RiskOrderFieldResidualRiskScore"
)
OWNER_FULL_NAME
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.RiskOrderFieldOwnerFullName"
)
}
enum EvidenceOrderField

View File

@@ -8564,6 +8564,10 @@ enum RiskOrderField
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.RiskOrderFieldResidualRiskScore"
)
OWNER_FULL_NAME
@goEnum(
value: "github.com/getprobo/probo/pkg/coredata.RiskOrderFieldOwnerFullName"
)
}
enum EvidenceOrderField
@@ -88188,6 +88192,7 @@ var (
"TREATMENT": coredata.RiskOrderFieldTreatment,
"INHERENT_RISK_SCORE": coredata.RiskOrderFieldInherentRiskScore,
"RESIDUAL_RISK_SCORE": coredata.RiskOrderFieldResidualRiskScore,
"OWNER_FULL_NAME": coredata.RiskOrderFieldOwnerFullName,
}
marshalNRiskOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskOrderField = map[coredata.RiskOrderField]string{
coredata.RiskOrderFieldCreatedAt: "CREATED_AT",
@@ -88197,6 +88202,7 @@ var (
coredata.RiskOrderFieldTreatment: "TREATMENT",
coredata.RiskOrderFieldInherentRiskScore: "INHERENT_RISK_SCORE",
coredata.RiskOrderFieldResidualRiskScore: "RESIDUAL_RISK_SCORE",
coredata.RiskOrderFieldOwnerFullName: "OWNER_FULL_NAME",
}
)