Rename policy to document

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-05-29 19:58:23 -07:00
parent c9f2df3cdd
commit e1b4079e1f
76 changed files with 5572 additions and 4690 deletions

View File

@@ -13,7 +13,7 @@
@import "@radix-ui/colors/orange.css";
@import "@radix-ui/colors/orange-dark.css";
@import "./styles/policy-content.css";
@import "./styles/document-content.css";
@plugin 'tailwindcss-animate';
@plugin "@tailwindcss/typography";

View File

@@ -7,7 +7,7 @@ import { HelmetProvider } from "react-helmet-async";
import { RelayEnvironmentProvider } from "react-relay";
import { BrowserRouter, Route, Routes, useLocation } from "react-router";
import "./App.css";
import "./styles/policy-content.css";
import "./styles/document-content.css";
import ErrorBoundary from "./components/ErrorBoundary";
import AuthLayout from "./layouts/AuthLayout";
import { RelayEnvironment } from "./RelayEnvironment";
@@ -55,7 +55,7 @@ function App() {
/>
<Route
path="policies/signing-requests"
path="documents/signing-requests"
element={<SigningRequestsPage />}
/>

View File

@@ -1,4 +1,4 @@
.policy-editor-container {
.document-editor-container {
border-radius: 0.5rem;
position: relative;
line-height: 1.5;
@@ -9,7 +9,7 @@
width: 100%;
}
.policy-editor {
.document-editor {
background: var(--bg-invert-bg);
position: relative;
border-radius: 0.5rem;
@@ -18,7 +18,7 @@
width: 100%;
}
.policy-editor-inner {
.document-editor-inner {
background: #fff;
position: relative;
border-radius: 0 0 0.5rem 0.5rem;
@@ -26,7 +26,7 @@
min-height: 250px;
}
.policy-editor-input {
.document-editor-input {
min-height: 250px;
max-height: 500px;
resize: none;
@@ -41,7 +41,7 @@
color: #000;
}
.policy-editor-placeholder {
.document-editor-placeholder {
color: #999;
overflow: hidden;
position: absolute;
@@ -54,12 +54,12 @@
pointer-events: none;
}
.policy-editor-paragraph {
.document-editor-paragraph {
margin: 0 0 15px 0;
position: relative;
}
.policy-editor .toolbar {
.document-editor .toolbar {
display: flex;
flex-wrap: wrap;
padding: 8px;
@@ -68,7 +68,7 @@
border-radius: 0.5rem 0.5rem 0 0;
}
.policy-editor .toolbar button {
.document-editor .toolbar button {
border: 0;
display: flex;
background: none;
@@ -80,15 +80,15 @@
justify-content: center;
}
.policy-editor .toolbar button:hover {
.document-editor .toolbar button:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.policy-editor .toolbar button.active {
.document-editor .toolbar button.active {
background-color: rgba(0, 0, 0, 0.1);
}
.policy-editor .toolbar .divider {
.document-editor .toolbar .divider {
width: 1px;
background-color: hsl(var(--solid-b));
margin: 0 8px;
@@ -281,4 +281,4 @@ ol.editor-list-ol ol.editor-list-ol > .editor-listitem {
.editor-tokenFunction {
color: #dd4a68;
}
}

View File

@@ -174,9 +174,9 @@ function getNavItems(organizationId?: string): NavItem[] {
icon: Store,
},
{
title: "Policies",
title: "Documents",
url: organizationId
? `/organizations/${organizationId}/policies`
? `/organizations/${organizationId}/documents`
: undefined,
icon: FileText,
},

View File

@@ -17,7 +17,7 @@ import remarkGfm from "remark-gfm";
import rehypeRaw from 'rehype-raw';
type Document = {
policy_version_id: string;
document_version_id: string;
title: string;
content: string;
signed?: boolean;
@@ -49,7 +49,7 @@ export default function SigningRequestsPage() {
async function fetchDocuments() {
try {
const response = await fetch(
buildEndpoint("/api/console/v1/policies/signing-requests"),
buildEndpoint("/api/console/v1/documents/signing-requests"),
{
method: "GET",
headers: {
@@ -96,7 +96,7 @@ export default function SigningRequestsPage() {
try {
const response = await fetch(
buildEndpoint(
`/api/console/v1/policies/signing-requests/${docToSign.policy_version_id}/sign`,
`/api/console/v1/documents/signing-requests/${docToSign.document_version_id}/sign`,
),
{
method: "POST",

View File

@@ -13,7 +13,7 @@ import { NavLink, Outlet, Route, Routes, To, useParams } from "react-router";
import { OrganizationBreadcrumbBreadcrumbFrameworkOverviewQuery } from "./__generated__/OrganizationBreadcrumbBreadcrumbFrameworkOverviewQuery.graphql";
import { OrganizationBreadcrumbBreadcrumbPeopleOverviewQuery } from "./__generated__/OrganizationBreadcrumbBreadcrumbPeopleOverviewQuery.graphql";
import { OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery } from "./__generated__/OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery.graphql";
import { OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery } from "./__generated__/OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery.graphql";
import { OrganizationBreadcrumbBreadcrumbVendorOverviewQuery } from "./__generated__/OrganizationBreadcrumbBreadcrumbVendorOverviewQuery.graphql";
import { OrganizationBreadcrumbOrganizationQuery } from "./__generated__/OrganizationBreadcrumbOrganizationQuery.graphql";
import { OrganizationBreadcrumbBreadcrumbMeasureViewQuery } from "./__generated__/OrganizationBreadcrumbBreadcrumbMeasureViewQuery.graphql";
@@ -264,14 +264,14 @@ function BreadcrumbPeopleOverview() {
);
}
function BreadcrumbPolicyList() {
function BreadcrumbDocumentList() {
const { organizationId } = useParams();
return (
<>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbNavLink to={`/organizations/${organizationId}/policies`}>
Policies
<BreadcrumbNavLink to={`/organizations/${organizationId}/documents`}>
Documents
</BreadcrumbNavLink>
</BreadcrumbItem>
<Outlet />
@@ -279,23 +279,23 @@ function BreadcrumbPolicyList() {
);
}
function BreadcrumbPolicyOverview() {
const { organizationId, policyId } = useParams();
function BreadcrumbDocumentOverview() {
const { organizationId, documentId } = useParams();
const data =
useLazyLoadQuery<OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery>(
useLazyLoadQuery<OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery>(
graphql`
query OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery(
$policyId: ID!
query OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery(
$documentId: ID!
) {
policy: node(id: $policyId) {
document: node(id: $documentId) {
id
... on Policy {
... on Document {
title
}
}
}
`,
{ policyId: policyId! },
{ documentId: documentId! },
{ fetchPolicy: "store-or-network" },
);
@@ -304,9 +304,9 @@ function BreadcrumbPolicyOverview() {
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbNavLink
to={`/organizations/${organizationId}/policies/${policyId}`}
to={`/organizations/${organizationId}/documents/${documentId}`}
>
{data.policy?.title}
{data.document?.title}
</BreadcrumbNavLink>
</BreadcrumbItem>
<Outlet />
@@ -531,12 +531,12 @@ export function BreadCrumb() {
}
/>
</Route>
<Route path="policies" element={<BreadcrumbPolicyList />}>
<Route path="documents" element={<BreadcrumbDocumentList />}>
<Route
path=":policyId"
path=":documentId"
element={
<Suspense>
<BreadcrumbPolicyOverview />
<BreadcrumbDocumentOverview />
</Suspense>
}
>

View File

@@ -18,9 +18,9 @@ import { NewMeasurePage } from "./measures/NewMeasurePage";
import { NewPeoplePage } from "./people/NewPeoplePage";
import { PeopleListPage } from "./people/PeopleListPage";
import { PeoplePage } from "./people/PeoplePage";
import { EditPolicyPage } from "./policies/EditPolicyPage";
import { PolicyListPage } from "./policies/PolicyListPage";
import { ShowPolicyPage } from "./policies/ShowPolicyPage";
import { EditDocumentPage } from "./documents/EditDocumentPage";
import { DocumentListPage } from "./documents/DocumentListPage";
import { ShowDocumentPage } from "./documents/ShowDocumentPage";
import { EditRiskPage } from "./risks/EditRiskPage";
import { NewRiskPage } from "./risks/NewRiskPage";
import { ListRiskPage } from "./risks/ListRiskPage";
@@ -54,11 +54,11 @@ export function OrganizationsRoutes() {
<Route path="measures/:measureId" element={<MeasurePage />} />
<Route path="measures/:measureId/edit" element={<EditMeasurePage />} />
<Route path="vendors/:vendorId" element={<VendorPage />} />
<Route path="policies" element={<PolicyListPage />} />
<Route path="policies/:policyId" element={<ShowPolicyPage />} />
<Route path="documents" element={<DocumentListPage />} />
<Route path="documents/:documentId" element={<ShowDocumentPage />} />
<Route
path="policies/:policyId/versions/:versionId/edit"
element={<EditPolicyPage />}
path="documents/:documentId/versions/:versionId/edit"
element={<EditDocumentPage />}
/>
<Route path="risks" element={<ListRiskPage />} />
<Route path="risks/new" element={<NewRiskPage />} />

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<ca410ce7df7231383e55d134d37916bd>>
* @generated SignedSource<<2cac1fe037796fc1b9542c9388ed930d>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,18 +9,18 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery$variables = {
policyId: string;
export type OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery$variables = {
documentId: string;
};
export type OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery$data = {
readonly policy: {
export type OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery$data = {
readonly document: {
readonly id: string;
readonly title?: string;
};
};
export type OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery = {
response: OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery$data;
variables: OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery$variables;
export type OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery = {
response: OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery$data;
variables: OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -28,14 +28,14 @@ var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "policyId"
"name": "documentId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "policyId"
"variableName": "documentId"
}
],
v2 = {
@@ -56,7 +56,7 @@ v3 = {
"storageKey": null
}
],
"type": "Policy",
"type": "Document",
"abstractKey": null
};
return {
@@ -64,10 +64,10 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery",
"name": "OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery",
"selections": [
{
"alias": "policy",
"alias": "document",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
@@ -87,10 +87,10 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery",
"name": "OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery",
"selections": [
{
"alias": "policy",
"alias": "document",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
@@ -112,16 +112,16 @@ return {
]
},
"params": {
"cacheID": "bc0b04bbe75c94660de230461532773a",
"cacheID": "bf577e8122cd59894e36f951f7a3551a",
"id": null,
"metadata": {},
"name": "OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery",
"name": "OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery",
"operationKind": "query",
"text": "query OrganizationBreadcrumbBreadcrumbPolicyOverviewQuery(\n $policyId: ID!\n) {\n policy: node(id: $policyId) {\n __typename\n id\n ... on Policy {\n title\n }\n }\n}\n"
"text": "query OrganizationBreadcrumbBreadcrumbDocumentOverviewQuery(\n $documentId: ID!\n) {\n document: node(id: $documentId) {\n __typename\n id\n ... on Document {\n title\n }\n }\n}\n"
}
};
})();
(node as any).hash = "ced380d1e6eb1c31ecc5f2dc9096133b";
(node as any).hash = "7ef8052c69e997cf2252d7c00b3f1c1f";
export default node;

View File

@@ -5,13 +5,13 @@ import { useLocation } from "react-router";
import { ErrorBoundaryWithLocation } from "../ErrorBoundary";
import { lazy } from "@probo/react-lazy";
const PolicyListView = lazy(() => import("./PolicyListView"));
const DocumentListView = lazy(() => import("./DocumentListView"));
export function PolicyListViewSkeleton() {
export function DocumentListViewSkeleton() {
return (
<PageTemplateSkeleton
title="Policies"
description="Manage your organization's policies"
title="Documents"
description="Manage your organization's documents"
actions={
<div className="bg-subtle-bg animate-pulse h-9 w-1/6 rounded-lg" />
}
@@ -28,7 +28,7 @@ export function PolicyListViewSkeleton() {
{/* Results summary skeleton */}
<div className="mb-4 h-4 w-48 bg-subtle-bg animate-pulse rounded" />
{/* Policy grid skeleton */}
{/* Document grid skeleton */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{[1, 2, 3, 4, 5, 6].map((i) => (
<Card key={i} className="bg-level-1/50 h-full flex flex-col">
@@ -60,13 +60,13 @@ export function PolicyListViewSkeleton() {
);
}
export function PolicyListPage() {
export function DocumentListPage() {
const location = useLocation();
return (
<Suspense key={location.pathname} fallback={<PolicyListViewSkeleton />}>
<Suspense key={location.pathname} fallback={<DocumentListViewSkeleton />}>
<ErrorBoundaryWithLocation>
<PolicyListView />
<DocumentListView />
</ErrorBoundaryWithLocation>
</Suspense>
);

View File

@@ -27,14 +27,14 @@ import {
import { useToast } from "@/hooks/use-toast";
import { format } from "date-fns";
import type {
PolicyListViewQuery,
PolicyListViewQuery$data,
} from "./__generated__/PolicyListViewQuery.graphql";
import type { PolicyListViewDeleteMutation } from "./__generated__/PolicyListViewDeleteMutation.graphql";
import type { PolicyListViewCreateMutation } from "./__generated__/PolicyListViewCreateMutation.graphql";
import type { PolicyListViewSendSigningNotificationsMutation } from "./__generated__/PolicyListViewSendSigningNotificationsMutation.graphql";
DocumentListViewQuery,
DocumentListViewQuery$data,
} from "./__generated__/DocumentListViewQuery.graphql";
import type { DocumentListViewDeleteMutation } from "./__generated__/DocumentListViewDeleteMutation.graphql";
import type { DocumentListViewCreateMutation } from "./__generated__/DocumentListViewCreateMutation.graphql";
import type { DocumentListViewSendSigningNotificationsMutation } from "./__generated__/DocumentListViewSendSigningNotificationsMutation.graphql";
import { PageTemplate } from "@/components/PageTemplate";
import { PolicyListViewSkeleton } from "./PolicyListPage";
import { DocumentListViewSkeleton } from "./DocumentListPage";
import {
Dialog,
DialogContent,
@@ -46,8 +46,8 @@ import PeopleSelector from "@/components/PeopleSelector";
import type { PeopleSelector_organization$key } from "@/components/__generated__/PeopleSelector_organization.graphql";
import { Textarea } from "@/components/ui/textarea";
const policyListViewQuery = graphql`
query PolicyListViewQuery($organizationId: ID!) {
const documentListViewQuery = graphql`
query DocumentListViewQuery($organizationId: ID!) {
viewer {
user {
id
@@ -57,8 +57,8 @@ const policyListViewQuery = graphql`
organization: node(id: $organizationId) {
... on Organization {
...PeopleSelector_organization
policies(first: 50, orderBy: { field: TITLE, direction: ASC })
@connection(key: "PolicyListView_policies") {
documents(first: 50, orderBy: { field: TITLE, direction: ASC })
@connection(key: "DocumentListView_documents") {
edges {
node {
id
@@ -96,24 +96,24 @@ const policyListViewQuery = graphql`
}
`;
const DeletePolicyMutation = graphql`
mutation PolicyListViewDeleteMutation(
$input: DeletePolicyInput!
const DeleteDocumentMutation = graphql`
mutation DocumentListViewDeleteMutation(
$input: DeleteDocumentInput!
$connections: [ID!]!
) {
deletePolicy(input: $input) {
deletedPolicyId @deleteEdge(connections: $connections)
deleteDocument(input: $input) {
deletedDocumentId @deleteEdge(connections: $connections)
}
}
`;
const createPolicyMutation = graphql`
mutation PolicyListViewCreateMutation(
$input: CreatePolicyInput!
const createDocumentMutation = graphql`
mutation DocumentListViewCreateMutation(
$input: CreateDocumentInput!
$connections: [ID!]!
) {
createPolicy(input: $input) {
policyEdge @prependEdge(connections: $connections) {
createDocument(input: $input) {
documentEdge @prependEdge(connections: $connections) {
node {
id
title
@@ -131,7 +131,7 @@ const createPolicyMutation = graphql`
`;
const sendSigningNotificationsMutation = graphql`
mutation PolicyListViewSendSigningNotificationsMutation(
mutation DocumentListViewSendSigningNotificationsMutation(
$input: SendSigningNotificationsInput!
) {
sendSigningNotifications(input: $input) {
@@ -139,21 +139,21 @@ const sendSigningNotificationsMutation = graphql`
}
}
`;
function PolicyTableRow({
policy,
function DocumentTableRow({
document,
organizationId,
}: {
policy: NonNullable<
PolicyListViewQuery$data["organization"]["policies"]
document: NonNullable<
DocumentListViewQuery$data["organization"]["documents"]
>["edges"][0]["node"];
organizationId: string;
}) {
const navigate = useNavigate();
const { toast } = useToast();
const [deletePolicy, isDeleting] =
useMutation<PolicyListViewDeleteMutation>(DeletePolicyMutation);
const [deleteDocument, isDeleting] =
useMutation<DocumentListViewDeleteMutation>(DeleteDocumentMutation);
const latestVersion = policy.versions?.edges[0]?.node;
const latestVersion = document.versions?.edges[0]?.node;
const status = latestVersion?.status || "DRAFT";
// Get signature counts
@@ -163,45 +163,45 @@ function PolicyTableRow({
(edge) => edge?.node?.state === "SIGNED",
).length;
const handleDeletePolicy = (e: React.MouseEvent) => {
const handleDeleteDocument = (e: React.MouseEvent) => {
e.stopPropagation();
if (
window.confirm(
"Are you sure you want to delete this policy? This action cannot be undone.",
"Are you sure you want to delete this document? This action cannot be undone.",
)
) {
deletePolicy({
deleteDocument({
variables: {
input: {
policyId: policy.id,
documentId: document.id,
},
connections: [
ConnectionHandler.getConnectionID(
organizationId,
"PolicyListView_policies",
"DocumentListView_documents",
),
],
},
onCompleted: (_, errors) => {
if (errors) {
console.error("Error deleting policy:", errors);
console.error("Error deleting document:", errors);
toast({
title: "Error",
description: "Failed to delete policy. Please try again.",
description: "Failed to delete document. Please try again.",
variant: "destructive",
});
return;
}
toast({
title: "Success",
description: "Policy deleted successfully.",
description: "Document deleted successfully.",
});
},
onError: (error) => {
console.error("Error deleting policy:", error);
console.error("Error deleting document:", error);
toast({
title: "Error",
description: "Failed to delete policy. Please try again.",
description: "Failed to delete document. Please try again.",
variant: "destructive",
});
},
@@ -211,32 +211,32 @@ function PolicyTableRow({
const handleView = (e: React.MouseEvent) => {
e.stopPropagation();
navigate(`/organizations/${organizationId}/policies/${policy.id}`);
navigate(`/organizations/${organizationId}/documents/${document.id}`);
};
return (
<tr
className="border-t border-solid-b hover:bg-subtle-bg cursor-pointer"
onClick={() => {
navigate(`/organizations/${organizationId}/policies/${policy.id}`);
navigate(`/organizations/${organizationId}/documents/${document.id}`);
}}
>
<td className="py-4 px-6">
<div className="flex flex-col">
<span className="font-medium text-primary">{policy.title}</span>
<span className="font-medium text-primary">{document.title}</span>
<span className="text-sm text-tertiary">
{policy.description || "No description provided"}
{document.description || "No description provided"}
</span>
</div>
</td>
<td className="py-4 px-6">
<span className="text-sm text-primary">
{policy.owner?.fullName || "Unassigned"}
{document.owner?.fullName || "Unassigned"}
</span>
</td>
<td className="py-4 px-6">
<span className="text-sm text-primary">
{format(new Date(policy.updatedAt), "MMM d, yyyy")}
{format(new Date(document.updatedAt), "MMM d, yyyy")}
</span>
</td>
<td className="py-4 px-6">
@@ -277,7 +277,7 @@ function PolicyTableRow({
View
</DropdownMenuItem>
<DropdownMenuItem
onClick={handleDeletePolicy}
onClick={handleDeleteDocument}
className="text-danger focus:text-danger focus:bg-danger-bg"
disabled={isDeleting}
>
@@ -291,7 +291,7 @@ function PolicyTableRow({
);
}
function CreatePolicyModal({
function CreateDocumentModal({
open,
onOpenChange,
organizationId,
@@ -307,8 +307,8 @@ function CreatePolicyModal({
const [content, setContent] = useState("");
const [ownerId, setOwnerId] = useState<string | null>(null);
const [createPolicy, isCreating] =
useMutation<PolicyListViewCreateMutation>(createPolicyMutation);
const [createDocument, isCreating] =
useMutation<DocumentListViewCreateMutation>(createDocumentMutation);
// Reset form fields
const resetForm = () => {
@@ -317,11 +317,11 @@ function CreatePolicyModal({
setOwnerId(null);
};
const handleCreatePolicy = () => {
const handleCreateDocument = () => {
if (!title.trim()) {
toast({
title: "Error",
description: "Please enter a policy title.",
description: "Please enter a document title.",
variant: "destructive",
});
return;
@@ -330,7 +330,7 @@ function CreatePolicyModal({
if (!ownerId) {
toast({
title: "Error",
description: "Please select an owner for the policy.",
description: "Please select an owner for the document.",
variant: "destructive",
});
return;
@@ -343,23 +343,23 @@ function CreatePolicyModal({
ownerId,
};
createPolicy({
createDocument({
variables: {
input,
connections: [
ConnectionHandler.getConnectionID(
organizationId,
"PolicyListView_policies",
"DocumentListView_documents",
{ orderBy: { field: "TITLE", direction: "ASC" } },
),
],
},
onCompleted: (response, errors) => {
if (errors) {
console.error("Error creating policy:", errors);
console.error("Error creating document:", errors);
toast({
title: "Error",
description: "Failed to create policy. Please try again.",
description: "Failed to create document. Please try again.",
variant: "destructive",
});
return;
@@ -367,17 +367,17 @@ function CreatePolicyModal({
toast({
title: "Success",
description: "Policy created successfully!",
description: "Document created successfully!",
});
resetForm();
onOpenChange(false);
},
onError: (error) => {
console.error("Error creating policy:", error);
console.error("Error creating document:", error);
toast({
title: "Error",
description: "Failed to create policy. Please try again.",
description: "Failed to create document. Please try again.",
variant: "destructive",
});
},
@@ -394,16 +394,16 @@ function CreatePolicyModal({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[1080px] h-[700px] max-h-[700px] p-0 gap-0 flex flex-col">
<DialogTitle className="sr-only">Create new policy</DialogTitle>
<DialogTitle className="sr-only">Create new document</DialogTitle>
<DialogDescription className="sr-only">
Form to create a new policy with title, content, and owner
Form to create a new document with title, content, and owner
information.
</DialogDescription>
<div className="flex justify-between items-center py-2 px-4 border-b border-solid-b h-[40px]">
<div className="flex items-center gap-1 text-sm">
<span className="text-tertiary">Policies</span>
<span className="text-tertiary">Documents</span>
<ChevronDown className="h-3 w-3 text-quaternary rotate-[270deg]" />
<span className="font-medium">New policy</span>
<span className="font-medium">New document</span>
</div>
</div>
@@ -425,25 +425,25 @@ function CreatePolicyModal({
}
}}
onFocus={(e) => {
if (e.currentTarget.textContent === "Enter policy title...") {
if (e.currentTarget.textContent === "Enter document title...") {
e.currentTarget.textContent = "";
}
}}
onBlur={(e) => {
if (!e.currentTarget.textContent?.trim()) {
e.currentTarget.textContent = "Enter policy title...";
e.currentTarget.textContent = "Enter document title...";
setTitle("");
}
}}
ref={(el) => {
if (el && !el.textContent) {
el.textContent = title || "Enter policy title...";
el.textContent = title || "Enter document title...";
}
}}
></h1>
</div>
<Textarea
placeholder="This Privacy Policy outlines how NovaSoft collects, uses, and protects personal information provided by users of its services. By accessing or using our platform, you agree to the collection and use of information in accordance with this policy..."
placeholder="This Privacy Document outlines how NovaSoft collects, uses, and protects personal information provided by users of its services. By accessing or using our platform, you agree to the collection and use of information in accordance with this document..."
className="min-h-[300px] border-none resize-none p-0 focus-visible:ring-0 focus-visible:ring-offset-0"
value={content}
onChange={(e) => setContent(e.target.value)}
@@ -499,11 +499,11 @@ function CreatePolicyModal({
Cancel
</Button>
<Button
onClick={handleCreatePolicy}
onClick={handleCreateDocument}
disabled={isCreating}
className="h-9"
>
{isCreating ? "Creating..." : "Create policy"}
{isCreating ? "Creating..." : "Create document"}
</Button>
</DialogFooter>
</DialogContent>
@@ -511,24 +511,24 @@ function CreatePolicyModal({
);
}
function PolicyListViewContent({
function DocumentListViewContent({
queryRef,
}: {
queryRef: PreloadedQuery<PolicyListViewQuery>;
queryRef: PreloadedQuery<DocumentListViewQuery>;
}) {
const data = usePreloadedQuery<PolicyListViewQuery>(
policyListViewQuery,
const data = usePreloadedQuery<DocumentListViewQuery>(
documentListViewQuery,
queryRef,
);
const { organizationId } = useParams();
const policies =
data.organization?.policies?.edges.map((edge) => edge?.node) ?? [];
const documents =
data.organization?.documents?.edges.map((edge) => edge?.node) ?? [];
const [createModalOpen, setCreateModalOpen] = useState(false);
const [confirmSigningModalOpen, setConfirmSigningModalOpen] = useState(false);
const [sendSigningNotifications, isSendingNotifications] =
useMutation<PolicyListViewSendSigningNotificationsMutation>(
useMutation<DocumentListViewSendSigningNotificationsMutation>(
sendSigningNotificationsMutation,
);
const { toast } = useToast();
@@ -580,12 +580,12 @@ function PolicyListViewContent({
return (
<PageTemplate
title="Policies"
title="Documents"
actions={
<div className="flex items-center gap-2">
<Button onClick={handleOpenModal}>
<Plus className="mr-2 h-4 w-4" />
New policy
New document
</Button>
<Button onClick={() => setConfirmSigningModalOpen(true)}>
Send signing notifications
@@ -593,14 +593,14 @@ function PolicyListViewContent({
</div>
}
>
{/* Policy table */}
{/* Document table */}
<div className="rounded-lg border border-solid-b overflow-hidden bg-level-1">
<table className="w-full">
<thead>
<tr className="bg-level-1 text-left">
<th className="py-3 px-6 text-xs font-medium text-tertiary border-b border-low-b">
<div className="flex items-center gap-1">
Policy
Document
<ChevronDown className="h-3 w-3 text-quaternary" />
</div>
</th>
@@ -632,11 +632,11 @@ function PolicyListViewContent({
</tr>
</thead>
<tbody className="bg-level-1">
{policies.length > 0 ? (
policies.map((policy: any) => (
<PolicyTableRow
key={policy.id}
policy={policy}
{documents.length > 0 ? (
documents.map((document: any) => (
<DocumentTableRow
key={document.id}
document={document}
organizationId={organizationId!}
/>
))
@@ -644,13 +644,13 @@ function PolicyListViewContent({
<tr>
<td colSpan={6} className="py-12 text-center">
<div className="flex flex-col items-center gap-2">
<h3 className="text-lg font-medium">No policies found</h3>
<h3 className="text-lg font-medium">No documents found</h3>
<p className="text-tertiary">
Create your first policy to get started
Create your first document to get started
</p>
<Button onClick={handleOpenModal}>
<Plus className="mr-2 h-4 w-4" />
Create policy
Create document
</Button>
</div>
</td>
@@ -660,7 +660,7 @@ function PolicyListViewContent({
</table>
</div>
<CreatePolicyModal
<CreateDocumentModal
open={createModalOpen}
onOpenChange={handleCloseModal}
organizationId={organizationId!}
@@ -676,7 +676,7 @@ function PolicyListViewContent({
<DialogTitle>Send Signing Notifications</DialogTitle>
<DialogDescription>
This will send signing notifications to all users who have pending
policies to sign. Are you sure you want to continue?
documents to sign. Are you sure you want to continue?
</DialogDescription>
<DialogFooter className="gap-2 mt-4">
<Button
@@ -698,9 +698,9 @@ function PolicyListViewContent({
);
}
export default function PolicyListView() {
export default function DocumentListView() {
const [queryRef, loadQuery] =
useQueryLoader<PolicyListViewQuery>(policyListViewQuery);
useQueryLoader<DocumentListViewQuery>(documentListViewQuery);
const { organizationId } = useParams();
@@ -709,12 +709,12 @@ export default function PolicyListView() {
}, [loadQuery, organizationId]);
if (!queryRef) {
return <PolicyListViewSkeleton />;
return <DocumentListViewSkeleton />;
}
return (
<Suspense fallback={<PolicyListViewSkeleton />}>
{<PolicyListViewContent queryRef={queryRef} />}
<Suspense fallback={<DocumentListViewSkeleton />}>
{<DocumentListViewContent queryRef={queryRef} />}
</Suspense>
);
}

View File

@@ -4,26 +4,26 @@ import { lazy } from "@probo/react-lazy";
import { useLocation } from "react-router";
import { ErrorBoundaryWithLocation } from "../ErrorBoundary";
const EditPolicyView = lazy(() => import("./EditPolicyView"));
const EditDocumentView = lazy(() => import("./EditDocumentView"));
export function EditPolicyViewSkeleton() {
export function EditDocumentViewSkeleton() {
return (
<PageTemplateSkeleton
title="Edit Policy"
description="Edit an existing policy"
title="Edit Document"
description="Edit an existing document"
>
<div className="bg-subtle-bg animate-pulse rounded-lg h-[600px]" />
</PageTemplateSkeleton>
);
}
export function EditPolicyPage() {
export function EditDocumentPage() {
const location = useLocation();
return (
<Suspense key={location.pathname} fallback={<EditPolicyViewSkeleton />}>
<Suspense key={location.pathname} fallback={<EditDocumentViewSkeleton />}>
<ErrorBoundaryWithLocation>
<EditPolicyView />
<EditDocumentView />
</ErrorBoundaryWithLocation>
</Suspense>
);

View File

@@ -13,27 +13,27 @@ import { Textarea } from "@/components/ui/textarea";
import { Label } from "@/components/ui/label";
import { toast } from "@/hooks/use-toast";
import { Suspense } from "react";
import type { EditPolicyViewQuery } from "./__generated__/EditPolicyViewQuery.graphql";
import type { EditPolicyViewMutation as EditPolicyViewMutationType } from "./__generated__/EditPolicyViewMutation.graphql";
import type { EditDocumentViewQuery } from "./__generated__/EditDocumentViewQuery.graphql";
import type { EditDocumentViewMutation as EditDocumentViewMutationType } from "./__generated__/EditDocumentViewMutation.graphql";
import { PageTemplate } from "@/components/PageTemplate";
import { EditPolicyViewSkeleton } from "./EditPolicyPage";
import { EditDocumentViewSkeleton } from "./EditDocumentPage";
const editPolicyViewQuery = graphql`
query EditPolicyViewQuery(
$policyId: ID!
const editDocumentViewQuery = graphql`
query EditDocumentViewQuery(
$documentId: ID!
$organizationId: ID!
$policyVersionId: ID!
$documentVersionId: ID!
) {
policyVersion: node(id: $policyVersionId) {
documentVersion: node(id: $documentVersionId) {
id
... on PolicyVersion {
... on DocumentVersion {
content
}
}
policy: node(id: $policyId) {
document: node(id: $documentId) {
id
... on Policy {
... on Document {
title
owner {
id
@@ -47,10 +47,10 @@ const editPolicyViewQuery = graphql`
}
`;
const UpdatePolicyMutation = graphql`
mutation EditPolicyViewMutation($input: UpdatePolicyVersionInput!) {
updatePolicyVersion(input: $input) {
policyVersion {
const UpdateDocumentMutation = graphql`
mutation EditDocumentViewMutation($input: UpdateDocumentVersionInput!) {
updateDocumentVersion(input: $input) {
documentVersion {
id
content
}
@@ -58,75 +58,75 @@ const UpdatePolicyMutation = graphql`
}
`;
function EditPolicyViewContent({
function EditDocumentViewContent({
queryRef,
}: {
queryRef: PreloadedQuery<EditPolicyViewQuery>;
queryRef: PreloadedQuery<EditDocumentViewQuery>;
}) {
const navigate = useNavigate();
const { organizationId, policyId, versionId } = useParams();
const data = usePreloadedQuery<EditPolicyViewQuery>(
editPolicyViewQuery,
const { organizationId, documentId, versionId } = useParams();
const data = usePreloadedQuery<EditDocumentViewQuery>(
editDocumentViewQuery,
queryRef,
);
const [content, setContent] = useState(data.policyVersion.content || "");
const [content, setContent] = useState(data.documentVersion.content || "");
const [updatePolicy, isSubmitting] =
useMutation<EditPolicyViewMutationType>(UpdatePolicyMutation);
const [updateDocument, isSubmitting] =
useMutation<EditDocumentViewMutationType>(UpdateDocumentMutation);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
updatePolicy({
updateDocument({
variables: {
input: {
policyVersionId: data.policyVersion.id,
documentVersionId: data.documentVersion.id,
content,
},
},
onCompleted: (_, errors) => {
if (errors) {
console.error("Error updating policy:", errors);
console.error("Error updating document:", errors);
toast({
title: "Error",
description: "Failed to update policy. Please try again.",
description: "Failed to update document. Please try again.",
});
return;
}
toast({
title: "Success",
description: "Policy updated successfully.",
description: "Document updated successfully.",
});
navigate(`/organizations/${organizationId}/policies/${policyId}`);
navigate(`/organizations/${organizationId}/documents/${documentId}`);
},
onError: (error) => {
console.error("Error updating policy:", error);
console.error("Error updating document:", error);
toast({
title: "Error",
description: "Failed to update policy. Please try again.",
description: "Failed to update document. Please try again.",
});
},
});
};
return (
<PageTemplate title="Update Policy" description="Update an existing policy">
<PageTemplate title="Update Document" description="Update an existing document">
<form onSubmit={handleSubmit}>
<div className="grid gap-6">
<Card>
<CardHeader>
<CardTitle>Policy Information</CardTitle>
<CardTitle>Document Information</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="content">Policy Content</Label>
<Label htmlFor="content">Document Content</Label>
<div className="min-h-[500px]">
<Textarea
id="content"
placeholder="Enter policy description"
placeholder="Enter document description"
value={content}
onChange={(e) => setContent(e.target.value)}
required
@@ -144,14 +144,14 @@ function EditPolicyViewContent({
variant="outline"
onClick={() =>
navigate(
`/organizations/${organizationId}/policies/${policyId}`,
`/organizations/${organizationId}/documents/${documentId}`,
)
}
>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
{isSubmitting ? "Updating..." : "Update Policy"}
{isSubmitting ? "Updating..." : "Update Document"}
</Button>
</div>
</div>
@@ -160,26 +160,26 @@ function EditPolicyViewContent({
);
}
export default function EditPolicyView() {
const { organizationId, policyId, versionId } = useParams();
export default function EditDocumentView() {
const { organizationId, documentId, versionId } = useParams();
const [queryRef, loadQuery] =
useQueryLoader<EditPolicyViewQuery>(editPolicyViewQuery);
useQueryLoader<EditDocumentViewQuery>(editDocumentViewQuery);
useEffect(() => {
loadQuery({
organizationId: organizationId!,
policyId: policyId!,
policyVersionId: versionId!,
documentId: documentId!,
documentVersionId: versionId!,
});
}, [organizationId, policyId, versionId]);
}, [organizationId, documentId, versionId]);
if (!queryRef) {
return <EditPolicyViewSkeleton />;
return <EditDocumentViewSkeleton />;
}
return (
<Suspense fallback={<EditPolicyViewSkeleton />}>
<EditPolicyViewContent queryRef={queryRef} />
<Suspense fallback={<EditDocumentViewSkeleton />}>
<EditDocumentViewContent queryRef={queryRef} />
</Suspense>
);
}

View File

@@ -5,9 +5,9 @@ import { useLocation } from "react-router";
import { ErrorBoundaryWithLocation } from "../ErrorBoundary";
import { lazy } from "@probo/react-lazy";
const ShowPolicyView = lazy(() => import("./ShowPolicyView"));
const ShowDocumentView = lazy(() => import("./ShowDocumentView"));
export function ShowPolicyViewSkeleton() {
export function ShowDocumentViewSkeleton() {
return (
<PageTemplateSkeleton
withDescription
@@ -108,13 +108,13 @@ export function ShowPolicyViewSkeleton() {
);
}
export function ShowPolicyPage() {
export function ShowDocumentPage() {
const location = useLocation();
return (
<Suspense key={location.pathname} fallback={<ShowPolicyViewSkeleton />}>
<Suspense key={location.pathname} fallback={<ShowDocumentViewSkeleton />}>
<ErrorBoundaryWithLocation>
<ShowPolicyView />
<ShowDocumentView />
</ErrorBoundaryWithLocation>
</Suspense>
);

View File

@@ -20,12 +20,12 @@ import {
import { Button } from "@/components/ui/button";
import { useToast } from "@/hooks/use-toast";
import { PageTemplate } from "@/components/PageTemplate";
import type { ShowPolicyViewQuery } from "./__generated__/ShowPolicyViewQuery.graphql";
import { ShowPolicyViewPublishMutation } from "./__generated__/ShowPolicyViewPublishMutation.graphql";
import { ShowPolicyViewCreateDraftMutation } from "./__generated__/ShowPolicyViewCreateDraftMutation.graphql";
import type { ShowDocumentViewQuery } from "./__generated__/ShowDocumentViewQuery.graphql";
import { ShowDocumentViewPublishMutation } from "./__generated__/ShowDocumentViewPublishMutation.graphql";
import { ShowDocumentViewCreateDraftMutation } from "./__generated__/ShowDocumentViewCreateDraftMutation.graphql";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { ShowPolicyViewSkeleton } from "./ShowPolicyPage";
import { ShowDocumentViewSkeleton } from "./ShowDocumentPage";
import { format } from "date-fns";
import {
DropdownMenu,
@@ -45,20 +45,20 @@ import { SignaturesModal } from "./SignaturesModal";
import { VersionHistoryModal } from "./VersionHistoryModal";
import rehypeRaw from "rehype-raw";
import { createRoot } from "react-dom/client";
import { policyVersionsFragment } from "./SignaturesModal";
import type { SignaturesModal_policyVersions$key } from "./__generated__/SignaturesModal_policyVersions.graphql";
import { documentVersionsFragment } from "./SignaturesModal";
import type { SignaturesModal_documentVersions$key } from "./__generated__/SignaturesModal_documentVersions.graphql";
const policyViewQuery = graphql`
query ShowPolicyViewQuery($policyId: ID!, $organizationId: ID!) {
const documentViewQuery = graphql`
query ShowDocumentViewQuery($documentId: ID!, $organizationId: ID!) {
organization: node(id: $organizationId) {
... on Organization {
name
}
}
node(id: $policyId) {
node(id: $documentId) {
id
... on Policy {
... on Document {
title
description
createdAt
@@ -70,8 +70,8 @@ const policyViewQuery = graphql`
primaryEmailAddress
}
...SignaturesModal_policyVersions
...VersionHistoryModal_policyVersions
...SignaturesModal_documentVersions
...VersionHistoryModal_documentVersions
latestVersion: versions(first: 1) {
edges {
@@ -95,14 +95,14 @@ const policyViewQuery = graphql`
}
`;
const publishPolicyVersionMutation = graphql`
mutation ShowPolicyViewPublishMutation($input: PublishPolicyVersionInput!) {
publishPolicyVersion(input: $input) {
policy {
const publishDocumentVersionMutation = graphql`
mutation ShowDocumentViewPublishMutation($input: PublishDocumentVersionInput!) {
publishDocumentVersion(input: $input) {
document {
id
currentPublishedVersion
}
policyVersion {
documentVersion {
id
status
publishedAt
@@ -114,12 +114,12 @@ const publishPolicyVersionMutation = graphql`
}
`;
const createDraftPolicyVersionMutation = graphql`
mutation ShowPolicyViewCreateDraftMutation(
$input: CreateDraftPolicyVersionInput!
const createDraftDocumentVersionMutation = graphql`
mutation ShowDocumentViewCreateDraftMutation(
$input: CreateDraftDocumentVersionInput!
) {
createDraftPolicyVersion(input: $input) {
policyVersionEdge {
createDraftDocumentVersion(input: $input) {
documentVersionEdge {
node {
id
version
@@ -130,22 +130,22 @@ const createDraftPolicyVersionMutation = graphql`
}
`;
function ShowPolicyContent({
function ShowDocumentContent({
queryRef,
}: {
queryRef: PreloadedQuery<ShowPolicyViewQuery>;
queryRef: PreloadedQuery<ShowDocumentViewQuery>;
}) {
const data = usePreloadedQuery<ShowPolicyViewQuery>(
policyViewQuery,
const data = usePreloadedQuery<ShowDocumentViewQuery>(
documentViewQuery,
queryRef,
);
const policy = data.node;
const documentValue = data.node;
const { organizationId } = useParams();
const navigate = useNavigate();
const { toast } = useToast();
const [queryRef2, loadQuery] =
useQueryLoader<ShowPolicyViewQuery>(policyViewQuery);
useQueryLoader<ShowDocumentViewQuery>(documentViewQuery);
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [isDeleting, setIsDeleting] = useState(false);
const [isVersionHistoryOpen, setIsVersionHistoryOpen] = useState(false);
@@ -153,13 +153,13 @@ function ShowPolicyContent({
const printContentRef = useRef<HTMLDivElement>(null);
const [publishDraft, isPublishInFlight] =
useMutation<ShowPolicyViewPublishMutation>(publishPolicyVersionMutation);
useMutation<ShowDocumentViewPublishMutation>(publishDocumentVersionMutation);
const [createDraft, isCreateDraftInFlight] =
useMutation<ShowPolicyViewCreateDraftMutation>(
createDraftPolicyVersionMutation,
useMutation<ShowDocumentViewCreateDraftMutation>(
createDraftDocumentVersionMutation,
);
const latestVersionEdge = policy.latestVersion?.edges[0];
const latestVersionEdge = documentValue.latestVersion?.edges[0];
const latestVersionNode = latestVersionEdge?.node;
const isDraft = latestVersionNode?.status === "DRAFT";
@@ -168,40 +168,40 @@ function ShowPolicyContent({
// No need to update selectedVersion state since we're using the VersionHistoryModal component
}, []);
// Handle delete policy
const handleDeletePolicy = useCallback(() => {
// Handle delete document
const handleDeleteDocument = useCallback(() => {
setIsDeleteDialogOpen(true);
}, []);
// Confirm delete policy
const confirmDeletePolicy = useCallback(() => {
// Confirm delete document
const confirmDeleteDocument = useCallback(() => {
setIsDeleting(true);
setTimeout(() => {
toast({
title: "Policy deleted",
description: "The policy has been deleted successfully",
title: "Document deleted",
description: "The document has been deleted successfully",
});
setIsDeleting(false);
setIsDeleteDialogOpen(false);
navigate(`/organizations/${organizationId}/policies`);
navigate(`/organizations/${organizationId}/documents`);
}, 1000);
}, [toast, navigate, organizationId]);
// Navigate to publish flow
const handlePublish = useCallback(() => {
if (!policy.id) return;
if (!documentValue.id) return;
publishDraft({
variables: {
input: {
policyId: policy.id,
documentId: documentValue.id,
},
},
onCompleted: (_, errors) => {
if (errors) {
toast({
title: "Error publishing policy",
title: "Error publishing document",
description: errors[0]?.message || "An unknown error occurred",
variant: "destructive",
});
@@ -209,22 +209,22 @@ function ShowPolicyContent({
}
toast({
title: "Policy published",
description: `The policy has been published successfully`,
title: "Document published",
description: `The document has been published successfully`,
});
// Reload the query to refresh the data
loadQuery({ policyId: policy.id, organizationId: organizationId! });
loadQuery({ documentId: documentValue.id, organizationId: organizationId! });
},
onError: (error) => {
toast({
title: "Error publishing policy",
title: "Error publishing document",
description: error.message || "An unknown error occurred",
variant: "destructive",
});
},
});
}, [policy.id, publishDraft, toast, loadQuery]);
}, [documentValue.id, publishDraft, toast, loadQuery]);
// Open version history modal
const handleVersionHistoryClick = useCallback(() => {
@@ -241,23 +241,23 @@ function ShowPolicyContent({
});
setIsVersionHistoryOpen(false);
// Reload the query to refresh the data
if (policy.id) {
loadQuery({ policyId: policy.id, organizationId: organizationId! });
if (documentValue.id) {
loadQuery({ documentId: documentValue.id, organizationId: organizationId! });
}
},
[policy.id, loadQuery, toast],
[documentValue.id, loadQuery, toast],
);
// Handle edit policy
const handleEditPolicy = useCallback(() => {
if (!policy.id) return;
// Handle edit document
const handleEditDocument = useCallback(() => {
if (!documentValue.id) return;
if (latestVersionNode?.status === "PUBLISHED") {
// Create a new draft version first
createDraft({
variables: {
input: {
policyID: policy.id,
documentID: documentValue.id,
},
},
onCompleted: (response, errors) => {
@@ -271,9 +271,9 @@ function ShowPolicyContent({
}
const newDraftId =
response.createDraftPolicyVersion.policyVersionEdge.node.id;
response.createDraftDocumentVersion.documentVersionEdge.node.id;
navigate(
`/organizations/${organizationId}/policies/${policy.id}/versions/${newDraftId}/edit`,
`/organizations/${organizationId}/documents/${documentValue.id}/versions/${newDraftId}/edit`,
);
},
onError: (error) => {
@@ -287,11 +287,11 @@ function ShowPolicyContent({
} else {
// Navigate directly to edit if it's already a draft
navigate(
`/organizations/${organizationId}/policies/${policy.id}/versions/${latestVersionNode?.id}/edit`,
`/organizations/${organizationId}/documents/${documentValue.id}/versions/${latestVersionNode?.id}/edit`,
);
}
}, [
policy.id,
documentValue.id,
latestVersionNode,
createDraft,
navigate,
@@ -306,10 +306,10 @@ function ShowPolicyContent({
return format(date, "MMM d, yyyy");
};
// Get policy signatures data
const policyData = useFragment<SignaturesModal_policyVersions$key>(
policyVersionsFragment,
policy as unknown as SignaturesModal_policyVersions$key
// Get document signatures data
const documentData = useFragment<SignaturesModal_documentVersions$key>(
documentVersionsFragment,
documentValue as unknown as SignaturesModal_documentVersions$key
);
// Handle PDF download
@@ -324,23 +324,23 @@ function ShowPolicyContent({
});
return;
}
// Get version nodes and signatures from the fragment data we have
const versionNodes = policyData?.policyVersions?.edges?.map(edge => edge.node) || [];
const versionNodes = documentData?.documentVersions?.edges?.map(edge => edge.node) || [];
const currentVersion = versionNodes.find(v => v.version === latestVersionNode?.version);
const signatures = currentVersion?.signatures?.edges?.map(edge => edge.node) || [];
// Create temporary div to render and capture markdown
const tempDiv = document.createElement('div');
const tempDiv = window.document.createElement('div');
const root = createRoot(tempDiv);
// Render the markdown content to HTML
root.render(
<ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}>
{latestVersionNode?.content || 'No content available'}
</ReactMarkdown>
);
// Give React a moment to render the content
setTimeout(() => {
const renderedMarkdown = tempDiv.innerHTML;
@@ -369,13 +369,13 @@ function ShowPolicyContent({
</table>
`;
}
// Create the print document content with the policy document data
// Create the print document content with the document document data
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<title>${policy.title || 'Policy Document'}</title>
<title>${documentValue.title || 'Document Document'}</title>
<style>
body { font-family: system-ui, -apple-system, sans-serif; margin: 40px; }
.header { margin-bottom: 30px; }
@@ -386,7 +386,7 @@ function ShowPolicyContent({
.signature-title { margin-top: 20px; font-weight: bold; font-size: 1.2em; margin-bottom: 10px; }
h1 { font-size: 24px; margin-bottom: 20px; }
.company-name { font-size: 16px; color: #555; margin-bottom: 5px; }
/* Markdown styles */
.content h1 { font-size: 1.8em; margin-top: 1em; margin-bottom: 0.5em; }
.content h2 { font-size: 1.5em; margin-top: 1em; margin-bottom: 0.5em; }
@@ -403,7 +403,7 @@ function ShowPolicyContent({
.content table { border-collapse: collapse; width: 100%; margin-bottom: 1em; }
.content th, .content td { border: 1px solid #ccc; padding: 0.5em; }
.content th { background: #f4f4f4; }
@media print {
body { margin: 0; }
.page-break { page-break-after: always; }
@@ -426,12 +426,12 @@ function ShowPolicyContent({
</head>
<body>
<div class="header">
<h1>${policy.title || 'Policy Document'}</h1>
<h1>${documentValue.title || 'Document Document'}</h1>
<div class="metadata">
<div class="metadata-item"><strong>Version:</strong> ${latestVersionNode?.version || 'N/A'}</div>
<div class="metadata-item"><strong>Status:</strong> ${latestVersionNode?.status === 'PUBLISHED' ? 'Published' : 'Draft'}</div>
<div class="metadata-item"><strong>Published Date:</strong> ${latestVersionNode?.status === 'PUBLISHED' ? formatDate(latestVersionNode.publishedAt || '') : 'Not yet published'}</div>
<div class="metadata-item"><strong>Owner:</strong> ${policy.owner?.fullName || 'Unknown'}</div>
<div class="metadata-item"><strong>Owner:</strong> ${documentValue.owner?.fullName || 'Unknown'}</div>
<div class="metadata-item"><strong>Last Modified:</strong> ${formatDate(latestVersionNode?.updatedAt)}</div>
<div class="metadata-item"><strong>Company:</strong> ${data.organization.name}</div>
</div>
@@ -446,27 +446,27 @@ function ShowPolicyContent({
</body>
</html>
`);
// Trigger print
printWindow.document.close();
printWindow.focus();
// Use setTimeout to give the browser time to load any resources
setTimeout(() => {
printWindow.print();
// Optional: close the window after printing
// printWindow.close();
}, 500);
// Clean up
root.unmount();
}, 100);
}, [policy, latestVersionNode, formatDate, toast, policyData, data.organization.name!]);
}, [documentValue, latestVersionNode, formatDate, toast, documentData, data.organization.name!]);
return (
<PageTemplate
title={policy.title!}
title={documentValue.title!}
actions={
<div className="flex items-center gap-2">
<Button
@@ -523,19 +523,19 @@ function ShowPolicyContent({
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem asChild>
<div onClick={handleEditPolicy}>
<div onClick={handleEditDocument}>
<Edit className="mr-2 h-4 w-4" />
{latestVersionNode?.status === "PUBLISHED"
? "Create new draft"
: "Edit draft policy"}
: "Edit draft document"}
</div>
</DropdownMenuItem>
<DropdownMenuItem
onClick={handleDeletePolicy}
onClick={handleDeleteDocument}
className="text-danger focus:text-danger focus:bg-danger-bg"
>
<Trash2 className="mr-2 h-4 w-4" />
Delete policy
Delete document
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
@@ -548,7 +548,7 @@ function ShowPolicyContent({
<div className="bg-gray-50 rounded-lg border border-solid-b shadow-sm p-6 mb-4">
<div className="grid grid-cols-2 gap-y-3">
<div>
<span className="font-medium">Document Title:</span> {policy.title}
<span className="font-medium">Document Title:</span> {documentValue.title}
</div>
<div>
<span className="font-medium">Version:</span> {latestVersionNode.version || "N/A"}
@@ -560,7 +560,7 @@ function ShowPolicyContent({
<span className="font-medium">Published Date:</span> {latestVersionNode.status === "PUBLISHED" ? formatDate(latestVersionNode.publishedAt || "") : "Not yet published"}
</div>
<div>
<span className="font-medium">Owner:</span> {policy.owner?.fullName || "Unknown"}
<span className="font-medium">Owner:</span> {documentValue.owner?.fullName || "Unknown"}
</div>
<div>
<span className="font-medium">Last Modified:</span> {formatDate(latestVersionNode.updatedAt)}
@@ -590,7 +590,7 @@ function ShowPolicyContent({
<div>
{latestVersionNode.status === "PUBLISHED"
? `Published on ${formatDate(latestVersionNode.publishedAt || "")}${latestVersionNode.publishedBy ? ` by ${latestVersionNode.publishedBy.fullName}` : ""}`
: `Last modified on ${formatDate(latestVersionNode.updatedAt)} by ${policy.owner?.fullName || "Unknown"}`}
: `Last modified on ${formatDate(latestVersionNode.updatedAt)} by ${documentValue.owner?.fullName || "Unknown"}`}
</div>
</div>
</div>
@@ -606,15 +606,15 @@ function ShowPolicyContent({
<SignaturesModal
isOpen={isSignaturesModalOpen}
onClose={() => setIsSignaturesModalOpen(false)}
policyRef={policy}
owner={policy.owner}
documentRef={documentValue}
owner={documentValue.owner}
/>
{/* Version History Modal */}
<VersionHistoryModal
isOpen={isVersionHistoryOpen}
onClose={() => setIsVersionHistoryOpen(false)}
policyRef={policy}
documentRef={documentValue}
onRestoreVersion={handleRestoreVersion}
/>
@@ -622,9 +622,9 @@ function ShowPolicyContent({
<Dialog open={isDeleteDialogOpen} onOpenChange={setIsDeleteDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Delete Policy</DialogTitle>
<DialogTitle>Delete Document</DialogTitle>
<DialogDescription>
Are you sure you want to delete the policy "{policy.title}"? This
Are you sure you want to delete the document &ldquo;{documentValue.title}&rdquo;? This
action cannot be undone.
</DialogDescription>
</DialogHeader>
@@ -638,7 +638,7 @@ function ShowPolicyContent({
</Button>
<Button
variant="destructive"
onClick={confirmDeletePolicy}
onClick={confirmDeleteDocument}
disabled={isDeleting}
>
{isDeleting ? "Deleting..." : "Delete"}
@@ -650,22 +650,22 @@ function ShowPolicyContent({
);
}
export default function ShowPolicyView() {
export default function ShowDocumentView() {
const [queryRef, loadQuery] =
useQueryLoader<ShowPolicyViewQuery>(policyViewQuery);
const { policyId, organizationId } = useParams();
useQueryLoader<ShowDocumentViewQuery>(documentViewQuery);
const { documentId, organizationId } = useParams();
useEffect(() => {
loadQuery({ policyId: policyId!, organizationId: organizationId! });
}, [loadQuery, policyId, organizationId]);
loadQuery({ documentId: documentId!, organizationId: organizationId! });
}, [loadQuery, documentId, organizationId]);
if (!queryRef) {
return <ShowPolicyViewSkeleton />;
return <ShowDocumentViewSkeleton />;
}
return (
<Suspense fallback={<ShowPolicyViewSkeleton />}>
<ShowPolicyContent queryRef={queryRef} />
<Suspense fallback={<ShowDocumentViewSkeleton />}>
<ShowDocumentContent queryRef={queryRef} />
</Suspense>
);
}

View File

@@ -1,7 +1,7 @@
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { format } from "date-fns";
interface PolicyVersionSignature {
interface DocumentVersionSignature {
id: string;
state: "REQUESTED" | "SIGNED";
signedBy: {
@@ -15,7 +15,7 @@ interface PolicyVersionSignature {
}
interface SignaturesListProps {
signatures: PolicyVersionSignature[];
signatures: DocumentVersionSignature[];
}
export function SignaturesList({ signatures }: SignaturesListProps) {

View File

@@ -12,9 +12,9 @@ import {
ConnectionHandler,
} from "react-relay";
import type {
SignaturesModal_policyVersions$data,
SignaturesModal_policyVersions$key,
} from "./__generated__/SignaturesModal_policyVersions.graphql";
SignaturesModal_documentVersions$data,
SignaturesModal_documentVersions$key,
} from "./__generated__/SignaturesModal_documentVersions.graphql";
import type { SignaturesModalRequestSignatureMutation } from "./__generated__/SignaturesModalRequestSignatureMutation.graphql";
import type { SignaturesModalOrganizationQuery } from "./__generated__/SignaturesModalOrganizationQuery.graphql";
import { useToast } from "@/hooks/use-toast";
@@ -22,10 +22,10 @@ import { useParams } from "react-router";
import { Loader2, CheckCircle2, Clock } from "lucide-react";
import { PreloadedQuery } from "react-relay";
export const policyVersionsFragment = graphql`
fragment SignaturesModal_policyVersions on Policy {
export const documentVersionsFragment = graphql`
fragment SignaturesModal_documentVersions on Document {
title
policyVersions: versions(first: 10) {
documentVersions: versions(first: 10) {
edges {
node {
id
@@ -37,7 +37,7 @@ export const policyVersionsFragment = graphql`
fullName
}
signatures(first: 100)
@connection(key: "SignaturesModal_policyVersions_signatures") {
@connection(key: "SignaturesModal_documentVersions_signatures") {
edges {
node {
id
@@ -66,7 +66,7 @@ const requestSignatureMutation = graphql`
$connections: [ID!]!
) {
requestSignature(input: $input) {
policyVersionSignatureEdge @prependEdge(connections: $connections) {
documentVersionSignatureEdge @prependEdge(connections: $connections) {
node {
id
state
@@ -108,7 +108,7 @@ const organizationQuery = graphql`
interface SignaturesModalProps {
isOpen: boolean;
onClose: () => void;
policyRef: SignaturesModal_policyVersions$key;
documentRef: SignaturesModal_documentVersions$key;
owner?: {
fullName: string;
} | null;
@@ -117,16 +117,16 @@ interface SignaturesModalProps {
export function SignaturesModal({
isOpen,
onClose,
policyRef,
documentRef,
owner,
}: SignaturesModalProps) {
const data = useFragment<SignaturesModal_policyVersions$key>(
policyVersionsFragment,
policyRef,
const data = useFragment<SignaturesModal_documentVersions$key>(
documentVersionsFragment,
documentRef,
);
const versionNodes =
data?.policyVersions?.edges?.map((edge) => edge.node) || [];
data?.documentVersions?.edges?.map((edge) => edge.node) || [];
const publishedVersions = versionNodes
.filter((v) => v.status === "PUBLISHED")
.sort((a, b) => b.version - a.version);
@@ -177,13 +177,13 @@ export function SignaturesModal({
commitRequestSignature({
variables: {
input: {
policyVersionId: selectedVersionData.id,
documentVersionId: selectedVersionData.id,
signatoryId: personId,
},
connections: [
ConnectionHandler.getConnectionID(
selectedVersionData.id,
"SignaturesModal_policyVersions_signatures",
"SignaturesModal_documentVersions_signatures",
),
],
},
@@ -406,7 +406,7 @@ function PeopleAndSignaturesList({
onRequestSignature: (personId: string) => void;
requestingId: string | null;
existingSignatures: Array<
SignaturesModal_policyVersions$data["policyVersions"]["edges"][0]["node"]["signatures"]["edges"][0]["node"]
SignaturesModal_documentVersions$data["documentVersions"]["edges"][0]["node"]["signatures"]["edges"][0]["node"]
>;
formatDateTime: (date?: string | null) => string;
}) {

View File

@@ -5,12 +5,12 @@ import { Button } from "@/components/ui/button";
import { useState } from "react";
import ReactMarkdown from "react-markdown";
import { graphql, useFragment } from "react-relay";
import type { VersionHistoryModal_policyVersions$key } from "./__generated__/VersionHistoryModal_policyVersions.graphql";
import type { VersionHistoryModal_documentVersions$key } from "./__generated__/VersionHistoryModal_documentVersions.graphql";
import remarkGfm from "remark-gfm";
import rehypeRaw from "rehype-raw";
export const policyVersionsFragment = graphql`
fragment VersionHistoryModal_policyVersions on Policy {
export const documentVersionsFragment = graphql`
fragment VersionHistoryModal_documentVersions on Document {
title
owner {
fullName
@@ -37,19 +37,19 @@ export const policyVersionsFragment = graphql`
interface VersionHistoryModalProps {
isOpen: boolean;
onClose: () => void;
policyRef: VersionHistoryModal_policyVersions$key;
documentRef: VersionHistoryModal_documentVersions$key;
onRestoreVersion?: (versionNumber: number) => void;
}
export function VersionHistoryModal({
isOpen,
onClose,
policyRef,
documentRef,
onRestoreVersion,
}: VersionHistoryModalProps) {
const data = useFragment<VersionHistoryModal_policyVersions$key>(
policyVersionsFragment,
policyRef,
const data = useFragment<VersionHistoryModal_documentVersions$key>(
documentVersionsFragment,
documentRef,
);
// Safely access and extract version nodes

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<885dc2a54ba3b8d4663e197cfe61d704>>
* @generated SignedSource<<095491df1cce828cc3ec9ba9f2ad4183>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,19 +9,19 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type CreatePolicyInput = {
export type CreateDocumentInput = {
content: string;
organizationId: string;
ownerId: string;
title: string;
};
export type PolicyListViewCreateMutation$variables = {
export type DocumentListViewCreateMutation$variables = {
connections: ReadonlyArray<string>;
input: CreatePolicyInput;
input: CreateDocumentInput;
};
export type PolicyListViewCreateMutation$data = {
readonly createPolicy: {
readonly policyEdge: {
export type DocumentListViewCreateMutation$data = {
readonly createDocument: {
readonly documentEdge: {
readonly node: {
readonly createdAt: string;
readonly description: string;
@@ -36,9 +36,9 @@ export type PolicyListViewCreateMutation$data = {
};
};
};
export type PolicyListViewCreateMutation = {
response: PolicyListViewCreateMutation$data;
variables: PolicyListViewCreateMutation$variables;
export type DocumentListViewCreateMutation = {
response: DocumentListViewCreateMutation$data;
variables: DocumentListViewCreateMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -69,15 +69,15 @@ v3 = {
v4 = {
"alias": null,
"args": null,
"concreteType": "PolicyEdge",
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "policyEdge",
"name": "documentEdge",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Policy",
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -144,14 +144,14 @@ return {
],
"kind": "Fragment",
"metadata": null,
"name": "PolicyListViewCreateMutation",
"name": "DocumentListViewCreateMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "CreatePolicyPayload",
"concreteType": "CreateDocumentPayload",
"kind": "LinkedField",
"name": "createPolicy",
"name": "createDocument",
"plural": false,
"selections": [
(v4/*: any*/)
@@ -169,14 +169,14 @@ return {
(v0/*: any*/)
],
"kind": "Operation",
"name": "PolicyListViewCreateMutation",
"name": "DocumentListViewCreateMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "CreatePolicyPayload",
"concreteType": "CreateDocumentPayload",
"kind": "LinkedField",
"name": "createPolicy",
"name": "createDocument",
"plural": false,
"selections": [
(v4/*: any*/),
@@ -187,7 +187,7 @@ return {
"handle": "prependEdge",
"key": "",
"kind": "LinkedHandle",
"name": "policyEdge",
"name": "documentEdge",
"handleArgs": [
{
"kind": "Variable",
@@ -202,16 +202,16 @@ return {
]
},
"params": {
"cacheID": "f7aae6d7a0d276e71caec643e43b5ee5",
"cacheID": "006fad3aafaae7d03f5d85cd78ea39fb",
"id": null,
"metadata": {},
"name": "PolicyListViewCreateMutation",
"name": "DocumentListViewCreateMutation",
"operationKind": "mutation",
"text": "mutation PolicyListViewCreateMutation(\n $input: CreatePolicyInput!\n) {\n createPolicy(input: $input) {\n policyEdge {\n node {\n id\n title\n description\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n }\n }\n }\n}\n"
"text": "mutation DocumentListViewCreateMutation(\n $input: CreateDocumentInput!\n) {\n createDocument(input: $input) {\n documentEdge {\n node {\n id\n title\n description\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "d55ac010a7ad352d830d3a38f2f8d5a8";
(node as any).hash = "0b6f4540b8bc9dc8168ba33ed6340311";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<c71120e2c59cabbcb2f9e55dacd2be6c>>
* @generated SignedSource<<f20fbf3a0fd45a8f408e5fd364c9dfee>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,21 +9,21 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DeletePolicyInput = {
policyId: string;
export type DeleteDocumentInput = {
documentId: string;
};
export type PolicyListViewDeleteMutation$variables = {
export type DocumentListViewDeleteMutation$variables = {
connections: ReadonlyArray<string>;
input: DeletePolicyInput;
input: DeleteDocumentInput;
};
export type PolicyListViewDeleteMutation$data = {
readonly deletePolicy: {
readonly deletedPolicyId: string;
export type DocumentListViewDeleteMutation$data = {
readonly deleteDocument: {
readonly deletedDocumentId: string;
};
};
export type PolicyListViewDeleteMutation = {
response: PolicyListViewDeleteMutation$data;
variables: PolicyListViewDeleteMutation$variables;
export type DocumentListViewDeleteMutation = {
response: DocumentListViewDeleteMutation$data;
variables: DocumentListViewDeleteMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -48,7 +48,7 @@ v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deletedPolicyId",
"name": "deletedDocumentId",
"storageKey": null
};
return {
@@ -59,14 +59,14 @@ return {
],
"kind": "Fragment",
"metadata": null,
"name": "PolicyListViewDeleteMutation",
"name": "DocumentListViewDeleteMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DeletePolicyPayload",
"concreteType": "DeleteDocumentPayload",
"kind": "LinkedField",
"name": "deletePolicy",
"name": "deleteDocument",
"plural": false,
"selections": [
(v3/*: any*/)
@@ -84,14 +84,14 @@ return {
(v0/*: any*/)
],
"kind": "Operation",
"name": "PolicyListViewDeleteMutation",
"name": "DocumentListViewDeleteMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DeletePolicyPayload",
"concreteType": "DeleteDocumentPayload",
"kind": "LinkedField",
"name": "deletePolicy",
"name": "deleteDocument",
"plural": false,
"selections": [
(v3/*: any*/),
@@ -102,7 +102,7 @@ return {
"handle": "deleteEdge",
"key": "",
"kind": "ScalarHandle",
"name": "deletedPolicyId",
"name": "deletedDocumentId",
"handleArgs": [
{
"kind": "Variable",
@@ -117,16 +117,16 @@ return {
]
},
"params": {
"cacheID": "3a182fce4a0616599bea274ddf7b95a1",
"cacheID": "61bee9d714b5ee08e1653d0ad426c6f5",
"id": null,
"metadata": {},
"name": "PolicyListViewDeleteMutation",
"name": "DocumentListViewDeleteMutation",
"operationKind": "mutation",
"text": "mutation PolicyListViewDeleteMutation(\n $input: DeletePolicyInput!\n) {\n deletePolicy(input: $input) {\n deletedPolicyId\n }\n}\n"
"text": "mutation DocumentListViewDeleteMutation(\n $input: DeleteDocumentInput!\n) {\n deleteDocument(input: $input) {\n deletedDocumentId\n }\n}\n"
}
};
})();
(node as any).hash = "d2a47c3563b6dcbbb88e78b954345768";
(node as any).hash = "f0da5a5c332d17752d23c2fbfcd0e503";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<fbe65b0fb14443a15a43bd3d4100118f>>
* @generated SignedSource<<4ae1fa075cd3c3fd2ae9d63e3ec0ae02>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,14 +10,14 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type PolicyStatus = "DRAFT" | "PUBLISHED";
export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED";
export type PolicyListViewQuery$variables = {
export type DocumentStatus = "DRAFT" | "PUBLISHED";
export type DocumentVersionSignatureState = "REQUESTED" | "SIGNED";
export type DocumentListViewQuery$variables = {
organizationId: string;
};
export type PolicyListViewQuery$data = {
export type DocumentListViewQuery$data = {
readonly organization: {
readonly policies?: {
readonly documents?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: string;
@@ -38,11 +38,11 @@ export type PolicyListViewQuery$data = {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly state: PolicyVersionSignatureState;
readonly state: DocumentVersionSignatureState;
};
}>;
};
readonly status: PolicyStatus;
readonly status: DocumentStatus;
readonly updatedAt: string;
};
}>;
@@ -58,9 +58,9 @@ export type PolicyListViewQuery$data = {
};
};
};
export type PolicyListViewQuery = {
response: PolicyListViewQuery$data;
variables: PolicyListViewQuery$variables;
export type DocumentListViewQuery = {
response: DocumentListViewQuery$data;
variables: DocumentListViewQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -167,7 +167,7 @@ v11 = [
{
"alias": null,
"args": null,
"concreteType": "PolicyEdge",
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -175,7 +175,7 @@ v11 = [
{
"alias": null,
"args": null,
"concreteType": "Policy",
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -232,7 +232,7 @@ v11 = [
"value": 1
}
],
"concreteType": "PolicyVersionConnection",
"concreteType": "DocumentVersionConnection",
"kind": "LinkedField",
"name": "versions",
"plural": false,
@@ -240,7 +240,7 @@ v11 = [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionEdge",
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -248,7 +248,7 @@ v11 = [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -267,7 +267,7 @@ v11 = [
"args": [
(v7/*: any*/)
],
"concreteType": "PolicyVersionSignatureConnection",
"concreteType": "DocumentVersionSignatureConnection",
"kind": "LinkedField",
"name": "signatures",
"plural": false,
@@ -275,7 +275,7 @@ v11 = [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignatureEdge",
"concreteType": "DocumentVersionSignatureEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -283,7 +283,7 @@ v11 = [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignature",
"concreteType": "DocumentVersionSignature",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -351,7 +351,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "PolicyListViewQuery",
"name": "DocumentListViewQuery",
"selections": [
{
"alias": null,
@@ -382,16 +382,16 @@ return {
"name": "PeopleSelector_organization"
},
{
"alias": "policies",
"alias": "documents",
"args": [
(v4/*: any*/)
],
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "__PolicyListView_policies_connection",
"name": "__DocumentListView_documents_connection",
"plural": false,
"selections": (v11/*: any*/),
"storageKey": "__PolicyListView_policies_connection(orderBy:{\"direction\":\"ASC\",\"field\":\"TITLE\"})"
"storageKey": "__DocumentListView_documents_connection(orderBy:{\"direction\":\"ASC\",\"field\":\"TITLE\"})"
}
],
"type": "Organization",
@@ -408,7 +408,7 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "PolicyListViewQuery",
"name": "DocumentListViewQuery",
"selections": [
{
"alias": null,
@@ -493,21 +493,21 @@ return {
{
"alias": null,
"args": (v14/*: any*/),
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "policies",
"name": "documents",
"plural": false,
"selections": (v11/*: any*/),
"storageKey": "policies(first:50,orderBy:{\"direction\":\"ASC\",\"field\":\"TITLE\"})"
"storageKey": "documents(first:50,orderBy:{\"direction\":\"ASC\",\"field\":\"TITLE\"})"
},
{
"alias": null,
"args": (v14/*: any*/),
"filters": (v13/*: any*/),
"handle": "connection",
"key": "PolicyListView_policies",
"key": "DocumentListView_documents",
"kind": "LinkedHandle",
"name": "policies"
"name": "documents"
}
],
"type": "Organization",
@@ -519,7 +519,7 @@ return {
]
},
"params": {
"cacheID": "1a9f6afc7b288a1051294afe154f14c4",
"cacheID": "6b91a4a77bedb9f66abeaeec8c1c5535",
"id": null,
"metadata": {
"connection": [
@@ -529,18 +529,18 @@ return {
"direction": "forward",
"path": [
"organization",
"policies"
"documents"
]
}
]
},
"name": "PolicyListViewQuery",
"name": "DocumentListViewQuery",
"operationKind": "query",
"text": "query PolicyListViewQuery(\n $organizationId: ID!\n) {\n viewer {\n user {\n id\n }\n id\n }\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...PeopleSelector_organization\n policies(first: 50, orderBy: {field: TITLE, direction: ASC}) {\n edges {\n node {\n id\n title\n description\n currentPublishedVersion\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n versions(first: 1) {\n edges {\n node {\n id\n status\n updatedAt\n signatures(first: 100) {\n edges {\n node {\n id\n state\n }\n }\n }\n }\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
"text": "query DocumentListViewQuery(\n $organizationId: ID!\n) {\n viewer {\n user {\n id\n }\n id\n }\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n ...PeopleSelector_organization\n documents(first: 50, orderBy: {field: TITLE, direction: ASC}) {\n edges {\n node {\n id\n title\n description\n currentPublishedVersion\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n versions(first: 1) {\n edges {\n node {\n id\n status\n updatedAt\n signatures(first: 100) {\n edges {\n node {\n id\n state\n }\n }\n }\n }\n }\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
}
};
})();
(node as any).hash = "0aa2374fc681f6d130fbf03586707d5a";
(node as any).hash = "df33668bcdfe69a122a8846bb1d66df1";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<ec7d0ef29b8366117ddf75e75669f5fa>>
* @generated SignedSource<<25fe683751dd38b0c417c7df9a7f773f>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -12,17 +12,17 @@ import { ConcreteRequest } from 'relay-runtime';
export type SendSigningNotificationsInput = {
organizationId: string;
};
export type PolicyListViewSendSigningNotificationsMutation$variables = {
export type DocumentListViewSendSigningNotificationsMutation$variables = {
input: SendSigningNotificationsInput;
};
export type PolicyListViewSendSigningNotificationsMutation$data = {
export type DocumentListViewSendSigningNotificationsMutation$data = {
readonly sendSigningNotifications: {
readonly success: boolean;
};
};
export type PolicyListViewSendSigningNotificationsMutation = {
response: PolicyListViewSendSigningNotificationsMutation$data;
variables: PolicyListViewSendSigningNotificationsMutation$variables;
export type DocumentListViewSendSigningNotificationsMutation = {
response: DocumentListViewSendSigningNotificationsMutation$data;
variables: DocumentListViewSendSigningNotificationsMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -64,7 +64,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "PolicyListViewSendSigningNotificationsMutation",
"name": "DocumentListViewSendSigningNotificationsMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
@@ -73,20 +73,20 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "PolicyListViewSendSigningNotificationsMutation",
"name": "DocumentListViewSendSigningNotificationsMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "a6b25b9e4abf4243131b90b47f4e2ef4",
"cacheID": "0eb5a217a3b01f80c0ec446df15b0c40",
"id": null,
"metadata": {},
"name": "PolicyListViewSendSigningNotificationsMutation",
"name": "DocumentListViewSendSigningNotificationsMutation",
"operationKind": "mutation",
"text": "mutation PolicyListViewSendSigningNotificationsMutation(\n $input: SendSigningNotificationsInput!\n) {\n sendSigningNotifications(input: $input) {\n success\n }\n}\n"
"text": "mutation DocumentListViewSendSigningNotificationsMutation(\n $input: SendSigningNotificationsInput!\n) {\n sendSigningNotifications(input: $input) {\n success\n }\n}\n"
}
};
})();
(node as any).hash = "71b0a1e7d209ed71a9bb6552eaf95cee";
(node as any).hash = "8a959080f5aa7cc752ce039bd7383dfa";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<d8d76cb73e37916ddc34017550ff3702>>
* @generated SignedSource<<544173fd0ab2731cb9d3a976212ceca5>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,24 +9,24 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type UpdatePolicyVersionInput = {
export type UpdateDocumentVersionInput = {
content: string;
policyVersionId: string;
documentVersionId: string;
};
export type EditPolicyViewMutation$variables = {
input: UpdatePolicyVersionInput;
export type EditDocumentViewMutation$variables = {
input: UpdateDocumentVersionInput;
};
export type EditPolicyViewMutation$data = {
readonly updatePolicyVersion: {
readonly policyVersion: {
export type EditDocumentViewMutation$data = {
readonly updateDocumentVersion: {
readonly documentVersion: {
readonly content: string;
readonly id: string;
};
};
};
export type EditPolicyViewMutation = {
response: EditPolicyViewMutation$data;
variables: EditPolicyViewMutation$variables;
export type EditDocumentViewMutation = {
response: EditDocumentViewMutation$data;
variables: EditDocumentViewMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -47,17 +47,17 @@ v1 = [
"variableName": "input"
}
],
"concreteType": "UpdatePolicyVersionPayload",
"concreteType": "UpdateDocumentVersionPayload",
"kind": "LinkedField",
"name": "updatePolicyVersion",
"name": "updateDocumentVersion",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "policyVersion",
"name": "documentVersion",
"plural": false,
"selections": [
{
@@ -86,7 +86,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "EditPolicyViewMutation",
"name": "EditDocumentViewMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
@@ -95,20 +95,20 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "EditPolicyViewMutation",
"name": "EditDocumentViewMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "02b56043d606c6237dd502a7695fea50",
"cacheID": "92e3e1e6d3bf1a2066b2e71c437c3b4e",
"id": null,
"metadata": {},
"name": "EditPolicyViewMutation",
"name": "EditDocumentViewMutation",
"operationKind": "mutation",
"text": "mutation EditPolicyViewMutation(\n $input: UpdatePolicyVersionInput!\n) {\n updatePolicyVersion(input: $input) {\n policyVersion {\n id\n content\n }\n }\n}\n"
"text": "mutation EditDocumentViewMutation(\n $input: UpdateDocumentVersionInput!\n) {\n updateDocumentVersion(input: $input) {\n documentVersion {\n id\n content\n }\n }\n}\n"
}
};
})();
(node as any).hash = "556fbcc4fadc0011c1a2154dcffeb389";
(node as any).hash = "14fc2fdfcdb2ccb827e237d5fc1f0a6f";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<7738a95cc83ee25c08f6ddc556f144c1>>
* @generated SignedSource<<d1a5426a3bb5920a1d2f94e4f689c93f>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,16 +10,13 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type EditPolicyViewQuery$variables = {
export type EditDocumentViewQuery$variables = {
documentId: string;
documentVersionId: string;
organizationId: string;
policyId: string;
policyVersionId: string;
};
export type EditPolicyViewQuery$data = {
readonly organization: {
readonly " $fragmentSpreads": FragmentRefs<"PeopleSelector_organization">;
};
readonly policy: {
export type EditDocumentViewQuery$data = {
readonly document: {
readonly id: string;
readonly owner?: {
readonly fullName: string;
@@ -27,37 +24,40 @@ export type EditPolicyViewQuery$data = {
};
readonly title?: string;
};
readonly policyVersion: {
readonly documentVersion: {
readonly content?: string;
readonly id: string;
};
readonly organization: {
readonly " $fragmentSpreads": FragmentRefs<"PeopleSelector_organization">;
};
};
export type EditPolicyViewQuery = {
response: EditPolicyViewQuery$data;
variables: EditPolicyViewQuery$variables;
export type EditDocumentViewQuery = {
response: EditDocumentViewQuery$data;
variables: EditDocumentViewQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
"name": "documentId"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "policyId"
"name": "documentVersionId"
},
v2 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "policyVersionId"
"name": "organizationId"
},
v3 = [
{
"kind": "Variable",
"name": "id",
"variableName": "policyVersionId"
"variableName": "documentVersionId"
}
],
v4 = {
@@ -78,14 +78,14 @@ v5 = {
"storageKey": null
}
],
"type": "PolicyVersion",
"type": "DocumentVersion",
"abstractKey": null
},
v6 = [
{
"kind": "Variable",
"name": "id",
"variableName": "policyId"
"variableName": "documentId"
}
],
v7 = {
@@ -119,7 +119,7 @@ v8 = {
"storageKey": null
}
],
"type": "Policy",
"type": "Document",
"abstractKey": null
},
v9 = [
@@ -160,10 +160,10 @@ return {
],
"kind": "Fragment",
"metadata": null,
"name": "EditPolicyViewQuery",
"name": "EditDocumentViewQuery",
"selections": [
{
"alias": "policyVersion",
"alias": "documentVersion",
"args": (v3/*: any*/),
"concreteType": null,
"kind": "LinkedField",
@@ -176,7 +176,7 @@ return {
"storageKey": null
},
{
"alias": "policy",
"alias": "document",
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
@@ -211,15 +211,15 @@ return {
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v1/*: any*/),
(v0/*: any*/),
(v2/*: any*/)
(v2/*: any*/),
(v1/*: any*/)
],
"kind": "Operation",
"name": "EditPolicyViewQuery",
"name": "EditDocumentViewQuery",
"selections": [
{
"alias": "policyVersion",
"alias": "documentVersion",
"args": (v3/*: any*/),
"concreteType": null,
"kind": "LinkedField",
@@ -233,7 +233,7 @@ return {
"storageKey": null
},
{
"alias": "policy",
"alias": "document",
"args": (v6/*: any*/),
"concreteType": null,
"kind": "LinkedField",
@@ -355,16 +355,16 @@ return {
]
},
"params": {
"cacheID": "4d586701fc5f2e4976bb87d9be61c594",
"cacheID": "44dcce3514fd8798e8b7bb0c23f9f982",
"id": null,
"metadata": {},
"name": "EditPolicyViewQuery",
"name": "EditDocumentViewQuery",
"operationKind": "query",
"text": "query EditPolicyViewQuery(\n $policyId: ID!\n $organizationId: ID!\n $policyVersionId: ID!\n) {\n policyVersion: node(id: $policyVersionId) {\n __typename\n id\n ... on PolicyVersion {\n content\n }\n }\n policy: node(id: $policyId) {\n __typename\n id\n ... on Policy {\n title\n owner {\n id\n fullName\n }\n }\n }\n organization: node(id: $organizationId) {\n __typename\n ...PeopleSelector_organization\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
"text": "query EditDocumentViewQuery(\n $documentId: ID!\n $organizationId: ID!\n $documentVersionId: ID!\n) {\n documentVersion: node(id: $documentVersionId) {\n __typename\n id\n ... on DocumentVersion {\n content\n }\n }\n document: node(id: $documentId) {\n __typename\n id\n ... on Document {\n title\n owner {\n id\n fullName\n }\n }\n }\n organization: node(id: $organizationId) {\n __typename\n ...PeopleSelector_organization\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
}
};
})();
(node as any).hash = "2a934195ed33bd073e3976e8cc19a925";
(node as any).hash = "90a8a811c0c8a08a1112a72537cbd76d";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<290d3c4fb382c7b99c60eeee5cfa8c5a>>
* @generated SignedSource<<70539298ec9a6ffd64b14fa98fdd283e>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,27 +9,27 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type PolicyStatus = "DRAFT" | "PUBLISHED";
export type CreateDraftPolicyVersionInput = {
policyID: string;
export type DocumentStatus = "DRAFT" | "PUBLISHED";
export type CreateDraftDocumentVersionInput = {
documentID: string;
};
export type ShowPolicyViewCreateDraftMutation$variables = {
input: CreateDraftPolicyVersionInput;
export type ShowDocumentViewCreateDraftMutation$variables = {
input: CreateDraftDocumentVersionInput;
};
export type ShowPolicyViewCreateDraftMutation$data = {
readonly createDraftPolicyVersion: {
readonly policyVersionEdge: {
export type ShowDocumentViewCreateDraftMutation$data = {
readonly createDraftDocumentVersion: {
readonly documentVersionEdge: {
readonly node: {
readonly id: string;
readonly status: PolicyStatus;
readonly status: DocumentStatus;
readonly version: number;
};
};
};
};
export type ShowPolicyViewCreateDraftMutation = {
response: ShowPolicyViewCreateDraftMutation$data;
variables: ShowPolicyViewCreateDraftMutation$variables;
export type ShowDocumentViewCreateDraftMutation = {
response: ShowDocumentViewCreateDraftMutation$data;
variables: ShowDocumentViewCreateDraftMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -50,23 +50,23 @@ v1 = [
"variableName": "input"
}
],
"concreteType": "CreateDraftPolicyVersionPayload",
"concreteType": "CreateDraftDocumentVersionPayload",
"kind": "LinkedField",
"name": "createDraftPolicyVersion",
"name": "createDraftDocumentVersion",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionEdge",
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "policyVersionEdge",
"name": "documentVersionEdge",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -107,7 +107,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ShowPolicyViewCreateDraftMutation",
"name": "ShowDocumentViewCreateDraftMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
@@ -116,20 +116,20 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ShowPolicyViewCreateDraftMutation",
"name": "ShowDocumentViewCreateDraftMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "e96d226e93260cd989dc122193fbcbce",
"cacheID": "6ca94698731c59c1d5881a1dd3092277",
"id": null,
"metadata": {},
"name": "ShowPolicyViewCreateDraftMutation",
"name": "ShowDocumentViewCreateDraftMutation",
"operationKind": "mutation",
"text": "mutation ShowPolicyViewCreateDraftMutation(\n $input: CreateDraftPolicyVersionInput!\n) {\n createDraftPolicyVersion(input: $input) {\n policyVersionEdge {\n node {\n id\n version\n status\n }\n }\n }\n}\n"
"text": "mutation ShowDocumentViewCreateDraftMutation(\n $input: CreateDraftDocumentVersionInput!\n) {\n createDraftDocumentVersion(input: $input) {\n documentVersionEdge {\n node {\n id\n version\n status\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "49282edca41fc2bdca1a1c6db4b2dc11";
(node as any).hash = "70edae5e8a303869b1686bb02fe4b22e";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<024ec8d58aa5f37adad3ac5e98c15a90>>
* @generated SignedSource<<91076d34daad785f7fce9f5a2cbc4018>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,32 +9,32 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type PolicyStatus = "DRAFT" | "PUBLISHED";
export type PublishPolicyVersionInput = {
policyId: string;
export type DocumentStatus = "DRAFT" | "PUBLISHED";
export type PublishDocumentVersionInput = {
documentId: string;
};
export type ShowPolicyViewPublishMutation$variables = {
input: PublishPolicyVersionInput;
export type ShowDocumentViewPublishMutation$variables = {
input: PublishDocumentVersionInput;
};
export type ShowPolicyViewPublishMutation$data = {
readonly publishPolicyVersion: {
readonly policy: {
export type ShowDocumentViewPublishMutation$data = {
readonly publishDocumentVersion: {
readonly document: {
readonly currentPublishedVersion: number | null | undefined;
readonly id: string;
};
readonly policyVersion: {
readonly documentVersion: {
readonly id: string;
readonly publishedAt: string | null | undefined;
readonly publishedBy: {
readonly fullName: string;
} | null | undefined;
readonly status: PolicyStatus;
readonly status: DocumentStatus;
};
};
};
export type ShowPolicyViewPublishMutation = {
response: ShowPolicyViewPublishMutation$data;
variables: ShowPolicyViewPublishMutation$variables;
export type ShowDocumentViewPublishMutation = {
response: ShowDocumentViewPublishMutation$data;
variables: ShowDocumentViewPublishMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -62,9 +62,9 @@ v2 = {
v3 = {
"alias": null,
"args": null,
"concreteType": "Policy",
"concreteType": "Document",
"kind": "LinkedField",
"name": "policy",
"name": "document",
"plural": false,
"selections": [
(v2/*: any*/),
@@ -104,23 +104,23 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ShowPolicyViewPublishMutation",
"name": "ShowDocumentViewPublishMutation",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": "PublishPolicyVersionPayload",
"concreteType": "PublishDocumentVersionPayload",
"kind": "LinkedField",
"name": "publishPolicyVersion",
"name": "publishDocumentVersion",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "policyVersion",
"name": "documentVersion",
"plural": false,
"selections": [
(v2/*: any*/),
@@ -152,23 +152,23 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ShowPolicyViewPublishMutation",
"name": "ShowDocumentViewPublishMutation",
"selections": [
{
"alias": null,
"args": (v1/*: any*/),
"concreteType": "PublishPolicyVersionPayload",
"concreteType": "PublishDocumentVersionPayload",
"kind": "LinkedField",
"name": "publishPolicyVersion",
"name": "publishDocumentVersion",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "policyVersion",
"name": "documentVersion",
"plural": false,
"selections": [
(v2/*: any*/),
@@ -196,16 +196,16 @@ return {
]
},
"params": {
"cacheID": "2047a011abeae6642230cb7b31080b08",
"cacheID": "794539aab3ddce5d004e72d10b980ca4",
"id": null,
"metadata": {},
"name": "ShowPolicyViewPublishMutation",
"name": "ShowDocumentViewPublishMutation",
"operationKind": "mutation",
"text": "mutation ShowPolicyViewPublishMutation(\n $input: PublishPolicyVersionInput!\n) {\n publishPolicyVersion(input: $input) {\n policy {\n id\n currentPublishedVersion\n }\n policyVersion {\n id\n status\n publishedAt\n publishedBy {\n fullName\n id\n }\n }\n }\n}\n"
"text": "mutation ShowDocumentViewPublishMutation(\n $input: PublishDocumentVersionInput!\n) {\n publishDocumentVersion(input: $input) {\n document {\n id\n currentPublishedVersion\n }\n documentVersion {\n id\n status\n publishedAt\n publishedBy {\n fullName\n id\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "d81485a797858cf5f2834cf131d248cc";
(node as any).hash = "66e590251b58966c2ac09625759332f7";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<09afc0438feb0aa6a5a8a95f93d70951>>
* @generated SignedSource<<f7c8f2df8a102d1bd15cb053d146a8b1>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -10,12 +10,12 @@
import { ConcreteRequest } from 'relay-runtime';
import { FragmentRefs } from "relay-runtime";
export type PolicyStatus = "DRAFT" | "PUBLISHED";
export type ShowPolicyViewQuery$variables = {
export type DocumentStatus = "DRAFT" | "PUBLISHED";
export type ShowDocumentViewQuery$variables = {
documentId: string;
organizationId: string;
policyId: string;
};
export type ShowPolicyViewQuery$data = {
export type ShowDocumentViewQuery$data = {
readonly node: {
readonly createdAt?: string;
readonly currentPublishedVersion?: number | null | undefined;
@@ -32,7 +32,7 @@ export type ShowPolicyViewQuery$data = {
readonly publishedBy: {
readonly fullName: string;
} | null | undefined;
readonly status: PolicyStatus;
readonly status: DocumentStatus;
readonly updatedAt: string;
readonly version: number;
};
@@ -45,36 +45,38 @@ export type ShowPolicyViewQuery$data = {
};
readonly title?: string;
readonly updatedAt?: string;
readonly " $fragmentSpreads": FragmentRefs<"SignaturesModal_policyVersions" | "VersionHistoryModal_policyVersions">;
readonly " $fragmentSpreads": FragmentRefs<"SignaturesModal_documentVersions" | "VersionHistoryModal_documentVersions">;
};
readonly organization: {
readonly name?: string;
};
};
export type ShowPolicyViewQuery = {
response: ShowPolicyViewQuery$data;
variables: ShowPolicyViewQuery$variables;
export type ShowDocumentViewQuery = {
response: ShowDocumentViewQuery$data;
variables: ShowDocumentViewQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "policyId"
},
v2 = [
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "documentId"
},
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v3 = {
v2 = {
"kind": "InlineFragment",
"selections": [
{
@@ -88,63 +90,63 @@ v3 = {
"type": "Organization",
"abstractKey": null
},
v4 = [
v3 = [
{
"kind": "Variable",
"name": "id",
"variableName": "policyId"
"variableName": "documentId"
}
],
v5 = {
v4 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v6 = {
v5 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
v7 = {
v6 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
v8 = {
v7 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
v9 = {
v8 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
v10 = {
v9 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "currentPublishedVersion",
"storageKey": null
},
v11 = {
v10 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
},
v12 = {
v11 = {
"alias": null,
"args": null,
"concreteType": "People",
@@ -152,8 +154,8 @@ v12 = {
"name": "owner",
"plural": false,
"selections": [
(v5/*: any*/),
(v11/*: any*/),
(v4/*: any*/),
(v10/*: any*/),
{
"alias": null,
"args": null,
@@ -164,70 +166,70 @@ v12 = {
],
"storageKey": null
},
v13 = [
v12 = [
{
"kind": "Literal",
"name": "first",
"value": 1
}
],
v14 = {
v13 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "version",
"storageKey": null
},
v15 = {
v14 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "status",
"storageKey": null
},
v16 = {
v15 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "content",
"storageKey": null
},
v17 = {
v16 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "changelog",
"storageKey": null
},
v18 = {
v17 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "publishedAt",
"storageKey": null
},
v19 = {
v18 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v20 = [
(v11/*: any*/),
(v5/*: any*/)
v19 = [
(v10/*: any*/),
(v4/*: any*/)
],
v21 = {
v20 = {
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "publishedBy",
"plural": false,
"selections": (v20/*: any*/),
"selections": (v19/*: any*/),
"storageKey": null
},
v22 = [
v21 = [
{
"kind": "Literal",
"name": "first",
@@ -236,58 +238,55 @@ v22 = [
];
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/)
],
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ShowPolicyViewQuery",
"name": "ShowDocumentViewQuery",
"selections": [
{
"alias": "organization",
"args": (v2/*: any*/),
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/)
(v2/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v4/*: any*/),
"args": (v3/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v5/*: any*/),
(v4/*: any*/),
{
"kind": "InlineFragment",
"selections": [
(v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v12/*: any*/),
(v11/*: any*/),
{
"args": null,
"kind": "FragmentSpread",
"name": "SignaturesModal_policyVersions"
"name": "SignaturesModal_documentVersions"
},
{
"args": null,
"kind": "FragmentSpread",
"name": "VersionHistoryModal_policyVersions"
"name": "VersionHistoryModal_documentVersions"
},
{
"alias": "latestVersion",
"args": (v13/*: any*/),
"concreteType": "PolicyVersionConnection",
"args": (v12/*: any*/),
"concreteType": "DocumentVersionConnection",
"kind": "LinkedField",
"name": "versions",
"plural": false,
@@ -295,7 +294,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionEdge",
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -303,17 +302,17 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v5/*: any*/),
(v4/*: any*/),
(v13/*: any*/),
(v14/*: any*/),
(v15/*: any*/),
(v16/*: any*/),
(v17/*: any*/),
(v18/*: any*/),
{
"alias": null,
"args": null,
@@ -322,12 +321,12 @@ return {
"name": "publishedBy",
"plural": false,
"selections": [
(v11/*: any*/)
(v10/*: any*/)
],
"storageKey": null
},
(v8/*: any*/),
(v9/*: any*/)
(v7/*: any*/),
(v8/*: any*/)
],
"storageKey": null
}
@@ -338,7 +337,7 @@ return {
"storageKey": "versions(first:1)"
}
],
"type": "Policy",
"type": "Document",
"abstractKey": null
}
],
@@ -350,48 +349,45 @@ return {
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v1/*: any*/),
(v0/*: any*/)
],
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ShowPolicyViewQuery",
"name": "ShowDocumentViewQuery",
"selections": [
{
"alias": "organization",
"args": (v2/*: any*/),
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v19/*: any*/),
(v3/*: any*/),
(v5/*: any*/)
(v18/*: any*/),
(v2/*: any*/),
(v4/*: any*/)
],
"storageKey": null
},
{
"alias": null,
"args": (v4/*: any*/),
"args": (v3/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v19/*: any*/),
(v5/*: any*/),
(v18/*: any*/),
(v4/*: any*/),
{
"kind": "InlineFragment",
"selections": [
(v5/*: any*/),
(v6/*: any*/),
(v7/*: any*/),
(v8/*: any*/),
(v9/*: any*/),
(v10/*: any*/),
(v12/*: any*/),
(v11/*: any*/),
{
"alias": "policyVersions",
"alias": "documentVersions",
"args": [
{
"kind": "Literal",
@@ -399,7 +395,7 @@ return {
"value": 10
}
],
"concreteType": "PolicyVersionConnection",
"concreteType": "DocumentVersionConnection",
"kind": "LinkedField",
"name": "versions",
"plural": false,
@@ -407,7 +403,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionEdge",
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -415,21 +411,21 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v5/*: any*/),
(v4/*: any*/),
(v13/*: any*/),
(v14/*: any*/),
(v15/*: any*/),
(v18/*: any*/),
(v9/*: any*/),
(v21/*: any*/),
(v17/*: any*/),
(v8/*: any*/),
(v20/*: any*/),
{
"alias": null,
"args": (v22/*: any*/),
"concreteType": "PolicyVersionSignatureConnection",
"args": (v21/*: any*/),
"concreteType": "DocumentVersionSignatureConnection",
"kind": "LinkedField",
"name": "signatures",
"plural": false,
@@ -437,7 +433,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignatureEdge",
"concreteType": "DocumentVersionSignatureEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -445,12 +441,12 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignature",
"concreteType": "DocumentVersionSignature",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v5/*: any*/),
(v4/*: any*/),
{
"alias": null,
"args": null,
@@ -479,7 +475,7 @@ return {
"kind": "LinkedField",
"name": "signedBy",
"plural": false,
"selections": (v20/*: any*/),
"selections": (v19/*: any*/),
"storageKey": null
},
{
@@ -489,10 +485,10 @@ return {
"kind": "LinkedField",
"name": "requestedBy",
"plural": false,
"selections": (v20/*: any*/),
"selections": (v19/*: any*/),
"storageKey": null
},
(v19/*: any*/)
(v18/*: any*/)
],
"storageKey": null
},
@@ -536,10 +532,10 @@ return {
},
{
"alias": null,
"args": (v22/*: any*/),
"args": (v21/*: any*/),
"filters": null,
"handle": "connection",
"key": "SignaturesModal_policyVersions_signatures",
"key": "SignaturesModal_documentVersions_signatures",
"kind": "LinkedHandle",
"name": "signatures"
}
@@ -561,7 +557,7 @@ return {
"value": 20
}
],
"concreteType": "PolicyVersionConnection",
"concreteType": "DocumentVersionConnection",
"kind": "LinkedField",
"name": "versions",
"plural": false,
@@ -569,7 +565,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionEdge",
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -577,19 +573,19 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v5/*: any*/),
(v4/*: any*/),
(v13/*: any*/),
(v14/*: any*/),
(v15/*: any*/),
(v16/*: any*/),
(v17/*: any*/),
(v18/*: any*/),
(v9/*: any*/),
(v21/*: any*/)
(v8/*: any*/),
(v20/*: any*/)
],
"storageKey": null
}
@@ -601,8 +597,8 @@ return {
},
{
"alias": "latestVersion",
"args": (v13/*: any*/),
"concreteType": "PolicyVersionConnection",
"args": (v12/*: any*/),
"concreteType": "DocumentVersionConnection",
"kind": "LinkedField",
"name": "versions",
"plural": false,
@@ -610,7 +606,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionEdge",
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -618,20 +614,20 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v5/*: any*/),
(v4/*: any*/),
(v13/*: any*/),
(v14/*: any*/),
(v15/*: any*/),
(v16/*: any*/),
(v17/*: any*/),
(v18/*: any*/),
(v21/*: any*/),
(v8/*: any*/),
(v9/*: any*/)
(v20/*: any*/),
(v7/*: any*/),
(v8/*: any*/)
],
"storageKey": null
}
@@ -642,7 +638,7 @@ return {
"storageKey": "versions(first:1)"
}
],
"type": "Policy",
"type": "Document",
"abstractKey": null
}
],
@@ -651,16 +647,16 @@ return {
]
},
"params": {
"cacheID": "643b6f01d617d7f7fa6995afe4960c3c",
"cacheID": "16dd0ba75fa5a1339b59fa3e6bb9a6be",
"id": null,
"metadata": {},
"name": "ShowPolicyViewQuery",
"name": "ShowDocumentViewQuery",
"operationKind": "query",
"text": "query ShowPolicyViewQuery(\n $policyId: ID!\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n name\n }\n id\n }\n node(id: $policyId) {\n __typename\n id\n ... on Policy {\n title\n description\n createdAt\n updatedAt\n currentPublishedVersion\n owner {\n id\n fullName\n primaryEmailAddress\n }\n ...SignaturesModal_policyVersions\n ...VersionHistoryModal_policyVersions\n latestVersion: versions(first: 1) {\n edges {\n node {\n id\n version\n status\n content\n changelog\n publishedAt\n publishedBy {\n fullName\n id\n }\n createdAt\n updatedAt\n }\n }\n }\n }\n }\n}\n\nfragment SignaturesModal_policyVersions on Policy {\n title\n policyVersions: versions(first: 10) {\n edges {\n node {\n id\n version\n status\n publishedAt\n updatedAt\n publishedBy {\n fullName\n id\n }\n signatures(first: 100) {\n edges {\n node {\n id\n state\n signedAt\n requestedAt\n signedBy {\n fullName\n id\n }\n requestedBy {\n fullName\n id\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n }\n}\n\nfragment VersionHistoryModal_policyVersions on Policy {\n title\n owner {\n fullName\n id\n }\n versionHistory: versions(first: 20) {\n edges {\n node {\n id\n version\n status\n content\n changelog\n publishedAt\n updatedAt\n publishedBy {\n fullName\n id\n }\n }\n }\n }\n}\n"
"text": "query ShowDocumentViewQuery(\n $documentId: ID!\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n name\n }\n id\n }\n node(id: $documentId) {\n __typename\n id\n ... on Document {\n title\n description\n createdAt\n updatedAt\n currentPublishedVersion\n owner {\n id\n fullName\n primaryEmailAddress\n }\n ...SignaturesModal_documentVersions\n ...VersionHistoryModal_documentVersions\n latestVersion: versions(first: 1) {\n edges {\n node {\n id\n version\n status\n content\n changelog\n publishedAt\n publishedBy {\n fullName\n id\n }\n createdAt\n updatedAt\n }\n }\n }\n }\n }\n}\n\nfragment SignaturesModal_documentVersions on Document {\n title\n documentVersions: versions(first: 10) {\n edges {\n node {\n id\n version\n status\n publishedAt\n updatedAt\n publishedBy {\n fullName\n id\n }\n signatures(first: 100) {\n edges {\n node {\n id\n state\n signedAt\n requestedAt\n signedBy {\n fullName\n id\n }\n requestedBy {\n fullName\n id\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n }\n}\n\nfragment VersionHistoryModal_documentVersions on Document {\n title\n owner {\n fullName\n id\n }\n versionHistory: versions(first: 20) {\n edges {\n node {\n id\n version\n status\n content\n changelog\n publishedAt\n updatedAt\n publishedBy {\n fullName\n id\n }\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "56b534c0a468ccee10939c7d6c731bfd";
(node as any).hash = "df52189b2fac349ac8588c518a4fce55";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<fda822cf46d8b9a49852a53edd8e363d>>
* @generated SignedSource<<b2f20948e0455b0ec2b79cc461e11242>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,9 +9,9 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED";
export type DocumentVersionSignatureState = "REQUESTED" | "SIGNED";
export type RequestSignatureInput = {
policyVersionId: string;
documentVersionId: string;
signatoryId: string;
};
export type SignaturesModalRequestSignatureMutation$variables = {
@@ -20,7 +20,7 @@ export type SignaturesModalRequestSignatureMutation$variables = {
};
export type SignaturesModalRequestSignatureMutation$data = {
readonly requestSignature: {
readonly policyVersionSignatureEdge: {
readonly documentVersionSignatureEdge: {
readonly node: {
readonly id: string;
readonly requestedAt: string;
@@ -32,7 +32,7 @@ export type SignaturesModalRequestSignatureMutation$data = {
readonly fullName: string;
readonly id: string;
};
readonly state: PolicyVersionSignatureState;
readonly state: DocumentVersionSignatureState;
};
};
};
@@ -130,15 +130,15 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignatureEdge",
"concreteType": "DocumentVersionSignatureEdge",
"kind": "LinkedField",
"name": "policyVersionSignatureEdge",
"name": "documentVersionSignatureEdge",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignature",
"concreteType": "DocumentVersionSignature",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -193,15 +193,15 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignatureEdge",
"concreteType": "DocumentVersionSignatureEdge",
"kind": "LinkedField",
"name": "policyVersionSignatureEdge",
"name": "documentVersionSignatureEdge",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignature",
"concreteType": "DocumentVersionSignature",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -234,7 +234,7 @@ return {
"handle": "prependEdge",
"key": "",
"kind": "LinkedHandle",
"name": "policyVersionSignatureEdge",
"name": "documentVersionSignatureEdge",
"handleArgs": [
{
"kind": "Variable",
@@ -249,16 +249,16 @@ return {
]
},
"params": {
"cacheID": "4c6a5b6ed95c76c157f8627409a4481b",
"cacheID": "e3606c0b910024de4f5223961365d7cc",
"id": null,
"metadata": {},
"name": "SignaturesModalRequestSignatureMutation",
"operationKind": "mutation",
"text": "mutation SignaturesModalRequestSignatureMutation(\n $input: RequestSignatureInput!\n) {\n requestSignature(input: $input) {\n policyVersionSignatureEdge {\n node {\n id\n state\n signedAt\n requestedAt\n signedBy {\n fullName\n id\n }\n requestedBy {\n fullName\n id\n }\n }\n }\n }\n}\n"
"text": "mutation SignaturesModalRequestSignatureMutation(\n $input: RequestSignatureInput!\n) {\n requestSignature(input: $input) {\n documentVersionSignatureEdge {\n node {\n id\n state\n signedAt\n requestedAt\n signedBy {\n fullName\n id\n }\n requestedBy {\n fullName\n id\n }\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "2b17fe4feae2614a6697c63a7334a1cf";
(node as any).hash = "9cb16becf1319afbef638f6461179984";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<ee81b03b50b0bc65932295b898b856d4>>
* @generated SignedSource<<58ee8eb503fb92a720f2033c229e6895>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,11 +9,11 @@
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type PolicyStatus = "DRAFT" | "PUBLISHED";
export type PolicyVersionSignatureState = "REQUESTED" | "SIGNED";
export type DocumentStatus = "DRAFT" | "PUBLISHED";
export type DocumentVersionSignatureState = "REQUESTED" | "SIGNED";
import { FragmentRefs } from "relay-runtime";
export type SignaturesModal_policyVersions$data = {
readonly policyVersions: {
export type SignaturesModal_documentVersions$data = {
readonly documentVersions: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
@@ -34,22 +34,22 @@ export type SignaturesModal_policyVersions$data = {
readonly fullName: string;
readonly id: string;
};
readonly state: PolicyVersionSignatureState;
readonly state: DocumentVersionSignatureState;
};
}>;
};
readonly status: PolicyStatus;
readonly status: DocumentStatus;
readonly updatedAt: string;
readonly version: number;
};
}>;
};
readonly title: string;
readonly " $fragmentType": "SignaturesModal_policyVersions";
readonly " $fragmentType": "SignaturesModal_documentVersions";
};
export type SignaturesModal_policyVersions$key = {
readonly " $data"?: SignaturesModal_policyVersions$data;
readonly " $fragmentSpreads": FragmentRefs<"SignaturesModal_policyVersions">;
export type SignaturesModal_documentVersions$key = {
readonly " $data"?: SignaturesModal_documentVersions$data;
readonly " $fragmentSpreads": FragmentRefs<"SignaturesModal_documentVersions">;
};
const node: ReaderFragment = (function(){
@@ -83,7 +83,7 @@ return {
}
]
},
"name": "SignaturesModal_policyVersions",
"name": "SignaturesModal_documentVersions",
"selections": [
{
"alias": null,
@@ -93,7 +93,7 @@ return {
"storageKey": null
},
{
"alias": "policyVersions",
"alias": "documentVersions",
"args": [
{
"kind": "Literal",
@@ -101,7 +101,7 @@ return {
"value": 10
}
],
"concreteType": "PolicyVersionConnection",
"concreteType": "DocumentVersionConnection",
"kind": "LinkedField",
"name": "versions",
"plural": false,
@@ -109,7 +109,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionEdge",
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -117,7 +117,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -164,15 +164,15 @@ return {
{
"alias": "signatures",
"args": null,
"concreteType": "PolicyVersionSignatureConnection",
"concreteType": "DocumentVersionSignatureConnection",
"kind": "LinkedField",
"name": "__SignaturesModal_policyVersions_signatures_connection",
"name": "__SignaturesModal_documentVersions_signatures_connection",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignatureEdge",
"concreteType": "DocumentVersionSignatureEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -180,7 +180,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionSignature",
"concreteType": "DocumentVersionSignature",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -288,11 +288,11 @@ return {
"storageKey": "versions(first:10)"
}
],
"type": "Policy",
"type": "Document",
"abstractKey": null
};
})();
(node as any).hash = "da9bf0fc12618afb0f9ec8f2337b9b9b";
(node as any).hash = "1e33c172b26b47a8fe21fdd66c9b4c26";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<21626cad90fcb579071d73bc47e3fb7a>>
* @generated SignedSource<<a88582302d627481e4214530f287e233>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,9 +9,9 @@
// @ts-nocheck
import { ReaderFragment } from 'relay-runtime';
export type PolicyStatus = "DRAFT" | "PUBLISHED";
export type DocumentStatus = "DRAFT" | "PUBLISHED";
import { FragmentRefs } from "relay-runtime";
export type VersionHistoryModal_policyVersions$data = {
export type VersionHistoryModal_documentVersions$data = {
readonly owner: {
readonly fullName: string;
};
@@ -26,17 +26,17 @@ export type VersionHistoryModal_policyVersions$data = {
readonly publishedBy: {
readonly fullName: string;
} | null | undefined;
readonly status: PolicyStatus;
readonly status: DocumentStatus;
readonly updatedAt: string;
readonly version: number;
};
}>;
};
readonly " $fragmentType": "VersionHistoryModal_policyVersions";
readonly " $fragmentType": "VersionHistoryModal_documentVersions";
};
export type VersionHistoryModal_policyVersions$key = {
readonly " $data"?: VersionHistoryModal_policyVersions$data;
readonly " $fragmentSpreads": FragmentRefs<"VersionHistoryModal_policyVersions">;
export type VersionHistoryModal_documentVersions$key = {
readonly " $data"?: VersionHistoryModal_documentVersions$data;
readonly " $fragmentSpreads": FragmentRefs<"VersionHistoryModal_documentVersions">;
};
const node: ReaderFragment = (function(){
@@ -53,7 +53,7 @@ return {
"argumentDefinitions": [],
"kind": "Fragment",
"metadata": null,
"name": "VersionHistoryModal_policyVersions",
"name": "VersionHistoryModal_documentVersions",
"selections": [
{
"alias": null,
@@ -81,7 +81,7 @@ return {
"value": 20
}
],
"concreteType": "PolicyVersionConnection",
"concreteType": "DocumentVersionConnection",
"kind": "LinkedField",
"name": "versions",
"plural": false,
@@ -89,7 +89,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersionEdge",
"concreteType": "DocumentVersionEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -97,7 +97,7 @@ return {
{
"alias": null,
"args": null,
"concreteType": "PolicyVersion",
"concreteType": "DocumentVersion",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -171,11 +171,11 @@ return {
"storageKey": "versions(first:20)"
}
],
"type": "Policy",
"type": "Document",
"abstractKey": null
};
})();
(node as any).hash = "09cd9142880cfbb239ce866ea81afe48";
(node as any).hash = "ffcba061a60a144c663de41a48e784d1";
export default node;

View File

@@ -35,13 +35,13 @@ import {
} from "./__generated__/ControlOrganizationMeasuresQuery.graphql";
import { ControlFragment_Control$key } from "./__generated__/ControlFragment_Control.graphql";
import {
ControlLinkedPoliciesQuery$data,
ControlLinkedPoliciesQuery,
} from "./__generated__/ControlLinkedPoliciesQuery.graphql";
ControlLinkedDocumentsQuery$data,
ControlLinkedDocumentsQuery,
} from "./__generated__/ControlLinkedDocumentsQuery.graphql";
import {
ControlOrganizationPoliciesQuery$data,
ControlOrganizationPoliciesQuery,
} from "./__generated__/ControlOrganizationPoliciesQuery.graphql";
ControlOrganizationDocumentsQuery$data,
ControlOrganizationDocumentsQuery,
} from "./__generated__/ControlOrganizationDocumentsQuery.graphql";
const controlFragment = graphql`
fragment ControlFragment_Control on Control {
@@ -96,13 +96,13 @@ const organizationMeasuresQuery = graphql`
}
`;
// Query to fetch linked policies
const linkedPoliciesQuery = graphql`
query ControlLinkedPoliciesQuery($controlId: ID!) {
// Query to fetch linked documents
const linkedDocumentsQuery = graphql`
query ControlLinkedDocumentsQuery($controlId: ID!) {
control: node(id: $controlId) {
id
... on Control {
policies(first: 100) @connection(key: "Control__policies") {
documents(first: 100) @connection(key: "Control__documents") {
edges {
node {
id
@@ -123,13 +123,13 @@ const linkedPoliciesQuery = graphql`
}
`;
// Query to fetch all policies for the organization
const organizationPoliciesQuery = graphql`
query ControlOrganizationPoliciesQuery($organizationId: ID!) {
// Query to fetch all documents for the organization
const organizationDocumentsQuery = graphql`
query ControlOrganizationDocumentsQuery($organizationId: ID!) {
organization: node(id: $organizationId) {
id
... on Organization {
policies(first: 100) @connection(key: "Organization__policies") {
documents(first: 100) @connection(key: "Organization__documents") {
edges {
node {
id
@@ -176,12 +176,12 @@ const deleteMeasureMappingMutation = graphql`
}
`;
// Mutation to create a mapping between a control and a policy
const createPolicyMappingMutation = graphql`
mutation ControlCreatePolicyMappingMutation(
$input: CreateControlPolicyMappingInput!
// Mutation to create a mapping between a control and a document
const createDocumentMappingMutation = graphql`
mutation ControlCreateDocumentMappingMutation(
$input: CreateControlDocumentMappingInput!
) {
createControlPolicyMapping(input: $input) {
createControlDocumentMapping(input: $input) {
controlEdge {
node {
id
@@ -191,13 +191,13 @@ const createPolicyMappingMutation = graphql`
}
`;
// Mutation to delete a mapping between a control and a policy
const deletePolicyMappingMutation = graphql`
mutation ControlDeletePolicyMappingMutation(
$input: DeleteControlPolicyMappingInput!
// Mutation to delete a mapping between a control and a document
const deleteDocumentMappingMutation = graphql`
mutation ControlDeleteDocumentMappingMutation(
$input: DeleteControlDocumentMappingInput!
) {
deleteControlPolicyMapping(input: $input) {
deletedPolicyId
deleteControlDocumentMapping(input: $input) {
deletedDocumentId
}
}
`;
@@ -228,17 +228,17 @@ export function Control({
const [isUnlinkingMeasure, setIsUnlinkingMeasure] = useState(false);
const [categoryFilter, setCategoryFilter] = useState<string | null>(null);
// Policy state
const [isPolicyMappingDialogOpen, setIsPolicyMappingDialogOpen] =
// Document state
const [isDocumentMappingDialogOpen, setIsDocumentMappingDialogOpen] =
useState(false);
const [linkedPoliciesData, setLinkedPoliciesData] =
useState<ControlLinkedPoliciesQuery$data | null>(null);
const [organizationPoliciesData, setOrganizationPoliciesData] =
useState<ControlOrganizationPoliciesQuery$data | null>(null);
const [policySearchQuery, setPolicySearchQuery] = useState("");
const [isLoadingPolicies, setIsLoadingPolicies] = useState(false);
const [isLinkingPolicy, setIsLinkingPolicy] = useState(false);
const [isUnlinkingPolicy, setIsUnlinkingPolicy] = useState(false);
const [linkedDocumentsData, setLinkedDocumentsData] =
useState<ControlLinkedDocumentsQuery$data | null>(null);
const [organizationDocumentsData, setOrganizationDocumentsData] =
useState<ControlOrganizationDocumentsQuery$data | null>(null);
const [documentSearchQuery, setDocumentSearchQuery] = useState("");
const [isLoadingDocuments, setIsLoadingDocuments] = useState(false);
const [isLinkingDocument, setIsLinkingDocument] = useState(false);
const [isUnlinkingDocument, setIsUnlinkingDocument] = useState(false);
// Create mutation hooks
const [commitCreateMeasureMapping] = useMutation(
@@ -247,8 +247,8 @@ export function Control({
const [commitDeleteMeasureMapping] = useMutation(
deleteMeasureMappingMutation
);
const [commitCreatePolicyMapping] = useMutation(createPolicyMappingMutation);
const [commitDeletePolicyMapping] = useMutation(deletePolicyMappingMutation);
const [commitCreateDocumentMapping] = useMutation(createDocumentMappingMutation);
const [commitDeleteDocumentMapping] = useMutation(deleteDocumentMappingMutation);
// Load initial linked measures data
useEffect(() => {
@@ -508,242 +508,242 @@ export function Control({
setIsMeasureMappingDialogOpen(true);
}, [loadMeasuresData]);
// Load initial linked policies data
// Load initial linked documents data
useEffect(() => {
if (control.id) {
setIsLoadingPolicies(true);
fetchQuery<ControlLinkedPoliciesQuery>(environment, linkedPoliciesQuery, {
setIsLoadingDocuments(true);
fetchQuery<ControlLinkedDocumentsQuery>(environment, linkedDocumentsQuery, {
controlId: control.id,
}).subscribe({
next: (data) => {
setLinkedPoliciesData(data);
setIsLoadingPolicies(false);
setLinkedDocumentsData(data);
setIsLoadingDocuments(false);
},
error: (error: Error) => {
console.error("Error loading initial policies:", error);
setIsLoadingPolicies(false);
console.error("Error loading initial documents:", error);
setIsLoadingDocuments(false);
},
});
}
}, [control.id, environment]);
// Load policies data
const loadPoliciesData = useCallback(() => {
// Load documents data
const loadDocumentsData = useCallback(() => {
if (!organizationId || !control.id) return;
setIsLoadingPolicies(true);
setIsLoadingDocuments(true);
// Fetch all policies for the organization
fetchQuery<ControlOrganizationPoliciesQuery>(
// Fetch all documents for the organization
fetchQuery<ControlOrganizationDocumentsQuery>(
environment,
organizationPoliciesQuery,
organizationDocumentsQuery,
{
organizationId,
}
).subscribe({
next: (data) => {
setOrganizationPoliciesData(data);
setOrganizationDocumentsData(data);
},
complete: () => {
// Fetch linked policies for this control
fetchQuery<ControlLinkedPoliciesQuery>(
// Fetch linked documents for this control
fetchQuery<ControlLinkedDocumentsQuery>(
environment,
linkedPoliciesQuery,
linkedDocumentsQuery,
{
controlId: control.id,
}
).subscribe({
next: (data) => {
setLinkedPoliciesData(data);
setIsLoadingPolicies(false);
setLinkedDocumentsData(data);
setIsLoadingDocuments(false);
},
error: (error: Error) => {
console.error("Error fetching linked policies:", error);
setIsLoadingPolicies(false);
console.error("Error fetching linked documents:", error);
setIsLoadingDocuments(false);
toast({
title: "Error",
description: "Failed to load linked policies.",
description: "Failed to load linked documents.",
variant: "destructive",
});
},
});
},
error: (error: Error) => {
console.error("Error fetching organization policies:", error);
setIsLoadingPolicies(false);
console.error("Error fetching organization documents:", error);
setIsLoadingDocuments(false);
toast({
title: "Error",
description: "Failed to load policies.",
description: "Failed to load documents.",
variant: "destructive",
});
},
});
}, [control.id, environment, organizationId, toast]);
// Policy helper functions
const getPolicies = useCallback(() => {
if (!organizationPoliciesData?.organization?.policies?.edges) return [];
return organizationPoliciesData.organization.policies.edges.map(
// Document helper functions
const getDocuments = useCallback(() => {
if (!organizationDocumentsData?.organization?.documents?.edges) return [];
return organizationDocumentsData.organization.documents.edges.map(
(edge) => edge.node
);
}, [organizationPoliciesData]);
}, [organizationDocumentsData]);
const getLinkedPolicies = useCallback(() => {
if (!linkedPoliciesData?.control?.policies?.edges) return [];
return linkedPoliciesData.control.policies.edges.map((edge) => edge.node);
}, [linkedPoliciesData]);
const getLinkedDocuments = useCallback(() => {
if (!linkedDocumentsData?.control?.documents?.edges) return [];
return linkedDocumentsData.control.documents.edges.map((edge) => edge.node);
}, [linkedDocumentsData]);
const isPolicyLinked = useCallback(
(policyId: string) => {
const linkedPolicies = getLinkedPolicies();
return linkedPolicies.some((policy) => policy.id === policyId);
const isDocumentLinked = useCallback(
(documentId: string) => {
const linkedDocuments = getLinkedDocuments();
return linkedDocuments.some((document) => document.id === documentId);
},
[getLinkedPolicies]
[getLinkedDocuments]
);
const filteredPolicies = useCallback(() => {
const policies = getPolicies();
if (!policySearchQuery) return policies;
const filteredDocuments = useCallback(() => {
const documents = getDocuments();
if (!documentSearchQuery) return documents;
return policies.filter((policy) => {
return documents.filter((document) => {
return (
!policySearchQuery ||
policy.title?.toLowerCase().includes(policySearchQuery.toLowerCase()) ||
(policy.description &&
policy.description
!documentSearchQuery ||
document.title?.toLowerCase().includes(documentSearchQuery.toLowerCase()) ||
(document.description &&
document.description
.toLowerCase()
.includes(policySearchQuery.toLowerCase()))
.includes(documentSearchQuery.toLowerCase()))
);
});
}, [getPolicies, policySearchQuery]);
}, [getDocuments, documentSearchQuery]);
// Policy link/unlink handlers
const handleLinkPolicy = useCallback(
(policyId: string) => {
// Document link/unlink handlers
const handleLinkDocument = useCallback(
(documentId: string) => {
if (!control.id) return;
setIsLinkingPolicy(true);
setIsLinkingDocument(true);
commitCreatePolicyMapping({
commitCreateDocumentMapping({
variables: {
input: {
controlId: control.id,
policyId: policyId,
documentId: documentId,
},
},
onCompleted: (_, errors) => {
setIsLinkingPolicy(false);
setIsLinkingDocument(false);
if (errors) {
console.error("Error linking policy:", errors);
console.error("Error linking document:", errors);
toast({
title: "Error",
description: "Failed to link policy. Please try again.",
description: "Failed to link document. Please try again.",
variant: "destructive",
});
return;
}
// Refresh linked policies data
fetchQuery<ControlLinkedPoliciesQuery>(
// Refresh linked documents data
fetchQuery<ControlLinkedDocumentsQuery>(
environment,
linkedPoliciesQuery,
linkedDocumentsQuery,
{
controlId: control.id,
}
).subscribe({
next: (data) => {
setLinkedPoliciesData(data);
setLinkedDocumentsData(data);
},
error: (error: Error) => {
console.error("Error refreshing linked policies:", error);
console.error("Error refreshing linked documents:", error);
},
});
toast({
title: "Success",
description: "Policy successfully linked to control.",
description: "Document successfully linked to control.",
});
},
onError: (error) => {
setIsLinkingPolicy(false);
console.error("Error linking policy:", error);
setIsLinkingDocument(false);
console.error("Error linking document:", error);
toast({
title: "Error",
description: "Failed to link policy. Please try again.",
description: "Failed to link document. Please try again.",
variant: "destructive",
});
},
});
},
[commitCreatePolicyMapping, control.id, environment, toast]
[commitCreateDocumentMapping, control.id, environment, toast]
);
const handleUnlinkPolicy = useCallback(
(policyId: string) => {
const handleUnlinkDocument = useCallback(
(documentId: string) => {
if (!control.id) return;
setIsUnlinkingPolicy(true);
setIsUnlinkingDocument(true);
commitDeletePolicyMapping({
commitDeleteDocumentMapping({
variables: {
input: {
controlId: control.id,
policyId: policyId,
documentId: documentId,
},
},
onCompleted: (_, errors) => {
setIsUnlinkingPolicy(false);
setIsUnlinkingDocument(false);
if (errors) {
console.error("Error unlinking policy:", errors);
console.error("Error unlinking document:", errors);
toast({
title: "Error",
description: "Failed to unlink policy. Please try again.",
description: "Failed to unlink document. Please try again.",
variant: "destructive",
});
return;
}
// Refresh linked policies data
fetchQuery<ControlLinkedPoliciesQuery>(
// Refresh linked documents data
fetchQuery<ControlLinkedDocumentsQuery>(
environment,
linkedPoliciesQuery,
linkedDocumentsQuery,
{
controlId: control.id,
}
).subscribe({
next: (data) => {
setLinkedPoliciesData(data);
setLinkedDocumentsData(data);
},
error: (error: Error) => {
console.error("Error refreshing linked policies:", error);
console.error("Error refreshing linked documents:", error);
},
});
toast({
title: "Success",
description: "Policy successfully unlinked from control.",
description: "Document successfully unlinked from control.",
});
},
onError: (error) => {
setIsUnlinkingPolicy(false);
console.error("Error unlinking policy:", error);
setIsUnlinkingDocument(false);
console.error("Error unlinking document:", error);
toast({
title: "Error",
description: "Failed to unlink policy. Please try again.",
description: "Failed to unlink document. Please try again.",
variant: "destructive",
});
},
});
},
[commitDeletePolicyMapping, control.id, environment, toast]
[commitDeleteDocumentMapping, control.id, environment, toast]
);
const handleOpenPolicyMappingDialog = useCallback(() => {
loadPoliciesData();
setIsPolicyMappingDialogOpen(true);
}, [loadPoliciesData]);
const handleOpenDocumentMappingDialog = useCallback(() => {
loadDocumentsData();
setIsDocumentMappingDialogOpen(true);
}, [loadDocumentsData]);
const formatState = (state: string | undefined): string => {
if (!state) return "Unknown";
@@ -1045,19 +1045,19 @@ export function Control({
</div>
</div>
{/* Policies Section */}
{/* Documents Section */}
<div className="mt-8">
{/* Policy Mapping Dialog */}
{/* Document Mapping Dialog */}
<Dialog
open={isPolicyMappingDialogOpen}
onOpenChange={setIsPolicyMappingDialogOpen}
open={isDocumentMappingDialogOpen}
onOpenChange={setIsDocumentMappingDialogOpen}
>
<DialogContent className="max-w-3xl max-h-[80vh] overflow-hidden flex flex-col">
<DialogHeader>
<DialogTitle>Link Policies to Control</DialogTitle>
<DialogTitle>Link Documents to Control</DialogTitle>
<DialogDescription>
Search and select policies to link to this control. This helps
track which policies address this control.
Search and select documents to link to this control. This helps
track which documents address this control.
</DialogDescription>
</DialogHeader>
@@ -1066,9 +1066,9 @@ export function Control({
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-tertiary" />
<Input
placeholder="Search policies by name or content..."
value={policySearchQuery}
onChange={(e) => setPolicySearchQuery(e.target.value)}
placeholder="Search documents by name or content..."
value={documentSearchQuery}
onChange={(e) => setDocumentSearchQuery(e.target.value)}
className="w-full pl-10"
/>
</div>
@@ -1076,16 +1076,16 @@ export function Control({
</div>
<div className="flex-1 overflow-hidden">
{isLoadingPolicies ? (
{isLoadingDocuments ? (
<div className="flex items-center justify-center h-full">
<Loader2 className="w-8 h-8 animate-spin text-info" />
<span className="ml-2">Loading policies...</span>
<span className="ml-2">Loading documents...</span>
</div>
) : (
<div className="max-h-[50vh] overflow-y-auto pr-2">
{filteredPolicies().length === 0 ? (
{filteredDocuments().length === 0 ? (
<div className="text-center py-8 text-secondary">
No policies found. Try adjusting your search.
No documents found. Try adjusting your search.
</div>
) : (
<table className="w-full bg-level-1">
@@ -1101,27 +1101,27 @@ export function Control({
</tr>
</thead>
<tbody>
{filteredPolicies().map((policy) => {
const isLinked = isPolicyLinked(policy.id);
{filteredDocuments().map((document) => {
const isLinked = isDocumentLinked(document.id);
return (
<tr
key={policy.id}
key={document.id}
className="border-b hover:bg-invert-bg"
>
<td className="py-3 px-4">
<div className="font-medium">
{policy.title}
{document.title}
</div>
{policy.description && (
{document.description && (
<div className="text-xs text-secondary line-clamp-1 mt-0.5">
{policy.description}
{document.description}
</div>
)}
</td>
<td className="py-3 px-4">
{policy.updatedAt
{document.updatedAt
? new Date(
policy.updatedAt
document.updatedAt
).toLocaleDateString()
: "Not set"}
</td>
@@ -1131,12 +1131,12 @@ export function Control({
variant="outline"
size="sm"
onClick={() =>
handleUnlinkPolicy(policy.id)
handleUnlinkDocument(document.id)
}
disabled={isUnlinkingPolicy}
disabled={isUnlinkingDocument}
className="text-xs h-7 text-danger border-danger-b hover:bg-h-danger-bg"
>
{isUnlinkingPolicy ? (
{isUnlinkingDocument ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
<X className="w-4 h-4" />
@@ -1148,12 +1148,12 @@ export function Control({
variant="secondary"
size="sm"
onClick={() =>
handleLinkPolicy(policy.id)
handleLinkDocument(document.id)
}
disabled={isLinkingPolicy}
disabled={isLinkingDocument}
className="text-xs h-7 text-info border-info-b hover:bg-h-info-bg"
>
{isLinkingPolicy ? (
{isLinkingDocument ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
<LinkIcon className="w-4 h-4" />
@@ -1173,35 +1173,35 @@ export function Control({
</div>
<DialogFooter className="mt-4">
<Button onClick={() => setIsPolicyMappingDialogOpen(false)}>
<Button onClick={() => setIsDocumentMappingDialogOpen(false)}>
Close
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
{/* Linked Policies List */}
{/* Linked Documents List */}
<div>
<div className="flex justify-between items-center mb-4">
<h3 className="text-xl font-medium text-secondary">Policies</h3>
<h3 className="text-xl font-medium text-secondary">Documents</h3>
<Button
variant="outline"
size="sm"
className="flex items-center gap-1"
onClick={handleOpenPolicyMappingDialog}
onClick={handleOpenDocumentMappingDialog}
>
<LinkIcon className="w-4 h-4" />
<span>Link Policies</span>
<span>Link Documents</span>
</Button>
</div>
{isLoadingPolicies ? (
{isLoadingDocuments ? (
<div className="flex items-center justify-center h-24">
<Loader2 className="w-6 h-6 animate-spin text-info" />
<span className="ml-2">Loading policies...</span>
<span className="ml-2">Loading documents...</span>
</div>
) : linkedPoliciesData?.control?.policies?.edges &&
linkedPoliciesData.control.policies.edges.length > 0 ? (
) : linkedDocumentsData?.control?.documents?.edges &&
linkedDocumentsData.control.documents.edges.length > 0 ? (
<div className="overflow-x-auto border rounded-md">
<table className="w-full">
<thead>
@@ -1214,22 +1214,22 @@ export function Control({
</tr>
</thead>
<tbody>
{getLinkedPolicies().map((policy) => (
{getLinkedDocuments().map((document) => (
<tr
key={policy.id}
key={document.id}
className="border-b hover:bg-invert-bg"
>
<td className="py-3 px-4">
<div className="font-medium">{policy.title}</div>
{policy.description && (
<div className="font-medium">{document.title}</div>
{document.description && (
<div className="text-xs text-secondary line-clamp-1 mt-0.5">
{policy.description}
{document.description}
</div>
)}
</td>
<td className="py-3 px-4">
{policy.updatedAt
? new Date(policy.updatedAt).toLocaleDateString()
{document.updatedAt
? new Date(document.updatedAt).toLocaleDateString()
: "Not set"}
</td>
<td className="py-3 px-4 text-right whitespace-nowrap">
@@ -1241,7 +1241,7 @@ export function Control({
className="text-xs h-7"
>
<Link
to={`/organizations/${organizationId}/policies/${policy.id}`}
to={`/organizations/${organizationId}/documents/${document.id}`}
>
View
</Link>
@@ -1249,8 +1249,8 @@ export function Control({
<Button
variant="outline"
size="sm"
onClick={() => handleUnlinkPolicy(policy.id)}
disabled={isUnlinkingPolicy}
onClick={() => handleUnlinkDocument(document.id)}
disabled={isUnlinkingDocument}
className="text-xs h-7 text-danger border-danger-b hover:bg-h-danger-bg"
>
Unlink
@@ -1264,8 +1264,8 @@ export function Control({
</div>
) : (
<div className="text-center py-8 text-secondary border rounded-md">
No policies linked to this control yet. Click &quot;Link
Policies&quot; to connect some.
No documents linked to this control yet. Click &quot;Link
Documents&quot; to connect some.
</div>
)}
</div>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<9e8a7131004ab3ef4f20c36c904bd9db>>
* @generated SignedSource<<50d6cda002b6548d568947de29ef3971>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,15 +9,15 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type CreateControlPolicyMappingInput = {
export type CreateControlDocumentMappingInput = {
controlId: string;
policyId: string;
documentId: string;
};
export type ControlCreatePolicyMappingMutation$variables = {
input: CreateControlPolicyMappingInput;
export type ControlCreateDocumentMappingMutation$variables = {
input: CreateControlDocumentMappingInput;
};
export type ControlCreatePolicyMappingMutation$data = {
readonly createControlPolicyMapping: {
export type ControlCreateDocumentMappingMutation$data = {
readonly createControlDocumentMapping: {
readonly controlEdge: {
readonly node: {
readonly id: string;
@@ -25,9 +25,9 @@ export type ControlCreatePolicyMappingMutation$data = {
};
};
};
export type ControlCreatePolicyMappingMutation = {
response: ControlCreatePolicyMappingMutation$data;
variables: ControlCreatePolicyMappingMutation$variables;
export type ControlCreateDocumentMappingMutation = {
response: ControlCreateDocumentMappingMutation$data;
variables: ControlCreateDocumentMappingMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -48,9 +48,9 @@ v1 = [
"variableName": "input"
}
],
"concreteType": "CreateControlPolicyMappingPayload",
"concreteType": "CreateControlDocumentMappingPayload",
"kind": "LinkedField",
"name": "createControlPolicyMapping",
"name": "createControlDocumentMapping",
"plural": false,
"selections": [
{
@@ -91,7 +91,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ControlCreatePolicyMappingMutation",
"name": "ControlCreateDocumentMappingMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
@@ -100,20 +100,20 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ControlCreatePolicyMappingMutation",
"name": "ControlCreateDocumentMappingMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "d2cf3e45fcc9109399c3b80addb03b20",
"cacheID": "44eba73b10ac45d65d97c96098260898",
"id": null,
"metadata": {},
"name": "ControlCreatePolicyMappingMutation",
"name": "ControlCreateDocumentMappingMutation",
"operationKind": "mutation",
"text": "mutation ControlCreatePolicyMappingMutation(\n $input: CreateControlPolicyMappingInput!\n) {\n createControlPolicyMapping(input: $input) {\n controlEdge {\n node {\n id\n }\n }\n }\n}\n"
"text": "mutation ControlCreateDocumentMappingMutation(\n $input: CreateControlDocumentMappingInput!\n) {\n createControlDocumentMapping(input: $input) {\n controlEdge {\n node {\n id\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "9deabb78c91eca04673b23cf5d0b68f5";
(node as any).hash = "8ffd23b4cc3ce09756891fcde03c33cd";
export default node;

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<16f8815c8b1db694fb8cd18be95c3f53>>
* @generated SignedSource<<a39e2bd50fb3d78ac40f96740496fcac>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,21 +9,21 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DeleteControlPolicyMappingInput = {
export type DeleteControlDocumentMappingInput = {
controlId: string;
policyId: string;
documentId: string;
};
export type ControlDeletePolicyMappingMutation$variables = {
input: DeleteControlPolicyMappingInput;
export type ControlDeleteDocumentMappingMutation$variables = {
input: DeleteControlDocumentMappingInput;
};
export type ControlDeletePolicyMappingMutation$data = {
readonly deleteControlPolicyMapping: {
readonly deletedPolicyId: string;
export type ControlDeleteDocumentMappingMutation$data = {
readonly deleteControlDocumentMapping: {
readonly deletedDocumentId: string;
};
};
export type ControlDeletePolicyMappingMutation = {
response: ControlDeletePolicyMappingMutation$data;
variables: ControlDeletePolicyMappingMutation$variables;
export type ControlDeleteDocumentMappingMutation = {
response: ControlDeleteDocumentMappingMutation$data;
variables: ControlDeleteDocumentMappingMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -44,16 +44,16 @@ v1 = [
"variableName": "input"
}
],
"concreteType": "DeleteControlPolicyMappingPayload",
"concreteType": "DeleteControlDocumentMappingPayload",
"kind": "LinkedField",
"name": "deleteControlPolicyMapping",
"name": "deleteControlDocumentMapping",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deletedPolicyId",
"name": "deletedDocumentId",
"storageKey": null
}
],
@@ -65,7 +65,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ControlDeletePolicyMappingMutation",
"name": "ControlDeleteDocumentMappingMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
@@ -74,20 +74,20 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ControlDeletePolicyMappingMutation",
"name": "ControlDeleteDocumentMappingMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "ae87d43859683362f6c7024e7f371425",
"cacheID": "de5f0d5a1db8bf370f893e99e58729df",
"id": null,
"metadata": {},
"name": "ControlDeletePolicyMappingMutation",
"name": "ControlDeleteDocumentMappingMutation",
"operationKind": "mutation",
"text": "mutation ControlDeletePolicyMappingMutation(\n $input: DeleteControlPolicyMappingInput!\n) {\n deleteControlPolicyMapping(input: $input) {\n deletedPolicyId\n }\n}\n"
"text": "mutation ControlDeleteDocumentMappingMutation(\n $input: DeleteControlDocumentMappingInput!\n) {\n deleteControlDocumentMapping(input: $input) {\n deletedDocumentId\n }\n}\n"
}
};
})();
(node as any).hash = "39306cd73fd5af5c603272f0bba45a8f";
(node as any).hash = "d7e9d7d588053130899fe2f52399a99d";
export default node;

View File

@@ -0,0 +1,301 @@
/**
* @generated SignedSource<<0368d1546d67e840ab9a22f8864fde5a>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ControlLinkedDocumentsQuery$variables = {
controlId: string;
};
export type ControlLinkedDocumentsQuery$data = {
readonly control: {
readonly documents?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: string;
readonly currentPublishedVersion: number | null | undefined;
readonly description: string;
readonly id: string;
readonly owner: {
readonly fullName: string;
readonly id: string;
};
readonly title: string;
readonly updatedAt: string;
};
}>;
};
readonly id: string;
};
};
export type ControlLinkedDocumentsQuery = {
response: ControlLinkedDocumentsQuery$data;
variables: ControlLinkedDocumentsQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "controlId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "controlId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = [
{
"alias": null,
"args": null,
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "currentPublishedVersion",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
}
],
"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": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
}
],
v5 = [
{
"kind": "Literal",
"name": "first",
"value": 100
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ControlLinkedDocumentsQuery",
"selections": [
{
"alias": "control",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": "documents",
"args": null,
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "__Control__documents_connection",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": null
}
],
"type": "Control",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ControlLinkedDocumentsQuery",
"selections": [
{
"alias": "control",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "documents",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": "documents(first:100)"
},
{
"alias": null,
"args": (v5/*: any*/),
"filters": null,
"handle": "connection",
"key": "Control__documents",
"kind": "LinkedHandle",
"name": "documents"
}
],
"type": "Control",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "991da084547d2b0790d0698baf953be0",
"id": null,
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "forward",
"path": [
"control",
"documents"
]
}
]
},
"name": "ControlLinkedDocumentsQuery",
"operationKind": "query",
"text": "query ControlLinkedDocumentsQuery(\n $controlId: ID!\n) {\n control: node(id: $controlId) {\n __typename\n id\n ... on Control {\n documents(first: 100) {\n edges {\n node {\n id\n title\n description\n currentPublishedVersion\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "ec0ce0c9a248664a239bb048da0bb76c";
export default node;

View File

@@ -9,13 +9,13 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ControlLinkedPoliciesQuery$variables = {
export type ControlLinkedDocumentsQuery$variables = {
controlId: string;
};
export type ControlLinkedPoliciesQuery$data = {
export type ControlLinkedDocumentsQuery$data = {
readonly control: {
readonly id: string;
readonly policies?: {
readonly documents?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: string;
@@ -33,9 +33,9 @@ export type ControlLinkedPoliciesQuery$data = {
};
};
};
export type ControlLinkedPoliciesQuery = {
response: ControlLinkedPoliciesQuery$data;
variables: ControlLinkedPoliciesQuery$variables;
export type ControlLinkedDocumentsQuery = {
response: ControlLinkedDocumentsQuery$data;
variables: ControlLinkedDocumentsQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -71,7 +71,7 @@ v4 = [
{
"alias": null,
"args": null,
"concreteType": "PolicyEdge",
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -79,7 +79,7 @@ v4 = [
{
"alias": null,
"args": null,
"concreteType": "Policy",
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -191,7 +191,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ControlLinkedPoliciesQuery",
"name": "ControlLinkedDocumentsQuery",
"selections": [
{
"alias": "control",
@@ -206,11 +206,11 @@ return {
"kind": "InlineFragment",
"selections": [
{
"alias": "policies",
"alias": "documents",
"args": null,
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "__Control__policies_connection",
"name": "__Control__documents_connection",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": null
@@ -230,7 +230,7 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ControlLinkedPoliciesQuery",
"name": "ControlLinkedDocumentsQuery",
"selections": [
{
"alias": "control",
@@ -248,21 +248,21 @@ return {
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "policies",
"name": "documents",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": "policies(first:100)"
"storageKey": "documents(first:100)"
},
{
"alias": null,
"args": (v5/*: any*/),
"filters": null,
"handle": "connection",
"key": "Control__policies",
"key": "Control__documents",
"kind": "LinkedHandle",
"name": "policies"
"name": "documents"
}
],
"type": "Control",
@@ -284,14 +284,14 @@ return {
"direction": "forward",
"path": [
"control",
"policies"
"documents"
]
}
]
},
"name": "ControlLinkedPoliciesQuery",
"name": "ControlLinkedDocumentsQuery",
"operationKind": "query",
"text": "query ControlLinkedPoliciesQuery(\n $controlId: ID!\n) {\n control: node(id: $controlId) {\n __typename\n id\n ... on Control {\n policies(first: 100) {\n edges {\n node {\n id\n title\n description\n currentPublishedVersion\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
"text": "query ControlLinkedDocumentsQuery(\n $controlId: ID!\n) {\n control: node(id: $controlId) {\n __typename\n id\n ... on Control {\n documents(first: 100) {\n edges {\n node {\n id\n title\n description\n currentPublishedVersion\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();

View File

@@ -0,0 +1,301 @@
/**
* @generated SignedSource<<2b85a8642da3bc98edc1342bd07841ae>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ControlOrganizationDocumentsQuery$variables = {
organizationId: string;
};
export type ControlOrganizationDocumentsQuery$data = {
readonly organization: {
readonly documents?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: string;
readonly currentPublishedVersion: number | null | undefined;
readonly description: string;
readonly id: string;
readonly owner: {
readonly fullName: string;
readonly id: string;
};
readonly title: string;
readonly updatedAt: string;
};
}>;
};
readonly id: string;
};
};
export type ControlOrganizationDocumentsQuery = {
response: ControlOrganizationDocumentsQuery$data;
variables: ControlOrganizationDocumentsQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = [
{
"alias": null,
"args": null,
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "description",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "currentPublishedVersion",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "createdAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "updatedAt",
"storageKey": null
},
{
"alias": null,
"args": null,
"concreteType": "People",
"kind": "LinkedField",
"name": "owner",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "fullName",
"storageKey": null
}
],
"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": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
}
],
v5 = [
{
"kind": "Literal",
"name": "first",
"value": 100
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ControlOrganizationDocumentsQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": "documents",
"args": null,
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "__Organization__documents_connection",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": null
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ControlOrganizationDocumentsQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "documents",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": "documents(first:100)"
},
{
"alias": null,
"args": (v5/*: any*/),
"filters": null,
"handle": "connection",
"key": "Organization__documents",
"kind": "LinkedHandle",
"name": "documents"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "6607215b906f016d5f1f7a432f9eb41b",
"id": null,
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "forward",
"path": [
"organization",
"documents"
]
}
]
},
"name": "ControlOrganizationDocumentsQuery",
"operationKind": "query",
"text": "query ControlOrganizationDocumentsQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n documents(first: 100) {\n edges {\n node {\n id\n title\n description\n currentPublishedVersion\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "99469ffc117f4f1dea4c96eb818d8fc3";
export default node;

View File

@@ -9,13 +9,13 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ControlOrganizationPoliciesQuery$variables = {
export type ControlOrganizationDocumentsQuery$variables = {
organizationId: string;
};
export type ControlOrganizationPoliciesQuery$data = {
export type ControlOrganizationDocumentsQuery$data = {
readonly organization: {
readonly id: string;
readonly policies?: {
readonly documents?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: string;
@@ -33,9 +33,9 @@ export type ControlOrganizationPoliciesQuery$data = {
};
};
};
export type ControlOrganizationPoliciesQuery = {
response: ControlOrganizationPoliciesQuery$data;
variables: ControlOrganizationPoliciesQuery$variables;
export type ControlOrganizationDocumentsQuery = {
response: ControlOrganizationDocumentsQuery$data;
variables: ControlOrganizationDocumentsQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -71,7 +71,7 @@ v4 = [
{
"alias": null,
"args": null,
"concreteType": "PolicyEdge",
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -79,7 +79,7 @@ v4 = [
{
"alias": null,
"args": null,
"concreteType": "Policy",
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -191,7 +191,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ControlOrganizationPoliciesQuery",
"name": "ControlOrganizationDocumentsQuery",
"selections": [
{
"alias": "organization",
@@ -206,11 +206,11 @@ return {
"kind": "InlineFragment",
"selections": [
{
"alias": "policies",
"alias": "documents",
"args": null,
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "__Organization__policies_connection",
"name": "__Organization__documents_connection",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": null
@@ -230,7 +230,7 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ControlOrganizationPoliciesQuery",
"name": "ControlOrganizationDocumentsQuery",
"selections": [
{
"alias": "organization",
@@ -248,21 +248,21 @@ return {
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "policies",
"name": "documents",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": "policies(first:100)"
"storageKey": "documents(first:100)"
},
{
"alias": null,
"args": (v5/*: any*/),
"filters": null,
"handle": "connection",
"key": "Organization__policies",
"key": "Organization__documents",
"kind": "LinkedHandle",
"name": "policies"
"name": "documents"
}
],
"type": "Organization",
@@ -284,14 +284,14 @@ return {
"direction": "forward",
"path": [
"organization",
"policies"
"documents"
]
}
]
},
"name": "ControlOrganizationPoliciesQuery",
"name": "ControlOrganizationDocumentsQuery",
"operationKind": "query",
"text": "query ControlOrganizationPoliciesQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n policies(first: 100) {\n edges {\n node {\n id\n title\n description\n currentPublishedVersion\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
"text": "query ControlOrganizationDocumentsQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n documents(first: 100) {\n edges {\n node {\n id\n title\n description\n currentPublishedVersion\n createdAt\n updatedAt\n owner {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();

View File

@@ -60,11 +60,11 @@ import {
import { ShowRiskViewCreateRiskMeasureMappingMutation } from "./__generated__/ShowRiskViewCreateRiskMeasureMappingMutation.graphql";
import { ShowRiskViewDeleteRiskMeasureMappingMutation } from "./__generated__/ShowRiskViewDeleteRiskMeasureMappingMutation.graphql";
import {
ShowRiskViewOrganizationPoliciesQuery,
ShowRiskViewOrganizationPoliciesQuery$data,
} from "./__generated__/ShowRiskViewOrganizationPoliciesQuery.graphql";
import { ShowRiskViewCreateRiskPolicyMappingMutation } from "./__generated__/ShowRiskViewCreateRiskPolicyMappingMutation.graphql";
import { ShowRiskViewDeleteRiskPolicyMappingMutation } from "./__generated__/ShowRiskViewDeleteRiskPolicyMappingMutation.graphql";
ShowRiskViewOrganizationDocumentsQuery,
ShowRiskViewOrganizationDocumentsQuery$data,
} from "./__generated__/ShowRiskViewOrganizationDocumentsQuery.graphql";
import { ShowRiskViewCreateRiskDocumentMappingMutation } from "./__generated__/ShowRiskViewCreateRiskDocumentMappingMutation.graphql";
import { ShowRiskViewDeleteRiskDocumentMappingMutation } from "./__generated__/ShowRiskViewDeleteRiskDocumentMappingMutation.graphql";
const showRiskViewQuery = graphql`
query ShowRiskViewQuery($riskId: ID!) {
@@ -97,7 +97,7 @@ const showRiskViewQuery = graphql`
}
}
}
policies(first: 100) @connection(key: "Risk__policies") {
documents(first: 100) @connection(key: "Risk__documents") {
edges {
node {
id
@@ -144,13 +144,13 @@ const organizationMeasuresQuery = graphql`
}
`;
// Add query to fetch all policies for the organization
const organizationPoliciesQuery = graphql`
query ShowRiskViewOrganizationPoliciesQuery($organizationId: ID!) {
// Add query to fetch all documents for the organization
const organizationDocumentsQuery = graphql`
query ShowRiskViewOrganizationDocumentsQuery($organizationId: ID!) {
organization: node(id: $organizationId) {
id
... on Organization {
policies(first: 100) @connection(key: "Organization__policies") {
documents(first: 100) @connection(key: "Organization__documents") {
edges {
node {
id
@@ -189,12 +189,12 @@ const deleteRiskMeasureMappingMutation = graphql`
}
`;
// Add mutation to create risk-policy mapping
const createRiskPolicyMappingMutation = graphql`
mutation ShowRiskViewCreateRiskPolicyMappingMutation(
$input: CreateRiskPolicyMappingInput!
// Add mutation to create risk-document mapping
const createRiskDocumentMappingMutation = graphql`
mutation ShowRiskViewCreateRiskDocumentMappingMutation(
$input: CreateRiskDocumentMappingInput!
) {
createRiskPolicyMapping(input: $input) {
createRiskDocumentMapping(input: $input) {
riskEdge {
node {
id
@@ -204,13 +204,13 @@ const createRiskPolicyMappingMutation = graphql`
}
`;
// Add mutation to delete risk-policy mapping
const deleteRiskPolicyMappingMutation = graphql`
mutation ShowRiskViewDeleteRiskPolicyMappingMutation(
$input: DeleteRiskPolicyMappingInput!
// Add mutation to delete risk-document mapping
const deleteRiskDocumentMappingMutation = graphql`
mutation ShowRiskViewDeleteRiskDocumentMappingMutation(
$input: DeleteRiskDocumentMappingInput!
) {
deleteRiskPolicyMapping(input: $input) {
deletedPolicyId
deleteRiskDocumentMapping(input: $input) {
deletedDocumentId
}
}
`;
@@ -377,8 +377,8 @@ function ShowRiskViewContent({
risk.residualImpact!
);
// Fix typing for policies
const policies = risk.policies?.edges?.map((edge) => edge.node) || [];
// Fix typing for documents
const documents = risk.documents?.edges?.map((edge) => edge.node) || [];
// Fix typing for controls
const controls = risk.controls?.edges?.map((edge) => edge.node) || [];
@@ -397,16 +397,16 @@ function ShowRiskViewContent({
Record<string, boolean>
>({});
// Add state for policy mapping dialog
const [isPolicyDialogOpen, setIsPolicyDialogOpen] = useState(false);
const [organizationPoliciesData, setOrganizationPoliciesData] =
useState<ShowRiskViewOrganizationPoliciesQuery$data | null>(null);
const [policySearchQuery, setPolicySearchQuery] = useState("");
const [isLoadingPolicies, setIsLoadingPolicies] = useState(false);
const [linkingPolicies, setLinkingPolicies] = useState<
// Add state for document mapping dialog
const [isDocumentDialogOpen, setIsDocumentDialogOpen] = useState(false);
const [organizationDocumentsData, setOrganizationDocumentsData] =
useState<ShowRiskViewOrganizationDocumentsQuery$data | null>(null);
const [documentSearchQuery, setDocumentSearchQuery] = useState("");
const [isLoadingDocuments, setIsLoadingDocuments] = useState(false);
const [linkingDocuments, setLinkingDocuments] = useState<
Record<string, boolean>
>({});
const [unlinkingPolicies, setUnlinkingPolicies] = useState<
const [unlinkingDocuments, setUnlinkingDocuments] = useState<
Record<string, boolean>
>({});
@@ -420,14 +420,14 @@ function ShowRiskViewContent({
deleteRiskMeasureMappingMutation
);
// Setup policy mutation hooks
const [createRiskPolicyMapping] =
useMutation<ShowRiskViewCreateRiskPolicyMappingMutation>(
createRiskPolicyMappingMutation
// Setup document mutation hooks
const [createRiskDocumentMapping] =
useMutation<ShowRiskViewCreateRiskDocumentMappingMutation>(
createRiskDocumentMappingMutation
);
const [deleteRiskPolicyMapping] =
useMutation<ShowRiskViewDeleteRiskPolicyMappingMutation>(
deleteRiskPolicyMappingMutation
const [deleteRiskDocumentMapping] =
useMutation<ShowRiskViewDeleteRiskDocumentMappingMutation>(
deleteRiskDocumentMappingMutation
);
// Clear filters when dialog closes
@@ -440,14 +440,14 @@ function ShowRiskViewContent({
}
}, [isMeasureDialogOpen]);
// Clear filters when policy dialog closes
// Clear filters when document dialog closes
useEffect(() => {
if (!isPolicyDialogOpen) {
setPolicySearchQuery("");
setLinkingPolicies({});
setUnlinkingPolicies({});
if (!isDocumentDialogOpen) {
setDocumentSearchQuery("");
setLinkingDocuments({});
setUnlinkingDocuments({});
}
}, [isPolicyDialogOpen]);
}, [isDocumentDialogOpen]);
// Load measures data when needed
const loadMeasuresData = useCallback(() => {
@@ -479,30 +479,30 @@ function ShowRiskViewContent({
});
}, [risk.id, environment, organizationId, toast]);
// Load policies data when needed
const loadPoliciesData = useCallback(() => {
// Load documents data when needed
const loadDocumentsData = useCallback(() => {
if (!organizationId || !risk.id) return;
setIsLoadingPolicies(true);
setIsLoadingDocuments(true);
// Fetch all policies for the organization
fetchQuery<ShowRiskViewOrganizationPoliciesQuery>(
// Fetch all documents for the organization
fetchQuery<ShowRiskViewOrganizationDocumentsQuery>(
environment,
organizationPoliciesQuery,
organizationDocumentsQuery,
{
organizationId,
}
).subscribe({
next: (data) => {
setOrganizationPoliciesData(data);
setIsLoadingPolicies(false);
setOrganizationDocumentsData(data);
setIsLoadingDocuments(false);
},
error: (error: Error) => {
console.error("Error fetching organization policies:", error);
setIsLoadingPolicies(false);
console.error("Error fetching organization documents:", error);
setIsLoadingDocuments(false);
toast({
title: "Error",
description: "Failed to load policies.",
description: "Failed to load documents.",
variant: "destructive",
});
},
@@ -554,25 +554,25 @@ function ShowRiskViewContent({
});
}, [getMeasures, measureSearchQuery, categoryFilter]);
// Helper functions for policies
const getPolicies = useCallback(() => {
if (!organizationPoliciesData?.organization?.policies?.edges) return [];
return organizationPoliciesData.organization.policies.edges.map(
// Helper functions for documents
const getDocuments = useCallback(() => {
if (!organizationDocumentsData?.organization?.documents?.edges) return [];
return organizationDocumentsData.organization.documents.edges.map(
(edge) => edge.node
);
}, [organizationPoliciesData]);
}, [organizationDocumentsData]);
const filteredPolicies = useCallback(() => {
const policies = getPolicies();
if (!policySearchQuery) return policies;
const filteredDocuments = useCallback(() => {
const documents = getDocuments();
if (!documentSearchQuery) return documents;
return policies.filter((policy) => {
return documents.filter((document) => {
return (
!policySearchQuery ||
policy.title.toLowerCase().includes(policySearchQuery.toLowerCase())
!documentSearchQuery ||
document.title.toLowerCase().includes(documentSearchQuery.toLowerCase())
);
});
}, [getPolicies, policySearchQuery]);
}, [getDocuments, documentSearchQuery]);
// Handle linking a measure to this risk
const handleLinkMeasure = useCallback(
@@ -718,38 +718,38 @@ function ShowRiskViewContent({
[risk.id, deleteRiskMeasureMapping, toast, environment, loadQuery]
);
// Handle linking a policy to this risk
const handleLinkPolicy = useCallback(
// Handle linking a document to this risk
const handleLinkDocument = useCallback(
(
policy: NonNullable<
document: NonNullable<
NonNullable<
ShowRiskViewOrganizationPoliciesQuery$data["organization"]
>["policies"]
ShowRiskViewOrganizationDocumentsQuery$data["organization"]
>["documents"]
>["edges"][0]["node"]
) => {
if (!risk.id) return;
// Track this specific policy as linking
setLinkingPolicies((prev) => ({ ...prev, [policy.id]: true }));
// Track this specific document as linking
setLinkingDocuments((prev) => ({ ...prev, [document.id]: true }));
createRiskPolicyMapping({
createRiskDocumentMapping({
variables: {
input: {
riskId: risk.id,
policyId: policy.id,
documentId: document.id,
},
},
onCompleted: (_, errors) => {
setLinkingPolicies((prev) => ({
setLinkingDocuments((prev) => ({
...prev,
[policy.id]: false,
[document.id]: false,
}));
if (errors && errors.length > 0) {
console.error("Error linking policy:", errors);
console.error("Error linking document:", errors);
toast({
title: "Error",
description: "Failed to link policy. Please try again.",
description: "Failed to link document. Please try again.",
variant: "destructive",
});
return;
@@ -770,58 +770,58 @@ function ShowRiskViewContent({
toast({
title: "Success",
description: `Linked policy "${policy.title}" to this risk.`,
description: `Linked document "${document.title}" to this risk.`,
});
},
onError: (error) => {
setLinkingPolicies((prev) => ({
setLinkingDocuments((prev) => ({
...prev,
[policy.id]: false,
[document.id]: false,
}));
console.error("Error linking policy:", error);
console.error("Error linking document:", error);
toast({
title: "Error",
description: "Failed to link policy. Please try again.",
description: "Failed to link document. Please try again.",
variant: "destructive",
});
},
});
},
[risk.id, createRiskPolicyMapping, toast, environment, loadQuery]
[risk.id, createRiskDocumentMapping, toast, environment, loadQuery]
);
// Handle unlinking a policy from this risk
const handleUnlinkPolicy = useCallback(
// Handle unlinking a document from this risk
const handleUnlinkDocument = useCallback(
(
policy: NonNullable<
document: NonNullable<
NonNullable<
ShowRiskViewOrganizationPoliciesQuery$data["organization"]
>["policies"]
ShowRiskViewOrganizationDocumentsQuery$data["organization"]
>["documents"]
>["edges"][0]["node"]
) => {
if (!risk.id) return;
// Track this specific policy as unlinking
setUnlinkingPolicies((prev) => ({ ...prev, [policy.id]: true }));
// Track this specific document as unlinking
setUnlinkingDocuments((prev) => ({ ...prev, [document.id]: true }));
deleteRiskPolicyMapping({
deleteRiskDocumentMapping({
variables: {
input: {
riskId: risk.id,
policyId: policy.id,
documentId: document.id,
},
},
onCompleted: (_, errors) => {
setUnlinkingPolicies((prev) => ({
setUnlinkingDocuments((prev) => ({
...prev,
[policy.id]: false,
[document.id]: false,
}));
if (errors && errors.length > 0) {
console.error("Error unlinking policy:", errors);
console.error("Error unlinking document:", errors);
toast({
title: "Error",
description: "Failed to unlink policy. Please try again.",
description: "Failed to unlink document. Please try again.",
variant: "destructive",
});
return;
@@ -842,24 +842,24 @@ function ShowRiskViewContent({
toast({
title: "Success",
description: `Unlinked policy "${policy.title}" from this risk.`,
description: `Unlinked document "${document.title}" from this risk.`,
});
},
onError: (error) => {
setUnlinkingPolicies((prev) => ({
setUnlinkingDocuments((prev) => ({
...prev,
[policy.id]: false,
[document.id]: false,
}));
console.error("Error unlinking policy:", error);
console.error("Error unlinking document:", error);
toast({
title: "Error",
description: "Failed to unlink policy. Please try again.",
description: "Failed to unlink document. Please try again.",
variant: "destructive",
});
},
});
},
[risk.id, deleteRiskPolicyMapping, toast, environment, loadQuery]
[risk.id, deleteRiskDocumentMapping, toast, environment, loadQuery]
);
return (
@@ -1073,7 +1073,7 @@ function ShowRiskViewContent({
<Tabs defaultValue="measures" className="w-full">
<TabsList>
<TabsTrigger value="measures">Measures</TabsTrigger>
<TabsTrigger value="policies">Policies</TabsTrigger>
<TabsTrigger value="documents">Documents</TabsTrigger>
<TabsTrigger value="controls">Controls</TabsTrigger>
</TabsList>
@@ -1133,48 +1133,48 @@ function ShowRiskViewContent({
)}
</TabsContent>
<TabsContent value="policies" className="space-y-4">
<TabsContent value="documents" className="space-y-4">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-semibold">Risk Policies</h2>
<h2 className="text-xl font-semibold">Risk Documents</h2>
<div className="flex space-x-2">
<Button
onClick={() => {
setIsPolicyDialogOpen(true);
loadPoliciesData();
setIsDocumentDialogOpen(true);
loadDocumentsData();
}}
>
<Plus className="mr-2 h-4 w-4" />
Link Policy
Link Document
</Button>
</div>
</div>
{policies.length > 0 ? (
{documents.length > 0 ? (
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-full">Policy</TableHead>
<TableHead className="w-full">Document</TableHead>
<TableHead className="w-20">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{policies.map((policy) => (
<TableRow key={policy.id}>
{documents.map((document) => (
<TableRow key={document.id}>
<TableCell>
<Link
to={`/organizations/${organizationId}/policies/${policy.id}`}
to={`/organizations/${organizationId}/documents/${document.id}`}
className="font-medium text-blue-600 hover:underline"
>
{policy.title}
{document.title}
</Link>
</TableCell>
<TableCell>
<Button
variant="ghost"
size="icon"
onClick={() => handleUnlinkPolicy(policy)}
disabled={unlinkingPolicies[policy.id] || false}
title="Unlink policy"
onClick={() => handleUnlinkDocument(document)}
disabled={unlinkingDocuments[document.id] || false}
title="Unlink document"
>
<Trash2 className="h-4 w-4 text-danger" />
</Button>
@@ -1186,7 +1186,7 @@ function ShowRiskViewContent({
</div>
) : (
<div className="text-center py-10 text-secondary">
<p>No policies associated with this risk.</p>
<p>No documents associated with this risk.</p>
</div>
)}
</TabsContent>
@@ -1351,15 +1351,15 @@ function ShowRiskViewContent({
</DialogContent>
</Dialog>
{/* Dialog for linking policies */}
<Dialog open={isPolicyDialogOpen} onOpenChange={setIsPolicyDialogOpen}>
{/* Dialog for linking documents */}
<Dialog open={isDocumentDialogOpen} onOpenChange={setIsDocumentDialogOpen}>
<DialogContent className="max-w-3xl">
<DialogHeader>
<div className="flex justify-between items-center">
<div>
<DialogTitle>Manage Risk Policies</DialogTitle>
<DialogTitle>Manage Risk Documents</DialogTitle>
<DialogDescription>
Link or unlink policies to manage this risk.
Link or unlink documents to manage this risk.
</DialogDescription>
</div>
</div>
@@ -1371,45 +1371,45 @@ function ShowRiskViewContent({
<div className="relative">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-tertiary" />
<Input
placeholder="Search policies..."
placeholder="Search documents..."
className="pl-8"
value={policySearchQuery}
onChange={(e) => setPolicySearchQuery(e.target.value)}
value={documentSearchQuery}
onChange={(e) => setDocumentSearchQuery(e.target.value)}
/>
</div>
</div>
</div>
<div className="border rounded-md max-h-96 overflow-y-auto">
{isLoadingPolicies ? (
<div className="p-4 text-center">Loading policies...</div>
) : filteredPolicies().length === 0 ? (
<div className="p-4 text-center">No policies found.</div>
{isLoadingDocuments ? (
<div className="p-4 text-center">Loading documents...</div>
) : filteredDocuments().length === 0 ? (
<div className="p-4 text-center">No documents found.</div>
) : (
<div className="divide-y">
{filteredPolicies().map((policy) => {
{filteredDocuments().map((document) => {
// For each render, recalculate linked status directly against the current risk data
const isLinked = policies.some(
(riskPolicy) => riskPolicy.id === policy.id
const isLinked = documents.some(
(riskDocument) => riskDocument.id === document.id
);
const isLinking = linkingPolicies[policy.id] || false;
const isUnlinking = unlinkingPolicies[policy.id] || false;
const isLinking = linkingDocuments[document.id] || false;
const isUnlinking = unlinkingDocuments[document.id] || false;
return (
<div
key={policy.id}
key={document.id}
className="relative p-4 hover:bg-blue-50 transition-colors duration-150"
>
<div className="flex justify-between items-center">
<div className="flex items-center gap-2">
<h3 className="font-medium">{policy.title}</h3>
<h3 className="font-medium">{document.title}</h3>
</div>
{isLinked ? (
<Button
size="sm"
variant="outline"
disabled={isUnlinking}
onClick={() => handleUnlinkPolicy(policy)}
onClick={() => handleUnlinkDocument(document)}
className="text-red-600 border-red-200 hover:bg-red-50"
>
{isUnlinking ? "Unlinking..." : "Unlink"}
@@ -1418,7 +1418,7 @@ function ShowRiskViewContent({
<Button
size="sm"
disabled={isLinking}
onClick={() => handleLinkPolicy(policy)}
onClick={() => handleLinkDocument(document)}
>
{isLinking ? "Linking..." : "Link"}
</Button>
@@ -1435,7 +1435,7 @@ function ShowRiskViewContent({
<DialogFooter>
<Button
variant="outline"
onClick={() => setIsPolicyDialogOpen(false)}
onClick={() => setIsDocumentDialogOpen(false)}
>
Close
</Button>

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<0a4cb496e3dd17d135eaa689ebba360a>>
* @generated SignedSource<<ef56acc9abd55ffea9aee1093be375bf>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -9,15 +9,15 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type CreateRiskPolicyMappingInput = {
policyId: string;
export type CreateRiskDocumentMappingInput = {
documentId: string;
riskId: string;
};
export type ShowRiskViewCreateRiskPolicyMappingMutation$variables = {
input: CreateRiskPolicyMappingInput;
export type ShowRiskViewCreateRiskDocumentMappingMutation$variables = {
input: CreateRiskDocumentMappingInput;
};
export type ShowRiskViewCreateRiskPolicyMappingMutation$data = {
readonly createRiskPolicyMapping: {
export type ShowRiskViewCreateRiskDocumentMappingMutation$data = {
readonly createRiskDocumentMapping: {
readonly riskEdge: {
readonly node: {
readonly id: string;
@@ -25,9 +25,9 @@ export type ShowRiskViewCreateRiskPolicyMappingMutation$data = {
};
};
};
export type ShowRiskViewCreateRiskPolicyMappingMutation = {
response: ShowRiskViewCreateRiskPolicyMappingMutation$data;
variables: ShowRiskViewCreateRiskPolicyMappingMutation$variables;
export type ShowRiskViewCreateRiskDocumentMappingMutation = {
response: ShowRiskViewCreateRiskDocumentMappingMutation$data;
variables: ShowRiskViewCreateRiskDocumentMappingMutation$variables;
};
const node: ConcreteRequest = (function(){
@@ -48,9 +48,9 @@ v1 = [
"variableName": "input"
}
],
"concreteType": "CreateRiskPolicyMappingPayload",
"concreteType": "CreateRiskDocumentMappingPayload",
"kind": "LinkedField",
"name": "createRiskPolicyMapping",
"name": "createRiskDocumentMapping",
"plural": false,
"selections": [
{
@@ -91,7 +91,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ShowRiskViewCreateRiskPolicyMappingMutation",
"name": "ShowRiskViewCreateRiskDocumentMappingMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
@@ -100,20 +100,20 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ShowRiskViewCreateRiskPolicyMappingMutation",
"name": "ShowRiskViewCreateRiskDocumentMappingMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "57ab115614eb72c930a05a4496827702",
"cacheID": "d48140a960f31c5ee40799780ad852c0",
"id": null,
"metadata": {},
"name": "ShowRiskViewCreateRiskPolicyMappingMutation",
"name": "ShowRiskViewCreateRiskDocumentMappingMutation",
"operationKind": "mutation",
"text": "mutation ShowRiskViewCreateRiskPolicyMappingMutation(\n $input: CreateRiskPolicyMappingInput!\n) {\n createRiskPolicyMapping(input: $input) {\n riskEdge {\n node {\n id\n }\n }\n }\n}\n"
"text": "mutation ShowRiskViewCreateRiskDocumentMappingMutation(\n $input: CreateRiskDocumentMappingInput!\n) {\n createRiskDocumentMapping(input: $input) {\n riskEdge {\n node {\n id\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "ca3e1eee912cd4b7ac2702e4192dd544";
(node as any).hash = "cfd17c609ec34647f8ecafc1b07037ec";
export default node;

View File

@@ -0,0 +1,93 @@
/**
* @generated SignedSource<<77d14d5c3a949757604407daf7ba2600>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DeleteRiskDocumentMappingInput = {
documentId: string;
riskId: string;
};
export type ShowRiskViewDeleteRiskDocumentMappingMutation$variables = {
input: DeleteRiskDocumentMappingInput;
};
export type ShowRiskViewDeleteRiskDocumentMappingMutation$data = {
readonly deleteRiskDocumentMapping: {
readonly deletedDocumentId: string;
};
};
export type ShowRiskViewDeleteRiskDocumentMappingMutation = {
response: ShowRiskViewDeleteRiskDocumentMappingMutation$data;
variables: ShowRiskViewDeleteRiskDocumentMappingMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "DeleteRiskDocumentMappingPayload",
"kind": "LinkedField",
"name": "deleteRiskDocumentMapping",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deletedDocumentId",
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ShowRiskViewDeleteRiskDocumentMappingMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ShowRiskViewDeleteRiskDocumentMappingMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "1cd0845f63cf338aed2c2e565e239306",
"id": null,
"metadata": {},
"name": "ShowRiskViewDeleteRiskDocumentMappingMutation",
"operationKind": "mutation",
"text": "mutation ShowRiskViewDeleteRiskDocumentMappingMutation(\n $input: DeleteRiskDocumentMappingInput!\n) {\n deleteRiskDocumentMapping(input: $input) {\n deletedDocumentId\n }\n}\n"
}
};
})();
(node as any).hash = "b7b61daef6f0544c6b78f69094ad2d82";
export default node;

View File

@@ -1,93 +0,0 @@
/**
* @generated SignedSource<<8f8d550cd2bbc73744ba0b7a97720a49>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DeleteRiskPolicyMappingInput = {
policyId: string;
riskId: string;
};
export type ShowRiskViewDeleteRiskPolicyMappingMutation$variables = {
input: DeleteRiskPolicyMappingInput;
};
export type ShowRiskViewDeleteRiskPolicyMappingMutation$data = {
readonly deleteRiskPolicyMapping: {
readonly deletedPolicyId: string;
};
};
export type ShowRiskViewDeleteRiskPolicyMappingMutation = {
response: ShowRiskViewDeleteRiskPolicyMappingMutation$data;
variables: ShowRiskViewDeleteRiskPolicyMappingMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
}
],
v1 = [
{
"alias": null,
"args": [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
"concreteType": "DeleteRiskPolicyMappingPayload",
"kind": "LinkedField",
"name": "deleteRiskPolicyMapping",
"plural": false,
"selections": [
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deletedPolicyId",
"storageKey": null
}
],
"storageKey": null
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ShowRiskViewDeleteRiskPolicyMappingMutation",
"selections": (v1/*: any*/),
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ShowRiskViewDeleteRiskPolicyMappingMutation",
"selections": (v1/*: any*/)
},
"params": {
"cacheID": "d10c9ccbc01259fb7fea2bf463d6ecc6",
"id": null,
"metadata": {},
"name": "ShowRiskViewDeleteRiskPolicyMappingMutation",
"operationKind": "mutation",
"text": "mutation ShowRiskViewDeleteRiskPolicyMappingMutation(\n $input: DeleteRiskPolicyMappingInput!\n) {\n deleteRiskPolicyMapping(input: $input) {\n deletedPolicyId\n }\n}\n"
}
};
})();
(node as any).hash = "26177c99b1c35723f913637a1d6ac54b";
export default node;

View File

@@ -0,0 +1,246 @@
/**
* @generated SignedSource<<dfa237a2ce4b8cc6254ff791cb28f9f3>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ShowRiskViewOrganizationDocumentsQuery$variables = {
organizationId: string;
};
export type ShowRiskViewOrganizationDocumentsQuery$data = {
readonly organization: {
readonly documents?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
readonly title: string;
};
}>;
};
readonly id: string;
};
};
export type ShowRiskViewOrganizationDocumentsQuery = {
response: ShowRiskViewOrganizationDocumentsQuery$data;
variables: ShowRiskViewOrganizationDocumentsQuery$variables;
};
const node: ConcreteRequest = (function(){
var v0 = [
{
"defaultValue": null,
"kind": "LocalArgument",
"name": "organizationId"
}
],
v1 = [
{
"kind": "Variable",
"name": "id",
"variableName": "organizationId"
}
],
v2 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "id",
"storageKey": null
},
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "__typename",
"storageKey": null
},
v4 = [
{
"alias": null,
"args": null,
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
"selections": [
{
"alias": null,
"args": null,
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "title",
"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": "endCursor",
"storageKey": null
},
{
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "hasNextPage",
"storageKey": null
}
],
"storageKey": null
}
],
v5 = [
{
"kind": "Literal",
"name": "first",
"value": 100
}
];
return {
"fragment": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ShowRiskViewOrganizationDocumentsQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": "documents",
"args": null,
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "__Organization__documents_connection",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": null
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
],
"type": "Query",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ShowRiskViewOrganizationDocumentsQuery",
"selections": [
{
"alias": "organization",
"args": (v1/*: any*/),
"concreteType": null,
"kind": "LinkedField",
"name": "node",
"plural": false,
"selections": [
(v3/*: any*/),
(v2/*: any*/),
{
"kind": "InlineFragment",
"selections": [
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "documents",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": "documents(first:100)"
},
{
"alias": null,
"args": (v5/*: any*/),
"filters": null,
"handle": "connection",
"key": "Organization__documents",
"kind": "LinkedHandle",
"name": "documents"
}
],
"type": "Organization",
"abstractKey": null
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "7006d02b892a141f835e095002b234b1",
"id": null,
"metadata": {
"connection": [
{
"count": null,
"cursor": null,
"direction": "forward",
"path": [
"organization",
"documents"
]
}
]
},
"name": "ShowRiskViewOrganizationDocumentsQuery",
"operationKind": "query",
"text": "query ShowRiskViewOrganizationDocumentsQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n documents(first: 100) {\n edges {\n node {\n id\n title\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "dc0a2a6d494838560e76ac1ff916ecd5";
export default node;

View File

@@ -9,13 +9,13 @@
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type ShowRiskViewOrganizationPoliciesQuery$variables = {
export type ShowRiskViewOrganizationDocumentsQuery$variables = {
organizationId: string;
};
export type ShowRiskViewOrganizationPoliciesQuery$data = {
export type ShowRiskViewOrganizationDocumentsQuery$data = {
readonly organization: {
readonly id: string;
readonly policies?: {
readonly documents?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly id: string;
@@ -25,9 +25,9 @@ export type ShowRiskViewOrganizationPoliciesQuery$data = {
};
};
};
export type ShowRiskViewOrganizationPoliciesQuery = {
response: ShowRiskViewOrganizationPoliciesQuery$data;
variables: ShowRiskViewOrganizationPoliciesQuery$variables;
export type ShowRiskViewOrganizationDocumentsQuery = {
response: ShowRiskViewOrganizationDocumentsQuery$data;
variables: ShowRiskViewOrganizationDocumentsQuery$variables;
};
const node: ConcreteRequest = (function(){
@@ -63,7 +63,7 @@ v4 = [
{
"alias": null,
"args": null,
"concreteType": "PolicyEdge",
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -71,7 +71,7 @@ v4 = [
{
"alias": null,
"args": null,
"concreteType": "Policy",
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -136,7 +136,7 @@ return {
"argumentDefinitions": (v0/*: any*/),
"kind": "Fragment",
"metadata": null,
"name": "ShowRiskViewOrganizationPoliciesQuery",
"name": "ShowRiskViewOrganizationDocumentsQuery",
"selections": [
{
"alias": "organization",
@@ -151,11 +151,11 @@ return {
"kind": "InlineFragment",
"selections": [
{
"alias": "policies",
"alias": "documents",
"args": null,
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "__Organization__policies_connection",
"name": "__Organization__documents_connection",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": null
@@ -175,7 +175,7 @@ return {
"operation": {
"argumentDefinitions": (v0/*: any*/),
"kind": "Operation",
"name": "ShowRiskViewOrganizationPoliciesQuery",
"name": "ShowRiskViewOrganizationDocumentsQuery",
"selections": [
{
"alias": "organization",
@@ -193,21 +193,21 @@ return {
{
"alias": null,
"args": (v5/*: any*/),
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "policies",
"name": "documents",
"plural": false,
"selections": (v4/*: any*/),
"storageKey": "policies(first:100)"
"storageKey": "documents(first:100)"
},
{
"alias": null,
"args": (v5/*: any*/),
"filters": null,
"handle": "connection",
"key": "Organization__policies",
"key": "Organization__documents",
"kind": "LinkedHandle",
"name": "policies"
"name": "documents"
}
],
"type": "Organization",
@@ -229,14 +229,14 @@ return {
"direction": "forward",
"path": [
"organization",
"policies"
"documents"
]
}
]
},
"name": "ShowRiskViewOrganizationPoliciesQuery",
"name": "ShowRiskViewOrganizationDocumentsQuery",
"operationKind": "query",
"text": "query ShowRiskViewOrganizationPoliciesQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n policies(first: 100) {\n edges {\n node {\n id\n title\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
"text": "query ShowRiskViewOrganizationDocumentsQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n documents(first: 100) {\n edges {\n node {\n id\n title\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();

View File

@@ -1,5 +1,5 @@
/**
* @generated SignedSource<<48d940f6040fa9375ac915ce8851c658>>
* @generated SignedSource<<d43ef1981a6db6f7813e6587e3eaf192>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -29,6 +29,15 @@ export type ShowRiskViewQuery$data = {
};
readonly createdAt?: string;
readonly description?: string;
readonly documents?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: string;
readonly id: string;
readonly title: string;
};
}>;
};
readonly id: string;
readonly inherentImpact?: number;
readonly inherentLikelihood?: number;
@@ -50,15 +59,6 @@ export type ShowRiskViewQuery$data = {
readonly fullName: string;
readonly id: string;
} | null | undefined;
readonly policies?: {
readonly edges: ReadonlyArray<{
readonly node: {
readonly createdAt: string;
readonly id: string;
readonly title: string;
};
}>;
};
readonly residualImpact?: number;
readonly residualLikelihood?: number;
readonly treatment?: RiskTreatment;
@@ -269,7 +269,7 @@ v18 = [
{
"alias": null,
"args": null,
"concreteType": "PolicyEdge",
"concreteType": "DocumentEdge",
"kind": "LinkedField",
"name": "edges",
"plural": true,
@@ -277,7 +277,7 @@ v18 = [
{
"alias": null,
"args": null,
"concreteType": "Policy",
"concreteType": "Document",
"kind": "LinkedField",
"name": "node",
"plural": false,
@@ -387,11 +387,11 @@ return {
"storageKey": null
},
{
"alias": "policies",
"alias": "documents",
"args": null,
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "__Risk__policies_connection",
"name": "__Risk__documents_connection",
"plural": false,
"selections": (v18/*: any*/),
"storageKey": null
@@ -469,21 +469,21 @@ return {
{
"alias": null,
"args": (v20/*: any*/),
"concreteType": "PolicyConnection",
"concreteType": "DocumentConnection",
"kind": "LinkedField",
"name": "policies",
"name": "documents",
"plural": false,
"selections": (v18/*: any*/),
"storageKey": "policies(first:100)"
"storageKey": "documents(first:100)"
},
{
"alias": null,
"args": (v20/*: any*/),
"filters": null,
"handle": "connection",
"key": "Risk__policies",
"key": "Risk__documents",
"kind": "LinkedHandle",
"name": "policies"
"name": "documents"
},
{
"alias": null,
@@ -514,7 +514,7 @@ return {
]
},
"params": {
"cacheID": "487765d92cad8c0915ad4fee24d7e702",
"cacheID": "9d1057cf6eac37c07ed841a80a4604b9",
"id": null,
"metadata": {
"connection": [
@@ -533,7 +533,7 @@ return {
"direction": "forward",
"path": [
"node",
"policies"
"documents"
]
},
{
@@ -549,11 +549,11 @@ return {
},
"name": "ShowRiskViewQuery",
"operationKind": "query",
"text": "query ShowRiskViewQuery(\n $riskId: ID!\n) {\n node(id: $riskId) {\n __typename\n id\n ... on Risk {\n name\n description\n treatment\n owner {\n id\n fullName\n }\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n createdAt\n updatedAt\n measures(first: 100) {\n edges {\n node {\n id\n name\n description\n category\n createdAt\n state\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n policies(first: 100) {\n edges {\n node {\n id\n title\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n controls(first: 100) {\n edges {\n node {\n id\n referenceId\n name\n description\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
"text": "query ShowRiskViewQuery(\n $riskId: ID!\n) {\n node(id: $riskId) {\n __typename\n id\n ... on Risk {\n name\n description\n treatment\n owner {\n id\n fullName\n }\n inherentLikelihood\n inherentImpact\n residualLikelihood\n residualImpact\n note\n createdAt\n updatedAt\n measures(first: 100) {\n edges {\n node {\n id\n name\n description\n category\n createdAt\n state\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n documents(first: 100) {\n edges {\n node {\n id\n title\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n controls(first: 100) {\n edges {\n node {\n id\n referenceId\n name\n description\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
}
};
})();
(node as any).hash = "b8506a3dd8980cd16b5344b990471533";
(node as any).hash = "96763bbbebd3aa29a02fcf1e6e782293";
export default node;

View File

@@ -224,18 +224,18 @@ interface Task {
badges?: Badge[];
}
function TaskCard({ task, onClick, onToggleState }: {
task: Task;
function TaskCard({ task, onClick, onToggleState }: {
task: Task;
onClick?: (task: Task) => void;
onToggleState?: (taskId: string, newState: TaskState) => void;
}) {
return (
<div
<div
className="flex justify-between items-center px-6 py-3 border-b border-gray-100 hover:bg-gray-50 cursor-pointer"
onClick={() => onClick && onClick(task)}
>
<div className="flex gap-4 items-center">
<div
<div
className="flex items-center cursor-pointer"
onClick={(e) => {
e.stopPropagation();
@@ -258,11 +258,11 @@ function TaskCard({ task, onClick, onToggleState }: {
<span className={`text-sm font-medium ${task.state === "DONE" ? "text-gray-500 line-through" : "text-gray-900"}`}>
{task.name}
</span>
<Badge
variant="outline"
className={`text-xs px-1.5 py-0.5 rounded-lg flex items-center gap-1
${task.state === "TODO"
? "bg-green-50 text-green-700 border-green-200"
<Badge
variant="outline"
className={`text-xs px-1.5 py-0.5 rounded-lg flex items-center gap-1
${task.state === "TODO"
? "bg-green-50 text-green-700 border-green-200"
: "bg-gray-50 text-gray-700 border-gray-200"}
`}
>
@@ -282,7 +282,7 @@ function TaskCard({ task, onClick, onToggleState }: {
)}
</div>
</div>
<div className="flex items-center gap-4">
<div className="flex gap-2">
{task.badges && task.badges.map((badge) => (
@@ -324,19 +324,19 @@ function ListTaskContent({
organizationQuery,
organizationQueryRef
);
const organization = data.node;
const [isNewTaskOpen, setIsNewTaskOpen] = useState(false);
// Get organization members
const members = organizationData.organization?.peoples?.edges.map(edge => edge.node) || [];
// Fetch measures
const environment = useRelayEnvironment();
const [measures, setMeasures] = useState<Array<{id: string, name: string, category: string, description?: string, state?: string}>>([]);
const [measuresLoading, setMeasuresLoading] = useState(false);
const [measureSearchQuery, setMeasureSearchQuery] = useState("");
// Task form state
const [taskTitle, setTaskTitle] = useState("");
const [taskDescription, setTaskDescription] = useState("");
@@ -409,7 +409,7 @@ function ListTaskContent({
// Function to convert timeEstimate to ISO8601 duration
const convertToISODuration = (value: number | null, unit: string): string | null => {
if (value === null || value <= 0) return null;
switch (unit) {
case "minutes":
return `PT${value}M`;
@@ -495,7 +495,7 @@ function ListTaskContent({
description="Track your assigned compliance tasks and keep progress on track."
actions={
<>
<Button
<Button
className="bg-gray-900 text-white hover:bg-gray-800 gap-1.5"
onClick={() => setIsNewTaskOpen(true)}
>
@@ -539,15 +539,15 @@ function ListTaskContent({
</TabsTrigger>
</TabsList>
</div>
<TabsContent value="todo">
{todoTasks.length > 0 ? (
todoTasks.map((task) => (
<TaskCard
key={task.id}
task={task}
<TaskCard
key={task.id}
task={task}
onClick={handleTaskClick}
onToggleState={handleToggleTaskState}
onToggleState={handleToggleTaskState}
/>
))
) : (
@@ -556,13 +556,13 @@ function ListTaskContent({
</div>
)}
</TabsContent>
<TabsContent value="done">
{doneTasks.length > 0 ? (
doneTasks.map((task) => (
<TaskCard
key={task.id}
task={task}
<TaskCard
key={task.id}
task={task}
onClick={handleTaskClick}
onToggleState={handleToggleTaskState}
/>
@@ -573,13 +573,13 @@ function ListTaskContent({
</div>
)}
</TabsContent>
<TabsContent value="all">
{allTasks.length > 0 ? (
allTasks.map((task) => (
<TaskCard
key={task.id}
task={task}
<TaskCard
key={task.id}
task={task}
onClick={handleTaskClick}
onToggleState={handleToggleTaskState}
/>
@@ -627,25 +627,25 @@ function ListTaskContent({
onChange={(e) => setTaskDescription(e.target.value)}
/>
</div>
{/* Right Column - Properties */}
<div className="w-[400px] p-6">
<h3 className="text-base font-medium text-gray-900 mb-4">Properties</h3>
<div className="space-y-4">
{/* Status */}
<div className="flex justify-between items-center border-b border-[rgba(2,42,2,0.08)] py-3">
<Label className="text-sm font-medium text-gray-500">Status</Label>
<div className="bg-[rgba(0,39,0,0.05)] px-[10px] py-[6px] rounded-lg flex items-center gap-1.5">
<img
src="/images/radio-unchecked.svg"
alt="Radio"
<img
src="/images/radio-unchecked.svg"
alt="Radio"
className="w-4 h-4"
/>
<span className="text-sm font-medium">To do</span>
</div>
</div>
{/* Assignee */}
<div className="flex justify-between items-center border-b border-[rgba(2,42,2,0.08)] py-3">
<Label className="text-sm font-medium text-gray-500">Assignee</Label>
@@ -671,16 +671,16 @@ function ListTaskContent({
</div>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[220px] max-h-[300px] overflow-y-auto">
<DropdownMenuItem
<DropdownMenuItem
className="flex items-center gap-2 cursor-pointer"
onClick={() => setAssignee(null)}
>
<User className="h-4 w-4 text-gray-500" />
<span>Unassigned</span>
</DropdownMenuItem>
{members.map(member => (
<DropdownMenuItem
<DropdownMenuItem
key={member.id}
className="flex items-center gap-2 cursor-pointer"
onClick={() => setAssignee({id: member.id, fullName: member.fullName})}
@@ -696,7 +696,7 @@ function ListTaskContent({
</DropdownMenuContent>
</DropdownMenu>
</div>
{/* Measure */}
<div className="flex justify-between items-center border-b border-[rgba(2,42,2,0.08)] py-3">
<Label className="text-sm font-medium text-gray-500">Measure</Label>
@@ -723,8 +723,8 @@ function ListTaskContent({
/>
</div>
</div>
<DropdownMenuItem
<DropdownMenuItem
className="flex items-center gap-2 cursor-pointer"
onClick={() => {
setSelectedMeasure(null);
@@ -733,14 +733,14 @@ function ListTaskContent({
>
<span>No measure</span>
</DropdownMenuItem>
{measuresLoading ? (
<div className="p-3 text-center text-sm text-gray-500">
Loading measures...
</div>
) : filteredMeasures.length > 0 ? (
filteredMeasures.map(measure => (
<DropdownMenuItem
<DropdownMenuItem
key={measure.id}
className="flex items-start gap-2 cursor-pointer py-2"
onClick={() => {
@@ -764,15 +764,15 @@ function ListTaskContent({
</DropdownMenuContent>
</DropdownMenu>
</div>
{/* Time estimate */}
<div className="flex justify-between items-center border-b border-[rgba(2,42,2,0.08)] py-3">
<Label className="text-sm font-medium text-gray-500">Time estimate</Label>
<div className="flex items-center gap-2">
{timeEstimate === null ? (
<Button
variant="ghost"
size="sm"
<Button
variant="ghost"
size="sm"
className="h-8 px-2"
onClick={() => setTimeEstimate(0)}
>
@@ -789,9 +789,9 @@ function ListTaskContent({
/>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="sm"
<Button
variant="outline"
size="sm"
className="h-8 flex items-center gap-1"
>
<span>{timeUnit}</span>
@@ -813,10 +813,10 @@ function ListTaskContent({
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Button
variant="ghost"
size="sm"
className="h-8 p-0"
<Button
variant="ghost"
size="sm"
className="h-8 p-0"
onClick={() => setTimeEstimate(null)}
>
<X className="w-4 h-4" />
@@ -831,14 +831,14 @@ function ListTaskContent({
{/* Modal Footer */}
<div className="flex justify-between items-center px-6 py-4 border-t border-[rgba(2,42,2,0.08)]">
<Button
variant="outline"
<Button
variant="outline"
className="h-8 flex items-center gap-1.5 border-[rgba(2,42,2,0.08)]"
>
<img src="/images/attachment.svg" alt="Attachment" className="w-4 h-4" />
Upload evidence
</Button>
<div className="flex items-center gap-2">
<Button
variant="outline"

View File

@@ -1,9 +1,9 @@
/* Policy Content Styles */
.policy-content {
/* Document Content Styles */
.document-content {
line-height: 1.6;
}
.policy-content h1 {
.document-content h1 {
font-size: 2rem;
font-weight: 700;
margin-top: 1.5rem;
@@ -11,7 +11,7 @@
color: hsl(var(--foreground));
}
.policy-content h2 {
.document-content h2 {
font-size: 1.5rem;
font-weight: 600;
margin-top: 1.5rem;
@@ -19,7 +19,7 @@
color: hsl(var(--foreground));
}
.policy-content h3 {
.document-content h3 {
font-size: 1.25rem;
font-weight: 600;
margin-top: 1.25rem;
@@ -27,7 +27,7 @@
color: hsl(var(--foreground));
}
.policy-content h4 {
.document-content h4 {
font-size: 1.125rem;
font-weight: 600;
margin-top: 1rem;
@@ -35,38 +35,38 @@
color: hsl(var(--foreground));
}
.policy-content p {
.document-content p {
margin-bottom: 1rem;
}
.policy-content ul,
.policy-content ol {
.document-content ul,
.document-content ol {
margin-left: 1.5rem;
margin-bottom: 1rem;
}
.policy-content ul {
.document-content ul {
list-style-type: disc;
}
.policy-content ol {
.document-content ol {
list-style-type: decimal;
}
.policy-content li {
.document-content li {
margin-bottom: 0.5rem;
}
.policy-content a {
.document-content a {
color: hsl(var(--primary));
text-decoration: underline;
}
.policy-content a:hover {
.document-content a:hover {
text-decoration: none;
}
.policy-content blockquote {
.document-content blockquote {
border-left: 4px solid hsl(var(--solid-b));
padding-left: 1rem;
margin-left: 0;
@@ -75,7 +75,7 @@
color: hsl(var(--tertiary));
}
.policy-content code {
.document-content code {
font-family: monospace;
background-color: hsl(var(--invert-bg));
padding: 0.2rem 0.4rem;
@@ -83,7 +83,7 @@
font-size: 0.875em;
}
.policy-content pre {
.document-content pre {
background-color: hsl(var(--invert-bg));
padding: 1rem;
border-radius: 0.5rem;
@@ -91,37 +91,37 @@
margin-bottom: 1rem;
}
.policy-content pre code {
.document-content pre code {
background-color: transparent;
padding: 0;
border-radius: 0;
}
.policy-content table {
.document-content table {
width: 100%;
border-collapse: collapse;
margin-bottom: 1rem;
}
.policy-content th,
.policy-content td {
.document-content th,
.document-content td {
border: 1px solid hsl(var(--solid-b));
padding: 0.5rem;
}
.policy-content th {
.document-content th {
background-color: hsl(var(--invert-bg));
font-weight: 600;
}
.policy-content img {
.document-content img {
max-width: 100%;
height: auto;
border-radius: 0.5rem;
}
.policy-content hr {
.document-content hr {
border: 0;
border-top: 1px solid hsl(var(--solid-b));
margin: 1.5rem 0;
}
}