Add risk tier, criticality on vendors

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-02-18 11:14:20 +01:00
parent 53bceb5479
commit 6da223ed36
10 changed files with 940 additions and 236 deletions

View File

@@ -1,29 +1,32 @@
"use client"; "use client";
import { useState } from "react";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { HelpCircle, ArrowUpRight } from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import { HelpCircle } from "lucide-react";
import { import {
graphql, graphql,
PreloadedQuery, PreloadedQuery,
usePreloadedQuery, usePreloadedQuery,
useQueryLoader, useQueryLoader,
} from "react-relay"; } from "react-relay";
import { Suspense, useEffect } from "react"; import { Suspense, useEffect, useState } from "react";
import type { VendorOverviewPageQuery as VendorOverviewPageQueryType } from "./__generated__/VendorOverviewPageQuery.graphql"; import type { VendorOverviewPageQuery as VendorOverviewPageQueryType } from "./__generated__/VendorOverviewPageQuery.graphql";
import { useParams } from "react-router"; import { useParams } from "react-router";
import { Helmet } from "react-helmet-async"; import { Helmet } from "react-helmet-async";
import { useBreadcrumb } from "@/contexts/BreadcrumbContext"; import { useBreadcrumb } from "@/contexts/BreadcrumbContext";
import { cn } from "@/lib/utils";
const VendorOverviewPageQuery = graphql` const vendorOverviewPageQuery = graphql`
query VendorOverviewPageQuery($vendorId: ID!) { query VendorOverviewPageQuery($vendorId: ID!) {
node(id: $vendorId) { node(id: $vendorId) {
... on Vendor { ... on Vendor {
id id
name name
serviceStartDate
serviceTerminationDate
serviceCriticality
riskTier
statusPageUrl
createdAt createdAt
updatedAt updatedAt
} }
@@ -36,9 +39,10 @@ function VendorOverviewPageContent({
}: { }: {
queryRef: PreloadedQuery<VendorOverviewPageQueryType>; queryRef: PreloadedQuery<VendorOverviewPageQueryType>;
}) { }) {
const data = usePreloadedQuery(VendorOverviewPageQuery, queryRef); const data = usePreloadedQuery(vendorOverviewPageQuery, queryRef);
const [riskLevel, setRiskLevel] = useState("medium");
const { setBreadcrumbSegment } = useBreadcrumb(); const { setBreadcrumbSegment } = useBreadcrumb();
const [selectedCriticality, setSelectedCriticality] = useState(data.node.serviceCriticality);
const [selectedRiskTier, setSelectedRiskTier] = useState(data.node.riskTier);
useEffect(() => { useEffect(() => {
if (data.node?.name) { 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="space-y-6 p-4 md:p-6 lg:p-8">
<div className="mx-auto max-w-4xl space-y-6"> <div className="mx-auto max-w-4xl space-y-6">
<div className="space-y-2"> <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"> <h1 className="text-xl font-semibold text-gray-900">
{data.node?.name} {data.node?.name}
</h1> </h1>
</div> <p className="text-gray-600">View and manage vendor details</p>
<p className="text-gray-600">
Use this form to assess the risk of using Google Workspace as a
vendor.
</p>
</div> </div>
<Card className="p-6"> <Card className="p-6">
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-2"> <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"> <p className="text-sm text-gray-500">
Questions related to the type of assets stored by the vendor. Basic information about the vendor service
</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.
</p> </p>
</div> </div>
@@ -108,179 +73,143 @@ function VendorOverviewPageContent({
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<HelpCircle className="h-4 w-4 text-gray-400" /> <HelpCircle className="h-4 w-4 text-gray-400" />
<Label className="text-sm"> <Label className="text-sm">Service Start Date</Label>
Does this vendor store production data?
</Label>
</div> </div>
<div className="flex gap-2"> <p className="text-sm text-gray-600">
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900"> {new Date(data.node?.serviceStartDate).toLocaleDateString()}
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">
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>
<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>
</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> </p>
</div> </div>
<div className="space-y-4"> {data.node?.serviceTerminationDate && (
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<HelpCircle className="h-4 w-4 text-gray-400" /> <HelpCircle className="h-4 w-4 text-gray-400" />
<Label className="text-sm"> <Label className="text-sm">Service Termination Date</Label>
Does the vendor have an uptime commitment?
</Label>
</div> </div>
<RadioGroup defaultValue="greater" className="space-y-2"> <p className="text-sm text-gray-600">
<div className="flex items-center space-x-2"> {new Date(data.node?.serviceTerminationDate).toLocaleDateString()}
<RadioGroupItem value="greater" id="greater" /> </p>
<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>
)}
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<HelpCircle className="h-4 w-4 text-gray-400" /> <HelpCircle className="h-4 w-4 text-gray-400" />
<Label className="text-sm"> <Label className="text-sm">Service Criticality</Label>
Does the vendor have a disaster recovery plan?
</Label>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900"> <button
No onClick={() => setSelectedCriticality('LOW')}
</button> className={cn(
<button className="rounded-full bg-green-100 px-4 py-1 text-sm text-green-900"> "rounded-full px-4 py-1 text-sm transition-colors",
Yes selectedCriticality === 'LOW'
</button> ? "bg-green-100 text-green-900 ring-2 ring-green-600 ring-offset-2"
</div> : "bg-gray-100 text-gray-900 hover:bg-gray-200"
</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">
Low Low
</button> </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 Medium
</button> </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 High
</button> </button>
</div> </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">Risk level</h2>
<p className="text-sm text-gray-500"> <p className="text-sm text-gray-500">
Based on the responses, the suggested risk level is medium. {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> </p>
</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">Risk Tier</Label>
</div>
<div className="flex gap-2"> <div className="flex gap-2">
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900"> <button
Low 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>
<button className="rounded-full bg-gray-100 px-4 py-1 text-sm text-gray-900"> <button
Medium 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>
<button className="rounded-full bg-green-100 px-4 py-1 text-sm text-green-900"> <button
High 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> </button>
</div> </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> </div>
</Card> </Card>
</div> </div>
@@ -296,7 +225,7 @@ function VendorOverviewPageFallback() {
<div className="h-4 w-96 bg-muted animate-pulse rounded" /> <div className="h-4 w-96 bg-muted animate-pulse rounded" />
</div> </div>
<div className="space-y-2"> <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 key={i} className="h-20 bg-muted animate-pulse rounded-lg" />
))} ))}
</div> </div>
@@ -307,7 +236,7 @@ function VendorOverviewPageFallback() {
export default function VendorOverviewPage() { export default function VendorOverviewPage() {
const { vendorId } = useParams(); const { vendorId } = useParams();
const [queryRef, loadQuery] = useQueryLoader<VendorOverviewPageQueryType>( const [queryRef, loadQuery] = useQueryLoader<VendorOverviewPageQueryType>(
VendorOverviewPageQuery, vendorOverviewPageQuery,
); );
useEffect(() => { useEffect(() => {

View File

@@ -1,5 +1,5 @@
/** /**
* @generated SignedSource<<a9ec0002895dd62d2845ae4fd6df3a53>> * @generated SignedSource<<939b83dd396154844197ee10514be613>>
* @lightSyntaxTransform * @lightSyntaxTransform
* @nogrep * @nogrep
*/ */
@@ -9,6 +9,8 @@
// @ts-nocheck // @ts-nocheck
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
export type RiskTier = "CRITICAL" | "GENERAL" | "SIGNIFICANT";
export type ServiceCriticality = "HIGH" | "LOW" | "MEDIUM";
export type VendorOverviewPageQuery$variables = { export type VendorOverviewPageQuery$variables = {
vendorId: string; vendorId: string;
}; };
@@ -17,6 +19,11 @@ export type VendorOverviewPageQuery$data = {
readonly createdAt?: any; readonly createdAt?: any;
readonly id?: string; readonly id?: string;
readonly name?: 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; readonly updatedAt?: any;
}; };
}; };
@@ -58,10 +65,45 @@ v4 = {
"alias": null, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
"name": "createdAt", "name": "serviceStartDate",
"storageKey": null "storageKey": null
}, },
v5 = { 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, "alias": null,
"args": null, "args": null,
"kind": "ScalarField", "kind": "ScalarField",
@@ -89,7 +131,12 @@ return {
(v2/*: any*/), (v2/*: any*/),
(v3/*: any*/), (v3/*: any*/),
(v4/*: any*/), (v4/*: any*/),
(v5/*: any*/) (v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/)
], ],
"type": "Vendor", "type": "Vendor",
"abstractKey": null "abstractKey": null
@@ -128,7 +175,12 @@ return {
"selections": [ "selections": [
(v3/*: any*/), (v3/*: any*/),
(v4/*: any*/), (v4/*: any*/),
(v5/*: any*/) (v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/)
], ],
"type": "Vendor", "type": "Vendor",
"abstractKey": null "abstractKey": null
@@ -139,16 +191,16 @@ return {
] ]
}, },
"params": { "params": {
"cacheID": "93086ca61d518fce9c6ed49fa9bd841e", "cacheID": "c9d7bade02d1802838f6ac3b02ef7c9a",
"id": null, "id": null,
"metadata": {}, "metadata": {},
"name": "VendorOverviewPageQuery", "name": "VendorOverviewPageQuery",
"operationKind": "query", "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; export default node;

View File

@@ -117,6 +117,11 @@ type Vendor implements Node {
name: String! name: String!
createdAt: Datetime! createdAt: Datetime!
updatedAt: Datetime! updatedAt: Datetime!
serviceStartDate: Datetime!
serviceTerminationDate: Datetime
serviceCriticality: ServiceCriticality!
riskTier: RiskTier!
statusPageUrl: String
} }
type FrameworkConnection { type FrameworkConnection {
@@ -329,3 +334,25 @@ input CreatePeopleInput {
primaryEmailAddress: String! primaryEmailAddress: String!
kind: PeopleKind! 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
}

View File

@@ -248,6 +248,11 @@ type ComplexityRoot struct {
CreatedAt func(childComplexity int) int CreatedAt func(childComplexity int) int
ID func(childComplexity int) int ID func(childComplexity int) int
Name 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 UpdatedAt func(childComplexity int) int
} }
@@ -1136,6 +1141,41 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Vendor.Name(childComplexity), true 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": case "Vendor.updatedAt":
if e.complexity.Vendor.UpdatedAt == nil { if e.complexity.Vendor.UpdatedAt == nil {
break break
@@ -1183,6 +1223,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputCreateVendorInput, ec.unmarshalInputCreateVendorInput,
ec.unmarshalInputDeletePeopleInput, ec.unmarshalInputDeletePeopleInput,
ec.unmarshalInputDeleteVendorInput, ec.unmarshalInputDeleteVendorInput,
ec.unmarshalInputUpdateVendorInput,
) )
first := true first := true
@@ -1399,6 +1440,11 @@ type Vendor implements Node {
name: String! name: String!
createdAt: Datetime! createdAt: Datetime!
updatedAt: Datetime! updatedAt: Datetime!
serviceStartDate: Datetime!
serviceTerminationDate: Datetime
serviceCriticality: ServiceCriticality!
riskTier: RiskTier!
statusPageUrl: String
} }
type FrameworkConnection { type FrameworkConnection {
@@ -1610,6 +1656,28 @@ input CreatePeopleInput {
fullName: String! fullName: String!
primaryEmailAddress: String! primaryEmailAddress: String!
kind: PeopleKind! 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}, }`, BuiltIn: false},
} }
var parsedSchema = gqlparser.MustLoadSchema(sources...) 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) return ec.fieldContext_Vendor_createdAt(ctx, field)
case "updatedAt": case "updatedAt":
return ec.fieldContext_Vendor_updatedAt(ctx, field) 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) 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 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) { 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) fc, err := ec.fieldContext_VendorConnection_edges(ctx, field)
if err != nil { if err != nil {
@@ -7309,6 +7571,16 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel
return ec.fieldContext_Vendor_createdAt(ctx, field) return ec.fieldContext_Vendor_createdAt(ctx, field)
case "updatedAt": case "updatedAt":
return ec.fieldContext_Vendor_updatedAt(ctx, field) 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) 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 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 ***************************** // endregion **************************** input.gotpl *****************************
// region ************************** interface.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 { if out.Values[i] == graphql.Null {
out.Invalids++ 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: default:
panic("unknown field " + strconv.Quote(field.Name)) 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) { func (ec *executionContext) unmarshalNString2string(ctx context.Context, v any) (string, error) {
res, err := graphql.UnmarshalString(v) res, err := graphql.UnmarshalString(v)
return res, graphql.ErrorOnPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)
@@ -12518,6 +12936,22 @@ func (ec *executionContext) marshalOCursorKey2ᚖgithubᚗcomᚋgetproboᚋprobo
return res 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) { func (ec *executionContext) unmarshalOEvidenceState2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋproboᚋcoredataᚐEvidenceState(ctx context.Context, v any) (*coredata.EvidenceState, error) {
if v == nil { if v == nil {
return nil, nil return nil, nil
@@ -12564,6 +12998,66 @@ func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.Sele
return res 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) { func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) {
if v == nil { if v == nil {
return nil, nil return nil, nil

View File

@@ -237,11 +237,26 @@ type TaskStateTransitionEdge struct {
Node *TaskStateTransition `json:"node"` 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 { type Vendor struct {
ID gid.GID `json:"id"` ID gid.GID `json:"id"`
Name string `json:"name"` Name string `json:"name"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"` 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() {} func (Vendor) IsNode() {}

View File

@@ -45,5 +45,10 @@ func NewVendor(v *coredata.Vendor) *Vendor {
Name: v.Name, Name: v.Name,
CreatedAt: v.CreatedAt, CreatedAt: v.CreatedAt,
UpdatedAt: v.UpdatedAt, UpdatedAt: v.UpdatedAt,
ServiceStartDate: v.ServiceStartDate,
ServiceTerminationDate: v.ServiceTerminationDate,
ServiceCriticality: v.ServiceCriticality,
RiskTier: v.RiskTier,
StatusPageURL: v.StatusPageURL,
} }
} }

View 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;

View 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
}

View 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
}

View File

@@ -31,6 +31,11 @@ type (
ID gid.GID ID gid.GID
OrganizationID gid.GID OrganizationID gid.GID
Name string Name string
ServiceStartDate time.Time
ServiceTerminationDate *time.Time
ServiceCriticality ServiceCriticality
RiskTier RiskTier
StatusPageURL *string
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
} }
@@ -47,6 +52,11 @@ func (v *Vendor) scan(r pgx.Row) error {
&v.ID, &v.ID,
&v.OrganizationID, &v.OrganizationID,
&v.Name, &v.Name,
&v.ServiceStartDate,
&v.ServiceTerminationDate,
&v.ServiceCriticality,
&v.RiskTier,
&v.StatusPageURL,
&v.CreatedAt, &v.CreatedAt,
&v.UpdatedAt, &v.UpdatedAt,
) )
@@ -63,6 +73,11 @@ SELECT
id, id,
organization_id, organization_id,
name, name,
service_start_date,
service_termination_date,
service_criticality,
risk_tier,
status_page_url,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -100,6 +115,11 @@ INSERT INTO
id, id,
organization_id, organization_id,
name, name,
service_start_date,
service_termination_date,
service_criticality,
risk_tier,
status_page_url,
created_at, created_at,
updated_at updated_at
) )
@@ -107,6 +127,11 @@ VALUES (
@vendor_id, @vendor_id,
@organization_id, @organization_id,
@name, @name,
@service_start_date,
@service_termination_date,
@service_criticality,
@risk_tier,
@status_page_url,
@created_at, @created_at,
@updated_at @updated_at
) )
@@ -116,6 +141,11 @@ VALUES (
"vendor_id": v.ID, "vendor_id": v.ID,
"organization_id": v.OrganizationID, "organization_id": v.OrganizationID,
"name": v.Name, "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, "created_at": v.CreatedAt,
"updated_at": v.UpdatedAt, "updated_at": v.UpdatedAt,
} }
@@ -153,6 +183,11 @@ SELECT
id, id,
organization_id, organization_id,
name, name,
service_start_date,
service_termination_date,
service_criticality,
risk_tier,
status_page_url,
created_at, created_at,
updated_at updated_at
FROM FROM
@@ -167,7 +202,7 @@ WHERE
args := pgx.NamedArgs{"organization_id": organizationID} args := pgx.NamedArgs{"organization_id": organizationID}
maps.Copy(args, cursor.SQLArguments()) maps.Copy(args, cursor.SQLArguments())
maps.Copy(args, cursor.SQLArguments()) maps.Copy(args, scope.SQLArguments())
r, err := conn.Query(ctx, q, args) r, err := conn.Query(ctx, q, args)
if err != nil { if err != nil {