@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<eda42f72473c65692ddd9cee68c0ce81>>
|
||||
* @generated SignedSource<<4dda94f89f726842762d68c28d8180b6>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -9,7 +9,7 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type MembershipRole = "ADMIN" | "OWNER" | "VIEWER";
|
||||
export type MembershipRole = "ADMIN" | "EMPLOYEE" | "OWNER" | "VIEWER";
|
||||
export type InviteUserInput = {
|
||||
createPeople: boolean;
|
||||
email: string;
|
||||
|
||||
377
apps/console/src/layouts/EmployeeLayout.tsx
Normal file
377
apps/console/src/layouts/EmployeeLayout.tsx
Normal file
@@ -0,0 +1,377 @@
|
||||
import { Link, Navigate, Outlet, useParams } from "react-router";
|
||||
import {
|
||||
DropdownSeparator,
|
||||
IconArrowBoxLeft,
|
||||
IconCircleQuestionmark,
|
||||
UserDropdown as UserDropdownRoot,
|
||||
UserDropdownItem,
|
||||
Skeleton,
|
||||
Dropdown,
|
||||
Button,
|
||||
DropdownItem,
|
||||
IconChevronGrabberVertical,
|
||||
IconLock,
|
||||
IconKey,
|
||||
IconPeopleAdd,
|
||||
IconPlusLarge,
|
||||
IconCheckmark1,
|
||||
IconClock,
|
||||
useToast,
|
||||
Logo,
|
||||
Toasts,
|
||||
ConfirmDialog,
|
||||
Avatar,
|
||||
Badge,
|
||||
} from "@probo/ui";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { graphql } from "relay-runtime";
|
||||
import { useLazyLoadQuery } from "react-relay";
|
||||
import type { EmployeeLayoutQuery as EmployeeLayoutQueryType } from "./__generated__/EmployeeLayoutQuery.graphql";
|
||||
import { Suspense, useState, useEffect, use } from "react";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import { PageError } from "/components/PageError";
|
||||
import { buildEndpoint } from "/providers/RelayProviders";
|
||||
import { PermissionsProvider } from "/providers/PermissionsProvider";
|
||||
import { PermissionsContext } from "/providers/PermissionsContext";
|
||||
|
||||
const EmployeeLayoutQuery = graphql`
|
||||
query EmployeeLayoutQuery($organizationId: ID!) {
|
||||
viewer {
|
||||
id
|
||||
user {
|
||||
fullName
|
||||
email
|
||||
}
|
||||
}
|
||||
organization: node(id: $organizationId) {
|
||||
... on Organization {
|
||||
id
|
||||
name
|
||||
logoUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export function EmployeeLayout() {
|
||||
const { organizationId } = useParams();
|
||||
|
||||
if (!organizationId) {
|
||||
return <Navigate to="/" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense fallback={<Skeleton className="w-full h-screen" />}>
|
||||
<PermissionsProvider>
|
||||
<EmployeeLayoutContent organizationId={organizationId} />
|
||||
</PermissionsProvider>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
function EmployeeLayoutContent({
|
||||
organizationId,
|
||||
}: {
|
||||
organizationId: string;
|
||||
}) {
|
||||
const data = useLazyLoadQuery<EmployeeLayoutQueryType>(EmployeeLayoutQuery, {
|
||||
organizationId,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="text-txt-primary bg-level-0">
|
||||
<header className="absolute z-2 left-0 right-0 px-4 flex items-center border-b border-border-solid h-12 bg-level-0">
|
||||
<Logo className="w-12 h-5" />
|
||||
<svg
|
||||
className="mx-3 text-txt-tertiary"
|
||||
width="8"
|
||||
height="18"
|
||||
viewBox="0 0 8 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M1 17L7 1" stroke="currentColor" />
|
||||
</svg>
|
||||
<div className="mr-auto">
|
||||
<OrganizationSelector currentOrganization={data.organization} />
|
||||
</div>
|
||||
<Suspense fallback={<Skeleton className="w-32 h-8" />}>
|
||||
<UserDropdown organizationId={organizationId} />
|
||||
</Suspense>
|
||||
</header>
|
||||
<main className="overflow-y-auto w-full pt-12 h-[calc(100vh-3rem)]">
|
||||
<div className="px-8 pb-8 pt-8">
|
||||
<ErrorBoundary FallbackComponent={PageError}>
|
||||
<Outlet />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</main>
|
||||
<Toasts />
|
||||
<ConfirmDialog />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface Organization {
|
||||
id: string;
|
||||
name: string;
|
||||
logoUrl?: string | null;
|
||||
authenticationMethod: string;
|
||||
authStatus: "authenticated" | "unauthenticated" | "expired";
|
||||
loginUrl: string;
|
||||
}
|
||||
|
||||
interface OrganizationsResponse {
|
||||
organizations: Organization[];
|
||||
}
|
||||
|
||||
interface Invitation {
|
||||
id: string;
|
||||
email: string;
|
||||
fullName: string;
|
||||
role: string;
|
||||
expiresAt: string;
|
||||
acceptedAt?: string | null;
|
||||
createdAt: string;
|
||||
organization: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface InvitationsResponse {
|
||||
invitations: Invitation[];
|
||||
}
|
||||
|
||||
function OrganizationSelector({
|
||||
currentOrganization,
|
||||
}: {
|
||||
currentOrganization: EmployeeLayoutQueryType["response"]["organization"];
|
||||
}) {
|
||||
const [organizations, setOrganizations] = useState<Organization[]>([]);
|
||||
const [pendingInvitationsCount, setPendingInvitationsCount] = useState(0);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const { __ } = useTranslate();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const [orgsResponse, invitationsResponse] = await Promise.all([
|
||||
fetch("/connect/organizations", { credentials: "include" }),
|
||||
fetch("/connect/invitations", { credentials: "include" }),
|
||||
]);
|
||||
|
||||
if (!orgsResponse.ok) {
|
||||
throw new Error("Failed to fetch organizations");
|
||||
}
|
||||
|
||||
if (!invitationsResponse.ok) {
|
||||
throw new Error("Failed to fetch invitations");
|
||||
}
|
||||
|
||||
const orgsData: OrganizationsResponse = await orgsResponse.json();
|
||||
const invitationsData: InvitationsResponse =
|
||||
await invitationsResponse.json();
|
||||
|
||||
const pendingCount = invitationsData.invitations.filter(
|
||||
(inv) => !inv.acceptedAt
|
||||
).length;
|
||||
|
||||
setOrganizations(orgsData.organizations);
|
||||
setPendingInvitationsCount(pendingCount);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Unknown error");
|
||||
console.error("Failed to fetch data:", err);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<Button className="-ml-3" variant="tertiary" disabled>
|
||||
{__("Error loading organizations")}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
<Dropdown
|
||||
toggle={
|
||||
<Button
|
||||
className="-ml-3"
|
||||
variant="tertiary"
|
||||
iconAfter={IconChevronGrabberVertical}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? __("Loading...") : currentOrganization?.name || ""}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<div className="max-h-150 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-transparent hover:scrollbar-thumb-gray-400">
|
||||
{isLoading ? (
|
||||
<div className="px-3 py-2 text-gray-500">
|
||||
{__("Loading organizations...")}
|
||||
</div>
|
||||
) : organizations.length === 0 ? (
|
||||
<div className="px-3 py-2 text-gray-500">
|
||||
{__("No organizations found")}
|
||||
</div>
|
||||
) : (
|
||||
organizations.map((organization) => {
|
||||
const isAuthenticated =
|
||||
organization.authStatus === "authenticated";
|
||||
const isExpired = organization.authStatus === "expired";
|
||||
const needsAuth = organization.authStatus === "unauthenticated";
|
||||
|
||||
const targetUrl = isAuthenticated
|
||||
? `/organizations/${organization.id}`
|
||||
: organization.loginUrl;
|
||||
|
||||
const isSAMLUrl = targetUrl.includes("/connect/saml/");
|
||||
|
||||
const logoUrl = organization.logoUrl;
|
||||
|
||||
return (
|
||||
<DropdownItem asChild key={organization.id}>
|
||||
{isSAMLUrl ? (
|
||||
<a href={targetUrl} className="flex items-center gap-2">
|
||||
<Avatar name={organization.name} src={logoUrl} />
|
||||
<span className="flex-1">{organization.name}</span>
|
||||
{isAuthenticated && (
|
||||
<IconCheckmark1 size={16} className="text-green-600" />
|
||||
)}
|
||||
{isExpired && (
|
||||
<IconClock size={16} className="text-orange-600" />
|
||||
)}
|
||||
{needsAuth && (
|
||||
<IconLock size={16} className="text-gray-400" />
|
||||
)}
|
||||
</a>
|
||||
) : (
|
||||
<Link to={targetUrl} className="flex items-center gap-2">
|
||||
<Avatar name={organization.name} src={logoUrl} />
|
||||
<span className="flex-1">{organization.name}</span>
|
||||
{isAuthenticated && (
|
||||
<IconCheckmark1 size={16} className="text-green-600" />
|
||||
)}
|
||||
{isExpired && (
|
||||
<IconClock size={16} className="text-orange-600" />
|
||||
)}
|
||||
{needsAuth && (
|
||||
<IconLock size={16} className="text-gray-400" />
|
||||
)}
|
||||
</Link>
|
||||
)}
|
||||
</DropdownItem>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
<DropdownSeparator />
|
||||
{pendingInvitationsCount > 0 && (
|
||||
<DropdownItem asChild>
|
||||
<Link to="/">
|
||||
<IconPeopleAdd size={16} />
|
||||
<span className="flex-1">{__("Invitations")}</span>
|
||||
<Badge variant="info" size="sm">
|
||||
{pendingInvitationsCount}
|
||||
</Badge>
|
||||
</Link>
|
||||
</DropdownItem>
|
||||
)}
|
||||
<DropdownItem asChild>
|
||||
<Link to="/organizations/new">
|
||||
<IconPlusLarge size={16} />
|
||||
{__("Add organization")}
|
||||
</Link>
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
{pendingInvitationsCount > 0 && (
|
||||
<Link to="/" className="relative" title={__("Invitations")}>
|
||||
<Button variant="tertiary" icon={IconPeopleAdd} />
|
||||
<Badge
|
||||
variant="info"
|
||||
size="sm"
|
||||
className="absolute -top-1 -right-1 min-w-[20px] h-5 flex items-center justify-center"
|
||||
>
|
||||
{pendingInvitationsCount}
|
||||
</Badge>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function UserDropdown({ organizationId }: { organizationId: string }) {
|
||||
const { __ } = useTranslate();
|
||||
const { toast } = useToast();
|
||||
const { isAuthorized } = use(PermissionsContext);
|
||||
const user = useLazyLoadQuery<EmployeeLayoutQueryType>(EmployeeLayoutQuery, {
|
||||
organizationId,
|
||||
}).viewer.user;
|
||||
|
||||
const handleLogout: React.MouseEventHandler<HTMLAnchorElement> = async (
|
||||
e
|
||||
) => {
|
||||
e.preventDefault();
|
||||
|
||||
fetch(buildEndpoint("/connect/logout"), {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({}),
|
||||
})
|
||||
.then(async (res) => {
|
||||
if (!res.ok) {
|
||||
const error = await res.json();
|
||||
throw new Error(error.message || __("Failed to login"));
|
||||
}
|
||||
|
||||
window.location.reload();
|
||||
})
|
||||
.catch((e) => {
|
||||
toast({
|
||||
title: __("Error"),
|
||||
description: e.message as string,
|
||||
variant: "error",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<UserDropdownRoot fullName={user.fullName} email={user.email}>
|
||||
{isAuthorized("Organization", "deleteOrganization") && (
|
||||
<UserDropdownItem
|
||||
to="/api-keys"
|
||||
icon={IconKey}
|
||||
label={__("API Keys")}
|
||||
/>
|
||||
)}
|
||||
<UserDropdownItem
|
||||
to="mailto:support@getprobo.com"
|
||||
icon={IconCircleQuestionmark}
|
||||
label={__("Help")}
|
||||
/>
|
||||
<DropdownSeparator />
|
||||
<UserDropdownItem
|
||||
variant="danger"
|
||||
to="/logout"
|
||||
icon={IconArrowBoxLeft}
|
||||
label="Logout"
|
||||
onClick={handleLogout}
|
||||
/>
|
||||
</UserDropdownRoot>
|
||||
);
|
||||
}
|
||||
@@ -299,6 +299,13 @@ function UserDropdown({ organizationId }: { organizationId: string }) {
|
||||
label={__("API Keys")}
|
||||
/>
|
||||
)}
|
||||
{isAuthorized("Organization", "listSignableDocuments") && (
|
||||
<UserDropdownItem
|
||||
to={`/organizations/${organizationId}/employee`}
|
||||
icon={IconPageTextLine}
|
||||
label={__("My Signatures")}
|
||||
/>
|
||||
)}
|
||||
<UserDropdownItem
|
||||
to="mailto:support@getprobo.com"
|
||||
icon={IconCircleQuestionmark}
|
||||
@@ -364,7 +371,6 @@ function OrganizationSelector({
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
// Fetch organizations and invitations in parallel
|
||||
const [orgsResponse, invitationsResponse] = await Promise.all([
|
||||
fetch("/connect/organizations", { credentials: "include" }),
|
||||
fetch("/connect/invitations", { credentials: "include" }),
|
||||
|
||||
216
apps/console/src/layouts/__generated__/EmployeeLayoutQuery.graphql.ts
generated
Normal file
216
apps/console/src/layouts/__generated__/EmployeeLayoutQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* @generated SignedSource<<626f9dd0bec23ddd103042d53539363a>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type EmployeeLayoutQuery$variables = {
|
||||
organizationId: string;
|
||||
};
|
||||
export type EmployeeLayoutQuery$data = {
|
||||
readonly organization: {
|
||||
readonly id?: string;
|
||||
readonly logoUrl?: string | null | undefined;
|
||||
readonly name?: string;
|
||||
};
|
||||
readonly viewer: {
|
||||
readonly id: string;
|
||||
readonly user: {
|
||||
readonly email: string;
|
||||
readonly fullName: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
export type EmployeeLayoutQuery = {
|
||||
response: EmployeeLayoutQuery$data;
|
||||
variables: EmployeeLayoutQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
}
|
||||
],
|
||||
v1 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v2 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "fullName",
|
||||
"storageKey": null
|
||||
},
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "email",
|
||||
"storageKey": null
|
||||
},
|
||||
v4 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "id",
|
||||
"variableName": "organizationId"
|
||||
}
|
||||
],
|
||||
v5 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "name",
|
||||
"storageKey": null
|
||||
},
|
||||
v6 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "logoUrl",
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "EmployeeLayoutQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "User",
|
||||
"kind": "LinkedField",
|
||||
"name": "user",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v2/*: any*/),
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": "organization",
|
||||
"args": (v4/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/)
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "EmployeeLayoutQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "User",
|
||||
"kind": "LinkedField",
|
||||
"name": "user",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v2/*: any*/),
|
||||
(v3/*: any*/),
|
||||
(v1/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": "organization",
|
||||
"args": (v4/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/)
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "64e05cc4b0940458c50a111f2ca42f1a",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "EmployeeLayoutQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query EmployeeLayoutQuery(\n $organizationId: ID!\n) {\n viewer {\n id\n user {\n fullName\n email\n id\n }\n }\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n name\n logoUrl\n }\n id\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "1d30db1e236d19d63e2edcbaf172c34d";
|
||||
|
||||
export default node;
|
||||
@@ -1,341 +0,0 @@
|
||||
/**
|
||||
* @generated SignedSource<<ea405e491a67747f288e05da62524468>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type ContinualImprovementsPageQuery$variables = {
|
||||
organizationId: string;
|
||||
snapshotId?: string | null | undefined;
|
||||
};
|
||||
export type ContinualImprovementsPageQuery$data = {
|
||||
readonly node: {
|
||||
readonly " $fragmentSpreads": FragmentRefs<"ContinualImprovementsPageFragment">;
|
||||
};
|
||||
};
|
||||
export type ContinualImprovementsPageQuery = {
|
||||
response: ContinualImprovementsPageQuery$data;
|
||||
variables: ContinualImprovementsPageQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "snapshotId"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "id",
|
||||
"variableName": "organizationId"
|
||||
}
|
||||
],
|
||||
v2 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "snapshotId",
|
||||
"variableName": "snapshotId"
|
||||
}
|
||||
],
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
v4 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v5 = [
|
||||
{
|
||||
"fields": (v2/*: any*/),
|
||||
"kind": "ObjectValue",
|
||||
"name": "filter"
|
||||
},
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 10
|
||||
}
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "ContinualImprovementsPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"args": (v2/*: any*/),
|
||||
"kind": "FragmentSpread",
|
||||
"name": "ContinualImprovementsPageFragment"
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "ContinualImprovementsPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"concreteType": "ContinualImprovementConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "continualImprovements",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "totalCount",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "ContinualImprovementEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "ContinualImprovement",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "snapshotId",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "sourceId",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "referenceId",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "description",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "source",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "targetDate",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "priority",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "People",
|
||||
"kind": "LinkedField",
|
||||
"name": "owner",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "fullName",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "createdAt",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
},
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
"kind": "LinkedField",
|
||||
"name": "pageInfo",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__id",
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"filters": [
|
||||
"filter"
|
||||
],
|
||||
"handle": "connection",
|
||||
"key": "ContinualImprovementsPage_continualImprovements",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "continualImprovements"
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "7213a2ee3776522282ddbc3c46b4002b",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "ContinualImprovementsPageQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query ContinualImprovementsPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ContinualImprovementsPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ContinualImprovementsPageFragment_3iomuz on Organization {\n id\n continualImprovements(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n referenceId\n description\n source\n targetDate\n status\n priority\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "7baadd4791b1c26eb7315a7755e28a08";
|
||||
|
||||
export default node;
|
||||
@@ -0,0 +1,399 @@
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Spinner,
|
||||
IconCircleCheck,
|
||||
IconRadioUnchecked,
|
||||
} from "@probo/ui";
|
||||
import clsx from "clsx";
|
||||
import {
|
||||
usePreloadedQuery,
|
||||
useFragment,
|
||||
useMutation,
|
||||
type PreloadedQuery,
|
||||
} from "react-relay";
|
||||
import { graphql } from "relay-runtime";
|
||||
import type { EmployeeDocumentSignaturePageQuery } from "./__generated__/EmployeeDocumentSignaturePageQuery.graphql";
|
||||
import { usePageTitle } from "@probo/hooks";
|
||||
import { useMutationWithToasts } from "/hooks/useMutationWithToasts";
|
||||
import type { EmployeeDocumentSignaturePageSignMutation } from "./__generated__/EmployeeDocumentSignaturePageSignMutation.graphql";
|
||||
import type { EmployeeDocumentSignaturePageExportSignablePDFMutation } from "./__generated__/EmployeeDocumentSignaturePageExportSignablePDFMutation.graphql";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||
import { PDFPreview } from "/components/documents/PDFPreview";
|
||||
import { useWindowSize } from "usehooks-ts";
|
||||
import { useState, useEffect, useRef, useMemo } from "react";
|
||||
import type { EmployeeDocumentSignaturePageDocumentFragment$key } from "./__generated__/EmployeeDocumentSignaturePageDocumentFragment.graphql";
|
||||
import type { EmployeeDocumentSignaturePageVersionFragment$key } from "./__generated__/EmployeeDocumentSignaturePageVersionFragment.graphql";
|
||||
import { useToast } from "@probo/ui";
|
||||
import { formatError, type GraphQLError } from "@probo/helpers";
|
||||
|
||||
export const employeeDocumentSignatureQuery = graphql`
|
||||
query EmployeeDocumentSignaturePageQuery($documentId: ID!) {
|
||||
viewer {
|
||||
id
|
||||
signableDocument(id: $documentId) {
|
||||
id
|
||||
...EmployeeDocumentSignaturePageDocumentFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const documentFragment = graphql`
|
||||
fragment EmployeeDocumentSignaturePageDocumentFragment on SignableDocument {
|
||||
id
|
||||
title
|
||||
signed
|
||||
versions(first: 100, orderBy: { field: CREATED_AT, direction: DESC }) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
...EmployeeDocumentSignaturePageVersionFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const versionFragment = graphql`
|
||||
fragment EmployeeDocumentSignaturePageVersionFragment on DocumentVersion {
|
||||
id
|
||||
version
|
||||
signed
|
||||
publishedAt
|
||||
}
|
||||
`;
|
||||
|
||||
const signDocumentMutation = graphql`
|
||||
mutation EmployeeDocumentSignaturePageSignMutation($input: SignDocumentInput!) {
|
||||
signDocument(input: $input) {
|
||||
documentVersionSignature {
|
||||
id
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const exportSignableVersionDocumentPDFMutation = graphql`
|
||||
mutation EmployeeDocumentSignaturePageExportSignablePDFMutation(
|
||||
$input: ExportSignableDocumentVersionPDFInput!
|
||||
) {
|
||||
exportSignableVersionDocumentPDF(input: $input) {
|
||||
data
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
queryRef: PreloadedQuery<EmployeeDocumentSignaturePageQuery>;
|
||||
};
|
||||
|
||||
export default function EmployeeDocumentSignaturePage(props: Props) {
|
||||
const data = usePreloadedQuery(employeeDocumentSignatureQuery, props.queryRef);
|
||||
const document = data.viewer.signableDocument;
|
||||
|
||||
if (!document) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<Spinner />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <DocumentSignatureContent document={document} />;
|
||||
}
|
||||
|
||||
function DocumentSignatureContent({
|
||||
document,
|
||||
}: {
|
||||
document: EmployeeDocumentSignaturePageDocumentFragment$key;
|
||||
}) {
|
||||
const { __ } = useTranslate();
|
||||
const navigate = useNavigate();
|
||||
const { width } = useWindowSize();
|
||||
const isMobile = width < 1100;
|
||||
const isDesktop = !isMobile;
|
||||
const organizationId = useOrganizationId();
|
||||
|
||||
const documentData = useFragment<EmployeeDocumentSignaturePageDocumentFragment$key>(
|
||||
documentFragment,
|
||||
document
|
||||
);
|
||||
|
||||
const versions = useMemo(() => {
|
||||
return documentData.versions?.edges
|
||||
?.map((edge) => edge?.node)
|
||||
.filter(Boolean) || [];
|
||||
}, [documentData.versions?.edges]);
|
||||
|
||||
const [selectedVersionId, setSelectedVersionId] = useState<string | undefined>(
|
||||
() => versions[0]?.id
|
||||
);
|
||||
|
||||
const selectedVersion = useMemo(() => {
|
||||
return versions.find((v) => v?.id === selectedVersionId);
|
||||
}, [versions, selectedVersionId]);
|
||||
|
||||
usePageTitle(__("Sign Document"));
|
||||
const { toast } = useToast();
|
||||
|
||||
const [signDocument, isSigning] = useMutationWithToasts<EmployeeDocumentSignaturePageSignMutation>(
|
||||
signDocumentMutation,
|
||||
{
|
||||
successMessage: __("Document signed successfully"),
|
||||
errorMessage: __("Failed to sign document"),
|
||||
}
|
||||
);
|
||||
|
||||
const [exportSignableVersionDocumentPDF] = useMutation<EmployeeDocumentSignaturePageExportSignablePDFMutation>(
|
||||
exportSignableVersionDocumentPDFMutation
|
||||
);
|
||||
|
||||
const [pdfUrl, setPdfUrl] = useState<string | null>(null);
|
||||
const pdfUrlRef = useRef<string | null>(null);
|
||||
|
||||
const handleSign = async (versionId: string) => {
|
||||
await signDocument({
|
||||
variables: {
|
||||
input: {
|
||||
documentVersionId: versionId,
|
||||
},
|
||||
},
|
||||
updater: (store) => {
|
||||
const signableDoc = store.get(documentData.id);
|
||||
if (signableDoc) {
|
||||
signableDoc.setValue(true, "signed");
|
||||
}
|
||||
store.invalidateStore();
|
||||
},
|
||||
onCompleted: () => {
|
||||
navigate(`/organizations/${organizationId}/employee`);
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("Error signing document:", error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedVersion?.id) return;
|
||||
|
||||
exportSignableVersionDocumentPDF({
|
||||
variables: {
|
||||
input: {
|
||||
documentVersionId: selectedVersion.id,
|
||||
},
|
||||
},
|
||||
onCompleted: (data, errors): void => {
|
||||
if (errors) {
|
||||
toast({
|
||||
title: __("Error"),
|
||||
description: formatError(__("Failed to load PDF"), errors as GraphQLError[]),
|
||||
variant: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (data.exportSignableVersionDocumentPDF?.data) {
|
||||
const dataUrl = data.exportSignableVersionDocumentPDF.data;
|
||||
pdfUrlRef.current = dataUrl;
|
||||
setPdfUrl(dataUrl);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
toast({
|
||||
title: __("Error"),
|
||||
description: formatError(__("Failed to load PDF"), error as GraphQLError),
|
||||
variant: "error",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return () => {
|
||||
pdfUrlRef.current = null;
|
||||
};
|
||||
}, [selectedVersion?.id, exportSignableVersionDocumentPDF, toast, __]);
|
||||
|
||||
return (
|
||||
<div className="fixed bg-level-2 flex flex-col" style={{ top: '3rem', left: 0, right: 0, bottom: 0 }}>
|
||||
<div className="grid lg:grid-cols-2 min-h-0 h-full">
|
||||
<div className="w-full lg:w-[440px] mx-auto py-20 overflow-y-auto scrollbar-hide">
|
||||
<h1 className="text-2xl font-semibold mb-6">
|
||||
{documentData.title || ""}
|
||||
</h1>
|
||||
|
||||
<Card className="mb-6 overflow-hidden">
|
||||
<div className="divide-y divide-border-solid">
|
||||
{versions.map((version) => {
|
||||
return (
|
||||
<VersionRow
|
||||
key={version.id}
|
||||
version={version}
|
||||
isSelected={version.id === selectedVersionId}
|
||||
onSelect={() => setSelectedVersionId(version.id)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<p className="text-txt-secondary text-sm mb-6">
|
||||
{__("Please review the document carefully before signing.")}
|
||||
</p>
|
||||
|
||||
<div className="min-h-[60px]">
|
||||
{selectedVersion ? (
|
||||
<VersionActions
|
||||
version={selectedVersion}
|
||||
isSigning={isSigning}
|
||||
onSign={handleSign}
|
||||
onBack={() => navigate(`/organizations/${organizationId}/employee`)}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isDesktop && (
|
||||
<div className="bg-subtle h-full border-l border-border-solid min-h-0">
|
||||
{pdfUrl && <PDFPreview src={pdfUrl} name={documentData.title || ""} />}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function VersionActions({
|
||||
version,
|
||||
isSigning,
|
||||
onSign,
|
||||
onBack,
|
||||
}: {
|
||||
version: EmployeeDocumentSignaturePageVersionFragment$key;
|
||||
isSigning: boolean;
|
||||
onSign: (versionId: string) => void;
|
||||
onBack: () => void;
|
||||
}) {
|
||||
const { __ } = useTranslate();
|
||||
const versionData = useFragment<EmployeeDocumentSignaturePageVersionFragment$key>(
|
||||
versionFragment,
|
||||
version
|
||||
);
|
||||
const isSigned = versionData.signed;
|
||||
|
||||
if (isSigned) {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
onClick={onBack}
|
||||
className="h-10 w-full"
|
||||
variant="secondary"
|
||||
>
|
||||
{__("Back to Documents")}
|
||||
</Button>
|
||||
<p className="text-xs text-txt-tertiary mt-2 h-5" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
onClick={() => onSign(versionData.id)}
|
||||
className="h-10 w-full"
|
||||
disabled={isSigning}
|
||||
icon={isSigning ? Spinner : undefined}
|
||||
>
|
||||
{__("I acknowledge and agree")}
|
||||
</Button>
|
||||
<p className="text-xs text-txt-tertiary mt-2 h-5">
|
||||
{__(
|
||||
"By clicking 'I acknowledge and agree', your digital signature will be recorded."
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function VersionRow({
|
||||
version,
|
||||
isSelected,
|
||||
onSelect,
|
||||
}: {
|
||||
version: EmployeeDocumentSignaturePageVersionFragment$key;
|
||||
isSelected: boolean;
|
||||
onSelect: () => void;
|
||||
}) {
|
||||
const { __ } = useTranslate();
|
||||
const versionData = useFragment<EmployeeDocumentSignaturePageVersionFragment$key>(
|
||||
versionFragment,
|
||||
version
|
||||
);
|
||||
const isVersionSigned = versionData.signed;
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={onSelect}
|
||||
className={clsx(
|
||||
"flex items-center gap-3 py-3 px-4 transition-colors cursor-pointer",
|
||||
isSelected
|
||||
? "bg-blue-50 border-l-4 border-blue-500"
|
||||
: "bg-transparent hover:bg-level-1"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-center w-8 h-8 rounded-full bg-level-2 flex-shrink-0">
|
||||
{isVersionSigned ? (
|
||||
<IconCircleCheck
|
||||
size={20}
|
||||
className="text-txt-success"
|
||||
/>
|
||||
) : (
|
||||
<IconRadioUnchecked
|
||||
size={20}
|
||||
className="text-txt-tertiary"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p
|
||||
className={clsx(
|
||||
"text-sm font-medium truncate",
|
||||
isVersionSigned
|
||||
? "text-txt-tertiary"
|
||||
: "text-txt-primary"
|
||||
)}
|
||||
>
|
||||
{versionData.publishedAt
|
||||
? `v${versionData.version} - ${(() => {
|
||||
const date = new Date(versionData.publishedAt);
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const year = date.getFullYear();
|
||||
return `${day}/${month}/${year}`;
|
||||
})()}`
|
||||
: `v${versionData.version}`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0">
|
||||
<span
|
||||
className={clsx(
|
||||
"inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium",
|
||||
isVersionSigned
|
||||
? "bg-green-100 text-green-800"
|
||||
: isSelected
|
||||
? "bg-blue-100 text-blue-800"
|
||||
: "bg-gray-100 text-gray-700"
|
||||
)}
|
||||
>
|
||||
{isVersionSigned
|
||||
? __("Signed")
|
||||
: isSelected
|
||||
? __("In review")
|
||||
: __("Waiting signature")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import {
|
||||
PageHeader,
|
||||
Tbody,
|
||||
Thead,
|
||||
Tr,
|
||||
Th,
|
||||
Td,
|
||||
Badge,
|
||||
Card,
|
||||
} from "@probo/ui";
|
||||
import { SortableTable } from "/components/SortableTable";
|
||||
import {
|
||||
useFragment,
|
||||
usePaginationFragment,
|
||||
usePreloadedQuery,
|
||||
type PreloadedQuery,
|
||||
} from "react-relay";
|
||||
import { graphql } from "relay-runtime";
|
||||
import type { EmployeeDocumentsPageListQuery } from "./__generated__/EmployeeDocumentsPageListQuery.graphql";
|
||||
import type { EmployeeDocumentsPageListFragment$key } from "./__generated__/EmployeeDocumentsPageListFragment.graphql";
|
||||
import { usePageTitle } from "@probo/hooks";
|
||||
import { getDocumentClassificationLabel, getDocumentTypeLabel, formatDate } from "@probo/helpers";
|
||||
import type { EmployeeDocumentsPageRowFragment$key } from "./__generated__/EmployeeDocumentsPageRowFragment.graphql";
|
||||
import { useEffect } from "react";
|
||||
import { useParams } from "react-router";
|
||||
|
||||
export const employeeDocumentsQuery = graphql`
|
||||
query EmployeeDocumentsPageListQuery($organizationId: ID!) {
|
||||
viewer {
|
||||
id
|
||||
...EmployeeDocumentsPageListFragment @arguments(organizationId: $organizationId)
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const employeeDocumentsFragment = graphql`
|
||||
fragment EmployeeDocumentsPageListFragment on Viewer
|
||||
@refetchable(queryName: "EmployeeDocumentsListQuery")
|
||||
@argumentDefinitions(
|
||||
organizationId: { type: "ID!" }
|
||||
first: { type: "Int", defaultValue: 50 }
|
||||
order: {
|
||||
type: "DocumentOrder"
|
||||
defaultValue: { field: CREATED_AT, direction: DESC }
|
||||
}
|
||||
after: { type: "CursorKey", defaultValue: null }
|
||||
before: { type: "CursorKey", defaultValue: null }
|
||||
last: { type: "Int", defaultValue: null }
|
||||
) {
|
||||
signableDocuments(
|
||||
organizationId: $organizationId
|
||||
first: $first
|
||||
after: $after
|
||||
last: $last
|
||||
before: $before
|
||||
orderBy: $order
|
||||
) @connection(key: "EmployeeDocumentsListQuery_signableDocuments") {
|
||||
__id
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
...EmployeeDocumentsPageRowFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
queryRef: PreloadedQuery<EmployeeDocumentsPageListQuery>;
|
||||
};
|
||||
|
||||
export default function EmployeeDocumentsPage(props: Props) {
|
||||
const { __ } = useTranslate();
|
||||
const params = useParams<{ organizationId: string }>();
|
||||
const organizationId = params.organizationId!;
|
||||
|
||||
const data = usePreloadedQuery(
|
||||
employeeDocumentsQuery,
|
||||
props.queryRef
|
||||
);
|
||||
|
||||
const pagination = usePaginationFragment(
|
||||
employeeDocumentsFragment,
|
||||
data.viewer as EmployeeDocumentsPageListFragment$key
|
||||
);
|
||||
|
||||
const { refetch } = pagination;
|
||||
|
||||
useEffect(() => {
|
||||
refetch({ organizationId }, { fetchPolicy: 'network-only' });
|
||||
}, [organizationId, refetch]);
|
||||
|
||||
const documents = pagination.data.signableDocuments?.edges
|
||||
?.map((edge) => edge?.node)
|
||||
.filter(Boolean) || [];
|
||||
|
||||
usePageTitle(__("Documents"));
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<PageHeader title={__("Documents")} />
|
||||
{documents.length > 0 ? (
|
||||
<SortableTable {...pagination}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th className="min-w-0 pr-12">{__("Name")}</Th>
|
||||
<Th className="w-48">{__("Type")}</Th>
|
||||
<Th className="w-36">{__("Classification")}</Th>
|
||||
<Th className="w-40">{__("Last update")}</Th>
|
||||
<Th className="w-32">{__("Signed")}</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{documents.map((document) => (
|
||||
<DocumentRow key={document.id} document={document} organizationId={organizationId} />
|
||||
))}
|
||||
</Tbody>
|
||||
</SortableTable>
|
||||
) : (
|
||||
<Card padded>
|
||||
<div className="text-center py-12">
|
||||
<h3 className="text-lg font-semibold mb-2">
|
||||
{__("No documents yet")}
|
||||
</h3>
|
||||
<p className="text-txt-tertiary mb-4">
|
||||
{__("No documents have been requested for your signature.")}
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const rowFragment = graphql`
|
||||
fragment EmployeeDocumentsPageRowFragment on SignableDocument {
|
||||
id
|
||||
title
|
||||
documentType
|
||||
classification
|
||||
signed
|
||||
updatedAt
|
||||
}
|
||||
`;
|
||||
|
||||
function DocumentRow({
|
||||
document: documentKey,
|
||||
organizationId,
|
||||
}: {
|
||||
document: EmployeeDocumentsPageRowFragment$key;
|
||||
organizationId: string;
|
||||
}) {
|
||||
const document = useFragment<EmployeeDocumentsPageRowFragment$key>(
|
||||
rowFragment,
|
||||
documentKey
|
||||
);
|
||||
const { __ } = useTranslate();
|
||||
|
||||
return (
|
||||
<Tr
|
||||
to={`/organizations/${organizationId}/employee/${document.id}`}
|
||||
>
|
||||
<Td className="min-w-0 pr-12">{document.title}</Td>
|
||||
<Td className="w-48">{getDocumentTypeLabel(__, document.documentType)}</Td>
|
||||
<Td className="w-36">
|
||||
<Badge variant="neutral">
|
||||
{getDocumentClassificationLabel(__, document.classification)}
|
||||
</Badge>
|
||||
</Td>
|
||||
<Td className="w-40">{formatDate(document.updatedAt)}</Td>
|
||||
<Td className="w-32">
|
||||
<Badge variant={document.signed ? "success" : "danger"}>
|
||||
{document.signed ? __("Yes") : __("No")}
|
||||
</Badge>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @generated SignedSource<<29c63d1f06c36d3670b5a4757b725b95>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type EmployeeDocumentSignaturePageDocumentFragment$data = {
|
||||
readonly id: string;
|
||||
readonly signed: boolean;
|
||||
readonly title: string;
|
||||
readonly versions: {
|
||||
readonly edges: ReadonlyArray<{
|
||||
readonly node: {
|
||||
readonly id: string;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"EmployeeDocumentSignaturePageVersionFragment">;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
readonly " $fragmentType": "EmployeeDocumentSignaturePageDocumentFragment";
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageDocumentFragment$key = {
|
||||
readonly " $data"?: EmployeeDocumentSignaturePageDocumentFragment$data;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"EmployeeDocumentSignaturePageDocumentFragment">;
|
||||
};
|
||||
|
||||
const node: ReaderFragment = (function(){
|
||||
var v0 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"argumentDefinitions": [],
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "EmployeeDocumentSignaturePageDocumentFragment",
|
||||
"selections": [
|
||||
(v0/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "title",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "signed",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": [
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "orderBy",
|
||||
"value": {
|
||||
"direction": "DESC",
|
||||
"field": "CREATED_AT"
|
||||
}
|
||||
}
|
||||
],
|
||||
"concreteType": "DocumentVersionConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "versions",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "DocumentVersionEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "DocumentVersion",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v0/*: any*/),
|
||||
{
|
||||
"args": null,
|
||||
"kind": "FragmentSpread",
|
||||
"name": "EmployeeDocumentSignaturePageVersionFragment"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": "versions(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
|
||||
}
|
||||
],
|
||||
"type": "SignableDocument",
|
||||
"abstractKey": null
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "a516f97725320f4fe0282d70cef83a62";
|
||||
|
||||
export default node;
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @generated SignedSource<<bd62735d2891123ff7f79b1b473d5143>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type ExportSignableDocumentVersionPDFInput = {
|
||||
documentVersionId: string;
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageExportSignablePDFMutation$variables = {
|
||||
input: ExportSignableDocumentVersionPDFInput;
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageExportSignablePDFMutation$data = {
|
||||
readonly exportSignableVersionDocumentPDF: {
|
||||
readonly data: string;
|
||||
};
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageExportSignablePDFMutation = {
|
||||
response: EmployeeDocumentSignaturePageExportSignablePDFMutation$data;
|
||||
variables: EmployeeDocumentSignaturePageExportSignablePDFMutation$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "input"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"alias": null,
|
||||
"args": [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "input",
|
||||
"variableName": "input"
|
||||
}
|
||||
],
|
||||
"concreteType": "ExportSignableDocumentVersionPDFPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "exportSignableVersionDocumentPDF",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "data",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "EmployeeDocumentSignaturePageExportSignablePDFMutation",
|
||||
"selections": (v1/*: any*/),
|
||||
"type": "Mutation",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "EmployeeDocumentSignaturePageExportSignablePDFMutation",
|
||||
"selections": (v1/*: any*/)
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "1bbeaaac843ecd06e9f7ee662aa11fc2",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "EmployeeDocumentSignaturePageExportSignablePDFMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation EmployeeDocumentSignaturePageExportSignablePDFMutation(\n $input: ExportSignableDocumentVersionPDFInput!\n) {\n exportSignableVersionDocumentPDF(input: $input) {\n data\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "39a1e34d4b4f8c98d262dd3a737ebb7c";
|
||||
|
||||
export default node;
|
||||
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* @generated SignedSource<<9e8c0459987993bb4b217618a46fdbf5>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type EmployeeDocumentSignaturePageQuery$variables = {
|
||||
documentId: string;
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageQuery$data = {
|
||||
readonly viewer: {
|
||||
readonly id: string;
|
||||
readonly signableDocument: {
|
||||
readonly id: string;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"EmployeeDocumentSignaturePageDocumentFragment">;
|
||||
} | null | undefined;
|
||||
};
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageQuery = {
|
||||
response: EmployeeDocumentSignaturePageQuery$data;
|
||||
variables: EmployeeDocumentSignaturePageQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "documentId"
|
||||
}
|
||||
],
|
||||
v1 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v2 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "id",
|
||||
"variableName": "documentId"
|
||||
}
|
||||
],
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "signed",
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "EmployeeDocumentSignaturePageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"concreteType": "SignableDocument",
|
||||
"kind": "LinkedField",
|
||||
"name": "signableDocument",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"args": null,
|
||||
"kind": "FragmentSpread",
|
||||
"name": "EmployeeDocumentSignaturePageDocumentFragment"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "EmployeeDocumentSignaturePageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"concreteType": "SignableDocument",
|
||||
"kind": "LinkedField",
|
||||
"name": "signableDocument",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "title",
|
||||
"storageKey": null
|
||||
},
|
||||
(v3/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": [
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "orderBy",
|
||||
"value": {
|
||||
"direction": "DESC",
|
||||
"field": "CREATED_AT"
|
||||
}
|
||||
}
|
||||
],
|
||||
"concreteType": "DocumentVersionConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "versions",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "DocumentVersionEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "DocumentVersion",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "version",
|
||||
"storageKey": null
|
||||
},
|
||||
(v3/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "publishedAt",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": "versions(first:100,orderBy:{\"direction\":\"DESC\",\"field\":\"CREATED_AT\"})"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "a4866db288e1bf46e6562aa06bff4231",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "EmployeeDocumentSignaturePageQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query EmployeeDocumentSignaturePageQuery(\n $documentId: ID!\n) {\n viewer {\n id\n signableDocument(id: $documentId) {\n id\n ...EmployeeDocumentSignaturePageDocumentFragment\n }\n }\n}\n\nfragment EmployeeDocumentSignaturePageDocumentFragment on SignableDocument {\n id\n title\n signed\n versions(first: 100, orderBy: {field: CREATED_AT, direction: DESC}) {\n edges {\n node {\n id\n ...EmployeeDocumentSignaturePageVersionFragment\n }\n }\n }\n}\n\nfragment EmployeeDocumentSignaturePageVersionFragment on DocumentVersion {\n id\n version\n signed\n publishedAt\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "a2ac190853e8f078ff90213605a66e29";
|
||||
|
||||
export default node;
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @generated SignedSource<<ea70fd099349ca45cb2a847b06e28694>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type DocumentVersionSignatureState = "REQUESTED" | "SIGNED";
|
||||
export type SignDocumentInput = {
|
||||
documentVersionId: string;
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageSignMutation$variables = {
|
||||
input: SignDocumentInput;
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageSignMutation$data = {
|
||||
readonly signDocument: {
|
||||
readonly documentVersionSignature: {
|
||||
readonly id: string;
|
||||
readonly state: DocumentVersionSignatureState;
|
||||
};
|
||||
};
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageSignMutation = {
|
||||
response: EmployeeDocumentSignaturePageSignMutation$data;
|
||||
variables: EmployeeDocumentSignaturePageSignMutation$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "input"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"alias": null,
|
||||
"args": [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "input",
|
||||
"variableName": "input"
|
||||
}
|
||||
],
|
||||
"concreteType": "SignDocumentPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "signDocument",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "DocumentVersionSignature",
|
||||
"kind": "LinkedField",
|
||||
"name": "documentVersionSignature",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "state",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "EmployeeDocumentSignaturePageSignMutation",
|
||||
"selections": (v1/*: any*/),
|
||||
"type": "Mutation",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "EmployeeDocumentSignaturePageSignMutation",
|
||||
"selections": (v1/*: any*/)
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "dfdd778fc4b0cfc9c007e4c29258ea96",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "EmployeeDocumentSignaturePageSignMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation EmployeeDocumentSignaturePageSignMutation(\n $input: SignDocumentInput!\n) {\n signDocument(input: $input) {\n documentVersionSignature {\n id\n state\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "b91674332a1914e270e4fb811ccfd479";
|
||||
|
||||
export default node;
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @generated SignedSource<<f05da6a037d3f282ff9ff6d60e2d684d>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type EmployeeDocumentSignaturePageVersionFragment$data = {
|
||||
readonly id: string;
|
||||
readonly publishedAt: any | null | undefined;
|
||||
readonly signed: boolean;
|
||||
readonly version: number;
|
||||
readonly " $fragmentType": "EmployeeDocumentSignaturePageVersionFragment";
|
||||
};
|
||||
export type EmployeeDocumentSignaturePageVersionFragment$key = {
|
||||
readonly " $data"?: EmployeeDocumentSignaturePageVersionFragment$data;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"EmployeeDocumentSignaturePageVersionFragment">;
|
||||
};
|
||||
|
||||
const node: ReaderFragment = {
|
||||
"argumentDefinitions": [],
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "EmployeeDocumentSignaturePageVersionFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "version",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "signed",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "publishedAt",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "DocumentVersion",
|
||||
"abstractKey": null
|
||||
};
|
||||
|
||||
(node as any).hash = "4a85fbbc1bf8b2610f554aa439fd0e95";
|
||||
|
||||
export default node;
|
||||
334
apps/console/src/pages/organizations/employee/__generated__/EmployeeDocumentsListQuery.graphql.ts
generated
Normal file
334
apps/console/src/pages/organizations/employee/__generated__/EmployeeDocumentsListQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* @generated SignedSource<<6caec1429cd03b026975c0e9ef7c76f6>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type DocumentOrderField = "CREATED_AT" | "DOCUMENT_TYPE" | "TITLE";
|
||||
export type OrderDirection = "ASC" | "DESC";
|
||||
export type DocumentOrder = {
|
||||
direction: OrderDirection;
|
||||
field: DocumentOrderField;
|
||||
};
|
||||
export type EmployeeDocumentsListQuery$variables = {
|
||||
after?: any | null | undefined;
|
||||
before?: any | null | undefined;
|
||||
first?: number | null | undefined;
|
||||
last?: number | null | undefined;
|
||||
order?: DocumentOrder | null | undefined;
|
||||
organizationId: string;
|
||||
};
|
||||
export type EmployeeDocumentsListQuery$data = {
|
||||
readonly viewer: {
|
||||
readonly " $fragmentSpreads": FragmentRefs<"EmployeeDocumentsPageListFragment">;
|
||||
};
|
||||
};
|
||||
export type EmployeeDocumentsListQuery = {
|
||||
response: EmployeeDocumentsListQuery$data;
|
||||
variables: EmployeeDocumentsListQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "after"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "before"
|
||||
},
|
||||
{
|
||||
"defaultValue": 50,
|
||||
"kind": "LocalArgument",
|
||||
"name": "first"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "last"
|
||||
},
|
||||
{
|
||||
"defaultValue": {
|
||||
"direction": "DESC",
|
||||
"field": "CREATED_AT"
|
||||
},
|
||||
"kind": "LocalArgument",
|
||||
"name": "order"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
}
|
||||
],
|
||||
v1 = {
|
||||
"kind": "Variable",
|
||||
"name": "after",
|
||||
"variableName": "after"
|
||||
},
|
||||
v2 = {
|
||||
"kind": "Variable",
|
||||
"name": "before",
|
||||
"variableName": "before"
|
||||
},
|
||||
v3 = {
|
||||
"kind": "Variable",
|
||||
"name": "first",
|
||||
"variableName": "first"
|
||||
},
|
||||
v4 = {
|
||||
"kind": "Variable",
|
||||
"name": "last",
|
||||
"variableName": "last"
|
||||
},
|
||||
v5 = {
|
||||
"kind": "Variable",
|
||||
"name": "organizationId",
|
||||
"variableName": "organizationId"
|
||||
},
|
||||
v6 = [
|
||||
(v1/*: any*/),
|
||||
(v2/*: any*/),
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "orderBy",
|
||||
"variableName": "order"
|
||||
},
|
||||
(v5/*: any*/)
|
||||
],
|
||||
v7 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "EmployeeDocumentsListQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"args": [
|
||||
(v1/*: any*/),
|
||||
(v2/*: any*/),
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "order",
|
||||
"variableName": "order"
|
||||
},
|
||||
(v5/*: any*/)
|
||||
],
|
||||
"kind": "FragmentSpread",
|
||||
"name": "EmployeeDocumentsPageListFragment"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "EmployeeDocumentsListQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v6/*: any*/),
|
||||
"concreteType": "SignableDocumentConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "signableDocuments",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "SignableDocumentEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "SignableDocument",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v7/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "title",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "documentType",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "classification",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "signed",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
"kind": "LinkedField",
|
||||
"name": "pageInfo",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasPreviousPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "startCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__id",
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v6/*: any*/),
|
||||
"filters": [
|
||||
"organizationId",
|
||||
"orderBy"
|
||||
],
|
||||
"handle": "connection",
|
||||
"key": "EmployeeDocumentsListQuery_signableDocuments",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "signableDocuments"
|
||||
},
|
||||
(v7/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "32e793fba0e3d2e46857cd1b8c436ba2",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "EmployeeDocumentsListQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query EmployeeDocumentsListQuery(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 50\n $last: Int = null\n $order: DocumentOrder = {field: CREATED_AT, direction: DESC}\n $organizationId: ID!\n) {\n viewer {\n ...EmployeeDocumentsPageListFragment_KjvVI\n id\n }\n}\n\nfragment EmployeeDocumentsPageListFragment_KjvVI on Viewer {\n signableDocuments(organizationId: $organizationId, first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n ...EmployeeDocumentsPageRowFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment EmployeeDocumentsPageRowFragment on SignableDocument {\n id\n title\n documentType\n classification\n signed\n updatedAt\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "ebd2703f79cdf6900b5e42fc3b28932a";
|
||||
|
||||
export default node;
|
||||
231
apps/console/src/pages/organizations/employee/__generated__/EmployeeDocumentsPageListFragment.graphql.ts
generated
Normal file
231
apps/console/src/pages/organizations/employee/__generated__/EmployeeDocumentsPageListFragment.graphql.ts
generated
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* @generated SignedSource<<47bb54b1ca3acc8736d619a74455a9c3>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type EmployeeDocumentsPageListFragment$data = {
|
||||
readonly signableDocuments: {
|
||||
readonly __id: string;
|
||||
readonly edges: ReadonlyArray<{
|
||||
readonly node: {
|
||||
readonly id: string;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"EmployeeDocumentsPageRowFragment">;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
readonly " $fragmentType": "EmployeeDocumentsPageListFragment";
|
||||
};
|
||||
export type EmployeeDocumentsPageListFragment$key = {
|
||||
readonly " $data"?: EmployeeDocumentsPageListFragment$data;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"EmployeeDocumentsPageListFragment">;
|
||||
};
|
||||
|
||||
import EmployeeDocumentsListQuery_graphql from './EmployeeDocumentsListQuery.graphql';
|
||||
|
||||
const node: ReaderFragment = (function(){
|
||||
var v0 = [
|
||||
"signableDocuments"
|
||||
];
|
||||
return {
|
||||
"argumentDefinitions": [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "after"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "before"
|
||||
},
|
||||
{
|
||||
"defaultValue": 50,
|
||||
"kind": "LocalArgument",
|
||||
"name": "first"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "last"
|
||||
},
|
||||
{
|
||||
"defaultValue": {
|
||||
"direction": "DESC",
|
||||
"field": "CREATED_AT"
|
||||
},
|
||||
"kind": "LocalArgument",
|
||||
"name": "order"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
}
|
||||
],
|
||||
"kind": "Fragment",
|
||||
"metadata": {
|
||||
"connection": [
|
||||
{
|
||||
"count": null,
|
||||
"cursor": null,
|
||||
"direction": "bidirectional",
|
||||
"path": (v0/*: any*/)
|
||||
}
|
||||
],
|
||||
"refetch": {
|
||||
"connection": {
|
||||
"forward": {
|
||||
"count": "first",
|
||||
"cursor": "after"
|
||||
},
|
||||
"backward": {
|
||||
"count": "last",
|
||||
"cursor": "before"
|
||||
},
|
||||
"path": (v0/*: any*/)
|
||||
},
|
||||
"fragmentPathInResult": [
|
||||
"viewer"
|
||||
],
|
||||
"operation": EmployeeDocumentsListQuery_graphql
|
||||
}
|
||||
},
|
||||
"name": "EmployeeDocumentsPageListFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": "signableDocuments",
|
||||
"args": [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "orderBy",
|
||||
"variableName": "order"
|
||||
},
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "organizationId",
|
||||
"variableName": "organizationId"
|
||||
}
|
||||
],
|
||||
"concreteType": "SignableDocumentConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "__EmployeeDocumentsListQuery_signableDocuments_connection",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "SignableDocumentEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "SignableDocument",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"args": null,
|
||||
"kind": "FragmentSpread",
|
||||
"name": "EmployeeDocumentsPageRowFragment"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
"kind": "LinkedField",
|
||||
"name": "pageInfo",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasPreviousPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "startCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__id",
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Viewer",
|
||||
"abstractKey": null
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "ebd2703f79cdf6900b5e42fc3b28932a";
|
||||
|
||||
export default node;
|
||||
272
apps/console/src/pages/organizations/employee/__generated__/EmployeeDocumentsPageListQuery.graphql.ts
generated
Normal file
272
apps/console/src/pages/organizations/employee/__generated__/EmployeeDocumentsPageListQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* @generated SignedSource<<fef5f504f43186b294a5acb2b063d1d1>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type EmployeeDocumentsPageListQuery$variables = {
|
||||
organizationId: string;
|
||||
};
|
||||
export type EmployeeDocumentsPageListQuery$data = {
|
||||
readonly viewer: {
|
||||
readonly id: string;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"EmployeeDocumentsPageListFragment">;
|
||||
};
|
||||
};
|
||||
export type EmployeeDocumentsPageListQuery = {
|
||||
response: EmployeeDocumentsPageListQuery$data;
|
||||
variables: EmployeeDocumentsPageListQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
}
|
||||
],
|
||||
v1 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v2 = {
|
||||
"kind": "Variable",
|
||||
"name": "organizationId",
|
||||
"variableName": "organizationId"
|
||||
},
|
||||
v3 = [
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 50
|
||||
},
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "orderBy",
|
||||
"value": {
|
||||
"direction": "DESC",
|
||||
"field": "CREATED_AT"
|
||||
}
|
||||
},
|
||||
(v2/*: any*/)
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "EmployeeDocumentsPageListQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"args": [
|
||||
(v2/*: any*/)
|
||||
],
|
||||
"kind": "FragmentSpread",
|
||||
"name": "EmployeeDocumentsPageListFragment"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "EmployeeDocumentsPageListQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Viewer",
|
||||
"kind": "LinkedField",
|
||||
"name": "viewer",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v3/*: any*/),
|
||||
"concreteType": "SignableDocumentConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "signableDocuments",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "SignableDocumentEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "SignableDocument",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v1/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "title",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "documentType",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "classification",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "signed",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
"kind": "LinkedField",
|
||||
"name": "pageInfo",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasPreviousPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "startCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__id",
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v3/*: any*/),
|
||||
"filters": [
|
||||
"organizationId",
|
||||
"orderBy"
|
||||
],
|
||||
"handle": "connection",
|
||||
"key": "EmployeeDocumentsListQuery_signableDocuments",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "signableDocuments"
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "e0d165b36ce3e65b6c3e7a4d3620ba7e",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "EmployeeDocumentsPageListQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query EmployeeDocumentsPageListQuery(\n $organizationId: ID!\n) {\n viewer {\n id\n ...EmployeeDocumentsPageListFragment_4xMPKw\n }\n}\n\nfragment EmployeeDocumentsPageListFragment_4xMPKw on Viewer {\n signableDocuments(organizationId: $organizationId, first: 50, orderBy: {field: CREATED_AT, direction: DESC}) {\n edges {\n node {\n id\n ...EmployeeDocumentsPageRowFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n}\n\nfragment EmployeeDocumentsPageRowFragment on SignableDocument {\n id\n title\n documentType\n classification\n signed\n updatedAt\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "8c281fd3823eb1894c0b46807e04e370";
|
||||
|
||||
export default node;
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @generated SignedSource<<f3d939f80d769a19b8f8ef64207ae911>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
export type DocumentClassification = "CONFIDENTIAL" | "INTERNAL" | "PUBLIC" | "SECRET";
|
||||
export type DocumentType = "ISMS" | "OTHER" | "POLICY" | "PROCEDURE";
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type EmployeeDocumentsPageRowFragment$data = {
|
||||
readonly classification: DocumentClassification;
|
||||
readonly documentType: DocumentType;
|
||||
readonly id: string;
|
||||
readonly signed: boolean;
|
||||
readonly title: string;
|
||||
readonly updatedAt: any;
|
||||
readonly " $fragmentType": "EmployeeDocumentsPageRowFragment";
|
||||
};
|
||||
export type EmployeeDocumentsPageRowFragment$key = {
|
||||
readonly " $data"?: EmployeeDocumentsPageRowFragment$data;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"EmployeeDocumentsPageRowFragment">;
|
||||
};
|
||||
|
||||
const node: ReaderFragment = {
|
||||
"argumentDefinitions": [],
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "EmployeeDocumentsPageRowFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "title",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "documentType",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "classification",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "signed",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "SignableDocument",
|
||||
"abstractKey": null
|
||||
};
|
||||
|
||||
(node as any).hash = "929301e6f6216fb0678b32061b70dd17";
|
||||
|
||||
export default node;
|
||||
@@ -1,381 +0,0 @@
|
||||
/**
|
||||
* @generated SignedSource<<3292b0059f82a3a5c1316f9312379621>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type NonconformitiesPageQuery$variables = {
|
||||
organizationId: string;
|
||||
snapshotId?: string | null | undefined;
|
||||
};
|
||||
export type NonconformitiesPageQuery$data = {
|
||||
readonly node: {
|
||||
readonly " $fragmentSpreads": FragmentRefs<"NonconformitiesPageFragment">;
|
||||
};
|
||||
};
|
||||
export type NonconformitiesPageQuery = {
|
||||
response: NonconformitiesPageQuery$data;
|
||||
variables: NonconformitiesPageQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "snapshotId"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "id",
|
||||
"variableName": "organizationId"
|
||||
}
|
||||
],
|
||||
v2 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "snapshotId",
|
||||
"variableName": "snapshotId"
|
||||
}
|
||||
],
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
v4 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v5 = [
|
||||
{
|
||||
"fields": (v2/*: any*/),
|
||||
"kind": "ObjectValue",
|
||||
"name": "filter"
|
||||
},
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 10
|
||||
}
|
||||
],
|
||||
v6 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "name",
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "NonconformitiesPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"args": (v2/*: any*/),
|
||||
"kind": "FragmentSpread",
|
||||
"name": "NonconformitiesPageFragment"
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "NonconformitiesPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"concreteType": "NonconformityConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "nonconformities",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "totalCount",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "NonconformityEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Nonconformity",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "referenceId",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "snapshotId",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "description",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "dateIdentified",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "dueDate",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "rootCause",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "correctiveAction",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "effectivenessCheck",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Audit",
|
||||
"kind": "LinkedField",
|
||||
"name": "audit",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
(v6/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Framework",
|
||||
"kind": "LinkedField",
|
||||
"name": "framework",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
(v6/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "People",
|
||||
"kind": "LinkedField",
|
||||
"name": "owner",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "fullName",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "createdAt",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
},
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
"kind": "LinkedField",
|
||||
"name": "pageInfo",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__id",
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"filters": [
|
||||
"filter"
|
||||
],
|
||||
"handle": "connection",
|
||||
"key": "NonconformitiesPage_nonconformities",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "nonconformities"
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "b4f53542e4ea747099f28629d5e8a0bb",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "NonconformitiesPageQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query NonconformitiesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...NonconformitiesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment NonconformitiesPageFragment_3iomuz on Organization {\n id\n nonconformities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n referenceId\n snapshotId\n description\n status\n dateIdentified\n dueDate\n rootCause\n correctiveAction\n effectivenessCheck\n audit {\n id\n name\n framework {\n id\n name\n }\n }\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "af4a93239b6065756759b4958980b846";
|
||||
|
||||
export default node;
|
||||
@@ -1,355 +0,0 @@
|
||||
/**
|
||||
* @generated SignedSource<<445c6cc243eadbe9e5eacdec0161ee62>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type ObligationsPageQuery$variables = {
|
||||
organizationId: string;
|
||||
snapshotId?: string | null | undefined;
|
||||
};
|
||||
export type ObligationsPageQuery$data = {
|
||||
readonly node: {
|
||||
readonly " $fragmentSpreads": FragmentRefs<"ObligationsPageFragment">;
|
||||
};
|
||||
};
|
||||
export type ObligationsPageQuery = {
|
||||
response: ObligationsPageQuery$data;
|
||||
variables: ObligationsPageQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "snapshotId"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "id",
|
||||
"variableName": "organizationId"
|
||||
}
|
||||
],
|
||||
v2 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "snapshotId",
|
||||
"variableName": "snapshotId"
|
||||
}
|
||||
],
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
v4 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v5 = [
|
||||
{
|
||||
"fields": (v2/*: any*/),
|
||||
"kind": "ObjectValue",
|
||||
"name": "filter"
|
||||
},
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 10
|
||||
}
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "ObligationsPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"args": (v2/*: any*/),
|
||||
"kind": "FragmentSpread",
|
||||
"name": "ObligationsPageFragment"
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "ObligationsPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"concreteType": "ObligationConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "obligations",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "totalCount",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "ObligationEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "Obligation",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "snapshotId",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "sourceId",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "area",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "source",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "requirement",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "status",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "lastReviewDate",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "dueDate",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "actionsToBeImplemented",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "regulator",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "People",
|
||||
"kind": "LinkedField",
|
||||
"name": "owner",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "fullName",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "createdAt",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
},
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
"kind": "LinkedField",
|
||||
"name": "pageInfo",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__id",
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"filters": [
|
||||
"filter"
|
||||
],
|
||||
"handle": "connection",
|
||||
"key": "ObligationsPage_obligations",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "obligations"
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "9a4d2f4ac3be91001f8c9bb602cd599f",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "ObligationsPageQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query ObligationsPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ObligationsPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ObligationsPageFragment_3iomuz on Organization {\n id\n obligations(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n area\n source\n requirement\n status\n lastReviewDate\n dueDate\n actionsToBeImplemented\n regulator\n owner {\n id\n fullName\n }\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "720209ab225ef7a42f1edb96e5d58aa1";
|
||||
|
||||
export default node;
|
||||
@@ -1,329 +0,0 @@
|
||||
/**
|
||||
* @generated SignedSource<<f85f96db81638fcf82015c2a936d6ed0>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type ProcessingActivitiesPageQuery$variables = {
|
||||
organizationId: string;
|
||||
snapshotId?: string | null | undefined;
|
||||
};
|
||||
export type ProcessingActivitiesPageQuery$data = {
|
||||
readonly node: {
|
||||
readonly " $fragmentSpreads": FragmentRefs<"ProcessingActivitiesPageFragment">;
|
||||
};
|
||||
};
|
||||
export type ProcessingActivitiesPageQuery = {
|
||||
response: ProcessingActivitiesPageQuery$data;
|
||||
variables: ProcessingActivitiesPageQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
},
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "snapshotId"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "id",
|
||||
"variableName": "organizationId"
|
||||
}
|
||||
],
|
||||
v2 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "snapshotId",
|
||||
"variableName": "snapshotId"
|
||||
}
|
||||
],
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
v4 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v5 = [
|
||||
{
|
||||
"fields": (v2/*: any*/),
|
||||
"kind": "ObjectValue",
|
||||
"name": "filter"
|
||||
},
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 10
|
||||
}
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "ProcessingActivitiesPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"args": (v2/*: any*/),
|
||||
"kind": "FragmentSpread",
|
||||
"name": "ProcessingActivitiesPageFragment"
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "ProcessingActivitiesPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"concreteType": "ProcessingActivityConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "processingActivities",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "totalCount",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "ProcessingActivityEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "ProcessingActivity",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "snapshotId",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "sourceId",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "name",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "purpose",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "dataSubjectCategory",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "personalDataCategory",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "lawfulBasis",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "location",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "internationalTransfers",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "createdAt",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
},
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
"kind": "LinkedField",
|
||||
"name": "pageInfo",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasNextPage",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__id",
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"filters": [
|
||||
"filter"
|
||||
],
|
||||
"handle": "connection",
|
||||
"key": "ProcessingActivitiesPage_processingActivities",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "processingActivities"
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "dfb1835056b3e318e7d1b8a9e351dcaf",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "ProcessingActivitiesPageQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query ProcessingActivitiesPageQuery(\n $organizationId: ID!\n $snapshotId: ID\n) {\n node(id: $organizationId) {\n __typename\n ... on Organization {\n ...ProcessingActivitiesPageFragment_3iomuz\n }\n id\n }\n}\n\nfragment ProcessingActivitiesPageFragment_3iomuz on Organization {\n id\n processingActivities(first: 10, filter: {snapshotId: $snapshotId}) {\n totalCount\n edges {\n node {\n id\n snapshotId\n sourceId\n name\n purpose\n dataSubjectCategory\n personalDataCategory\n lawfulBasis\n location\n internationalTransfers\n createdAt\n updatedAt\n __typename\n }\n cursor\n }\n pageInfo {\n hasNextPage\n endCursor\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "68aa1223c7d37dec18879900c126bd42";
|
||||
|
||||
export default node;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<0a1a073bbc42108dd13e235594c27457>>
|
||||
* @generated SignedSource<<0bd95d20e79294c530610625c86e88d7>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
export type InvitationStatus = "ACCEPTED" | "EXPIRED" | "PENDING";
|
||||
export type MembershipRole = "ADMIN" | "OWNER" | "VIEWER";
|
||||
export type MembershipRole = "ADMIN" | "EMPLOYEE" | "OWNER" | "VIEWER";
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type MembersSettingsTabInvitationsFragment$data = {
|
||||
readonly id: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<752dcbc2d152883fa2ac09b52039f01c>>
|
||||
* @generated SignedSource<<8fcd99714c4bf7dba138fcb0de398a3a>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -9,7 +9,7 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { ReaderFragment } from 'relay-runtime';
|
||||
export type MembershipRole = "ADMIN" | "OWNER" | "VIEWER";
|
||||
export type MembershipRole = "ADMIN" | "EMPLOYEE" | "OWNER" | "VIEWER";
|
||||
export type UserAuthMethod = "PASSWORD" | "SAML";
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type MembersSettingsTabMembershipsFragment$data = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<562744e07bdb502c26aebe267b181b0e>>
|
||||
* @generated SignedSource<<9aaf763355340403cfd0c9666b61be19>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -9,7 +9,7 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type MembershipRole = "ADMIN" | "OWNER" | "VIEWER";
|
||||
export type MembershipRole = "ADMIN" | "EMPLOYEE" | "OWNER" | "VIEWER";
|
||||
export type UpdateMembershipInput = {
|
||||
memberId: string;
|
||||
organizationId: string;
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
useRouteError,
|
||||
} from "react-router";
|
||||
import { MainLayout } from "./layouts/MainLayout";
|
||||
import { EmployeeLayout } from "./layouts/EmployeeLayout";
|
||||
import { AuthLayout, CenteredLayout, CenteredLayoutSkeleton } from "@probo/ui";
|
||||
import { Fragment } from "react";
|
||||
import {
|
||||
relayEnvironment,
|
||||
UnAuthenticatedError,
|
||||
@@ -36,6 +36,11 @@ import { continualImprovementRoutes } from "./routes/continualImprovementRoutes.
|
||||
import { processingActivityRoutes } from "./routes/processingActivityRoutes.ts";
|
||||
import { lazy } from "@probo/react-lazy";
|
||||
import { loaderFromQueryLoader, routeFromAppRoute, withQueryRef, type AppRoute } from "@probo/routes";
|
||||
import { employeeDocumentsQuery } from "./pages/organizations/employee/EmployeeDocumentsPage";
|
||||
import { employeeDocumentSignatureQuery } from "./pages/organizations/employee/EmployeeDocumentSignaturePage";
|
||||
import { Role } from "@probo/helpers";
|
||||
import { PermissionsContext } from "./providers/PermissionsContext";
|
||||
import { use } from "react";
|
||||
|
||||
/**
|
||||
* Top level error boundary
|
||||
@@ -117,6 +122,40 @@ const routes = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/organizations/:organizationId/employee",
|
||||
Component: EmployeeLayout,
|
||||
ErrorBoundary: ErrorBoundary,
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
Fallback: PageSkeleton,
|
||||
loader: loaderFromQueryLoader(
|
||||
({ organizationId }) =>
|
||||
loadQuery(relayEnvironment, employeeDocumentsQuery, {
|
||||
organizationId: organizationId!,
|
||||
})
|
||||
),
|
||||
Component: withQueryRef(lazy(
|
||||
() => import("./pages/organizations/employee/EmployeeDocumentsPage")
|
||||
)),
|
||||
},
|
||||
{
|
||||
path: ":documentId",
|
||||
Fallback: PageSkeleton,
|
||||
ErrorBoundary: ErrorBoundary,
|
||||
loader: loaderFromQueryLoader(
|
||||
({ documentId }) =>
|
||||
loadQuery(relayEnvironment, employeeDocumentSignatureQuery, {
|
||||
documentId: documentId!,
|
||||
})
|
||||
),
|
||||
Component: withQueryRef(lazy(
|
||||
() => import("./pages/organizations/employee/EmployeeDocumentSignaturePage")
|
||||
)),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/organizations/:organizationId",
|
||||
Component: MainLayout,
|
||||
@@ -124,10 +163,13 @@ const routes = [
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
loader: () => {
|
||||
throw redirect(`tasks`);
|
||||
Component: () => {
|
||||
const { role } = use(PermissionsContext);
|
||||
if (role === Role.EMPLOYEE) {
|
||||
return <Navigate to="employee" />;
|
||||
}
|
||||
return <Navigate to="tasks" />;
|
||||
},
|
||||
Component: Fragment,
|
||||
},
|
||||
{
|
||||
path: "settings",
|
||||
|
||||
@@ -2,6 +2,7 @@ export const Role = {
|
||||
OWNER: "OWNER",
|
||||
ADMIN: "ADMIN",
|
||||
VIEWER: "VIEWER",
|
||||
EMPLOYEE: "EMPLOYEE",
|
||||
} as const
|
||||
|
||||
export type Role = (typeof Role)[keyof typeof Role];
|
||||
@@ -16,4 +17,4 @@ export function getAssignableRoles(currentRole: Role): Role[] {
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func MapSAMLRoleToSystemRole(samlRole string) *coredata.MembershipRole {
|
||||
|
||||
func isValidRole(role string) bool {
|
||||
switch role {
|
||||
case "OWNER", "ADMIN", "VIEWER":
|
||||
case "OWNER", "ADMIN", "EMPLOYEE", "VIEWER":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
||||
@@ -27,10 +27,11 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
RoleOwner Role = "OWNER"
|
||||
RoleAdmin Role = "ADMIN"
|
||||
RoleViewer Role = "VIEWER"
|
||||
RoleFull Role = "FULL"
|
||||
RoleOwner Role = "OWNER"
|
||||
RoleAdmin Role = "ADMIN"
|
||||
RoleEmployee Role = "EMPLOYEE"
|
||||
RoleViewer Role = "VIEWER"
|
||||
RoleFull Role = "FULL"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -43,6 +44,7 @@ const (
|
||||
ActionGetBusinessOwner Action = "getBusinessOwner"
|
||||
ActionGetCustomDomain Action = "getCustomDomain"
|
||||
ActionGetDataPrivacyAgreement Action = "getDataPrivacyAgreement"
|
||||
ActionGetDocument Action = "getDocument"
|
||||
ActionGetFile Action = "getFile"
|
||||
ActionGetFileUrl Action = "getFileUrl"
|
||||
ActionGetFramework Action = "getFramework"
|
||||
@@ -53,6 +55,8 @@ const (
|
||||
ActionGetOrganization Action = "getOrganization"
|
||||
ActionGetOwner Action = "getOwner"
|
||||
ActionGetSecurityOwner Action = "getSecurityOwner"
|
||||
ActionGetSigned Action = "getSigned"
|
||||
ActionGetSignableDocument Action = "getSignableDocument"
|
||||
ActionGetSnapshot Action = "getSnapshot"
|
||||
ActionGetTask Action = "getTask"
|
||||
ActionGetTrustCenter Action = "getTrustCenter"
|
||||
@@ -62,7 +66,6 @@ const (
|
||||
ActionActiveCount Action = "activeCount"
|
||||
ActionAudit Action = "audit"
|
||||
ActionAvailableDocumentAccesses Action = "availableDocumentAccesses"
|
||||
ActionDocument Action = "document"
|
||||
ActionDocumentVersion Action = "documentVersion"
|
||||
ActionDownloadUrl Action = "downloadUrl"
|
||||
ActionMemberships Action = "memberships"
|
||||
@@ -77,36 +80,38 @@ const (
|
||||
ActionTotalCount Action = "totalCount"
|
||||
ActionTrustCenterFile Action = "trustCenterFile"
|
||||
|
||||
ActionListAccesses Action = "listAccesses"
|
||||
ActionListAssets Action = "listAssets"
|
||||
ActionListAudits Action = "listAudits"
|
||||
ActionListComplianceReports Action = "listComplianceReports"
|
||||
ActionListContacts Action = "listContacts"
|
||||
ActionListContinualImprovements Action = "listContinualImprovements"
|
||||
ActionListControls Action = "listControls"
|
||||
ActionListData Action = "listData"
|
||||
ActionListDocuments Action = "listDocuments"
|
||||
ActionListEvidences Action = "listEvidences"
|
||||
ActionListFrameworks Action = "listFrameworks"
|
||||
ActionListInvitations Action = "listInvitations"
|
||||
ActionListMeasures Action = "listMeasures"
|
||||
ActionListMeetings Action = "listMeetings"
|
||||
ActionListMembers Action = "listMembers"
|
||||
ActionListNonconformities Action = "listNonconformities"
|
||||
ActionListObligations Action = "listObligations"
|
||||
ActionListPeople Action = "listPeople"
|
||||
ActionListProcessingActivities Action = "listProcessingActivities"
|
||||
ActionListReferences Action = "listReferences"
|
||||
ActionListRiskAssessments Action = "listRiskAssessments"
|
||||
ActionListRisks Action = "listRisks"
|
||||
ActionListSAMLConfigurations Action = "listSAMLConfigurations"
|
||||
ActionListServices Action = "listServices"
|
||||
ActionListSlackConnections Action = "listSlackConnections"
|
||||
ActionListSnapshots Action = "listSnapshots"
|
||||
ActionListTasks Action = "listTasks"
|
||||
ActionListTrustCenterFiles Action = "listTrustCenterFiles"
|
||||
ActionListVendors Action = "listVendors"
|
||||
ActionListVersions Action = "listVersions"
|
||||
ActionListAccesses Action = "listAccesses"
|
||||
ActionListAssets Action = "listAssets"
|
||||
ActionListAudits Action = "listAudits"
|
||||
ActionListComplianceReports Action = "listComplianceReports"
|
||||
ActionListContacts Action = "listContacts"
|
||||
ActionListContinualImprovements Action = "listContinualImprovements"
|
||||
ActionListControls Action = "listControls"
|
||||
ActionListData Action = "listData"
|
||||
ActionListDocuments Action = "listDocuments"
|
||||
ActionListEvidences Action = "listEvidences"
|
||||
ActionListFrameworks Action = "listFrameworks"
|
||||
ActionListInvitations Action = "listInvitations"
|
||||
ActionListMeasures Action = "listMeasures"
|
||||
ActionListMeetings Action = "listMeetings"
|
||||
ActionListMembers Action = "listMembers"
|
||||
ActionListNonconformities Action = "listNonconformities"
|
||||
ActionListObligations Action = "listObligations"
|
||||
ActionListPeople Action = "listPeople"
|
||||
ActionListProcessingActivities Action = "listProcessingActivities"
|
||||
ActionListReferences Action = "listReferences"
|
||||
ActionListRiskAssessments Action = "listRiskAssessments"
|
||||
ActionListRisks Action = "listRisks"
|
||||
ActionListSAMLConfigurations Action = "listSAMLConfigurations"
|
||||
ActionListServices Action = "listServices"
|
||||
ActionListSlackConnections Action = "listSlackConnections"
|
||||
ActionListSnapshots Action = "listSnapshots"
|
||||
ActionListTasks Action = "listTasks"
|
||||
ActionListTrustCenterFiles Action = "listTrustCenterFiles"
|
||||
ActionListVendors Action = "listVendors"
|
||||
ActionListVersions Action = "listVersions"
|
||||
ActionListSignableDocuments Action = "listSignableDocuments"
|
||||
ActionListSignableDocumentVersion Action = "listSignableDocumentVersion"
|
||||
|
||||
ActionCreateAsset Action = "createAsset"
|
||||
ActionCreateAudit Action = "createAudit"
|
||||
@@ -222,10 +227,12 @@ const (
|
||||
ActionBulkPublishDocumentVersions Action = "bulkPublishDocumentVersions"
|
||||
ActionBulkRequestSignatures Action = "bulkRequestSignatures"
|
||||
ActionCancelSignatureRequest Action = "cancelSignatureRequest"
|
||||
ActionSignDocument Action = "signDocument"
|
||||
ActionConfirmEmail Action = "confirmEmail"
|
||||
ActionDisableSAML Action = "disableSAML"
|
||||
ActionEnableSAML Action = "enableSAML"
|
||||
ActionExportDocumentVersionPDF Action = "exportDocumentVersionPDF"
|
||||
ActionExportSignableVersionDocumentPDF Action = "exportSignableVersionDocumentPDF"
|
||||
ActionExportFramework Action = "exportFramework"
|
||||
ActionGenerateDocumentChangelog Action = "generateDocumentChangelog"
|
||||
ActionGenerateFrameworkStateOfApplicability Action = "generateFrameworkStateOfApplicability"
|
||||
@@ -248,45 +255,47 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
AllRoles = []Role{RoleOwner, RoleAdmin, RoleViewer, RoleFull}
|
||||
EditRoles = []Role{RoleOwner, RoleAdmin, RoleFull}
|
||||
AllRoles = []Role{RoleOwner, RoleAdmin, RoleEmployee, RoleViewer, RoleFull}
|
||||
NonEmployeeRoles = []Role{RoleOwner, RoleAdmin, RoleViewer, RoleFull}
|
||||
EditRoles = []Role{RoleOwner, RoleAdmin, RoleFull}
|
||||
)
|
||||
|
||||
var Permissions = map[uint16]map[Action][]Role{
|
||||
coredata.OrganizationEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetLogoUrl: AllRoles,
|
||||
ActionGetHorizontalLogoUrl: AllRoles,
|
||||
ActionMemberships: AllRoles,
|
||||
ActionPeoples: AllRoles,
|
||||
ActionTotalCount: AllRoles,
|
||||
ActionListMembers: AllRoles,
|
||||
ActionListInvitations: AllRoles,
|
||||
ActionListSlackConnections: AllRoles,
|
||||
ActionListFrameworks: AllRoles,
|
||||
ActionListControls: AllRoles,
|
||||
ActionListVendors: AllRoles,
|
||||
ActionListPeople: AllRoles,
|
||||
ActionListDocuments: AllRoles,
|
||||
ActionListMeetings: AllRoles,
|
||||
ActionListMeasures: AllRoles,
|
||||
ActionListRisks: AllRoles,
|
||||
ActionListTasks: AllRoles,
|
||||
ActionListAssets: AllRoles,
|
||||
ActionListData: AllRoles,
|
||||
ActionListAudits: AllRoles,
|
||||
ActionListNonconformities: AllRoles,
|
||||
ActionListObligations: AllRoles,
|
||||
ActionListContinualImprovements: AllRoles,
|
||||
ActionListProcessingActivities: AllRoles,
|
||||
ActionListSnapshots: AllRoles,
|
||||
ActionListTrustCenterFiles: AllRoles,
|
||||
ActionGetTrustCenter: AllRoles,
|
||||
ActionAudit: AllRoles,
|
||||
ActionGetCustomDomain: AllRoles,
|
||||
ActionListSAMLConfigurations: AllRoles,
|
||||
ActionConfirmEmail: AllRoles,
|
||||
ActionAcceptInvitation: AllRoles,
|
||||
ActionGet: AllRoles,
|
||||
ActionListSignableDocuments: AllRoles,
|
||||
ActionGetLogoUrl: AllRoles,
|
||||
|
||||
ActionListDocuments: NonEmployeeRoles,
|
||||
ActionGetHorizontalLogoUrl: NonEmployeeRoles,
|
||||
ActionMemberships: NonEmployeeRoles,
|
||||
ActionPeoples: NonEmployeeRoles,
|
||||
ActionTotalCount: NonEmployeeRoles,
|
||||
ActionListMembers: NonEmployeeRoles,
|
||||
ActionListInvitations: NonEmployeeRoles,
|
||||
ActionListSlackConnections: NonEmployeeRoles,
|
||||
ActionListFrameworks: NonEmployeeRoles,
|
||||
ActionListControls: NonEmployeeRoles,
|
||||
ActionListVendors: NonEmployeeRoles,
|
||||
ActionListPeople: NonEmployeeRoles,
|
||||
ActionListMeetings: NonEmployeeRoles,
|
||||
ActionListMeasures: NonEmployeeRoles,
|
||||
ActionListRisks: NonEmployeeRoles,
|
||||
ActionListTasks: NonEmployeeRoles,
|
||||
ActionListAssets: NonEmployeeRoles,
|
||||
ActionListData: NonEmployeeRoles,
|
||||
ActionListAudits: NonEmployeeRoles,
|
||||
ActionListNonconformities: NonEmployeeRoles,
|
||||
ActionListObligations: NonEmployeeRoles,
|
||||
ActionListContinualImprovements: NonEmployeeRoles,
|
||||
ActionListProcessingActivities: NonEmployeeRoles,
|
||||
ActionListSnapshots: NonEmployeeRoles,
|
||||
ActionListTrustCenterFiles: NonEmployeeRoles,
|
||||
ActionGetTrustCenter: NonEmployeeRoles,
|
||||
ActionGetCustomDomain: NonEmployeeRoles,
|
||||
ActionListSAMLConfigurations: NonEmployeeRoles,
|
||||
ActionConfirmEmail: NonEmployeeRoles,
|
||||
ActionAcceptInvitation: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateOrganization: EditRoles,
|
||||
ActionDeleteOrganizationHorizontalLogo: EditRoles,
|
||||
@@ -325,11 +334,11 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionDeleteOrganization: {RoleOwner},
|
||||
},
|
||||
coredata.TrustCenterEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetNdaFileUrl: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionListAccesses: AllRoles,
|
||||
ActionListReferences: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetNdaFileUrl: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionListAccesses: NonEmployeeRoles,
|
||||
ActionListReferences: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateTrustCenter: EditRoles,
|
||||
ActionUploadTrustCenterNDA: EditRoles,
|
||||
@@ -338,62 +347,59 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionCreateTrustCenterReference: EditRoles,
|
||||
},
|
||||
coredata.TrustCenterAccessEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionActiveCount: AllRoles,
|
||||
ActionPendingRequestCount: AllRoles,
|
||||
ActionAvailableDocumentAccesses: AllRoles,
|
||||
ActionDocument: AllRoles,
|
||||
ActionReport: AllRoles,
|
||||
ActionTrustCenterFile: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionActiveCount: NonEmployeeRoles,
|
||||
ActionPendingRequestCount: NonEmployeeRoles,
|
||||
ActionAvailableDocumentAccesses: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateTrustCenterAccess: EditRoles,
|
||||
ActionDeleteTrustCenterAccess: EditRoles,
|
||||
},
|
||||
coredata.TrustCenterReferenceEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetLogoUrl: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetLogoUrl: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateTrustCenterReference: EditRoles,
|
||||
ActionDeleteTrustCenterReference: EditRoles,
|
||||
},
|
||||
coredata.TrustCenterFileEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetFileUrl: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetFileUrl: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateTrustCenterFile: EditRoles,
|
||||
ActionGetTrustCenterFile: EditRoles,
|
||||
ActionDeleteTrustCenterFile: EditRoles,
|
||||
},
|
||||
coredata.UserEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
},
|
||||
coredata.MembershipEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetAuthMethod: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetAuthMethod: NonEmployeeRoles,
|
||||
},
|
||||
coredata.InvitationEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
|
||||
ActionDeleteInvitation: EditRoles,
|
||||
},
|
||||
coredata.PeopleEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
|
||||
ActionUpdatePeople: EditRoles,
|
||||
ActionDeletePeople: EditRoles,
|
||||
},
|
||||
coredata.VendorEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionListComplianceReports: AllRoles,
|
||||
ActionGetBusinessAssociateAgreement: AllRoles,
|
||||
ActionGetDataPrivacyAgreement: AllRoles,
|
||||
ActionListContacts: AllRoles,
|
||||
ActionListServices: AllRoles,
|
||||
ActionListRiskAssessments: AllRoles,
|
||||
ActionGetBusinessOwner: AllRoles,
|
||||
ActionGetSecurityOwner: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionListComplianceReports: NonEmployeeRoles,
|
||||
ActionGetBusinessAssociateAgreement: NonEmployeeRoles,
|
||||
ActionGetDataPrivacyAgreement: NonEmployeeRoles,
|
||||
ActionListContacts: NonEmployeeRoles,
|
||||
ActionListServices: NonEmployeeRoles,
|
||||
ActionListRiskAssessments: NonEmployeeRoles,
|
||||
ActionGetBusinessOwner: NonEmployeeRoles,
|
||||
ActionGetSecurityOwner: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateVendor: EditRoles,
|
||||
ActionDeleteVendor: EditRoles,
|
||||
@@ -407,49 +413,49 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionAssessVendor: EditRoles,
|
||||
},
|
||||
coredata.VendorComplianceReportEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetVendor: AllRoles,
|
||||
ActionGetFile: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetVendor: NonEmployeeRoles,
|
||||
ActionGetFile: NonEmployeeRoles,
|
||||
|
||||
ActionDeleteVendorComplianceReport: EditRoles,
|
||||
},
|
||||
coredata.VendorBusinessAssociateAgreementEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetVendor: AllRoles,
|
||||
ActionGetFileUrl: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetVendor: NonEmployeeRoles,
|
||||
ActionGetFileUrl: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateVendorBusinessAssociateAgreement: EditRoles,
|
||||
ActionDeleteVendorBusinessAssociateAgreement: EditRoles,
|
||||
},
|
||||
coredata.VendorContactEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetVendor: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetVendor: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateVendorContact: EditRoles,
|
||||
ActionDeleteVendorContact: EditRoles,
|
||||
},
|
||||
coredata.VendorServiceEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetVendor: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetVendor: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateVendorService: EditRoles,
|
||||
ActionDeleteVendorService: EditRoles,
|
||||
},
|
||||
coredata.VendorDataPrivacyAgreementEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetVendor: AllRoles,
|
||||
ActionGetFileUrl: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetVendor: NonEmployeeRoles,
|
||||
ActionGetFileUrl: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateVendorDataPrivacyAgreement: EditRoles,
|
||||
ActionDeleteVendorDataPrivacyAgreement: EditRoles,
|
||||
},
|
||||
coredata.VendorRiskAssessmentEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
},
|
||||
coredata.FrameworkEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionListControls: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionListControls: NonEmployeeRoles,
|
||||
|
||||
ActionCreateControl: EditRoles,
|
||||
ActionUpdateFramework: EditRoles,
|
||||
@@ -458,12 +464,12 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionExportFramework: EditRoles,
|
||||
},
|
||||
coredata.ControlEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetFramework: AllRoles,
|
||||
ActionListMeasures: AllRoles,
|
||||
ActionListDocuments: AllRoles,
|
||||
ActionListAudits: AllRoles,
|
||||
ActionListSnapshots: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetFramework: NonEmployeeRoles,
|
||||
ActionListMeasures: NonEmployeeRoles,
|
||||
ActionListDocuments: NonEmployeeRoles,
|
||||
ActionListAudits: NonEmployeeRoles,
|
||||
ActionListSnapshots: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateControl: EditRoles,
|
||||
ActionDeleteControl: EditRoles,
|
||||
@@ -477,23 +483,23 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionDeleteControlSnapshotMapping: EditRoles,
|
||||
},
|
||||
coredata.MeasureEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionListEvidences: AllRoles,
|
||||
ActionListTasks: AllRoles,
|
||||
ActionListRisks: AllRoles,
|
||||
ActionListControls: AllRoles,
|
||||
ActionTotalCount: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionListEvidences: NonEmployeeRoles,
|
||||
ActionListTasks: NonEmployeeRoles,
|
||||
ActionListRisks: NonEmployeeRoles,
|
||||
ActionListControls: NonEmployeeRoles,
|
||||
ActionTotalCount: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateMeasure: EditRoles,
|
||||
ActionDeleteMeasure: EditRoles,
|
||||
ActionUploadMeasureEvidence: EditRoles,
|
||||
},
|
||||
coredata.TaskEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetAssignedTo: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionGetMeasure: AllRoles,
|
||||
ActionListEvidences: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetAssignedTo: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionGetMeasure: NonEmployeeRoles,
|
||||
ActionListEvidences: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateTask: EditRoles,
|
||||
ActionDeleteTask: EditRoles,
|
||||
@@ -501,28 +507,31 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionUnassignTask: EditRoles,
|
||||
},
|
||||
coredata.EvidenceEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetFile: AllRoles,
|
||||
ActionGetTask: AllRoles,
|
||||
ActionGetMeasure: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetFile: NonEmployeeRoles,
|
||||
ActionGetTask: NonEmployeeRoles,
|
||||
ActionGetMeasure: NonEmployeeRoles,
|
||||
|
||||
ActionDeleteEvidence: EditRoles,
|
||||
},
|
||||
coredata.DocumentEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionExportDocumentVersionPDF: AllRoles,
|
||||
ActionGetOwner: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionListVersions: AllRoles,
|
||||
ActionListControls: AllRoles,
|
||||
ActionTotalCount: AllRoles,
|
||||
ActionListSignableDocumentVersion: AllRoles,
|
||||
ActionGetSigned: AllRoles,
|
||||
ActionGetSignableDocument: AllRoles,
|
||||
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOwner: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionBulkExportDocuments: NonEmployeeRoles,
|
||||
ActionTotalCount: NonEmployeeRoles,
|
||||
ActionListControls: NonEmployeeRoles,
|
||||
ActionListVersions: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateDocument: EditRoles,
|
||||
ActionDeleteDocument: EditRoles,
|
||||
ActionPublishDocumentVersion: EditRoles,
|
||||
ActionBulkPublishDocumentVersions: EditRoles,
|
||||
ActionBulkDeleteDocuments: EditRoles,
|
||||
ActionBulkExportDocuments: EditRoles,
|
||||
ActionGenerateDocumentChangelog: EditRoles,
|
||||
ActionCreateDraftDocumentVersion: EditRoles,
|
||||
ActionDeleteDraftDocumentVersion: EditRoles,
|
||||
@@ -533,33 +542,35 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionCancelSignatureRequest: EditRoles,
|
||||
},
|
||||
coredata.DocumentVersionEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetFile: AllRoles,
|
||||
ActionGetOwner: AllRoles,
|
||||
ActionDocument: AllRoles,
|
||||
ActionSignatures: AllRoles,
|
||||
ActionExportDocumentVersionPDF: AllRoles,
|
||||
ActionSignDocument: AllRoles,
|
||||
|
||||
ActionUpdateDocumentVersion: EditRoles,
|
||||
ActionRequestSignature: EditRoles,
|
||||
ActionBulkRequestSignatures: EditRoles,
|
||||
ActionSendSigningNotifications: EditRoles,
|
||||
ActionCancelSignatureRequest: EditRoles,
|
||||
ActionExportSignableVersionDocumentPDF: AllRoles,
|
||||
ActionGetSigned: AllRoles,
|
||||
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetFile: NonEmployeeRoles,
|
||||
ActionGetOwner: NonEmployeeRoles,
|
||||
ActionGetDocument: NonEmployeeRoles,
|
||||
ActionSignatures: NonEmployeeRoles,
|
||||
ActionExportDocumentVersionPDF: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateDocumentVersion: EditRoles,
|
||||
ActionRequestSignature: EditRoles,
|
||||
},
|
||||
coredata.DocumentVersionSignatureEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionDocumentVersion: AllRoles,
|
||||
ActionSignedBy: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionDocumentVersion: NonEmployeeRoles,
|
||||
ActionSignedBy: NonEmployeeRoles,
|
||||
},
|
||||
coredata.RiskEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOwner: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionTotalCount: AllRoles,
|
||||
ActionListControls: AllRoles,
|
||||
ActionListMeasures: AllRoles,
|
||||
ActionListDocuments: AllRoles,
|
||||
ActionListObligations: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOwner: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionTotalCount: NonEmployeeRoles,
|
||||
ActionListControls: NonEmployeeRoles,
|
||||
ActionListMeasures: NonEmployeeRoles,
|
||||
ActionListDocuments: NonEmployeeRoles,
|
||||
ActionListObligations: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateRisk: EditRoles,
|
||||
ActionDeleteRisk: EditRoles,
|
||||
@@ -571,32 +582,32 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionDeleteRiskObligationMapping: EditRoles,
|
||||
},
|
||||
coredata.AssetEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOwner: AllRoles,
|
||||
ActionListVendors: AllRoles,
|
||||
ActionGetAssetType: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOwner: NonEmployeeRoles,
|
||||
ActionListVendors: NonEmployeeRoles,
|
||||
ActionGetAssetType: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateAsset: EditRoles,
|
||||
ActionDeleteAsset: EditRoles,
|
||||
},
|
||||
coredata.DatumEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOwner: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionListVendors: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOwner: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionListVendors: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateDatum: EditRoles,
|
||||
ActionDeleteDatum: EditRoles,
|
||||
},
|
||||
coredata.AuditEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetFile: AllRoles,
|
||||
ActionGetFramework: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionReport: AllRoles,
|
||||
ActionReportUrl: AllRoles,
|
||||
ActionListControls: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetFile: NonEmployeeRoles,
|
||||
ActionGetFramework: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionReport: NonEmployeeRoles,
|
||||
ActionReportUrl: NonEmployeeRoles,
|
||||
ActionListControls: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateAudit: EditRoles,
|
||||
ActionDeleteAudit: EditRoles,
|
||||
@@ -604,51 +615,50 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionDeleteAuditReport: EditRoles,
|
||||
},
|
||||
coredata.ReportEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetFile: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionGetSnapshot: AllRoles,
|
||||
ActionDownloadUrl: AllRoles,
|
||||
ActionAudit: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetFile: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionGetSnapshot: NonEmployeeRoles,
|
||||
ActionDownloadUrl: NonEmployeeRoles,
|
||||
},
|
||||
coredata.NonconformityEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOwner: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionAudit: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOwner: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionAudit: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateNonconformity: EditRoles,
|
||||
ActionDeleteNonconformity: EditRoles,
|
||||
},
|
||||
coredata.ObligationEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionGetOwner: AllRoles,
|
||||
ActionListRisks: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionGetOwner: NonEmployeeRoles,
|
||||
ActionListRisks: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateObligation: EditRoles,
|
||||
ActionDeleteObligation: EditRoles,
|
||||
},
|
||||
coredata.ContinualImprovementEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOwner: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOwner: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateContinualImprovement: EditRoles,
|
||||
ActionDeleteContinualImprovement: EditRoles,
|
||||
},
|
||||
coredata.ProcessingActivityEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionListVendors: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionListVendors: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateProcessingActivity: EditRoles,
|
||||
ActionDeleteProcessingActivity: EditRoles,
|
||||
},
|
||||
coredata.SnapshotEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionListControls: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionListControls: NonEmployeeRoles,
|
||||
|
||||
ActionDeleteSnapshot: EditRoles,
|
||||
},
|
||||
@@ -669,19 +679,18 @@ var Permissions = map[uint16]map[Action][]Role{
|
||||
ActionVerifyDomain: {RoleOwner},
|
||||
},
|
||||
coredata.FileEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionDownloadUrl: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionDownloadUrl: NonEmployeeRoles,
|
||||
},
|
||||
coredata.TrustCenterDocumentAccessEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionDocument: {RoleOwner, RoleAdmin},
|
||||
ActionReport: {RoleOwner, RoleAdmin},
|
||||
ActionTrustCenterFile: {RoleOwner, RoleAdmin},
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionReport: NonEmployeeRoles,
|
||||
ActionTrustCenterFile: NonEmployeeRoles,
|
||||
},
|
||||
coredata.MeetingEntityType: {
|
||||
ActionGet: AllRoles,
|
||||
ActionGetOrganization: AllRoles,
|
||||
ActionTotalCount: AllRoles,
|
||||
ActionGet: NonEmployeeRoles,
|
||||
ActionGetOrganization: NonEmployeeRoles,
|
||||
ActionTotalCount: NonEmployeeRoles,
|
||||
|
||||
ActionUpdateMeeting: EditRoles,
|
||||
ActionDeleteMeeting: EditRoles,
|
||||
|
||||
@@ -124,6 +124,60 @@ LIMIT 1;
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Document) LoadByIDWithFilter(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
documentID gid.GID,
|
||||
filter *DocumentFilter,
|
||||
) error {
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
owner_id,
|
||||
title,
|
||||
document_type,
|
||||
classification,
|
||||
current_published_version,
|
||||
trust_center_visibility,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
documents
|
||||
WHERE
|
||||
%s
|
||||
AND deleted_at IS NULL
|
||||
AND id = @document_id
|
||||
AND %s
|
||||
LIMIT 1;
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{"document_id": documentID}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
maps.Copy(args, filter.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query documents: %w", err)
|
||||
}
|
||||
|
||||
document, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Document])
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return &ErrDocumentNotFound{Identifier: documentID.String()}
|
||||
}
|
||||
|
||||
return fmt.Errorf("cannot collect document: %w", err)
|
||||
}
|
||||
|
||||
*p = document
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Documents) CountByOrganizationID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
@@ -400,28 +454,17 @@ func (p *Documents) CountByControlID(
|
||||
filter *DocumentFilter,
|
||||
) (int, error) {
|
||||
q := `
|
||||
WITH plcs AS (
|
||||
SELECT
|
||||
p.id,
|
||||
p.tenant_id,
|
||||
p.search_vector,
|
||||
p.trust_center_visibility,
|
||||
p.deleted_at
|
||||
FROM
|
||||
documents p
|
||||
INNER JOIN
|
||||
controls_documents cp ON p.id = cp.document_id
|
||||
WHERE
|
||||
cp.control_id = @control_id
|
||||
WITH scoped_documents AS (
|
||||
SELECT *
|
||||
FROM documents
|
||||
WHERE %s
|
||||
AND deleted_at IS NULL
|
||||
AND %s
|
||||
)
|
||||
SELECT
|
||||
COUNT(id)
|
||||
FROM
|
||||
plcs
|
||||
WHERE
|
||||
%s
|
||||
AND deleted_at IS NULL
|
||||
AND %s
|
||||
SELECT COUNT(scoped_documents.id)
|
||||
FROM scoped_documents
|
||||
INNER JOIN controls_documents cp ON scoped_documents.id = cp.document_id
|
||||
WHERE cp.control_id = @control_id
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment())
|
||||
@@ -448,46 +491,28 @@ func (p *Documents) LoadByControlID(
|
||||
filter *DocumentFilter,
|
||||
) error {
|
||||
q := `
|
||||
WITH plcs AS (
|
||||
SELECT
|
||||
p.id,
|
||||
p.tenant_id,
|
||||
p.search_vector,
|
||||
p.organization_id,
|
||||
p.owner_id,
|
||||
p.title,
|
||||
p.document_type,
|
||||
p.classification,
|
||||
p.current_published_version,
|
||||
p.trust_center_visibility,
|
||||
p.created_at,
|
||||
p.updated_at,
|
||||
p.deleted_at
|
||||
FROM
|
||||
documents p
|
||||
INNER JOIN
|
||||
controls_documents cp ON p.id = cp.document_id
|
||||
WHERE
|
||||
cp.control_id = @control_id
|
||||
WITH scoped_documents AS (
|
||||
SELECT *
|
||||
FROM documents
|
||||
WHERE %s
|
||||
AND deleted_at IS NULL
|
||||
AND %s
|
||||
AND %s
|
||||
)
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
owner_id,
|
||||
title,
|
||||
document_type,
|
||||
classification,
|
||||
current_published_version,
|
||||
trust_center_visibility,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
plcs
|
||||
WHERE
|
||||
%s
|
||||
AND deleted_at IS NULL
|
||||
AND %s
|
||||
AND %s
|
||||
scoped_documents.id,
|
||||
scoped_documents.organization_id,
|
||||
scoped_documents.owner_id,
|
||||
scoped_documents.title,
|
||||
scoped_documents.document_type,
|
||||
scoped_documents.classification,
|
||||
scoped_documents.current_published_version,
|
||||
scoped_documents.trust_center_visibility,
|
||||
scoped_documents.created_at,
|
||||
scoped_documents.updated_at
|
||||
FROM scoped_documents
|
||||
INNER JOIN controls_documents cp ON scoped_documents.id = cp.document_id
|
||||
WHERE cp.control_id = @control_id
|
||||
`
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment())
|
||||
|
||||
@@ -519,28 +544,17 @@ func (p *Documents) CountByRiskID(
|
||||
filter *DocumentFilter,
|
||||
) (int, error) {
|
||||
q := `
|
||||
WITH plcs AS (
|
||||
SELECT
|
||||
p.id,
|
||||
p.tenant_id,
|
||||
p.search_vector,
|
||||
p.trust_center_visibility,
|
||||
p.deleted_at
|
||||
FROM
|
||||
documents p
|
||||
INNER JOIN
|
||||
risks_documents rp ON p.id = rp.document_id
|
||||
WHERE
|
||||
rp.risk_id = @risk_id
|
||||
WITH scoped_documents AS (
|
||||
SELECT *
|
||||
FROM documents
|
||||
WHERE %s
|
||||
AND deleted_at IS NULL
|
||||
AND %s
|
||||
)
|
||||
SELECT
|
||||
COUNT(id)
|
||||
FROM
|
||||
plcs
|
||||
WHERE
|
||||
%s
|
||||
AND deleted_at IS NULL
|
||||
AND %s
|
||||
SELECT COUNT(scoped_documents.id)
|
||||
FROM scoped_documents
|
||||
INNER JOIN risks_documents rp ON scoped_documents.id = rp.document_id
|
||||
WHERE rp.risk_id = @risk_id
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment())
|
||||
@@ -567,46 +581,28 @@ func (p *Documents) LoadByRiskID(
|
||||
filter *DocumentFilter,
|
||||
) error {
|
||||
q := `
|
||||
WITH plcs AS (
|
||||
SELECT
|
||||
p.id,
|
||||
p.tenant_id,
|
||||
p.organization_id,
|
||||
p.owner_id,
|
||||
p.title,
|
||||
p.document_type,
|
||||
p.classification,
|
||||
p.current_published_version,
|
||||
p.trust_center_visibility,
|
||||
p.created_at,
|
||||
p.updated_at,
|
||||
p.search_vector,
|
||||
p.deleted_at
|
||||
FROM
|
||||
documents p
|
||||
INNER JOIN
|
||||
risks_documents rp ON p.id = rp.document_id
|
||||
WHERE
|
||||
rp.risk_id = @risk_id
|
||||
WITH scoped_documents AS (
|
||||
SELECT *
|
||||
FROM documents
|
||||
WHERE %s
|
||||
AND deleted_at IS NULL
|
||||
AND %s
|
||||
AND %s
|
||||
)
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
owner_id,
|
||||
title,
|
||||
document_type,
|
||||
classification,
|
||||
current_published_version,
|
||||
trust_center_visibility,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
plcs
|
||||
WHERE
|
||||
%s
|
||||
AND deleted_at IS NULL
|
||||
AND %s
|
||||
AND %s
|
||||
scoped_documents.id,
|
||||
scoped_documents.organization_id,
|
||||
scoped_documents.owner_id,
|
||||
scoped_documents.title,
|
||||
scoped_documents.document_type,
|
||||
scoped_documents.classification,
|
||||
scoped_documents.current_published_version,
|
||||
scoped_documents.trust_center_visibility,
|
||||
scoped_documents.created_at,
|
||||
scoped_documents.updated_at
|
||||
FROM scoped_documents
|
||||
INNER JOIN risks_documents rp ON scoped_documents.id = rp.document_id
|
||||
WHERE rp.risk_id = @risk_id
|
||||
`
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment())
|
||||
|
||||
@@ -653,3 +649,61 @@ UPDATE documents SET deleted_at = @deleted_at WHERE %s AND id = ANY(@document_id
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Document) IsLastSignableVersionSignedByUserEmail(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
documentID gid.GID,
|
||||
userEmail string,
|
||||
) (bool, error) {
|
||||
q := `
|
||||
WITH last_signable_version AS (
|
||||
SELECT
|
||||
d.id AS document_id,
|
||||
d.tenant_id,
|
||||
dv.version_number,
|
||||
dvs.state
|
||||
FROM documents d
|
||||
INNER JOIN document_versions dv ON dv.document_id = d.id
|
||||
INNER JOIN document_version_signatures dvs ON dvs.document_version_id = dv.id
|
||||
INNER JOIN peoples p ON dvs.signed_by = p.id
|
||||
WHERE d.id = @document_id
|
||||
AND p.primary_email_address = @user_email
|
||||
AND dv.version_number = (
|
||||
SELECT MAX(dv2.version_number)
|
||||
FROM document_versions dv2
|
||||
INNER JOIN document_version_signatures dvs2 ON dvs2.document_version_id = dv2.id
|
||||
INNER JOIN peoples p2 ON dvs2.signed_by = p2.id
|
||||
WHERE dv2.document_id = d.id
|
||||
AND p2.primary_email_address = @user_email
|
||||
)
|
||||
)
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM last_signable_version
|
||||
WHERE %s
|
||||
AND state = 'SIGNED'
|
||||
) AS signed
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_id": documentID,
|
||||
"user_email": userEmail,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot query document signed status: %w", err)
|
||||
}
|
||||
|
||||
signed, err := pgx.CollectOneRow(rows, pgx.RowTo[bool])
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot collect signed status: %w", err)
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ type (
|
||||
DocumentFilter struct {
|
||||
query *string
|
||||
trustCenterVisibilities []TrustCenterVisibility
|
||||
published *bool
|
||||
userEmail *string
|
||||
}
|
||||
)
|
||||
|
||||
@@ -40,7 +42,17 @@ func NewDocumentTrustCenterFilter() *DocumentFilter {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *DocumentFilter) SQLArguments() pgx.StrictNamedArgs {
|
||||
func (f *DocumentFilter) WithPublished(published *bool) *DocumentFilter {
|
||||
f.published = published
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *DocumentFilter) WithUserEmail(userEmail *string) *DocumentFilter {
|
||||
f.userEmail = userEmail
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *DocumentFilter) SQLArguments() pgx.NamedArgs {
|
||||
var visibilities []string
|
||||
if f.trustCenterVisibilities != nil {
|
||||
visibilities = make([]string, len(f.trustCenterVisibilities))
|
||||
@@ -48,9 +60,11 @@ func (f *DocumentFilter) SQLArguments() pgx.StrictNamedArgs {
|
||||
visibilities[i] = v.String()
|
||||
}
|
||||
}
|
||||
return pgx.StrictNamedArgs{
|
||||
return pgx.NamedArgs{
|
||||
"query": f.query,
|
||||
"trust_center_visibilities": visibilities,
|
||||
"published": f.published,
|
||||
"user_email": f.userEmail,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,5 +85,25 @@ func (f *DocumentFilter) SQLFragment() string {
|
||||
trust_center_visibility = ANY(@trust_center_visibilities::trust_center_visibility[])
|
||||
ELSE TRUE
|
||||
END
|
||||
AND
|
||||
CASE
|
||||
WHEN @published::boolean IS NULL THEN TRUE
|
||||
WHEN @published::boolean IS TRUE THEN current_published_version IS NOT NULL
|
||||
WHEN @published::boolean IS FALSE THEN current_published_version IS NULL
|
||||
END
|
||||
AND
|
||||
CASE
|
||||
WHEN @user_email::text IS NULL THEN TRUE
|
||||
ELSE EXISTS (
|
||||
SELECT 1
|
||||
FROM document_versions dv
|
||||
INNER JOIN document_version_signatures dvs ON dv.id = dvs.document_version_id
|
||||
INNER JOIN peoples p ON dvs.signed_by = p.id
|
||||
WHERE dv.document_id = documents.id
|
||||
AND dv.status = 'PUBLISHED'
|
||||
AND p.primary_email_address = @user_email::text
|
||||
AND dvs.state IN ('REQUESTED', 'SIGNED')
|
||||
)
|
||||
END
|
||||
)`
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ func (p *DocumentVersions) LoadByDocumentID(
|
||||
scope Scoper,
|
||||
documentID gid.GID,
|
||||
cursor *page.Cursor[DocumentVersionOrderField],
|
||||
filter *DocumentVersionFilter,
|
||||
) error {
|
||||
q := `
|
||||
SELECT
|
||||
@@ -100,14 +101,16 @@ WHERE
|
||||
%s
|
||||
AND document_id = @document_id
|
||||
AND %s
|
||||
AND %s
|
||||
`
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_id": documentID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
maps.Copy(args, cursor.SQLArguments())
|
||||
maps.Copy(args, filter.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
|
||||
55
pkg/coredata/document_version_filter.go
Normal file
55
pkg/coredata/document_version_filter.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package coredata
|
||||
|
||||
import (
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
type (
|
||||
DocumentVersionFilter struct {
|
||||
userEmail *string
|
||||
}
|
||||
)
|
||||
|
||||
func NewDocumentVersionFilter() *DocumentVersionFilter {
|
||||
return &DocumentVersionFilter{}
|
||||
}
|
||||
|
||||
func (f *DocumentVersionFilter) WithUserEmail(userEmail *string) *DocumentVersionFilter {
|
||||
f.userEmail = userEmail
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *DocumentVersionFilter) SQLArguments() pgx.StrictNamedArgs {
|
||||
return pgx.StrictNamedArgs{
|
||||
"user_email": f.userEmail,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *DocumentVersionFilter) SQLFragment() string {
|
||||
return `
|
||||
(
|
||||
@user_email::text IS NULL
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM document_version_signatures dvs
|
||||
INNER JOIN peoples p ON dvs.signed_by = p.id
|
||||
WHERE dvs.document_version_id = document_versions.id
|
||||
AND p.primary_email_address = @user_email::text
|
||||
AND dvs.state IN ('REQUESTED', 'SIGNED')
|
||||
)
|
||||
)`
|
||||
}
|
||||
@@ -20,7 +20,6 @@ type (
|
||||
|
||||
const (
|
||||
DocumentVersionOrderFieldCreatedAt DocumentVersionOrderField = "CREATED_AT"
|
||||
DocumentVersionOrderFieldVersion DocumentVersionOrderField = "VERSION"
|
||||
)
|
||||
|
||||
func (p DocumentVersionOrderField) Column() string {
|
||||
|
||||
@@ -57,6 +57,8 @@ type (
|
||||
ErrDocumentVersionSignatureAlreadyExists struct {
|
||||
message string
|
||||
}
|
||||
|
||||
ErrDocumentVersionSignatureAlreadySigned struct{}
|
||||
)
|
||||
|
||||
func (e ErrDocumentVersionSignatureNotFound) Error() string {
|
||||
@@ -67,6 +69,10 @@ func (e ErrDocumentVersionSignatureAlreadyExists) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
func (e ErrDocumentVersionSignatureAlreadySigned) Error() string {
|
||||
return "document version already signed"
|
||||
}
|
||||
|
||||
func (pvs DocumentVersionSignature) CursorKey(orderBy DocumentVersionSignatureOrderField) page.CursorKey {
|
||||
switch orderBy {
|
||||
case DocumentVersionSignatureOrderFieldCreatedAt:
|
||||
@@ -412,3 +418,41 @@ WHERE
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pvs *DocumentVersionSignature) IsSignedByUserEmail(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
documentVersionID gid.GID,
|
||||
userEmail string,
|
||||
) (bool, error) {
|
||||
q := `
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM document_version_signatures dvs
|
||||
INNER JOIN peoples p ON dvs.signed_by = p.id
|
||||
WHERE dvs.document_version_id = @document_version_id
|
||||
AND p.primary_email_address = @user_email
|
||||
AND dvs.state = 'SIGNED'
|
||||
AND dvs.tenant_id = @tenant_id
|
||||
) AS signed
|
||||
`
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_version_id": documentVersionID,
|
||||
"user_email": userEmail,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot query document version signature: %w", err)
|
||||
}
|
||||
|
||||
signed, err := pgx.CollectOneRow(rows, pgx.RowTo[bool])
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot collect signed status: %w", err)
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
|
||||
@@ -22,9 +22,10 @@ import (
|
||||
type MembershipRole string
|
||||
|
||||
const (
|
||||
MembershipRoleOwner MembershipRole = "OWNER"
|
||||
MembershipRoleAdmin MembershipRole = "ADMIN"
|
||||
MembershipRoleViewer MembershipRole = "VIEWER"
|
||||
MembershipRoleOwner MembershipRole = "OWNER"
|
||||
MembershipRoleAdmin MembershipRole = "ADMIN"
|
||||
MembershipRoleEmployee MembershipRole = "EMPLOYEE"
|
||||
MembershipRoleViewer MembershipRole = "VIEWER"
|
||||
)
|
||||
|
||||
func (r MembershipRole) String() string {
|
||||
@@ -47,6 +48,8 @@ func (r *MembershipRole) Scan(value any) error {
|
||||
*r = MembershipRoleOwner
|
||||
case "ADMIN":
|
||||
*r = MembershipRoleAdmin
|
||||
case "EMPLOYEE":
|
||||
*r = MembershipRoleEmployee
|
||||
case "VIEWER":
|
||||
*r = MembershipRoleViewer
|
||||
default:
|
||||
|
||||
1
pkg/coredata/migrations/20251113T000000Z.sql
Normal file
1
pkg/coredata/migrations/20251113T000000Z.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TYPE authz_role RENAME VALUE 'MEMBER' TO 'EMPLOYEE';
|
||||
@@ -132,24 +132,24 @@ func (p *People) LoadByEmail(
|
||||
primaryEmailAddress string,
|
||||
) error {
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
kind,
|
||||
full_name,
|
||||
primary_email_address,
|
||||
additional_email_addresses,
|
||||
position,
|
||||
contract_start_date,
|
||||
contract_end_date,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
peoples
|
||||
WHERE
|
||||
%s
|
||||
AND primary_email_address = @primary_email_address
|
||||
LIMIT 1;
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
kind,
|
||||
full_name,
|
||||
primary_email_address,
|
||||
additional_email_addresses,
|
||||
position,
|
||||
contract_start_date,
|
||||
contract_end_date,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
peoples
|
||||
WHERE
|
||||
%s
|
||||
AND primary_email_address = @primary_email_address
|
||||
LIMIT 1;
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
@@ -176,6 +176,62 @@ func (p *People) LoadByEmail(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *People) LoadByEmailAndOrganizationID(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
scope Scoper,
|
||||
primaryEmailAddress string,
|
||||
organizationID gid.GID,
|
||||
) error {
|
||||
q := `
|
||||
SELECT
|
||||
id,
|
||||
organization_id,
|
||||
kind,
|
||||
full_name,
|
||||
primary_email_address,
|
||||
additional_email_addresses,
|
||||
position,
|
||||
contract_start_date,
|
||||
contract_end_date,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
peoples
|
||||
WHERE
|
||||
%s
|
||||
AND primary_email_address = @primary_email_address
|
||||
AND organization_id = @organization_id
|
||||
LIMIT 1;
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"primary_email_address": primaryEmailAddress,
|
||||
"organization_id": organizationID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query people: %w", err)
|
||||
}
|
||||
|
||||
people, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[People])
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return &ErrPeopleNotFound{Identifier: primaryEmailAddress}
|
||||
}
|
||||
|
||||
return fmt.Errorf("cannot collect people: %w", err)
|
||||
}
|
||||
|
||||
*p = people
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Peoples) LoadByIDs(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
|
||||
@@ -164,6 +164,32 @@ func (s *DocumentService) Get(
|
||||
return document, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) GetWithFilter(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
filter *coredata.DocumentFilter,
|
||||
) (*coredata.Document, error) {
|
||||
document := &coredata.Document{}
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
err := document.LoadByIDWithFilter(ctx, conn, s.svc.scope, documentID, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load document: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return document, nil
|
||||
}
|
||||
|
||||
func (s DocumentService) GenerateChangelog(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
@@ -559,39 +585,13 @@ func (s *DocumentService) SignDocumentVersion(
|
||||
documentVersionID gid.GID,
|
||||
signatory gid.GID,
|
||||
) error {
|
||||
documentVersion := &coredata.DocumentVersion{}
|
||||
documentVersionSignature := &coredata.DocumentVersionSignature{}
|
||||
now := time.Now()
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
if err := documentVersion.LoadByID(ctx, conn, s.svc.scope, documentVersionID); err != nil {
|
||||
return fmt.Errorf("cannot load document version %q: %w", documentVersionID, err)
|
||||
}
|
||||
|
||||
if documentVersion.Status != coredata.DocumentStatusPublished {
|
||||
return fmt.Errorf("cannot sign unpublished version")
|
||||
}
|
||||
|
||||
if err := documentVersionSignature.LoadByDocumentVersionIDAndSignatory(ctx, conn, s.svc.scope, documentVersionID, signatory); err != nil {
|
||||
return fmt.Errorf("cannot load document version signature: %w", err)
|
||||
}
|
||||
|
||||
if documentVersionSignature.State == coredata.DocumentVersionSignatureStateSigned {
|
||||
return fmt.Errorf("document version already signed")
|
||||
}
|
||||
|
||||
documentVersionSignature.State = coredata.DocumentVersionSignatureStateSigned
|
||||
documentVersionSignature.SignedAt = &now
|
||||
documentVersionSignature.UpdatedAt = now
|
||||
|
||||
if err := documentVersion.Update(ctx, conn, s.svc.scope); err != nil {
|
||||
return fmt.Errorf("cannot update document version: %w", err)
|
||||
}
|
||||
|
||||
if err := documentVersionSignature.Update(ctx, conn, s.svc.scope); err != nil {
|
||||
return fmt.Errorf("cannot update document version signature: %w", err)
|
||||
var err error
|
||||
_, err = s.signDocumentVersionInTx(ctx, conn, documentVersionID, signatory)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot sign document version: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -605,6 +605,80 @@ func (s *DocumentService) SignDocumentVersion(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) SignDocumentVersionByEmail(
|
||||
ctx context.Context,
|
||||
documentVersionID gid.GID,
|
||||
userEmail string,
|
||||
) (*coredata.DocumentVersionSignature, error) {
|
||||
var documentVersionSignature *coredata.DocumentVersionSignature
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
documentVersion := &coredata.DocumentVersion{}
|
||||
if err := documentVersion.LoadByID(ctx, conn, s.svc.scope, documentVersionID); err != nil {
|
||||
return fmt.Errorf("cannot get document version: %w", err)
|
||||
}
|
||||
|
||||
people := &coredata.People{}
|
||||
if err := people.LoadByEmailAndOrganizationID(ctx, conn, s.svc.scope, userEmail, documentVersion.OrganizationID); err != nil {
|
||||
return fmt.Errorf("cannot find people record for user email in organization %q: %w", documentVersion.OrganizationID, err)
|
||||
}
|
||||
|
||||
var signErr error
|
||||
documentVersionSignature, signErr = s.signDocumentVersionInTx(ctx, conn, documentVersionID, people.ID)
|
||||
return signErr
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot sign document version: %w", err)
|
||||
}
|
||||
|
||||
return documentVersionSignature, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) signDocumentVersionInTx(
|
||||
ctx context.Context,
|
||||
conn pg.Conn,
|
||||
documentVersionID gid.GID,
|
||||
signatory gid.GID,
|
||||
) (*coredata.DocumentVersionSignature, error) {
|
||||
documentVersion := &coredata.DocumentVersion{}
|
||||
documentVersionSignature := &coredata.DocumentVersionSignature{}
|
||||
now := time.Now()
|
||||
|
||||
if err := documentVersion.LoadByID(ctx, conn, s.svc.scope, documentVersionID); err != nil {
|
||||
return nil, fmt.Errorf("cannot load document version %q: %w", documentVersionID, err)
|
||||
}
|
||||
|
||||
if documentVersion.Status != coredata.DocumentStatusPublished {
|
||||
return nil, fmt.Errorf("cannot sign unpublished version")
|
||||
}
|
||||
|
||||
if err := documentVersionSignature.LoadByDocumentVersionIDAndSignatory(ctx, conn, s.svc.scope, documentVersionID, signatory); err != nil {
|
||||
return nil, fmt.Errorf("cannot load document version signature: %w", err)
|
||||
}
|
||||
|
||||
if documentVersionSignature.State == coredata.DocumentVersionSignatureStateSigned {
|
||||
return nil, &coredata.ErrDocumentVersionSignatureAlreadySigned{}
|
||||
}
|
||||
|
||||
documentVersionSignature.State = coredata.DocumentVersionSignatureStateSigned
|
||||
documentVersionSignature.SignedAt = &now
|
||||
documentVersionSignature.UpdatedAt = now
|
||||
|
||||
if err := documentVersion.Update(ctx, conn, s.svc.scope); err != nil {
|
||||
return nil, fmt.Errorf("cannot update document version: %w", err)
|
||||
}
|
||||
|
||||
if err := documentVersionSignature.Update(ctx, conn, s.svc.scope); err != nil {
|
||||
return nil, fmt.Errorf("cannot update document version signature: %w", err)
|
||||
}
|
||||
|
||||
return documentVersionSignature, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) UpdateVersion(
|
||||
ctx context.Context,
|
||||
req UpdateDocumentVersionRequest,
|
||||
@@ -810,6 +884,36 @@ func (s *DocumentService) ListSignatures(
|
||||
return page.NewPage(documentVersionSignatures, cursor), nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) IsVersionSignedByUserEmail(
|
||||
ctx context.Context,
|
||||
documentVersionID gid.GID,
|
||||
userEmail string,
|
||||
) (bool, error) {
|
||||
documentVersionSignature := &coredata.DocumentVersionSignature{}
|
||||
|
||||
var signed bool
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
var err error
|
||||
signed, err = documentVersionSignature.IsSignedByUserEmail(
|
||||
ctx,
|
||||
conn,
|
||||
s.svc.scope,
|
||||
documentVersionID,
|
||||
userEmail,
|
||||
)
|
||||
return err
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot check if document version is signed: %w", err)
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) CreateDraft(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
@@ -998,13 +1102,20 @@ func (s *DocumentService) ListVersions(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
cursor *page.Cursor[coredata.DocumentVersionOrderField],
|
||||
filter *coredata.DocumentVersionFilter,
|
||||
) (*page.Page[*coredata.DocumentVersion, coredata.DocumentVersionOrderField], error) {
|
||||
var documentVersions coredata.DocumentVersions
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
return documentVersions.LoadByDocumentID(ctx, conn, s.svc.scope, documentID, cursor)
|
||||
|
||||
err := documentVersions.LoadByDocumentID(ctx, conn, s.svc.scope, documentID, cursor, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load document versions: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1035,6 +1146,36 @@ func (s *DocumentService) GetVersion(
|
||||
return documentVersion, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) IsSigned(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
userEmail string,
|
||||
) (bool, error) {
|
||||
document := &coredata.Document{}
|
||||
|
||||
var signed bool
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
var err error
|
||||
signed, err = document.IsLastSignableVersionSignedByUserEmail(
|
||||
ctx,
|
||||
conn,
|
||||
s.svc.scope,
|
||||
documentID,
|
||||
userEmail,
|
||||
)
|
||||
return err
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot check if document is signed: %w", err)
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) CountForOrganizationID(
|
||||
ctx context.Context,
|
||||
organizationID gid.GID,
|
||||
|
||||
@@ -108,6 +108,31 @@ func (s PeopleService) Get(
|
||||
return people, nil
|
||||
}
|
||||
|
||||
func (s PeopleService) GetByEmailAndOrganizationID(
|
||||
ctx context.Context,
|
||||
primaryEmailAddress string,
|
||||
organizationID gid.GID,
|
||||
) (*coredata.People, error) {
|
||||
people := &coredata.People{}
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
err := people.LoadByEmailAndOrganizationID(ctx, conn, s.svc.scope, primaryEmailAddress, organizationID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot load people by email and organization ID: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return people, nil
|
||||
}
|
||||
|
||||
func (s PeopleService) CountForOrganizationID(
|
||||
ctx context.Context,
|
||||
organizationID gid.GID,
|
||||
|
||||
@@ -94,6 +94,7 @@ enum InvitationStatus
|
||||
enum MembershipRole @goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipRole") {
|
||||
OWNER @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleOwner")
|
||||
ADMIN @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleAdmin")
|
||||
EMPLOYEE @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleEmployee")
|
||||
VIEWER @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleViewer")
|
||||
}
|
||||
|
||||
@@ -522,10 +523,6 @@ enum BusinessImpact
|
||||
|
||||
enum DocumentVersionOrderField
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.DocumentVersionOrderField") {
|
||||
VERSION
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionOrderFieldVersion"
|
||||
)
|
||||
CREATED_AT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.DocumentVersionOrderFieldCreatedAt"
|
||||
@@ -2035,6 +2032,29 @@ type Document implements Node {
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type SignableDocument @goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.SignableDocument"
|
||||
){
|
||||
id: ID!
|
||||
title: String!
|
||||
description: String
|
||||
documentType: DocumentType!
|
||||
classification: DocumentClassification!
|
||||
signed: Boolean! @goField(forceResolver: true)
|
||||
|
||||
versions(
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentVersionOrder
|
||||
filter: DocumentVersionFilter
|
||||
): DocumentVersionConnection! @goField(forceResolver: true)
|
||||
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
}
|
||||
|
||||
type Meeting implements Node {
|
||||
id: ID!
|
||||
name: String!
|
||||
@@ -2259,6 +2279,17 @@ type Viewer {
|
||||
before: CursorKey
|
||||
orderBy: OrganizationOrder
|
||||
): OrganizationConnection! @goField(forceResolver: true)
|
||||
|
||||
signableDocuments(
|
||||
organizationId: ID!
|
||||
first: Int
|
||||
after: CursorKey
|
||||
last: Int
|
||||
before: CursorKey
|
||||
orderBy: DocumentOrder
|
||||
): SignableDocumentConnection! @goField(forceResolver: true)
|
||||
|
||||
signableDocument(id: ID!): SignableDocument @goField(forceResolver: true)
|
||||
}
|
||||
|
||||
# Connection Types
|
||||
@@ -2514,6 +2545,22 @@ type EvidenceEdge {
|
||||
node: Evidence!
|
||||
}
|
||||
|
||||
type SignableDocumentConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.SignableDocumentConnection"
|
||||
) {
|
||||
edges: [SignableDocumentEdge!]!
|
||||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type SignableDocumentEdge
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.SignableDocumentEdge"
|
||||
) {
|
||||
cursor: CursorKey!
|
||||
node: SignableDocument!
|
||||
}
|
||||
|
||||
type DocumentConnection
|
||||
@goModel(
|
||||
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.DocumentConnection"
|
||||
@@ -2914,9 +2961,16 @@ type Mutation {
|
||||
input: SendSigningNotificationsInput!
|
||||
): SendSigningNotificationsPayload! cancelSignatureRequest(
|
||||
input: CancelSignatureRequestInput!
|
||||
): CancelSignatureRequestPayload! exportDocumentVersionPDF(
|
||||
): CancelSignatureRequestPayload!
|
||||
signDocument(
|
||||
input: SignDocumentInput!
|
||||
): SignDocumentPayload!
|
||||
exportDocumentVersionPDF(
|
||||
input: ExportDocumentVersionPDFInput!
|
||||
): ExportDocumentVersionPDFPayload!
|
||||
exportSignableVersionDocumentPDF(
|
||||
input: ExportSignableDocumentVersionPDFInput!
|
||||
): ExportSignableDocumentVersionPDFPayload!
|
||||
createVendorRiskAssessment(
|
||||
input: CreateVendorRiskAssessmentInput!
|
||||
): CreateVendorRiskAssessmentPayload!
|
||||
@@ -3488,6 +3542,10 @@ input ExportDocumentVersionPDFInput {
|
||||
withSignatures: Boolean!
|
||||
}
|
||||
|
||||
input ExportSignableDocumentVersionPDFInput {
|
||||
documentVersionId: ID!
|
||||
}
|
||||
|
||||
input DeleteDocumentInput {
|
||||
documentId: ID!
|
||||
}
|
||||
@@ -4072,6 +4130,10 @@ type ExportDocumentVersionPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type ExportSignableDocumentVersionPDFPayload {
|
||||
data: String!
|
||||
}
|
||||
|
||||
type UpdateDocumentPayload {
|
||||
document: Document!
|
||||
}
|
||||
@@ -4186,6 +4248,8 @@ type DocumentVersion implements Node @goModel(model: "go.probo.inc/probo/pkg/ser
|
||||
filter: DocumentVersionSignatureFilter
|
||||
): DocumentVersionSignatureConnection! @goField(forceResolver: true)
|
||||
|
||||
signed: Boolean! @goField(forceResolver: true)
|
||||
|
||||
publishedAt: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
@@ -4347,6 +4411,14 @@ type CancelSignatureRequestPayload {
|
||||
deletedDocumentVersionSignatureId: ID!
|
||||
}
|
||||
|
||||
input SignDocumentInput {
|
||||
documentVersionId: ID!
|
||||
}
|
||||
|
||||
type SignDocumentPayload {
|
||||
documentVersionSignature: DocumentVersionSignature!
|
||||
}
|
||||
|
||||
type UploadMeasureEvidencePayload {
|
||||
evidenceEdge: EvidenceEdge!
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
83
pkg/server/api/console/v1/types/signable_document.go
Normal file
83
pkg/server/api/console/v1/types/signable_document.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.probo.inc/probo/pkg/coredata"
|
||||
"go.probo.inc/probo/pkg/gid"
|
||||
"go.probo.inc/probo/pkg/page"
|
||||
)
|
||||
|
||||
type (
|
||||
SignableDocumentConnection struct {
|
||||
Edges []*SignableDocumentEdge
|
||||
PageInfo *PageInfo
|
||||
}
|
||||
|
||||
SignableDocumentEdge struct {
|
||||
Cursor page.CursorKey
|
||||
Node *SignableDocument
|
||||
}
|
||||
|
||||
SignableDocument struct {
|
||||
ID gid.GID
|
||||
Title string
|
||||
Description *string
|
||||
DocumentType coredata.DocumentType
|
||||
Classification coredata.DocumentClassification
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
)
|
||||
|
||||
func (SignableDocument) IsNode() {}
|
||||
func (this SignableDocument) GetID() gid.GID { return this.ID }
|
||||
|
||||
func NewSignableDocumentConnection(
|
||||
p *page.Page[*SignableDocument, coredata.DocumentOrderField],
|
||||
) *SignableDocumentConnection {
|
||||
var edges = make([]*SignableDocumentEdge, len(p.Data))
|
||||
|
||||
for i := range edges {
|
||||
edges[i] = NewSignableDocumentEdge(p.Data[i], p.Cursor.OrderBy.Field)
|
||||
}
|
||||
|
||||
return &SignableDocumentConnection{
|
||||
Edges: edges,
|
||||
PageInfo: NewPageInfo(p),
|
||||
}
|
||||
}
|
||||
|
||||
func NewSignableDocumentEdge(document *SignableDocument, orderBy coredata.DocumentOrderField) *SignableDocumentEdge {
|
||||
return &SignableDocumentEdge{
|
||||
Cursor: document.CursorKey(orderBy),
|
||||
Node: document,
|
||||
}
|
||||
}
|
||||
|
||||
func (d SignableDocument) CursorKey(orderBy coredata.DocumentOrderField) page.CursorKey {
|
||||
switch orderBy {
|
||||
case coredata.DocumentOrderFieldCreatedAt:
|
||||
return page.NewCursorKey(d.ID, d.CreatedAt)
|
||||
case coredata.DocumentOrderFieldTitle:
|
||||
return page.NewCursorKey(d.ID, d.Title)
|
||||
case coredata.DocumentOrderFieldDocumentType:
|
||||
return page.NewCursorKey(d.ID, d.DocumentType)
|
||||
}
|
||||
|
||||
panic("unsupported order by")
|
||||
}
|
||||
@@ -1153,6 +1153,14 @@ type ExportFrameworkPayload struct {
|
||||
ExportJobID gid.GID `json:"exportJobId"`
|
||||
}
|
||||
|
||||
type ExportSignableDocumentVersionPDFInput struct {
|
||||
DocumentVersionID gid.GID `json:"documentVersionId"`
|
||||
}
|
||||
|
||||
type ExportSignableDocumentVersionPDFPayload struct {
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
type File struct {
|
||||
ID gid.GID `json:"id"`
|
||||
MimeType string `json:"mimeType"`
|
||||
@@ -1680,6 +1688,14 @@ type Session struct {
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
}
|
||||
|
||||
type SignDocumentInput struct {
|
||||
DocumentVersionID gid.GID `json:"documentVersionId"`
|
||||
}
|
||||
|
||||
type SignDocumentPayload struct {
|
||||
DocumentVersionSignature *DocumentVersionSignature `json:"documentVersionSignature"`
|
||||
}
|
||||
|
||||
type SlackConnection struct {
|
||||
ID gid.GID `json:"id"`
|
||||
Channel *string `json:"channel,omitempty"`
|
||||
@@ -2506,9 +2522,11 @@ type VerifyDomainPayload struct {
|
||||
}
|
||||
|
||||
type Viewer struct {
|
||||
ID gid.GID `json:"id"`
|
||||
User *User `json:"user"`
|
||||
Organizations *OrganizationConnection `json:"organizations"`
|
||||
ID gid.GID `json:"id"`
|
||||
User *User `json:"user"`
|
||||
Organizations *OrganizationConnection `json:"organizations"`
|
||||
SignableDocuments *SignableDocumentConnection `json:"signableDocuments"`
|
||||
SignableDocument *SignableDocument `json:"signableDocument,omitempty"`
|
||||
}
|
||||
|
||||
type Role string
|
||||
|
||||
@@ -714,7 +714,9 @@ func (r *documentResolver) Versions(ctx context.Context, obj *types.Document, fi
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
page, err := prb.Documents.ListVersions(ctx, obj.ID, cursor)
|
||||
versionFilter := coredata.NewDocumentVersionFilter()
|
||||
|
||||
page, err := prb.Documents.ListVersions(ctx, obj.ID, cursor, versionFilter)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot list document versions: %w", err))
|
||||
}
|
||||
@@ -785,7 +787,7 @@ func (r *documentConnectionResolver) TotalCount(ctx context.Context, obj *types.
|
||||
|
||||
// Document is the resolver for the document field.
|
||||
func (r *documentVersionResolver) Document(ctx context.Context, obj *types.DocumentVersion) (*types.Document, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionDocument)
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGetDocument)
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
@@ -862,6 +864,24 @@ func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.Doc
|
||||
return types.NewDocumentVersionSignatureConnection(page), nil
|
||||
}
|
||||
|
||||
// Signed is the resolver for the signed field.
|
||||
func (r *documentVersionResolver) Signed(ctx context.Context, obj *types.DocumentVersion) (bool, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGetSigned)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
signed, err := prb.Documents.IsVersionSignedByUserEmail(ctx, obj.ID, user.EmailAddress)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot check if document version is signed: %w", err))
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
|
||||
// DocumentVersion is the resolver for the documentVersion field.
|
||||
func (r *documentVersionSignatureResolver) DocumentVersion(ctx context.Context, obj *types.DocumentVersionSignature) (*types.DocumentVersion, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionDocumentVersion)
|
||||
@@ -3551,6 +3571,31 @@ func (r *mutationResolver) CancelSignatureRequest(ctx context.Context, input typ
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SignDocument is the resolver for the signDocument field.
|
||||
func (r *mutationResolver) SignDocument(ctx context.Context, input types.SignDocumentInput) (*types.SignDocumentPayload, error) {
|
||||
r.MustBeAuthorized(ctx, input.DocumentVersionID, authz.ActionSignDocument)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
||||
|
||||
documentVersionSignature, err := prb.Documents.SignDocumentVersionByEmail(ctx, input.DocumentVersionID, user.EmailAddress)
|
||||
if err != nil {
|
||||
var errAlreadySigned *coredata.ErrDocumentVersionSignatureAlreadySigned
|
||||
if errors.As(err, &errAlreadySigned) {
|
||||
return nil, gqlutils.Conflict(errAlreadySigned)
|
||||
}
|
||||
panic(fmt.Errorf("cannot sign document: %w", err))
|
||||
}
|
||||
|
||||
return &types.SignDocumentPayload{
|
||||
DocumentVersionSignature: types.NewDocumentVersionSignature(documentVersionSignature),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportDocumentVersionPDF is the resolver for the exportDocumentVersionPDF field.
|
||||
func (r *mutationResolver) ExportDocumentVersionPDF(ctx context.Context, input types.ExportDocumentVersionPDFInput) (*types.ExportDocumentVersionPDFPayload, error) {
|
||||
r.MustBeAuthorized(ctx, input.DocumentVersionID, authz.ActionExportDocumentVersionPDF)
|
||||
@@ -3573,6 +3618,49 @@ func (r *mutationResolver) ExportDocumentVersionPDF(ctx context.Context, input t
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExportSignableVersionDocumentPDF is the resolver for the exportSignableVersionDocumentPDF field.
|
||||
func (r *mutationResolver) ExportSignableVersionDocumentPDF(ctx context.Context, input types.ExportSignableDocumentVersionPDFInput) (*types.ExportSignableDocumentVersionPDFPayload, error) {
|
||||
r.MustBeAuthorized(ctx, input.DocumentVersionID, authz.ActionExportSignableVersionDocumentPDF)
|
||||
|
||||
prb := r.ProboService(ctx, input.DocumentVersionID.TenantID())
|
||||
|
||||
documentVersion, err := prb.Documents.GetVersion(ctx, input.DocumentVersionID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot get document version: %w", err))
|
||||
}
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithUserEmail(&user.EmailAddress)
|
||||
|
||||
_, err = prb.Documents.GetWithFilter(ctx, documentVersion.DocumentID, documentFilter)
|
||||
if err != nil {
|
||||
var errNotFound *coredata.ErrDocumentNotFound
|
||||
if errors.As(err, &errNotFound) {
|
||||
return nil, gqlutils.NotFound(errNotFound)
|
||||
}
|
||||
panic(fmt.Errorf("cannot get signable document: %w", err))
|
||||
}
|
||||
|
||||
options := probo.ExportPDFOptions{
|
||||
WithSignatures: false,
|
||||
WithWatermark: true,
|
||||
WatermarkEmail: &user.EmailAddress,
|
||||
}
|
||||
|
||||
pdf, err := prb.Documents.ExportPDF(ctx, input.DocumentVersionID, options)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot export signable document PDF: %w", err))
|
||||
}
|
||||
|
||||
return &types.ExportSignableDocumentVersionPDFPayload{
|
||||
Data: fmt.Sprintf("data:application/pdf;base64,%s", base64.StdEncoding.EncodeToString(pdf)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateVendorRiskAssessment is the resolver for the createVendorRiskAssessment field.
|
||||
func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error) {
|
||||
r.MustBeAuthorized(ctx, input.VendorID, authz.ActionCreateVendorRiskAssessment)
|
||||
@@ -5994,6 +6082,59 @@ func (r *sAMLConfigurationResolver) TestLoginURL(ctx context.Context, obj *types
|
||||
return fmt.Sprintf("%s/connect/saml/login/%s", parts[0], obj.ID), nil
|
||||
}
|
||||
|
||||
// Signed is the resolver for the signed field.
|
||||
func (r *signableDocumentResolver) Signed(ctx context.Context, obj *types.SignableDocument) (bool, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGetSigned)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
signed, err := prb.Documents.IsSigned(ctx, obj.ID, user.EmailAddress)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot check if document is signed: %w", err))
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
|
||||
// Versions is the resolver for the versions field.
|
||||
func (r *signableDocumentResolver) Versions(ctx context.Context, obj *types.SignableDocument, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionOrderBy, filter *types.DocumentVersionFilter) (*types.DocumentVersionConnection, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionListSignableDocumentVersion)
|
||||
|
||||
prb := r.ProboService(ctx, obj.ID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DocumentVersionOrderField]{
|
||||
Field: coredata.DocumentVersionOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.DocumentVersionOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
versionFilter := coredata.NewDocumentVersionFilter().WithUserEmail(&user.EmailAddress)
|
||||
|
||||
page, err := prb.Documents.ListVersions(ctx, obj.ID, cursor, versionFilter)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot list signable document versions: %w", err))
|
||||
}
|
||||
|
||||
return types.NewDocumentVersionConnection(page), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *snapshotResolver) Organization(ctx context.Context, obj *types.Snapshot) (*types.Organization, error) {
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGetOrganization)
|
||||
@@ -6349,7 +6490,7 @@ func (r *trustCenterAccessResolver) AvailableDocumentAccesses(ctx context.Contex
|
||||
|
||||
// Document is the resolver for the document field.
|
||||
func (r *trustCenterDocumentAccessResolver) Document(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Document, error) {
|
||||
r.MustBeAuthorized(ctx, obj.TrustCenterAccessID, authz.ActionDocument)
|
||||
r.MustBeAuthorized(ctx, obj.ID, authz.ActionGet)
|
||||
|
||||
if obj.DocumentID == nil {
|
||||
return nil, nil
|
||||
@@ -6979,6 +7120,85 @@ func (r *viewerResolver) Organizations(ctx context.Context, obj *types.Viewer, f
|
||||
return types.NewOrganizationConnection(page), nil
|
||||
}
|
||||
|
||||
// SignableDocuments is the resolver for the signableDocuments field.
|
||||
func (r *viewerResolver) SignableDocuments(ctx context.Context, obj *types.Viewer, organizationID gid.GID, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy) (*types.SignableDocumentConnection, error) {
|
||||
r.MustBeAuthorized(ctx, organizationID, authz.ActionListSignableDocuments)
|
||||
|
||||
prb := r.ProboService(ctx, organizationID.TenantID())
|
||||
|
||||
pageOrderBy := page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: coredata.DocumentOrderFieldCreatedAt,
|
||||
Direction: page.OrderDirectionDesc,
|
||||
}
|
||||
if orderBy != nil {
|
||||
pageOrderBy = page.OrderBy[coredata.DocumentOrderField]{
|
||||
Field: orderBy.Field,
|
||||
Direction: orderBy.Direction,
|
||||
}
|
||||
}
|
||||
|
||||
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithUserEmail(&user.EmailAddress)
|
||||
|
||||
documentsPage, err := prb.Documents.ListByOrganizationID(ctx, organizationID, cursor, documentFilter)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot list organization signable documents: %w", err))
|
||||
}
|
||||
|
||||
signableDocuments := make([]*types.SignableDocument, len(documentsPage.Data))
|
||||
for i, doc := range documentsPage.Data {
|
||||
signableDocuments[i] = &types.SignableDocument{
|
||||
ID: doc.ID,
|
||||
Title: doc.Title,
|
||||
DocumentType: doc.DocumentType,
|
||||
Classification: doc.Classification,
|
||||
CreatedAt: doc.CreatedAt,
|
||||
UpdatedAt: doc.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
page := page.NewPage(signableDocuments, documentsPage.Cursor)
|
||||
|
||||
return types.NewSignableDocumentConnection(page), nil
|
||||
}
|
||||
|
||||
// SignableDocument is the resolver for the signableDocument field.
|
||||
func (r *viewerResolver) SignableDocument(ctx context.Context, obj *types.Viewer, id gid.GID) (*types.SignableDocument, error) {
|
||||
r.MustBeAuthorized(ctx, id, authz.ActionGetSignableDocument)
|
||||
|
||||
prb := r.ProboService(ctx, id.TenantID())
|
||||
|
||||
user := UserFromContext(ctx)
|
||||
if user == nil {
|
||||
panic(fmt.Errorf("user not found in context"))
|
||||
}
|
||||
|
||||
documentFilter := coredata.NewDocumentFilter(nil).WithUserEmail(&user.EmailAddress)
|
||||
document, err := prb.Documents.GetWithFilter(ctx, id, documentFilter)
|
||||
if err != nil {
|
||||
var errNotFound *coredata.ErrDocumentNotFound
|
||||
if errors.As(err, &errNotFound) {
|
||||
return nil, gqlutils.NotFound(errNotFound)
|
||||
}
|
||||
panic(fmt.Errorf("cannot get signable document: %w", err))
|
||||
}
|
||||
|
||||
return &types.SignableDocument{
|
||||
ID: document.ID,
|
||||
Title: document.Title,
|
||||
DocumentType: document.DocumentType,
|
||||
Classification: document.Classification,
|
||||
CreatedAt: document.CreatedAt,
|
||||
UpdatedAt: document.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Asset returns schema.AssetResolver implementation.
|
||||
func (r *Resolver) Asset() schema.AssetResolver { return &assetResolver{r} }
|
||||
|
||||
@@ -7144,6 +7364,11 @@ func (r *Resolver) SAMLConfiguration() schema.SAMLConfigurationResolver {
|
||||
return &sAMLConfigurationResolver{r}
|
||||
}
|
||||
|
||||
// SignableDocument returns schema.SignableDocumentResolver implementation.
|
||||
func (r *Resolver) SignableDocument() schema.SignableDocumentResolver {
|
||||
return &signableDocumentResolver{r}
|
||||
}
|
||||
|
||||
// Snapshot returns schema.SnapshotResolver implementation.
|
||||
func (r *Resolver) Snapshot() schema.SnapshotResolver { return &snapshotResolver{r} }
|
||||
|
||||
@@ -7277,6 +7502,7 @@ type reportResolver struct{ *Resolver }
|
||||
type riskResolver struct{ *Resolver }
|
||||
type riskConnectionResolver struct{ *Resolver }
|
||||
type sAMLConfigurationResolver struct{ *Resolver }
|
||||
type signableDocumentResolver struct{ *Resolver }
|
||||
type snapshotResolver struct{ *Resolver }
|
||||
type snapshotConnectionResolver struct{ *Resolver }
|
||||
type taskResolver struct{ *Resolver }
|
||||
|
||||
@@ -1595,7 +1595,7 @@ func (r *Resolver) ListDocumentVersionsTool(ctx context.Context, req *mcp.CallTo
|
||||
cursor := types.NewCursor(input.Size, input.Cursor, pageOrderBy)
|
||||
svc := r.ProboService(ctx, input.DocumentID)
|
||||
|
||||
page, err := svc.Documents.ListVersions(ctx, input.DocumentID, cursor)
|
||||
page, err := svc.Documents.ListVersions(ctx, input.DocumentID, cursor, coredata.NewDocumentVersionFilter())
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot list document versions: %w", err))
|
||||
}
|
||||
|
||||
@@ -46,7 +46,8 @@ func (s *DocumentService) ListVersions(
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
return documentVersions.LoadByDocumentID(ctx, conn, s.svc.scope, documentID, cursor)
|
||||
filter := coredata.NewDocumentVersionFilter()
|
||||
return documentVersions.LoadByDocumentID(ctx, conn, s.svc.scope, documentID, cursor, filter)
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user