Redesign trust center console

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-10-28 13:44:41 +01:00
parent abeaaec734
commit 1f0a5dff5c
39 changed files with 2308 additions and 2423 deletions

View File

@@ -1,6 +1,5 @@
import { graphql } from "relay-runtime";
import {
Card,
Button,
Tr,
Td,
@@ -18,7 +17,6 @@ import { useFragment } from "react-relay";
import { useMemo, useState, useCallback, useEffect } from "react";
import { sprintf, getAuditStateVariant, getAuditStateLabel, formatDate, getTrustCenterVisibilityOptions } from "@probo/helpers";
import { useOrganizationId } from "/hooks/useOrganizationId";
import clsx from "clsx";
import type { TrustCenterAuditsCardFragment$key } from "./__generated__/TrustCenterAuditsCardFragment.graphql";
const trustCenterAuditFragment = graphql`
@@ -50,17 +48,15 @@ type Props<Params> = {
params: Params;
disabled?: boolean;
onChangeVisibility: Mutation<Params>;
variant?: "card" | "table";
};
export function TrustCenterAuditsCard<Params>(props: Props<Params>) {
const { __ } = useTranslate();
const [limit, setLimit] = useState<number | null>(4);
const [limit, setLimit] = useState<number | null>(100);
const audits = useMemo(() => {
return limit ? props.audits.slice(0, limit) : props.audits;
}, [props.audits, limit]);
const showMoreButton = limit !== null && props.audits.length > limit;
const variant = props.variant ?? "table";
const onChangeVisibility = (auditId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => {
props.onChangeVisibility({
@@ -74,11 +70,9 @@ export function TrustCenterAuditsCard<Params>(props: Props<Params>) {
});
};
const Wrapper = variant === "card" ? Card : "div";
return (
<Wrapper {...(variant === "card" ? { padded: true } : {})} className="space-y-[10px]">
<Table className={clsx(variant === "card" && "bg-invert")}>
<div className="space-y-[10px]">
<Table>
<Thead>
<Tr>
<Th>{__("Framework")}</Th>
@@ -116,7 +110,7 @@ export function TrustCenterAuditsCard<Params>(props: Props<Params>) {
{sprintf(__("Show %s more"), props.audits.length - limit)}
</Button>
)}
</Wrapper>
</div>
);
}

View File

@@ -1,6 +1,5 @@
import { graphql } from "relay-runtime";
import {
Card,
Button,
Tr,
Td,
@@ -21,7 +20,6 @@ import { useFragment } from "react-relay";
import { useMemo, useState, useCallback, useEffect } from "react";
import { sprintf, getTrustCenterVisibilityOptions } from "@probo/helpers";
import { useOrganizationId } from "/hooks/useOrganizationId";
import clsx from "clsx";
const trustCenterDocumentFragment = graphql`
fragment TrustCenterDocumentsCardFragment on Document {
@@ -55,17 +53,15 @@ type Props<Params> = {
params: Params;
disabled?: boolean;
onChangeVisibility: Mutation<Params>;
variant?: "card" | "table";
};
export function TrustCenterDocumentsCard<Params>(props: Props<Params>) {
const { __ } = useTranslate();
const [limit, setLimit] = useState<number | null>(4);
const [limit, setLimit] = useState<number | null>(100);
const documents = useMemo(() => {
return limit ? props.documents.slice(0, limit) : props.documents;
}, [props.documents, limit]);
const showMoreButton = limit !== null && props.documents.length > limit;
const variant = props.variant ?? "table";
const onChangeVisibility = (documentId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => {
props.onChangeVisibility({
@@ -79,11 +75,9 @@ export function TrustCenterDocumentsCard<Params>(props: Props<Params>) {
});
};
const Wrapper = variant === "card" ? Card : "div";
return (
<Wrapper padded className="space-y-[10px]">
<Table className={clsx(variant === "card" && "bg-invert")}>
<div className="space-y-[10px]">
<Table>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
@@ -121,7 +115,7 @@ export function TrustCenterDocumentsCard<Params>(props: Props<Params>) {
{sprintf(__("Show %s more"), props.documents.length - limit)}
</Button>
)}
</Wrapper>
</div>
);
}

View File

@@ -1,6 +1,5 @@
import { graphql } from "relay-runtime";
import {
Card,
Button,
Tr,
Td,
@@ -22,7 +21,6 @@ import { useFragment } from "react-relay";
import { useMemo, useState, useCallback, useEffect } from "react";
import { sprintf, getTrustCenterVisibilityOptions } from "@probo/helpers";
import { formatDate } from "@probo/helpers";
import clsx from "clsx";
const trustCenterFileFragment = graphql`
fragment TrustCenterFilesCardFragment on TrustCenterFile {
@@ -52,17 +50,15 @@ type Props<Params> = {
onChangeVisibility: Mutation<Params>;
onEdit: (file: { id: string; name: string; category: string }) => void;
onDelete: (id: string) => void;
variant?: "card" | "table";
};
export function TrustCenterFilesCard<Params>(props: Props<Params>) {
const { __ } = useTranslate();
const [limit, setLimit] = useState<number | null>(4);
const [limit, setLimit] = useState<number | null>(100);
const files = useMemo(() => {
return limit ? props.files.slice(0, limit) : props.files;
}, [props.files, limit]);
const showMoreButton = limit !== null && props.files.length > limit;
const variant = props.variant ?? "table";
const onChangeVisibility = (fileId: string, trustCenterVisibility: "NONE" | "PRIVATE" | "PUBLIC") => {
props.onChangeVisibility({
@@ -76,11 +72,9 @@ export function TrustCenterFilesCard<Params>(props: Props<Params>) {
});
};
const Wrapper = variant === "card" ? Card : "div";
return (
<Wrapper padded className="space-y-[10px]">
<Table className={clsx(variant === "card" && "bg-invert")}>
<div className="space-y-[10px]">
<Table>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
@@ -120,7 +114,7 @@ export function TrustCenterFilesCard<Params>(props: Props<Params>) {
{sprintf(__("Show %s more"), props.files.length - limit)}
</Button>
)}
</Wrapper>
</div>
);
}
@@ -215,7 +209,7 @@ function FileRow(props: {
title={__("Edit")}
/>
<Button
variant="secondary"
variant="danger"
icon={IconTrashCan}
onClick={() => props.onDelete(file.id)}
disabled={props.disabled}

View File

@@ -3,10 +3,16 @@ import { safeOpenUrl } from "@probo/helpers";
import {
Avatar,
Button,
Card,
Table,
Thead,
Tbody,
Tr,
Th,
Td,
IconPlusLarge,
IconTrashCan,
IconPencil,
IconArrowLink,
} from "@probo/ui";
import { type ReactNode, useRef } from "react";
import {
@@ -64,7 +70,6 @@ export function TrustCenterReferencesSection({ trustCenterId }: Props) {
</p>
</div>
<Button
variant="secondary"
icon={IconPlusLarge}
onClick={handleCreate}
>
@@ -72,33 +77,33 @@ export function TrustCenterReferencesSection({ trustCenterId }: Props) {
</Button>
</div>
<Card padded>
{references.length === 0 ? (
<div className="text-center py-12">
<div className="mx-auto w-12 h-12 bg-tertiary rounded-lg flex items-center justify-center mb-4">
<IconPlusLarge size={24} className="text-txt-tertiary" />
</div>
<h3 className="text-lg font-medium text-txt-primary mb-2">
{__("No references yet")}
</h3>
<p className="text-txt-tertiary mb-4">
{__("Add customer testimonials and partner references to build trust")}
</p>
</div>
) : (
<div className="space-y-4">
{references.map((reference: Reference) => (
<ReferenceRow
key={reference.id}
reference={reference}
onEdit={() => handleEdit(reference)}
connectionId={referencesConnectionId}
onVisitWebsite={() => handleVisitWebsite(reference.websiteUrl)}
/>
))}
</div>
)}
</Card>
<Table>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
<Th>{__("Description")}</Th>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{references.length === 0 && (
<Tr>
<Td colSpan={3} className="text-center text-txt-secondary">
{__("No references available")}
</Td>
</Tr>
)}
{references.map((reference: Reference) => (
<ReferenceRow
key={reference.id}
reference={reference}
onEdit={() => handleEdit(reference)}
connectionId={referencesConnectionId}
onVisitWebsite={() => handleVisitWebsite(reference.websiteUrl)}
/>
))}
</Tbody>
</Table>
<TrustCenterReferenceDialog ref={dialogRef} />
</div>
@@ -113,52 +118,47 @@ type ReferenceRowProps = {
};
function ReferenceRow({ reference, onEdit, connectionId, onVisitWebsite }: ReferenceRowProps) {
return (
<div className="flex items-center justify-between p-4 bg-level-1 rounded-lg">
<div className="flex items-center space-x-4 flex-1">
<Avatar
src={reference.logoUrl}
name={reference.name}
size="l"
/>
<div className="flex-1 min-w-0">
<div className="flex items-center space-x-2 mb-1">
<button
type="button"
onClick={onVisitWebsite}
className="font-medium text-txt-primary truncate hover:text-primary hover:underline text-left cursor-pointer"
>
{reference.name}
</button>
</div>
<p className="text-sm text-txt-secondary line-clamp-2 mb-2">
{reference.description}
</p>
</div>
</div>
<div className="flex items-center justify-center space-x-2 ml-4">
<Button
variant="tertiary"
icon={IconPencil}
onClick={onEdit}
aria-label="Edit reference"
/>
<DeleteTrustCenterReferenceDialog
referenceId={reference.id}
referenceName={reference.name}
connectionId={connectionId}
>
<Button
variant="danger"
icon={IconTrashCan}
aria-label="Delete reference"
<Tr>
<Td>
<div className="flex items-center gap-3">
<Avatar
src={reference.logoUrl}
name={reference.name}
size="m"
/>
</DeleteTrustCenterReferenceDialog>
</div>
</div>
<span className="font-medium">{reference.name}</span>
</div>
</Td>
<Td>
<span className="text-txt-secondary line-clamp-2">
{reference.description}
</span>
</Td>
<Td noLink width={200} className="text-end">
<div className="flex gap-2 justify-end">
<Button
variant="secondary"
icon={IconArrowLink}
onClick={onVisitWebsite}
/>
<Button
variant="secondary"
icon={IconPencil}
onClick={onEdit}
/>
<DeleteTrustCenterReferenceDialog
referenceId={reference.id}
referenceName={reference.name}
connectionId={connectionId}
>
<Button
variant="danger"
icon={IconTrashCan}
/>
</DeleteTrustCenterReferenceDialog>
</div>
</Td>
</Tr>
);
}

View File

@@ -1,6 +1,5 @@
import { graphql } from "relay-runtime";
import {
Card,
Button,
Tr,
Td,
@@ -18,7 +17,6 @@ import { useFragment } from "react-relay";
import { useMemo, useState } from "react";
import { sprintf } from "@probo/helpers";
import { useOrganizationId } from "/hooks/useOrganizationId";
import clsx from "clsx";
import type { TrustCenterVendorsCardFragment$key } from "./__generated__/TrustCenterVendorsCardFragment.graphql";
const trustCenterVendorFragment = graphql`
@@ -46,17 +44,15 @@ type Props<Params> = {
params: Params;
disabled?: boolean;
onToggleVisibility: Mutation<Params>;
variant?: "card" | "table";
};
export function TrustCenterVendorsCard<Params>(props: Props<Params>) {
const { __ } = useTranslate();
const [limit, setLimit] = useState<number | null>(4);
const [limit, setLimit] = useState<number | null>(100);
const vendors = useMemo(() => {
return limit ? props.vendors.slice(0, limit) : props.vendors;
}, [props.vendors, limit]);
const showMoreButton = limit !== null && props.vendors.length > limit;
const variant = props.variant ?? "table";
const onToggleVisibility = (vendorId: string, showOnTrustCenter: boolean) => {
props.onToggleVisibility({
@@ -70,11 +66,9 @@ export function TrustCenterVendorsCard<Params>(props: Props<Params>) {
});
};
const Wrapper = variant === "card" ? Card : "div";
return (
<Wrapper padded className="space-y-[10px]">
<Table className={clsx(variant === "card" && "bg-invert")}>
<div className="space-y-[10px]">
<Table>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
@@ -111,7 +105,7 @@ export function TrustCenterVendorsCard<Params>(props: Props<Params>) {
{sprintf(__("Show %s more"), props.vendors.length - limit)}
</Button>
)}
</Wrapper>
</div>
);
}

View File

@@ -25,36 +25,9 @@ export const trustCenterAccessesPaginationFragment = graphql`
active
hasAcceptedNonDisclosureAgreement
createdAt
documentAccesses(first: 100, orderBy: { field: CREATED_AT, direction: DESC }) {
edges {
node {
id
active
createdAt
updatedAt
document {
id
title
documentType
}
report {
id
filename
audit {
id
framework {
name
}
}
}
trustCenterFile {
id
name
category
}
}
}
}
lastTokenExpiresAt
pendingRequestCount
activeCount
}
}
}
@@ -87,36 +60,9 @@ export const createTrustCenterAccessMutation = graphql`
active
hasAcceptedNonDisclosureAgreement
createdAt
documentAccesses(first: 100, orderBy: { field: CREATED_AT, direction: DESC }) {
edges {
node {
id
active
createdAt
updatedAt
document {
id
title
documentType
}
report {
id
filename
audit {
id
framework {
name
}
}
}
trustCenterFile {
id
name
category
}
}
}
}
lastTokenExpiresAt
pendingRequestCount
activeCount
}
}
}
@@ -136,13 +82,35 @@ export const updateTrustCenterAccessMutation = graphql`
hasAcceptedNonDisclosureAgreement
createdAt
updatedAt
documentAccesses(first: 100, orderBy: { field: CREATED_AT, direction: DESC }) {
lastTokenExpiresAt
pendingRequestCount
activeCount
}
}
}
`;
export const deleteTrustCenterAccessMutation = graphql`
mutation TrustCenterAccessGraphDeleteMutation(
$input: DeleteTrustCenterAccessInput!
$connections: [ID!]!
) {
deleteTrustCenterAccess(input: $input) {
deletedTrustCenterAccessId @deleteEdge(connections: $connections)
}
}
`;
export const loadTrustCenterAccessDocumentAccessesQuery = graphql`
query TrustCenterAccessGraphLoadDocumentAccessesQuery($accessId: ID!) {
node(id: $accessId) {
... on TrustCenterAccess {
id
availableDocumentAccesses(first: 100, orderBy: { field: CREATED_AT, direction: DESC }) {
edges {
node {
id
active
createdAt
updatedAt
requested
document {
id
title
@@ -171,17 +139,6 @@ export const updateTrustCenterAccessMutation = graphql`
}
`;
export const deleteTrustCenterAccessMutation = graphql`
mutation TrustCenterAccessGraphDeleteMutation(
$input: DeleteTrustCenterAccessInput!
$connections: [ID!]!
) {
deleteTrustCenterAccess(input: $input) {
deletedTrustCenterAccessId @deleteEdge(connections: $connections)
}
}
`;
interface PaginatedData {
data: { node: any } | null;
hasNext: boolean;
@@ -197,7 +154,7 @@ export function useTrustCenterAccesses(trustCenterId: string): PaginatedData {
count: 10,
cursor: null
},
{ fetchPolicy: 'network-only' }
{ fetchPolicy: 'store-and-network' }
);
if (!trustCenterId) {

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<d527603a814e765a1a2be0900d1c59e1>>
* @generated SignedSource<<271260153dc611541b234266fbdd0c74>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,7 +9,6 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DocumentType = "ISMS" | "OTHER" | "POLICY" | "PROCEDURE";
export type CreateTrustCenterAccessInput = {
active: boolean;
email: string;
@@ -26,41 +25,14 @@ export type TrustCenterAccessGraphCreateMutation$data = {
readonly cursor: any;
readonly node: {
readonly active: boolean;
readonly activeCount: number;
readonly createdAt: any;
readonly documentAccesses: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly active: boolean;
readonly createdAt: any;
readonly document: {
readonly documentType: DocumentType;
readonly id: string;
readonly title: string;
} | null | undefined;
readonly id: string;
readonly report: {
readonly audit: {
readonly framework: {
readonly name: string;
};
readonly id: string;
} | null | undefined;
readonly filename: string;
readonly id: string;
} | null | undefined;
readonly trustCenterFile: {
readonly category: string;
readonly id: string;
readonly name: string;
} | null | undefined;
readonly updatedAt: any;
};
}>;
};
readonly email: string;
readonly hasAcceptedNonDisclosureAgreement: boolean;
readonly id: string;
readonly lastTokenExpiresAt: any | null | undefined;
readonly name: string;
readonly pendingRequestCount: number;
};
};
};
@@ -91,122 +63,90 @@ v2 = [
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "cursor",
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasAcceptedNonDisclosureAgreement",
"storageKey": null
},
v9 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
v10 = [
{
"kind": "Literal",
"name": "first",
"value": 100
},
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
}
],
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
v12 = {
"alias": null,
"args": null,
"concreteType": "Document",
"concreteType": "TrustCenterAccessEdge",
"kind": "LinkedField",
"name": "document",
"name": "trustCenterAccessEdge",
"plural": false,
"selections": [
(v4/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"name": "cursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
}
],
"storageKey": null
},
v13 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "filename",
"storageKey": null
},
v14 = {
"alias": null,
"args": null,
"concreteType": "TrustCenterFile",
"kind": "LinkedField",
"name": "trustCenterFile",
"plural": false,
"selections": [
(v4/*: any*/),
(v6/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasAcceptedNonDisclosureAgreement",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lastTokenExpiresAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "pendingRequestCount",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "activeCount",
"storageKey": null
}
],
"storageKey": null
}
],
@@ -230,111 +170,7 @@ return {
"name": "createTrustCenterAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccessEdge",
"kind": "LinkedField",
"name": "trustCenterAccessEdge",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
{
"alias": null,
"args": (v10/*: any*/),
"concreteType": "TrustCenterDocumentAccessConnection",
"kind": "LinkedField",
"name": "documentAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccessEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
(v7/*: any*/),
(v9/*: any*/),
(v11/*: any*/),
(v12/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v4/*: any*/),
(v13/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "audit",
"plural": false,
"selections": [
(v4/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v6/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v14/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documentAccesses(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
}
],
"storageKey": null
}
],
"storageKey": null
}
(v3/*: any*/)
],
"storageKey": null
}
@@ -359,112 +195,7 @@ return {
"name": "createTrustCenterAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccessEdge",
"kind": "LinkedField",
"name": "trustCenterAccessEdge",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
{
"alias": null,
"args": (v10/*: any*/),
"concreteType": "TrustCenterDocumentAccessConnection",
"kind": "LinkedField",
"name": "documentAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccessEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
(v7/*: any*/),
(v9/*: any*/),
(v11/*: any*/),
(v12/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v4/*: any*/),
(v13/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "audit",
"plural": false,
"selections": [
(v4/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v6/*: any*/),
(v4/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v14/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documentAccesses(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
}
],
"storageKey": null
}
],
"storageKey": null
},
(v3/*: any*/),
{
"alias": null,
"args": null,
@@ -487,16 +218,16 @@ return {
]
},
"params": {
"cacheID": "4422a02632b77f81f3b5048b5acbac98",
"cacheID": "501c3c38f8d44e41a178514443803ce2",
"id": null,
"metadata": {},
"name": "TrustCenterAccessGraphCreateMutation",
"operationKind": "mutation",
"text": "mutation TrustCenterAccessGraphCreateMutation(\n $input: CreateTrustCenterAccessInput!\n) {\n createTrustCenterAccess(input: $input) {\n trustCenterAccessEdge {\n cursor\n node {\n id\n email\n name\n active\n hasAcceptedNonDisclosureAgreement\n createdAt\n documentAccesses(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {\n edges {\n node {\n id\n active\n createdAt\n updatedAt\n document {\n id\n title\n documentType\n }\n report {\n id\n filename\n audit {\n id\n framework {\n name\n id\n }\n }\n }\n trustCenterFile {\n id\n name\n category\n }\n }\n }\n }\n }\n }\n }\n}\n"
"text": "mutation TrustCenterAccessGraphCreateMutation(\n $input: CreateTrustCenterAccessInput!\n) {\n createTrustCenterAccess(input: $input) {\n trustCenterAccessEdge {\n cursor\n node {\n id\n email\n name\n active\n hasAcceptedNonDisclosureAgreement\n createdAt\n lastTokenExpiresAt\n pendingRequestCount\n activeCount\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "c09c8a22a45226949a08f2262ddd0b1c";
(node as any).hash = "bfe1841f269ba04a77e9b3ecf73665d2";
export default node;

View File

@@ -0,0 +1,391 @@
/**
* @generated SignedSource<<ef22c40e1c881ddd440a0468bae615f9>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DocumentType = "ISMS" | "OTHER" | "POLICY" | "PROCEDURE";
export type TrustCenterAccessGraphLoadDocumentAccessesQuery$variables = {
accessId: string;
};
export type TrustCenterAccessGraphLoadDocumentAccessesQuery$data = {
readonly node: {
readonly availableDocumentAccesses?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly active: boolean;
readonly document: {
readonly documentType: DocumentType;
readonly id: string;
readonly title: string;
} | null | undefined;
readonly report: {
readonly audit: {
readonly framework: {
readonly name: string;
};
readonly id: string;
} | null | undefined;
readonly filename: string;
readonly id: string;
} | null | undefined;
readonly requested: boolean;
readonly trustCenterFile: {
readonly category: string;
readonly id: string;
readonly name: string;
} | null | undefined;
};
}>;
};
readonly id?: string;
};
};
export type TrustCenterAccessGraphLoadDocumentAccessesQuery = {
response: TrustCenterAccessGraphLoadDocumentAccessesQuery$data;
variables: TrustCenterAccessGraphLoadDocumentAccessesQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "accessId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "accessId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = [
{
"kind": "Literal",
"name": "first",
"value": 100
},
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
}
],
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "requested",
"storageKey": null
},
v6 = {
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "document",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
}
],
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "filename",
"storageKey": null
},
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v9 = {
"alias": null,
"args": null,
"concreteType": "TrustCenterFile",
"kind": "LinkedField",
"name": "trustCenterFile",
"plural": false,
"selections": [
(v2/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
}
],
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "TrustCenterAccessGraphLoadDocumentAccessesQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"kind": "InlineFragment",
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": (v3/*: any*/),
"concreteType": "TrustCenterDocumentAccessConnection",
"kind": "LinkedField",
"name": "availableDocumentAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccessEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v2/*: any*/),
(v7/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "audit",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v8/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v9/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "availableDocumentAccesses(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
}
],
"type": "TrustCenterAccess",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "TrustCenterAccessGraphLoadDocumentAccessesQuery",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v3/*: any*/),
"concreteType": "TrustCenterDocumentAccessConnection",
"kind": "LinkedField",
"name": "availableDocumentAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccessEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v2/*: any*/),
(v7/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "audit",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v8/*: any*/),
(v2/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v9/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "availableDocumentAccesses(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
}
],
"type": "TrustCenterAccess",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "50de5f19f1c13ee4d4a0b125231b989f",
"id": null,
"metadata": {},
"name": "TrustCenterAccessGraphLoadDocumentAccessesQuery",
"operationKind": "query",
"text": "query TrustCenterAccessGraphLoadDocumentAccessesQuery(\n $accessId: ID!\n) {\n node(id: $accessId) {\n __typename\n ... on TrustCenterAccess {\n id\n availableDocumentAccesses(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {\n edges {\n node {\n active\n requested\n document {\n id\n title\n documentType\n }\n report {\n id\n filename\n audit {\n id\n framework {\n name\n id\n }\n }\n }\n trustCenterFile {\n id\n name\n category\n }\n }\n }\n }\n }\n id\n }\n}\n"
}
};
})();
(node as any).hash = "64c69558e335d4cecb14192d8c5b66b8";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<8c2482b7d32c42396e4645bd309e7cc2>>
* @generated SignedSource<<fedd4f94d88d48ba3152491a5c0101f4>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -64,15 +64,7 @@ v3 = {
"name": "id",
"storageKey": null
},
v4 = {
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
},
v5 = [
v4 = [
{
"kind": "Variable",
"name": "after",
@@ -83,29 +75,15 @@ v5 = [
"name": "first",
"variableName": "count"
},
(v4/*: any*/)
],
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
};
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
@@ -154,7 +132,7 @@ return {
"selections": [
{
"alias": null,
"args": (v5/*: any*/),
"args": (v4/*: any*/),
"concreteType": "TrustCenterAccessConnection",
"kind": "LinkedField",
"name": "accesses",
@@ -230,8 +208,20 @@ return {
"name": "email",
"storageKey": null
},
(v6/*: any*/),
(v7/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -239,146 +229,33 @@ return {
"name": "hasAcceptedNonDisclosureAgreement",
"storageKey": null
},
(v8/*: any*/),
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 100
},
(v4/*: any*/)
],
"concreteType": "TrustCenterDocumentAccessConnection",
"kind": "LinkedField",
"name": "documentAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccessEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "document",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "filename",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "audit",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v6/*: any*/),
(v3/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "TrustCenterFile",
"kind": "LinkedField",
"name": "trustCenterFile",
"plural": false,
"selections": [
(v3/*: any*/),
(v6/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documentAccesses(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lastTokenExpiresAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "pendingRequestCount",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "activeCount",
"storageKey": null
},
(v2/*: any*/)
],
@@ -404,7 +281,7 @@ return {
},
{
"alias": null,
"args": (v5/*: any*/),
"args": (v4/*: any*/),
"filters": [
"orderBy"
],
@@ -423,16 +300,16 @@ return {
]
},
"params": {
"cacheID": "12322ab403d03a821d2228ff68c3d191",
"cacheID": "98a87a363a8a26e30506346db052e11a",
"id": null,
"metadata": {},
"name": "TrustCenterAccessGraphPaginationQuery",
"operationKind": "query",
"text": "query TrustCenterAccessGraphPaginationQuery(\n $count: Int\n $cursor: CursorKey\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...TrustCenterAccessGraph_accesses\n id\n }\n}\n\nfragment TrustCenterAccessGraph_accesses on TrustCenter {\n accesses(first: $count, after: $cursor, orderBy: {field: CREATED_AT, direction: DESC}) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n email\n name\n active\n hasAcceptedNonDisclosureAgreement\n createdAt\n documentAccesses(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {\n edges {\n node {\n id\n active\n createdAt\n updatedAt\n document {\n id\n title\n documentType\n }\n report {\n id\n filename\n audit {\n id\n framework {\n name\n id\n }\n }\n }\n trustCenterFile {\n id\n name\n category\n }\n }\n }\n }\n __typename\n }\n }\n }\n id\n}\n"
"text": "query TrustCenterAccessGraphPaginationQuery(\n $count: Int\n $cursor: CursorKey\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...TrustCenterAccessGraph_accesses\n id\n }\n}\n\nfragment TrustCenterAccessGraph_accesses on TrustCenter {\n accesses(first: $count, after: $cursor, orderBy: {field: CREATED_AT, direction: DESC}) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n email\n name\n active\n hasAcceptedNonDisclosureAgreement\n createdAt\n lastTokenExpiresAt\n pendingRequestCount\n activeCount\n __typename\n }\n }\n }\n id\n}\n"
}
};
})();
(node as any).hash = "9c7f3e866e2593c169b1f98d0e637667";
(node as any).hash = "10bb084980182a1e2334be77c29cf1ec";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<e0c9c25c78bb6c8cf63eb9437947a013>>
* @generated SignedSource<<d13da95487a7fd3dafa22397092b134c>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -63,15 +63,7 @@ v5 = {
"name": "__typename",
"storageKey": null
},
v6 = {
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
},
v7 = [
v6 = [
{
"kind": "Variable",
"name": "after",
@@ -82,29 +74,15 @@ v7 = [
"name": "first",
"variableName": "count"
},
(v6/*: any*/)
],
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v9 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
v10 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
};
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
}
];
return {
"fragment": {
"argumentDefinitions": [
@@ -169,7 +147,7 @@ return {
"selections": [
{
"alias": null,
"args": (v7/*: any*/),
"args": (v6/*: any*/),
"concreteType": "TrustCenterAccessConnection",
"kind": "LinkedField",
"name": "accesses",
@@ -245,8 +223,20 @@ return {
"name": "email",
"storageKey": null
},
(v8/*: any*/),
(v9/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -254,146 +244,33 @@ return {
"name": "hasAcceptedNonDisclosureAgreement",
"storageKey": null
},
(v10/*: any*/),
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 100
},
(v6/*: any*/)
],
"concreteType": "TrustCenterDocumentAccessConnection",
"kind": "LinkedField",
"name": "documentAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccessEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v4/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "document",
"plural": false,
"selections": [
(v4/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v4/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "filename",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "audit",
"plural": false,
"selections": [
(v4/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v8/*: any*/),
(v4/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "TrustCenterFile",
"kind": "LinkedField",
"name": "trustCenterFile",
"plural": false,
"selections": [
(v4/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documentAccesses(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lastTokenExpiresAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "pendingRequestCount",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "activeCount",
"storageKey": null
},
(v5/*: any*/)
],
@@ -419,7 +296,7 @@ return {
},
{
"alias": null,
"args": (v7/*: any*/),
"args": (v6/*: any*/),
"filters": [
"orderBy"
],
@@ -438,12 +315,12 @@ return {
]
},
"params": {
"cacheID": "37deb80fc3ff8892d2e68f7588da4e55",
"cacheID": "703f94692a1696b15e0c92b282866673",
"id": null,
"metadata": {},
"name": "TrustCenterAccessGraphQuery",
"operationKind": "query",
"text": "query TrustCenterAccessGraphQuery(\n $trustCenterId: ID!\n $count: Int!\n $cursor: CursorKey\n) {\n node(id: $trustCenterId) {\n __typename\n ... on TrustCenter {\n id\n ...TrustCenterAccessGraph_accesses\n }\n id\n }\n}\n\nfragment TrustCenterAccessGraph_accesses on TrustCenter {\n accesses(first: $count, after: $cursor, orderBy: {field: CREATED_AT, direction: DESC}) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n email\n name\n active\n hasAcceptedNonDisclosureAgreement\n createdAt\n documentAccesses(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {\n edges {\n node {\n id\n active\n createdAt\n updatedAt\n document {\n id\n title\n documentType\n }\n report {\n id\n filename\n audit {\n id\n framework {\n name\n id\n }\n }\n }\n trustCenterFile {\n id\n name\n category\n }\n }\n }\n }\n __typename\n }\n }\n }\n id\n}\n"
"text": "query TrustCenterAccessGraphQuery(\n $trustCenterId: ID!\n $count: Int!\n $cursor: CursorKey\n) {\n node(id: $trustCenterId) {\n __typename\n ... on TrustCenter {\n id\n ...TrustCenterAccessGraph_accesses\n }\n id\n }\n}\n\nfragment TrustCenterAccessGraph_accesses on TrustCenter {\n accesses(first: $count, after: $cursor, orderBy: {field: CREATED_AT, direction: DESC}) {\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n edges {\n cursor\n node {\n id\n email\n name\n active\n hasAcceptedNonDisclosureAgreement\n createdAt\n lastTokenExpiresAt\n pendingRequestCount\n activeCount\n __typename\n }\n }\n }\n id\n}\n"
}
};
})();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<8ecf71138aa0165738506f5e589d3181>>
* @generated SignedSource<<25b79c235754d47097b2ca28f1f3e9a0>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,7 +9,6 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DocumentType = "ISMS" | "OTHER" | "POLICY" | "PROCEDURE";
export type UpdateTrustCenterAccessInput = {
active?: boolean | null | undefined;
documentIds?: ReadonlyArray<string> | null | undefined;
@@ -25,41 +24,14 @@ export type TrustCenterAccessGraphUpdateMutation$data = {
readonly updateTrustCenterAccess: {
readonly trustCenterAccess: {
readonly active: boolean;
readonly activeCount: number;
readonly createdAt: any;
readonly documentAccesses: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly active: boolean;
readonly createdAt: any;
readonly document: {
readonly documentType: DocumentType;
readonly id: string;
readonly title: string;
} | null | undefined;
readonly id: string;
readonly report: {
readonly audit: {
readonly framework: {
readonly name: string;
};
readonly id: string;
} | null | undefined;
readonly filename: string;
readonly id: string;
} | null | undefined;
readonly trustCenterFile: {
readonly category: string;
readonly id: string;
readonly name: string;
} | null | undefined;
readonly updatedAt: any;
};
}>;
};
readonly email: string;
readonly hasAcceptedNonDisclosureAgreement: boolean;
readonly id: string;
readonly lastTokenExpiresAt: any | null | undefined;
readonly name: string;
readonly pendingRequestCount: number;
readonly updatedAt: any;
};
};
@@ -79,241 +51,111 @@ var v0 = [
],
v1 = [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasAcceptedNonDisclosureAgreement",
"storageKey": null
},
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
v9 = [
{
"kind": "Literal",
"name": "first",
"value": 100
},
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
}
],
v10 = {
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "document",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
}
],
"storageKey": null
},
v11 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "filename",
"storageKey": null
},
v12 = {
"alias": null,
"args": null,
"concreteType": "TrustCenterFile",
"kind": "LinkedField",
"name": "trustCenterFile",
"plural": false,
"selections": [
(v2/*: any*/),
(v4/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
}
],
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "TrustCenterAccessGraphUpdateMutation",
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "UpdateTrustCenterAccessPayload",
"kind": "LinkedField",
"name": "updateTrustCenterAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": "UpdateTrustCenterAccessPayload",
"args": null,
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "updateTrustCenterAccess",
"name": "trustCenterAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "trustCenterAccess",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": (v9/*: any*/),
"concreteType": "TrustCenterDocumentAccessConnection",
"kind": "LinkedField",
"name": "documentAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccessEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v5/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v10/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v2/*: any*/),
(v11/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "audit",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v4/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v12/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documentAccesses(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
}
],
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "email",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasAcceptedNonDisclosureAgreement",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lastTokenExpiresAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "pendingRequestCount",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "activeCount",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "TrustCenterAccessGraphUpdateMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
@@ -322,126 +164,19 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "TrustCenterAccessGraphUpdateMutation",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": "UpdateTrustCenterAccessPayload",
"kind": "LinkedField",
"name": "updateTrustCenterAccess",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterAccess",
"kind": "LinkedField",
"name": "trustCenterAccess",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
{
"alias": null,
"args": (v9/*: any*/),
"concreteType": "TrustCenterDocumentAccessConnection",
"kind": "LinkedField",
"name": "documentAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccessEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v5/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v10/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v2/*: any*/),
(v11/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "audit",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v4/*: any*/),
(v2/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
(v12/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documentAccesses(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
}
],
"storageKey": null
}
],
"storageKey": null
}
]
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "b66da9236d9f81563608b3aa5f730908",
"cacheID": "8b330240bc19bbebb3244a49dc0a6db0",
"id": null,
"metadata": {},
"name": "TrustCenterAccessGraphUpdateMutation",
"operationKind": "mutation",
"text": "mutation TrustCenterAccessGraphUpdateMutation(\n $input: UpdateTrustCenterAccessInput!\n) {\n updateTrustCenterAccess(input: $input) {\n trustCenterAccess {\n id\n email\n name\n active\n hasAcceptedNonDisclosureAgreement\n createdAt\n updatedAt\n documentAccesses(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {\n edges {\n node {\n id\n active\n createdAt\n updatedAt\n document {\n id\n title\n documentType\n }\n report {\n id\n filename\n audit {\n id\n framework {\n name\n id\n }\n }\n }\n trustCenterFile {\n id\n name\n category\n }\n }\n }\n }\n }\n }\n}\n"
"text": "mutation TrustCenterAccessGraphUpdateMutation(\n $input: UpdateTrustCenterAccessInput!\n) {\n updateTrustCenterAccess(input: $input) {\n trustCenterAccess {\n id\n email\n name\n active\n hasAcceptedNonDisclosureAgreement\n createdAt\n updatedAt\n lastTokenExpiresAt\n pendingRequestCount\n activeCount\n }\n }\n}\n"
}
};
})();
(node as any).hash = "43e73cc9d80e898f1ba2a92eaf4646f5";
(node as any).hash = "f78b4d25b0977a14269491db951a1d9d";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<d572a906e6afd89e4a3f1dcffa5c0528>>
* @generated SignedSource<<a3da155281753945ab0645a04f0b74fb>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,7 +9,6 @@
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type DocumentType = "ISMS" | "OTHER" | "POLICY" | "PROCEDURE";
import { FragmentRefs } from "relay-runtime";
export type TrustCenterAccessGraph_accesses$data = {
readonly accesses: {
@@ -18,41 +17,14 @@ export type TrustCenterAccessGraph_accesses$data = {
readonly cursor: any;
readonly node: {
readonly active: boolean;
readonly activeCount: number;
readonly createdAt: any;
readonly documentAccesses: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly active: boolean;
readonly createdAt: any;
readonly document: {
readonly documentType: DocumentType;
readonly id: string;
readonly title: string;
} | null | undefined;
readonly id: string;
readonly report: {
readonly audit: {
readonly framework: {
readonly name: string;
};
readonly id: string;
} | null | undefined;
readonly filename: string;
readonly id: string;
} | null | undefined;
readonly trustCenterFile: {
readonly category: string;
readonly id: string;
readonly name: string;
} | null | undefined;
readonly updatedAt: any;
};
}>;
};
readonly email: string;
readonly hasAcceptedNonDisclosureAgreement: boolean;
readonly id: string;
readonly lastTokenExpiresAt: any | null | undefined;
readonly name: string;
readonly pendingRequestCount: number;
};
}>;
readonly pageInfo: {
@@ -77,40 +49,11 @@ var v0 = [
"accesses"
],
v1 = {
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
},
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
};
return {
"argumentDefinitions": [
@@ -157,7 +100,14 @@ return {
{
"alias": "accesses",
"args": [
(v1/*: any*/)
{
"kind": "Literal",
"name": "orderBy",
"value": {
"direction": "DESC",
"field": "CREATED_AT"
}
}
],
"concreteType": "TrustCenterAccessConnection",
"kind": "LinkedField",
@@ -226,7 +176,7 @@ return {
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v1/*: any*/),
{
"alias": null,
"args": null,
@@ -234,8 +184,20 @@ return {
"name": "email",
"storageKey": null
},
(v3/*: any*/),
(v4/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "name",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "active",
"storageKey": null
},
{
"alias": null,
"args": null,
@@ -243,145 +205,33 @@ return {
"name": "hasAcceptedNonDisclosureAgreement",
"storageKey": null
},
(v5/*: any*/),
{
"alias": null,
"args": [
{
"kind": "Literal",
"name": "first",
"value": 100
},
(v1/*: any*/)
],
"concreteType": "TrustCenterDocumentAccessConnection",
"kind": "LinkedField",
"name": "documentAccesses",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccessEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "TrustCenterDocumentAccess",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
(v4/*: any*/),
(v5/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "document",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "documentType",
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Report",
"kind": "LinkedField",
"name": "report",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "filename",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "Audit",
"kind": "LinkedField",
"name": "audit",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "Framework",
"kind": "LinkedField",
"name": "framework",
"plural": false,
"selections": [
(v3/*: any*/)
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "TrustCenterFile",
"kind": "LinkedField",
"name": "trustCenterFile",
"plural": false,
"selections": [
(v2/*: any*/),
(v3/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "category",
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": null
}
],
"storageKey": "documentAccesses(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "lastTokenExpiresAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "pendingRequestCount",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "activeCount",
"storageKey": null
},
{
"alias": null,
@@ -411,13 +261,13 @@ return {
],
"storageKey": "__TrustCenterAccessGraph_accesses_connection(orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
},
(v2/*: any*/)
(v1/*: any*/)
],
"type": "TrustCenter",
"abstractKey": null
};
})();
(node as any).hash = "9c7f3e866e2593c169b1f98d0e637667";
(node as any).hash = "10bb084980182a1e2334be77c29cf1ec";
export default node;

View File

@@ -12,7 +12,6 @@ import {
IconInboxEmpty,
IconPageTextLine,
IconSettingsGear2,
IconCheckmark1,
IconStore,
IconTodo,
IconListStack,
@@ -20,6 +19,7 @@ import {
IconShield,
IconRotateCw,
IconCircleProgress,
IconMedal,
Layout,
SidebarItem,
UserDropdown as UserDropdownRoot,
@@ -169,7 +169,7 @@ export function MainLayout() {
/>
<SidebarItem
label={__("Audits")}
icon={IconCheckmark1}
icon={IconMedal}
to={`${prefix}/audits`}
/>
<SidebarItem

View File

@@ -1,7 +1,6 @@
import {
Badge,
Button,
Card,
Checkbox,
Dialog,
DialogContent,
@@ -20,19 +19,21 @@ import {
IconCheckmark1,
IconCrossLargeX,
IconChevronDown,
IconPlusLarge,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { formatDate } from "@probo/helpers";
import { useOutletContext } from "react-router";
import { useState, useCallback, useEffect } from "react";
import { useState, useCallback, useEffect, useRef } from "react";
import { useQueryLoader, usePreloadedQuery } from 'react-relay';
import z from "zod";
import {
useTrustCenterAccesses,
createTrustCenterAccessMutation,
updateTrustCenterAccessMutation,
deleteTrustCenterAccessMutation
deleteTrustCenterAccessMutation,
loadTrustCenterAccessDocumentAccessesQuery
} from "/hooks/graph/TrustCenterAccessGraph";
import type { TrustCenterAccessGraph_accesses$data } from "/hooks/graph/__generated__/TrustCenterAccessGraph_accesses.graphql";
import { useFormWithSchema } from "/hooks/useFormWithSchema";
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
@@ -42,9 +43,89 @@ type ContextType = {
trustCenter?: {
id: string;
};
documents?: {
edges: Array<{
node: {
id: string;
title: string;
documentType: string;
trustCenterVisibility: string;
};
}>;
};
audits?: {
edges: Array<{
node: {
id: string;
filename: string;
trustCenterVisibility: string;
framework: {
name: string;
};
};
}>;
};
trustCenterFiles?: {
edges: Array<{
node: {
id: string;
name: string;
category: string;
trustCenterVisibility: string;
};
}>;
};
};
};
type DocumentAccessInfo = {
id: string;
active: boolean;
requested: boolean;
document?: {
id: string;
title: string;
documentType: string;
} | null;
report?: {
id: string;
filename: string;
audit: {
id: string;
framework: {
name: string;
};
};
} | null;
trustCenterFile?: {
id: string;
name: string;
category: string;
} | null;
};
function DocumentAccessesLoader({
queryReference,
onDataLoaded
}: {
queryReference: any;
onDataLoaded: (documentAccesses: DocumentAccessInfo[]) => void;
}) {
const data = usePreloadedQuery(loadTrustCenterAccessDocumentAccessesQuery, queryReference);
useEffect(() => {
if (data && typeof data === 'object' && 'node' in data) {
const node = (data as any).node;
if (node?.availableDocumentAccesses?.edges) {
const documentAccesses = node.availableDocumentAccesses.edges.map((edge: any) => edge.node);
onDataLoaded(documentAccesses);
}
}
}, [data, onDataLoaded]);
return null;
}
export default function TrustCenterAccessTab() {
const { __ } = useTranslate();
const { organization } = useOutletContext<ContextType>();
@@ -75,10 +156,35 @@ export default function TrustCenterAccessTab() {
const dialogRef = useDialogRef();
const editDialogRef = useDialogRef();
const [editingAccess, setEditingAccess] = useState<AccessType | null>(null);
const [editingDocumentAccesses, setEditingDocumentAccesses] = useState<DocumentAccessType[]>([]);
const [selectedDocumentAccesses, setSelectedDocumentAccesses] = useState<Set<string>>(new Set());
const [pendingEditEmail, setPendingEditEmail] = useState<string | null>(null);
const [documentAccessesQueryReference, loadDocumentAccessesQuery] = useQueryLoader(loadTrustCenterAccessDocumentAccessesQuery);
const loadedAccessIdRef = useRef<string | null>(null);
const [isLoadingDocumentAccesses, setIsLoadingDocumentAccesses] = useState(false);
const formattedDocumentAccesses = editingAccess?.documentAccesses
useEffect(() => {
if (editingAccess?.id && loadedAccessIdRef.current !== editingAccess.id) {
loadedAccessIdRef.current = editingAccess.id;
setIsLoadingDocumentAccesses(true);
loadDocumentAccessesQuery({ accessId: editingAccess.id }, { fetchPolicy: 'network-only' });
}
}, [editingAccess?.id, loadDocumentAccessesQuery]);
const handleDocumentAccessesLoaded = useCallback((documentAccesses: DocumentAccessInfo[]) => {
setEditingDocumentAccesses(documentAccesses);
const activeIds = new Set<string>(
documentAccesses
.filter((docAccess) => docAccess.active)
.map((docAccess) => docAccess.document?.id || docAccess.report?.id || docAccess.trustCenterFile?.id)
.filter((id: unknown): id is string => typeof id === 'string')
);
setSelectedDocumentAccesses(activeIds);
setIsLoadingDocumentAccesses(false);
}, []);
const formattedDocumentAccesses = editingDocumentAccesses
?.map((docAccess) => getDocumentAccessInfo(docAccess, __))
?.filter((info) => info !== null) ?? [];
@@ -93,6 +199,7 @@ export default function TrustCenterAccessTab() {
type DocumentAccessType = {
id: string;
active: boolean;
requested: boolean;
document?: {
id: string;
title: string;
@@ -126,6 +233,8 @@ export default function TrustCenterAccessTab() {
type: __("Document"),
category: docAccess.document?.documentType,
id: docAccess.document?.id,
requested: docAccess.requested,
active: docAccess.active,
};
}
if (!!docAccess.report) {
@@ -135,6 +244,8 @@ export default function TrustCenterAccessTab() {
type: __("Report"),
category: docAccess.report?.audit?.framework?.name,
id: docAccess.report?.id,
requested: docAccess.requested,
active: docAccess.active,
};
}
if (!!docAccess.trustCenterFile) {
@@ -144,6 +255,8 @@ export default function TrustCenterAccessTab() {
type: __("File"),
category: docAccess.trustCenterFile?.category,
id: docAccess.trustCenterFile?.id,
requested: docAccess.requested,
active: docAccess.active,
};
}
@@ -157,28 +270,24 @@ export default function TrustCenterAccessTab() {
active: boolean;
hasAcceptedNonDisclosureAgreement: boolean;
createdAt: string;
documentAccesses: DocumentAccessType[];
lastTokenExpiresAt: string | null;
pendingRequestCount: number;
activeCount: number;
documentAccesses?: DocumentAccessType[];
};
const { data: trustCenterData, loadMore, hasNext, isLoadingNext } = useTrustCenterAccesses(organization.trustCenter?.id || "");
type AccessEdge = NonNullable<NonNullable<TrustCenterAccessGraph_accesses$data['accesses']>['edges']>[number];
type DocumentAccessEdge = NonNullable<NonNullable<NonNullable<AccessEdge>['node']['documentAccesses']>['edges']>[number];
const accesses: AccessType[] = trustCenterData?.node?.accesses?.edges?.map((edge: AccessEdge) => ({
const accesses: AccessType[] = trustCenterData?.node?.accesses?.edges?.map((edge: any) => ({
id: edge.node.id,
email: edge.node.email,
name: edge.node.name,
active: edge.node.active,
hasAcceptedNonDisclosureAgreement: edge.node.hasAcceptedNonDisclosureAgreement,
createdAt: edge.node.createdAt,
documentAccesses: edge.node.documentAccesses?.edges?.map((docEdge: DocumentAccessEdge) => ({
id: docEdge.node.id,
active: docEdge.node.active,
document: docEdge.node.document,
report: docEdge.node.report,
trustCenterFile: docEdge.node.trustCenterFile
})) ?? []
lastTokenExpiresAt: edge.node.lastTokenExpiresAt,
pendingRequestCount: edge.node.pendingRequestCount || 0,
activeCount: edge.node.activeCount || 0,
})) ?? [];
@@ -201,8 +310,6 @@ export default function TrustCenterAccessTab() {
connections: connectionId ? [connectionId] : [],
},
onSuccess: () => {
dialogRef.current?.close();
inviteForm.reset();
setPendingEditEmail(email);
},
});
@@ -220,32 +327,37 @@ export default function TrustCenterAccessTab() {
}, [deleteInvitation, trustCenterData]);
const getActiveDocumentIds = useCallback((access: AccessType) => {
return access.documentAccesses
.filter(docAccess => docAccess.active)
.map(docAccess => docAccess.document?.id || docAccess.report?.id || docAccess.trustCenterFile?.id)
.filter((id): id is string => id !== undefined);
}, []);
const handleEditAccess = useCallback((access: AccessType) => {
loadedAccessIdRef.current = null;
setEditingAccess(access);
setEditingDocumentAccesses([]);
setSelectedDocumentAccesses(new Set());
setIsLoadingDocumentAccesses(false);
editForm.reset({ name: access.name, active: access.active });
setSelectedDocumentAccesses(new Set(getActiveDocumentIds(access)));
editDialogRef.current?.open();
}, [editDialogRef, editForm, getActiveDocumentIds]);
}, [editDialogRef, editForm]);
useEffect(() => {
if (pendingEditEmail && accesses.length > 0) {
const newAccess = accesses.find(access => access.email === pendingEditEmail);
if (newAccess) {
setPendingEditEmail(null);
loadedAccessIdRef.current = null;
setEditingAccess(newAccess);
editForm.reset({ name: newAccess.name, active: true });
setSelectedDocumentAccesses(new Set(getActiveDocumentIds(newAccess)));
setEditingDocumentAccesses([]);
setSelectedDocumentAccesses(new Set());
editDialogRef.current?.open();
setTimeout(() => {
dialogRef.current?.close();
}, 50);
setTimeout(() => {
inviteForm.reset();
}, 300);
}
}
}, [accesses, pendingEditEmail, editForm, editDialogRef, getActiveDocumentIds]);
}, [accesses, pendingEditEmail, editForm, dialogRef, editDialogRef, inviteForm]);
const handleToggleDocumentAccess = useCallback((documentId: string, active: boolean) => {
setSelectedDocumentAccesses(prev => {
@@ -262,7 +374,7 @@ export default function TrustCenterAccessTab() {
const handleUpdateName = editForm.handleSubmit(async (data) => {
if (!editingAccess) return;
const { documentIds, reportIds, trustCenterFileIds } = editingAccess.documentAccesses.reduce(
const { documentIds, reportIds, trustCenterFileIds } = editingDocumentAccesses.reduce(
(acc, docAccess) => {
const id = docAccess.document?.id || docAccess.report?.id || docAccess.trustCenterFile?.id;
if (id && selectedDocumentAccesses.has(id)) {
@@ -294,6 +406,7 @@ export default function TrustCenterAccessTab() {
editDialogRef.current?.close();
setEditingAccess(null);
editForm.reset();
setEditingDocumentAccesses([]);
setSelectedDocumentAccesses(new Set());
},
});
@@ -309,7 +422,7 @@ export default function TrustCenterAccessTab() {
</p>
</div>
{organization.trustCenter?.id && (
<Button onClick={() => {
<Button icon={IconPlusLarge} onClick={() => {
inviteForm.reset();
dialogRef.current?.open();
}}>
@@ -318,126 +431,151 @@ export default function TrustCenterAccessTab() {
)}
</div>
<Card padded>
{!organization.trustCenter?.id ? (
<div className="text-center text-txt-tertiary py-8">
<Spinner />
</div>
) : accesses.length === 0 ? (
<div className="text-center text-txt-tertiary py-8">
{__("No external access granted yet")}
</div>
) : (
<>
<Table>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
<Th>{__("Email")}</Th>
<Th>{__("Date")}</Th>
<Th>{__("Active")}</Th>
<Th>{__("Documents")}</Th>
<Th>{__("NDA")}</Th>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{accesses.map((access) => {
const activeDocuments = access.documentAccesses.filter(doc => doc.active).length;
const totalDocuments = access.documentAccesses.length;
{!organization.trustCenter?.id ? (
<Table>
<Tbody>
<Tr>
<Td className="text-center text-txt-tertiary py-8">
<Spinner />
</Td>
</Tr>
</Tbody>
</Table>
) : accesses.length === 0 ? (
<Table>
<Tbody>
<Tr>
<Td className="text-center text-txt-tertiary py-8">
{__("No external access granted yet")}
</Td>
</Tr>
</Tbody>
</Table>
) : (
<>
<Table>
<Thead>
<Tr>
<Th>{__("Name")}</Th>
<Th>{__("Email")}</Th>
<Th>{__("Date")}</Th>
<Th>{__("Expires")}</Th>
<Th className="text-center">{__("Active")}</Th>
<Th className="text-center">{__("Access")}</Th>
<Th className="text-center">{__("Requests")}</Th>
<Th className="text-center">{__("NDA")}</Th>
<Th></Th>
</Tr>
</Thead>
<Tbody>
{accesses.map((access) => {
const isExpired = access.lastTokenExpiresAt ? new Date(access.lastTokenExpiresAt) < new Date() : false;
return (
<Tr
key={access.id}
onClick={() => handleEditAccess(access)}
className="cursor-pointer hover:bg-bg-secondary transition-colors"
>
<Td className="font-medium">{access.name}</Td>
<Td>{access.email}</Td>
<Td>
{formatDate(access.createdAt)}
</Td>
<Td>
return (
<Tr
key={access.id}
onClick={() => handleEditAccess(access)}
className="cursor-pointer hover:bg-bg-secondary transition-colors"
>
<Td className="font-medium">{access.name}</Td>
<Td>{access.email}</Td>
<Td>
{formatDate(access.createdAt)}
</Td>
<Td className={isExpired ? "text-txt-danger" : ""}>
{access.lastTokenExpiresAt ? formatDate(access.lastTokenExpiresAt) : "-"}
</Td>
<Td>
<div className="flex justify-center">
{access.active ? (
<IconCheckmark1 size={16} className="text-txt-success" />
) : (
<IconCrossLargeX size={16} className="text-txt-danger" />
)}
</Td>
<Td>
{totalDocuments > 0 ? `${activeDocuments}/${totalDocuments}` : '0/0'}
</Td>
<Td>
</div>
</Td>
<Td className="text-center">
{access.activeCount}
</Td>
<Td className="text-center">
{access.pendingRequestCount > 0 ? access.pendingRequestCount : ""}
</Td>
<Td>
<div className="flex justify-center">
{access.hasAcceptedNonDisclosureAgreement && (
<IconCheckmark1 size={16} className="text-txt-success" />
)}
</Td>
<Td noLink width={160} className="text-end">
<div
className="flex gap-2 justify-end"
onClick={(e) => e.stopPropagation()}
>
<Button
variant="secondary"
onClick={() => handleEditAccess(access)}
disabled={isUpdating}
icon={IconPencil}
/>
<Button
variant="secondary"
onClick={() => handleDelete(access.id)}
disabled={isDeleting}
icon={IconTrashCan}
/>
</div>
</Td>
</Tr>
);
})}
</Tbody>
</Table>
{hasNext && (
<Button
variant="tertiary"
onClick={loadMore}
disabled={isLoadingNext}
className="mt-3 mx-auto"
icon={IconChevronDown}
>
{isLoadingNext && <Spinner />}
{__("Show More")}
</Button>
)}
</>
)}
</Card>
<Td noLink width={160} className="text-end">
<div
className="flex gap-2 justify-end"
onClick={(e) => e.stopPropagation()}
>
<Button
variant="secondary"
onClick={() => handleEditAccess(access)}
disabled={isUpdating}
icon={IconPencil}
/>
<Button
variant="danger"
onClick={() => handleDelete(access.id)}
disabled={isDeleting}
icon={IconTrashCan}
/>
</div>
</Td>
</Tr>
);
})}
</Tbody>
</Table>
{hasNext && (
<Button
variant="tertiary"
onClick={loadMore}
disabled={isLoadingNext}
className="mt-3 mx-auto"
icon={IconChevronDown}
>
{isLoadingNext && <Spinner />}
{__("Show More")}
</Button>
)}
</>
)}
<Dialog
ref={dialogRef}
title={__("Invite External Access")}
>
<form onSubmit={handleInvite}>
<DialogContent padded className="space-y-4">
<p className="text-txt-secondary text-sm">
{__("Send a 7-day access token to an external person to view your trust center")}
</p>
<DialogContent padded className="space-y-6">
<div>
<p className="text-txt-secondary text-sm mb-4">
{__("Send a 30-day access token to an external person to view your trust center")}
</p>
<Field
label={__("Full Name")}
required
error={inviteForm.formState.errors.name?.message}
{...inviteForm.register("name")}
placeholder={__("John Doe")}
/>
<Field
label={__("Full Name")}
required
error={inviteForm.formState.errors.name?.message}
{...inviteForm.register("name")}
placeholder={__("John Doe")}
/>
<Field
label={__("Email Address")}
required
error={inviteForm.formState.errors.email?.message}
type="email"
{...inviteForm.register("email")}
placeholder={__("john@example.com")}
/>
<div className="mt-4">
<Field
label={__("Email Address")}
required
error={inviteForm.formState.errors.email?.message}
type="email"
{...inviteForm.register("email")}
placeholder={__("john@example.com")}
/>
</div>
</div>
</DialogContent>
<DialogFooter>
@@ -453,6 +591,12 @@ export default function TrustCenterAccessTab() {
ref={editDialogRef}
title={__("Edit Access")}
>
{documentAccessesQueryReference && (
<DocumentAccessesLoader
queryReference={documentAccessesQueryReference}
onDataLoaded={handleDocumentAccessesLoaded}
/>
)}
<form onSubmit={handleUpdateName}>
<DialogContent padded className="space-y-6">
<div>
@@ -484,11 +628,37 @@ export default function TrustCenterAccessTab() {
</div>
</div>
{formattedDocumentAccesses.length > 0 && (
<div>
<h4 className="font-medium text-txt-primary mb-4">
<div>
<div className="flex justify-between items-center mb-4">
<h4 className="font-medium text-txt-primary">
{__("Document Access Permissions")}
</h4>
{!isLoadingDocumentAccesses && formattedDocumentAccesses.length > 0 && (
<Button
type="button"
variant="tertiary"
onClick={() => {
if (selectedDocumentAccesses.size === formattedDocumentAccesses.length) {
setSelectedDocumentAccesses(new Set());
} else {
const allIds = new Set(formattedDocumentAccesses.map(doc => doc.id).filter((id): id is string => !!id));
setSelectedDocumentAccesses(allIds);
}
}}
className="text-xs h-7 min-h-7"
>
{selectedDocumentAccesses.size === formattedDocumentAccesses.length
? __("Clear All")
: __("Select All")}
</Button>
)}
</div>
{isLoadingDocumentAccesses ? (
<div className="flex justify-center items-center py-12">
<Spinner />
</div>
) : formattedDocumentAccesses.length > 0 ? (
<div className="bg-bg-secondary rounded-lg overflow-hidden">
<Table>
<Thead>
@@ -496,6 +666,7 @@ export default function TrustCenterAccessTab() {
<Th>{__("Name")}</Th>
<Th>{__("Type")}</Th>
<Th>{__("Category")}</Th>
<Th></Th>
<Th>
<div className="flex justify-end">
{__("Access")}
@@ -505,7 +676,7 @@ export default function TrustCenterAccessTab() {
</Thead>
<Tbody>
{formattedDocumentAccesses.map((info) => {
const { variant, name, type, category, id } = info;
const { variant, name, type, category, id, requested } = info;
return (
<Tr key={id}>
@@ -524,6 +695,13 @@ export default function TrustCenterAccessTab() {
{category || "-"}
</div>
</Td>
<Td>
{requested && (
<Badge variant="warning">
{__("Requested")}
</Badge>
)}
</Td>
<Td>
<div className="flex justify-end">
<Checkbox
@@ -540,13 +718,17 @@ export default function TrustCenterAccessTab() {
</Tbody>
</Table>
</div>
</div>
)}
) : (
<div className="text-center text-txt-tertiary py-8">
{__("No documents available")}
</div>
)}
</div>
</DialogContent>
<DialogFooter>
<Button type="submit" disabled={isUpdating}>
{isUpdating && <Spinner />}
<Button type="submit" disabled={isUpdating || isLoadingDocumentAccesses}>
{(isUpdating || isLoadingDocumentAccesses) && <Spinner />}
{__("Update Access")}
</Button>
</DialogFooter>

View File

@@ -1,4 +1,5 @@
import { Card, Spinner } from "@probo/ui";
import { Spinner } from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { useOutletContext } from "react-router";
import { TrustCenterAuditsCard } from "/components/trustCenter/TrustCenterAuditsCard";
import { useTrustCenterAuditUpdate } from "/hooks/graph/TrustCenterAuditGraph";
@@ -15,6 +16,7 @@ type ContextType = {
};
export default function TrustCenterAuditsTab() {
const { __ } = useTranslate();
const { organization } = useOutletContext<ContextType>();
const [updateAuditVisibility, isUpdatingAudits] = useTrustCenterAuditUpdate();
@@ -23,17 +25,20 @@ export default function TrustCenterAuditsTab() {
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h3 className="text-base font-medium">{__("Audits")}</h3>
<p className="text-sm text-txt-tertiary">
{__("Manage audit reports and compliance certifications")}
</p>
</div>
{isUpdatingAudits && <Spinner />}
</div>
<Card padded>
<TrustCenterAuditsCard
audits={audits}
params={{}}
disabled={isUpdatingAudits}
onChangeVisibility={updateAuditVisibility}
variant="table"
/>
</Card>
<TrustCenterAuditsCard
audits={audits}
params={{}}
disabled={isUpdatingAudits}
onChangeVisibility={updateAuditVisibility}
/>
</div>
);
}

View File

@@ -1,4 +1,5 @@
import { Card, Spinner } from "@probo/ui";
import { Spinner } from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { useOutletContext } from "react-router";
import { TrustCenterDocumentsCard } from "/components/trustCenter/TrustCenterDocumentsCard";
import { useUpdateDocumentVisibilityMutation } from "/hooks/graph/TrustCenterDocumentGraph";
@@ -15,6 +16,7 @@ type ContextType = {
};
export default function TrustCenterDocumentsTab() {
const { __ } = useTranslate();
const { organization } = useOutletContext<ContextType>();
const [updateDocumentVisibility, isUpdatingDocuments] = useUpdateDocumentVisibilityMutation();
@@ -23,17 +25,20 @@ export default function TrustCenterDocumentsTab() {
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h3 className="text-base font-medium">{__("Documents")}</h3>
<p className="text-sm text-txt-tertiary">
{__("Manage policies, procedures and compliance documents")}
</p>
</div>
{isUpdatingDocuments && <Spinner />}
</div>
<Card padded>
<TrustCenterDocumentsCard
documents={documents}
params={{}}
disabled={isUpdatingDocuments}
onChangeVisibility={updateDocumentVisibility}
variant="table"
/>
</Card>
<TrustCenterDocumentsCard
documents={documents}
params={{}}
disabled={isUpdatingDocuments}
onChangeVisibility={updateDocumentVisibility}
/>
</div>
);
}

View File

@@ -1,6 +1,5 @@
import {
Button,
Card,
Dialog,
DialogContent,
DialogFooter,
@@ -10,6 +9,7 @@ import {
Dropzone,
Option,
Badge,
IconPlusLarge,
} from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { useOutletContext } from "react-router";
@@ -200,7 +200,7 @@ export default function TrustCenterFilesTab() {
{__("Upload and manage files for your trust center")}
</p>
</div>
<Button onClick={() => createDialogRef.current?.open()}>
<Button icon={IconPlusLarge} onClick={() => createDialogRef.current?.open()}>
{__("Add File")}
</Button>
</div>
@@ -209,17 +209,14 @@ export default function TrustCenterFilesTab() {
<Spinner />
</div>
)}
<Card padded>
<TrustCenterFilesCard
files={files}
params={{}}
disabled={isUpdating || isDeleting}
onChangeVisibility={handleChangeVisibility}
onEdit={handleEdit}
onDelete={handleDeleteClick}
variant="table"
/>
</Card>
<TrustCenterFilesCard
files={files}
params={{}}
disabled={isUpdating || isDeleting}
onChangeVisibility={handleChangeVisibility}
onEdit={handleEdit}
onDelete={handleDeleteClick}
/>
<Dialog ref={createDialogRef} title={__("Add File")}>
<form onSubmit={handleCreate}>

View File

@@ -0,0 +1,248 @@
import { useTranslate } from "@probo/i18n";
import {
Button,
Card,
Checkbox,
Dropzone,
Spinner,
useToast,
IconTrashCan,
} from "@probo/ui";
import { useOutletContext } from "react-router";
import { useUpdateTrustCenterMutation, useUploadTrustCenterNDAMutation, useDeleteTrustCenterNDAMutation } from "/hooks/graph/TrustCenterGraph";
import type { TrustCenterGraphQuery$data } from "/hooks/graph/__generated__/TrustCenterGraphQuery.graphql";
import { useState } from "react";
import { SlackConnections } from "../../../components/organizations/SlackConnection";
type ContextType = {
organization: TrustCenterGraphQuery$data["organization"];
};
export default function TrustCenterOverviewTab() {
const { __ } = useTranslate();
const { toast } = useToast();
const { organization } = useOutletContext<ContextType>();
const [updateTrustCenter, isUpdating] = useUpdateTrustCenterMutation();
const [uploadNDA, isUploadingNDA] = useUploadTrustCenterNDAMutation();
const [deleteNDA, isDeletingNDA] = useDeleteTrustCenterNDAMutation();
const [isActive, setIsActive] = useState(organization.trustCenter?.active || false);
const handleToggleActive = async (active: boolean) => {
if (!organization.trustCenter?.id) {
toast({
title: __("Error"),
description: __("Trust center not found"),
variant: "error",
});
return;
}
setIsActive(active);
updateTrustCenter({
variables: {
input: {
trustCenterId: organization.trustCenter.id,
active,
},
},
onError: () => {
setIsActive(!active);
},
});
};
const handleNDAUpload = async (files: File[]) => {
if (!organization.trustCenter?.id) {
toast({
title: __("Error"),
description: __("Trust center not found"),
variant: "error",
});
return;
}
if (files.length === 0) return;
const file = files[0];
await uploadNDA({
variables: {
input: {
trustCenterId: organization.trustCenter.id,
fileName: file.name,
file: null,
},
},
uploadables: {
"input.file": file,
},
});
};
const handleNDADelete = async () => {
if (!organization.trustCenter?.id) {
toast({
title: __("Error"),
description: __("Trust center not found"),
variant: "error",
});
return;
}
if (!confirm(__("Are you sure you want to delete the NDA file?"))) {
return;
}
await deleteNDA({
variables: {
input: {
trustCenterId: organization.trustCenter.id,
},
},
});
};
const trustCenterUrl = organization.trustCenter?.id
? organization.customDomain?.domain
? `https://${organization.customDomain.domain}`
: `${window.location.origin}/trust/${organization.trustCenter.id}`
: null;
return (
<div className="space-y-6">
<div className="space-y-4">
<div className="flex items-center justify-between">
<h2 className="text-base font-medium">{__("Trust Center Status")}</h2>
{isUpdating && <Spinner />}
</div>
<Card padded className="space-y-4">
<div className="flex items-center justify-between">
<div className="space-y-1">
<h3 className="font-medium">{__("Activate Trust Center")}</h3>
<p className="text-sm text-txt-tertiary">
{__("Make your trust center publicly accessible to build customer confidence")}
</p>
</div>
<Checkbox
checked={isActive}
onChange={handleToggleActive}
/>
</div>
{isActive && trustCenterUrl && (
<div className="mt-4 p-4 bg-accent-light rounded-lg border border-accent">
<div className="flex items-center justify-between">
<div>
<h4 className="font-medium text-accent-dark">
{__("Your Trust Center is Live!")}
</h4>
<p className="text-sm text-accent-dark mt-1">
{__("Your customers can now access your trust center at:")}
</p>
<a
href={trustCenterUrl}
target="_blank"
rel="noopener noreferrer"
className="text-sm font-mono text-accent underline hover:no-underline"
>
{trustCenterUrl}
</a>
</div>
<Button
variant="secondary"
onClick={() => window.open(trustCenterUrl, '_blank', 'noopener,noreferrer')}
>
{__("View")}
</Button>
</div>
</div>
)}
{!isActive && (
<div className="mt-4 p-4 bg-tertiary rounded-lg border border-border-solid">
<h4 className="font-medium text-txt-secondary">
{__("Trust Center is Inactive")}
</h4>
<p className="text-sm text-txt-tertiary mt-1">
{__("Your trust center is currently not accessible to the public. Enable it to start sharing your compliance status.")}
</p>
</div>
)}
</Card>
</div>
<div className="space-y-4">
<div className="flex items-center justify-between">
<h2 className="text-base font-medium">{__("Non-Disclosure Agreement")}</h2>
{(isUploadingNDA || isDeletingNDA) && <Spinner />}
</div>
<Card padded className="space-y-4">
<div className="space-y-2">
{!organization.trustCenter?.ndaFileName ? (
<p className="text-sm text-txt-tertiary">
{__("Upload a Non-Disclosure Agreement that visitors must accept before accessing your trust center")}
</p>
) : (<></>)}
{organization.trustCenter?.ndaFileName ? (
<div className="space-y-3">
<div className="flex items-center justify-between">
<div className="space-y-1">
<div className="flex items-center gap-2">
<p className="text-sm font-medium">
{organization.trustCenter.ndaFileName || __("Non-Disclosure Agreement")}
</p>
</div>
<p className="text-xs text-txt-tertiary">
{__("Visitors will need to accept this NDA before accessing your trust center")}
</p>
</div>
<div className="flex items-center gap-2">
<Button
type="button"
variant="secondary"
onClick={() => {
if (organization.trustCenter?.ndaFileUrl) {
window.open(organization.trustCenter.ndaFileUrl, '_blank');
}
}}
>
{__("Download PDF")}
</Button>
<Button
variant="quaternary"
icon={IconTrashCan}
onClick={handleNDADelete}
disabled={isDeletingNDA}
/>
</div>
</div>
</div>
) : (
<Dropzone
description={__("Upload PDF files up to 10MB")}
isUploading={isUploadingNDA}
onDrop={handleNDAUpload}
accept={{
"application/pdf": [".pdf"],
}}
maxSize={10}
/>
)}
</div>
</Card>
</div>
<div className="space-y-4">
<h2 className="text-base font-medium">{__("Integrations")}</h2>
<Card padded>
<SlackConnections
organizationId={organization.id!}
slackConnections={organization.slackConnections?.edges?.map((edge) => edge.node) ?? []}
/>
</Card>
</div>
</div>
);
}

View File

@@ -1,26 +1,23 @@
import { useTranslate } from "@probo/i18n";
import { usePageTitle } from "@probo/hooks";
import {
Button,
Card,
Checkbox,
Dropzone,
PageHeader,
Spinner,
useToast,
Tabs,
TabLink,
TabItem,
IconTrashCan,
Badge,
IconSettingsGear2,
IconMedal,
IconCheckmark1,
IconPageTextLine,
IconFolder2,
IconStore,
IconPeopleAdd,
} from "@probo/ui";
import { usePreloadedQuery, type PreloadedQuery } from "react-relay";
import { trustCenterQuery, useUpdateTrustCenterMutation, useUploadTrustCenterNDAMutation, useDeleteTrustCenterNDAMutation } from "/hooks/graph/TrustCenterGraph";
import { trustCenterQuery } from "/hooks/graph/TrustCenterGraph";
import type { TrustCenterGraphQuery } from "/hooks/graph/__generated__/TrustCenterGraphQuery.graphql";
import { useState } from "react";
import { useOrganizationId } from "/hooks/useOrganizationId";
import { Outlet, useLocation, Link } from "react-router";
import { TrustCenterReferencesSection } from "/components/trustCenter/TrustCenterReferencesSection";
import { SlackConnections } from "../../../components/organizations/SlackConnection";
import { Outlet } from "react-router";
type Props = {
queryRef: PreloadedQuery<TrustCenterGraphQuery>;
@@ -28,100 +25,12 @@ type Props = {
export default function TrustCenterPage({ queryRef }: Props) {
const { __ } = useTranslate();
const { toast } = useToast();
const organizationId = useOrganizationId();
const location = useLocation();
const { organization } = usePreloadedQuery(trustCenterQuery, queryRef);
const [updateTrustCenter, isUpdating] = useUpdateTrustCenterMutation();
const [uploadNDA, isUploadingNDA] = useUploadTrustCenterNDAMutation();
const [deleteNDA, isDeletingNDA] = useDeleteTrustCenterNDAMutation();
const [isActive, setIsActive] = useState(organization.trustCenter?.active || false);
usePageTitle(__("Trust Center"));
const handleToggleActive = async (active: boolean) => {
if (!organization.trustCenter?.id) {
toast({
title: __("Error"),
description: __("Trust center not found"),
variant: "error",
});
return;
}
setIsActive(active);
updateTrustCenter({
variables: {
input: {
trustCenterId: organization.trustCenter.id,
active,
},
},
onError: () => {
setIsActive(!active);
},
});
};
const handleNDAUpload = async (files: File[]) => {
if (!organization.trustCenter?.id) {
toast({
title: __("Error"),
description: __("Trust center not found"),
variant: "error",
});
return;
}
if (files.length === 0) return;
const file = files[0];
await uploadNDA({
variables: {
input: {
trustCenterId: organization.trustCenter.id,
fileName: file.name,
file: null,
},
},
uploadables: {
"input.file": file,
},
});
};
const handleNDADelete = async () => {
if (!organization.trustCenter?.id) {
toast({
title: __("Error"),
description: __("Trust center not found"),
variant: "error",
});
return;
}
if (!confirm(__("Are you sure you want to delete the NDA file?"))) {
return;
}
await deleteNDA({
variables: {
input: {
trustCenterId: organization.trustCenter.id,
},
},
});
};
const trustCenterUrl = organization.trustCenter?.id
? organization.customDomain?.domain
? `https://${organization.customDomain.domain}`
: `${window.location.origin}/trust/${organization.trustCenter.id}`
: null;
const isActive = organization.trustCenter?.active || false;
return (
<div className="space-y-6">
@@ -130,173 +39,44 @@ export default function TrustCenterPage({ queryRef }: Props) {
description={__(
"Configure your public trust center to showcase your security and compliance posture."
)}
/>
>
<Badge variant={isActive ? "success" : "danger"}>
{isActive ? __("Active") : __("Inactive")}
</Badge>
</PageHeader>
<div className="space-y-4">
<div className="flex items-center justify-between">
<h2 className="text-base font-medium">{__("Trust Center Status")}</h2>
{isUpdating && <Spinner />}
</div>
<Card padded className="space-y-4">
<div className="flex items-center justify-between">
<div className="space-y-1">
<h3 className="font-medium">{__("Activate Trust Center")}</h3>
<p className="text-sm text-txt-tertiary">
{__("Make your trust center publicly accessible to build customer confidence")}
</p>
</div>
<Checkbox
checked={isActive}
onChange={handleToggleActive}
/>
</div>
<Tabs>
<TabLink to={`/organizations/${organizationId}/trust-center`} end>
<IconSettingsGear2 className="size-4" />
{__("Overview")}
</TabLink>
<TabLink to={`/organizations/${organizationId}/trust-center/trust-by`}>
<IconCheckmark1 className="size-4" />
{__("Trusted by")}
</TabLink>
<TabLink to={`/organizations/${organizationId}/trust-center/audits`}>
<IconMedal className="size-4" />
{__("Audits")}
</TabLink>
<TabLink to={`/organizations/${organizationId}/trust-center/documents`}>
<IconPageTextLine className="size-4" />
{__("Documents")}
</TabLink>
<TabLink to={`/organizations/${organizationId}/trust-center/files`}>
<IconFolder2 className="size-4" />
{__("Files")}
</TabLink>
<TabLink to={`/organizations/${organizationId}/trust-center/vendors`}>
<IconStore className="size-4" />
{__("Vendors")}
</TabLink>
<TabLink to={`/organizations/${organizationId}/trust-center/access`}>
<IconPeopleAdd className="size-4" />
{__("Access")}
</TabLink>
</Tabs>
{isActive && trustCenterUrl && (
<div className="mt-4 p-4 bg-accent-light rounded-lg border border-accent">
<div className="flex items-center justify-between">
<div>
<h4 className="font-medium text-accent-dark">
{__("Your Trust Center is Live!")}
</h4>
<p className="text-sm text-accent-dark mt-1">
{__("Your customers can now access your trust center at:")}
</p>
<a
href={trustCenterUrl}
target="_blank"
rel="noopener noreferrer"
className="text-sm font-mono text-accent underline hover:no-underline"
>
{trustCenterUrl}
</a>
</div>
<Button
variant="secondary"
onClick={() => window.open(trustCenterUrl, '_blank', 'noopener,noreferrer')}
>
{__("View")}
</Button>
</div>
</div>
)}
{!isActive && (
<div className="mt-4 p-4 bg-tertiary rounded-lg border border-border-solid">
<h4 className="font-medium text-txt-secondary">
{__("Trust Center is Inactive")}
</h4>
<p className="text-sm text-txt-tertiary mt-1">
{__("Your trust center is currently not accessible to the public. Enable it to start sharing your compliance status.")}
</p>
</div>
)}
</Card>
</div>
<div className="space-y-4">
<div className="flex items-center justify-between">
<h2 className="text-base font-medium">{__("Non-Disclosure Agreement")}</h2>
{(isUploadingNDA || isDeletingNDA) && <Spinner />}
</div>
<Card padded className="space-y-4">
<div className="space-y-2">
{!organization.trustCenter?.ndaFileName ? (
<p className="text-sm text-txt-tertiary">
{__("Upload a Non-Disclosure Agreement that visitors must accept before accessing your trust center")}
</p>
) : (<></>)}
{organization.trustCenter?.ndaFileName ? (
<div className="space-y-3">
<div className="flex items-center justify-between">
<div className="space-y-1">
<div className="flex items-center gap-2">
<p className="text-sm font-medium">
{organization.trustCenter.ndaFileName || __("Non-Disclosure Agreement")}
</p>
</div>
<p className="text-xs text-txt-tertiary">
{__("Visitors will need to accept this NDA before accessing your trust center")}
</p>
</div>
<div className="flex items-center gap-2">
<Button
type="button"
variant="secondary"
onClick={() => {
if (organization.trustCenter?.ndaFileUrl) {
window.open(organization.trustCenter.ndaFileUrl, '_blank');
}
}}
>
{__("Download PDF")}
</Button>
<Button
variant="quaternary"
icon={IconTrashCan}
onClick={handleNDADelete}
disabled={isDeletingNDA}
/>
</div>
</div>
</div>
) : (
<Dropzone
description={__("Upload PDF files up to 10MB")}
isUploading={isUploadingNDA}
onDrop={handleNDAUpload}
accept={{
"application/pdf": [".pdf"],
}}
maxSize={10}
/>
)}
</div>
</Card>
</div>
{organization.trustCenter?.id && (
<TrustCenterReferencesSection trustCenterId={organization.trustCenter.id} />
)}
<div className="space-y-4">
<h2 className="text-base font-medium">{__("Integrations")}</h2>
<Card padded>
<SlackConnections
organizationId={organization.id!}
slackConnections={organization.slackConnections?.edges?.map((edge) => edge.node) ?? []}
/>
</Card>
</div>
<div className="space-y-4">
<Tabs>
<TabItem
asChild
active={
location.pathname === `/organizations/${organizationId}/trust-center` ||
location.pathname === `/organizations/${organizationId}/trust-center/audits`
}
>
<Link to={`/organizations/${organizationId}/trust-center/audits`}>
{__("Audits")}
</Link>
</TabItem>
<TabLink to={`/organizations/${organizationId}/trust-center/vendors`}>
{__("Vendors")}
</TabLink>
<TabLink to={`/organizations/${organizationId}/trust-center/documents`}>
{__("Documents")}
</TabLink>
<TabLink to={`/organizations/${organizationId}/trust-center/files`}>
{__("Files")}
</TabLink>
<TabLink to={`/organizations/${organizationId}/trust-center/access`}>
{__("Access")}
</TabLink>
</Tabs>
<Outlet context={{ organization }} />
</div>
<Outlet context={{ organization }} />
</div>
);
}

View File

@@ -0,0 +1,22 @@
import { useOutletContext } from "react-router";
import { TrustCenterReferencesSection } from "/components/trustCenter/TrustCenterReferencesSection";
type ContextType = {
organization: {
trustCenter?: {
id: string;
} | null;
};
};
export default function TrustCenterReferencesTab() {
const { organization } = useOutletContext<ContextType>();
return (
<div className="space-y-4">
{organization.trustCenter?.id && (
<TrustCenterReferencesSection trustCenterId={organization.trustCenter.id} />
)}
</div>
);
}

View File

@@ -1,4 +1,5 @@
import { Card, Spinner } from "@probo/ui";
import { Spinner } from "@probo/ui";
import { useTranslate } from "@probo/i18n";
import { useOutletContext } from "react-router";
import { TrustCenterVendorsCard } from "/components/trustCenter/TrustCenterVendorsCard";
import { useTrustCenterVendorUpdate } from "/hooks/graph/TrustCenterVendorGraph";
@@ -15,6 +16,7 @@ type ContextType = {
};
export default function TrustCenterVendorsTab() {
const { __ } = useTranslate();
const { organization } = useOutletContext<ContextType>();
const [updateVendorVisibility, isUpdatingVendors] = useTrustCenterVendorUpdate();
@@ -23,17 +25,20 @@ export default function TrustCenterVendorsTab() {
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div>
<h3 className="text-base font-medium">{__("Vendors")}</h3>
<p className="text-sm text-txt-tertiary">
{__("Manage vendor assessments and third-party risk information")}
</p>
</div>
{isUpdatingVendors && <Spinner />}
</div>
<Card padded>
<TrustCenterVendorsCard
vendors={vendors}
params={{}}
disabled={isUpdatingVendors}
onToggleVisibility={updateVendorVisibility}
variant="table"
/>
</Card>
<TrustCenterVendorsCard
vendors={vendors}
params={{}}
disabled={isUpdatingVendors}
onToggleVisibility={updateVendorVisibility}
/>
</div>
);
}

View File

@@ -20,7 +20,14 @@ export const trustCenterRoutes = [
index: true,
fallback: LinkCardSkeleton,
Component: lazy(
() => import("/pages/organizations/trustCenter/TrustCenterAuditsTab")
() => import("/pages/organizations/trustCenter/TrustCenterOverviewTab")
),
},
{
path: "trust-by",
fallback: LinkCardSkeleton,
Component: lazy(
() => import("/pages/organizations/trustCenter/TrustCenterReferencesTab")
),
},
{
@@ -30,13 +37,6 @@ export const trustCenterRoutes = [
() => import("/pages/organizations/trustCenter/TrustCenterAuditsTab")
),
},
{
path: "vendors",
fallback: LinkCardSkeleton,
Component: lazy(
() => import("/pages/organizations/trustCenter/TrustCenterVendorsTab")
),
},
{
path: "documents",
fallback: LinkCardSkeleton,
@@ -51,6 +51,13 @@ export const trustCenterRoutes = [
() => import("/pages/organizations/trustCenter/TrustCenterFilesTab")
),
},
{
path: "vendors",
fallback: LinkCardSkeleton,
Component: lazy(
() => import("/pages/organizations/trustCenter/TrustCenterVendorsTab")
),
},
{
path: "access",
fallback: LinkCardSkeleton,

View File

@@ -42,7 +42,7 @@ probod:
cookie-name: "TCT"
cookie-domain: "localhost"
cookie-duration: 24
token-duration: 168
token-duration: 720
report-url-duration: 15
token-secret: "this-is-a-secure-secret-for-trust-token-signing-at-least-32-bytes"
scope: "trust_center_readonly"

View File

@@ -61,7 +61,7 @@ probod:
cookie-name: "TCT"
cookie-domain: "localhost"
cookie-duration: 24
token-duration: 168
token-duration: 720
report-url-duration: 15
token-secret: "trust-token-signing-secret"
scope: "trust_center_readonly"
@@ -397,7 +397,7 @@ Trust center cookie lifetime in hours.
#### `trust-auth.token-duration` (integer)
**Default**: `168`
**Default**: `720`
Trust center access token lifetime in hours.

View File

@@ -19,7 +19,9 @@ import (
"embed"
"fmt"
htmltemplate "html/template"
"math"
texttemplate "text/template"
"time"
)
//go:embed dist
@@ -148,17 +150,21 @@ func RenderFrameworkExport(hostname, fullName, downloadUrl string) (subject stri
return subjectFrameworkExport, textBody, htmlBody, err
}
func RenderTrustCenterAccess(hostname, fullName, organizationName, accessUrl string) (subject string, textBody string, htmlBody *string, err error) {
func RenderTrustCenterAccess(hostname, fullName, organizationName, accessUrl string, tokenDuration time.Duration) (subject string, textBody string, htmlBody *string, err error) {
durationInDays := int(math.Round(tokenDuration.Hours() / 24))
data := struct {
FullName string
OrganizationName string
AccessUrl string
LogoURL string
DurationInDays int
}{
FullName: fullName,
OrganizationName: organizationName,
AccessUrl: accessUrl,
LogoURL: fmt.Sprintf(logoURLFormat, hostname),
DurationInDays: durationInDays,
}
textBody, htmlBody, err = renderEmail(trustCenterAccessTextTemplate, trustCenterAccessHTMLTemplate, data)

View File

@@ -16,7 +16,7 @@ export const TrustCenterAccess = () => {
</Section>
<Text style={footerText}>
This link will expire in 7 days.
This link will expire in {'{{.DurationInDays}}'} days.
</Text>
</EmailLayout>
);

View File

@@ -6,6 +6,6 @@ You have been granted access to {{.OrganizationName}}'s Trust Center! Click the
{{.AccessUrl}}
This link will expire in 7 days.
This link will expire in {{.DurationInDays}} days.
Probo Inc, 490 Post St, STE 640, San Francisco, CA, 94102, US

View File

@@ -0,0 +1,10 @@
ALTER TABLE trust_center_accesses
ADD COLUMN last_token_expires_at TIMESTAMP WITH TIME ZONE;
UPDATE trust_center_accesses
SET last_token_expires_at = created_at + INTERVAL '7 days'
WHERE active = true AND last_token_expires_at IS NULL;
ALTER TABLE trust_center_document_accesses ADD COLUMN requested BOOLEAN NOT NULL DEFAULT false;
UPDATE trust_center_document_accesses SET requested = true WHERE active = false;
ALTER TABLE trust_center_document_accesses ALTER COLUMN requested DROP DEFAULT;

View File

@@ -41,6 +41,7 @@ type (
NDAFileID *gid.GID `db:"nda_file_id"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
LastTokenExpiresAt *time.Time `db:"last_token_expires_at"`
}
TrustCenterAccesses []*TrustCenterAccess
@@ -81,7 +82,8 @@ SELECT
has_accepted_non_disclosure_agreement_metadata,
nda_file_id,
created_at,
updated_at
updated_at,
last_token_expires_at
FROM
trust_center_accesses
WHERE
@@ -133,7 +135,8 @@ SELECT
has_accepted_non_disclosure_agreement_metadata,
nda_file_id,
created_at,
updated_at
updated_at,
last_token_expires_at
FROM
trust_center_accesses
WHERE
@@ -231,7 +234,8 @@ UPDATE trust_center_accesses SET
updated_at = @updated_at,
has_accepted_non_disclosure_agreement = @has_accepted_non_disclosure_agreement,
has_accepted_non_disclosure_agreement_metadata = @has_accepted_non_disclosure_agreement_metadata,
nda_file_id = @nda_file_id
nda_file_id = @nda_file_id,
last_token_expires_at = @last_token_expires_at
WHERE
%s
AND id = @id
@@ -246,7 +250,8 @@ WHERE
"updated_at": tca.UpdatedAt,
"has_accepted_non_disclosure_agreement": tca.HasAcceptedNonDisclosureAgreement,
"has_accepted_non_disclosure_agreement_metadata": tca.HasAcceptedNonDisclosureAgreementMetadata,
"nda_file_id": tca.NDAFileID,
"nda_file_id": tca.NDAFileID,
"last_token_expires_at": tca.LastTokenExpiresAt,
}
maps.Copy(args, scope.SQLArguments())
@@ -304,7 +309,8 @@ SELECT
has_accepted_non_disclosure_agreement_metadata,
nda_file_id,
created_at,
updated_at
updated_at,
last_token_expires_at
FROM
trust_center_accesses
WHERE

View File

@@ -16,6 +16,7 @@ package coredata
import (
"context"
"errors"
"fmt"
"maps"
"time"
@@ -34,13 +35,22 @@ type (
ReportID *gid.GID `db:"report_id"`
TrustCenterFileID *gid.GID `db:"trust_center_file_id"`
Active bool `db:"active"`
Requested bool `db:"requested"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
}
TrustCenterDocumentAccesses []*TrustCenterDocumentAccess
ErrTrustCenterDocumentAccessNotFound struct {
Identifier string
}
)
func (e ErrTrustCenterDocumentAccessNotFound) Error() string {
return fmt.Sprintf("trust center document access not found: %s", e.Identifier)
}
func (tcda *TrustCenterDocumentAccess) CursorKey(orderBy TrustCenterDocumentAccessOrderField) page.CursorKey {
switch orderBy {
case TrustCenterDocumentAccessOrderFieldCreatedAt:
@@ -64,6 +74,7 @@ SELECT
report_id,
trust_center_file_id,
active,
requested,
created_at,
updated_at
FROM
@@ -86,6 +97,9 @@ LIMIT 1;
access, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[TrustCenterDocumentAccess])
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return &ErrTrustCenterDocumentAccessNotFound{Identifier: accessID.String()}
}
return fmt.Errorf("cannot collect trust center document access: %w", err)
}
@@ -109,6 +123,7 @@ SELECT
report_id,
trust_center_file_id,
active,
requested,
created_at,
updated_at
FROM
@@ -158,6 +173,7 @@ SELECT
report_id,
trust_center_file_id,
active,
requested,
created_at,
updated_at
FROM
@@ -206,6 +222,7 @@ INSERT INTO trust_center_document_accesses (
report_id,
trust_center_file_id,
active,
requested,
created_at,
updated_at
) VALUES (
@@ -216,6 +233,7 @@ INSERT INTO trust_center_document_accesses (
@report_id,
@trust_center_file_id,
@active,
@requested,
@created_at,
@updated_at
)
@@ -229,6 +247,7 @@ INSERT INTO trust_center_document_accesses (
"report_id": tcda.ReportID,
"trust_center_file_id": tcda.TrustCenterFileID,
"active": tcda.Active,
"requested": tcda.Requested,
"created_at": tcda.CreatedAt,
"updated_at": tcda.UpdatedAt,
}
@@ -332,7 +351,76 @@ WHERE
return count, nil
}
func (tcdas *TrustCenterDocumentAccesses) LoadByTrustCenterAccessID(
func (tcdas *TrustCenterDocumentAccesses) CountPendingRequestByTrustCenterAccessID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
trustCenterAccessID gid.GID,
) (int, error) {
q := `
SELECT
COUNT(id)
FROM
trust_center_document_accesses
WHERE
%s
AND trust_center_access_id = @trust_center_access_id
AND requested = true
AND active = false
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"trust_center_access_id": trustCenterAccessID,
}
maps.Copy(args, scope.SQLArguments())
row := conn.QueryRow(ctx, q, args)
var count int
if err := row.Scan(&count); err != nil {
return 0, fmt.Errorf("cannot scan count: %w", err)
}
return count, nil
}
func (tcdas *TrustCenterDocumentAccesses) CountActiveByTrustCenterAccessID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
trustCenterAccessID gid.GID,
) (int, error) {
q := `
SELECT
COUNT(id)
FROM
trust_center_document_accesses
WHERE
%s
AND trust_center_access_id = @trust_center_access_id
AND active = true
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{
"trust_center_access_id": trustCenterAccessID,
}
maps.Copy(args, scope.SQLArguments())
row := conn.QueryRow(ctx, q, args)
var count int
if err := row.Scan(&count); err != nil {
return 0, fmt.Errorf("cannot scan count: %w", err)
}
return count, nil
}
func (tcdas *TrustCenterDocumentAccesses) LoadAvailableByTrustCenterAccessID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
@@ -340,6 +428,79 @@ func (tcdas *TrustCenterDocumentAccesses) LoadByTrustCenterAccessID(
cursor *page.Cursor[TrustCenterDocumentAccessOrderField],
) error {
q := `
WITH organization AS (
SELECT tc.organization_id
FROM trust_center_accesses tca
INNER JOIN trust_centers tc ON tca.trust_center_id = tc.id
WHERE tca.tenant_id = @tenant_id
AND tca.id = @trust_center_access_id
),
tenant_organization AS (
SELECT o.id AS organization_id
FROM organizations o
WHERE %s
),
all_items AS (
SELECT
d.id AS item_id,
d.id AS document_id,
NULL::text AS report_id,
NULL::text AS trust_center_file_id,
d.created_at AS item_created_at,
d.updated_at AS item_updated_at
FROM documents d, tenant_organization o
WHERE d.organization_id = o.organization_id
AND d.deleted_at IS NULL
AND d.trust_center_visibility = 'PRIVATE'::trust_center_visibility
UNION ALL
SELECT
r.id AS item_id,
NULL::text AS document_id,
r.id AS report_id,
NULL::text AS trust_center_file_id,
r.created_at AS item_created_at,
r.updated_at AS item_updated_at
FROM audits r, tenant_organization o
WHERE r.organization_id = o.organization_id
AND r.trust_center_visibility = 'PRIVATE'::trust_center_visibility
UNION ALL
SELECT
tcf.id AS item_id,
NULL::text AS document_id,
NULL::text AS report_id,
tcf.id AS trust_center_file_id,
tcf.created_at AS item_created_at,
tcf.updated_at AS item_updated_at
FROM trust_center_files tcf, tenant_organization o
WHERE tcf.organization_id = o.organization_id
AND tcf.trust_center_visibility = 'PRIVATE'::trust_center_visibility
),
final_items AS (
SELECT
COALESCE(tcda.id, ai.item_id) AS id,
tcda.tenant_id,
@trust_center_access_id AS trust_center_access_id,
ai.document_id,
ai.report_id,
ai.trust_center_file_id,
COALESCE(tcda.active, false) AS active,
COALESCE(tcda.requested, false) AS requested,
COALESCE(tcda.created_at, ai.item_created_at) AS created_at,
COALESCE(tcda.updated_at, ai.item_updated_at) AS updated_at
FROM all_items ai
LEFT JOIN trust_center_document_accesses tcda ON (
tcda.trust_center_access_id = @trust_center_access_id
AND (
(tcda.document_id = ai.document_id AND ai.document_id IS NOT NULL)
OR (tcda.report_id = ai.report_id AND ai.report_id IS NOT NULL)
OR (tcda.trust_center_file_id = ai.trust_center_file_id AND ai.trust_center_file_id IS NOT NULL)
)
)
)
SELECT
id,
trust_center_access_id,
@@ -347,14 +508,11 @@ SELECT
report_id,
trust_center_file_id,
active,
requested,
created_at,
updated_at
FROM
trust_center_document_accesses
WHERE
%s
AND trust_center_access_id = @trust_center_access_id
AND %s
FROM final_items
WHERE %s
`
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
@@ -394,6 +552,7 @@ SELECT
report_id,
trust_center_file_id,
active,
requested,
created_at,
updated_at
FROM
@@ -464,10 +623,6 @@ func ActivateByDocumentIDs(
documentIDs []gid.GID,
updatedAt time.Time,
) error {
if len(documentIDs) == 0 {
return nil
}
q := `
UPDATE trust_center_document_accesses
SET active = true, updated_at = @updated_at
@@ -502,10 +657,6 @@ func ActivateByReportIDs(
reportIDs []gid.GID,
updatedAt time.Time,
) error {
if len(reportIDs) == 0 {
return nil
}
q := `
UPDATE trust_center_document_accesses
SET active = true, updated_at = @updated_at
@@ -538,6 +689,7 @@ func (tcdas TrustCenterDocumentAccesses) BulkInsertDocumentAccesses(
scope Scoper,
trustCenterAccessID gid.GID,
documentIDs []gid.GID,
requested bool,
createdAt time.Time,
) error {
if len(documentIDs) == 0 {
@@ -554,13 +706,15 @@ WITH document_access_data AS (
null::text AS report_id,
null::text AS trust_center_file_id,
false AS active,
@requested::boolean AS requested,
@created_at::timestamptz AS created_at,
@updated_at::timestamptz AS updated_at
)
INSERT INTO trust_center_document_accesses (
id, tenant_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, created_at, updated_at
id, tenant_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, requested, created_at, updated_at
)
SELECT * FROM document_access_data
ON CONFLICT DO NOTHING
`
args := pgx.StrictNamedArgs{
@@ -568,6 +722,7 @@ SELECT * FROM document_access_data
"trust_center_access_id": trustCenterAccessID,
"document_ids": documentIDs,
"trust_center_document_access_entity_type": TrustCenterDocumentAccessEntityType,
"requested": requested,
"created_at": createdAt,
"updated_at": createdAt,
}
@@ -585,6 +740,7 @@ func (tcdas TrustCenterDocumentAccesses) BulkInsertReportAccesses(
scope Scoper,
trustCenterAccessID gid.GID,
reportIDs []gid.GID,
requested bool,
createdAt time.Time,
) error {
if len(reportIDs) == 0 {
@@ -601,13 +757,15 @@ WITH report_access_data AS (
unnest(@report_ids::text[]) AS report_id,
null::text AS trust_center_file_id,
false AS active,
@requested::boolean AS requested,
@created_at::timestamptz AS created_at,
@updated_at::timestamptz AS updated_at
)
INSERT INTO trust_center_document_accesses (
id, tenant_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, created_at, updated_at
id, tenant_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, requested, created_at, updated_at
)
SELECT * FROM report_access_data
ON CONFLICT DO NOTHING
`
args := pgx.StrictNamedArgs{
@@ -641,6 +799,7 @@ SELECT
report_id,
trust_center_file_id,
active,
requested,
created_at,
updated_at
FROM
@@ -715,6 +874,7 @@ func (tcdas TrustCenterDocumentAccesses) BulkInsertTrustCenterFileAccesses(
scope Scoper,
trustCenterAccessID gid.GID,
trustCenterFileIDs []gid.GID,
requested bool,
createdAt time.Time,
) error {
q := `
@@ -727,13 +887,15 @@ WITH trust_center_file_access_data AS (
null::text AS report_id,
unnest(@trust_center_file_ids::text[]) AS trust_center_file_id,
false AS active,
@requested::boolean AS requested,
@created_at::timestamptz AS created_at,
@updated_at::timestamptz AS updated_at
)
INSERT INTO trust_center_document_accesses (
id, tenant_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, created_at, updated_at
id, tenant_id, trust_center_access_id, document_id, report_id, trust_center_file_id, active, requested, created_at, updated_at
)
SELECT * FROM trust_center_file_access_data
ON CONFLICT DO NOTHING
`
args := pgx.StrictNamedArgs{
@@ -741,6 +903,7 @@ SELECT * FROM trust_center_file_access_data
"trust_center_document_access_entity_type": TrustCenterDocumentAccessEntityType,
"trust_center_access_id": trustCenterAccessID,
"trust_center_file_ids": trustCenterFileIDs,
"requested": requested,
"created_at": createdAt,
"updated_at": createdAt,
}

View File

@@ -80,7 +80,7 @@ func (s TrustCenterAccessService) ListForTrustCenterID(
return page.NewPage(accesses, cursor), nil
}
func (s TrustCenterAccessService) ListDocumentAccesses(
func (s TrustCenterAccessService) ListAvailableDocumentAccesses(
ctx context.Context,
trustCenterAccessID gid.GID,
cursor *page.Cursor[coredata.TrustCenterDocumentAccessOrderField],
@@ -90,7 +90,7 @@ func (s TrustCenterAccessService) ListDocumentAccesses(
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
return documentAccesses.LoadByTrustCenterAccessID(ctx, conn, s.svc.scope, trustCenterAccessID, cursor)
return documentAccesses.LoadAvailableByTrustCenterAccessID(ctx, conn, s.svc.scope, trustCenterAccessID, cursor)
},
)
@@ -163,6 +163,50 @@ func (s TrustCenterAccessService) CountDocumentAccesses(
return count, nil
}
func (s TrustCenterAccessService) CountPendingRequestDocumentAccesses(
ctx context.Context,
trustCenterAccessID gid.GID,
) (int, error) {
var count int
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
var documentAccesses coredata.TrustCenterDocumentAccesses
var err error
count, err = documentAccesses.CountPendingRequestByTrustCenterAccessID(ctx, conn, s.svc.scope, trustCenterAccessID)
return err
},
)
if err != nil {
return 0, err
}
return count, nil
}
func (s TrustCenterAccessService) CountActiveDocumentAccesses(
ctx context.Context,
trustCenterAccessID gid.GID,
) (int, error) {
var count int
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
var documentAccesses coredata.TrustCenterDocumentAccesses
var err error
count, err = documentAccesses.CountActiveByTrustCenterAccessID(ctx, conn, s.svc.scope, trustCenterAccessID)
return err
},
)
if err != nil {
return 0, err
}
return count, nil
}
func (s TrustCenterAccessService) ValidateToken(
ctx context.Context,
tokenString string,
@@ -210,50 +254,6 @@ func (s TrustCenterAccessService) Create(
err := s.svc.pg.WithTx(
ctx,
func(tx pg.Conn) error {
trustCenter := &coredata.TrustCenter{}
if err := trustCenter.LoadByID(ctx, tx, s.svc.scope, req.TrustCenterID); err != nil {
return fmt.Errorf("cannot load trust center: %w", err)
}
organizationID := trustCenter.OrganizationID
documentIDs := []gid.GID{}
reportIDs := []gid.GID{}
trustCenterFileIDs := []gid.GID{}
var allDocuments coredata.Documents
filter := coredata.NewDocumentTrustCenterFilter()
if err := allDocuments.LoadAllByOrganizationID(ctx, tx, s.svc.scope, organizationID, filter); err != nil {
return fmt.Errorf("cannot list documents: %w", err)
}
for _, doc := range allDocuments {
documentIDs = append(documentIDs, doc.ID)
}
var allAudits coredata.Audits
auditFilter := coredata.NewAuditTrustCenterFilter()
if err := allAudits.LoadAllByOrganizationID(ctx, tx, s.svc.scope, organizationID, auditFilter); err != nil {
return fmt.Errorf("cannot list audits: %w", err)
}
for _, audit := range allAudits {
if audit.ReportID != nil {
reportIDs = append(reportIDs, *audit.ReportID)
}
}
var allTrustCenterFiles coredata.TrustCenterFiles
if err := allTrustCenterFiles.LoadAllByOrganizationID(ctx, tx, s.svc.scope, organizationID); err != nil {
return fmt.Errorf("cannot list trust center files: %w", err)
}
for _, file := range allTrustCenterFiles {
trustCenterFileIDs = append(trustCenterFileIDs, file.ID)
}
access = &coredata.TrustCenterAccess{
ID: gid.New(s.svc.scope.GetTenantID(), coredata.TrustCenterAccessEntityType),
TenantID: s.svc.scope.GetTenantID(),
@@ -270,19 +270,6 @@ func (s TrustCenterAccessService) Create(
return fmt.Errorf("cannot insert trust center access: %w", err)
}
var documentAccesses coredata.TrustCenterDocumentAccesses
if err := documentAccesses.BulkInsertDocumentAccesses(ctx, tx, s.svc.scope, access.ID, documentIDs, now); err != nil {
return fmt.Errorf("cannot bulk insert trust center document accesses: %w", err)
}
if err := documentAccesses.BulkInsertReportAccesses(ctx, tx, s.svc.scope, access.ID, reportIDs, now); err != nil {
return fmt.Errorf("cannot bulk insert trust center report accesses: %w", err)
}
if err := documentAccesses.BulkInsertTrustCenterFileAccesses(ctx, tx, s.svc.scope, access.ID, trustCenterFileIDs, now); err != nil {
return fmt.Errorf("cannot bulk insert trust center file accesses: %w", err)
}
return nil
},
)
@@ -328,28 +315,8 @@ func (s TrustCenterAccessService) Update(
return fmt.Errorf("cannot update trust center access: %w", err)
}
if req.DocumentIDs != nil || req.ReportIDs != nil || req.TrustCenterFileIDs != nil {
if err := coredata.DeactivateByTrustCenterAccessID(ctx, tx, s.svc.scope, access.ID, now); err != nil {
return fmt.Errorf("cannot deactivate existing document accesses: %w", err)
}
if req.DocumentIDs != nil {
if err := coredata.ActivateByDocumentIDs(ctx, tx, s.svc.scope, access.ID, req.DocumentIDs, now); err != nil {
return fmt.Errorf("cannot activate document accesses: %w", err)
}
}
if req.ReportIDs != nil {
if err := coredata.ActivateByReportIDs(ctx, tx, s.svc.scope, access.ID, req.ReportIDs, now); err != nil {
return fmt.Errorf("cannot activate report accesses: %w", err)
}
}
if req.TrustCenterFileIDs != nil {
if err := coredata.ActivateByTrustCenterFileIDs(ctx, tx, s.svc.scope, access.ID, req.TrustCenterFileIDs, now); err != nil {
return fmt.Errorf("cannot activate trust center file accesses: %w", err)
}
}
if err := s.upsertDocumentAccesses(ctx, tx, access.ID, req.DocumentIDs, req.ReportIDs, req.TrustCenterFileIDs, now); err != nil {
return fmt.Errorf("cannot upsert document accesses: %w", err)
}
if shouldSendEmail {
@@ -393,6 +360,56 @@ func (s TrustCenterAccessService) Delete(
return err
}
func (s TrustCenterAccessService) upsertDocumentAccesses(
ctx context.Context,
tx pg.Conn,
accessID gid.GID,
documentIDs []gid.GID,
reportIDs []gid.GID,
trustCenterFileIDs []gid.GID,
now time.Time,
) error {
if documentIDs == nil && reportIDs == nil && trustCenterFileIDs == nil {
return nil
}
if err := coredata.DeactivateByTrustCenterAccessID(ctx, tx, s.svc.scope, accessID, now); err != nil {
return fmt.Errorf("cannot deactivate existing document accesses: %w", err)
}
if documentIDs != nil {
var documentAccesses coredata.TrustCenterDocumentAccesses
if err := documentAccesses.BulkInsertDocumentAccesses(ctx, tx, s.svc.scope, accessID, documentIDs, false, now); err != nil {
return fmt.Errorf("cannot create document accesses: %w", err)
}
if err := coredata.ActivateByDocumentIDs(ctx, tx, s.svc.scope, accessID, documentIDs, now); err != nil {
return fmt.Errorf("cannot activate document accesses: %w", err)
}
}
if reportIDs != nil {
var documentAccesses coredata.TrustCenterDocumentAccesses
if err := documentAccesses.BulkInsertReportAccesses(ctx, tx, s.svc.scope, accessID, reportIDs, false, now); err != nil {
return fmt.Errorf("cannot create report accesses: %w", err)
}
if err := coredata.ActivateByReportIDs(ctx, tx, s.svc.scope, accessID, reportIDs, now); err != nil {
return fmt.Errorf("cannot activate report accesses: %w", err)
}
}
if trustCenterFileIDs != nil {
var documentAccesses coredata.TrustCenterDocumentAccesses
if err := documentAccesses.BulkInsertTrustCenterFileAccesses(ctx, tx, s.svc.scope, accessID, trustCenterFileIDs, false, now); err != nil {
return fmt.Errorf("cannot create trust center file accesses: %w", err)
}
if err := coredata.ActivateByTrustCenterFileIDs(ctx, tx, s.svc.scope, accessID, trustCenterFileIDs, now); err != nil {
return fmt.Errorf("cannot activate trust center file accesses: %w", err)
}
}
return nil
}
func (s TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Conn, access *coredata.TrustCenterAccess) error {
accessToken, err := statelesstoken.NewToken(
s.svc.trustConfig.TokenSecret,
@@ -445,6 +462,15 @@ func (s TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Con
}.Encode(),
}
now := time.Now()
expiresAt := now.Add(s.svc.trustConfig.TokenDuration)
access.LastTokenExpiresAt = &expiresAt
access.UpdatedAt = now
if err := access.Update(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot update trust center access with expiration: %w", err)
}
return s.sendTrustCenterAccessEmail(ctx, tx, access.Name, access.Email, organization.Name, accessURL.String())
}
@@ -461,6 +487,7 @@ func (s TrustCenterAccessService) sendTrustCenterAccessEmail(
name,
companyName,
accessURL,
s.svc.trustConfig.TokenDuration,
)
if err != nil {
return fmt.Errorf("cannot render trust center access email: %w", err)

View File

@@ -54,10 +54,6 @@ type (
TrustCenterVisibility *coredata.TrustCenterVisibility
}
GetTrustCenterFileRequest struct {
ID gid.GID
}
DeleteTrustCenterFileRequest struct {
ID gid.GID
}
@@ -114,21 +110,18 @@ func (s TrustCenterFileService) CountForOrganizationID(
func (s TrustCenterFileService) Get(
ctx context.Context,
req *GetTrustCenterFileRequest,
id gid.GID,
) (*coredata.TrustCenterFile, error) {
var file *coredata.TrustCenterFile
err := s.svc.pg.WithConn(
ctx,
func(conn pg.Conn) error {
file = &coredata.TrustCenterFile{}
if err := file.LoadByID(ctx, conn, s.svc.scope, req.ID); err != nil {
return fmt.Errorf("cannot load trust center file: %w", err)
}
err := s.svc.pg.WithConn(ctx, func(conn pg.Conn) error {
file = &coredata.TrustCenterFile{}
if err := file.LoadByID(ctx, conn, s.svc.scope, id); err != nil {
return fmt.Errorf("cannot load trust center file: %w", err)
}
return nil
},
)
return nil
})
if err != nil {
return nil, err

View File

@@ -123,7 +123,7 @@ func New() *Implm {
CookieName: "TCT",
CookieDomain: "localhost",
CookieDuration: 24,
TokenDuration: 168,
TokenDuration: 720,
ReportURLDuration: 15,
TokenSecret: "this-is-a-secure-secret-for-trust-token-signing-at-least-32-bytes",
Scope: "trust_center_readonly",

View File

@@ -2407,8 +2407,11 @@ type TrustCenterAccess implements Node {
hasAcceptedNonDisclosureAgreement: Boolean!
createdAt: Datetime!
updatedAt: Datetime!
lastTokenExpiresAt: Datetime
pendingRequestCount: Int! @goField(forceResolver: true)
activeCount: Int! @goField(forceResolver: true)
documentAccesses(
availableDocumentAccesses(
first: Int
after: CursorKey
last: Int
@@ -2417,12 +2420,12 @@ type TrustCenterAccess implements Node {
): TrustCenterDocumentAccessConnection! @goField(forceResolver: true)
}
type TrustCenterDocumentAccess implements Node {
id: ID!
type TrustCenterDocumentAccess
@goModel(
model: "github.com/getprobo/probo/pkg/server/api/console/v1/types.TrustCenterDocumentAccess"
) {
active: Boolean!
createdAt: Datetime!
updatedAt: Datetime!
trustCenterAccess: TrustCenterAccess! @goField(forceResolver: true)
requested: Boolean!
document: Document @goField(forceResolver: true)
report: Report @goField(forceResolver: true)
trustCenterFile: TrustCenterFile @goField(forceResolver: true)

View File

@@ -1287,12 +1287,15 @@ type ComplexityRoot struct {
TrustCenterAccess struct {
Active func(childComplexity int) int
ActiveCount func(childComplexity int) int
AvailableDocumentAccesses func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]) int
CreatedAt func(childComplexity int) int
DocumentAccesses func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]) int
Email func(childComplexity int) int
HasAcceptedNonDisclosureAgreement func(childComplexity int) int
ID func(childComplexity int) int
LastTokenExpiresAt func(childComplexity int) int
Name func(childComplexity int) int
PendingRequestCount func(childComplexity int) int
UpdatedAt func(childComplexity int) int
}
@@ -1312,14 +1315,11 @@ type ComplexityRoot struct {
}
TrustCenterDocumentAccess struct {
Active func(childComplexity int) int
CreatedAt func(childComplexity int) int
Document func(childComplexity int) int
ID func(childComplexity int) int
Report func(childComplexity int) int
TrustCenterAccess func(childComplexity int) int
TrustCenterFile func(childComplexity int) int
UpdatedAt func(childComplexity int) int
Active func(childComplexity int) int
Document func(childComplexity int) int
Report func(childComplexity int) int
Requested func(childComplexity int) int
TrustCenterFile func(childComplexity int) int
}
TrustCenterDocumentAccessConnection struct {
@@ -2017,10 +2017,11 @@ type TrustCenterResolver interface {
References(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterReferenceOrderField]) (*types.TrustCenterReferenceConnection, error)
}
type TrustCenterAccessResolver interface {
DocumentAccesses(ctx context.Context, obj *types.TrustCenterAccess, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]) (*types.TrustCenterDocumentAccessConnection, error)
PendingRequestCount(ctx context.Context, obj *types.TrustCenterAccess) (int, error)
ActiveCount(ctx context.Context, obj *types.TrustCenterAccess) (int, error)
AvailableDocumentAccesses(ctx context.Context, obj *types.TrustCenterAccess, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]) (*types.TrustCenterDocumentAccessConnection, error)
}
type TrustCenterDocumentAccessResolver interface {
TrustCenterAccess(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.TrustCenterAccess, error)
Document(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Document, error)
Report(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Report, error)
TrustCenterFile(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.TrustCenterFile, error)
@@ -7609,6 +7610,25 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenterAccess.Active(childComplexity), true
case "TrustCenterAccess.activeCount":
if e.complexity.TrustCenterAccess.ActiveCount == nil {
break
}
return e.complexity.TrustCenterAccess.ActiveCount(childComplexity), true
case "TrustCenterAccess.availableDocumentAccesses":
if e.complexity.TrustCenterAccess.AvailableDocumentAccesses == nil {
break
}
args, err := ec.field_TrustCenterAccess_availableDocumentAccesses_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.TrustCenterAccess.AvailableDocumentAccesses(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.OrderBy[coredata.TrustCenterDocumentAccessOrderField])), true
case "TrustCenterAccess.createdAt":
if e.complexity.TrustCenterAccess.CreatedAt == nil {
break
@@ -7616,18 +7636,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenterAccess.CreatedAt(childComplexity), true
case "TrustCenterAccess.documentAccesses":
if e.complexity.TrustCenterAccess.DocumentAccesses == nil {
break
}
args, err := ec.field_TrustCenterAccess_documentAccesses_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.TrustCenterAccess.DocumentAccesses(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.OrderBy[coredata.TrustCenterDocumentAccessOrderField])), true
case "TrustCenterAccess.email":
if e.complexity.TrustCenterAccess.Email == nil {
break
@@ -7649,6 +7657,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenterAccess.ID(childComplexity), true
case "TrustCenterAccess.lastTokenExpiresAt":
if e.complexity.TrustCenterAccess.LastTokenExpiresAt == nil {
break
}
return e.complexity.TrustCenterAccess.LastTokenExpiresAt(childComplexity), true
case "TrustCenterAccess.name":
if e.complexity.TrustCenterAccess.Name == nil {
break
@@ -7656,6 +7671,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenterAccess.Name(childComplexity), true
case "TrustCenterAccess.pendingRequestCount":
if e.complexity.TrustCenterAccess.PendingRequestCount == nil {
break
}
return e.complexity.TrustCenterAccess.PendingRequestCount(childComplexity), true
case "TrustCenterAccess.updatedAt":
if e.complexity.TrustCenterAccess.UpdatedAt == nil {
break
@@ -7712,13 +7734,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenterDocumentAccess.Active(childComplexity), true
case "TrustCenterDocumentAccess.createdAt":
if e.complexity.TrustCenterDocumentAccess.CreatedAt == nil {
break
}
return e.complexity.TrustCenterDocumentAccess.CreatedAt(childComplexity), true
case "TrustCenterDocumentAccess.document":
if e.complexity.TrustCenterDocumentAccess.Document == nil {
break
@@ -7726,13 +7741,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenterDocumentAccess.Document(childComplexity), true
case "TrustCenterDocumentAccess.id":
if e.complexity.TrustCenterDocumentAccess.ID == nil {
break
}
return e.complexity.TrustCenterDocumentAccess.ID(childComplexity), true
case "TrustCenterDocumentAccess.report":
if e.complexity.TrustCenterDocumentAccess.Report == nil {
break
@@ -7740,12 +7748,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenterDocumentAccess.Report(childComplexity), true
case "TrustCenterDocumentAccess.trustCenterAccess":
if e.complexity.TrustCenterDocumentAccess.TrustCenterAccess == nil {
case "TrustCenterDocumentAccess.requested":
if e.complexity.TrustCenterDocumentAccess.Requested == nil {
break
}
return e.complexity.TrustCenterDocumentAccess.TrustCenterAccess(childComplexity), true
return e.complexity.TrustCenterDocumentAccess.Requested(childComplexity), true
case "TrustCenterDocumentAccess.trustCenterFile":
if e.complexity.TrustCenterDocumentAccess.TrustCenterFile == nil {
@@ -7754,13 +7762,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.TrustCenterDocumentAccess.TrustCenterFile(childComplexity), true
case "TrustCenterDocumentAccess.updatedAt":
if e.complexity.TrustCenterDocumentAccess.UpdatedAt == nil {
break
}
return e.complexity.TrustCenterDocumentAccess.UpdatedAt(childComplexity), true
case "TrustCenterDocumentAccessConnection.edges":
if e.complexity.TrustCenterDocumentAccessConnection.Edges == nil {
break
@@ -11724,8 +11725,11 @@ type TrustCenterAccess implements Node {
hasAcceptedNonDisclosureAgreement: Boolean!
createdAt: Datetime!
updatedAt: Datetime!
lastTokenExpiresAt: Datetime
pendingRequestCount: Int! @goField(forceResolver: true)
activeCount: Int! @goField(forceResolver: true)
documentAccesses(
availableDocumentAccesses(
first: Int
after: CursorKey
last: Int
@@ -11734,12 +11738,12 @@ type TrustCenterAccess implements Node {
): TrustCenterDocumentAccessConnection! @goField(forceResolver: true)
}
type TrustCenterDocumentAccess implements Node {
id: ID!
type TrustCenterDocumentAccess
@goModel(
model: "github.com/getprobo/probo/pkg/server/api/console/v1/types.TrustCenterDocumentAccess"
) {
active: Boolean!
createdAt: Datetime!
updatedAt: Datetime!
trustCenterAccess: TrustCenterAccess! @goField(forceResolver: true)
requested: Boolean!
document: Document @goField(forceResolver: true)
report: Report @goField(forceResolver: true)
trustCenterFile: TrustCenterFile @goField(forceResolver: true)
@@ -21371,37 +21375,37 @@ func (ec *executionContext) field_Task_evidences_argsOrderBy(
return zeroVal, nil
}
func (ec *executionContext) field_TrustCenterAccess_documentAccesses_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
func (ec *executionContext) field_TrustCenterAccess_availableDocumentAccesses_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := ec.field_TrustCenterAccess_documentAccesses_argsFirst(ctx, rawArgs)
arg0, err := ec.field_TrustCenterAccess_availableDocumentAccesses_argsFirst(ctx, rawArgs)
if err != nil {
return nil, err
}
args["first"] = arg0
arg1, err := ec.field_TrustCenterAccess_documentAccesses_argsAfter(ctx, rawArgs)
arg1, err := ec.field_TrustCenterAccess_availableDocumentAccesses_argsAfter(ctx, rawArgs)
if err != nil {
return nil, err
}
args["after"] = arg1
arg2, err := ec.field_TrustCenterAccess_documentAccesses_argsLast(ctx, rawArgs)
arg2, err := ec.field_TrustCenterAccess_availableDocumentAccesses_argsLast(ctx, rawArgs)
if err != nil {
return nil, err
}
args["last"] = arg2
arg3, err := ec.field_TrustCenterAccess_documentAccesses_argsBefore(ctx, rawArgs)
arg3, err := ec.field_TrustCenterAccess_availableDocumentAccesses_argsBefore(ctx, rawArgs)
if err != nil {
return nil, err
}
args["before"] = arg3
arg4, err := ec.field_TrustCenterAccess_documentAccesses_argsOrderBy(ctx, rawArgs)
arg4, err := ec.field_TrustCenterAccess_availableDocumentAccesses_argsOrderBy(ctx, rawArgs)
if err != nil {
return nil, err
}
args["orderBy"] = arg4
return args, nil
}
func (ec *executionContext) field_TrustCenterAccess_documentAccesses_argsFirst(
func (ec *executionContext) field_TrustCenterAccess_availableDocumentAccesses_argsFirst(
ctx context.Context,
rawArgs map[string]any,
) (*int, error) {
@@ -21414,7 +21418,7 @@ func (ec *executionContext) field_TrustCenterAccess_documentAccesses_argsFirst(
return zeroVal, nil
}
func (ec *executionContext) field_TrustCenterAccess_documentAccesses_argsAfter(
func (ec *executionContext) field_TrustCenterAccess_availableDocumentAccesses_argsAfter(
ctx context.Context,
rawArgs map[string]any,
) (*page.CursorKey, error) {
@@ -21427,7 +21431,7 @@ func (ec *executionContext) field_TrustCenterAccess_documentAccesses_argsAfter(
return zeroVal, nil
}
func (ec *executionContext) field_TrustCenterAccess_documentAccesses_argsLast(
func (ec *executionContext) field_TrustCenterAccess_availableDocumentAccesses_argsLast(
ctx context.Context,
rawArgs map[string]any,
) (*int, error) {
@@ -21440,7 +21444,7 @@ func (ec *executionContext) field_TrustCenterAccess_documentAccesses_argsLast(
return zeroVal, nil
}
func (ec *executionContext) field_TrustCenterAccess_documentAccesses_argsBefore(
func (ec *executionContext) field_TrustCenterAccess_availableDocumentAccesses_argsBefore(
ctx context.Context,
rawArgs map[string]any,
) (*page.CursorKey, error) {
@@ -21453,7 +21457,7 @@ func (ec *executionContext) field_TrustCenterAccess_documentAccesses_argsBefore(
return zeroVal, nil
}
func (ec *executionContext) field_TrustCenterAccess_documentAccesses_argsOrderBy(
func (ec *executionContext) field_TrustCenterAccess_availableDocumentAccesses_argsOrderBy(
ctx context.Context,
rawArgs map[string]any,
) (*types.OrderBy[coredata.TrustCenterDocumentAccessOrderField], error) {
@@ -57622,8 +57626,8 @@ func (ec *executionContext) fieldContext_TrustCenterAccess_updatedAt(_ context.C
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_documentAccesses(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_documentAccesses(ctx, field)
func (ec *executionContext) _TrustCenterAccess_lastTokenExpiresAt(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_lastTokenExpiresAt(ctx, field)
if err != nil {
return graphql.Null
}
@@ -57636,7 +57640,136 @@ func (ec *executionContext) _TrustCenterAccess_documentAccesses(ctx context.Cont
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.TrustCenterAccess().DocumentAccesses(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]))
return obj.LastTokenExpiresAt, 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_TrustCenterAccess_lastTokenExpiresAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
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) _TrustCenterAccess_pendingRequestCount(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_pendingRequestCount(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.TrustCenterAccess().PendingRequestCount(rctx, obj)
})
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.(int)
fc.Result = res
return ec.marshalNInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterAccess_pendingRequestCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Int does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_activeCount(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_activeCount(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.TrustCenterAccess().ActiveCount(rctx, obj)
})
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.(int)
fc.Result = res
return ec.marshalNInt2int(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterAccess_activeCount(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type Int does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _TrustCenterAccess_availableDocumentAccesses(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterAccess_availableDocumentAccesses(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.TrustCenterAccess().AvailableDocumentAccesses(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]))
})
if err != nil {
ec.Error(ctx, err)
@@ -57653,7 +57786,7 @@ func (ec *executionContext) _TrustCenterAccess_documentAccesses(ctx context.Cont
return ec.marshalNTrustCenterDocumentAccessConnection2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTrustCenterDocumentAccessConnection(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterAccess_documentAccesses(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
func (ec *executionContext) fieldContext_TrustCenterAccess_availableDocumentAccesses(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterAccess",
Field: field,
@@ -57678,7 +57811,7 @@ func (ec *executionContext) fieldContext_TrustCenterAccess_documentAccesses(ctx
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_TrustCenterAccess_documentAccesses_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
if fc.Args, err = ec.field_TrustCenterAccess_availableDocumentAccesses_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
@@ -57886,8 +58019,14 @@ func (ec *executionContext) fieldContext_TrustCenterAccessEdge_node(_ context.Co
return ec.fieldContext_TrustCenterAccess_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_TrustCenterAccess_updatedAt(ctx, field)
case "documentAccesses":
return ec.fieldContext_TrustCenterAccess_documentAccesses(ctx, field)
case "lastTokenExpiresAt":
return ec.fieldContext_TrustCenterAccess_lastTokenExpiresAt(ctx, field)
case "pendingRequestCount":
return ec.fieldContext_TrustCenterAccess_pendingRequestCount(ctx, field)
case "activeCount":
return ec.fieldContext_TrustCenterAccess_activeCount(ctx, field)
case "availableDocumentAccesses":
return ec.fieldContext_TrustCenterAccess_availableDocumentAccesses(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type TrustCenterAccess", field.Name)
},
@@ -57999,50 +58138,6 @@ func (ec *executionContext) fieldContext_TrustCenterConnection_pageInfo(_ contex
return fc, nil
}
func (ec *executionContext) _TrustCenterDocumentAccess_id(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterDocumentAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterDocumentAccess_id(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.ID, 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.(gid.GID)
fc.Result = res
return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterDocumentAccess_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterDocumentAccess",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type ID does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _TrustCenterDocumentAccess_active(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterDocumentAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterDocumentAccess_active(ctx, field)
if err != nil {
@@ -58087,8 +58182,8 @@ func (ec *executionContext) fieldContext_TrustCenterDocumentAccess_active(_ cont
return fc, nil
}
func (ec *executionContext) _TrustCenterDocumentAccess_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterDocumentAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterDocumentAccess_createdAt(ctx, field)
func (ec *executionContext) _TrustCenterDocumentAccess_requested(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterDocumentAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterDocumentAccess_requested(ctx, field)
if err != nil {
return graphql.Null
}
@@ -58101,7 +58196,7 @@ func (ec *executionContext) _TrustCenterDocumentAccess_createdAt(ctx context.Con
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.CreatedAt, nil
return obj.Requested, nil
})
if err != nil {
ec.Error(ctx, err)
@@ -58113,125 +58208,19 @@ func (ec *executionContext) _TrustCenterDocumentAccess_createdAt(ctx context.Con
}
return graphql.Null
}
res := resTmp.(time.Time)
res := resTmp.(bool)
fc.Result = res
return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res)
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterDocumentAccess_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
func (ec *executionContext) fieldContext_TrustCenterDocumentAccess_requested(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterDocumentAccess",
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) _TrustCenterDocumentAccess_updatedAt(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterDocumentAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterDocumentAccess_updatedAt(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.UpdatedAt, 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_TrustCenterDocumentAccess_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterDocumentAccess",
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) _TrustCenterDocumentAccess_trustCenterAccess(ctx context.Context, field graphql.CollectedField, obj *types.TrustCenterDocumentAccess) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_TrustCenterDocumentAccess_trustCenterAccess(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.TrustCenterDocumentAccess().TrustCenterAccess(rctx, obj)
})
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.(*types.TrustCenterAccess)
fc.Result = res
return ec.marshalNTrustCenterAccess2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTrustCenterAccess(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_TrustCenterDocumentAccess_trustCenterAccess(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "TrustCenterDocumentAccess",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_TrustCenterAccess_id(ctx, field)
case "email":
return ec.fieldContext_TrustCenterAccess_email(ctx, field)
case "name":
return ec.fieldContext_TrustCenterAccess_name(ctx, field)
case "active":
return ec.fieldContext_TrustCenterAccess_active(ctx, field)
case "hasAcceptedNonDisclosureAgreement":
return ec.fieldContext_TrustCenterAccess_hasAcceptedNonDisclosureAgreement(ctx, field)
case "createdAt":
return ec.fieldContext_TrustCenterAccess_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_TrustCenterAccess_updatedAt(ctx, field)
case "documentAccesses":
return ec.fieldContext_TrustCenterAccess_documentAccesses(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type TrustCenterAccess", field.Name)
return nil, errors.New("field of type Boolean does not have child fields")
},
}
return fc, nil
@@ -58657,16 +58646,10 @@ func (ec *executionContext) fieldContext_TrustCenterDocumentAccessEdge_node(_ co
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "id":
return ec.fieldContext_TrustCenterDocumentAccess_id(ctx, field)
case "active":
return ec.fieldContext_TrustCenterDocumentAccess_active(ctx, field)
case "createdAt":
return ec.fieldContext_TrustCenterDocumentAccess_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_TrustCenterDocumentAccess_updatedAt(ctx, field)
case "trustCenterAccess":
return ec.fieldContext_TrustCenterDocumentAccess_trustCenterAccess(ctx, field)
case "requested":
return ec.fieldContext_TrustCenterDocumentAccess_requested(ctx, field)
case "document":
return ec.fieldContext_TrustCenterDocumentAccess_document(ctx, field)
case "report":
@@ -61337,8 +61320,14 @@ func (ec *executionContext) fieldContext_UpdateTrustCenterAccessPayload_trustCen
return ec.fieldContext_TrustCenterAccess_createdAt(ctx, field)
case "updatedAt":
return ec.fieldContext_TrustCenterAccess_updatedAt(ctx, field)
case "documentAccesses":
return ec.fieldContext_TrustCenterAccess_documentAccesses(ctx, field)
case "lastTokenExpiresAt":
return ec.fieldContext_TrustCenterAccess_lastTokenExpiresAt(ctx, field)
case "pendingRequestCount":
return ec.fieldContext_TrustCenterAccess_pendingRequestCount(ctx, field)
case "activeCount":
return ec.fieldContext_TrustCenterAccess_activeCount(ctx, field)
case "availableDocumentAccesses":
return ec.fieldContext_TrustCenterAccess_availableDocumentAccesses(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type TrustCenterAccess", field.Name)
},
@@ -77458,13 +77447,6 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj
return graphql.Null
}
return ec._TrustCenterFile(ctx, sel, obj)
case types.TrustCenterDocumentAccess:
return ec._TrustCenterDocumentAccess(ctx, sel, &obj)
case *types.TrustCenterDocumentAccess:
if obj == nil {
return graphql.Null
}
return ec._TrustCenterDocumentAccess(ctx, sel, obj)
case types.TrustCenterAccess:
return ec._TrustCenterAccess(ctx, sel, &obj)
case *types.TrustCenterAccess:
@@ -90142,7 +90124,9 @@ func (ec *executionContext) _TrustCenterAccess(ctx context.Context, sel ast.Sele
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
case "documentAccesses":
case "lastTokenExpiresAt":
out.Values[i] = ec._TrustCenterAccess_lastTokenExpiresAt(ctx, field, obj)
case "pendingRequestCount":
field := field
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
@@ -90151,7 +90135,79 @@ func (ec *executionContext) _TrustCenterAccess(ctx context.Context, sel ast.Sele
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._TrustCenterAccess_documentAccesses(ctx, field, obj)
res = ec._TrustCenterAccess_pendingRequestCount(ctx, field, obj)
if res == graphql.Null {
atomic.AddUint32(&fs.Invalids, 1)
}
return res
}
if field.Deferrable != nil {
dfs, ok := deferred[field.Deferrable.Label]
di := 0
if ok {
dfs.AddField(field)
di = len(dfs.Values) - 1
} else {
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
deferred[field.Deferrable.Label] = dfs
}
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
return innerFunc(ctx, dfs)
})
// don't run the out.Concurrently() call below
out.Values[i] = graphql.Null
continue
}
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
case "activeCount":
field := field
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._TrustCenterAccess_activeCount(ctx, field, obj)
if res == graphql.Null {
atomic.AddUint32(&fs.Invalids, 1)
}
return res
}
if field.Deferrable != nil {
dfs, ok := deferred[field.Deferrable.Label]
di := 0
if ok {
dfs.AddField(field)
di = len(dfs.Values) - 1
} else {
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
deferred[field.Deferrable.Label] = dfs
}
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
return innerFunc(ctx, dfs)
})
// don't run the out.Concurrently() call below
out.Values[i] = graphql.Null
continue
}
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
case "availableDocumentAccesses":
field := field
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._TrustCenterAccess_availableDocumentAccesses(ctx, field, obj)
if res == graphql.Null {
atomic.AddUint32(&fs.Invalids, 1)
}
@@ -90333,7 +90389,7 @@ func (ec *executionContext) _TrustCenterConnection(ctx context.Context, sel ast.
return out
}
var trustCenterDocumentAccessImplementors = []string{"TrustCenterDocumentAccess", "Node"}
var trustCenterDocumentAccessImplementors = []string{"TrustCenterDocumentAccess"}
func (ec *executionContext) _TrustCenterDocumentAccess(ctx context.Context, sel ast.SelectionSet, obj *types.TrustCenterDocumentAccess) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, trustCenterDocumentAccessImplementors)
@@ -90344,62 +90400,16 @@ func (ec *executionContext) _TrustCenterDocumentAccess(ctx context.Context, sel
switch field.Name {
case "__typename":
out.Values[i] = graphql.MarshalString("TrustCenterDocumentAccess")
case "id":
out.Values[i] = ec._TrustCenterDocumentAccess_id(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
case "active":
out.Values[i] = ec._TrustCenterDocumentAccess_active(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
case "createdAt":
out.Values[i] = ec._TrustCenterDocumentAccess_createdAt(ctx, field, obj)
case "requested":
out.Values[i] = ec._TrustCenterDocumentAccess_requested(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
case "updatedAt":
out.Values[i] = ec._TrustCenterDocumentAccess_updatedAt(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&out.Invalids, 1)
}
case "trustCenterAccess":
field := field
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._TrustCenterDocumentAccess_trustCenterAccess(ctx, field, obj)
if res == graphql.Null {
atomic.AddUint32(&fs.Invalids, 1)
}
return res
}
if field.Deferrable != nil {
dfs, ok := deferred[field.Deferrable.Label]
di := 0
if ok {
dfs.AddField(field)
di = len(dfs.Values) - 1
} else {
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
deferred[field.Deferrable.Label] = dfs
}
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
return innerFunc(ctx, dfs)
})
// don't run the out.Concurrently() call below
out.Values[i] = graphql.Null
continue
}
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
case "document":
field := field
@@ -100961,10 +100971,6 @@ func (ec *executionContext) marshalNTrustCenter2ᚖgithubᚗcomᚋgetproboᚋpro
return ec._TrustCenter(ctx, sel, v)
}
func (ec *executionContext) marshalNTrustCenterAccess2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTrustCenterAccess(ctx context.Context, sel ast.SelectionSet, v types.TrustCenterAccess) graphql.Marshaler {
return ec._TrustCenterAccess(ctx, sel, &v)
}
func (ec *executionContext) marshalNTrustCenterAccess2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐTrustCenterAccess(ctx context.Context, sel ast.SelectionSet, v *types.TrustCenterAccess) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {

View File

@@ -15,6 +15,8 @@
package types
import (
"time"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
@@ -31,14 +33,35 @@ type (
Resolver any
ParentID gid.GID
}
TrustCenterDocumentAccess struct {
ID gid.GID `json:"id"`
Active bool `json:"active"`
Requested bool `json:"requested"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
TrustCenterAccess *TrustCenterAccess `json:"trustCenterAccess"`
Document *Document `json:"document,omitempty"`
Report *Report `json:"report,omitempty"`
TrustCenterFile *TrustCenterFile `json:"trustCenterFile,omitempty"`
// Internal fields used by resolvers
DocumentID *gid.GID `json:"-"`
ReportID *gid.GID `json:"-"`
TrustCenterFileID *gid.GID `json:"-"`
}
)
func NewTrustCenterDocumentAccess(tcda *coredata.TrustCenterDocumentAccess) *TrustCenterDocumentAccess {
return &TrustCenterDocumentAccess{
ID: tcda.ID,
Active: tcda.Active,
CreatedAt: tcda.CreatedAt,
UpdatedAt: tcda.UpdatedAt,
ID: tcda.ID,
Active: tcda.Active,
Requested: tcda.Requested,
CreatedAt: tcda.CreatedAt,
UpdatedAt: tcda.UpdatedAt,
DocumentID: tcda.DocumentID,
ReportID: tcda.ReportID,
TrustCenterFileID: tcda.TrustCenterFileID,
}
}

View File

@@ -1675,7 +1675,10 @@ type TrustCenterAccess struct {
HasAcceptedNonDisclosureAgreement bool `json:"hasAcceptedNonDisclosureAgreement"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
DocumentAccesses *TrustCenterDocumentAccessConnection `json:"documentAccesses"`
LastTokenExpiresAt *time.Time `json:"lastTokenExpiresAt,omitempty"`
PendingRequestCount int `json:"pendingRequestCount"`
ActiveCount int `json:"activeCount"`
AvailableDocumentAccesses *TrustCenterDocumentAccessConnection `json:"availableDocumentAccesses"`
}
func (TrustCenterAccess) IsNode() {}
@@ -1696,20 +1699,6 @@ type TrustCenterConnection struct {
PageInfo *PageInfo `json:"pageInfo"`
}
type TrustCenterDocumentAccess struct {
ID gid.GID `json:"id"`
Active bool `json:"active"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
TrustCenterAccess *TrustCenterAccess `json:"trustCenterAccess"`
Document *Document `json:"document,omitempty"`
Report *Report `json:"report,omitempty"`
TrustCenterFile *TrustCenterFile `json:"trustCenterFile,omitempty"`
}
func (TrustCenterDocumentAccess) IsNode() {}
func (this TrustCenterDocumentAccess) GetID() gid.GID { return this.ID }
type TrustCenterDocumentAccessEdge struct {
Cursor page.CursorKey `json:"cursor"`
Node *TrustCenterDocumentAccess `json:"node"`

View File

@@ -1439,9 +1439,7 @@ func (r *mutationResolver) UpdateTrustCenterFile(ctx context.Context, input type
func (r *mutationResolver) GetTrustCenterFile(ctx context.Context, input types.GetTrustCenterFileInput) (*types.GetTrustCenterFilePayload, error) {
prb := r.ProboService(ctx, input.ID.TenantID())
file, err := prb.TrustCenterFiles.Get(ctx, &probo.GetTrustCenterFileRequest{
ID: input.ID,
})
file, err := prb.TrustCenterFiles.Get(ctx, input.ID)
if err != nil {
return nil, fmt.Errorf("cannot get trust center file: %w", err)
}
@@ -4501,6 +4499,13 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
}
return types.NewTrustCenter(trustCenter, file), nil
case coredata.TrustCenterAccessEntityType:
trustCenterAccess, err := prb.TrustCenterAccesses.Get(ctx, id)
if err != nil {
panic(fmt.Errorf("cannot get trust center access: %w", err))
}
return types.NewTrustCenterAccess(trustCenterAccess), nil
default:
}
@@ -4959,8 +4964,32 @@ func (r *trustCenterResolver) References(ctx context.Context, obj *types.TrustCe
return types.NewTrustCenterReferenceConnection(result, obj.ID), nil
}
// DocumentAccesses is the resolver for the documentAccesses field.
func (r *trustCenterAccessResolver) DocumentAccesses(ctx context.Context, obj *types.TrustCenterAccess, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]) (*types.TrustCenterDocumentAccessConnection, error) {
// PendingRequestCount is the resolver for the pendingRequestCount field.
func (r *trustCenterAccessResolver) PendingRequestCount(ctx context.Context, obj *types.TrustCenterAccess) (int, error) {
prb := r.ProboService(ctx, obj.ID.TenantID())
count, err := prb.TrustCenterAccesses.CountPendingRequestDocumentAccesses(ctx, obj.ID)
if err != nil {
panic(fmt.Errorf("cannot count pending request document accesses: %w", err))
}
return count, nil
}
// ActiveCount is the resolver for the activeCount field.
func (r *trustCenterAccessResolver) ActiveCount(ctx context.Context, obj *types.TrustCenterAccess) (int, error) {
prb := r.ProboService(ctx, obj.ID.TenantID())
count, err := prb.TrustCenterAccesses.CountActiveDocumentAccesses(ctx, obj.ID)
if err != nil {
panic(fmt.Errorf("cannot count active document accesses: %w", err))
}
return count, nil
}
// AvailableDocumentAccesses is the resolver for the availableDocumentAccesses field.
func (r *trustCenterAccessResolver) AvailableDocumentAccesses(ctx context.Context, obj *types.TrustCenterAccess, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]) (*types.TrustCenterDocumentAccessConnection, error) {
prb := r.ProboService(ctx, obj.ID.TenantID())
pageOrderBy := page.OrderBy[coredata.TrustCenterDocumentAccessOrderField]{
@@ -4976,7 +5005,7 @@ func (r *trustCenterAccessResolver) DocumentAccesses(ctx context.Context, obj *t
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
result, err := prb.TrustCenterAccesses.ListDocumentAccesses(ctx, obj.ID, cursor)
result, err := prb.TrustCenterAccesses.ListAvailableDocumentAccesses(ctx, obj.ID, cursor)
if err != nil {
panic(fmt.Errorf("cannot list trust center document accesses: %w", err))
}
@@ -4984,26 +5013,15 @@ func (r *trustCenterAccessResolver) DocumentAccesses(ctx context.Context, obj *t
return types.NewTrustCenterDocumentAccessConnection(result, obj, obj.ID), nil
}
// TrustCenterAccess is the resolver for the trustCenterAccess field.
func (r *trustCenterDocumentAccessResolver) TrustCenterAccess(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.TrustCenterAccess, error) {
// The TrustCenterAccess is already loaded from the connection resolver
return obj.TrustCenterAccess, nil
}
// Document is the resolver for the document field.
func (r *trustCenterDocumentAccessResolver) Document(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Document, error) {
prb := r.ProboService(ctx, obj.ID.TenantID())
documentAccess, err := prb.TrustCenterAccesses.GetDocumentAccess(ctx, obj.ID)
if err != nil {
return nil, fmt.Errorf("cannot load trust center document access: %w", err)
}
if documentAccess.DocumentID == nil {
if obj.DocumentID == nil {
return nil, nil
}
document, err := prb.Documents.Get(ctx, *documentAccess.DocumentID)
prb := r.ProboService(ctx, obj.ID.TenantID())
document, err := prb.Documents.Get(ctx, *obj.DocumentID)
if err != nil {
return nil, fmt.Errorf("cannot load document: %w", err)
}
@@ -5013,18 +5031,13 @@ func (r *trustCenterDocumentAccessResolver) Document(ctx context.Context, obj *t
// Report is the resolver for the report field.
func (r *trustCenterDocumentAccessResolver) Report(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Report, error) {
prb := r.ProboService(ctx, obj.ID.TenantID())
documentAccess, err := prb.TrustCenterAccesses.GetDocumentAccess(ctx, obj.ID)
if err != nil {
return nil, fmt.Errorf("cannot load trust center document access: %w", err)
}
if documentAccess.ReportID == nil {
if obj.ReportID == nil {
return nil, nil
}
report, err := prb.Reports.Get(ctx, *documentAccess.ReportID)
prb := r.ProboService(ctx, obj.ID.TenantID())
report, err := prb.Reports.Get(ctx, *obj.ReportID)
if err != nil {
return nil, fmt.Errorf("cannot load report: %w", err)
}
@@ -5034,20 +5047,13 @@ func (r *trustCenterDocumentAccessResolver) Report(ctx context.Context, obj *typ
// TrustCenterFile is the resolver for the trustCenterFile field.
func (r *trustCenterDocumentAccessResolver) TrustCenterFile(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.TrustCenterFile, error) {
prb := r.ProboService(ctx, obj.ID.TenantID())
documentAccess, err := prb.TrustCenterAccesses.GetDocumentAccess(ctx, obj.ID)
if err != nil {
return nil, fmt.Errorf("cannot load trust center document access: %w", err)
}
if documentAccess.TrustCenterFileID == nil {
if obj.TrustCenterFileID == nil {
return nil, nil
}
trustCenterFile, err := prb.TrustCenterFiles.Get(ctx, &probo.GetTrustCenterFileRequest{
ID: *documentAccess.TrustCenterFileID,
})
prb := r.ProboService(ctx, obj.ID.TenantID())
trustCenterFile, err := prb.TrustCenterFiles.Get(ctx, *obj.TrustCenterFileID)
if err != nil {
return nil, fmt.Errorf("cannot load trust center file: %w", err)
}
@@ -5083,9 +5089,7 @@ func (r *trustCenterFileResolver) FileURL(ctx context.Context, obj *types.TrustC
func (r *trustCenterFileResolver) Organization(ctx context.Context, obj *types.TrustCenterFile) (*types.Organization, error) {
prb := r.ProboService(ctx, obj.ID.TenantID())
file, err := prb.TrustCenterFiles.Get(ctx, &probo.GetTrustCenterFileRequest{
ID: obj.ID,
})
file, err := prb.TrustCenterFiles.Get(ctx, obj.ID)
if err != nil {
panic(fmt.Errorf("cannot get trust center file: %w", err))
}

View File

@@ -208,15 +208,15 @@ func (s TrustCenterAccessService) Request(
var accesses coredata.TrustCenterDocumentAccesses
if err := accesses.BulkInsertDocumentAccesses(ctx, tx, s.svc.scope, access.ID, newDocumentIDs, now); err != nil {
if err := accesses.BulkInsertDocumentAccesses(ctx, tx, s.svc.scope, access.ID, newDocumentIDs, true, now); err != nil {
return fmt.Errorf("cannot bulk insert trust center document accesses: %w", err)
}
if err := accesses.BulkInsertReportAccesses(ctx, tx, s.svc.scope, access.ID, newReportIDs, now); err != nil {
if err := accesses.BulkInsertReportAccesses(ctx, tx, s.svc.scope, access.ID, newReportIDs, true, now); err != nil {
return fmt.Errorf("cannot bulk insert trust center report accesses: %w", err)
}
if err := accesses.BulkInsertTrustCenterFileAccesses(ctx, tx, s.svc.scope, access.ID, newTrustCenterFileIDs, now); err != nil {
if err := accesses.BulkInsertTrustCenterFileAccesses(ctx, tx, s.svc.scope, access.ID, newTrustCenterFileIDs, true, now); err != nil {
return fmt.Errorf("cannot bulk insert trust center file accesses: %w", err)
}
@@ -409,7 +409,7 @@ func (s *TrustCenterAccessService) AcceptByIDs(
return fmt.Errorf("cannot load trust center access: %w", err)
}
wasInactive := !access.Active
shouldSendEmail := !access.Active
now := time.Now()
if len(documentIDs) > 0 {
@@ -428,7 +428,7 @@ func (s *TrustCenterAccessService) AcceptByIDs(
}
}
if wasInactive {
if shouldSendEmail {
access.Active = true
access.UpdatedAt = now
if err := access.Update(ctx, tx, s.svc.scope); err != nil {
@@ -496,6 +496,15 @@ func (s *TrustCenterAccessService) sendAccessEmail(ctx context.Context, tx pg.Co
}.Encode(),
}
now := time.Now()
expiresAt := now.Add(s.svc.trustConfig.TokenDuration)
access.LastTokenExpiresAt = &expiresAt
access.UpdatedAt = now
if err := access.Update(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot update trust center access with expiration: %w", err)
}
return s.sendTrustCenterAccessEmail(ctx, tx, access.Name, access.Email, organization.Name, accessURL.String())
}
@@ -512,6 +521,7 @@ func (s *TrustCenterAccessService) sendTrustCenterAccessEmail(
name,
companyName,
accessURL,
s.svc.trustConfig.TokenDuration,
)
if err != nil {
return fmt.Errorf("cannot render trust center access email: %w", err)