Remove version update dialog
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import { useNavigate, useParams } from "react-router";
|
||||
import { ConnectionHandler, graphql } from "relay-runtime";
|
||||
|
||||
import type { DocumentActionsDropdown_archiveMutation } from "#/__generated__/core/DocumentActionsDropdown_archiveMutation.graphql";
|
||||
import type { DocumentActionsDropdown_createDraftMutation } from "#/__generated__/core/DocumentActionsDropdown_createDraftMutation.graphql";
|
||||
import type { DocumentActionsDropdown_documentFragment$key } from "#/__generated__/core/DocumentActionsDropdown_documentFragment.graphql";
|
||||
import type { DocumentActionsDropdown_unarchiveMutation } from "#/__generated__/core/DocumentActionsDropdown_unarchiveMutation.graphql";
|
||||
import type { DocumentActionsDropdown_versionFragment$key } from "#/__generated__/core/DocumentActionsDropdown_versionFragment.graphql";
|
||||
@@ -31,8 +32,6 @@ import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||
import { CurrentUser } from "#/providers/CurrentUser";
|
||||
|
||||
import UpdateVersionDialog from "./UpdateVersionDialog";
|
||||
|
||||
const documentFragment = graphql`
|
||||
fragment DocumentActionsDropdown_documentFragment on Document {
|
||||
id
|
||||
@@ -43,10 +42,37 @@ const documentFragment = graphql`
|
||||
canUnarchive: permission(action: "core:document:unarchive")
|
||||
canDelete: permission(action: "core:document:delete")
|
||||
versions(first: 20) {
|
||||
__id
|
||||
totalCount
|
||||
}
|
||||
...UpdateVersionDialogFragment
|
||||
}
|
||||
`;
|
||||
|
||||
const createDraftDocumentVersionMutation = graphql`
|
||||
mutation DocumentActionsDropdown_createDraftMutation(
|
||||
$input: CreateDraftDocumentVersionInput!
|
||||
$connections: [ID!]!
|
||||
) {
|
||||
createDraftDocumentVersion(input: $input) {
|
||||
documentVersionEdge @prependEdge(connections: $connections) {
|
||||
node {
|
||||
id
|
||||
content
|
||||
status
|
||||
publishedAt
|
||||
major
|
||||
minor
|
||||
updatedAt
|
||||
signatures(first: 100) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -118,7 +144,6 @@ export function DocumentActionsDropdownn(props: {
|
||||
const { versionId } = useParams();
|
||||
const { __ } = useTranslate();
|
||||
const { email: defaultEmail } = use(CurrentUser);
|
||||
const updateDialogRef = useRef<{ open: () => void }>(null);
|
||||
const pdfDownloadDialogRef = useRef<PdfDownloadDialogRef>(null);
|
||||
const confirm = useConfirm();
|
||||
const { toast } = useToast();
|
||||
@@ -128,6 +153,8 @@ export function DocumentActionsDropdownn(props: {
|
||||
|
||||
const isDraft = version.status === "DRAFT";
|
||||
|
||||
const [createDraftDocumentVersion, isCreatingDraft]
|
||||
= useMutation<DocumentActionsDropdown_createDraftMutation>(createDraftDocumentVersionMutation);
|
||||
const [deleteDocument, isDeleting] = useDeleteDocumentMutation();
|
||||
const [archiveDocument, isArchiving]
|
||||
= useMutation<DocumentActionsDropdown_archiveMutation>(archiveDocumentMutation);
|
||||
@@ -144,6 +171,38 @@ export function DocumentActionsDropdownn(props: {
|
||||
},
|
||||
);
|
||||
|
||||
const handleCreateDraft = () => {
|
||||
const connectionId = ConnectionHandler.getConnectionID(document.id, "DocumentversionsDropdownMenu_versions");
|
||||
createDraftDocumentVersion({
|
||||
variables: {
|
||||
input: {
|
||||
documentID: document.id,
|
||||
},
|
||||
connections: [connectionId],
|
||||
},
|
||||
onCompleted: (response, errors) => {
|
||||
if (errors) {
|
||||
toast({
|
||||
variant: "error",
|
||||
title: __("Error creating draft"),
|
||||
description:
|
||||
errors[0]?.message || __("An unknown error occurred"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const newVersionId
|
||||
= response.createDraftDocumentVersion.documentVersionEdge.node.id;
|
||||
|
||||
void navigate(`/organizations/${organizationId}/documents/${document.id}/versions/${newVersionId}`);
|
||||
},
|
||||
onError(error) {
|
||||
console.log(error);
|
||||
toast({ title: __("Error"), description: error.message, variant: "error" });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleArchive = () => {
|
||||
confirm(
|
||||
() =>
|
||||
@@ -220,16 +279,13 @@ export function DocumentActionsDropdownn(props: {
|
||||
};
|
||||
|
||||
const handleDeleteDraft = () => {
|
||||
const versionsConnectionId = ConnectionHandler.getConnectionID(
|
||||
document.id,
|
||||
"DocumentLayout_versions",
|
||||
);
|
||||
const connectionId = ConnectionHandler.getConnectionID(document.id, "DocumentversionsDropdownMenu_versions");
|
||||
confirm(
|
||||
() =>
|
||||
deleteDraftDocumentVersion({
|
||||
variables: {
|
||||
input: { documentVersionId: version.id },
|
||||
connections: [document.versions.__id, versionsConnectionId],
|
||||
connections: [connectionId],
|
||||
},
|
||||
onSuccess() {
|
||||
if (versionId) {
|
||||
@@ -285,10 +341,6 @@ export function DocumentActionsDropdownn(props: {
|
||||
|
||||
return (
|
||||
<>
|
||||
<UpdateVersionDialog
|
||||
ref={updateDialogRef}
|
||||
fKey={document}
|
||||
/>
|
||||
<PdfDownloadDialog
|
||||
ref={pdfDownloadDialogRef}
|
||||
onDownload={options => void handleExportDocumentVersion(options)}
|
||||
@@ -296,12 +348,13 @@ export function DocumentActionsDropdownn(props: {
|
||||
defaultEmail={defaultEmail}
|
||||
/>
|
||||
<ActionDropdown variant="secondary">
|
||||
{document.canUpdate && (
|
||||
{document.canUpdate && !isDraft && (
|
||||
<DropdownItem
|
||||
onClick={() => updateDialogRef.current?.open()}
|
||||
onClick={handleCreateDraft}
|
||||
icon={IconPencil}
|
||||
disabled={isCreatingDraft}
|
||||
>
|
||||
{isDraft ? __("Edit draft document") : __("Create new draft")}
|
||||
{__("Create new draft")}
|
||||
</DropdownItem>
|
||||
)}
|
||||
{isDraft
|
||||
|
||||
@@ -24,7 +24,7 @@ export const documentVersionsDropdownMenuQuery = graphql`
|
||||
document: node(id: $documentId) {
|
||||
__typename
|
||||
... on Document {
|
||||
versions(first: 20) {
|
||||
versions(first: 20) @connection(key: "DocumentversionsDropdownMenu_versions") {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
// Copyright (c) 2026 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.
|
||||
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import {
|
||||
Breadcrumb,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
Spinner,
|
||||
Textarea,
|
||||
useDialogRef,
|
||||
useToast,
|
||||
} from "@probo/ui";
|
||||
import { type RefObject, useEffect } from "react";
|
||||
import { useFragment, useMutation } from "react-relay";
|
||||
import { useNavigate } from "react-router";
|
||||
import { graphql } from "relay-runtime";
|
||||
import { z } from "zod";
|
||||
|
||||
import type { UpdateVersionDialogCreateMutation } from "#/__generated__/core/UpdateVersionDialogCreateMutation.graphql";
|
||||
import type { UpdateVersionDialogFragment$key } from "#/__generated__/core/UpdateVersionDialogFragment.graphql";
|
||||
import type { UpdateVersionDialogUpdateMutation } from "#/__generated__/core/UpdateVersionDialogUpdateMutation.graphql";
|
||||
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
||||
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||
|
||||
const fragment = graphql`
|
||||
fragment UpdateVersionDialogFragment on Document {
|
||||
id
|
||||
versions(first: 20) @connection(key: "DocumentLayout_versions") {
|
||||
__id
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
status
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const createDraftDocument = graphql`
|
||||
mutation UpdateVersionDialogCreateMutation(
|
||||
$input: CreateDraftDocumentVersionInput!
|
||||
$connections: [ID!]!
|
||||
) {
|
||||
createDraftDocumentVersion(input: $input) {
|
||||
documentVersionEdge @prependEdge(connections: $connections) {
|
||||
node {
|
||||
id
|
||||
content
|
||||
status
|
||||
publishedAt
|
||||
major
|
||||
minor
|
||||
updatedAt
|
||||
signatures(first: 100) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const updateDocumentMutation = graphql`
|
||||
mutation UpdateVersionDialogUpdateMutation(
|
||||
$input: UpdateDocumentVersionInput!
|
||||
) {
|
||||
updateDocumentVersion(input: $input) {
|
||||
documentVersion {
|
||||
id
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
type UpdateVersionDialogProps = {
|
||||
fKey: UpdateVersionDialogFragment$key;
|
||||
ref: RefObject<{ open: () => void } | null>;
|
||||
};
|
||||
|
||||
const versionSchema = z.object({
|
||||
content: z.string(),
|
||||
});
|
||||
|
||||
export default function UpdateVersionDialog(props: UpdateVersionDialogProps) {
|
||||
const { fKey, ref } = props;
|
||||
|
||||
const organizationId = useOrganizationId();
|
||||
const navigate = useNavigate();
|
||||
const { __ } = useTranslate();
|
||||
const { toast } = useToast();
|
||||
const dialogRef = useDialogRef();
|
||||
|
||||
const document = useFragment<UpdateVersionDialogFragment$key>(fragment, fKey);
|
||||
const version = document.versions.edges[0].node;
|
||||
const isDraft = version.status === "DRAFT";
|
||||
const [createDraftDocumentVersion, isCreatingDraft]
|
||||
= useMutation<UpdateVersionDialogCreateMutation>(createDraftDocument);
|
||||
const [updateDocumentVersion, isUpdating]
|
||||
= useMutationWithToasts<UpdateVersionDialogUpdateMutation>(
|
||||
updateDocumentMutation,
|
||||
{
|
||||
successMessage: __("Document updated successfully."),
|
||||
errorMessage: __("Failed to update document"),
|
||||
},
|
||||
);
|
||||
const { handleSubmit, register } = useFormWithSchema(versionSchema, {
|
||||
defaultValues: {
|
||||
content: version.content,
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!ref.current) {
|
||||
ref.current = {
|
||||
open: () => {
|
||||
dialogRef.current?.open();
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
if (!version) {
|
||||
return;
|
||||
}
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof versionSchema>) => {
|
||||
if (isDraft) {
|
||||
await updateDocumentVersion({
|
||||
variables: {
|
||||
input: {
|
||||
documentVersionId: version.id,
|
||||
content: data.content,
|
||||
},
|
||||
},
|
||||
onSuccess: () => {
|
||||
dialogRef.current?.close();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
createDraftDocumentVersion({
|
||||
variables: {
|
||||
input: {
|
||||
documentID: document.id,
|
||||
},
|
||||
connections: [document.versions.__id],
|
||||
},
|
||||
onCompleted: (createResponse, errors) => {
|
||||
if (errors) {
|
||||
toast({
|
||||
variant: "error",
|
||||
title: __("Error creating draft"),
|
||||
description:
|
||||
errors[0]?.message || __("An unknown error occurred"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const newVersionId
|
||||
= createResponse?.createDraftDocumentVersion?.documentVersionEdge
|
||||
?.node?.id;
|
||||
if (newVersionId && data.content !== version.content) {
|
||||
void updateDocumentVersion({
|
||||
variables: {
|
||||
input: {
|
||||
documentVersionId: newVersionId,
|
||||
content: data.content,
|
||||
},
|
||||
},
|
||||
onSuccess: () => {
|
||||
dialogRef.current?.close();
|
||||
void navigate(`/organizations/${organizationId}/documents/${document.id}/versions/${newVersionId}`);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
dialogRef.current?.close();
|
||||
void navigate(`/organizations/${organizationId}/documents/${document.id}/versions/${newVersionId}`);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const isLoading = isCreatingDraft || isUpdating;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
ref={dialogRef}
|
||||
title={<Breadcrumb items={[__("Documents"), __("Edit document")]} />}
|
||||
>
|
||||
<form onSubmit={e => void handleSubmit(onSubmit)(e)}>
|
||||
<DialogContent>
|
||||
<Textarea
|
||||
id="content"
|
||||
variant="ghost"
|
||||
autogrow
|
||||
required
|
||||
placeholder={__("Add content")}
|
||||
aria-label={__("Content")}
|
||||
className="p-6"
|
||||
{...register("content")}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogFooter>
|
||||
<Button disabled={isLoading} type="submit">
|
||||
{isLoading && <Spinner />}
|
||||
{__("Update document")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user