Change document version
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -25,7 +25,7 @@ import type { ShowDocumentViewQuery } from "./__generated__/ShowDocumentViewQuer
|
||||
import { ShowDocumentViewPublishMutation } from "./__generated__/ShowDocumentViewPublishMutation.graphql";
|
||||
import { ShowDocumentViewCreateDraftMutation } from "./__generated__/ShowDocumentViewCreateDraftMutation.graphql";
|
||||
import { ShowDocumentViewUpdateDocumentMutation } from "./__generated__/ShowDocumentViewUpdateDocumentMutation.graphql";
|
||||
import { ShowDocumentViewUpdateDocumentTypeMutation } from "./__generated__/ShowDocumentViewUpdateDocumentTypeMutation.graphql";
|
||||
import { ShowDocumentViewGenerateChangelogMutation } from "./__generated__/ShowDocumentViewGenerateChangelogMutation.graphql";
|
||||
import type { DocumentType } from "./__generated__/DocumentListViewCreateMutation.graphql";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
@@ -90,6 +90,10 @@ const documentViewQuery = graphql`
|
||||
content
|
||||
changelog
|
||||
publishedAt
|
||||
title
|
||||
owner {
|
||||
fullName
|
||||
}
|
||||
publishedBy {
|
||||
fullName
|
||||
}
|
||||
@@ -114,6 +118,7 @@ const publishDocumentVersionMutation = graphql`
|
||||
id
|
||||
status
|
||||
publishedAt
|
||||
changelog
|
||||
publishedBy {
|
||||
fullName
|
||||
}
|
||||
@@ -144,6 +149,7 @@ const updateDocumentMutation = graphql`
|
||||
document {
|
||||
id
|
||||
documentType
|
||||
title
|
||||
owner {
|
||||
id
|
||||
fullName
|
||||
@@ -154,6 +160,14 @@ const updateDocumentMutation = graphql`
|
||||
}
|
||||
`;
|
||||
|
||||
const generateChangelogMutation = graphql`
|
||||
mutation ShowDocumentViewGenerateChangelogMutation($input: GenerateDocumentChangelogInput!) {
|
||||
generateDocumentChangelog(input: $input) {
|
||||
changelog
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
function ShowDocumentContent({
|
||||
queryRef,
|
||||
}: {
|
||||
@@ -176,8 +190,18 @@ function ShowDocumentContent({
|
||||
const [isSignaturesModalOpen, setIsSignaturesModalOpen] = useState(false);
|
||||
const [isEditingOwner, setIsEditingOwner] = useState(false);
|
||||
const [isEditingType, setIsEditingType] = useState(false);
|
||||
const [isEditingTitle, setIsEditingTitle] = useState(false);
|
||||
const [editedTitle, setEditedTitle] = useState(documentValue.title || '');
|
||||
const [isPublishDialogOpen, setIsPublishDialogOpen] = useState(false);
|
||||
const [publishChangelog, setPublishChangelog] = useState('');
|
||||
const [isGeneratingChangelog, setIsGeneratingChangelog] = useState(false);
|
||||
const printContentRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Keep editedTitle in sync with documentValue.title
|
||||
useEffect(() => {
|
||||
setEditedTitle(documentValue.title || '');
|
||||
}, [documentValue.title]);
|
||||
|
||||
const [publishDraft, isPublishInFlight] =
|
||||
useMutation<ShowDocumentViewPublishMutation>(publishDocumentVersionMutation);
|
||||
const [createDraft, isCreateDraftInFlight] =
|
||||
@@ -186,6 +210,7 @@ function ShowDocumentContent({
|
||||
);
|
||||
const [updateDocument, isUpdatingDocument] =
|
||||
useMutation<ShowDocumentViewUpdateDocumentMutation>(updateDocumentMutation);
|
||||
const [generateChangelog] = useMutation<ShowDocumentViewGenerateChangelogMutation>(generateChangelogMutation);
|
||||
|
||||
const latestVersionEdge = documentValue.latestVersion?.edges[0];
|
||||
const latestVersionNode = latestVersionEdge?.node;
|
||||
@@ -300,12 +325,57 @@ function ShowDocumentContent({
|
||||
|
||||
// Navigate to publish flow
|
||||
const handlePublish = useCallback(() => {
|
||||
setIsPublishDialogOpen(true);
|
||||
setPublishChangelog("");
|
||||
|
||||
// Generate changelog
|
||||
setIsGeneratingChangelog(true);
|
||||
|
||||
generateChangelog({
|
||||
variables: {
|
||||
input: {
|
||||
documentId: documentValue.id,
|
||||
},
|
||||
},
|
||||
onCompleted: (response, errors) => {
|
||||
setIsGeneratingChangelog(false);
|
||||
if (errors) {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: errors[0]?.message || "An unknown error occurred",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const generatedChangelog = response.generateDocumentChangelog.changelog;
|
||||
setPublishChangelog(prev => {
|
||||
if (prev.trim()) {
|
||||
return `${prev}\n${generatedChangelog}`;
|
||||
}
|
||||
return generatedChangelog;
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
setIsGeneratingChangelog(false);
|
||||
toast({
|
||||
title: "Error",
|
||||
description: error.message || "An unknown error occurred",
|
||||
variant: "destructive",
|
||||
});
|
||||
},
|
||||
});
|
||||
}, [documentValue.id, generateChangelog, toast]);
|
||||
|
||||
// Confirm publish
|
||||
const confirmPublish = useCallback(() => {
|
||||
if (!documentValue.id) return;
|
||||
|
||||
publishDraft({
|
||||
variables: {
|
||||
input: {
|
||||
documentId: documentValue.id,
|
||||
changelog: publishChangelog,
|
||||
},
|
||||
},
|
||||
onCompleted: (_, errors) => {
|
||||
@@ -323,6 +393,7 @@ function ShowDocumentContent({
|
||||
description: `The document has been published successfully`,
|
||||
});
|
||||
|
||||
setIsPublishDialogOpen(false);
|
||||
// Reload the query to refresh the data
|
||||
loadQuery({ documentId: documentValue.id, organizationId: organizationId! });
|
||||
},
|
||||
@@ -334,7 +405,7 @@ function ShowDocumentContent({
|
||||
});
|
||||
},
|
||||
});
|
||||
}, [documentValue.id, publishDraft, toast, loadQuery]);
|
||||
}, [documentValue.id, publishDraft, toast, loadQuery, publishChangelog, organizationId]);
|
||||
|
||||
// Open version history modal
|
||||
const handleVersionHistoryClick = useCallback(() => {
|
||||
@@ -658,7 +729,84 @@ function ShowDocumentContent({
|
||||
<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> {documentValue.title}
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">Document Title:</span>
|
||||
{isEditingTitle ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="text"
|
||||
className="h-9 w-[250px] rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm transition-colors"
|
||||
value={editedTitle}
|
||||
onChange={(e) => setEditedTitle(e.target.value)}
|
||||
placeholder="Enter document title"
|
||||
/>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
if (editedTitle.trim()) {
|
||||
updateDocument({
|
||||
variables: {
|
||||
input: {
|
||||
id: documentValue.id,
|
||||
title: editedTitle.trim(),
|
||||
},
|
||||
},
|
||||
onCompleted: (_, errors) => {
|
||||
if (errors) {
|
||||
toast({
|
||||
title: "Error updating title",
|
||||
description: errors[0]?.message || "An unknown error occurred",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
toast({
|
||||
title: "Success",
|
||||
description: "Document title updated successfully",
|
||||
});
|
||||
setIsEditingTitle(false);
|
||||
loadQuery({ documentId: documentValue.id, organizationId: organizationId! });
|
||||
},
|
||||
onError: (error) => {
|
||||
toast({
|
||||
title: "Error updating title",
|
||||
description: error.message || "An unknown error occurred",
|
||||
variant: "destructive",
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
disabled={!editedTitle.trim() || isUpdatingDocument}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setIsEditingTitle(false);
|
||||
setEditedTitle(documentValue.title || '');
|
||||
}}
|
||||
disabled={isUpdatingDocument}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2">
|
||||
<span>{documentValue.title}</span>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setIsEditingTitle(true)}
|
||||
>
|
||||
Change
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-medium">Version:</span> {latestVersionNode.version || "N/A"}
|
||||
@@ -826,6 +974,50 @@ function ShowDocumentContent({
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Publish Confirmation Dialog */}
|
||||
<Dialog open={isPublishDialogOpen} onOpenChange={setIsPublishDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Publish Document</DialogTitle>
|
||||
<DialogDescription>
|
||||
Please review and edit the changelog before publishing the document.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="py-4">
|
||||
<Label htmlFor="changelog">Changelog</Label>
|
||||
<textarea
|
||||
id="changelog"
|
||||
className="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
value={publishChangelog}
|
||||
onChange={(e) => setPublishChangelog(e.target.value)}
|
||||
placeholder="Enter changelog message"
|
||||
/>
|
||||
{isGeneratingChangelog && (
|
||||
<div className="mt-2 flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent"></div>
|
||||
<span>Generating changelog...</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setIsPublishDialogOpen(false)}
|
||||
disabled={isPublishInFlight}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
onClick={confirmPublish}
|
||||
disabled={isPublishInFlight || !publishChangelog.trim()}
|
||||
>
|
||||
{isPublishInFlight ? "Publishing..." : "Publish"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</PageTemplate>
|
||||
);
|
||||
}
|
||||
@@ -834,10 +1026,26 @@ export default function ShowDocumentView() {
|
||||
const [queryRef, loadQuery] =
|
||||
useQueryLoader<ShowDocumentViewQuery>(documentViewQuery);
|
||||
const { documentId, organizationId } = useParams();
|
||||
const { toast } = useToast();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
loadQuery({ documentId: documentId!, organizationId: organizationId! });
|
||||
}, [loadQuery, documentId, organizationId]);
|
||||
if (!organizationId || !documentId) {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Invalid document or organization ID",
|
||||
variant: "destructive",
|
||||
});
|
||||
navigate("/");
|
||||
return;
|
||||
}
|
||||
|
||||
loadQuery({ documentId, organizationId });
|
||||
}, [loadQuery, documentId, organizationId, toast, navigate]);
|
||||
|
||||
if (!organizationId || !documentId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!queryRef) {
|
||||
return <ShowDocumentViewSkeleton />;
|
||||
|
||||
@@ -22,9 +22,13 @@ export const documentVersionsFragment = graphql`
|
||||
version
|
||||
status
|
||||
content
|
||||
title
|
||||
changelog
|
||||
publishedAt
|
||||
updatedAt
|
||||
owner {
|
||||
fullName
|
||||
}
|
||||
publishedBy {
|
||||
fullName
|
||||
}
|
||||
@@ -122,6 +126,14 @@ export function VersionHistoryModal({
|
||||
•{" "}
|
||||
{formatDateTime(version.publishedAt || version.updatedAt)}
|
||||
</div>
|
||||
{version.changelog && (
|
||||
<div className="text-xs text-tertiary mt-1">
|
||||
Changelog: {version.changelog}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-xs text-tertiary mt-1">
|
||||
Owner: {version.owner?.fullName || "Unknown"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -130,8 +142,12 @@ export function VersionHistoryModal({
|
||||
|
||||
{/* Content Area */}
|
||||
<div className="flex-1 p-6 relative overflow-y-auto">
|
||||
<h2 className="text-2xl font-semibold mb-6">{data.title}</h2>
|
||||
|
||||
{selectedVersion && (
|
||||
<h2 className="text-2xl font-semibold mb-6">
|
||||
{versions.find((v) => v.version === selectedVersion)
|
||||
?.title || data.title}
|
||||
</h2>
|
||||
)}
|
||||
<div className="prose prose-olive max-w-none">
|
||||
{selectedVersion && (
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}>
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @generated SignedSource<<7743b633410bdb28ce017cc0799f2df4>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type GenerateDocumentChangelogInput = {
|
||||
documentId: string;
|
||||
};
|
||||
export type ShowDocumentViewGenerateChangelogMutation$variables = {
|
||||
input: GenerateDocumentChangelogInput;
|
||||
};
|
||||
export type ShowDocumentViewGenerateChangelogMutation$data = {
|
||||
readonly generateDocumentChangelog: {
|
||||
readonly changelog: string;
|
||||
};
|
||||
};
|
||||
export type ShowDocumentViewGenerateChangelogMutation = {
|
||||
response: ShowDocumentViewGenerateChangelogMutation$data;
|
||||
variables: ShowDocumentViewGenerateChangelogMutation$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "input"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"alias": null,
|
||||
"args": [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "input",
|
||||
"variableName": "input"
|
||||
}
|
||||
],
|
||||
"concreteType": "GenerateDocumentChangelogPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "generateDocumentChangelog",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "changelog",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "ShowDocumentViewGenerateChangelogMutation",
|
||||
"selections": (v1/*: any*/),
|
||||
"type": "Mutation",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "ShowDocumentViewGenerateChangelogMutation",
|
||||
"selections": (v1/*: any*/)
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "8051b5412b1d2d73a7fe686890e86f41",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "ShowDocumentViewGenerateChangelogMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation ShowDocumentViewGenerateChangelogMutation(\n $input: GenerateDocumentChangelogInput!\n) {\n generateDocumentChangelog(input: $input) {\n changelog\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "60be598c9c528b2173be7be580057ea7";
|
||||
|
||||
export default node;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<91076d34daad785f7fce9f5a2cbc4018>>
|
||||
* @generated SignedSource<<f67241da996f7e38c84c64b99084ed97>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -11,6 +11,7 @@
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type DocumentStatus = "DRAFT" | "PUBLISHED";
|
||||
export type PublishDocumentVersionInput = {
|
||||
changelog?: string | null | undefined;
|
||||
documentId: string;
|
||||
};
|
||||
export type ShowDocumentViewPublishMutation$variables = {
|
||||
@@ -23,6 +24,7 @@ export type ShowDocumentViewPublishMutation$data = {
|
||||
readonly id: string;
|
||||
};
|
||||
readonly documentVersion: {
|
||||
readonly changelog: string;
|
||||
readonly id: string;
|
||||
readonly publishedAt: string | null | undefined;
|
||||
readonly publishedBy: {
|
||||
@@ -93,6 +95,13 @@ v5 = {
|
||||
"storageKey": null
|
||||
},
|
||||
v6 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "changelog",
|
||||
"storageKey": null
|
||||
},
|
||||
v7 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
@@ -126,6 +135,7 @@ return {
|
||||
(v2/*: any*/),
|
||||
(v4/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -134,7 +144,7 @@ return {
|
||||
"name": "publishedBy",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v6/*: any*/)
|
||||
(v7/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
@@ -174,6 +184,7 @@ return {
|
||||
(v2/*: any*/),
|
||||
(v4/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -182,7 +193,7 @@ return {
|
||||
"name": "publishedBy",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v6/*: any*/),
|
||||
(v7/*: any*/),
|
||||
(v2/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
@@ -196,16 +207,16 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "794539aab3ddce5d004e72d10b980ca4",
|
||||
"cacheID": "9e097de4f6f61bd4762e57b4863c573b",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "ShowDocumentViewPublishMutation",
|
||||
"operationKind": "mutation",
|
||||
"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"
|
||||
"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 changelog\n publishedBy {\n fullName\n id\n }\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "66e590251b58966c2ac09625759332f7";
|
||||
(node as any).hash = "9b2033c7f39d178fb9a25828ade6af3c";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<bf950636055ed83dd68cd6e513a4d83e>>
|
||||
* @generated SignedSource<<edd3d7d537e2ed956853a8be083189fa>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -30,11 +30,15 @@ export type ShowDocumentViewQuery$data = {
|
||||
readonly content: string;
|
||||
readonly createdAt: string;
|
||||
readonly id: string;
|
||||
readonly owner: {
|
||||
readonly fullName: string;
|
||||
};
|
||||
readonly publishedAt: string | null | undefined;
|
||||
readonly publishedBy: {
|
||||
readonly fullName: string;
|
||||
} | null | undefined;
|
||||
readonly status: DocumentStatus;
|
||||
readonly title: string;
|
||||
readonly updatedAt: string;
|
||||
readonly version: number;
|
||||
};
|
||||
@@ -212,20 +216,23 @@ v19 = {
|
||||
"name": "publishedAt",
|
||||
"storageKey": null
|
||||
},
|
||||
v20 = {
|
||||
v20 = [
|
||||
(v11/*: any*/)
|
||||
],
|
||||
v21 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
v21 = {
|
||||
v22 = {
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 100
|
||||
},
|
||||
v22 = [
|
||||
(v21/*: any*/),
|
||||
v23 = [
|
||||
(v22/*: any*/),
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "orderBy",
|
||||
@@ -235,14 +242,14 @@ v22 = [
|
||||
}
|
||||
}
|
||||
],
|
||||
v23 = {
|
||||
v24 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
},
|
||||
v24 = {
|
||||
v25 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
@@ -267,23 +274,33 @@ v24 = {
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
v25 = [
|
||||
v26 = [
|
||||
(v11/*: any*/),
|
||||
(v4/*: any*/)
|
||||
],
|
||||
v26 = {
|
||||
v27 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "People",
|
||||
"kind": "LinkedField",
|
||||
"name": "publishedBy",
|
||||
"plural": false,
|
||||
"selections": (v25/*: any*/),
|
||||
"selections": (v26/*: any*/),
|
||||
"storageKey": null
|
||||
},
|
||||
v27 = [
|
||||
(v21/*: any*/)
|
||||
];
|
||||
v28 = [
|
||||
(v22/*: any*/)
|
||||
],
|
||||
v29 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "People",
|
||||
"kind": "LinkedField",
|
||||
"name": "owner",
|
||||
"plural": false,
|
||||
"selections": (v26/*: any*/),
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
@@ -374,6 +391,17 @@ return {
|
||||
(v17/*: any*/),
|
||||
(v18/*: any*/),
|
||||
(v19/*: any*/),
|
||||
(v5/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "People",
|
||||
"kind": "LinkedField",
|
||||
"name": "owner",
|
||||
"plural": false,
|
||||
"selections": (v20/*: any*/),
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -381,9 +409,7 @@ return {
|
||||
"kind": "LinkedField",
|
||||
"name": "publishedBy",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v11/*: any*/)
|
||||
],
|
||||
"selections": (v20/*: any*/),
|
||||
"storageKey": null
|
||||
},
|
||||
(v7/*: any*/),
|
||||
@@ -422,7 +448,7 @@ return {
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v20/*: any*/),
|
||||
(v21/*: any*/),
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
@@ -430,7 +456,7 @@ return {
|
||||
(v2/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v22/*: any*/),
|
||||
"args": (v23/*: any*/),
|
||||
"concreteType": "PeopleConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "peoples",
|
||||
@@ -455,21 +481,21 @@ return {
|
||||
(v4/*: any*/),
|
||||
(v11/*: any*/),
|
||||
(v12/*: any*/),
|
||||
(v20/*: any*/)
|
||||
(v21/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v23/*: any*/)
|
||||
(v24/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v24/*: any*/)
|
||||
(v25/*: any*/)
|
||||
],
|
||||
"storageKey": "peoples(first:100,orderBy:{\"direction\":\"ASC\",\"field\":\"FULL_NAME\"})"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v22/*: any*/),
|
||||
"args": (v23/*: any*/),
|
||||
"filters": [
|
||||
"orderBy"
|
||||
],
|
||||
@@ -493,7 +519,7 @@ return {
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v20/*: any*/),
|
||||
(v21/*: any*/),
|
||||
(v4/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
@@ -540,10 +566,10 @@ return {
|
||||
(v16/*: any*/),
|
||||
(v19/*: any*/),
|
||||
(v8/*: any*/),
|
||||
(v26/*: any*/),
|
||||
(v27/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v27/*: any*/),
|
||||
"args": (v28/*: any*/),
|
||||
"concreteType": "DocumentVersionSignatureConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "signatures",
|
||||
@@ -594,7 +620,7 @@ return {
|
||||
"kind": "LinkedField",
|
||||
"name": "signedBy",
|
||||
"plural": false,
|
||||
"selections": (v25/*: any*/),
|
||||
"selections": (v26/*: any*/),
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
@@ -604,24 +630,24 @@ return {
|
||||
"kind": "LinkedField",
|
||||
"name": "requestedBy",
|
||||
"plural": false,
|
||||
"selections": (v25/*: any*/),
|
||||
"selections": (v26/*: any*/),
|
||||
"storageKey": null
|
||||
},
|
||||
(v20/*: any*/)
|
||||
(v21/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v23/*: any*/)
|
||||
(v24/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v24/*: any*/)
|
||||
(v25/*: any*/)
|
||||
],
|
||||
"storageKey": "signatures(first:100)"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v27/*: any*/),
|
||||
"args": (v28/*: any*/),
|
||||
"filters": null,
|
||||
"handle": "connection",
|
||||
"key": "SignaturesModal_documentVersions_signatures",
|
||||
@@ -671,10 +697,12 @@ return {
|
||||
(v15/*: any*/),
|
||||
(v16/*: any*/),
|
||||
(v17/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v18/*: any*/),
|
||||
(v19/*: any*/),
|
||||
(v8/*: any*/),
|
||||
(v26/*: any*/)
|
||||
(v29/*: any*/),
|
||||
(v27/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
@@ -714,7 +742,9 @@ return {
|
||||
(v17/*: any*/),
|
||||
(v18/*: any*/),
|
||||
(v19/*: any*/),
|
||||
(v26/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v29/*: any*/),
|
||||
(v27/*: any*/),
|
||||
(v7/*: any*/),
|
||||
(v8/*: any*/)
|
||||
],
|
||||
@@ -736,16 +766,16 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "a1b25325fb4a764d130253f86435efcb",
|
||||
"cacheID": "7e1dfac8673eeb68f1d3821db3ca95c2",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "ShowDocumentViewQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query ShowDocumentViewQuery(\n $documentId: ID!\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n name\n ...PeopleSelector_organization\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 documentType\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 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\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"
|
||||
"text": "query ShowDocumentViewQuery(\n $documentId: ID!\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n name\n ...PeopleSelector_organization\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 documentType\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 title\n owner {\n fullName\n id\n }\n publishedBy {\n fullName\n id\n }\n createdAt\n updatedAt\n }\n }\n }\n }\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\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 title\n changelog\n publishedAt\n updatedAt\n owner {\n fullName\n id\n }\n publishedBy {\n fullName\n id\n }\n }\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "96c84ddc6ada95da2302068bae68f825";
|
||||
(node as any).hash = "41461d6b97a3672ae58a36fbb5615489";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<f884c800d6c27056d14eec073a481151>>
|
||||
* @generated SignedSource<<5cf1d2c84b94cf4c7d35965f67b36191>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -31,6 +31,7 @@ export type ShowDocumentViewUpdateDocumentMutation$data = {
|
||||
readonly id: string;
|
||||
readonly primaryEmailAddress: string;
|
||||
};
|
||||
readonly title: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -85,6 +86,13 @@ v2 = [
|
||||
"name": "documentType",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "title",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -136,16 +144,16 @@ return {
|
||||
"selections": (v2/*: any*/)
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "62cd235bd1903d80012364fbc3358054",
|
||||
"cacheID": "81d866e2f2de8bc1d7d440bfb2c66144",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "ShowDocumentViewUpdateDocumentMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation ShowDocumentViewUpdateDocumentMutation(\n $input: UpdateDocumentInput!\n) {\n updateDocument(input: $input) {\n document {\n id\n documentType\n owner {\n id\n fullName\n primaryEmailAddress\n }\n }\n }\n}\n"
|
||||
"text": "mutation ShowDocumentViewUpdateDocumentMutation(\n $input: UpdateDocumentInput!\n) {\n updateDocument(input: $input) {\n document {\n id\n documentType\n title\n owner {\n id\n fullName\n primaryEmailAddress\n }\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "094ff9193be9f023152588380f5114b5";
|
||||
(node as any).hash = "acaf0d38623ccc096f19c9d6c3e05c69";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<a88582302d627481e4214530f287e233>>
|
||||
* @generated SignedSource<<00c4778ab72567e2c573d98bdbbc4c5f>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -22,11 +22,15 @@ export type VersionHistoryModal_documentVersions$data = {
|
||||
readonly changelog: string;
|
||||
readonly content: string;
|
||||
readonly id: string;
|
||||
readonly owner: {
|
||||
readonly fullName: string;
|
||||
};
|
||||
readonly publishedAt: string | null | undefined;
|
||||
readonly publishedBy: {
|
||||
readonly fullName: string;
|
||||
} | null | undefined;
|
||||
readonly status: DocumentStatus;
|
||||
readonly title: string;
|
||||
readonly updatedAt: string;
|
||||
readonly version: number;
|
||||
};
|
||||
@@ -40,7 +44,14 @@ export type VersionHistoryModal_documentVersions$key = {
|
||||
};
|
||||
|
||||
const node: ReaderFragment = (function(){
|
||||
var v0 = [
|
||||
var v0 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "title",
|
||||
"storageKey": null
|
||||
},
|
||||
v1 = [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -48,30 +59,25 @@ var v0 = [
|
||||
"name": "fullName",
|
||||
"storageKey": null
|
||||
}
|
||||
];
|
||||
],
|
||||
v2 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "People",
|
||||
"kind": "LinkedField",
|
||||
"name": "owner",
|
||||
"plural": false,
|
||||
"selections": (v1/*: any*/),
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"argumentDefinitions": [],
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "VersionHistoryModal_documentVersions",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "title",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "People",
|
||||
"kind": "LinkedField",
|
||||
"name": "owner",
|
||||
"plural": false,
|
||||
"selections": (v0/*: any*/),
|
||||
"storageKey": null
|
||||
},
|
||||
(v0/*: any*/),
|
||||
(v2/*: any*/),
|
||||
{
|
||||
"alias": "versionHistory",
|
||||
"args": [
|
||||
@@ -130,6 +136,7 @@ return {
|
||||
"name": "content",
|
||||
"storageKey": null
|
||||
},
|
||||
(v0/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -151,6 +158,7 @@ return {
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
},
|
||||
(v2/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -158,7 +166,7 @@ return {
|
||||
"kind": "LinkedField",
|
||||
"name": "publishedBy",
|
||||
"plural": false,
|
||||
"selections": (v0/*: any*/),
|
||||
"selections": (v1/*: any*/),
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
@@ -176,6 +184,6 @@ return {
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "ffcba061a60a144c663de41a48e784d1";
|
||||
(node as any).hash = "344e822be4a3eb20d147ecd1c3ea7ced";
|
||||
|
||||
export default node;
|
||||
|
||||
41
pkg/agents/agents.go
Normal file
41
pkg/agents/agents.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package agents
|
||||
|
||||
import (
|
||||
"github.com/openai/openai-go"
|
||||
"github.com/openai/openai-go/option"
|
||||
"go.gearno.de/kit/log"
|
||||
)
|
||||
|
||||
type (
|
||||
Agent struct {
|
||||
l *log.Logger
|
||||
cfg Config
|
||||
client *openai.Client
|
||||
}
|
||||
|
||||
Config struct {
|
||||
OpenAIAPIKey string
|
||||
Temperature float64
|
||||
ModelName string
|
||||
}
|
||||
)
|
||||
|
||||
func NewAgent(l *log.Logger, cfg Config) *Agent {
|
||||
client := openai.NewClient(option.WithAPIKey(cfg.OpenAIAPIKey))
|
||||
|
||||
return &Agent{l: l, cfg: cfg, client: &client}
|
||||
}
|
||||
70
pkg/agents/changelog_generator.go
Normal file
70
pkg/agents/changelog_generator.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package agents
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/openai/openai-go"
|
||||
"github.com/openai/openai-go/packages/param"
|
||||
)
|
||||
|
||||
const (
|
||||
changelogGeneratorSystemPrompt = `
|
||||
# Role:You are an assistant that creates clear and concise changelogs.
|
||||
|
||||
# Objective
|
||||
Given two versions of a document — the "old version" and the "new version" — identify and summarize all meaningful changes between them.
|
||||
Focus on additions, deletions, modifications, and restructuring.
|
||||
|
||||
# Response Format
|
||||
Respond with simple and short phrases that describe the changes, if possible use a single phrase.
|
||||
|
||||
# Change types
|
||||
Change types can include: "Added", "Removed", "Updated", "Reworded", "Reorganized", "Fixed", etc.
|
||||
|
||||
# SOP
|
||||
- Be objective and neutral in tone.
|
||||
- Do not comment on the quality of the change.
|
||||
- Use the language of the document.
|
||||
|
||||
**Example output format:**
|
||||
Respond ONLY with the phrase that describes the changes. No explanation, no markdown, no preamble. Like this:
|
||||
Added Clause about sharing personal information with trusted partners
|
||||
`
|
||||
)
|
||||
|
||||
func (a *Agent) GenerateChangelog(ctx context.Context, oldContent string, newContent string) (*string, error) {
|
||||
model := openai.ChatModel(a.cfg.ModelName)
|
||||
chatCompletion, err := a.client.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.SystemMessage(changelogGeneratorSystemPrompt),
|
||||
openai.UserMessage(fmt.Sprintf(`Old content: %s`, oldContent)),
|
||||
openai.UserMessage(fmt.Sprintf(`New content: %s`, newContent)),
|
||||
},
|
||||
Model: model,
|
||||
Temperature: param.NewOpt(a.cfg.Temperature),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse vendor info: %w", err)
|
||||
}
|
||||
|
||||
if len(chatCompletion.Choices) == 0 {
|
||||
return nil, fmt.Errorf("no completion choices returned from API")
|
||||
}
|
||||
|
||||
return &chatCompletion.Choices[0].Message.Content, nil
|
||||
}
|
||||
@@ -20,24 +20,10 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/openai/openai-go"
|
||||
"github.com/openai/openai-go/option"
|
||||
"github.com/openai/openai-go/packages/param"
|
||||
"go.gearno.de/kit/log"
|
||||
)
|
||||
|
||||
type (
|
||||
VendorAssessment struct {
|
||||
l *log.Logger
|
||||
cfg Config
|
||||
client *openai.Client
|
||||
}
|
||||
|
||||
Config struct {
|
||||
OpenAIAPIKey string
|
||||
Temperature float64
|
||||
ModelName string
|
||||
}
|
||||
|
||||
vendorInfo struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
@@ -58,7 +44,7 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
systemPrompt = `
|
||||
assessVendorSystemPrompt = `
|
||||
# Role: You are a compliance assistant.
|
||||
|
||||
# Objective
|
||||
@@ -136,21 +122,15 @@ const (
|
||||
`
|
||||
)
|
||||
|
||||
func NewVendorAssessment(l *log.Logger, cfg Config) *VendorAssessment {
|
||||
client := openai.NewClient(option.WithAPIKey(cfg.OpenAIAPIKey))
|
||||
|
||||
return &VendorAssessment{l: l, cfg: cfg, client: &client}
|
||||
}
|
||||
|
||||
func (va *VendorAssessment) Fetch(ctx context.Context, websiteURL string) (*vendorInfo, error) {
|
||||
model := openai.ChatModel(va.cfg.ModelName)
|
||||
chatCompletion, err := va.client.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
|
||||
func (a *Agent) AssessVendor(ctx context.Context, websiteURL string) (*vendorInfo, error) {
|
||||
model := openai.ChatModel(a.cfg.ModelName)
|
||||
chatCompletion, err := a.client.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.SystemMessage(systemPrompt),
|
||||
openai.SystemMessage(assessVendorSystemPrompt),
|
||||
openai.UserMessage(websiteURL),
|
||||
},
|
||||
Model: model,
|
||||
Temperature: param.NewOpt(va.cfg.Temperature),
|
||||
Temperature: param.NewOpt(a.cfg.Temperature),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse vendor info: %w", err)
|
||||
|
||||
@@ -30,6 +30,8 @@ type (
|
||||
DocumentVersion struct {
|
||||
ID gid.GID `db:"id"`
|
||||
DocumentID gid.GID `db:"document_id"`
|
||||
Title string `db:"title"`
|
||||
OwnerID gid.GID `db:"owner_id"`
|
||||
VersionNumber int `db:"version_number"`
|
||||
Content string `db:"content"`
|
||||
Changelog string `db:"changelog"`
|
||||
@@ -55,6 +57,8 @@ func (p *DocumentVersions) LoadByDocumentID(
|
||||
SELECT
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -71,10 +75,11 @@ WHERE
|
||||
AND document_id = @document_id
|
||||
AND %s
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{"document_id": documentID}
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_id": documentID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
maps.Copy(args, cursor.SQLArguments())
|
||||
|
||||
@@ -112,6 +117,8 @@ func (p *DocumentVersion) LoadByID(
|
||||
SELECT
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -131,7 +138,9 @@ LIMIT 1;
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{"document_version_id": documentVersionID}
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_version_id": documentVersionID,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
@@ -159,6 +168,8 @@ INSERT INTO document_versions (
|
||||
tenant_id,
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -166,10 +177,13 @@ INSERT INTO document_versions (
|
||||
status,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES (
|
||||
)
|
||||
VALUES (
|
||||
@tenant_id,
|
||||
@id,
|
||||
@document_id,
|
||||
@title,
|
||||
@owner_id,
|
||||
@version_number,
|
||||
@content,
|
||||
@changelog,
|
||||
@@ -179,24 +193,24 @@ INSERT INTO document_versions (
|
||||
@updated_at
|
||||
)
|
||||
`
|
||||
|
||||
now := time.Now()
|
||||
args := pgx.StrictNamedArgs{
|
||||
"tenant_id": scope.GetTenantID(),
|
||||
"id": p.ID,
|
||||
"document_id": p.DocumentID,
|
||||
"title": p.Title,
|
||||
"owner_id": p.OwnerID,
|
||||
"version_number": p.VersionNumber,
|
||||
"content": p.Content,
|
||||
"changelog": p.Changelog,
|
||||
"created_by": p.CreatedBy,
|
||||
"status": p.Status,
|
||||
"created_at": now,
|
||||
"updated_at": now,
|
||||
"created_at": p.CreatedAt,
|
||||
"updated_at": p.UpdatedAt,
|
||||
}
|
||||
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating/updating document version: %w", err)
|
||||
return fmt.Errorf("error creating document version: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -213,6 +227,8 @@ func (p *DocumentVersion) LoadByDocumentIDAndVersionNumber(
|
||||
SELECT
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -237,7 +253,6 @@ LIMIT 1;
|
||||
"document_id": documentID,
|
||||
"version_number": versionNumber,
|
||||
}
|
||||
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
@@ -265,6 +280,8 @@ func (p *DocumentVersion) LoadLatestVersion(
|
||||
SELECT
|
||||
id,
|
||||
document_id,
|
||||
title,
|
||||
owner_id,
|
||||
version_number,
|
||||
content,
|
||||
changelog,
|
||||
@@ -282,13 +299,11 @@ WHERE
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1;
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_id": documentID,
|
||||
}
|
||||
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
@@ -313,6 +328,8 @@ func (p DocumentVersion) Update(
|
||||
) error {
|
||||
q := `
|
||||
UPDATE document_versions SET
|
||||
title = @title,
|
||||
owner_id = @owner_id,
|
||||
changelog = @changelog,
|
||||
status = @status,
|
||||
content = @content,
|
||||
@@ -320,12 +337,15 @@ UPDATE document_versions SET
|
||||
published_at = @published_at,
|
||||
updated_at = @updated_at
|
||||
WHERE %s
|
||||
AND id = @document_version_id;`
|
||||
AND id = @document_version_id
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
||||
|
||||
args := pgx.StrictNamedArgs{
|
||||
"document_version_id": p.ID,
|
||||
"title": p.Title,
|
||||
"owner_id": p.OwnerID,
|
||||
"changelog": p.Changelog,
|
||||
"status": p.Status,
|
||||
"content": p.Content,
|
||||
|
||||
35
pkg/coredata/migrations/20250603T231005Z.sql
Normal file
35
pkg/coredata/migrations/20250603T231005Z.sql
Normal file
@@ -0,0 +1,35 @@
|
||||
ALTER INDEX policy_versions_pkey RENAME TO document_versions_pkey;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
RENAME CONSTRAINT policy_versions_policy_id_version_number_key
|
||||
TO document_versions_document_id_version_number_key;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
RENAME CONSTRAINT policy_versions_published_by_fkey
|
||||
TO document_versions_published_by_fkey;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
ADD CONSTRAINT document_versions_created_by_fkey
|
||||
FOREIGN KEY (created_by) REFERENCES peoples(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
ADD COLUMN title TEXT,
|
||||
ADD COLUMN owner_id TEXT;
|
||||
|
||||
UPDATE document_versions dv
|
||||
SET title = d.title,
|
||||
owner_id = d.owner_id
|
||||
FROM documents d
|
||||
WHERE dv.document_id = d.id;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
ALTER COLUMN title SET NOT NULL,
|
||||
ALTER COLUMN owner_id SET NOT NULL;
|
||||
|
||||
ALTER TABLE document_versions
|
||||
ADD CONSTRAINT document_versions_owner_id_fkey
|
||||
FOREIGN KEY (owner_id) REFERENCES peoples(id)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE;
|
||||
@@ -69,10 +69,58 @@ func (s *DocumentService) Get(
|
||||
return document, nil
|
||||
}
|
||||
|
||||
func (s DocumentService) GenerateChangelog(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
) (*string, error) {
|
||||
draftVersion := &coredata.DocumentVersion{}
|
||||
publishedVersion := &coredata.DocumentVersion{}
|
||||
|
||||
err := s.svc.pg.WithConn(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
if err := draftVersion.LoadLatestVersion(ctx, conn, s.svc.scope, documentID); err != nil {
|
||||
return fmt.Errorf("cannot load draft version: %w", err)
|
||||
}
|
||||
|
||||
if draftVersion.Status != coredata.DocumentStatusDraft {
|
||||
return fmt.Errorf("latest version is not a draft")
|
||||
}
|
||||
|
||||
document := &coredata.Document{}
|
||||
if err := document.LoadByID(ctx, conn, s.svc.scope, documentID); err != nil {
|
||||
return fmt.Errorf("cannot load document: %w", err)
|
||||
}
|
||||
|
||||
if document.CurrentPublishedVersion == nil {
|
||||
publishedVersion.Content = ""
|
||||
} else {
|
||||
if err := publishedVersion.LoadByDocumentIDAndVersionNumber(ctx, conn, s.svc.scope, documentID, *document.CurrentPublishedVersion); err != nil {
|
||||
return fmt.Errorf("cannot load published version: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
changelog, err := s.svc.agent.GenerateChangelog(ctx, publishedVersion.Content, draftVersion.Content)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate changelog: %w", err)
|
||||
}
|
||||
|
||||
return changelog, nil
|
||||
}
|
||||
|
||||
func (s *DocumentService) PublishVersion(
|
||||
ctx context.Context,
|
||||
documentID gid.GID,
|
||||
publishedBy gid.GID,
|
||||
changelog *string,
|
||||
) (*coredata.Document, *coredata.DocumentVersion, error) {
|
||||
document := &coredata.Document{}
|
||||
documentVersion := &coredata.DocumentVersion{}
|
||||
@@ -93,6 +141,10 @@ func (s *DocumentService) PublishVersion(
|
||||
return fmt.Errorf("cannot publish version")
|
||||
}
|
||||
|
||||
if changelog != nil {
|
||||
documentVersion.Changelog = *changelog
|
||||
}
|
||||
|
||||
document.CurrentPublishedVersion = &documentVersion.VersionNumber
|
||||
document.UpdatedAt = now
|
||||
|
||||
@@ -142,6 +194,8 @@ func (s *DocumentService) Create(
|
||||
documentVersion := &coredata.DocumentVersion{
|
||||
ID: documentVersionID,
|
||||
DocumentID: documentID,
|
||||
Title: req.Title,
|
||||
OwnerID: req.OwnerID,
|
||||
VersionNumber: 1,
|
||||
Content: req.Content,
|
||||
Status: coredata.DocumentStatusDraft,
|
||||
@@ -149,6 +203,7 @@ func (s *DocumentService) Create(
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
@@ -348,6 +403,7 @@ func (s *DocumentService) UpdateVersion(
|
||||
req UpdateDocumentVersionRequest,
|
||||
) (*coredata.DocumentVersion, error) {
|
||||
documentVersion := &coredata.DocumentVersion{}
|
||||
document := &coredata.Document{}
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
@@ -356,10 +412,16 @@ func (s *DocumentService) UpdateVersion(
|
||||
return fmt.Errorf("cannot load document version %q: %w", req.ID, err)
|
||||
}
|
||||
|
||||
if err := document.LoadByID(ctx, conn, s.svc.scope, documentVersion.DocumentID); err != nil {
|
||||
return fmt.Errorf("cannot load document %q: %w", documentVersion.DocumentID, err)
|
||||
}
|
||||
|
||||
if documentVersion.Status != coredata.DocumentStatusDraft {
|
||||
return fmt.Errorf("cannot update published version")
|
||||
}
|
||||
|
||||
documentVersion.Title = document.Title
|
||||
documentVersion.OwnerID = document.OwnerID
|
||||
documentVersion.Content = req.Content
|
||||
documentVersion.UpdatedAt = time.Now()
|
||||
|
||||
@@ -473,12 +535,17 @@ func (s *DocumentService) CreateDraft(
|
||||
draftVersionID := gid.New(s.svc.scope.GetTenantID(), coredata.DocumentVersionEntityType)
|
||||
|
||||
latestVersion := &coredata.DocumentVersion{}
|
||||
document := &coredata.Document{}
|
||||
draftVersion := &coredata.DocumentVersion{}
|
||||
now := time.Now()
|
||||
|
||||
err := s.svc.pg.WithTx(
|
||||
ctx,
|
||||
func(conn pg.Conn) error {
|
||||
if err := document.LoadByID(ctx, conn, s.svc.scope, documentID); err != nil {
|
||||
return fmt.Errorf("cannot load document: %w", err)
|
||||
}
|
||||
|
||||
if err := latestVersion.LoadLatestVersion(ctx, conn, s.svc.scope, documentID); err != nil {
|
||||
return fmt.Errorf("cannot load latest version: %w", err)
|
||||
}
|
||||
@@ -489,6 +556,8 @@ func (s *DocumentService) CreateDraft(
|
||||
|
||||
draftVersion.ID = draftVersionID
|
||||
draftVersion.DocumentID = documentID
|
||||
draftVersion.Title = document.Title
|
||||
draftVersion.OwnerID = document.OwnerID
|
||||
draftVersion.VersionNumber = latestVersion.VersionNumber + 1
|
||||
draftVersion.Content = latestVersion.Content
|
||||
draftVersion.Status = coredata.DocumentStatusDraft
|
||||
@@ -640,6 +709,7 @@ func (s *DocumentService) Update(
|
||||
documentID gid.GID,
|
||||
newOwnerID *gid.GID,
|
||||
documentType *coredata.DocumentType,
|
||||
title *string,
|
||||
) (*coredata.Document, error) {
|
||||
document := &coredata.Document{}
|
||||
people := &coredata.People{}
|
||||
@@ -662,6 +732,11 @@ func (s *DocumentService) Update(
|
||||
if documentType != nil {
|
||||
document.DocumentType = *documentType
|
||||
}
|
||||
|
||||
if title != nil {
|
||||
document.Title = *title
|
||||
}
|
||||
|
||||
document.UpdatedAt = now
|
||||
|
||||
if err := document.Update(ctx, tx, s.svc.scope); err != nil {
|
||||
|
||||
@@ -29,13 +29,13 @@ import (
|
||||
|
||||
type (
|
||||
Service struct {
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
encryptionKey cipher.EncryptionKey
|
||||
hostname string
|
||||
tokenSecret string
|
||||
vendorAssessment agents.Config
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
encryptionKey cipher.EncryptionKey
|
||||
hostname string
|
||||
tokenSecret string
|
||||
agentConfig agents.Config
|
||||
}
|
||||
|
||||
TenantService struct {
|
||||
@@ -46,7 +46,7 @@ type (
|
||||
scope coredata.Scoper
|
||||
hostname string
|
||||
tokenSecret string
|
||||
vendorAssessment *agents.VendorAssessment
|
||||
agent *agents.Agent
|
||||
Frameworks *FrameworkService
|
||||
Measures *MeasureService
|
||||
Tasks *TaskService
|
||||
@@ -72,20 +72,20 @@ func NewService(
|
||||
bucket string,
|
||||
hostname string,
|
||||
tokenSecret string,
|
||||
vendorAssessment agents.Config,
|
||||
agentConfig agents.Config,
|
||||
) (*Service, error) {
|
||||
if bucket == "" {
|
||||
return nil, fmt.Errorf("bucket is required")
|
||||
}
|
||||
|
||||
svc := &Service{
|
||||
pg: pgClient,
|
||||
s3: s3Client,
|
||||
bucket: bucket,
|
||||
encryptionKey: encryptionKey,
|
||||
hostname: hostname,
|
||||
tokenSecret: tokenSecret,
|
||||
vendorAssessment: vendorAssessment,
|
||||
pg: pgClient,
|
||||
s3: s3Client,
|
||||
bucket: bucket,
|
||||
encryptionKey: encryptionKey,
|
||||
hostname: hostname,
|
||||
tokenSecret: tokenSecret,
|
||||
agentConfig: agentConfig,
|
||||
}
|
||||
|
||||
return svc, nil
|
||||
@@ -93,14 +93,14 @@ func NewService(
|
||||
|
||||
func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
||||
tenantService := &TenantService{
|
||||
pg: s.pg,
|
||||
s3: s.s3,
|
||||
bucket: s.bucket,
|
||||
encryptionKey: s.encryptionKey,
|
||||
hostname: s.hostname,
|
||||
scope: coredata.NewScope(tenantID),
|
||||
tokenSecret: s.tokenSecret,
|
||||
vendorAssessment: agents.NewVendorAssessment(nil, s.vendorAssessment),
|
||||
pg: s.pg,
|
||||
s3: s.s3,
|
||||
bucket: s.bucket,
|
||||
encryptionKey: s.encryptionKey,
|
||||
hostname: s.hostname,
|
||||
scope: coredata.NewScope(tenantID),
|
||||
tokenSecret: s.tokenSecret,
|
||||
agent: agents.NewAgent(nil, s.agentConfig),
|
||||
}
|
||||
|
||||
tenantService.Frameworks = &FrameworkService{svc: tenantService}
|
||||
|
||||
@@ -447,7 +447,7 @@ func (s VendorService) Assess(
|
||||
ctx context.Context,
|
||||
req AssessVendorRequest,
|
||||
) (*coredata.Vendor, error) {
|
||||
vendorInfo, err := s.svc.vendorAssessment.Fetch(ctx, req.WebsiteURL)
|
||||
vendorInfo, err := s.svc.agent.AssessVendor(ctx, req.WebsiteURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to assess vendor info: %w", err)
|
||||
}
|
||||
|
||||
@@ -187,13 +187,13 @@ func (impl *Implm) Run(
|
||||
}
|
||||
}
|
||||
|
||||
vendorAssessmentConfig := agents.Config{
|
||||
agentConfig := agents.Config{
|
||||
OpenAIAPIKey: impl.cfg.OpenAI.APIKey,
|
||||
Temperature: impl.cfg.OpenAI.Temperature,
|
||||
ModelName: impl.cfg.OpenAI.ModelName,
|
||||
}
|
||||
|
||||
vendorAssessment := agents.NewVendorAssessment(l.Named("vendor-assessment"), vendorAssessmentConfig)
|
||||
agent := agents.NewAgent(l.Named("agent"), agentConfig)
|
||||
|
||||
usrmgrService, err := usrmgr.NewService(
|
||||
ctx,
|
||||
@@ -215,7 +215,7 @@ func (impl *Implm) Run(
|
||||
impl.cfg.AWS.Bucket,
|
||||
impl.cfg.Hostname,
|
||||
impl.cfg.Auth.Cookie.Secret,
|
||||
vendorAssessmentConfig,
|
||||
agentConfig,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create probo service: %w", err)
|
||||
@@ -227,7 +227,7 @@ func (impl *Implm) Run(
|
||||
Probo: proboService,
|
||||
Usrmgr: usrmgrService,
|
||||
ConnectorRegistry: defaultConnectorRegistry,
|
||||
VendorAssessment: vendorAssessment,
|
||||
Agent: agent,
|
||||
SafeRedirect: &saferedirect.SafeRedirect{AllowedHost: impl.cfg.Hostname},
|
||||
Logger: l.Named("http.server"),
|
||||
Auth: console_v1.AuthConfig{
|
||||
|
||||
@@ -1157,6 +1157,9 @@ type Mutation {
|
||||
publishDocumentVersion(
|
||||
input: PublishDocumentVersionInput!
|
||||
): PublishDocumentVersionPayload!
|
||||
generateDocumentChangelog(
|
||||
input: GenerateDocumentChangelogInput!
|
||||
): GenerateDocumentChangelogPayload!
|
||||
createDraftDocumentVersion(
|
||||
input: CreateDraftDocumentVersionInput!
|
||||
): CreateDraftDocumentVersionPayload!
|
||||
@@ -1746,6 +1749,8 @@ type DocumentVersion implements Node {
|
||||
version: Int!
|
||||
content: String!
|
||||
changelog: String!
|
||||
title: String!
|
||||
owner: People! @goField(forceResolver: true)
|
||||
|
||||
signatures(
|
||||
first: Int
|
||||
@@ -1827,6 +1832,7 @@ type RequestSignaturePayload {
|
||||
|
||||
input PublishDocumentVersionInput {
|
||||
documentId: ID!
|
||||
changelog: String
|
||||
}
|
||||
|
||||
type PublishDocumentVersionPayload {
|
||||
@@ -1885,6 +1891,14 @@ type ExportAuditPayload {
|
||||
url: String!
|
||||
}
|
||||
|
||||
input GenerateDocumentChangelogInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
type GenerateDocumentChangelogPayload {
|
||||
changelog: String!
|
||||
}
|
||||
|
||||
input AssessVendorInput {
|
||||
id: ID!
|
||||
websiteUrl: String!
|
||||
|
||||
@@ -343,10 +343,12 @@ type ComplexityRoot struct {
|
||||
CreatedAt func(childComplexity int) int
|
||||
Document func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
Owner func(childComplexity int) int
|
||||
PublishedAt func(childComplexity int) int
|
||||
PublishedBy func(childComplexity int) int
|
||||
Signatures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionSignatureOrder) int
|
||||
Status func(childComplexity int) int
|
||||
Title func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
Version func(childComplexity int) int
|
||||
}
|
||||
@@ -437,6 +439,10 @@ type ComplexityRoot struct {
|
||||
EvidenceEdge func(childComplexity int) int
|
||||
}
|
||||
|
||||
GenerateDocumentChangelogPayload struct {
|
||||
Changelog func(childComplexity int) int
|
||||
}
|
||||
|
||||
ImportFrameworkPayload struct {
|
||||
FrameworkEdge func(childComplexity int) int
|
||||
}
|
||||
@@ -513,6 +519,7 @@ type ComplexityRoot struct {
|
||||
DeleteVendorComplianceReport func(childComplexity int, input types.DeleteVendorComplianceReportInput) int
|
||||
ExportAudit func(childComplexity int, input types.ExportAuditInput) int
|
||||
FulfillEvidence func(childComplexity int, input types.FulfillEvidenceInput) int
|
||||
GenerateDocumentChangelog func(childComplexity int, input types.GenerateDocumentChangelogInput) int
|
||||
ImportFramework func(childComplexity int, input types.ImportFrameworkInput) int
|
||||
ImportMeasure func(childComplexity int, input types.ImportMeasureInput) int
|
||||
InviteUser func(childComplexity int, input types.InviteUserInput) int
|
||||
@@ -889,6 +896,7 @@ type DocumentResolver interface {
|
||||
type DocumentVersionResolver interface {
|
||||
Document(ctx context.Context, obj *types.DocumentVersion) (*types.Document, error)
|
||||
|
||||
Owner(ctx context.Context, obj *types.DocumentVersion) (*types.People, error)
|
||||
Signatures(ctx context.Context, obj *types.DocumentVersion, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionSignatureOrder) (*types.DocumentVersionSignatureConnection, error)
|
||||
PublishedBy(ctx context.Context, obj *types.DocumentVersion) (*types.People, error)
|
||||
}
|
||||
@@ -963,6 +971,7 @@ type MutationResolver interface {
|
||||
UpdateDocument(ctx context.Context, input types.UpdateDocumentInput) (*types.UpdateDocumentPayload, error)
|
||||
DeleteDocument(ctx context.Context, input types.DeleteDocumentInput) (*types.DeleteDocumentPayload, error)
|
||||
PublishDocumentVersion(ctx context.Context, input types.PublishDocumentVersionInput) (*types.PublishDocumentVersionPayload, error)
|
||||
GenerateDocumentChangelog(ctx context.Context, input types.GenerateDocumentChangelogInput) (*types.GenerateDocumentChangelogPayload, error)
|
||||
CreateDraftDocumentVersion(ctx context.Context, input types.CreateDraftDocumentVersionInput) (*types.CreateDraftDocumentVersionPayload, error)
|
||||
UpdateDocumentVersion(ctx context.Context, input types.UpdateDocumentVersionInput) (*types.UpdateDocumentVersionPayload, error)
|
||||
RequestSignature(ctx context.Context, input types.RequestSignatureInput) (*types.RequestSignaturePayload, error)
|
||||
@@ -1897,6 +1906,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.DocumentVersion.ID(childComplexity), true
|
||||
|
||||
case "DocumentVersion.owner":
|
||||
if e.complexity.DocumentVersion.Owner == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.DocumentVersion.Owner(childComplexity), true
|
||||
|
||||
case "DocumentVersion.publishedAt":
|
||||
if e.complexity.DocumentVersion.PublishedAt == nil {
|
||||
break
|
||||
@@ -1930,6 +1946,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.DocumentVersion.Status(childComplexity), true
|
||||
|
||||
case "DocumentVersion.title":
|
||||
if e.complexity.DocumentVersion.Title == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.DocumentVersion.Title(childComplexity), true
|
||||
|
||||
case "DocumentVersion.updatedAt":
|
||||
if e.complexity.DocumentVersion.UpdatedAt == nil {
|
||||
break
|
||||
@@ -2278,6 +2301,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.FulfillEvidencePayload.EvidenceEdge(childComplexity), true
|
||||
|
||||
case "GenerateDocumentChangelogPayload.changelog":
|
||||
if e.complexity.GenerateDocumentChangelogPayload.Changelog == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.GenerateDocumentChangelogPayload.Changelog(childComplexity), true
|
||||
|
||||
case "ImportFrameworkPayload.frameworkEdge":
|
||||
if e.complexity.ImportFrameworkPayload.FrameworkEdge == nil {
|
||||
break
|
||||
@@ -2892,6 +2922,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.complexity.Mutation.FulfillEvidence(childComplexity, args["input"].(types.FulfillEvidenceInput)), true
|
||||
|
||||
case "Mutation.generateDocumentChangelog":
|
||||
if e.complexity.Mutation.GenerateDocumentChangelog == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_generateDocumentChangelog_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Mutation.GenerateDocumentChangelog(childComplexity, args["input"].(types.GenerateDocumentChangelogInput)), true
|
||||
|
||||
case "Mutation.importFramework":
|
||||
if e.complexity.Mutation.ImportFramework == nil {
|
||||
break
|
||||
@@ -4547,6 +4589,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
ec.unmarshalInputExportAuditInput,
|
||||
ec.unmarshalInputFrameworkOrder,
|
||||
ec.unmarshalInputFulfillEvidenceInput,
|
||||
ec.unmarshalInputGenerateDocumentChangelogInput,
|
||||
ec.unmarshalInputImportFrameworkInput,
|
||||
ec.unmarshalInputImportMeasureInput,
|
||||
ec.unmarshalInputInviteUserInput,
|
||||
@@ -5837,6 +5880,9 @@ type Mutation {
|
||||
publishDocumentVersion(
|
||||
input: PublishDocumentVersionInput!
|
||||
): PublishDocumentVersionPayload!
|
||||
generateDocumentChangelog(
|
||||
input: GenerateDocumentChangelogInput!
|
||||
): GenerateDocumentChangelogPayload!
|
||||
createDraftDocumentVersion(
|
||||
input: CreateDraftDocumentVersionInput!
|
||||
): CreateDraftDocumentVersionPayload!
|
||||
@@ -6426,6 +6472,8 @@ type DocumentVersion implements Node {
|
||||
version: Int!
|
||||
content: String!
|
||||
changelog: String!
|
||||
title: String!
|
||||
owner: People! @goField(forceResolver: true)
|
||||
|
||||
signatures(
|
||||
first: Int
|
||||
@@ -6507,6 +6555,7 @@ type RequestSignaturePayload {
|
||||
|
||||
input PublishDocumentVersionInput {
|
||||
documentId: ID!
|
||||
changelog: String
|
||||
}
|
||||
|
||||
type PublishDocumentVersionPayload {
|
||||
@@ -6565,6 +6614,14 @@ type ExportAuditPayload {
|
||||
url: String!
|
||||
}
|
||||
|
||||
input GenerateDocumentChangelogInput {
|
||||
documentId: ID!
|
||||
}
|
||||
|
||||
type GenerateDocumentChangelogPayload {
|
||||
changelog: String!
|
||||
}
|
||||
|
||||
input AssessVendorInput {
|
||||
id: ID!
|
||||
websiteUrl: String!
|
||||
@@ -8799,6 +8856,29 @@ func (ec *executionContext) field_Mutation_fulfillEvidence_argsInput(
|
||||
return zeroVal, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_generateDocumentChangelog_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
arg0, err := ec.field_Mutation_generateDocumentChangelog_argsInput(ctx, rawArgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args["input"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
func (ec *executionContext) field_Mutation_generateDocumentChangelog_argsInput(
|
||||
ctx context.Context,
|
||||
rawArgs map[string]any,
|
||||
) (types.GenerateDocumentChangelogInput, error) {
|
||||
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
|
||||
if tmp, ok := rawArgs["input"]; ok {
|
||||
return ec.unmarshalNGenerateDocumentChangelogInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogInput(ctx, tmp)
|
||||
}
|
||||
|
||||
var zeroVal types.GenerateDocumentChangelogInput
|
||||
return zeroVal, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_importFramework_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
@@ -17134,6 +17214,116 @@ func (ec *executionContext) fieldContext_DocumentVersion_changelog(_ context.Con
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _DocumentVersion_title(ctx context.Context, field graphql.CollectedField, obj *types.DocumentVersion) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Title, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(string)
|
||||
fc.Result = res
|
||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_DocumentVersion_title(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "DocumentVersion",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _DocumentVersion_owner(ctx context.Context, field graphql.CollectedField, obj *types.DocumentVersion) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.DocumentVersion().Owner(rctx, obj)
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*types.People)
|
||||
fc.Result = res
|
||||
return ec.marshalNPeople2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPeople(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_DocumentVersion_owner(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "DocumentVersion",
|
||||
Field: field,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "id":
|
||||
return ec.fieldContext_People_id(ctx, field)
|
||||
case "fullName":
|
||||
return ec.fieldContext_People_fullName(ctx, field)
|
||||
case "primaryEmailAddress":
|
||||
return ec.fieldContext_People_primaryEmailAddress(ctx, field)
|
||||
case "additionalEmailAddresses":
|
||||
return ec.fieldContext_People_additionalEmailAddresses(ctx, field)
|
||||
case "kind":
|
||||
return ec.fieldContext_People_kind(ctx, field)
|
||||
case "position":
|
||||
return ec.fieldContext_People_position(ctx, field)
|
||||
case "contractStartDate":
|
||||
return ec.fieldContext_People_contractStartDate(ctx, field)
|
||||
case "contractEndDate":
|
||||
return ec.fieldContext_People_contractEndDate(ctx, field)
|
||||
case "createdAt":
|
||||
return ec.fieldContext_People_createdAt(ctx, field)
|
||||
case "updatedAt":
|
||||
return ec.fieldContext_People_updatedAt(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type People", field.Name)
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _DocumentVersion_signatures(ctx context.Context, field graphql.CollectedField, obj *types.DocumentVersion) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
if err != nil {
|
||||
@@ -17586,6 +17776,10 @@ func (ec *executionContext) fieldContext_DocumentVersionEdge_node(_ context.Cont
|
||||
return ec.fieldContext_DocumentVersion_content(ctx, field)
|
||||
case "changelog":
|
||||
return ec.fieldContext_DocumentVersion_changelog(ctx, field)
|
||||
case "title":
|
||||
return ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
case "owner":
|
||||
return ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
case "signatures":
|
||||
return ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
case "publishedBy":
|
||||
@@ -17698,6 +17892,10 @@ func (ec *executionContext) fieldContext_DocumentVersionSignature_documentVersio
|
||||
return ec.fieldContext_DocumentVersion_content(ctx, field)
|
||||
case "changelog":
|
||||
return ec.fieldContext_DocumentVersion_changelog(ctx, field)
|
||||
case "title":
|
||||
return ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
case "owner":
|
||||
return ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
case "signatures":
|
||||
return ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
case "publishedBy":
|
||||
@@ -19768,6 +19966,50 @@ func (ec *executionContext) fieldContext_FulfillEvidencePayload_evidenceEdge(_ c
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _GenerateDocumentChangelogPayload_changelog(ctx context.Context, field graphql.CollectedField, obj *types.GenerateDocumentChangelogPayload) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_GenerateDocumentChangelogPayload_changelog(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Changelog, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(string)
|
||||
fc.Result = res
|
||||
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_GenerateDocumentChangelogPayload_changelog(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "GenerateDocumentChangelogPayload",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ImportFrameworkPayload_frameworkEdge(ctx context.Context, field graphql.CollectedField, obj *types.ImportFrameworkPayload) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ImportFrameworkPayload_frameworkEdge(ctx, field)
|
||||
if err != nil {
|
||||
@@ -23473,6 +23715,65 @@ func (ec *executionContext) fieldContext_Mutation_publishDocumentVersion(ctx con
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_generateDocumentChangelog(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Mutation_generateDocumentChangelog(ctx, field)
|
||||
if err != nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Mutation().GenerateDocumentChangelog(rctx, fc.Args["input"].(types.GenerateDocumentChangelogInput))
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
if !graphql.HasFieldError(ctx, fc) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*types.GenerateDocumentChangelogPayload)
|
||||
fc.Result = res
|
||||
return ec.marshalNGenerateDocumentChangelogPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogPayload(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Mutation_generateDocumentChangelog(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "changelog":
|
||||
return ec.fieldContext_GenerateDocumentChangelogPayload_changelog(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type GenerateDocumentChangelogPayload", field.Name)
|
||||
},
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = ec.Recover(ctx, r)
|
||||
ec.Error(ctx, err)
|
||||
}
|
||||
}()
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
if fc.Args, err = ec.field_Mutation_generateDocumentChangelog_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return fc, err
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_createDraftDocumentVersion(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_Mutation_createDraftDocumentVersion(ctx, field)
|
||||
if err != nil {
|
||||
@@ -26456,6 +26757,10 @@ func (ec *executionContext) fieldContext_PublishDocumentVersionPayload_documentV
|
||||
return ec.fieldContext_DocumentVersion_content(ctx, field)
|
||||
case "changelog":
|
||||
return ec.fieldContext_DocumentVersion_changelog(ctx, field)
|
||||
case "title":
|
||||
return ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
case "owner":
|
||||
return ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
case "signatures":
|
||||
return ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
case "publishedBy":
|
||||
@@ -29462,6 +29767,10 @@ func (ec *executionContext) fieldContext_UpdateDocumentVersionPayload_documentVe
|
||||
return ec.fieldContext_DocumentVersion_content(ctx, field)
|
||||
case "changelog":
|
||||
return ec.fieldContext_DocumentVersion_changelog(ctx, field)
|
||||
case "title":
|
||||
return ec.fieldContext_DocumentVersion_title(ctx, field)
|
||||
case "owner":
|
||||
return ec.fieldContext_DocumentVersion_owner(ctx, field)
|
||||
case "signatures":
|
||||
return ec.fieldContext_DocumentVersion_signatures(ctx, field)
|
||||
case "publishedBy":
|
||||
@@ -37516,6 +37825,33 @@ func (ec *executionContext) unmarshalInputFulfillEvidenceInput(ctx context.Conte
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputGenerateDocumentChangelogInput(ctx context.Context, obj any) (types.GenerateDocumentChangelogInput, error) {
|
||||
var it types.GenerateDocumentChangelogInput
|
||||
asMap := map[string]any{}
|
||||
for k, v := range obj.(map[string]any) {
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"documentId"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch k {
|
||||
case "documentId":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("documentId"))
|
||||
data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.DocumentID = data
|
||||
}
|
||||
}
|
||||
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputImportFrameworkInput(ctx context.Context, obj any) (types.ImportFrameworkInput, error) {
|
||||
var it types.ImportFrameworkInput
|
||||
asMap := map[string]any{}
|
||||
@@ -37734,7 +38070,7 @@ func (ec *executionContext) unmarshalInputPublishDocumentVersionInput(ctx contex
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"documentId"}
|
||||
fieldsInOrder := [...]string{"documentId", "changelog"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
@@ -37748,6 +38084,13 @@ func (ec *executionContext) unmarshalInputPublishDocumentVersionInput(ctx contex
|
||||
return it, err
|
||||
}
|
||||
it.DocumentID = data
|
||||
case "changelog":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("changelog"))
|
||||
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Changelog = data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42067,6 +42410,47 @@ func (ec *executionContext) _DocumentVersion(ctx context.Context, sel ast.Select
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&out.Invalids, 1)
|
||||
}
|
||||
case "title":
|
||||
out.Values[i] = ec._DocumentVersion_title(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&out.Invalids, 1)
|
||||
}
|
||||
case "owner":
|
||||
field := field
|
||||
|
||||
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
}
|
||||
}()
|
||||
res = ec._DocumentVersion_owner(ctx, field, obj)
|
||||
if res == graphql.Null {
|
||||
atomic.AddUint32(&fs.Invalids, 1)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
if field.Deferrable != nil {
|
||||
dfs, ok := deferred[field.Deferrable.Label]
|
||||
di := 0
|
||||
if ok {
|
||||
dfs.AddField(field)
|
||||
di = len(dfs.Values) - 1
|
||||
} else {
|
||||
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
|
||||
deferred[field.Deferrable.Label] = dfs
|
||||
}
|
||||
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
|
||||
return innerFunc(ctx, dfs)
|
||||
})
|
||||
|
||||
// don't run the out.Concurrently() call below
|
||||
out.Values[i] = graphql.Null
|
||||
continue
|
||||
}
|
||||
|
||||
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||
case "signatures":
|
||||
field := field
|
||||
|
||||
@@ -43084,6 +43468,45 @@ func (ec *executionContext) _FulfillEvidencePayload(ctx context.Context, sel ast
|
||||
return out
|
||||
}
|
||||
|
||||
var generateDocumentChangelogPayloadImplementors = []string{"GenerateDocumentChangelogPayload"}
|
||||
|
||||
func (ec *executionContext) _GenerateDocumentChangelogPayload(ctx context.Context, sel ast.SelectionSet, obj *types.GenerateDocumentChangelogPayload) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, generateDocumentChangelogPayloadImplementors)
|
||||
|
||||
out := graphql.NewFieldSet(fields)
|
||||
deferred := make(map[string]*graphql.FieldSet)
|
||||
for i, field := range fields {
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("GenerateDocumentChangelogPayload")
|
||||
case "changelog":
|
||||
out.Values[i] = ec._GenerateDocumentChangelogPayload_changelog(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch(ctx)
|
||||
if out.Invalids > 0 {
|
||||
return graphql.Null
|
||||
}
|
||||
|
||||
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
|
||||
|
||||
for label, dfs := range deferred {
|
||||
ec.processDeferredGroup(graphql.DeferredGroup{
|
||||
Label: label,
|
||||
Path: graphql.GetPath(ctx),
|
||||
FieldSet: dfs,
|
||||
Context: ctx,
|
||||
})
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
var importFrameworkPayloadImplementors = []string{"ImportFrameworkPayload"}
|
||||
|
||||
func (ec *executionContext) _ImportFrameworkPayload(ctx context.Context, sel ast.SelectionSet, obj *types.ImportFrameworkPayload) graphql.Marshaler {
|
||||
@@ -43850,6 +44273,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "generateDocumentChangelog":
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_generateDocumentChangelog(ctx, field)
|
||||
})
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "createDraftDocumentVersion":
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_createDraftDocumentVersion(ctx, field)
|
||||
@@ -49850,6 +50280,25 @@ func (ec *executionContext) marshalNFulfillEvidencePayload2ᚖgithubᚗcomᚋget
|
||||
return ec._FulfillEvidencePayload(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNGenerateDocumentChangelogInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogInput(ctx context.Context, v any) (types.GenerateDocumentChangelogInput, error) {
|
||||
res, err := ec.unmarshalInputGenerateDocumentChangelogInput(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNGenerateDocumentChangelogPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogPayload(ctx context.Context, sel ast.SelectionSet, v types.GenerateDocumentChangelogPayload) graphql.Marshaler {
|
||||
return ec._GenerateDocumentChangelogPayload(ctx, sel, &v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNGenerateDocumentChangelogPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐGenerateDocumentChangelogPayload(ctx context.Context, sel ast.SelectionSet, v *types.GenerateDocumentChangelogPayload) graphql.Marshaler {
|
||||
if v == nil {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
return ec._GenerateDocumentChangelogPayload(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx context.Context, v any) (gid.GID, error) {
|
||||
res, err := types.UnmarshalGIDScalar(v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
|
||||
@@ -46,6 +46,7 @@ func NewDocumentVersion(documentVersion *coredata.DocumentVersion) *DocumentVers
|
||||
return &DocumentVersion{
|
||||
ID: documentVersion.ID,
|
||||
Version: documentVersion.VersionNumber,
|
||||
Title: documentVersion.Title,
|
||||
Content: documentVersion.Content,
|
||||
Status: documentVersion.Status,
|
||||
PublishedAt: documentVersion.PublishedAt,
|
||||
|
||||
@@ -557,6 +557,8 @@ type DocumentVersion struct {
|
||||
Version int `json:"version"`
|
||||
Content string `json:"content"`
|
||||
Changelog string `json:"changelog"`
|
||||
Title string `json:"title"`
|
||||
Owner *People `json:"owner"`
|
||||
Signatures *DocumentVersionSignatureConnection `json:"signatures"`
|
||||
PublishedBy *People `json:"publishedBy,omitempty"`
|
||||
PublishedAt *time.Time `json:"publishedAt,omitempty"`
|
||||
@@ -682,6 +684,14 @@ type FulfillEvidencePayload struct {
|
||||
EvidenceEdge *EvidenceEdge `json:"evidenceEdge"`
|
||||
}
|
||||
|
||||
type GenerateDocumentChangelogInput struct {
|
||||
DocumentID gid.GID `json:"documentId"`
|
||||
}
|
||||
|
||||
type GenerateDocumentChangelogPayload struct {
|
||||
Changelog string `json:"changelog"`
|
||||
}
|
||||
|
||||
type ImportFrameworkInput struct {
|
||||
OrganizationID gid.GID `json:"organizationId"`
|
||||
File graphql.Upload `json:"file"`
|
||||
@@ -812,6 +822,7 @@ type PeopleEdge struct {
|
||||
|
||||
type PublishDocumentVersionInput struct {
|
||||
DocumentID gid.GID `json:"documentId"`
|
||||
Changelog *string `json:"changelog,omitempty"`
|
||||
}
|
||||
|
||||
type PublishDocumentVersionPayload struct {
|
||||
|
||||
@@ -302,6 +302,23 @@ func (r *documentVersionResolver) Document(ctx context.Context, obj *types.Docum
|
||||
return types.NewDocument(document), nil
|
||||
}
|
||||
|
||||
// Owner is the resolver for the owner field.
|
||||
func (r *documentVersionResolver) Owner(ctx context.Context, obj *types.DocumentVersion) (*types.People, error) {
|
||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||
|
||||
documentVersion, err := svc.Documents.GetVersion(ctx, obj.ID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot get document version: %w", err))
|
||||
}
|
||||
|
||||
owner, err := svc.Peoples.Get(ctx, documentVersion.OwnerID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot get owner: %w", err))
|
||||
}
|
||||
|
||||
return types.NewPeople(owner), nil
|
||||
}
|
||||
|
||||
// Signatures is the resolver for the signatures field.
|
||||
func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.DocumentVersion, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionSignatureOrder) (*types.DocumentVersionSignatureConnection, error) {
|
||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||
@@ -1491,6 +1508,7 @@ func (r *mutationResolver) UpdateDocument(ctx context.Context, input types.Updat
|
||||
input.ID,
|
||||
input.OwnerID,
|
||||
input.DocumentType,
|
||||
input.Title,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@@ -1526,7 +1544,7 @@ func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input typ
|
||||
panic(fmt.Errorf("cannot get people: %w", err))
|
||||
}
|
||||
|
||||
document, documentVersion, err := svc.Documents.PublishVersion(ctx, input.DocumentID, people.ID)
|
||||
document, documentVersion, err := svc.Documents.PublishVersion(ctx, input.DocumentID, people.ID, input.Changelog)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot publish document version: %w", err))
|
||||
}
|
||||
@@ -1537,6 +1555,20 @@ func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input typ
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateDocumentChangelog is the resolver for the generateDocumentChangelog field.
|
||||
func (r *mutationResolver) GenerateDocumentChangelog(ctx context.Context, input types.GenerateDocumentChangelogInput) (*types.GenerateDocumentChangelogPayload, error) {
|
||||
svc := GetTenantService(ctx, r.proboSvc, input.DocumentID.TenantID())
|
||||
|
||||
changelog, err := svc.Documents.GenerateChangelog(ctx, input.DocumentID)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot generate document changelog: %w", err))
|
||||
}
|
||||
|
||||
return &types.GenerateDocumentChangelogPayload{
|
||||
Changelog: *changelog,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateDraftDocumentVersion is the resolver for the createDraftDocumentVersion field.
|
||||
func (r *mutationResolver) CreateDraftDocumentVersion(ctx context.Context, input types.CreateDraftDocumentVersionInput) (*types.CreateDraftDocumentVersionPayload, error) {
|
||||
svc := GetTenantService(ctx, r.proboSvc, input.DocumentID.TenantID())
|
||||
|
||||
@@ -38,7 +38,7 @@ type Config struct {
|
||||
Usrmgr *usrmgr.Service
|
||||
Auth console_v1.AuthConfig
|
||||
ConnectorRegistry *connector.ConnectorRegistry
|
||||
VendorAssessment *agents.VendorAssessment
|
||||
Agent *agents.Agent
|
||||
SafeRedirect *saferedirect.SafeRedirect
|
||||
Logger *log.Logger
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user