diff --git a/app/actions/definitions/documents.tsx b/app/actions/definitions/documents.tsx index 871e7406e..a9275e489 100644 --- a/app/actions/definitions/documents.tsx +++ b/app/actions/definitions/documents.tsx @@ -20,6 +20,8 @@ import { ShuffleIcon, HistoryIcon, LightBulbIcon, + UnpublishIcon, + PublishIcon, } from "outline-icons"; import * as React from "react"; import { ExportContentType } from "@shared/types"; @@ -128,6 +130,61 @@ export const unstarDocument = createAction({ }, }); +export const publishDocument = createAction({ + name: ({ t }) => t("Publish"), + section: DocumentSection, + icon: , + visible: ({ activeDocumentId, stores }) => { + if (!activeDocumentId) { + return false; + } + const document = stores.documents.get(activeDocumentId); + return ( + !!document?.isDraft && stores.policies.abilities(activeDocumentId).update + ); + }, + perform: ({ activeDocumentId, stores, t }) => { + if (!activeDocumentId) { + return; + } + + const document = stores.documents.get(activeDocumentId); + + document?.save({ + publish: true, + }); + + stores.toasts.showToast(t("Document published"), { + type: "success", + }); + }, +}); + +export const unpublishDocument = createAction({ + name: ({ t }) => t("Unpublish"), + section: DocumentSection, + icon: , + visible: ({ activeDocumentId, stores }) => { + if (!activeDocumentId) { + return false; + } + return stores.policies.abilities(activeDocumentId).unpublish; + }, + perform: ({ activeDocumentId, stores, t }) => { + if (!activeDocumentId) { + return; + } + + const document = stores.documents.get(activeDocumentId); + + document?.unpublish(); + + stores.toasts.showToast(t("Document unpublished"), { + type: "success", + }); + }, +}); + export const subscribeDocument = createAction({ name: ({ t }) => t("Subscribe"), section: DocumentSection, @@ -662,6 +719,8 @@ export const rootDocumentActions = [ downloadDocument, starDocument, unstarDocument, + publishDocument, + unpublishDocument, subscribeDocument, unsubscribeDocument, duplicateDocument, diff --git a/app/actions/index.ts b/app/actions/index.ts index cd7a554ad..738022f71 100644 --- a/app/actions/index.ts +++ b/app/actions/index.ts @@ -57,8 +57,16 @@ export function actionToMenuItem( icon, visible, dangerous: action.dangerous, - onClick: () => action.perform && action.perform(context), - selected: action.selected ? action.selected(context) : undefined, + onClick: () => { + try { + action.perform?.(context); + } catch (err) { + context.stores.toasts.showToast(err.message, { + type: "error", + }); + } + }, + selected: action.selected?.(context), }; } diff --git a/app/menus/DocumentMenu.tsx b/app/menus/DocumentMenu.tsx index f9d64a188..15e0583a9 100644 --- a/app/menus/DocumentMenu.tsx +++ b/app/menus/DocumentMenu.tsx @@ -1,7 +1,6 @@ import { observer } from "mobx-react"; import { EditIcon, - UnpublishIcon, PrintIcon, NewDocumentIcon, RestoreIcon, @@ -39,6 +38,8 @@ import { archiveDocument, openDocumentHistory, openDocumentInsights, + publishDocument, + unpublishDocument, } from "~/actions/definitions/documents"; import useActionContext from "~/hooks/useActionContext"; import useCurrentTeam from "~/hooks/useCurrentTeam"; @@ -124,13 +125,6 @@ function DocumentMenu({ [showToast, t, document] ); - const handleUnpublish = React.useCallback(async () => { - await document.unpublish(); - showToast(t("Document unpublished"), { - type: "success", - }); - }, [showToast, t, document]); - const handlePrint = React.useCallback(() => { menu.hide(); window.print(); @@ -289,13 +283,8 @@ function DocumentMenu({ actionToMenuItem(importDocument, context), actionToMenuItem(createTemplate, context), actionToMenuItem(duplicateDocument, context), - { - type: "button", - title: t("Unpublish"), - onClick: handleUnpublish, - visible: !!can.unpublish, - icon: , - }, + actionToMenuItem(publishDocument, context), + actionToMenuItem(unpublishDocument, context), actionToMenuItem(archiveDocument, context), actionToMenuItem(moveDocument, context), actionToMenuItem(pinDocument, context), diff --git a/shared/i18n/locales/en_US/translation.json b/shared/i18n/locales/en_US/translation.json index 5c91bf72d..d015e82cc 100644 --- a/shared/i18n/locales/en_US/translation.json +++ b/shared/i18n/locales/en_US/translation.json @@ -13,6 +13,10 @@ "Developer": "Developer", "Open document": "Open document", "New document": "New document", + "Publish": "Publish", + "Document published": "Document published", + "Unpublish": "Unpublish", + "Document unpublished": "Document unpublished", "Subscribe": "Subscribe", "Subscribed to document notifications": "Subscribed to document notifications", "Unsubscribe": "Unsubscribe", @@ -316,11 +320,9 @@ "Sort in sidebar": "Sort in sidebar", "Alphabetical sort": "Alphabetical sort", "Manual sort": "Manual sort", - "Document unpublished": "Document unpublished", "Document options": "Document options", "Restore": "Restore", "Choose a collection": "Choose a collection", - "Unpublish": "Unpublish", "Enable embeds": "Enable embeds", "Export options": "Export options", "Edit group": "Edit group", @@ -441,7 +443,6 @@ "Done Editing": "Done Editing", "New from template": "New from template", "Restore version": "Restore version", - "Publish": "Publish", "Publishing": "Publishing", "No history yet": "No history yet", "Stats": "Stats", @@ -659,7 +660,6 @@ "document updated": "document updated", "Posting to the {{ channelName }} channel on": "Posting to the {{ channelName }} channel on", "These events should be posted to Slack": "These events should be posted to Slack", - "Document published": "Document published", "Document updated": "Document updated", "Disconnect": "Disconnect", "API token copied to clipboard": "API token copied to clipboard",