Add risk tier, criticality on vendors
Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
@@ -1,29 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { HelpCircle } from "lucide-react";
|
||||
import { HelpCircle, ArrowUpRight } from "lucide-react";
|
||||
import {
|
||||
graphql,
|
||||
PreloadedQuery,
|
||||
usePreloadedQuery,
|
||||
useQueryLoader,
|
||||
} from "react-relay";
|
||||
import { Suspense, useEffect } from "react";
|
||||
import { Suspense, useEffect, useState } from "react";
|
||||
import type { VendorOverviewPageQuery as VendorOverviewPageQueryType } from "./__generated__/VendorOverviewPageQuery.graphql";
|
||||
import { useParams } from "react-router";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useBreadcrumb } from "@/contexts/BreadcrumbContext";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const VendorOverviewPageQuery = graphql`
|
||||
const vendorOverviewPageQuery = graphql`
|
||||
query VendorOverviewPageQuery($vendorId: ID!) {
|
||||
node(id: $vendorId) {
|
||||
... on Vendor {
|
||||
id
|
||||
name
|
||||
serviceStartDate
|
||||
serviceTerminationDate
|
||||
serviceCriticality
|
||||
riskTier
|
||||
statusPageUrl
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
@@ -36,9 +39,10 @@ function VendorOverviewPageContent({
|
||||
}: {
|
||||
queryRef: PreloadedQuery<VendorOverviewPageQueryType>;
|
||||
}) {
|
||||
const data = usePreloadedQuery(VendorOverviewPageQuery, queryRef);
|
||||
const [riskLevel, setRiskLevel] = useState("medium");
|
||||
const data = usePreloadedQuery(vendorOverviewPageQuery, queryRef);
|
||||
const { setBreadcrumbSegment } = useBreadcrumb();
|
||||
const [selectedCriticality, setSelectedCriticality] = useState(data.node.serviceCriticality);
|
||||
const [selectedRiskTier, setSelectedRiskTier] = useState(data.node.riskTier);
|
||||
|
||||
useEffect(() => {
|
||||
if (data.node?.name) {
|
||||
@@ -50,57 +54,18 @@ function VendorOverviewPageContent({
|
||||
<div className="space-y-6 p-4 md:p-6 lg:p-8">
|
||||
<div className="mx-auto max-w-4xl space-y-6">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<img
|
||||
src="https://hebbkx1anhila5yf.public.blob.vercel-storage.com/image-G4dMt0eis6LFLrCaYPeMr7Nkt2iPoj.png"
|
||||
alt="Google Cloud"
|
||||
className="h-8 w-8"
|
||||
/>
|
||||
<h1 className="text-xl font-semibold text-gray-900">
|
||||
{data.node?.name}
|
||||
</h1>
|
||||
</div>
|
||||
<p className="text-gray-600">
|
||||
Use this form to assess the risk of using Google Workspace as a
|
||||
vendor.
|
||||
</p>
|
||||
<h1 className="text-xl font-semibold text-gray-900">
|
||||
{data.node?.name}
|
||||
</h1>
|
||||
<p className="text-gray-600">View and manage vendor details</p>
|
||||
</div>
|
||||
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-lg font-medium">Asset Storage Type</h2>
|
||||
<h2 className="text-lg font-medium">Service Information</h2>
|
||||
<p className="text-sm text-gray-500">
|
||||
Questions related to the type of assets stored by the vendor.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">
|
||||
Does this vendor store physical or digital assets?
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900">
|
||||
Digital
|
||||
</button>
|
||||
<button className="rounded-full bg-green-100 px-4 py-1 text-sm text-green-900">
|
||||
Physical
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-lg font-medium">Data Storage and Handling</h2>
|
||||
<p className="text-sm text-gray-500">
|
||||
Questions related to the vendor's data storage and handling
|
||||
practices.
|
||||
Basic information about the vendor service
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -108,178 +73,142 @@ function VendorOverviewPageContent({
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">
|
||||
Does this vendor store production data?
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900">
|
||||
No
|
||||
</button>
|
||||
<button className="rounded-full bg-green-100 px-4 py-1 text-sm text-green-900">
|
||||
Yes
|
||||
</button>
|
||||
<Label className="text-sm">Service Start Date</Label>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600">
|
||||
{new Date(data.node?.serviceStartDate).toLocaleDateString()}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">
|
||||
Is the production data encrypted at rest?
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900">
|
||||
No
|
||||
</button>
|
||||
<button className="rounded-full bg-green-100 px-4 py-1 text-sm text-green-900">
|
||||
Yes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">
|
||||
Who has access to the production data?
|
||||
</Label>
|
||||
</div>
|
||||
{data.node?.serviceTerminationDate && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox id="vendor-staff" defaultChecked />
|
||||
<label
|
||||
htmlFor="vendor-staff"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Vendor Staff
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox id="third-parties" />
|
||||
<label
|
||||
htmlFor="third-parties"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Third Parties
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox id="automated-systems" />
|
||||
<label
|
||||
htmlFor="automated-systems"
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
>
|
||||
Automated Systems
|
||||
</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">Service Termination Date</Label>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600">
|
||||
{new Date(data.node?.serviceTerminationDate).toLocaleDateString()}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-lg font-medium">
|
||||
Vendor Reliability and Continuity
|
||||
</h2>
|
||||
<p className="text-sm text-gray-500">
|
||||
Evaluating the vendor's reliability and plans for business
|
||||
continuity.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">
|
||||
Does the vendor have an uptime commitment?
|
||||
</Label>
|
||||
</div>
|
||||
<RadioGroup defaultValue="greater" className="space-y-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="greater" id="greater" />
|
||||
<Label htmlFor="greater">Greater than 99.9% uptime</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="between" id="between" />
|
||||
<Label htmlFor="between">
|
||||
Between 99% and 99.9% uptime
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="less" id="less" />
|
||||
<Label htmlFor="less">Less than 99% uptime</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="na" id="na" />
|
||||
<Label htmlFor="na">Not applicable</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">
|
||||
Does the vendor have a disaster recovery plan?
|
||||
</Label>
|
||||
<Label className="text-sm">Service Criticality</Label>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900">
|
||||
No
|
||||
</button>
|
||||
<button className="rounded-full bg-green-100 px-4 py-1 text-sm text-green-900">
|
||||
Yes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">
|
||||
Impact of a Data Breach or Outage
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900">
|
||||
<button
|
||||
onClick={() => setSelectedCriticality('LOW')}
|
||||
className={cn(
|
||||
"rounded-full px-4 py-1 text-sm transition-colors",
|
||||
selectedCriticality === 'LOW'
|
||||
? "bg-green-100 text-green-900 ring-2 ring-green-600 ring-offset-2"
|
||||
: "bg-gray-100 text-gray-900 hover:bg-gray-200"
|
||||
)}
|
||||
>
|
||||
Low
|
||||
</button>
|
||||
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900">
|
||||
<button
|
||||
onClick={() => setSelectedCriticality('MEDIUM')}
|
||||
className={cn(
|
||||
"rounded-full px-4 py-1 text-sm transition-colors",
|
||||
selectedCriticality === 'MEDIUM'
|
||||
? "bg-yellow-100 text-yellow-900 ring-2 ring-yellow-600 ring-offset-2"
|
||||
: "bg-gray-100 text-gray-900 hover:bg-gray-200"
|
||||
)}
|
||||
>
|
||||
Medium
|
||||
</button>
|
||||
<button className="rounded-full bg-green-100 px-4 py-1 text-sm text-green-900">
|
||||
<button
|
||||
onClick={() => setSelectedCriticality('HIGH')}
|
||||
className={cn(
|
||||
"rounded-full px-4 py-1 text-sm transition-colors",
|
||||
selectedCriticality === 'HIGH'
|
||||
? "bg-red-100 text-red-900 ring-2 ring-red-600 ring-offset-2"
|
||||
: "bg-gray-100 text-gray-900 hover:bg-gray-200"
|
||||
)}
|
||||
>
|
||||
High
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500">
|
||||
{selectedCriticality === 'HIGH' &&
|
||||
"Critical service - downtime severely impacts end-users"}
|
||||
{selectedCriticality === 'MEDIUM' &&
|
||||
"Important service - downtime moderately affects end-users"}
|
||||
{selectedCriticality === 'LOW' &&
|
||||
"Non-critical service - minimal end-user impact if down"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h2 className="text-lg font-medium">Risk level</h2>
|
||||
<p className="text-sm text-gray-500">
|
||||
Based on the responses, the suggested risk level is medium.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900">
|
||||
Low
|
||||
</button>
|
||||
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900">
|
||||
Medium
|
||||
</button>
|
||||
<button className="rounded-full bg-green-100 px-4 py-1 text-sm text-green-900">
|
||||
High
|
||||
</button>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">Risk Tier</Label>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => setSelectedRiskTier('CRITICAL')}
|
||||
className={cn(
|
||||
"rounded-full px-4 py-1 text-sm transition-colors",
|
||||
selectedRiskTier === 'CRITICAL'
|
||||
? "bg-red-100 text-red-900 ring-2 ring-red-600 ring-offset-2"
|
||||
: "bg-gray-100 text-gray-900 hover:bg-gray-200"
|
||||
)}
|
||||
>
|
||||
Critical
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setSelectedRiskTier('SIGNIFICANT')}
|
||||
className={cn(
|
||||
"rounded-full px-4 py-1 text-sm transition-colors",
|
||||
selectedRiskTier === 'SIGNIFICANT'
|
||||
? "bg-yellow-100 text-yellow-900 ring-2 ring-yellow-600 ring-offset-2"
|
||||
: "bg-gray-100 text-gray-900 hover:bg-gray-200"
|
||||
)}
|
||||
>
|
||||
Significant
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setSelectedRiskTier('GENERAL')}
|
||||
className={cn(
|
||||
"rounded-full px-4 py-1 text-sm transition-colors",
|
||||
selectedRiskTier === 'GENERAL'
|
||||
? "bg-green-100 text-green-900 ring-2 ring-green-600 ring-offset-2"
|
||||
: "bg-gray-100 text-gray-900 hover:bg-gray-200"
|
||||
)}
|
||||
>
|
||||
General
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500">
|
||||
{selectedRiskTier === 'CRITICAL' &&
|
||||
"Handles sensitive data, critical for platform operation"}
|
||||
{selectedRiskTier === 'SIGNIFICANT' &&
|
||||
"No user data access, but important for platform management"}
|
||||
{selectedRiskTier === 'GENERAL' &&
|
||||
"General vendor with minimal risk"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{data.node?.statusPageUrl && (
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<HelpCircle className="h-4 w-4 text-gray-400" />
|
||||
<Label className="text-sm">Status Page</Label>
|
||||
</div>
|
||||
<a
|
||||
href={data.node.statusPageUrl}
|
||||
className="text-primary hover:underline inline-flex items-center gap-1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
View Status Page
|
||||
<ArrowUpRight className="h-4 w-4" />
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -296,7 +225,7 @@ function VendorOverviewPageFallback() {
|
||||
<div className="h-4 w-96 bg-muted animate-pulse rounded" />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{[1, 2, 3].map((i) => (
|
||||
{[1, 2].map((i) => (
|
||||
<div key={i} className="h-20 bg-muted animate-pulse rounded-lg" />
|
||||
))}
|
||||
</div>
|
||||
@@ -307,7 +236,7 @@ function VendorOverviewPageFallback() {
|
||||
export default function VendorOverviewPage() {
|
||||
const { vendorId } = useParams();
|
||||
const [queryRef, loadQuery] = useQueryLoader<VendorOverviewPageQueryType>(
|
||||
VendorOverviewPageQuery,
|
||||
vendorOverviewPageQuery,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<a9ec0002895dd62d2845ae4fd6df3a53>>
|
||||
* @generated SignedSource<<939b83dd396154844197ee10514be613>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -9,6 +9,8 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type RiskTier = "CRITICAL" | "GENERAL" | "SIGNIFICANT";
|
||||
export type ServiceCriticality = "HIGH" | "LOW" | "MEDIUM";
|
||||
export type VendorOverviewPageQuery$variables = {
|
||||
vendorId: string;
|
||||
};
|
||||
@@ -17,6 +19,11 @@ export type VendorOverviewPageQuery$data = {
|
||||
readonly createdAt?: any;
|
||||
readonly id?: string;
|
||||
readonly name?: string;
|
||||
readonly riskTier?: RiskTier;
|
||||
readonly serviceCriticality?: ServiceCriticality;
|
||||
readonly serviceStartDate?: any;
|
||||
readonly serviceTerminationDate?: any | null | undefined;
|
||||
readonly statusPageUrl?: string | null | undefined;
|
||||
readonly updatedAt?: any;
|
||||
};
|
||||
};
|
||||
@@ -58,10 +65,45 @@ v4 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "createdAt",
|
||||
"name": "serviceStartDate",
|
||||
"storageKey": null
|
||||
},
|
||||
v5 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "serviceTerminationDate",
|
||||
"storageKey": null
|
||||
},
|
||||
v6 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "serviceCriticality",
|
||||
"storageKey": null
|
||||
},
|
||||
v7 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "riskTier",
|
||||
"storageKey": null
|
||||
},
|
||||
v8 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "statusPageUrl",
|
||||
"storageKey": null
|
||||
},
|
||||
v9 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "createdAt",
|
||||
"storageKey": null
|
||||
},
|
||||
v10 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
@@ -89,7 +131,12 @@ return {
|
||||
(v2/*: any*/),
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
(v5/*: any*/)
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/),
|
||||
(v7/*: any*/),
|
||||
(v8/*: any*/),
|
||||
(v9/*: any*/),
|
||||
(v10/*: any*/)
|
||||
],
|
||||
"type": "Vendor",
|
||||
"abstractKey": null
|
||||
@@ -128,7 +175,12 @@ return {
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
(v5/*: any*/)
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/),
|
||||
(v7/*: any*/),
|
||||
(v8/*: any*/),
|
||||
(v9/*: any*/),
|
||||
(v10/*: any*/)
|
||||
],
|
||||
"type": "Vendor",
|
||||
"abstractKey": null
|
||||
@@ -139,16 +191,16 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "93086ca61d518fce9c6ed49fa9bd841e",
|
||||
"cacheID": "c9d7bade02d1802838f6ac3b02ef7c9a",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "VendorOverviewPageQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query VendorOverviewPageQuery(\n $vendorId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n createdAt\n updatedAt\n }\n id\n }\n}\n"
|
||||
"text": "query VendorOverviewPageQuery(\n $vendorId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n serviceStartDate\n serviceTerminationDate\n serviceCriticality\n riskTier\n statusPageUrl\n createdAt\n updatedAt\n }\n id\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "7959720cf1a6376d406ac5f478f6d9c3";
|
||||
(node as any).hash = "92a640f674261d28028d752f027ec141";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -117,6 +117,11 @@ type Vendor implements Node {
|
||||
name: String!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
serviceStartDate: Datetime!
|
||||
serviceTerminationDate: Datetime
|
||||
serviceCriticality: ServiceCriticality!
|
||||
riskTier: RiskTier!
|
||||
statusPageUrl: String
|
||||
}
|
||||
|
||||
type FrameworkConnection {
|
||||
@@ -328,4 +333,26 @@ input CreatePeopleInput {
|
||||
fullName: String!
|
||||
primaryEmailAddress: String!
|
||||
kind: PeopleKind!
|
||||
}
|
||||
|
||||
enum ServiceCriticality @goModel(model: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticality") {
|
||||
LOW @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticalityLow")
|
||||
MEDIUM @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticalityMedium")
|
||||
HIGH @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticalityHigh")
|
||||
}
|
||||
|
||||
enum RiskTier @goModel(model: "github.com/getprobo/probo/pkg/probo/coredata.RiskTier") {
|
||||
CRITICAL @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.RiskTierCritical")
|
||||
SIGNIFICANT @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.RiskTierSignificant")
|
||||
GENERAL @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.RiskTierGeneral")
|
||||
}
|
||||
|
||||
input UpdateVendorInput {
|
||||
id: ID!
|
||||
name: String
|
||||
serviceStartDate: Datetime
|
||||
serviceTerminationDate: Datetime
|
||||
serviceCriticality: ServiceCriticality
|
||||
riskTier: RiskTier
|
||||
statusPageUrl: String
|
||||
}
|
||||
@@ -245,10 +245,15 @@ type ComplexityRoot struct {
|
||||
}
|
||||
|
||||
Vendor struct {
|
||||
CreatedAt func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
Name func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
CreatedAt func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
Name func(childComplexity int) int
|
||||
RiskTier func(childComplexity int) int
|
||||
ServiceCriticality func(childComplexity int) int
|
||||
ServiceStartDate func(childComplexity int) int
|
||||
ServiceTerminationDate func(childComplexity int) int
|
||||
StatusPageURL func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
}
|
||||
|
||||
VendorConnection struct {
|
||||
@@ -1136,6 +1141,41 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||
|
||||
return e.complexity.Vendor.Name(childComplexity), true
|
||||
|
||||
case "Vendor.riskTier":
|
||||
if e.complexity.Vendor.RiskTier == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Vendor.RiskTier(childComplexity), true
|
||||
|
||||
case "Vendor.serviceCriticality":
|
||||
if e.complexity.Vendor.ServiceCriticality == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Vendor.ServiceCriticality(childComplexity), true
|
||||
|
||||
case "Vendor.serviceStartDate":
|
||||
if e.complexity.Vendor.ServiceStartDate == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Vendor.ServiceStartDate(childComplexity), true
|
||||
|
||||
case "Vendor.serviceTerminationDate":
|
||||
if e.complexity.Vendor.ServiceTerminationDate == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Vendor.ServiceTerminationDate(childComplexity), true
|
||||
|
||||
case "Vendor.statusPageUrl":
|
||||
if e.complexity.Vendor.StatusPageURL == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.Vendor.StatusPageURL(childComplexity), true
|
||||
|
||||
case "Vendor.updatedAt":
|
||||
if e.complexity.Vendor.UpdatedAt == nil {
|
||||
break
|
||||
@@ -1183,6 +1223,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
ec.unmarshalInputCreateVendorInput,
|
||||
ec.unmarshalInputDeletePeopleInput,
|
||||
ec.unmarshalInputDeleteVendorInput,
|
||||
ec.unmarshalInputUpdateVendorInput,
|
||||
)
|
||||
first := true
|
||||
|
||||
@@ -1399,6 +1440,11 @@ type Vendor implements Node {
|
||||
name: String!
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
serviceStartDate: Datetime!
|
||||
serviceTerminationDate: Datetime
|
||||
serviceCriticality: ServiceCriticality!
|
||||
riskTier: RiskTier!
|
||||
statusPageUrl: String
|
||||
}
|
||||
|
||||
type FrameworkConnection {
|
||||
@@ -1610,6 +1656,28 @@ input CreatePeopleInput {
|
||||
fullName: String!
|
||||
primaryEmailAddress: String!
|
||||
kind: PeopleKind!
|
||||
}
|
||||
|
||||
enum ServiceCriticality @goModel(model: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticality") {
|
||||
LOW @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticalityLow")
|
||||
MEDIUM @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticalityMedium")
|
||||
HIGH @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.ServiceCriticalityHigh")
|
||||
}
|
||||
|
||||
enum RiskTier @goModel(model: "github.com/getprobo/probo/pkg/probo/coredata.RiskTier") {
|
||||
CRITICAL @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.RiskTierCritical")
|
||||
SIGNIFICANT @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.RiskTierSignificant")
|
||||
GENERAL @goEnum(value: "github.com/getprobo/probo/pkg/probo/coredata.RiskTierGeneral")
|
||||
}
|
||||
|
||||
input UpdateVendorInput {
|
||||
id: ID!
|
||||
name: String
|
||||
serviceStartDate: Datetime
|
||||
serviceTerminationDate: Datetime
|
||||
serviceCriticality: ServiceCriticality
|
||||
riskTier: RiskTier
|
||||
statusPageUrl: String
|
||||
}`, BuiltIn: false},
|
||||
}
|
||||
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||
@@ -4826,6 +4894,16 @@ func (ec *executionContext) fieldContext_Mutation_createVendor(ctx context.Conte
|
||||
return ec.fieldContext_Vendor_createdAt(ctx, field)
|
||||
case "updatedAt":
|
||||
return ec.fieldContext_Vendor_updatedAt(ctx, field)
|
||||
case "serviceStartDate":
|
||||
return ec.fieldContext_Vendor_serviceStartDate(ctx, field)
|
||||
case "serviceTerminationDate":
|
||||
return ec.fieldContext_Vendor_serviceTerminationDate(ctx, field)
|
||||
case "serviceCriticality":
|
||||
return ec.fieldContext_Vendor_serviceCriticality(ctx, field)
|
||||
case "riskTier":
|
||||
return ec.fieldContext_Vendor_riskTier(ctx, field)
|
||||
case "statusPageUrl":
|
||||
return ec.fieldContext_Vendor_statusPageUrl(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type Vendor", field.Name)
|
||||
},
|
||||
@@ -7138,6 +7216,190 @@ func (ec *executionContext) fieldContext_Vendor_updatedAt(_ context.Context, fie
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Vendor_serviceStartDate(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Vendor_serviceStartDate(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.ServiceStartDate, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(time.Time)
|
||||
fc.Result = res
|
||||
return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Vendor_serviceStartDate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Vendor",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Datetime does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Vendor_serviceTerminationDate(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Vendor_serviceTerminationDate(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.ServiceTerminationDate, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*time.Time)
|
||||
fc.Result = res
|
||||
return ec.marshalODatetime2ᚖtimeᚐTime(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Vendor_serviceTerminationDate(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Vendor",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Datetime does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Vendor_serviceCriticality(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Vendor_serviceCriticality(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.ServiceCriticality, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(coredata.ServiceCriticality)
|
||||
fc.Result = res
|
||||
return ec.marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Vendor_serviceCriticality(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Vendor",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type ServiceCriticality does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Vendor_riskTier(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Vendor_riskTier(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.RiskTier, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(coredata.RiskTier)
|
||||
fc.Result = res
|
||||
return ec.marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Vendor_riskTier(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Vendor",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type RiskTier does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Vendor_statusPageUrl(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Vendor_statusPageUrl(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.StatusPageURL, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*string)
|
||||
fc.Result = res
|
||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Vendor_statusPageUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Vendor",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _VendorConnection_edges(ctx context.Context, field graphql.CollectedField, obj *types.VendorConnection) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_VendorConnection_edges(ctx, field)
|
||||
if err != nil {
|
||||
@@ -7309,6 +7571,16 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel
|
||||
return ec.fieldContext_Vendor_createdAt(ctx, field)
|
||||
case "updatedAt":
|
||||
return ec.fieldContext_Vendor_updatedAt(ctx, field)
|
||||
case "serviceStartDate":
|
||||
return ec.fieldContext_Vendor_serviceStartDate(ctx, field)
|
||||
case "serviceTerminationDate":
|
||||
return ec.fieldContext_Vendor_serviceTerminationDate(ctx, field)
|
||||
case "serviceCriticality":
|
||||
return ec.fieldContext_Vendor_serviceCriticality(ctx, field)
|
||||
case "riskTier":
|
||||
return ec.fieldContext_Vendor_riskTier(ctx, field)
|
||||
case "statusPageUrl":
|
||||
return ec.fieldContext_Vendor_statusPageUrl(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type Vendor", field.Name)
|
||||
},
|
||||
@@ -9003,6 +9275,75 @@ func (ec *executionContext) unmarshalInputDeleteVendorInput(ctx context.Context,
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, obj any) (types.UpdateVendorInput, error) {
|
||||
var it types.UpdateVendorInput
|
||||
asMap := map[string]any{}
|
||||
for k, v := range obj.(map[string]any) {
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"id", "name", "serviceStartDate", "serviceTerminationDate", "serviceCriticality", "riskTier", "statusPageUrl"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch k {
|
||||
case "id":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
|
||||
data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.ID = data
|
||||
case "name":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Name = data
|
||||
case "serviceStartDate":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceStartDate"))
|
||||
data, err := ec.unmarshalODatetime2ᚖtimeᚐTime(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.ServiceStartDate = data
|
||||
case "serviceTerminationDate":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceTerminationDate"))
|
||||
data, err := ec.unmarshalODatetime2ᚖtimeᚐTime(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.ServiceTerminationDate = data
|
||||
case "serviceCriticality":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceCriticality"))
|
||||
data, err := ec.unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.ServiceCriticality = data
|
||||
case "riskTier":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("riskTier"))
|
||||
data, err := ec.unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.RiskTier = data
|
||||
case "statusPageUrl":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("statusPageUrl"))
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.StatusPageURL = data
|
||||
}
|
||||
}
|
||||
|
||||
return it, nil
|
||||
}
|
||||
|
||||
// endregion **************************** input.gotpl *****************************
|
||||
|
||||
// region ************************** interface.gotpl ***************************
|
||||
@@ -10831,6 +11172,25 @@ func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, o
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "serviceStartDate":
|
||||
out.Values[i] = ec._Vendor_serviceStartDate(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "serviceTerminationDate":
|
||||
out.Values[i] = ec._Vendor_serviceTerminationDate(ctx, field, obj)
|
||||
case "serviceCriticality":
|
||||
out.Values[i] = ec._Vendor_serviceCriticality(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "riskTier":
|
||||
out.Values[i] = ec._Vendor_riskTier(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "statusPageUrl":
|
||||
out.Values[i] = ec._Vendor_statusPageUrl(ctx, field, obj)
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
@@ -11906,6 +12266,64 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func (ec *executionContext) unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx context.Context, v any) (coredata.RiskTier, error) {
|
||||
tmp, err := graphql.UnmarshalString(v)
|
||||
res := unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier[tmp]
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx context.Context, sel ast.SelectionSet, v coredata.RiskTier) graphql.Marshaler {
|
||||
res := graphql.MarshalString(marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier[v])
|
||||
if res == graphql.Null {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
var (
|
||||
unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier = map[string]coredata.RiskTier{
|
||||
"CRITICAL": coredata.RiskTierCritical,
|
||||
"SIGNIFICANT": coredata.RiskTierSignificant,
|
||||
"GENERAL": coredata.RiskTierGeneral,
|
||||
}
|
||||
marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier = map[coredata.RiskTier]string{
|
||||
coredata.RiskTierCritical: "CRITICAL",
|
||||
coredata.RiskTierSignificant: "SIGNIFICANT",
|
||||
coredata.RiskTierGeneral: "GENERAL",
|
||||
}
|
||||
)
|
||||
|
||||
func (ec *executionContext) unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx context.Context, v any) (coredata.ServiceCriticality, error) {
|
||||
tmp, err := graphql.UnmarshalString(v)
|
||||
res := unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality[tmp]
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx context.Context, sel ast.SelectionSet, v coredata.ServiceCriticality) graphql.Marshaler {
|
||||
res := graphql.MarshalString(marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality[v])
|
||||
if res == graphql.Null {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
var (
|
||||
unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality = map[string]coredata.ServiceCriticality{
|
||||
"LOW": coredata.ServiceCriticalityLow,
|
||||
"MEDIUM": coredata.ServiceCriticalityMedium,
|
||||
"HIGH": coredata.ServiceCriticalityHigh,
|
||||
}
|
||||
marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality = map[coredata.ServiceCriticality]string{
|
||||
coredata.ServiceCriticalityLow: "LOW",
|
||||
coredata.ServiceCriticalityMedium: "MEDIUM",
|
||||
coredata.ServiceCriticalityHigh: "HIGH",
|
||||
}
|
||||
)
|
||||
|
||||
func (ec *executionContext) unmarshalNString2string(ctx context.Context, v any) (string, error) {
|
||||
res, err := graphql.UnmarshalString(v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
@@ -12518,6 +12936,22 @@ func (ec *executionContext) marshalOCursorKey2ᚖgithubᚗcomᚋgetproboᚋprobo
|
||||
return res
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalODatetime2ᚖtimeᚐTime(ctx context.Context, v any) (*time.Time, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
res, err := graphql.UnmarshalTime(v)
|
||||
return &res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalODatetime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := graphql.MarshalTime(*v)
|
||||
return res
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalOEvidenceState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐEvidenceState(ctx context.Context, v any) (*coredata.EvidenceState, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
@@ -12564,6 +12998,66 @@ func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.Sele
|
||||
return res
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx context.Context, v any) (*coredata.RiskTier, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
tmp, err := graphql.UnmarshalString(v)
|
||||
res := unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier[tmp]
|
||||
return &res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier(ctx context.Context, sel ast.SelectionSet, v *coredata.RiskTier) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := graphql.MarshalString(marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier[*v])
|
||||
return res
|
||||
}
|
||||
|
||||
var (
|
||||
unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier = map[string]coredata.RiskTier{
|
||||
"CRITICAL": coredata.RiskTierCritical,
|
||||
"SIGNIFICANT": coredata.RiskTierSignificant,
|
||||
"GENERAL": coredata.RiskTierGeneral,
|
||||
}
|
||||
marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐRiskTier = map[coredata.RiskTier]string{
|
||||
coredata.RiskTierCritical: "CRITICAL",
|
||||
coredata.RiskTierSignificant: "SIGNIFICANT",
|
||||
coredata.RiskTierGeneral: "GENERAL",
|
||||
}
|
||||
)
|
||||
|
||||
func (ec *executionContext) unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx context.Context, v any) (*coredata.ServiceCriticality, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
tmp, err := graphql.UnmarshalString(v)
|
||||
res := unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality[tmp]
|
||||
return &res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality(ctx context.Context, sel ast.SelectionSet, v *coredata.ServiceCriticality) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := graphql.MarshalString(marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality[*v])
|
||||
return res
|
||||
}
|
||||
|
||||
var (
|
||||
unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality = map[string]coredata.ServiceCriticality{
|
||||
"LOW": coredata.ServiceCriticalityLow,
|
||||
"MEDIUM": coredata.ServiceCriticalityMedium,
|
||||
"HIGH": coredata.ServiceCriticalityHigh,
|
||||
}
|
||||
marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐServiceCriticality = map[coredata.ServiceCriticality]string{
|
||||
coredata.ServiceCriticalityLow: "LOW",
|
||||
coredata.ServiceCriticalityMedium: "MEDIUM",
|
||||
coredata.ServiceCriticalityHigh: "HIGH",
|
||||
}
|
||||
)
|
||||
|
||||
func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
|
||||
@@ -237,11 +237,26 @@ type TaskStateTransitionEdge struct {
|
||||
Node *TaskStateTransition `json:"node"`
|
||||
}
|
||||
|
||||
type UpdateVendorInput struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
ServiceStartDate *time.Time `json:"serviceStartDate,omitempty"`
|
||||
ServiceTerminationDate *time.Time `json:"serviceTerminationDate,omitempty"`
|
||||
ServiceCriticality *coredata.ServiceCriticality `json:"serviceCriticality,omitempty"`
|
||||
RiskTier *coredata.RiskTier `json:"riskTier,omitempty"`
|
||||
StatusPageURL *string `json:"statusPageUrl,omitempty"`
|
||||
}
|
||||
|
||||
type Vendor struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
ID gid.GID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
ServiceStartDate time.Time `json:"serviceStartDate"`
|
||||
ServiceTerminationDate *time.Time `json:"serviceTerminationDate,omitempty"`
|
||||
ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"`
|
||||
RiskTier coredata.RiskTier `json:"riskTier"`
|
||||
StatusPageURL *string `json:"statusPageUrl,omitempty"`
|
||||
}
|
||||
|
||||
func (Vendor) IsNode() {}
|
||||
|
||||
@@ -41,9 +41,14 @@ func NewVendorEdge(v *coredata.Vendor) *VendorEdge {
|
||||
|
||||
func NewVendor(v *coredata.Vendor) *Vendor {
|
||||
return &Vendor{
|
||||
ID: v.ID,
|
||||
Name: v.Name,
|
||||
CreatedAt: v.CreatedAt,
|
||||
UpdatedAt: v.UpdatedAt,
|
||||
ID: v.ID,
|
||||
Name: v.Name,
|
||||
CreatedAt: v.CreatedAt,
|
||||
UpdatedAt: v.UpdatedAt,
|
||||
ServiceStartDate: v.ServiceStartDate,
|
||||
ServiceTerminationDate: v.ServiceTerminationDate,
|
||||
ServiceCriticality: v.ServiceCriticality,
|
||||
RiskTier: v.RiskTier,
|
||||
StatusPageURL: v.StatusPageURL,
|
||||
}
|
||||
}
|
||||
|
||||
15
pkg/probo/coredata/migrations/20250218T101900Z.sql
Normal file
15
pkg/probo/coredata/migrations/20250218T101900Z.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
CREATE TYPE service_criticality AS ENUM ('LOW', 'MEDIUM', 'HIGH');
|
||||
CREATE TYPE risk_tier AS ENUM ('CRITICAL', 'SIGNIFICANT', 'GENERAL');
|
||||
|
||||
ALTER TABLE vendors
|
||||
ADD COLUMN service_start_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
|
||||
ADD COLUMN service_termination_date TIMESTAMP WITH TIME ZONE,
|
||||
ADD COLUMN service_criticality service_criticality NOT NULL DEFAULT 'LOW',
|
||||
ADD COLUMN risk_tier risk_tier NOT NULL DEFAULT 'GENERAL',
|
||||
ADD COLUMN status_page_url TEXT;
|
||||
|
||||
UPDATE vendors SET service_start_date = created_at;
|
||||
|
||||
ALTER TABLE vendors ALTER COLUMN service_start_date DROP DEFAULT;
|
||||
ALTER TABLE vendors ALTER COLUMN service_criticality DROP DEFAULT;
|
||||
ALTER TABLE vendors ALTER COLUMN risk_tier DROP DEFAULT;
|
||||
66
pkg/probo/coredata/risk_tier.go
Normal file
66
pkg/probo/coredata/risk_tier.go
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2025 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.
|
||||
|
||||
package coredata
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type RiskTier string
|
||||
|
||||
const (
|
||||
RiskTierCritical RiskTier = "CRITICAL" // Handles sensitive data, critical for platform operation
|
||||
RiskTierSignificant RiskTier = "SIGNIFICANT" // No user data access, but important for platform management
|
||||
RiskTierGeneral RiskTier = "GENERAL" // General vendor with minimal risk
|
||||
)
|
||||
|
||||
func (rt RiskTier) MarshalText() ([]byte, error) {
|
||||
return []byte(rt.String()), nil
|
||||
}
|
||||
|
||||
func (rt *RiskTier) UnmarshalText(data []byte) error {
|
||||
val := string(data)
|
||||
|
||||
switch val {
|
||||
case RiskTierCritical.String():
|
||||
*rt = RiskTierCritical
|
||||
case RiskTierSignificant.String():
|
||||
*rt = RiskTierSignificant
|
||||
case RiskTierGeneral.String():
|
||||
*rt = RiskTierGeneral
|
||||
default:
|
||||
return fmt.Errorf("invalid RiskTier value: %q", val)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rt RiskTier) String() string {
|
||||
return string(rt)
|
||||
}
|
||||
|
||||
func (rt *RiskTier) Scan(value any) error {
|
||||
val, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid scan source for RiskTier, expected string got %T", value)
|
||||
}
|
||||
|
||||
return rt.UnmarshalText([]byte(val))
|
||||
}
|
||||
|
||||
func (rt RiskTier) Value() (driver.Value, error) {
|
||||
return rt.String(), nil
|
||||
}
|
||||
66
pkg/probo/coredata/service_criticality.go
Normal file
66
pkg/probo/coredata/service_criticality.go
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2025 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.
|
||||
|
||||
package coredata
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ServiceCriticality string
|
||||
|
||||
const (
|
||||
ServiceCriticalityLow ServiceCriticality = "LOW"
|
||||
ServiceCriticalityMedium ServiceCriticality = "MEDIUM"
|
||||
ServiceCriticalityHigh ServiceCriticality = "HIGH"
|
||||
)
|
||||
|
||||
func (sc ServiceCriticality) MarshalText() ([]byte, error) {
|
||||
return []byte(sc.String()), nil
|
||||
}
|
||||
|
||||
func (sc *ServiceCriticality) UnmarshalText(data []byte) error {
|
||||
val := string(data)
|
||||
|
||||
switch val {
|
||||
case ServiceCriticalityLow.String():
|
||||
*sc = ServiceCriticalityLow
|
||||
case ServiceCriticalityMedium.String():
|
||||
*sc = ServiceCriticalityMedium
|
||||
case ServiceCriticalityHigh.String():
|
||||
*sc = ServiceCriticalityHigh
|
||||
default:
|
||||
return fmt.Errorf("invalid ServiceCriticality value: %q", val)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sc ServiceCriticality) String() string {
|
||||
return string(sc)
|
||||
}
|
||||
|
||||
func (sc *ServiceCriticality) Scan(value any) error {
|
||||
val, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid scan source for ServiceCriticality, expected string got %T", value)
|
||||
}
|
||||
|
||||
return sc.UnmarshalText([]byte(val))
|
||||
}
|
||||
|
||||
func (sc ServiceCriticality) Value() (driver.Value, error) {
|
||||
return sc.String(), nil
|
||||
}
|
||||
@@ -28,11 +28,16 @@ import (
|
||||
|
||||
type (
|
||||
Vendor struct {
|
||||
ID gid.GID
|
||||
OrganizationID gid.GID
|
||||
Name string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
ID gid.GID
|
||||
OrganizationID gid.GID
|
||||
Name string
|
||||
ServiceStartDate time.Time
|
||||
ServiceTerminationDate *time.Time
|
||||
ServiceCriticality ServiceCriticality
|
||||
RiskTier RiskTier
|
||||
StatusPageURL *string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
Vendors []*Vendor
|
||||
@@ -47,6 +52,11 @@ func (v *Vendor) scan(r pgx.Row) error {
|
||||
&v.ID,
|
||||
&v.OrganizationID,
|
||||
&v.Name,
|
||||
&v.ServiceStartDate,
|
||||
&v.ServiceTerminationDate,
|
||||
&v.ServiceCriticality,
|
||||
&v.RiskTier,
|
||||
&v.StatusPageURL,
|
||||
&v.CreatedAt,
|
||||
&v.UpdatedAt,
|
||||
)
|
||||
@@ -63,6 +73,11 @@ SELECT
|
||||
id,
|
||||
organization_id,
|
||||
name,
|
||||
service_start_date,
|
||||
service_termination_date,
|
||||
service_criticality,
|
||||
risk_tier,
|
||||
status_page_url,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
@@ -100,6 +115,11 @@ INSERT INTO
|
||||
id,
|
||||
organization_id,
|
||||
name,
|
||||
service_start_date,
|
||||
service_termination_date,
|
||||
service_criticality,
|
||||
risk_tier,
|
||||
status_page_url,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
@@ -107,17 +127,27 @@ VALUES (
|
||||
@vendor_id,
|
||||
@organization_id,
|
||||
@name,
|
||||
@service_start_date,
|
||||
@service_termination_date,
|
||||
@service_criticality,
|
||||
@risk_tier,
|
||||
@status_page_url,
|
||||
@created_at,
|
||||
@updated_at
|
||||
)
|
||||
`
|
||||
|
||||
args := pgx.NamedArgs{
|
||||
"vendor_id": v.ID,
|
||||
"organization_id": v.OrganizationID,
|
||||
"name": v.Name,
|
||||
"created_at": v.CreatedAt,
|
||||
"updated_at": v.UpdatedAt,
|
||||
"vendor_id": v.ID,
|
||||
"organization_id": v.OrganizationID,
|
||||
"name": v.Name,
|
||||
"service_start_date": v.ServiceStartDate,
|
||||
"service_termination_date": v.ServiceTerminationDate,
|
||||
"service_criticality": v.ServiceCriticality,
|
||||
"risk_tier": v.RiskTier,
|
||||
"status_page_url": v.StatusPageURL,
|
||||
"created_at": v.CreatedAt,
|
||||
"updated_at": v.UpdatedAt,
|
||||
}
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
@@ -153,6 +183,11 @@ SELECT
|
||||
id,
|
||||
organization_id,
|
||||
name,
|
||||
service_start_date,
|
||||
service_termination_date,
|
||||
service_criticality,
|
||||
risk_tier,
|
||||
status_page_url,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
@@ -167,7 +202,7 @@ WHERE
|
||||
|
||||
args := pgx.NamedArgs{"organization_id": organizationID}
|
||||
maps.Copy(args, cursor.SQLArguments())
|
||||
maps.Copy(args, cursor.SQLArguments())
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
r, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user