@webiny/app-headless-cms-scheduler 6.6.0-alpha.0 → 6.6.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Browser/BrowserConfig.js +6 -0
- package/components/Browser/BrowserConfig.js.map +1 -1
- package/components/Browser/CellLive.d.ts +11 -0
- package/components/Browser/CellLive.js +34 -0
- package/components/Browser/CellLive.js.map +1 -0
- package/components/Browser/LiveTag.d.ts +4 -0
- package/components/Browser/LiveTag.js +10 -0
- package/components/Browser/LiveTag.js.map +1 -0
- package/components/Browser/MenuItem.d.ts +2 -2
- package/components/Browser/MenuItem.js +4 -1
- package/components/Browser/MenuItem.js.map +1 -1
- package/components/Browser/ScheduledTag.d.ts +5 -0
- package/components/Browser/ScheduledTag.js +24 -0
- package/components/Browser/ScheduledTag.js.map +1 -0
- package/components/Browser/SchedulerMenuItem.js +3 -0
- package/components/Browser/SchedulerMenuItem.js.map +1 -1
- package/components/Browser/isScheduleRedundant.d.ts +12 -0
- package/components/Browser/isScheduleRedundant.js +8 -0
- package/components/Browser/isScheduleRedundant.js.map +1 -0
- package/components/Dialogs/PublishScheduleNotice.d.ts +6 -0
- package/components/Dialogs/PublishScheduleNotice.js +17 -0
- package/components/Dialogs/PublishScheduleNotice.js.map +1 -0
- package/components/Dialogs/ScheduleNoticeAlert.d.ts +14 -0
- package/components/Dialogs/ScheduleNoticeAlert.js +22 -0
- package/components/Dialogs/ScheduleNoticeAlert.js.map +1 -0
- package/components/Dialogs/UnpublishScheduleNotice.d.ts +6 -0
- package/components/Dialogs/UnpublishScheduleNotice.js +17 -0
- package/components/Dialogs/UnpublishScheduleNotice.js.map +1 -0
- package/components/Editor/EditorConfig.js +4 -4
- package/components/Editor/EditorConfig.js.map +1 -1
- package/components/Editor/MenuItem.d.ts +2 -2
- package/components/Editor/MenuItem.js +4 -1
- package/components/Editor/MenuItem.js.map +1 -1
- package/components/Editor/ScheduledActionAlert.d.ts +6 -0
- package/components/Editor/ScheduledActionAlert.js +43 -0
- package/components/Editor/ScheduledActionAlert.js.map +1 -0
- package/components/index.d.ts +3 -0
- package/components/index.js +3 -0
- package/hooks/useScheduledActionsPresenter.d.ts +6 -0
- package/hooks/useScheduledActionsPresenter.js +12 -0
- package/hooks/useScheduledActionsPresenter.js.map +1 -0
- package/index.js +6 -2
- package/index.js.map +1 -1
- package/package.json +12 -9
- package/presentation/scheduledActions/ContentEntriesPresenterSchedulingDecorator.d.ts +30 -0
- package/presentation/scheduledActions/ContentEntriesPresenterSchedulingDecorator.js +67 -0
- package/presentation/scheduledActions/ContentEntriesPresenterSchedulingDecorator.js.map +1 -0
- package/presentation/scheduledActions/ScheduledActionsPresenter.d.ts +28 -0
- package/presentation/scheduledActions/ScheduledActionsPresenter.js +90 -0
- package/presentation/scheduledActions/ScheduledActionsPresenter.js.map +1 -0
- package/presentation/scheduledActions/abstractions.d.ts +16 -0
- package/presentation/scheduledActions/abstractions.js +5 -0
- package/presentation/scheduledActions/abstractions.js.map +1 -0
- package/presentation/scheduledActions/feature.d.ts +3 -0
- package/presentation/scheduledActions/feature.js +19 -0
- package/presentation/scheduledActions/feature.js.map +1 -0
|
@@ -3,6 +3,7 @@ import { IsModelPublishable } from "@webiny/app-headless-cms/exports/admin/cms.j
|
|
|
3
3
|
import { ContentEntryListConfig } from "@webiny/app-headless-cms/admin/config/contentEntries/index.js";
|
|
4
4
|
import { MenuItem } from "./MenuItem.js";
|
|
5
5
|
import { SchedulerMenuItem } from "./SchedulerMenuItem.js";
|
|
6
|
+
import { CellLive } from "./CellLive.js";
|
|
6
7
|
const { Browser: Browser } = ContentEntryListConfig;
|
|
7
8
|
const BrowserConfig = ()=>/*#__PURE__*/ react.createElement(ContentEntryListConfig, null, /*#__PURE__*/ react.createElement(IsModelPublishable, null, /*#__PURE__*/ react.createElement(Browser.Sidebar.Footer, {
|
|
8
9
|
name: "scheduler",
|
|
@@ -10,6 +11,11 @@ const BrowserConfig = ()=>/*#__PURE__*/ react.createElement(ContentEntryListConf
|
|
|
10
11
|
}), /*#__PURE__*/ react.createElement(Browser.Entry.Action, {
|
|
11
12
|
name: "schedule",
|
|
12
13
|
element: /*#__PURE__*/ react.createElement(MenuItem, null)
|
|
14
|
+
}), /*#__PURE__*/ react.createElement(Browser.Table.Column, {
|
|
15
|
+
name: "live",
|
|
16
|
+
header: "Live",
|
|
17
|
+
truncate: false,
|
|
18
|
+
cell: /*#__PURE__*/ react.createElement(CellLive, null)
|
|
13
19
|
})));
|
|
14
20
|
export { BrowserConfig };
|
|
15
21
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components/Browser/BrowserConfig.js","sources":["../../../src/components/Browser/BrowserConfig.tsx"],"sourcesContent":["import React from \"react\";\nimport { IsModelPublishable } from \"@webiny/app-headless-cms/exports/admin/cms.js\";\nimport { ContentEntryListConfig } from \"@webiny/app-headless-cms/admin/config/contentEntries/index.js\";\nimport { MenuItem } from \"./MenuItem.js\";\nimport { SchedulerMenuItem } from \"./SchedulerMenuItem.js\";\n\nconst { Browser } = ContentEntryListConfig;\n\nexport const BrowserConfig = () => {\n return (\n <ContentEntryListConfig>\n <IsModelPublishable>\n <Browser.Sidebar.Footer name={\"scheduler\"} element={<SchedulerMenuItem />} />\n <Browser.Entry.Action name={\"schedule\"} element={<MenuItem />} />\n </IsModelPublishable>\n </ContentEntryListConfig>\n );\n};\n"],"names":["Browser","ContentEntryListConfig","BrowserConfig","IsModelPublishable","SchedulerMenuItem","MenuItem"],"mappings":"
|
|
1
|
+
{"version":3,"file":"components/Browser/BrowserConfig.js","sources":["../../../src/components/Browser/BrowserConfig.tsx"],"sourcesContent":["import React from \"react\";\nimport { IsModelPublishable } from \"@webiny/app-headless-cms/exports/admin/cms.js\";\nimport { ContentEntryListConfig } from \"@webiny/app-headless-cms/admin/config/contentEntries/index.js\";\nimport { MenuItem } from \"./MenuItem.js\";\nimport { SchedulerMenuItem } from \"./SchedulerMenuItem.js\";\nimport { CellLive } from \"./CellLive.js\";\n\nconst { Browser } = ContentEntryListConfig;\n\nexport const BrowserConfig = () => {\n return (\n <ContentEntryListConfig>\n <IsModelPublishable>\n <Browser.Sidebar.Footer name={\"scheduler\"} element={<SchedulerMenuItem />} />\n <Browser.Entry.Action name={\"schedule\"} element={<MenuItem />} />\n {/* Override the core \"Live\" column cell to surface scheduled actions. Same column\n name merges over the core (primary) definition from the public (secondary)\n config, replacing only the cell. */}\n <Browser.Table.Column\n name={\"live\"}\n header={\"Live\"}\n truncate={false}\n cell={<CellLive />}\n />\n </IsModelPublishable>\n </ContentEntryListConfig>\n );\n};\n"],"names":["Browser","ContentEntryListConfig","BrowserConfig","IsModelPublishable","SchedulerMenuItem","MenuItem","CellLive"],"mappings":";;;;;;AAOA,MAAM,EAAEA,SAAAA,OAAO,EAAE,GAAGC;AAEb,MAAMC,gBAAgB,IAClB,WAAP,GACI,oBAACD,wBAAsBA,MAAAA,WAAAA,GACnB,oBAACE,oBAAkBA,MAAAA,WAAAA,GACf,oBAACH,QAAQ,OAAO,CAAC,MAAM;QAAC,MAAM;QAAa,uBAAS,oBAACI,mBAAiBA;sBACtE,oBAACJ,QAAQ,KAAK,CAAC,MAAM;QAAC,MAAM;QAAY,uBAAS,oBAACK,UAAQA;sBAI1D,oBAACL,QAAQ,KAAK,CAAC,MAAM;QACjB,MAAM;QACN,QAAQ;QACR,UAAU;QACV,oBAAM,oBAACM,UAAQA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Overrides the CMS "Live" column cell to surface scheduled publish/unpublish actions.
|
|
4
|
+
*
|
|
5
|
+
* The data comes from ScheduledActionsPresenter, which the content-entries list presenter decorator
|
|
6
|
+
* keeps loaded for the current model. An entry can be live AND have a scheduled action (e.g. a new
|
|
7
|
+
* revision scheduled to publish), so both are shown when both apply.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CellLive: (() => React.JSX.Element) & React.NamedExoticComponent<unknown> & {
|
|
10
|
+
readonly type: () => React.JSX.Element;
|
|
11
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import react from "react";
|
|
2
|
+
import { observer } from "mobx-react-lite";
|
|
3
|
+
import { ContentEntryListConfig } from "@webiny/app-headless-cms/admin/config/contentEntries/index.js";
|
|
4
|
+
import { useScheduledActionsPresenter } from "../../hooks/useScheduledActionsPresenter.js";
|
|
5
|
+
import { LiveTag } from "./LiveTag.js";
|
|
6
|
+
import { ScheduledTag } from "./ScheduledTag.js";
|
|
7
|
+
import { isScheduleRedundant } from "./isScheduleRedundant.js";
|
|
8
|
+
const CellLive = observer(()=>{
|
|
9
|
+
const { useTableRow, isFolderRow } = ContentEntryListConfig.Browser.Table.Column;
|
|
10
|
+
const { row } = useTableRow();
|
|
11
|
+
const presenter = useScheduledActionsPresenter();
|
|
12
|
+
if (isFolderRow(row)) return /*#__PURE__*/ react.createElement(react.Fragment, null, "-");
|
|
13
|
+
const entry = row.data;
|
|
14
|
+
const liveVersion = entry.live?.version;
|
|
15
|
+
const rawScheduled = presenter.getScheduledAction(entry.id);
|
|
16
|
+
const scheduled = rawScheduled && !isScheduleRedundant(rawScheduled, liveVersion, entry.meta?.version) ? rawScheduled : void 0;
|
|
17
|
+
if (liveVersion && scheduled) return /*#__PURE__*/ react.createElement("div", {
|
|
18
|
+
className: "flex flex-wrap items-center gap-xs"
|
|
19
|
+
}, /*#__PURE__*/ react.createElement(LiveTag, {
|
|
20
|
+
version: liveVersion
|
|
21
|
+
}), /*#__PURE__*/ react.createElement(ScheduledTag, {
|
|
22
|
+
scheduled: scheduled
|
|
23
|
+
}));
|
|
24
|
+
if (scheduled) return /*#__PURE__*/ react.createElement(ScheduledTag, {
|
|
25
|
+
scheduled: scheduled
|
|
26
|
+
});
|
|
27
|
+
if (!liveVersion) return /*#__PURE__*/ react.createElement(react.Fragment, null, "No");
|
|
28
|
+
return /*#__PURE__*/ react.createElement(LiveTag, {
|
|
29
|
+
version: liveVersion
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
export { CellLive };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=CellLive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components/Browser/CellLive.js","sources":["../../../src/components/Browser/CellLive.tsx"],"sourcesContent":["import React from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { ContentEntryListConfig } from \"@webiny/app-headless-cms/admin/config/contentEntries/index.js\";\nimport { useScheduledActionsPresenter } from \"~/hooks/useScheduledActionsPresenter.js\";\nimport { LiveTag } from \"./LiveTag.js\";\nimport { ScheduledTag } from \"./ScheduledTag.js\";\nimport { isScheduleRedundant } from \"./isScheduleRedundant.js\";\n\n/**\n * Overrides the CMS \"Live\" column cell to surface scheduled publish/unpublish actions.\n *\n * The data comes from ScheduledActionsPresenter, which the content-entries list presenter decorator\n * keeps loaded for the current model. An entry can be live AND have a scheduled action (e.g. a new\n * revision scheduled to publish), so both are shown when both apply.\n */\nexport const CellLive = observer(() => {\n const { useTableRow, isFolderRow } = ContentEntryListConfig.Browser.Table.Column;\n const { row } = useTableRow();\n const presenter = useScheduledActionsPresenter();\n\n if (isFolderRow(row)) {\n return <>{\"-\"}</>;\n }\n\n const entry = row.data;\n const liveVersion = entry.live?.version;\n\n const rawScheduled = presenter.getScheduledAction(entry.id);\n // Ignore a scheduled action the entry's current state has already made redundant (see helper).\n const scheduled =\n rawScheduled && !isScheduleRedundant(rawScheduled, liveVersion, entry.meta?.version)\n ? rawScheduled\n : undefined;\n\n // Live now AND a change scheduled — show both, wrapping to a second line if the column is narrow.\n if (liveVersion && scheduled) {\n return (\n <div className={\"flex flex-wrap items-center gap-xs\"}>\n <LiveTag version={liveVersion} />\n <ScheduledTag scheduled={scheduled} />\n </div>\n );\n }\n\n if (scheduled) {\n return <ScheduledTag scheduled={scheduled} />;\n }\n\n if (!liveVersion) {\n return <>No</>;\n }\n\n return <LiveTag version={liveVersion} />;\n});\n"],"names":["CellLive","observer","useTableRow","isFolderRow","ContentEntryListConfig","row","presenter","useScheduledActionsPresenter","entry","liveVersion","rawScheduled","scheduled","isScheduleRedundant","undefined","LiveTag","ScheduledTag"],"mappings":";;;;;;;AAeO,MAAMA,WAAWC,SAAS;IAC7B,MAAM,EAAEC,WAAW,EAAEC,WAAW,EAAE,GAAGC,uBAAuB,OAAO,CAAC,KAAK,CAAC,MAAM;IAChF,MAAM,EAAEC,GAAG,EAAE,GAAGH;IAChB,MAAMI,YAAYC;IAElB,IAAIJ,YAAYE,MACZ,OAAO,WAAP,GAAO,0CAAG;IAGd,MAAMG,QAAQH,IAAI,IAAI;IACtB,MAAMI,cAAcD,MAAM,IAAI,EAAE;IAEhC,MAAME,eAAeJ,UAAU,kBAAkB,CAACE,MAAM,EAAE;IAE1D,MAAMG,YACFD,gBAAgB,CAACE,oBAAoBF,cAAcD,aAAaD,MAAM,IAAI,EAAE,WACtEE,eACAG;IAGV,IAAIJ,eAAeE,WACf,OAAO,WAAP,GACI,oBAAC;QAAI,WAAW;qBACZ,oBAACG,SAAOA;QAAC,SAASL;sBAClB,oBAACM,cAAYA;QAAC,WAAWJ;;IAKrC,IAAIA,WACA,OAAO,WAAP,GAAO,oBAACI,cAAYA;QAAC,WAAWJ;;IAGpC,IAAI,CAACF,aACD,OAAO,WAAP,GAAO,0CAAE;IAGb,OAAO,WAAP,GAAO,oBAACK,SAAOA;QAAC,SAASL;;AAC7B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import react from "react";
|
|
2
|
+
import { Tag } from "@webiny/admin-ui";
|
|
3
|
+
const LiveTag = ({ version })=>/*#__PURE__*/ react.createElement(Tag, {
|
|
4
|
+
swatchColor: "#5AC84C",
|
|
5
|
+
variant: "success-light",
|
|
6
|
+
content: `Live (v${version})`
|
|
7
|
+
});
|
|
8
|
+
export { LiveTag };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=LiveTag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components/Browser/LiveTag.js","sources":["../../../src/components/Browser/LiveTag.tsx"],"sourcesContent":["import React from \"react\";\nimport { Tag } from \"@webiny/admin-ui\";\n\nexport const LiveTag = ({ version }: { version: number }) => (\n <Tag swatchColor={\"#5AC84C\"} variant={\"success-light\"} content={`Live (v${version})`} />\n);\n"],"names":["LiveTag","version","Tag"],"mappings":";;AAGO,MAAMA,UAAU,CAAC,EAAEC,OAAO,EAAuB,iBACpD,oBAACC,KAAGA;QAAC,aAAa;QAAW,SAAS;QAAiB,SAAS,CAAC,OAAO,EAAED,QAAQ,CAAC,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
export declare const MenuItem: (() => React.JSX.Element | null) & {
|
|
3
|
-
|
|
2
|
+
export declare const MenuItem: (() => React.JSX.Element | null) & React.NamedExoticComponent<unknown> & {
|
|
3
|
+
readonly type: () => React.JSX.Element | null;
|
|
4
4
|
};
|
|
@@ -7,9 +7,11 @@ import { useEntry } from "@webiny/app-headless-cms";
|
|
|
7
7
|
import { useModel } from "@webiny/app-headless-cms/exports/admin/cms.js";
|
|
8
8
|
import { usePermissions } from "../../hooks/usePermissions.js";
|
|
9
9
|
import { createNamespace } from "../../utils/index.js";
|
|
10
|
+
import { useScheduledActionsPresenter } from "../../hooks/useScheduledActionsPresenter.js";
|
|
10
11
|
const MenuItem = observer(()=>{
|
|
11
12
|
const { model } = useModel();
|
|
12
13
|
const { entry } = useEntry();
|
|
14
|
+
const scheduledActions = useScheduledActionsPresenter();
|
|
13
15
|
const { canPublish, canUnpublish } = usePermissions();
|
|
14
16
|
const { showDialog: showSchedulerDialog } = useScheduleDialog({
|
|
15
17
|
namespace: createNamespace({
|
|
@@ -19,7 +21,8 @@ const MenuItem = observer(()=>{
|
|
|
19
21
|
id: entry.id,
|
|
20
22
|
title: entry.meta.title,
|
|
21
23
|
status: entry.meta.status
|
|
22
|
-
}
|
|
24
|
+
},
|
|
25
|
+
onCompleted: ()=>scheduledActions.reload()
|
|
23
26
|
});
|
|
24
27
|
const { OptionsMenuItem } = ContentEntryListConfig.Browser.Entry.Action;
|
|
25
28
|
const showDialog = useCallback(()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components/Browser/MenuItem.js","sources":["../../../src/components/Browser/MenuItem.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { ReactComponent as ScheduleIcon } from \"@webiny/icons/cell_tower.svg\";\nimport { useScheduleDialog } from \"@webiny/app-scheduler\";\nimport { ContentEntryListConfig } from \"@webiny/app-headless-cms/exports/admin/cms/entry/list.js\";\nimport { useEntry } from \"@webiny/app-headless-cms\";\nimport { useModel } from \"@webiny/app-headless-cms/exports/admin/cms.js\";\nimport { usePermissions } from \"~/hooks/usePermissions.js\";\nimport { createNamespace } from \"~/utils/index.js\";\n\nexport const MenuItem = observer(() => {\n const { model } = useModel();\n const { entry } = useEntry();\n\n const { canPublish, canUnpublish } = usePermissions();\n\n const { showDialog: showSchedulerDialog } = useScheduleDialog({\n namespace: createNamespace({ modelId: model.modelId }),\n target: {\n id: entry.id,\n title: entry.meta.title,\n status: entry.meta.status\n }\n });\n\n const { OptionsMenuItem } = ContentEntryListConfig.Browser.Entry.Action;\n\n const showDialog = useCallback(() => {\n showSchedulerDialog();\n }, [showSchedulerDialog]);\n\n if (!canPublish && !canUnpublish) {\n return null;\n }\n\n const action = entry.meta?.status === \"published\" ? \"unpublish\" : \"publish\";\n\n return (\n <OptionsMenuItem\n icon={<ScheduleIcon />}\n label={`Schedule ${action}`}\n onAction={showDialog}\n disabled={!entry?.meta?.status}\n data-testid={\"cms.content-form.header.schedule\"}\n />\n );\n});\n"],"names":["MenuItem","observer","model","useModel","entry","useEntry","canPublish","canUnpublish","usePermissions","showSchedulerDialog","useScheduleDialog","createNamespace","OptionsMenuItem","ContentEntryListConfig","showDialog","useCallback","action","ScheduleIcon"],"mappings":"
|
|
1
|
+
{"version":3,"file":"components/Browser/MenuItem.js","sources":["../../../src/components/Browser/MenuItem.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { ReactComponent as ScheduleIcon } from \"@webiny/icons/cell_tower.svg\";\nimport { useScheduleDialog } from \"@webiny/app-scheduler\";\nimport { ContentEntryListConfig } from \"@webiny/app-headless-cms/exports/admin/cms/entry/list.js\";\nimport { useEntry } from \"@webiny/app-headless-cms\";\nimport { useModel } from \"@webiny/app-headless-cms/exports/admin/cms.js\";\nimport { usePermissions } from \"~/hooks/usePermissions.js\";\nimport { createNamespace } from \"~/utils/index.js\";\nimport { useScheduledActionsPresenter } from \"~/hooks/useScheduledActionsPresenter.js\";\n\nexport const MenuItem = observer(() => {\n const { model } = useModel();\n const { entry } = useEntry();\n const scheduledActions = useScheduledActionsPresenter();\n\n const { canPublish, canUnpublish } = usePermissions();\n\n const { showDialog: showSchedulerDialog } = useScheduleDialog({\n namespace: createNamespace({ modelId: model.modelId }),\n target: {\n id: entry.id,\n title: entry.meta.title,\n status: entry.meta.status\n },\n onCompleted: () => scheduledActions.reload()\n });\n\n const { OptionsMenuItem } = ContentEntryListConfig.Browser.Entry.Action;\n\n const showDialog = useCallback(() => {\n showSchedulerDialog();\n }, [showSchedulerDialog]);\n\n if (!canPublish && !canUnpublish) {\n return null;\n }\n\n const action = entry.meta?.status === \"published\" ? \"unpublish\" : \"publish\";\n\n return (\n <OptionsMenuItem\n icon={<ScheduleIcon />}\n label={`Schedule ${action}`}\n onAction={showDialog}\n disabled={!entry?.meta?.status}\n data-testid={\"cms.content-form.header.schedule\"}\n />\n );\n});\n"],"names":["MenuItem","observer","model","useModel","entry","useEntry","scheduledActions","useScheduledActionsPresenter","canPublish","canUnpublish","usePermissions","showSchedulerDialog","useScheduleDialog","createNamespace","OptionsMenuItem","ContentEntryListConfig","showDialog","useCallback","action","ScheduleIcon"],"mappings":";;;;;;;;;;AAWO,MAAMA,WAAWC,SAAS;IAC7B,MAAM,EAAEC,KAAK,EAAE,GAAGC;IAClB,MAAM,EAAEC,KAAK,EAAE,GAAGC;IAClB,MAAMC,mBAAmBC;IAEzB,MAAM,EAAEC,UAAU,EAAEC,YAAY,EAAE,GAAGC;IAErC,MAAM,EAAE,YAAYC,mBAAmB,EAAE,GAAGC,kBAAkB;QAC1D,WAAWC,gBAAgB;YAAE,SAASX,MAAM,OAAO;QAAC;QACpD,QAAQ;YACJ,IAAIE,MAAM,EAAE;YACZ,OAAOA,MAAM,IAAI,CAAC,KAAK;YACvB,QAAQA,MAAM,IAAI,CAAC,MAAM;QAC7B;QACA,aAAa,IAAME,iBAAiB,MAAM;IAC9C;IAEA,MAAM,EAAEQ,eAAe,EAAE,GAAGC,uBAAuB,OAAO,CAAC,KAAK,CAAC,MAAM;IAEvE,MAAMC,aAAaC,YAAY;QAC3BN;IACJ,GAAG;QAACA;KAAoB;IAExB,IAAI,CAACH,cAAc,CAACC,cAChB,OAAO;IAGX,MAAMS,SAASd,MAAM,IAAI,EAAE,WAAW,cAAc,cAAc;IAElE,OAAO,WAAP,GACI,oBAACU,iBAAAA;QACG,oBAAM,oBAACK,gBAAYA;QACnB,OAAO,CAAC,SAAS,EAAED,QAAQ;QAC3B,UAAUF;QACV,UAAU,CAACZ,OAAO,MAAM;QACxB,eAAa;;AAGzB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import react from "react";
|
|
2
|
+
import { ReactComponent } from "@webiny/icons/access_time.svg";
|
|
3
|
+
import { Tag, Tooltip } from "@webiny/admin-ui";
|
|
4
|
+
import { ScheduleActionType } from "@webiny/app-scheduler/types.js";
|
|
5
|
+
import { useDateFormatter } from "@webiny/app-admin";
|
|
6
|
+
const scheduledTooltip = (scheduled, dateFormatter)=>{
|
|
7
|
+
const goLiveOn = scheduled.publishOn || scheduled.unpublishOn;
|
|
8
|
+
const actionLabel = scheduled.actionType === ScheduleActionType.unpublish ? "unpublish" : "publish";
|
|
9
|
+
return goLiveOn ? `Scheduled to ${actionLabel} on ${dateFormatter.format(goLiveOn)}` : `Scheduled to ${actionLabel}`;
|
|
10
|
+
};
|
|
11
|
+
const ScheduledTag = ({ scheduled })=>{
|
|
12
|
+
const dateFormatter = useDateFormatter();
|
|
13
|
+
return /*#__PURE__*/ react.createElement(Tooltip, {
|
|
14
|
+
content: scheduledTooltip(scheduled, dateFormatter),
|
|
15
|
+
trigger: /*#__PURE__*/ react.createElement(Tag, {
|
|
16
|
+
variant: "warning",
|
|
17
|
+
icon: /*#__PURE__*/ react.createElement(ReactComponent, null),
|
|
18
|
+
content: "Scheduled"
|
|
19
|
+
})
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
export { ScheduledTag };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=ScheduledTag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components/Browser/ScheduledTag.js","sources":["../../../src/components/Browser/ScheduledTag.tsx"],"sourcesContent":["import React from \"react\";\nimport { ReactComponent as ScheduledIcon } from \"@webiny/icons/access_time.svg\";\nimport { Tag, Tooltip } from \"@webiny/admin-ui\";\nimport { ScheduleActionType } from \"@webiny/app-scheduler/types.js\";\nimport type { SchedulerEntry } from \"@webiny/app-scheduler/types.js\";\nimport { useDateFormatter } from \"@webiny/app-admin\";\nimport type { DateFormatter } from \"@webiny/app-admin\";\n\nconst scheduledTooltip = (\n scheduled: SchedulerEntry,\n dateFormatter: DateFormatter.Interface\n): string => {\n const goLiveOn = scheduled.publishOn || scheduled.unpublishOn;\n const actionLabel =\n scheduled.actionType === ScheduleActionType.unpublish ? \"unpublish\" : \"publish\";\n return goLiveOn\n ? `Scheduled to ${actionLabel} on ${dateFormatter.format(goLiveOn)}`\n : `Scheduled to ${actionLabel}`;\n};\n\nexport const ScheduledTag = ({ scheduled }: { scheduled: SchedulerEntry }) => {\n const dateFormatter = useDateFormatter();\n return (\n <Tooltip\n content={scheduledTooltip(scheduled, dateFormatter)}\n trigger={<Tag variant={\"warning\"} icon={<ScheduledIcon />} content={\"Scheduled\"} />}\n />\n );\n};\n"],"names":["scheduledTooltip","scheduled","dateFormatter","goLiveOn","actionLabel","ScheduleActionType","ScheduledTag","useDateFormatter","Tooltip","Tag","ScheduledIcon"],"mappings":";;;;;AAQA,MAAMA,mBAAmB,CACrBC,WACAC;IAEA,MAAMC,WAAWF,UAAU,SAAS,IAAIA,UAAU,WAAW;IAC7D,MAAMG,cACFH,UAAU,UAAU,KAAKI,mBAAmB,SAAS,GAAG,cAAc;IAC1E,OAAOF,WACD,CAAC,aAAa,EAAEC,YAAY,IAAI,EAAEF,cAAc,MAAM,CAACC,WAAW,GAClE,CAAC,aAAa,EAAEC,aAAa;AACvC;AAEO,MAAME,eAAe,CAAC,EAAEL,SAAS,EAAiC;IACrE,MAAMC,gBAAgBK;IACtB,OAAO,WAAP,GACI,oBAACC,SAAOA;QACJ,SAASR,iBAAiBC,WAAWC;QACrC,uBAAS,oBAACO,KAAGA;YAAC,SAAS;YAAW,oBAAM,oBAACC,gBAAaA;YAAK,SAAS;;;AAGhF"}
|
|
@@ -3,16 +3,19 @@ import { useModel } from "@webiny/app-headless-cms/exports/admin/cms.js";
|
|
|
3
3
|
import { usePermissions } from "../../hooks/usePermissions.js";
|
|
4
4
|
import { Scheduler } from "@webiny/app-scheduler";
|
|
5
5
|
import { SchedulerButton } from "./SchedulerButton.js";
|
|
6
|
+
import { useScheduledActionsPresenter } from "../../hooks/useScheduledActionsPresenter.js";
|
|
6
7
|
import { createNamespace } from "../../utils/index.js";
|
|
7
8
|
const SchedulerMenuItem = ()=>{
|
|
8
9
|
const { model } = useModel();
|
|
9
10
|
const { canPublish, canUnpublish } = usePermissions();
|
|
11
|
+
const scheduledActions = useScheduledActionsPresenter();
|
|
10
12
|
const namespace = createNamespace(model);
|
|
11
13
|
if (!canPublish && !canUnpublish) return null;
|
|
12
14
|
return /*#__PURE__*/ react.createElement(Scheduler, {
|
|
13
15
|
namespace: namespace,
|
|
14
16
|
canPublish: canPublish,
|
|
15
17
|
canUnpublish: canUnpublish,
|
|
18
|
+
onClose: ()=>scheduledActions.loadForModel(model.modelId),
|
|
16
19
|
render: ({ showScheduler })=>/*#__PURE__*/ react.createElement(SchedulerButton, {
|
|
17
20
|
onClick: showScheduler
|
|
18
21
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components/Browser/SchedulerMenuItem.js","sources":["../../../src/components/Browser/SchedulerMenuItem.tsx"],"sourcesContent":["import React from \"react\";\nimport { useModel } from \"@webiny/app-headless-cms/exports/admin/cms.js\";\nimport { usePermissions } from \"~/hooks/usePermissions.js\";\nimport { Scheduler as BaseScheduler } from \"@webiny/app-scheduler\";\nimport { SchedulerButton } from \"./SchedulerButton.js\";\nimport { createNamespace } from \"~/utils/index.js\";\n\nexport const SchedulerMenuItem = () => {\n const { model } = useModel();\n const { canPublish, canUnpublish } = usePermissions();\n\n const namespace = createNamespace(model);\n\n if (!canPublish && !canUnpublish) {\n return null;\n }\n\n return (\n <BaseScheduler\n namespace={namespace}\n canPublish={canPublish}\n canUnpublish={canUnpublish}\n render={({ showScheduler }) => {\n return <SchedulerButton onClick={showScheduler} />;\n }}\n />\n );\n};\n"],"names":["SchedulerMenuItem","model","useModel","canPublish","canUnpublish","usePermissions","namespace","createNamespace","BaseScheduler","showScheduler","SchedulerButton"],"mappings":"
|
|
1
|
+
{"version":3,"file":"components/Browser/SchedulerMenuItem.js","sources":["../../../src/components/Browser/SchedulerMenuItem.tsx"],"sourcesContent":["import React from \"react\";\nimport { useModel } from \"@webiny/app-headless-cms/exports/admin/cms.js\";\nimport { usePermissions } from \"~/hooks/usePermissions.js\";\nimport { Scheduler as BaseScheduler } from \"@webiny/app-scheduler\";\nimport { SchedulerButton } from \"./SchedulerButton.js\";\nimport { useScheduledActionsPresenter } from \"~/hooks/useScheduledActionsPresenter.js\";\nimport { createNamespace } from \"~/utils/index.js\";\n\nexport const SchedulerMenuItem = () => {\n const { model } = useModel();\n const { canPublish, canUnpublish } = usePermissions();\n const scheduledActions = useScheduledActionsPresenter();\n\n const namespace = createNamespace(model);\n\n if (!canPublish && !canUnpublish) {\n return null;\n }\n\n return (\n <BaseScheduler\n namespace={namespace}\n canPublish={canPublish}\n canUnpublish={canUnpublish}\n // The scheduler overlay opens on top of the entries list, so the list stays mounted and\n // its cached scheduled actions go stale when one is cancelled here. Reload on close so the\n // \"Live\" column reflects any cancellations before the user sees the list again.\n onClose={() => scheduledActions.loadForModel(model.modelId)}\n render={({ showScheduler }) => {\n return <SchedulerButton onClick={showScheduler} />;\n }}\n />\n );\n};\n"],"names":["SchedulerMenuItem","model","useModel","canPublish","canUnpublish","usePermissions","scheduledActions","useScheduledActionsPresenter","namespace","createNamespace","BaseScheduler","showScheduler","SchedulerButton"],"mappings":";;;;;;;AAQO,MAAMA,oBAAoB;IAC7B,MAAM,EAAEC,KAAK,EAAE,GAAGC;IAClB,MAAM,EAAEC,UAAU,EAAEC,YAAY,EAAE,GAAGC;IACrC,MAAMC,mBAAmBC;IAEzB,MAAMC,YAAYC,gBAAgBR;IAElC,IAAI,CAACE,cAAc,CAACC,cAChB,OAAO;IAGX,OAAO,WAAP,GACI,oBAACM,WAAaA;QACV,WAAWF;QACX,YAAYL;QACZ,cAAcC;QAId,SAAS,IAAME,iBAAiB,YAAY,CAACL,MAAM,OAAO;QAC1D,QAAQ,CAAC,EAAEU,aAAa,EAAE,GACf,WAAP,GAAO,oBAACC,iBAAeA;gBAAC,SAASD;;;AAIjD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SchedulerEntry } from "@webiny/app-scheduler/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* A scheduled action is made redundant by a direct publish/unpublish. The API cancels it, but that
|
|
4
|
+
* happens asynchronously, so reconcile against the entry's current state to clear the badge
|
|
5
|
+
* immediately instead of waiting for the backend cancellation to propagate:
|
|
6
|
+
*
|
|
7
|
+
* - Scheduled PUBLISH is redundant once the latest revision is already live
|
|
8
|
+
* (`live.version === version`). It is NOT redundant when an older revision is live and a newer one
|
|
9
|
+
* is queued (live.version < version) — that is the legitimate "live and scheduled" case.
|
|
10
|
+
* - Scheduled UNPUBLISH is redundant once nothing is live.
|
|
11
|
+
*/
|
|
12
|
+
export declare const isScheduleRedundant: (scheduled: SchedulerEntry, liveVersion: number | undefined, currentVersion: number | undefined) => boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ScheduleActionType } from "@webiny/app-scheduler/types.js";
|
|
2
|
+
const isScheduleRedundant = (scheduled, liveVersion, currentVersion)=>{
|
|
3
|
+
if (scheduled.actionType === ScheduleActionType.unpublish) return void 0 === liveVersion;
|
|
4
|
+
return void 0 !== liveVersion && liveVersion === currentVersion;
|
|
5
|
+
};
|
|
6
|
+
export { isScheduleRedundant };
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=isScheduleRedundant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components/Browser/isScheduleRedundant.js","sources":["../../../src/components/Browser/isScheduleRedundant.ts"],"sourcesContent":["import { ScheduleActionType } from \"@webiny/app-scheduler/types.js\";\nimport type { SchedulerEntry } from \"@webiny/app-scheduler/types.js\";\n\n/**\n * A scheduled action is made redundant by a direct publish/unpublish. The API cancels it, but that\n * happens asynchronously, so reconcile against the entry's current state to clear the badge\n * immediately instead of waiting for the backend cancellation to propagate:\n *\n * - Scheduled PUBLISH is redundant once the latest revision is already live\n * (`live.version === version`). It is NOT redundant when an older revision is live and a newer one\n * is queued (live.version < version) — that is the legitimate \"live and scheduled\" case.\n * - Scheduled UNPUBLISH is redundant once nothing is live.\n */\nexport const isScheduleRedundant = (\n scheduled: SchedulerEntry,\n liveVersion: number | undefined,\n currentVersion: number | undefined\n): boolean => {\n if (scheduled.actionType === ScheduleActionType.unpublish) {\n return liveVersion === undefined;\n }\n return liveVersion !== undefined && liveVersion === currentVersion;\n};\n"],"names":["isScheduleRedundant","scheduled","liveVersion","currentVersion","ScheduleActionType","undefined"],"mappings":";AAaO,MAAMA,sBAAsB,CAC/BC,WACAC,aACAC;IAEA,IAAIF,UAAU,UAAU,KAAKG,mBAAmB,SAAS,EACrD,OAAOF,AAAgBG,WAAhBH;IAEX,OAAOA,AAAgBG,WAAhBH,eAA6BA,gBAAgBC;AACxD"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Decorates the "Publish entry" dialog to warn (via its `intro` prop) that publishing now will
|
|
4
|
+
* cancel an existing scheduled action for the entry.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PublishScheduleNoticeDecorator: (props: unknown) => React.JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import react from "react";
|
|
2
|
+
import { useNamedConfirmationDialog } from "@webiny/app-admin";
|
|
3
|
+
import { PublishEntryConfirmDialog } from "@webiny/app-headless-cms/exports/admin/cms.js";
|
|
4
|
+
import { ScheduleNoticeAlert } from "./ScheduleNoticeAlert.js";
|
|
5
|
+
const PublishScheduleNoticeDecorator = PublishEntryConfirmDialog.createDecorator((Original)=>function(props) {
|
|
6
|
+
const { params } = useNamedConfirmationDialog();
|
|
7
|
+
return /*#__PURE__*/ react.createElement(Original, {
|
|
8
|
+
...props,
|
|
9
|
+
intro: /*#__PURE__*/ react.createElement(react.Fragment, null, props.intro, /*#__PURE__*/ react.createElement(ScheduleNoticeAlert, {
|
|
10
|
+
targetId: params.entry?.id,
|
|
11
|
+
verb: "Publishing"
|
|
12
|
+
}))
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
export { PublishScheduleNoticeDecorator };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=PublishScheduleNotice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components/Dialogs/PublishScheduleNotice.js","sources":["../../../src/components/Dialogs/PublishScheduleNotice.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNamedConfirmationDialog } from \"@webiny/app-admin\";\nimport { PublishEntryConfirmDialog } from \"@webiny/app-headless-cms/exports/admin/cms.js\";\nimport type { CmsContentEntry } from \"@webiny/app-headless-cms-common/types/index.js\";\nimport { ScheduleNoticeAlert } from \"./ScheduleNoticeAlert.js\";\n\n/**\n * Decorates the \"Publish entry\" dialog to warn (via its `intro` prop) that publishing now will\n * cancel an existing scheduled action for the entry.\n */\nexport const PublishScheduleNoticeDecorator = PublishEntryConfirmDialog.createDecorator(\n Original => {\n return function PublishEntryConfirmDialogWithNotice(props) {\n const { params } = useNamedConfirmationDialog<{ entry: CmsContentEntry }>();\n return (\n <Original\n {...props}\n intro={\n <>\n {props.intro}\n <ScheduleNoticeAlert targetId={params.entry?.id} verb={\"Publishing\"} />\n </>\n }\n />\n );\n };\n }\n);\n"],"names":["PublishScheduleNoticeDecorator","PublishEntryConfirmDialog","Original","props","params","useNamedConfirmationDialog","ScheduleNoticeAlert"],"mappings":";;;;AAUO,MAAMA,iCAAiCC,0BAA0B,eAAe,CACnFC,CAAAA,WACW,SAA6CC,KAAK;QACrD,MAAM,EAAEC,MAAM,EAAE,GAAGC;QACnB,OAAO,WAAP,GACI,oBAACH,UAAAA;YACI,GAAGC,KAAK;YACT,qBACI,0CACKA,MAAM,KAAK,gBACZ,oBAACG,qBAAmBA;gBAAC,UAAUF,OAAO,KAAK,EAAE;gBAAI,MAAM;;;IAK3E"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface ScheduleNoticeAlertProps {
|
|
3
|
+
targetId: string | undefined;
|
|
4
|
+
verb: "Publishing" | "Unpublishing";
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Warns that an about-to-happen publish/unpublish will cancel an existing scheduled action for the
|
|
8
|
+
* entry (the API cancels it). Reads from ScheduledActionsPresenter, already populated by the list
|
|
9
|
+
* (or the entry form). Renders nothing when there is no scheduled action.
|
|
10
|
+
*/
|
|
11
|
+
export declare const ScheduleNoticeAlert: (({ targetId, verb }: ScheduleNoticeAlertProps) => React.JSX.Element | null) & React.NamedExoticComponent<ScheduleNoticeAlertProps> & {
|
|
12
|
+
readonly type: ({ targetId, verb }: ScheduleNoticeAlertProps) => React.JSX.Element | null;
|
|
13
|
+
};
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import react from "react";
|
|
2
|
+
import { observer } from "mobx-react-lite";
|
|
3
|
+
import { Alert } from "@webiny/admin-ui";
|
|
4
|
+
import { ScheduleActionType } from "@webiny/app-scheduler/types.js";
|
|
5
|
+
import { useDateFormatter } from "@webiny/app-admin";
|
|
6
|
+
import { useScheduledActionsPresenter } from "../../hooks/useScheduledActionsPresenter.js";
|
|
7
|
+
const ScheduleNoticeAlert = observer(({ targetId, verb })=>{
|
|
8
|
+
const presenter = useScheduledActionsPresenter();
|
|
9
|
+
const dateFormatter = useDateFormatter();
|
|
10
|
+
const scheduled = targetId ? presenter.getScheduledAction(targetId) : void 0;
|
|
11
|
+
if (!scheduled) return null;
|
|
12
|
+
const goLiveOn = scheduled.publishOn || scheduled.unpublishOn;
|
|
13
|
+
const actionLabel = scheduled.actionType === ScheduleActionType.unpublish ? "unpublish" : "publish";
|
|
14
|
+
return /*#__PURE__*/ react.createElement(Alert, {
|
|
15
|
+
type: "warning",
|
|
16
|
+
variant: "subtle",
|
|
17
|
+
className: "mb-md"
|
|
18
|
+
}, "This entry has a ", actionLabel, " scheduled", goLiveOn ? ` for ${dateFormatter.format(goLiveOn)}` : "", ". ", verb, " now will cancel it.");
|
|
19
|
+
});
|
|
20
|
+
export { ScheduleNoticeAlert };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=ScheduleNoticeAlert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components/Dialogs/ScheduleNoticeAlert.js","sources":["../../../src/components/Dialogs/ScheduleNoticeAlert.tsx"],"sourcesContent":["import React from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { Alert } from \"@webiny/admin-ui\";\nimport { ScheduleActionType } from \"@webiny/app-scheduler/types.js\";\nimport { useDateFormatter } from \"@webiny/app-admin\";\nimport { useScheduledActionsPresenter } from \"~/hooks/useScheduledActionsPresenter.js\";\n\ninterface ScheduleNoticeAlertProps {\n targetId: string | undefined;\n // The action the user is about to take, used in the warning (\"Publishing now will cancel it.\").\n verb: \"Publishing\" | \"Unpublishing\";\n}\n\n/**\n * Warns that an about-to-happen publish/unpublish will cancel an existing scheduled action for the\n * entry (the API cancels it). Reads from ScheduledActionsPresenter, already populated by the list\n * (or the entry form). Renders nothing when there is no scheduled action.\n */\nexport const ScheduleNoticeAlert = observer(({ targetId, verb }: ScheduleNoticeAlertProps) => {\n const presenter = useScheduledActionsPresenter();\n const dateFormatter = useDateFormatter();\n\n const scheduled = targetId ? presenter.getScheduledAction(targetId) : undefined;\n\n if (!scheduled) {\n return null;\n }\n\n const goLiveOn = scheduled.publishOn || scheduled.unpublishOn;\n const actionLabel =\n scheduled.actionType === ScheduleActionType.unpublish ? \"unpublish\" : \"publish\";\n\n return (\n <Alert type={\"warning\"} variant={\"subtle\"} className={\"mb-md\"}>\n This entry has a {actionLabel} scheduled\n {goLiveOn ? ` for ${dateFormatter.format(goLiveOn)}` : \"\"}. {verb} now will cancel it.\n </Alert>\n );\n});\n"],"names":["ScheduleNoticeAlert","observer","targetId","verb","presenter","useScheduledActionsPresenter","dateFormatter","useDateFormatter","scheduled","undefined","goLiveOn","actionLabel","ScheduleActionType","Alert"],"mappings":";;;;;;AAkBO,MAAMA,sBAAsBC,SAAS,CAAC,EAAEC,QAAQ,EAAEC,IAAI,EAA4B;IACrF,MAAMC,YAAYC;IAClB,MAAMC,gBAAgBC;IAEtB,MAAMC,YAAYN,WAAWE,UAAU,kBAAkB,CAACF,YAAYO;IAEtE,IAAI,CAACD,WACD,OAAO;IAGX,MAAME,WAAWF,UAAU,SAAS,IAAIA,UAAU,WAAW;IAC7D,MAAMG,cACFH,UAAU,UAAU,KAAKI,mBAAmB,SAAS,GAAG,cAAc;IAE1E,OAAO,WAAP,GACI,oBAACC,OAAKA;QAAC,MAAM;QAAW,SAAS;QAAU,WAAW;OAAS,qBACzCF,aAAY,cAC7BD,WAAW,CAAC,KAAK,EAAEJ,cAAc,MAAM,CAACI,WAAW,GAAG,IAAG,MAAGP,MAAK;AAG9E"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Decorates the "Unpublish entry" dialog to warn (via its `intro` prop) that unpublishing now will
|
|
4
|
+
* cancel an existing scheduled action for the entry.
|
|
5
|
+
*/
|
|
6
|
+
export declare const UnpublishScheduleNoticeDecorator: (props: unknown) => React.JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import react from "react";
|
|
2
|
+
import { useNamedConfirmationDialog } from "@webiny/app-admin";
|
|
3
|
+
import { UnpublishEntryConfirmDialog } from "@webiny/app-headless-cms/exports/admin/cms.js";
|
|
4
|
+
import { ScheduleNoticeAlert } from "./ScheduleNoticeAlert.js";
|
|
5
|
+
const UnpublishScheduleNoticeDecorator = UnpublishEntryConfirmDialog.createDecorator((Original)=>function(props) {
|
|
6
|
+
const { params } = useNamedConfirmationDialog();
|
|
7
|
+
return /*#__PURE__*/ react.createElement(Original, {
|
|
8
|
+
...props,
|
|
9
|
+
intro: /*#__PURE__*/ react.createElement(react.Fragment, null, props.intro, /*#__PURE__*/ react.createElement(ScheduleNoticeAlert, {
|
|
10
|
+
targetId: params.entryId,
|
|
11
|
+
verb: "Unpublishing"
|
|
12
|
+
}))
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
export { UnpublishScheduleNoticeDecorator };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=UnpublishScheduleNotice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components/Dialogs/UnpublishScheduleNotice.js","sources":["../../../src/components/Dialogs/UnpublishScheduleNotice.tsx"],"sourcesContent":["import React from \"react\";\nimport { useNamedConfirmationDialog } from \"@webiny/app-admin\";\nimport { UnpublishEntryConfirmDialog } from \"@webiny/app-headless-cms/exports/admin/cms.js\";\nimport { ScheduleNoticeAlert } from \"./ScheduleNoticeAlert.js\";\n\n/**\n * Decorates the \"Unpublish entry\" dialog to warn (via its `intro` prop) that unpublishing now will\n * cancel an existing scheduled action for the entry.\n */\nexport const UnpublishScheduleNoticeDecorator = UnpublishEntryConfirmDialog.createDecorator(\n Original => {\n return function UnpublishEntryConfirmDialogWithNotice(props) {\n const { params } = useNamedConfirmationDialog<{ entryId: string }>();\n return (\n <Original\n {...props}\n intro={\n <>\n {props.intro}\n <ScheduleNoticeAlert targetId={params.entryId} verb={\"Unpublishing\"} />\n </>\n }\n />\n );\n };\n }\n);\n"],"names":["UnpublishScheduleNoticeDecorator","UnpublishEntryConfirmDialog","Original","props","params","useNamedConfirmationDialog","ScheduleNoticeAlert"],"mappings":";;;;AASO,MAAMA,mCAAmCC,4BAA4B,eAAe,CACvFC,CAAAA,WACW,SAA+CC,KAAK;QACvD,MAAM,EAAEC,MAAM,EAAE,GAAGC;QACnB,OAAO,WAAP,GACI,oBAACH,UAAAA;YACI,GAAGC,KAAK;YACT,qBACI,0CACKA,MAAM,KAAK,gBACZ,oBAACG,qBAAmBA;gBAAC,UAAUF,OAAO,OAAO;gBAAE,MAAM;;;IAKzE"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { IsModelPublishable } from "@webiny/app-headless-cms/exports/admin/cms.js";
|
|
2
|
-
import { ContentEntryEditorConfig } from "@webiny/app-headless-cms/exports/admin/cms/entry/editor.js";
|
|
3
1
|
import react from "react";
|
|
2
|
+
import { InternalContentEntryEditorConfig } from "@webiny/app-headless-cms";
|
|
3
|
+
import { IsModelPublishable } from "@webiny/app-headless-cms/exports/admin/cms.js";
|
|
4
4
|
import { MenuItem } from "./MenuItem.js";
|
|
5
|
-
const { Actions: Actions } =
|
|
6
|
-
const EditorConfig = ()=>/*#__PURE__*/ react.createElement(
|
|
5
|
+
const { Actions: Actions } = InternalContentEntryEditorConfig;
|
|
6
|
+
const EditorConfig = ()=>/*#__PURE__*/ react.createElement(InternalContentEntryEditorConfig, null, /*#__PURE__*/ react.createElement(IsModelPublishable, null, /*#__PURE__*/ react.createElement(Actions.MenuItemAction, {
|
|
7
7
|
name: "schedule",
|
|
8
8
|
element: /*#__PURE__*/ react.createElement(MenuItem, null)
|
|
9
9
|
})));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components/Editor/EditorConfig.js","sources":["../../../src/components/Editor/EditorConfig.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"components/Editor/EditorConfig.js","sources":["../../../src/components/Editor/EditorConfig.tsx"],"sourcesContent":["import React from \"react\";\nimport { InternalContentEntryEditorConfig } from \"@webiny/app-headless-cms\";\nimport { IsModelPublishable } from \"@webiny/app-headless-cms/exports/admin/cms.js\";\nimport { MenuItem } from \"./MenuItem.js\";\n\nconst { Actions } = InternalContentEntryEditorConfig;\n\nexport const EditorConfig = () => {\n return (\n <InternalContentEntryEditorConfig>\n <IsModelPublishable>\n <Actions.MenuItemAction name={\"schedule\"} element={<MenuItem />} />\n </IsModelPublishable>\n </InternalContentEntryEditorConfig>\n );\n};\n"],"names":["Actions","InternalContentEntryEditorConfig","EditorConfig","IsModelPublishable","MenuItem"],"mappings":";;;;AAKA,MAAM,EAAEA,SAAAA,OAAO,EAAE,GAAGC;AAEb,MAAMC,eAAe,IACjB,WAAP,GACI,oBAACD,kCAAgCA,MAAAA,WAAAA,GAC7B,oBAACE,oBAAkBA,MAAAA,WAAAA,GACf,oBAACH,QAAQ,cAAc;QAAC,MAAM;QAAY,uBAAS,oBAACI,UAAQA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
export declare const MenuItem: (() => React.JSX.Element | null) & {
|
|
3
|
-
|
|
2
|
+
export declare const MenuItem: (() => React.JSX.Element | null) & React.NamedExoticComponent<unknown> & {
|
|
3
|
+
readonly type: () => React.JSX.Element | null;
|
|
4
4
|
};
|
|
@@ -6,7 +6,9 @@ import { ReactComponent } from "@webiny/icons/cell_tower.svg";
|
|
|
6
6
|
import { useScheduleDialog } from "@webiny/app-scheduler";
|
|
7
7
|
import { usePermissions } from "../../hooks/usePermissions.js";
|
|
8
8
|
import { createNamespace } from "../../utils/index.js";
|
|
9
|
+
import { useScheduledActionsPresenter } from "../../hooks/useScheduledActionsPresenter.js";
|
|
9
10
|
const MenuItemWithId = ({ entryId, entryTitle, entryStatus, modelId, loading })=>{
|
|
11
|
+
const scheduledActions = useScheduledActionsPresenter();
|
|
10
12
|
const { showDialog: showSchedulerDialog } = useScheduleDialog({
|
|
11
13
|
namespace: createNamespace({
|
|
12
14
|
modelId
|
|
@@ -15,7 +17,8 @@ const MenuItemWithId = ({ entryId, entryTitle, entryStatus, modelId, loading })=
|
|
|
15
17
|
id: entryId,
|
|
16
18
|
title: entryTitle,
|
|
17
19
|
status: entryStatus
|
|
18
|
-
}
|
|
20
|
+
},
|
|
21
|
+
onCompleted: ()=>scheduledActions.reload()
|
|
19
22
|
});
|
|
20
23
|
const showDialog = useCallback(()=>{
|
|
21
24
|
showSchedulerDialog();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components/Editor/MenuItem.js","sources":["../../../src/components/Editor/MenuItem.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { OptionsMenuItem } from \"@webiny/app-admin\";\nimport { useContentEntryFormPresenter } from \"@webiny/app-headless-cms/exports/admin/cms/entry/editor.js\";\nimport { ReactComponent as ScheduleIcon } from \"@webiny/icons/cell_tower.svg\";\nimport { useScheduleDialog } from \"@webiny/app-scheduler\";\nimport { usePermissions } from \"~/hooks/usePermissions.js\";\nimport { createNamespace } from \"~/utils/index.js\";\n\ninterface MenuItemWithIdProps {\n entryId: string;\n entryTitle: string;\n entryStatus: string;\n modelId: string;\n loading: boolean;\n}\n\nconst MenuItemWithId = ({\n entryId,\n entryTitle,\n entryStatus,\n modelId,\n loading\n}: MenuItemWithIdProps) => {\n const { showDialog: showSchedulerDialog } = useScheduleDialog({\n namespace: createNamespace({ modelId }),\n target: {\n id: entryId,\n title: entryTitle,\n status: entryStatus\n }\n });\n\n const showDialog = useCallback(() => {\n showSchedulerDialog();\n }, [showSchedulerDialog]);\n\n const action = entryStatus === \"published\" ? \"unpublish\" : \"publish\";\n\n return (\n <OptionsMenuItem\n icon={<ScheduleIcon />}\n label={`Schedule ${action}`}\n onAction={showDialog}\n disabled={!entryStatus || loading}\n data-testid={\"cms.content-form.header.schedule\"}\n />\n );\n};\n\nexport const MenuItem = observer(() => {\n const presenter = useContentEntryFormPresenter();\n const { canPublish, canUnpublish } = usePermissions();\n\n const vm = presenter.vm;\n\n if (!vm.canPublish && !vm.canUnpublish) {\n return null;\n }\n\n if (!canPublish && !canUnpublish) {\n return null;\n }\n\n if (!vm.entry) {\n return (\n <OptionsMenuItem\n icon={<ScheduleIcon />}\n label={\"Schedule\"}\n onAction={() => void 0}\n disabled={true}\n data-testid={\"cms.content-form.header.schedule\"}\n />\n );\n }\n\n return (\n <MenuItemWithId\n entryId={vm.entry.id}\n entryTitle={vm.entry.meta?.title || \"\"}\n entryStatus={vm.entry.meta?.status || \"\"}\n modelId={vm.model.modelId}\n loading={vm.loading !== null}\n />\n );\n});\n"],"names":["MenuItemWithId","entryId","entryTitle","entryStatus","modelId","loading","showSchedulerDialog","useScheduleDialog","createNamespace","showDialog","useCallback","action","OptionsMenuItem","ScheduleIcon","MenuItem","observer","presenter","useContentEntryFormPresenter","canPublish","canUnpublish","usePermissions","vm"],"mappings":"
|
|
1
|
+
{"version":3,"file":"components/Editor/MenuItem.js","sources":["../../../src/components/Editor/MenuItem.tsx"],"sourcesContent":["import React, { useCallback } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { OptionsMenuItem } from \"@webiny/app-admin\";\nimport { useContentEntryFormPresenter } from \"@webiny/app-headless-cms/exports/admin/cms/entry/editor.js\";\nimport { ReactComponent as ScheduleIcon } from \"@webiny/icons/cell_tower.svg\";\nimport { useScheduleDialog } from \"@webiny/app-scheduler\";\nimport { usePermissions } from \"~/hooks/usePermissions.js\";\nimport { createNamespace } from \"~/utils/index.js\";\nimport { useScheduledActionsPresenter } from \"~/hooks/useScheduledActionsPresenter.js\";\n\ninterface MenuItemWithIdProps {\n entryId: string;\n entryTitle: string;\n entryStatus: string;\n modelId: string;\n loading: boolean;\n}\n\nconst MenuItemWithId = ({\n entryId,\n entryTitle,\n entryStatus,\n modelId,\n loading\n}: MenuItemWithIdProps) => {\n const scheduledActions = useScheduledActionsPresenter();\n const { showDialog: showSchedulerDialog } = useScheduleDialog({\n namespace: createNamespace({ modelId }),\n target: {\n id: entryId,\n title: entryTitle,\n status: entryStatus\n },\n onCompleted: () => scheduledActions.reload()\n });\n\n const showDialog = useCallback(() => {\n showSchedulerDialog();\n }, [showSchedulerDialog]);\n\n const action = entryStatus === \"published\" ? \"unpublish\" : \"publish\";\n\n return (\n <OptionsMenuItem\n icon={<ScheduleIcon />}\n label={`Schedule ${action}`}\n onAction={showDialog}\n disabled={!entryStatus || loading}\n data-testid={\"cms.content-form.header.schedule\"}\n />\n );\n};\n\nexport const MenuItem = observer(() => {\n const presenter = useContentEntryFormPresenter();\n const { canPublish, canUnpublish } = usePermissions();\n\n const vm = presenter.vm;\n\n if (!vm.canPublish && !vm.canUnpublish) {\n return null;\n }\n\n if (!canPublish && !canUnpublish) {\n return null;\n }\n\n if (!vm.entry) {\n return (\n <OptionsMenuItem\n icon={<ScheduleIcon />}\n label={\"Schedule\"}\n onAction={() => void 0}\n disabled={true}\n data-testid={\"cms.content-form.header.schedule\"}\n />\n );\n }\n\n return (\n <MenuItemWithId\n entryId={vm.entry.id}\n entryTitle={vm.entry.meta?.title || \"\"}\n entryStatus={vm.entry.meta?.status || \"\"}\n modelId={vm.model.modelId}\n loading={vm.loading !== null}\n />\n );\n});\n"],"names":["MenuItemWithId","entryId","entryTitle","entryStatus","modelId","loading","scheduledActions","useScheduledActionsPresenter","showSchedulerDialog","useScheduleDialog","createNamespace","showDialog","useCallback","action","OptionsMenuItem","ScheduleIcon","MenuItem","observer","presenter","useContentEntryFormPresenter","canPublish","canUnpublish","usePermissions","vm"],"mappings":";;;;;;;;;AAkBA,MAAMA,iBAAiB,CAAC,EACpBC,OAAO,EACPC,UAAU,EACVC,WAAW,EACXC,OAAO,EACPC,OAAO,EACW;IAClB,MAAMC,mBAAmBC;IACzB,MAAM,EAAE,YAAYC,mBAAmB,EAAE,GAAGC,kBAAkB;QAC1D,WAAWC,gBAAgB;YAAEN;QAAQ;QACrC,QAAQ;YACJ,IAAIH;YACJ,OAAOC;YACP,QAAQC;QACZ;QACA,aAAa,IAAMG,iBAAiB,MAAM;IAC9C;IAEA,MAAMK,aAAaC,YAAY;QAC3BJ;IACJ,GAAG;QAACA;KAAoB;IAExB,MAAMK,SAASV,AAAgB,gBAAhBA,cAA8B,cAAc;IAE3D,OAAO,WAAP,GACI,oBAACW,iBAAeA;QACZ,oBAAM,oBAACC,gBAAYA;QACnB,OAAO,CAAC,SAAS,EAAEF,QAAQ;QAC3B,UAAUF;QACV,UAAU,CAACR,eAAeE;QAC1B,eAAa;;AAGzB;AAEO,MAAMW,WAAWC,SAAS;IAC7B,MAAMC,YAAYC;IAClB,MAAM,EAAEC,UAAU,EAAEC,YAAY,EAAE,GAAGC;IAErC,MAAMC,KAAKL,UAAU,EAAE;IAEvB,IAAI,CAACK,GAAG,UAAU,IAAI,CAACA,GAAG,YAAY,EAClC,OAAO;IAGX,IAAI,CAACH,cAAc,CAACC,cAChB,OAAO;IAGX,IAAI,CAACE,GAAG,KAAK,EACT,OAAO,WAAP,GACI,oBAACT,iBAAeA;QACZ,oBAAM,oBAACC,gBAAYA;QACnB,OAAO;QACP,UAAU,IAAM,KAAK;QACrB,UAAU;QACV,eAAa;;IAKzB,OAAO,WAAP,GACI,oBAACf,gBAAcA;QACX,SAASuB,GAAG,KAAK,CAAC,EAAE;QACpB,YAAYA,GAAG,KAAK,CAAC,IAAI,EAAE,SAAS;QACpC,aAAaA,GAAG,KAAK,CAAC,IAAI,EAAE,UAAU;QACtC,SAASA,GAAG,KAAK,CAAC,OAAO;QACzB,SAASA,AAAe,SAAfA,GAAG,OAAO;;AAG/B"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Decorates the content entry form layout to render the scheduled-action bar below the header,
|
|
4
|
+
* above the form content (mirroring how the workflow bar is positioned).
|
|
5
|
+
*/
|
|
6
|
+
export declare const ScheduledActionAlertDecorator: (props: unknown) => React.JSX.Element;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import react, { useEffect } from "react";
|
|
2
|
+
import { observer } from "mobx-react-lite";
|
|
3
|
+
import { ReactComponent } from "@webiny/icons/access_time.svg";
|
|
4
|
+
import { Alert } from "@webiny/admin-ui";
|
|
5
|
+
import { ContentEntryFormContent } from "@webiny/app-headless-cms/presentation/contentEntries/views/layout/index.js";
|
|
6
|
+
import { useContentEntryFormPresenter } from "@webiny/app-headless-cms/exports/admin/cms/entry/editor.js";
|
|
7
|
+
import { ScheduleActionType } from "@webiny/app-scheduler/types.js";
|
|
8
|
+
import { useDateFormatter } from "@webiny/app-admin";
|
|
9
|
+
import { useScheduledActionsPresenter } from "../../hooks/useScheduledActionsPresenter.js";
|
|
10
|
+
const ScheduledActionBar = observer(()=>{
|
|
11
|
+
const formPresenter = useContentEntryFormPresenter();
|
|
12
|
+
const presenter = useScheduledActionsPresenter();
|
|
13
|
+
const dateFormatter = useDateFormatter();
|
|
14
|
+
const vm = formPresenter.vm;
|
|
15
|
+
const entryId = vm.entry?.id;
|
|
16
|
+
const modelId = vm.model?.modelId;
|
|
17
|
+
useEffect(()=>{
|
|
18
|
+
if (entryId && modelId) presenter.loadForEntry(modelId, entryId);
|
|
19
|
+
}, [
|
|
20
|
+
presenter,
|
|
21
|
+
entryId,
|
|
22
|
+
modelId
|
|
23
|
+
]);
|
|
24
|
+
const scheduled = entryId ? presenter.getScheduledAction(entryId) : void 0;
|
|
25
|
+
const status = vm.entry?.meta?.status;
|
|
26
|
+
const redundant = !!scheduled && (scheduled.actionType === ScheduleActionType.unpublish ? "unpublished" === status : "published" === status);
|
|
27
|
+
if (!scheduled || redundant) return null;
|
|
28
|
+
const goLiveOn = scheduled.publishOn || scheduled.unpublishOn;
|
|
29
|
+
const actionLabel = scheduled.actionType === ScheduleActionType.unpublish ? "unpublish" : "publish";
|
|
30
|
+
return /*#__PURE__*/ react.createElement("div", {
|
|
31
|
+
className: "max-w-screen bg-white p-sm border-solid border-b-sm border-neutral-dimmed"
|
|
32
|
+
}, /*#__PURE__*/ react.createElement(Alert, {
|
|
33
|
+
type: "warning",
|
|
34
|
+
variant: "subtle",
|
|
35
|
+
icon: /*#__PURE__*/ react.createElement(ReactComponent, null)
|
|
36
|
+
}, goLiveOn ? /*#__PURE__*/ react.createElement(react.Fragment, null, "This entry is scheduled to ", actionLabel, " on", " ", /*#__PURE__*/ react.createElement("strong", null, dateFormatter.format(goLiveOn)), ".") : /*#__PURE__*/ react.createElement(react.Fragment, null, "This entry is scheduled to ", actionLabel, ".")));
|
|
37
|
+
});
|
|
38
|
+
const ScheduledActionAlertDecorator = ContentEntryFormContent.createDecorator((Original)=>function(props) {
|
|
39
|
+
return /*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(ScheduledActionBar, null), /*#__PURE__*/ react.createElement(Original, props));
|
|
40
|
+
});
|
|
41
|
+
export { ScheduledActionAlertDecorator };
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=ScheduledActionAlert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components/Editor/ScheduledActionAlert.js","sources":["../../../src/components/Editor/ScheduledActionAlert.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\nimport { observer } from \"mobx-react-lite\";\nimport { ReactComponent as ScheduledIcon } from \"@webiny/icons/access_time.svg\";\nimport { Alert } from \"@webiny/admin-ui\";\nimport { ContentEntryFormContent } from \"@webiny/app-headless-cms/presentation/contentEntries/views/layout/index.js\";\nimport { useContentEntryFormPresenter } from \"@webiny/app-headless-cms/exports/admin/cms/entry/editor.js\";\nimport { ScheduleActionType } from \"@webiny/app-scheduler/types.js\";\nimport { useDateFormatter } from \"@webiny/app-admin\";\nimport { useScheduledActionsPresenter } from \"~/hooks/useScheduledActionsPresenter.js\";\n\n/**\n * Full-width bar shown below the entry-form header (above the form content) when the entry has a\n * scheduled publish/unpublish. Positioned like the workflow bar for visual consistency.\n */\nconst ScheduledActionBar = observer(() => {\n const formPresenter = useContentEntryFormPresenter();\n const presenter = useScheduledActionsPresenter();\n const dateFormatter = useDateFormatter();\n\n const vm = formPresenter.vm;\n const entryId = vm.entry?.id;\n const modelId = vm.model?.modelId;\n\n useEffect(() => {\n if (entryId && modelId) {\n presenter.loadForEntry(modelId, entryId);\n }\n }, [presenter, entryId, modelId]);\n\n const scheduled = entryId ? presenter.getScheduledAction(entryId) : undefined;\n\n // Reconcile against the entry's current status: a direct publish/unpublish supersedes the\n // scheduled action (the API cancels it asynchronously), so hide the bar immediately.\n const status = vm.entry?.meta?.status;\n const redundant =\n !!scheduled &&\n (scheduled.actionType === ScheduleActionType.unpublish\n ? status === \"unpublished\"\n : status === \"published\");\n\n if (!scheduled || redundant) {\n return null;\n }\n\n const goLiveOn = scheduled.publishOn || scheduled.unpublishOn;\n const actionLabel =\n scheduled.actionType === ScheduleActionType.unpublish ? \"unpublish\" : \"publish\";\n\n // Match the workflow bar: a full-width white strip (below the header) containing the alert.\n return (\n <div\n className={\"max-w-screen bg-white p-sm border-solid border-b-sm border-neutral-dimmed\"}\n >\n <Alert type={\"warning\"} variant={\"subtle\"} icon={<ScheduledIcon />}>\n {goLiveOn ? (\n <>\n This entry is scheduled to {actionLabel} on{\" \"}\n <strong>{dateFormatter.format(goLiveOn)}</strong>.\n </>\n ) : (\n <>This entry is scheduled to {actionLabel}.</>\n )}\n </Alert>\n </div>\n );\n});\n\n/**\n * Decorates the content entry form layout to render the scheduled-action bar below the header,\n * above the form content (mirroring how the workflow bar is positioned).\n */\nexport const ScheduledActionAlertDecorator = ContentEntryFormContent.createDecorator(Original => {\n return function ContentEntryFormContentWithScheduledBar(props) {\n return (\n <>\n <ScheduledActionBar />\n <Original {...props} />\n </>\n );\n };\n});\n"],"names":["ScheduledActionBar","observer","formPresenter","useContentEntryFormPresenter","presenter","useScheduledActionsPresenter","dateFormatter","useDateFormatter","vm","entryId","modelId","useEffect","scheduled","undefined","status","redundant","ScheduleActionType","goLiveOn","actionLabel","Alert","ScheduledIcon","ScheduledActionAlertDecorator","ContentEntryFormContent","Original","props"],"mappings":";;;;;;;;;AAcA,MAAMA,qBAAqBC,SAAS;IAChC,MAAMC,gBAAgBC;IACtB,MAAMC,YAAYC;IAClB,MAAMC,gBAAgBC;IAEtB,MAAMC,KAAKN,cAAc,EAAE;IAC3B,MAAMO,UAAUD,GAAG,KAAK,EAAE;IAC1B,MAAME,UAAUF,GAAG,KAAK,EAAE;IAE1BG,UAAU;QACN,IAAIF,WAAWC,SACXN,UAAU,YAAY,CAACM,SAASD;IAExC,GAAG;QAACL;QAAWK;QAASC;KAAQ;IAEhC,MAAME,YAAYH,UAAUL,UAAU,kBAAkB,CAACK,WAAWI;IAIpE,MAAMC,SAASN,GAAG,KAAK,EAAE,MAAM;IAC/B,MAAMO,YACF,CAAC,CAACH,aACDA,CAAAA,UAAU,UAAU,KAAKI,mBAAmB,SAAS,GAChDF,AAAW,kBAAXA,SACAA,AAAW,gBAAXA,MAAqB;IAE/B,IAAI,CAACF,aAAaG,WACd,OAAO;IAGX,MAAME,WAAWL,UAAU,SAAS,IAAIA,UAAU,WAAW;IAC7D,MAAMM,cACFN,UAAU,UAAU,KAAKI,mBAAmB,SAAS,GAAG,cAAc;IAG1E,OAAO,WAAP,GACI,oBAAC;QACG,WAAW;qBAEX,oBAACG,OAAKA;QAAC,MAAM;QAAW,SAAS;QAAU,oBAAM,oBAACC,gBAAaA;OAC1DH,WAAW,WAAXA,GACG,0CAAE,+BAC8BC,aAAY,OAAI,mBAC5C,oBAAC,gBAAQZ,cAAc,MAAM,CAACW,YAAmB,qBAGrD,0CAAE,+BAA4BC,aAAY;AAK9D;AAMO,MAAMG,gCAAgCC,wBAAwB,eAAe,CAACC,CAAAA,WAC1E,SAAiDC,KAAK;QACzD,OAAO,WAAP,GACI,wDACI,oBAACxB,oBAAkBA,OAAAA,WAAAA,GACnB,oBAACuB,UAAaC;IAG1B"}
|
package/components/index.d.ts
CHANGED
package/components/index.js
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ScheduledActionsPresenter } from "../presentation/scheduledActions/abstractions.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the shared ScheduledActionsPresenter — the source of scheduled-action state for the
|
|
4
|
+
* Live column, the entry-form bar and the publish/unpublish dialog notices.
|
|
5
|
+
*/
|
|
6
|
+
export declare const useScheduledActionsPresenter: () => ScheduledActionsPresenter.Interface;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useContainer } from "@webiny/app";
|
|
3
|
+
import { ScheduledActionsPresenter } from "../presentation/scheduledActions/abstractions.js";
|
|
4
|
+
const useScheduledActionsPresenter = ()=>{
|
|
5
|
+
const container = useContainer();
|
|
6
|
+
return useMemo(()=>container.resolve(ScheduledActionsPresenter), [
|
|
7
|
+
container
|
|
8
|
+
]);
|
|
9
|
+
};
|
|
10
|
+
export { useScheduledActionsPresenter };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=useScheduledActionsPresenter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks/useScheduledActionsPresenter.js","sources":["../../src/hooks/useScheduledActionsPresenter.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useContainer } from \"@webiny/app\";\nimport { ScheduledActionsPresenter } from \"~/presentation/scheduledActions/abstractions.js\";\n\n/**\n * Resolves the shared ScheduledActionsPresenter — the source of scheduled-action state for the\n * Live column, the entry-form bar and the publish/unpublish dialog notices.\n */\nexport const useScheduledActionsPresenter = (): ScheduledActionsPresenter.Interface => {\n const container = useContainer();\n return useMemo(() => container.resolve(ScheduledActionsPresenter), [container]);\n};\n"],"names":["useScheduledActionsPresenter","container","useContainer","useMemo","ScheduledActionsPresenter"],"mappings":";;;AAQO,MAAMA,+BAA+B;IACxC,MAAMC,YAAYC;IAClB,OAAOC,QAAQ,IAAMF,UAAU,OAAO,CAACG,4BAA4B;QAACH;KAAU;AAClF"}
|
package/index.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import react from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { RegisterFeature } from "@webiny/app-admin";
|
|
3
|
+
import { ScheduledActionsPresenterFeature } from "./presentation/scheduledActions/feature.js";
|
|
4
|
+
import { BrowserConfig, EditorConfig, PublishScheduleNoticeDecorator, ScheduledActionAlertDecorator, UnpublishScheduleNoticeDecorator } from "./components/index.js";
|
|
5
|
+
const CmsScheduler = ()=>/*#__PURE__*/ react.createElement(react.Fragment, null, /*#__PURE__*/ react.createElement(RegisterFeature, {
|
|
6
|
+
feature: ScheduledActionsPresenterFeature
|
|
7
|
+
}), /*#__PURE__*/ react.createElement(BrowserConfig, null), /*#__PURE__*/ react.createElement(EditorConfig, null), /*#__PURE__*/ react.createElement(ScheduledActionAlertDecorator, null), /*#__PURE__*/ react.createElement(PublishScheduleNoticeDecorator, null), /*#__PURE__*/ react.createElement(UnpublishScheduleNoticeDecorator, null));
|
|
4
8
|
export { CmsScheduler };
|
|
5
9
|
|
|
6
10
|
//# sourceMappingURL=index.js.map
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["import React from \"react\";\nimport {
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.tsx"],"sourcesContent":["import React from \"react\";\nimport { RegisterFeature } from \"@webiny/app-admin\";\nimport { ScheduledActionsPresenterFeature } from \"./presentation/scheduledActions/feature.js\";\nimport {\n EditorConfig,\n BrowserConfig,\n ScheduledActionAlertDecorator,\n PublishScheduleNoticeDecorator,\n UnpublishScheduleNoticeDecorator\n} from \"./components/index.js\";\n\nexport const CmsScheduler = () => {\n return (\n <>\n <RegisterFeature feature={ScheduledActionsPresenterFeature} />\n <BrowserConfig />\n <EditorConfig />\n <ScheduledActionAlertDecorator />\n <PublishScheduleNoticeDecorator />\n <UnpublishScheduleNoticeDecorator />\n </>\n );\n};\n"],"names":["CmsScheduler","RegisterFeature","ScheduledActionsPresenterFeature","BrowserConfig","EditorConfig","ScheduledActionAlertDecorator","PublishScheduleNoticeDecorator","UnpublishScheduleNoticeDecorator"],"mappings":";;;;AAWO,MAAMA,eAAe,IACjB,WAAP,GACI,wDACI,oBAACC,iBAAeA;QAAC,SAASC;sBAC1B,oBAACC,eAAaA,OAAAA,WAAAA,GACd,oBAACC,cAAYA,OAAAA,WAAAA,GACb,oBAACC,+BAA6BA,OAAAA,WAAAA,GAC9B,oBAACC,gCAA8BA,OAAAA,WAAAA,GAC/B,oBAACC,kCAAgCA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/app-headless-cms-scheduler",
|
|
3
|
-
"version": "6.6.0-alpha.
|
|
3
|
+
"version": "6.6.0-alpha.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -13,19 +13,22 @@
|
|
|
13
13
|
"author": "Webiny Ltd",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@webiny/admin-ui": "6.6.0-alpha.
|
|
17
|
-
"@webiny/app
|
|
18
|
-
"@webiny/app-
|
|
19
|
-
"@webiny/app-headless-cms
|
|
20
|
-
"@webiny/app-
|
|
21
|
-
"@webiny/
|
|
22
|
-
"
|
|
16
|
+
"@webiny/admin-ui": "6.6.0-alpha.2",
|
|
17
|
+
"@webiny/app": "6.6.0-alpha.2",
|
|
18
|
+
"@webiny/app-admin": "6.6.0-alpha.2",
|
|
19
|
+
"@webiny/app-headless-cms": "6.6.0-alpha.2",
|
|
20
|
+
"@webiny/app-headless-cms-common": "6.6.0-alpha.2",
|
|
21
|
+
"@webiny/app-scheduler": "6.6.0-alpha.2",
|
|
22
|
+
"@webiny/feature": "6.6.0-alpha.2",
|
|
23
|
+
"@webiny/icons": "6.6.0-alpha.2",
|
|
24
|
+
"mobx": "7.0.3",
|
|
25
|
+
"mobx-react-lite": "5.0.3",
|
|
23
26
|
"react": "18.3.1",
|
|
24
27
|
"react-dom": "18.3.1"
|
|
25
28
|
},
|
|
26
29
|
"devDependencies": {
|
|
27
30
|
"@types/react": "18.3.31",
|
|
28
|
-
"@webiny/build-tools": "6.6.0-alpha.
|
|
31
|
+
"@webiny/build-tools": "6.6.0-alpha.2",
|
|
29
32
|
"rimraf": "6.1.3",
|
|
30
33
|
"typescript": "7.0.2"
|
|
31
34
|
},
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type IContentEntriesPresenter, type IContentEntriesInitConfig } from "@webiny/app-headless-cms/presentation/contentEntries/list/abstractions.js";
|
|
2
|
+
import { ScheduledActionsPresenter } from "./abstractions.js";
|
|
3
|
+
/**
|
|
4
|
+
* Decorates the content-entries list presenter so the scheduled actions for the current model are
|
|
5
|
+
* (re)loaded whenever the visible rows change. The reaction key includes each row's status/live,
|
|
6
|
+
* so a direct publish/unpublish (which changes those, and lets the API cancel a schedule) triggers
|
|
7
|
+
* a refresh without any extra signalling.
|
|
8
|
+
*/
|
|
9
|
+
declare class ContentEntriesPresenterWithScheduling implements IContentEntriesPresenter {
|
|
10
|
+
private scheduledActions;
|
|
11
|
+
private original;
|
|
12
|
+
private _disposeReaction;
|
|
13
|
+
constructor(scheduledActions: ScheduledActionsPresenter.Interface, original: IContentEntriesPresenter);
|
|
14
|
+
get vm(): import("@webiny/app-headless-cms/presentation/contentEntries/list/abstractions.js").IContentEntriesViewModel;
|
|
15
|
+
get list(): import("@webiny/app-admin/presentation/listPresenter/abstractions.js").IListPresenter<import("@webiny/app-headless-cms/types.js").CmsContentEntry<import("@webiny/app/types.js").GenericRecord>>;
|
|
16
|
+
get folders(): import("@webiny/app-aco/index.js").IFolderTreePresenter;
|
|
17
|
+
init(config?: IContentEntriesInitConfig): void;
|
|
18
|
+
dispose(): void;
|
|
19
|
+
selectEntry(id: string): void;
|
|
20
|
+
deselectEntry(): void;
|
|
21
|
+
createEntry(): void;
|
|
22
|
+
deleteEntry(id: string): Promise<boolean>;
|
|
23
|
+
publishEntry(id: string): Promise<boolean>;
|
|
24
|
+
unpublishEntry(id: string): Promise<boolean>;
|
|
25
|
+
moveEntry(id: string, folderId: string): Promise<boolean>;
|
|
26
|
+
}
|
|
27
|
+
export declare const ContentEntriesPresenterSchedulingDecorator: typeof ContentEntriesPresenterWithScheduling & {
|
|
28
|
+
__abstraction: import("@webiny/di").Abstraction<IContentEntriesPresenter>;
|
|
29
|
+
};
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { compareStructural, reaction } from "mobx";
|
|
2
|
+
import { ContentEntriesPresenter } from "@webiny/app-headless-cms/presentation/contentEntries/list/abstractions.js";
|
|
3
|
+
import { ScheduledActionsPresenter } from "./abstractions.js";
|
|
4
|
+
class ContentEntriesPresenterWithScheduling {
|
|
5
|
+
constructor(scheduledActions, original){
|
|
6
|
+
this.scheduledActions = scheduledActions;
|
|
7
|
+
this.original = original;
|
|
8
|
+
this._disposeReaction = null;
|
|
9
|
+
}
|
|
10
|
+
get vm() {
|
|
11
|
+
return this.original.vm;
|
|
12
|
+
}
|
|
13
|
+
get list() {
|
|
14
|
+
return this.original.list;
|
|
15
|
+
}
|
|
16
|
+
get folders() {
|
|
17
|
+
return this.original.folders;
|
|
18
|
+
}
|
|
19
|
+
init(config) {
|
|
20
|
+
this.original.init(config);
|
|
21
|
+
this._disposeReaction = reaction(()=>this.original.list.vm.rows.map((row)=>`${row.id}:${row.meta?.status ?? ""}:${row.live?.version ?? ""}`), (keys)=>{
|
|
22
|
+
if (0 === keys.length) return;
|
|
23
|
+
this.scheduledActions.loadForModel(this.original.vm.model.modelId);
|
|
24
|
+
}, {
|
|
25
|
+
fireImmediately: true,
|
|
26
|
+
equals: compareStructural
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
dispose() {
|
|
30
|
+
if (this._disposeReaction) {
|
|
31
|
+
this._disposeReaction();
|
|
32
|
+
this._disposeReaction = null;
|
|
33
|
+
}
|
|
34
|
+
this.scheduledActions.dispose();
|
|
35
|
+
this.original.dispose();
|
|
36
|
+
}
|
|
37
|
+
selectEntry(id) {
|
|
38
|
+
this.original.selectEntry(id);
|
|
39
|
+
}
|
|
40
|
+
deselectEntry() {
|
|
41
|
+
this.original.deselectEntry();
|
|
42
|
+
}
|
|
43
|
+
createEntry() {
|
|
44
|
+
this.original.createEntry();
|
|
45
|
+
}
|
|
46
|
+
deleteEntry(id) {
|
|
47
|
+
return this.original.deleteEntry(id);
|
|
48
|
+
}
|
|
49
|
+
publishEntry(id) {
|
|
50
|
+
return this.original.publishEntry(id);
|
|
51
|
+
}
|
|
52
|
+
unpublishEntry(id) {
|
|
53
|
+
return this.original.unpublishEntry(id);
|
|
54
|
+
}
|
|
55
|
+
moveEntry(id, folderId) {
|
|
56
|
+
return this.original.moveEntry(id, folderId);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const ContentEntriesPresenterSchedulingDecorator = ContentEntriesPresenter.createDecorator({
|
|
60
|
+
decorator: ContentEntriesPresenterWithScheduling,
|
|
61
|
+
dependencies: [
|
|
62
|
+
ScheduledActionsPresenter
|
|
63
|
+
]
|
|
64
|
+
});
|
|
65
|
+
export { ContentEntriesPresenterSchedulingDecorator };
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=ContentEntriesPresenterSchedulingDecorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation/scheduledActions/ContentEntriesPresenterSchedulingDecorator.js","sources":["../../../src/presentation/scheduledActions/ContentEntriesPresenterSchedulingDecorator.ts"],"sourcesContent":["import { compareStructural, reaction } from \"mobx\";\nimport type { IReactionDisposer } from \"mobx\";\nimport {\n ContentEntriesPresenter,\n type IContentEntriesPresenter,\n type IContentEntriesInitConfig\n} from \"@webiny/app-headless-cms/presentation/contentEntries/list/abstractions.js\";\nimport { ScheduledActionsPresenter } from \"./abstractions.js\";\n\n/**\n * Decorates the content-entries list presenter so the scheduled actions for the current model are\n * (re)loaded whenever the visible rows change. The reaction key includes each row's status/live,\n * so a direct publish/unpublish (which changes those, and lets the API cancel a schedule) triggers\n * a refresh without any extra signalling.\n */\nclass ContentEntriesPresenterWithScheduling implements IContentEntriesPresenter {\n private _disposeReaction: IReactionDisposer | null = null;\n\n constructor(\n private scheduledActions: ScheduledActionsPresenter.Interface,\n private original: IContentEntriesPresenter\n ) {}\n\n get vm() {\n return this.original.vm;\n }\n\n get list() {\n return this.original.list;\n }\n\n get folders() {\n return this.original.folders;\n }\n\n init(config?: IContentEntriesInitConfig): void {\n this.original.init(config);\n\n this._disposeReaction = reaction(\n () =>\n this.original.list.vm.rows.map(\n row => `${row.id}:${row.meta?.status ?? \"\"}:${row.live?.version ?? \"\"}`\n ),\n keys => {\n if (keys.length === 0) {\n return;\n }\n this.scheduledActions.loadForModel(this.original.vm.model.modelId);\n },\n { fireImmediately: true, equals: compareStructural }\n );\n }\n\n dispose(): void {\n if (this._disposeReaction) {\n this._disposeReaction();\n this._disposeReaction = null;\n }\n this.scheduledActions.dispose();\n this.original.dispose();\n }\n\n selectEntry(id: string) {\n this.original.selectEntry(id);\n }\n\n deselectEntry() {\n this.original.deselectEntry();\n }\n\n createEntry() {\n this.original.createEntry();\n }\n\n deleteEntry(id: string) {\n return this.original.deleteEntry(id);\n }\n\n publishEntry(id: string) {\n return this.original.publishEntry(id);\n }\n\n unpublishEntry(id: string) {\n return this.original.unpublishEntry(id);\n }\n\n moveEntry(id: string, folderId: string) {\n return this.original.moveEntry(id, folderId);\n }\n}\n\nexport const ContentEntriesPresenterSchedulingDecorator = ContentEntriesPresenter.createDecorator({\n decorator: ContentEntriesPresenterWithScheduling,\n dependencies: [ScheduledActionsPresenter]\n});\n"],"names":["ContentEntriesPresenterWithScheduling","scheduledActions","original","config","reaction","row","keys","compareStructural","id","folderId","ContentEntriesPresenterSchedulingDecorator","ContentEntriesPresenter","ScheduledActionsPresenter"],"mappings":";;;AAeA,MAAMA;IAGF,YACYC,gBAAqD,EACrDC,QAAkC,CAC5C;aAFUD,gBAAgB,GAAhBA;aACAC,QAAQ,GAARA;aAJJ,gBAAgB,GAA6B;IAKlD;IAEH,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE;IAC3B;IAEA,IAAI,OAAO;QACP,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI;IAC7B;IAEA,IAAI,UAAU;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO;IAChC;IAEA,KAAKC,MAAkC,EAAQ;QAC3C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAACA;QAEnB,IAAI,CAAC,gBAAgB,GAAGC,SACpB,IACI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAC1BC,CAAAA,MAAO,GAAGA,IAAI,EAAE,CAAC,CAAC,EAAEA,IAAI,IAAI,EAAE,UAAU,GAAG,CAAC,EAAEA,IAAI,IAAI,EAAE,WAAW,IAAI,GAE/EC,CAAAA;YACI,IAAIA,AAAgB,MAAhBA,KAAK,MAAM,EACX;YAEJ,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO;QACrE,GACA;YAAE,iBAAiB;YAAM,QAAQC;QAAkB;IAE3D;IAEA,UAAgB;QACZ,IAAI,IAAI,CAAC,gBAAgB,EAAE;YACvB,IAAI,CAAC,gBAAgB;YACrB,IAAI,CAAC,gBAAgB,GAAG;QAC5B;QACA,IAAI,CAAC,gBAAgB,CAAC,OAAO;QAC7B,IAAI,CAAC,QAAQ,CAAC,OAAO;IACzB;IAEA,YAAYC,EAAU,EAAE;QACpB,IAAI,CAAC,QAAQ,CAAC,WAAW,CAACA;IAC9B;IAEA,gBAAgB;QACZ,IAAI,CAAC,QAAQ,CAAC,aAAa;IAC/B;IAEA,cAAc;QACV,IAAI,CAAC,QAAQ,CAAC,WAAW;IAC7B;IAEA,YAAYA,EAAU,EAAE;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAACA;IACrC;IAEA,aAAaA,EAAU,EAAE;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAACA;IACtC;IAEA,eAAeA,EAAU,EAAE;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,cAAc,CAACA;IACxC;IAEA,UAAUA,EAAU,EAAEC,QAAgB,EAAE;QACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,CAACD,IAAIC;IACvC;AACJ;AAEO,MAAMC,6CAA6CC,wBAAwB,eAAe,CAAC;IAC9F,WAAWX;IACX,cAAc;QAACY;KAA0B;AAC7C"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ListScheduledActionsGateway } from "@webiny/app-scheduler/features/listScheduledActions/abstractions.js";
|
|
2
|
+
import { GetScheduledActionGateway } from "@webiny/app-scheduler/features/getScheduledAction/abstractions.js";
|
|
3
|
+
import type { SchedulerEntry } from "@webiny/app-scheduler/types.js";
|
|
4
|
+
import { type IScheduledActionsPresenter } from "./abstractions.js";
|
|
5
|
+
/**
|
|
6
|
+
* Holds the scheduled actions relevant to the current view (entries list or a single entry),
|
|
7
|
+
* keyed by target (entry) id. Fetching is driven by the presenters that own the view — the list
|
|
8
|
+
* presenter decorator reloads on row changes, the form alert loads the open entry — so this holds
|
|
9
|
+
* no invalidation logic of its own beyond `reload()`.
|
|
10
|
+
*/
|
|
11
|
+
declare class ScheduledActionsPresenterImpl implements IScheduledActionsPresenter {
|
|
12
|
+
private listGateway;
|
|
13
|
+
private getGateway;
|
|
14
|
+
private _scheduledActions;
|
|
15
|
+
private _lastLoad;
|
|
16
|
+
constructor(listGateway: ListScheduledActionsGateway.Interface, getGateway: GetScheduledActionGateway.Interface);
|
|
17
|
+
getScheduledAction(targetId: string): SchedulerEntry | undefined;
|
|
18
|
+
loadForModel(modelId: string): Promise<void>;
|
|
19
|
+
loadForEntry(modelId: string, entryId: string): Promise<void>;
|
|
20
|
+
reload(): Promise<void>;
|
|
21
|
+
dispose(): void;
|
|
22
|
+
private fetchModel;
|
|
23
|
+
private fetchEntry;
|
|
24
|
+
}
|
|
25
|
+
export declare const ScheduledActionsPresenter: typeof ScheduledActionsPresenterImpl & {
|
|
26
|
+
__abstraction: import("@webiny/di").Abstraction<IScheduledActionsPresenter>;
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { makeAutoObservable, observable, runInAction } from "mobx";
|
|
2
|
+
import { ListScheduledActionsGateway } from "@webiny/app-scheduler/features/listScheduledActions/abstractions.js";
|
|
3
|
+
import { GetScheduledActionGateway } from "@webiny/app-scheduler/features/getScheduledAction/abstractions.js";
|
|
4
|
+
import { createNamespace } from "../../utils/index.js";
|
|
5
|
+
import { ScheduledActionsPresenter } from "./abstractions.js";
|
|
6
|
+
const PAGE_SIZE = 100;
|
|
7
|
+
class ScheduledActionsPresenterImpl {
|
|
8
|
+
constructor(listGateway, getGateway){
|
|
9
|
+
this.listGateway = listGateway;
|
|
10
|
+
this.getGateway = getGateway;
|
|
11
|
+
this._scheduledActions = observable.map();
|
|
12
|
+
this._lastLoad = null;
|
|
13
|
+
makeAutoObservable(this, {
|
|
14
|
+
listGateway: false,
|
|
15
|
+
getGateway: false,
|
|
16
|
+
_lastLoad: false
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
getScheduledAction(targetId) {
|
|
20
|
+
return this._scheduledActions.get(targetId);
|
|
21
|
+
}
|
|
22
|
+
loadForModel(modelId) {
|
|
23
|
+
const namespace = createNamespace({
|
|
24
|
+
modelId
|
|
25
|
+
});
|
|
26
|
+
this._lastLoad = ()=>this.fetchModel(namespace);
|
|
27
|
+
return this._lastLoad();
|
|
28
|
+
}
|
|
29
|
+
loadForEntry(modelId, entryId) {
|
|
30
|
+
const namespace = createNamespace({
|
|
31
|
+
modelId
|
|
32
|
+
});
|
|
33
|
+
this._lastLoad = ()=>this.fetchEntry(namespace, entryId);
|
|
34
|
+
return this._lastLoad();
|
|
35
|
+
}
|
|
36
|
+
reload() {
|
|
37
|
+
return this._lastLoad ? this._lastLoad() : Promise.resolve();
|
|
38
|
+
}
|
|
39
|
+
dispose() {
|
|
40
|
+
runInAction(()=>this._scheduledActions.clear());
|
|
41
|
+
this._lastLoad = null;
|
|
42
|
+
}
|
|
43
|
+
async fetchModel(namespace) {
|
|
44
|
+
try {
|
|
45
|
+
const actions = new Map();
|
|
46
|
+
let after;
|
|
47
|
+
do {
|
|
48
|
+
const response = await this.listGateway.execute({
|
|
49
|
+
namespace,
|
|
50
|
+
limit: PAGE_SIZE,
|
|
51
|
+
after,
|
|
52
|
+
sort: [
|
|
53
|
+
"scheduledFor_ASC"
|
|
54
|
+
]
|
|
55
|
+
});
|
|
56
|
+
for (const item of response.items)actions.set(item.targetId, item);
|
|
57
|
+
after = response.meta.hasMoreItems ? response.meta.cursor ?? void 0 : void 0;
|
|
58
|
+
}while (after)
|
|
59
|
+
runInAction(()=>{
|
|
60
|
+
this._scheduledActions.replace(actions);
|
|
61
|
+
});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(error);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async fetchEntry(namespace, entryId) {
|
|
67
|
+
try {
|
|
68
|
+
const action = await this.getGateway.execute({
|
|
69
|
+
namespace,
|
|
70
|
+
id: entryId
|
|
71
|
+
});
|
|
72
|
+
runInAction(()=>{
|
|
73
|
+
if (action) this._scheduledActions.set(entryId, action);
|
|
74
|
+
else this._scheduledActions.delete(entryId);
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const ScheduledActionsPresenter_ScheduledActionsPresenter = ScheduledActionsPresenter.createImplementation({
|
|
82
|
+
implementation: ScheduledActionsPresenterImpl,
|
|
83
|
+
dependencies: [
|
|
84
|
+
ListScheduledActionsGateway,
|
|
85
|
+
GetScheduledActionGateway
|
|
86
|
+
]
|
|
87
|
+
});
|
|
88
|
+
export { ScheduledActionsPresenter_ScheduledActionsPresenter as ScheduledActionsPresenter };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=ScheduledActionsPresenter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation/scheduledActions/ScheduledActionsPresenter.js","sources":["../../../src/presentation/scheduledActions/ScheduledActionsPresenter.ts"],"sourcesContent":["import { makeAutoObservable, observable, runInAction } from \"mobx\";\nimport { ListScheduledActionsGateway } from \"@webiny/app-scheduler/features/listScheduledActions/abstractions.js\";\nimport { GetScheduledActionGateway } from \"@webiny/app-scheduler/features/getScheduledAction/abstractions.js\";\nimport type { SchedulerEntry } from \"@webiny/app-scheduler/types.js\";\nimport { createNamespace } from \"~/utils/index.js\";\nimport {\n ScheduledActionsPresenter as Abstraction,\n type IScheduledActionsPresenter\n} from \"./abstractions.js\";\n\nconst PAGE_SIZE = 100;\n\n/**\n * Holds the scheduled actions relevant to the current view (entries list or a single entry),\n * keyed by target (entry) id. Fetching is driven by the presenters that own the view — the list\n * presenter decorator reloads on row changes, the form alert loads the open entry — so this holds\n * no invalidation logic of its own beyond `reload()`.\n */\nclass ScheduledActionsPresenterImpl implements IScheduledActionsPresenter {\n private _scheduledActions = observable.map<string, SchedulerEntry>();\n private _lastLoad: (() => Promise<void>) | null = null;\n\n constructor(\n private listGateway: ListScheduledActionsGateway.Interface,\n private getGateway: GetScheduledActionGateway.Interface\n ) {\n makeAutoObservable<\n ScheduledActionsPresenterImpl,\n \"listGateway\" | \"getGateway\" | \"_lastLoad\"\n >(this, {\n listGateway: false,\n getGateway: false,\n _lastLoad: false\n });\n }\n\n getScheduledAction(targetId: string): SchedulerEntry | undefined {\n return this._scheduledActions.get(targetId);\n }\n\n loadForModel(modelId: string): Promise<void> {\n const namespace = createNamespace({ modelId });\n this._lastLoad = () => this.fetchModel(namespace);\n return this._lastLoad();\n }\n\n loadForEntry(modelId: string, entryId: string): Promise<void> {\n const namespace = createNamespace({ modelId });\n this._lastLoad = () => this.fetchEntry(namespace, entryId);\n return this._lastLoad();\n }\n\n reload(): Promise<void> {\n return this._lastLoad ? this._lastLoad() : Promise.resolve();\n }\n\n dispose(): void {\n runInAction(() => this._scheduledActions.clear());\n this._lastLoad = null;\n }\n\n private async fetchModel(namespace: string): Promise<void> {\n try {\n const actions = new Map<string, SchedulerEntry>();\n let after: string | undefined = undefined;\n\n do {\n const response = await this.listGateway.execute({\n namespace,\n limit: PAGE_SIZE,\n after,\n sort: [\"scheduledFor_ASC\"]\n });\n for (const item of response.items) {\n actions.set(item.targetId, item);\n }\n after = response.meta.hasMoreItems\n ? (response.meta.cursor ?? undefined)\n : undefined;\n } while (after);\n\n runInAction(() => {\n this._scheduledActions.replace(actions);\n });\n } catch (error) {\n console.error(error);\n }\n }\n\n private async fetchEntry(namespace: string, entryId: string): Promise<void> {\n try {\n const action = await this.getGateway.execute({ namespace, id: entryId });\n runInAction(() => {\n if (action) {\n this._scheduledActions.set(entryId, action);\n } else {\n this._scheduledActions.delete(entryId);\n }\n });\n } catch (error) {\n console.error(error);\n }\n }\n}\n\nexport const ScheduledActionsPresenter = Abstraction.createImplementation({\n implementation: ScheduledActionsPresenterImpl,\n dependencies: [ListScheduledActionsGateway, GetScheduledActionGateway]\n});\n"],"names":["PAGE_SIZE","ScheduledActionsPresenterImpl","listGateway","getGateway","observable","makeAutoObservable","targetId","modelId","namespace","createNamespace","entryId","Promise","runInAction","actions","Map","after","response","item","undefined","error","console","action","ScheduledActionsPresenter","Abstraction","ListScheduledActionsGateway","GetScheduledActionGateway"],"mappings":";;;;;AAUA,MAAMA,YAAY;AAQlB,MAAMC;IAIF,YACYC,WAAkD,EAClDC,UAA+C,CACzD;aAFUD,WAAW,GAAXA;aACAC,UAAU,GAAVA;aALJ,iBAAiB,GAAGC,WAAW,GAAG;aAClC,SAAS,GAAiC;QAM9CC,mBAGE,IAAI,EAAE;YACJ,aAAa;YACb,YAAY;YACZ,WAAW;QACf;IACJ;IAEA,mBAAmBC,QAAgB,EAA8B;QAC7D,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAACA;IACtC;IAEA,aAAaC,OAAe,EAAiB;QACzC,MAAMC,YAAYC,gBAAgB;YAAEF;QAAQ;QAC5C,IAAI,CAAC,SAAS,GAAG,IAAM,IAAI,CAAC,UAAU,CAACC;QACvC,OAAO,IAAI,CAAC,SAAS;IACzB;IAEA,aAAaD,OAAe,EAAEG,OAAe,EAAiB;QAC1D,MAAMF,YAAYC,gBAAgB;YAAEF;QAAQ;QAC5C,IAAI,CAAC,SAAS,GAAG,IAAM,IAAI,CAAC,UAAU,CAACC,WAAWE;QAClD,OAAO,IAAI,CAAC,SAAS;IACzB;IAEA,SAAwB;QACpB,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,KAAKC,QAAQ,OAAO;IAC9D;IAEA,UAAgB;QACZC,YAAY,IAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK;QAC9C,IAAI,CAAC,SAAS,GAAG;IACrB;IAEA,MAAc,WAAWJ,SAAiB,EAAiB;QACvD,IAAI;YACA,MAAMK,UAAU,IAAIC;YACpB,IAAIC;YAEJ,GAAG;gBACC,MAAMC,WAAW,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;oBAC5CR;oBACA,OAAOR;oBACPe;oBACA,MAAM;wBAAC;qBAAmB;gBAC9B;gBACA,KAAK,MAAME,QAAQD,SAAS,KAAK,CAC7BH,QAAQ,GAAG,CAACI,KAAK,QAAQ,EAAEA;gBAE/BF,QAAQC,SAAS,IAAI,CAAC,YAAY,GAC3BA,SAAS,IAAI,CAAC,MAAM,IAAIE,SACzBA;YACV,QAASH,MAAO;YAEhBH,YAAY;gBACR,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAACC;YACnC;QACJ,EAAE,OAAOM,OAAO;YACZC,QAAQ,KAAK,CAACD;QAClB;IACJ;IAEA,MAAc,WAAWX,SAAiB,EAAEE,OAAe,EAAiB;QACxE,IAAI;YACA,MAAMW,SAAS,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAEb;gBAAW,IAAIE;YAAQ;YACtEE,YAAY;gBACR,IAAIS,QACA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAACX,SAASW;qBAEpC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAACX;YAEtC;QACJ,EAAE,OAAOS,OAAO;YACZC,QAAQ,KAAK,CAACD;QAClB;IACJ;AACJ;AAEO,MAAMG,sDAA4BC,0BAAAA,oBAAgC,CAAC;IACtE,gBAAgBtB;IAChB,cAAc;QAACuB;QAA6BC;KAA0B;AAC1E"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SchedulerEntry } from "@webiny/app-scheduler/types.js";
|
|
2
|
+
export interface IScheduledActionsPresenter {
|
|
3
|
+
/** Loads all scheduled actions for a model (used by the entries list). */
|
|
4
|
+
loadForModel(modelId: string): Promise<void>;
|
|
5
|
+
/** Loads the scheduled action for a single entry (used by the entry form). */
|
|
6
|
+
loadForEntry(modelId: string, entryId: string): Promise<void>;
|
|
7
|
+
/** Re-runs the last load. Call after a schedule/cancel to reflect the change. */
|
|
8
|
+
reload(): Promise<void>;
|
|
9
|
+
/** Returns the scheduled action for a target (entry) id, if any. */
|
|
10
|
+
getScheduledAction(targetId: string): SchedulerEntry | undefined;
|
|
11
|
+
dispose(): void;
|
|
12
|
+
}
|
|
13
|
+
export declare const ScheduledActionsPresenter: import("@webiny/di").Abstraction<IScheduledActionsPresenter>;
|
|
14
|
+
export declare namespace ScheduledActionsPresenter {
|
|
15
|
+
type Interface = IScheduledActionsPresenter;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation/scheduledActions/abstractions.js","sources":["../../../src/presentation/scheduledActions/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\nimport type { SchedulerEntry } from \"@webiny/app-scheduler/types.js\";\n\nexport interface IScheduledActionsPresenter {\n /** Loads all scheduled actions for a model (used by the entries list). */\n loadForModel(modelId: string): Promise<void>;\n /** Loads the scheduled action for a single entry (used by the entry form). */\n loadForEntry(modelId: string, entryId: string): Promise<void>;\n /** Re-runs the last load. Call after a schedule/cancel to reflect the change. */\n reload(): Promise<void>;\n /** Returns the scheduled action for a target (entry) id, if any. */\n getScheduledAction(targetId: string): SchedulerEntry | undefined;\n dispose(): void;\n}\n\nexport const ScheduledActionsPresenter = createAbstraction<IScheduledActionsPresenter>(\n \"ScheduledActionsPresenter\"\n);\n\nexport namespace ScheduledActionsPresenter {\n export type Interface = IScheduledActionsPresenter;\n}\n"],"names":["ScheduledActionsPresenter","createAbstraction"],"mappings":";AAeO,MAAMA,4BAA4BC,kBACrC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/admin";
|
|
2
|
+
import { ScheduledActionsPresenter } from "./abstractions.js";
|
|
3
|
+
import { ScheduledActionsPresenter as external_ScheduledActionsPresenter_js_ScheduledActionsPresenter } from "./ScheduledActionsPresenter.js";
|
|
4
|
+
import { ContentEntriesPresenterSchedulingDecorator } from "./ContentEntriesPresenterSchedulingDecorator.js";
|
|
5
|
+
const ScheduledActionsPresenterFeature = createFeature({
|
|
6
|
+
name: "Scheduler/ScheduledActionsPresenter",
|
|
7
|
+
register (container) {
|
|
8
|
+
container.register(external_ScheduledActionsPresenter_js_ScheduledActionsPresenter).inSingletonScope();
|
|
9
|
+
container.registerDecorator(ContentEntriesPresenterSchedulingDecorator);
|
|
10
|
+
},
|
|
11
|
+
resolve (container) {
|
|
12
|
+
return {
|
|
13
|
+
presenter: container.resolve(ScheduledActionsPresenter)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
export { ScheduledActionsPresenterFeature };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation/scheduledActions/feature.js","sources":["../../../src/presentation/scheduledActions/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/admin\";\nimport { ScheduledActionsPresenter as Abstraction } from \"./abstractions.js\";\nimport { ScheduledActionsPresenter } from \"./ScheduledActionsPresenter.js\";\nimport { ContentEntriesPresenterSchedulingDecorator } from \"./ContentEntriesPresenterSchedulingDecorator.js\";\n\nexport const ScheduledActionsPresenterFeature = createFeature({\n name: \"Scheduler/ScheduledActionsPresenter\",\n register(container) {\n container.register(ScheduledActionsPresenter).inSingletonScope();\n container.registerDecorator(ContentEntriesPresenterSchedulingDecorator);\n },\n resolve(container) {\n return {\n presenter: container.resolve(Abstraction)\n };\n }\n});\n"],"names":["ScheduledActionsPresenterFeature","createFeature","container","ScheduledActionsPresenter","ContentEntriesPresenterSchedulingDecorator","Abstraction"],"mappings":";;;;AAKO,MAAMA,mCAAmCC,cAAc;IAC1D,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC,iEAA2B,gBAAgB;QAC9DD,UAAU,iBAAiB,CAACE;IAChC;IACA,SAAQF,SAAS;QACb,OAAO;YACH,WAAWA,UAAU,OAAO,CAACG;QACjC;IACJ;AACJ"}
|