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 { ConnectionHandler, graphql } from "relay-runtime";
|
||||||
|
|
||||||
import type { DocumentActionsDropdown_archiveMutation } from "#/__generated__/core/DocumentActionsDropdown_archiveMutation.graphql";
|
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_documentFragment$key } from "#/__generated__/core/DocumentActionsDropdown_documentFragment.graphql";
|
||||||
import type { DocumentActionsDropdown_unarchiveMutation } from "#/__generated__/core/DocumentActionsDropdown_unarchiveMutation.graphql";
|
import type { DocumentActionsDropdown_unarchiveMutation } from "#/__generated__/core/DocumentActionsDropdown_unarchiveMutation.graphql";
|
||||||
import type { DocumentActionsDropdown_versionFragment$key } from "#/__generated__/core/DocumentActionsDropdown_versionFragment.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 { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
import { CurrentUser } from "#/providers/CurrentUser";
|
import { CurrentUser } from "#/providers/CurrentUser";
|
||||||
|
|
||||||
import UpdateVersionDialog from "./UpdateVersionDialog";
|
|
||||||
|
|
||||||
const documentFragment = graphql`
|
const documentFragment = graphql`
|
||||||
fragment DocumentActionsDropdown_documentFragment on Document {
|
fragment DocumentActionsDropdown_documentFragment on Document {
|
||||||
id
|
id
|
||||||
@@ -43,10 +42,37 @@ const documentFragment = graphql`
|
|||||||
canUnarchive: permission(action: "core:document:unarchive")
|
canUnarchive: permission(action: "core:document:unarchive")
|
||||||
canDelete: permission(action: "core:document:delete")
|
canDelete: permission(action: "core:document:delete")
|
||||||
versions(first: 20) {
|
versions(first: 20) {
|
||||||
__id
|
|
||||||
totalCount
|
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 { versionId } = useParams();
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const { email: defaultEmail } = use(CurrentUser);
|
const { email: defaultEmail } = use(CurrentUser);
|
||||||
const updateDialogRef = useRef<{ open: () => void }>(null);
|
|
||||||
const pdfDownloadDialogRef = useRef<PdfDownloadDialogRef>(null);
|
const pdfDownloadDialogRef = useRef<PdfDownloadDialogRef>(null);
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@@ -128,6 +153,8 @@ export function DocumentActionsDropdownn(props: {
|
|||||||
|
|
||||||
const isDraft = version.status === "DRAFT";
|
const isDraft = version.status === "DRAFT";
|
||||||
|
|
||||||
|
const [createDraftDocumentVersion, isCreatingDraft]
|
||||||
|
= useMutation<DocumentActionsDropdown_createDraftMutation>(createDraftDocumentVersionMutation);
|
||||||
const [deleteDocument, isDeleting] = useDeleteDocumentMutation();
|
const [deleteDocument, isDeleting] = useDeleteDocumentMutation();
|
||||||
const [archiveDocument, isArchiving]
|
const [archiveDocument, isArchiving]
|
||||||
= useMutation<DocumentActionsDropdown_archiveMutation>(archiveDocumentMutation);
|
= 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 = () => {
|
const handleArchive = () => {
|
||||||
confirm(
|
confirm(
|
||||||
() =>
|
() =>
|
||||||
@@ -220,16 +279,13 @@ export function DocumentActionsDropdownn(props: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteDraft = () => {
|
const handleDeleteDraft = () => {
|
||||||
const versionsConnectionId = ConnectionHandler.getConnectionID(
|
const connectionId = ConnectionHandler.getConnectionID(document.id, "DocumentversionsDropdownMenu_versions");
|
||||||
document.id,
|
|
||||||
"DocumentLayout_versions",
|
|
||||||
);
|
|
||||||
confirm(
|
confirm(
|
||||||
() =>
|
() =>
|
||||||
deleteDraftDocumentVersion({
|
deleteDraftDocumentVersion({
|
||||||
variables: {
|
variables: {
|
||||||
input: { documentVersionId: version.id },
|
input: { documentVersionId: version.id },
|
||||||
connections: [document.versions.__id, versionsConnectionId],
|
connections: [connectionId],
|
||||||
},
|
},
|
||||||
onSuccess() {
|
onSuccess() {
|
||||||
if (versionId) {
|
if (versionId) {
|
||||||
@@ -285,10 +341,6 @@ export function DocumentActionsDropdownn(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<UpdateVersionDialog
|
|
||||||
ref={updateDialogRef}
|
|
||||||
fKey={document}
|
|
||||||
/>
|
|
||||||
<PdfDownloadDialog
|
<PdfDownloadDialog
|
||||||
ref={pdfDownloadDialogRef}
|
ref={pdfDownloadDialogRef}
|
||||||
onDownload={options => void handleExportDocumentVersion(options)}
|
onDownload={options => void handleExportDocumentVersion(options)}
|
||||||
@@ -296,12 +348,13 @@ export function DocumentActionsDropdownn(props: {
|
|||||||
defaultEmail={defaultEmail}
|
defaultEmail={defaultEmail}
|
||||||
/>
|
/>
|
||||||
<ActionDropdown variant="secondary">
|
<ActionDropdown variant="secondary">
|
||||||
{document.canUpdate && (
|
{document.canUpdate && !isDraft && (
|
||||||
<DropdownItem
|
<DropdownItem
|
||||||
onClick={() => updateDialogRef.current?.open()}
|
onClick={handleCreateDraft}
|
||||||
icon={IconPencil}
|
icon={IconPencil}
|
||||||
|
disabled={isCreatingDraft}
|
||||||
>
|
>
|
||||||
{isDraft ? __("Edit draft document") : __("Create new draft")}
|
{__("Create new draft")}
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
)}
|
)}
|
||||||
{isDraft
|
{isDraft
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const documentVersionsDropdownMenuQuery = graphql`
|
|||||||
document: node(id: $documentId) {
|
document: node(id: $documentId) {
|
||||||
__typename
|
__typename
|
||||||
... on Document {
|
... on Document {
|
||||||
versions(first: 20) {
|
versions(first: 20) @connection(key: "DocumentversionsDropdownMenu_versions") {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
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