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",