@cosmicdrift/kumiko-document-designer 0.363.0 → 0.365.0
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/dist/constants.d.ts +3 -0
- package/dist/constants.js +4 -0
- package/dist/i18n.js +208 -50
- package/dist/web/cells.js +4 -3
- package/dist/web/editor-header.d.ts +37 -0
- package/dist/web/editor-header.js +43 -0
- package/dist/web/editor-locale.d.ts +1 -0
- package/dist/web/editor-locale.js +15 -0
- package/dist/web/editor-shell.d.ts +40 -0
- package/dist/web/editor-shell.js +36 -0
- package/dist/web/i18n.js +35 -59
- package/dist/web/layout-editor-body.d.ts +2 -2
- package/dist/web/layout-editor-body.js +101 -52
- package/dist/web/layout-editor.js +14 -7
- package/dist/web/layout-html.d.ts +2 -0
- package/dist/web/layout-html.js +13 -1
- package/dist/web/layout-meta.d.ts +29 -0
- package/dist/web/layout-meta.js +32 -0
- package/dist/web/layout-rails.d.ts +15 -5
- package/dist/web/layout-rails.js +61 -68
- package/dist/web/layout-types.d.ts +4 -0
- package/dist/web/layout-users.d.ts +1 -0
- package/dist/web/layout-users.js +4 -1
- package/dist/web/mail-dialogs.d.ts +1 -6
- package/dist/web/mail-dialogs.js +2 -2
- package/dist/web/mail-draft.d.ts +8 -6
- package/dist/web/mail-draft.js +45 -11
- package/dist/web/mail-edit-center.d.ts +3 -1
- package/dist/web/mail-edit-center.js +5 -4
- package/dist/web/mail-editor-body.d.ts +0 -1
- package/dist/web/mail-editor-body.js +60 -45
- package/dist/web/mail-editor.js +9 -14
- package/dist/web/mail-footer.d.ts +3 -14
- package/dist/web/mail-footer.js +12 -13
- package/dist/web/mail-left-rail.d.ts +9 -4
- package/dist/web/mail-left-rail.js +18 -15
- package/dist/web/mail-missing-locale.d.ts +10 -0
- package/dist/web/mail-missing-locale.js +45 -0
- package/dist/web/mail-origin-bar.d.ts +3 -5
- package/dist/web/mail-origin-bar.js +26 -50
- package/dist/web/mail-preview-side.d.ts +12 -5
- package/dist/web/mail-preview-side.js +14 -5
- package/dist/web/mail-preview.d.ts +9 -5
- package/dist/web/mail-preview.js +24 -13
- package/dist/web/mail-right-rail.d.ts +8 -0
- package/dist/web/mail-right-rail.js +65 -14
- package/dist/web/mail-types.d.ts +10 -1
- package/dist/web/mail-upload-modal.js +12 -2
- package/dist/web/mail-versions.js +3 -3
- package/dist/web/origin-bar.d.ts +11 -2
- package/dist/web/origin-bar.js +46 -24
- package/dist/web/overrides-drawer.d.ts +3 -2
- package/dist/web/overrides-drawer.js +87 -11
- package/dist/web/overview-row.d.ts +2 -0
- package/dist/web/overview-row.js +2 -1
- package/dist/web/page-canvas.d.ts +2 -1
- package/dist/web/page-canvas.js +23 -13
- package/dist/web/pdf-footer.d.ts +13 -0
- package/dist/web/pdf-footer.js +34 -0
- package/dist/web/pdf-left-rail.d.ts +9 -0
- package/dist/web/pdf-left-rail.js +16 -0
- package/dist/web/pdf-meta.d.ts +3 -5
- package/dist/web/pdf-meta.js +10 -16
- package/dist/web/pdf-preview.js +21 -8
- package/dist/web/pdf-template-editor.js +91 -76
- package/dist/web/rail.d.ts +13 -1
- package/dist/web/rail.js +15 -7
- package/dist/web/relative-time.d.ts +1 -0
- package/dist/web/relative-time.js +18 -0
- package/dist/web/settings-panel.d.ts +11 -5
- package/dist/web/settings-panel.js +24 -13
- package/dist/web/status-label.d.ts +7 -0
- package/dist/web/status-label.js +8 -0
- package/dist/web/types.d.ts +23 -0
- package/dist/web/use-debounced-value.d.ts +1 -0
- package/dist/web/use-debounced-value.js +11 -0
- package/dist/web/use-insert-targets.d.ts +2 -2
- package/dist/web/use-insert-targets.js +4 -1
- package/dist/web/use-mail-persistence.d.ts +2 -2
- package/dist/web/use-mail-persistence.js +4 -4
- package/dist/web/use-own-address.d.ts +5 -0
- package/dist/web/use-own-address.js +14 -0
- package/dist/web/used-by-label.d.ts +1 -0
- package/dist/web/used-by-label.js +11 -0
- package/package.json +8 -8
- package/src/changes.json +48 -0
- package/dist/web/mail-header.d.ts +0 -23
- package/dist/web/mail-header.js +0 -16
- package/dist/web/placeholder-panel.d.ts +0 -21
- package/dist/web/placeholder-panel.js +0 -35
|
@@ -3,25 +3,30 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
import { TemplateResolverHandlers, TemplateResolverQueries, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
4
|
import { dispatcherErrorText, useMutation, usePrimitives, useQuery, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
5
|
import { useState } from "react";
|
|
6
|
+
import { EditorHeader, EditorLocaleSwitch, EditorModeSwitch, originOf, } from "./editor-header.js";
|
|
7
|
+
import { EditorBody, EditorFooter, EditorFrame } from "./editor-shell.js";
|
|
6
8
|
import { fileUrl } from "./file-name.js";
|
|
7
9
|
import { MailConfirmDialogs } from "./mail-dialogs.js";
|
|
8
|
-
import { buildMeta, isDraftDirty, loadedMailOf, parseJsonRecord, parseLinkedResources, variableLabelMap, } from "./mail-draft.js";
|
|
10
|
+
import { buildMeta, isDraftDirty, loadedMailOf, parseJsonRecord, parseLinkedResources, systemLabelMap, variableLabelMap, } from "./mail-draft.js";
|
|
9
11
|
import { MailEditCenter } from "./mail-edit-center.js";
|
|
10
|
-
import {
|
|
11
|
-
import { MailHeader } from "./mail-header.js";
|
|
12
|
+
import { footerMessage, metaFieldMessages } from "./mail-footer.js";
|
|
12
13
|
import { PlaceholderSection, ResourceSection, SystemPlaceholderSection } from "./mail-left-rail.js";
|
|
14
|
+
import { MissingLocaleCanvas } from "./mail-missing-locale.js";
|
|
13
15
|
import { MailOriginBar } from "./mail-origin-bar.js";
|
|
14
16
|
import { PdfLinkModal } from "./mail-pdf-link-modal.js";
|
|
15
17
|
import { MailPreviewMode } from "./mail-preview.js";
|
|
16
|
-
import { AttachmentSection, PropertiesSection, UsageSection } from "./mail-right-rail.js";
|
|
18
|
+
import { AttachmentSection, ChromeSection, PropertiesSection, UsageSection, } from "./mail-right-rail.js";
|
|
17
19
|
import { UploadModal } from "./mail-upload-modal.js";
|
|
18
20
|
import { VersionsSection } from "./mail-versions.js";
|
|
19
21
|
import { useInsertTargets } from "./use-insert-targets.js";
|
|
20
22
|
import { useMailPersistence } from "./use-mail-persistence.js";
|
|
21
23
|
import { useOverviewRows } from "./use-overview-rows.js";
|
|
24
|
+
import { useOwnAddress } from "./use-own-address.js";
|
|
22
25
|
import { useSettledValue } from "./use-settled-value.js";
|
|
23
26
|
import { useTestMail } from "./use-test-mail.js";
|
|
24
|
-
|
|
27
|
+
// The editor replaces this token with the decoded image size once the preview image loaded.
|
|
28
|
+
const SIZE_TOKEN = "{size}";
|
|
29
|
+
function uniqueValues(values) {
|
|
25
30
|
return [...new Set(values)];
|
|
26
31
|
}
|
|
27
32
|
export function placeholderNames(validation) {
|
|
@@ -31,22 +36,25 @@ export function placeholderNames(validation) {
|
|
|
31
36
|
name,
|
|
32
37
|
...Object.keys(variable.item ?? {}).map((item) => `${name}.${item}`),
|
|
33
38
|
]);
|
|
34
|
-
return
|
|
39
|
+
return uniqueValues([...own, ...validation.systemPlaceholders]);
|
|
35
40
|
}
|
|
36
41
|
export function MailEditorBody(props) {
|
|
37
42
|
const { slug, locale, title, isSystemAdmin, row, onReload, onRefreshRow } = props;
|
|
38
43
|
const t = useTranslation();
|
|
39
44
|
const { Banner } = usePrimitives();
|
|
40
45
|
const [baseline] = useState(() => loadedMailOf(row));
|
|
41
|
-
const [draft, setDraft] = useState(baseline
|
|
42
|
-
const [settled, settle] = useSettledValue(baseline
|
|
46
|
+
const [draft, setDraft] = useState(baseline);
|
|
47
|
+
const [settled, settle] = useSettledValue(baseline);
|
|
43
48
|
const [mode, setMode] = useState("edit");
|
|
44
49
|
const [creating, setCreating] = useState(false);
|
|
45
50
|
const [dialog, setDialog] = useState({ kind: "none" });
|
|
46
51
|
const [uploadOpen, setUploadOpen] = useState(false);
|
|
47
52
|
const [pdfOpen, setPdfOpen] = useState(false);
|
|
48
53
|
const [resourceError, setResourceError] = useState(null);
|
|
54
|
+
const [resetError, setResetError] = useState(null);
|
|
49
55
|
const [editorEpoch, setEditorEpoch] = useState(0);
|
|
56
|
+
const [includeAttachments, setIncludeAttachments] = useState(true);
|
|
57
|
+
const [prefixSubject, setPrefixSubject] = useState(true);
|
|
50
58
|
const insert = useInsertTargets();
|
|
51
59
|
const persistence = useMailPersistence({
|
|
52
60
|
slug,
|
|
@@ -54,9 +62,9 @@ export function MailEditorBody(props) {
|
|
|
54
62
|
title,
|
|
55
63
|
isSystemAdmin,
|
|
56
64
|
row,
|
|
57
|
-
sender: baseline.sender,
|
|
58
65
|
});
|
|
59
66
|
const testMail = useTestMail();
|
|
67
|
+
const own = useOwnAddress();
|
|
60
68
|
const resourceRemove = useMutation(TemplateResolverHandlers.resourceRemove);
|
|
61
69
|
const layouts = useOverviewRows("mail-layout");
|
|
62
70
|
const pdfTemplates = useOverviewRows("document-pdf");
|
|
@@ -67,7 +75,7 @@ export function MailEditorBody(props) {
|
|
|
67
75
|
kind: "mail",
|
|
68
76
|
contentFormat: "html",
|
|
69
77
|
content: settled.body,
|
|
70
|
-
meta: buildMeta(settled
|
|
78
|
+
meta: buildMeta(settled),
|
|
71
79
|
variableSchema,
|
|
72
80
|
locale,
|
|
73
81
|
scope: isSystemAdmin ? "system" : "tenant",
|
|
@@ -78,38 +86,26 @@ export function MailEditorBody(props) {
|
|
|
78
86
|
settle(next);
|
|
79
87
|
};
|
|
80
88
|
const reset = () => {
|
|
81
|
-
setDraft(baseline
|
|
82
|
-
settle(baseline
|
|
89
|
+
setDraft(baseline);
|
|
90
|
+
settle(baseline);
|
|
83
91
|
setEditorEpoch((epoch) => epoch + 1);
|
|
84
92
|
persistence.clearError();
|
|
85
93
|
};
|
|
86
|
-
const dirty = isDraftDirty(draft, baseline
|
|
87
|
-
const isActiveTenantRow = row?.scope === "tenant" && row.status === "active";
|
|
94
|
+
const dirty = isDraftDirty(draft, baseline);
|
|
88
95
|
const busy = persistence.busy;
|
|
89
96
|
const canSave = !locked && !busy && validation?.canSave === true && (dirty || creating);
|
|
90
97
|
const canPublish = !locked &&
|
|
91
98
|
!busy &&
|
|
92
99
|
validation?.canPublish === true &&
|
|
93
100
|
(dirty || creating || row?.status !== "active");
|
|
94
|
-
const persist = async (publish) => persistence.save(draft, publish);
|
|
95
101
|
const saveAndReload = async (publish) => {
|
|
96
|
-
if (await
|
|
102
|
+
if ((await persistence.save(draft, publish)) !== "failed")
|
|
97
103
|
await onReload();
|
|
98
104
|
};
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
setDialog({ kind: "activeSave" });
|
|
102
|
-
else
|
|
103
|
-
void saveAndReload(false);
|
|
104
|
-
};
|
|
105
|
-
const perform = (target) => {
|
|
106
|
-
if (target.kind === "locale")
|
|
107
|
-
props.onLocaleChange(target.locale);
|
|
108
|
-
else
|
|
109
|
-
props.onBack();
|
|
110
|
-
};
|
|
105
|
+
const saveDraft = () => void saveAndReload(false);
|
|
106
|
+
const perform = (target) => props.onLocaleChange(target.locale);
|
|
111
107
|
const leave = (target) => {
|
|
112
|
-
if (target.
|
|
108
|
+
if (target.locale === locale)
|
|
113
109
|
return;
|
|
114
110
|
if (dirty)
|
|
115
111
|
setDialog({ kind: "leave", target });
|
|
@@ -124,7 +120,10 @@ export function MailEditorBody(props) {
|
|
|
124
120
|
resource.key,
|
|
125
121
|
{
|
|
126
122
|
src: fileUrl(resource.fileRefId),
|
|
127
|
-
caption: t("documentDesigner.mail.resource.caption", {
|
|
123
|
+
caption: t("documentDesigner.mail.resource.caption", {
|
|
124
|
+
key: resource.key,
|
|
125
|
+
size: SIZE_TOKEN,
|
|
126
|
+
}),
|
|
128
127
|
},
|
|
129
128
|
],
|
|
130
129
|
]
|
|
@@ -146,31 +145,49 @@ export function MailEditorBody(props) {
|
|
|
146
145
|
slug,
|
|
147
146
|
locale,
|
|
148
147
|
content: draft.body,
|
|
149
|
-
meta: buildMeta(draft
|
|
148
|
+
meta: buildMeta(draft),
|
|
150
149
|
variableSchema,
|
|
150
|
+
includeAttachments,
|
|
151
|
+
prefixSubject,
|
|
151
152
|
});
|
|
152
153
|
};
|
|
154
|
+
// Nothing is written yet in a missing language, so no placeholder may read as missing.
|
|
155
|
+
const railValidation = locked && validation != null ? { ...validation, missingRequired: [] } : (validation ?? null);
|
|
153
156
|
const names = placeholderNames(validation ?? null);
|
|
154
157
|
const vocabulary = {
|
|
155
158
|
names,
|
|
156
|
-
labels:
|
|
159
|
+
labels: {
|
|
160
|
+
...systemLabelMap(t, validation?.systemPlaceholders ?? []),
|
|
161
|
+
...variableLabelMap(validation?.variables ?? {}),
|
|
162
|
+
},
|
|
157
163
|
system: validation?.systemPlaceholders ?? [],
|
|
158
164
|
};
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
const attachments = resources.filter((resource) => resource.kind !== "image");
|
|
166
|
+
const footer = locked || validation === undefined || validation === null
|
|
167
|
+
? null
|
|
168
|
+
: footerMessage(t, validation, mode === "preview");
|
|
169
|
+
const fieldErrors = locked ? {} : metaFieldMessages(t, validation ?? null);
|
|
170
|
+
const publish = () => void saveAndReload(true);
|
|
171
|
+
const controls = (_jsx(EditorLocaleSwitch, { testIdPrefix: "mail", locales: props.locales, locale: locale, onLocale: (next) => leave({ kind: "locale", locale: next }) }));
|
|
172
|
+
const origin = row === null ? null : originOf(row.scope !== "tenant", props.systemVersion !== null);
|
|
173
|
+
return (_jsxs(EditorFrame, { testId: "document-designer-mail-editor", children: [_jsx(EditorHeader, { title: title, stored: row === null ? null : { status: row.status, version: row.version }, actions: { busy, canSave, canPublish, onSave: saveDraft, onPublish: publish }, children: _jsx(EditorModeSwitch, { testIdPrefix: "mail", mode: mode, onMode: setMode }) }), mode === "edit" && (_jsx(MailOriginBar, { row: row, systemVersion: props.systemVersion, locale: locale, isSystemAdmin: isSystemAdmin, creating: creating, controls: controls, onReload: () => {
|
|
174
|
+
setResetError(null);
|
|
175
|
+
void onReload();
|
|
176
|
+
}, onResetError: setResetError })), testMail.state.kind === "sent" && (_jsx(Banner, { variant: "primary", testId: "mail-test-sent", children: t("documentDesigner.mail.testMail.sent", { subject: testMail.state.subject }) })), testMail.state.kind === "error" && (_jsx(Banner, { variant: "error", testId: "mail-test-error", children: testMail.state.text })), resetError !== null && (_jsx(Banner, { variant: "error", testId: "mail-reset-error", children: resetError })), resourceError !== null && (_jsx(Banner, { variant: "error", testId: "mail-resource-error", children: resourceError })), mode === "edit" ? (_jsx(EditorBody, { left: _jsxs(_Fragment, { children: [_jsx(PlaceholderSection, { validation: railValidation, onInsert: insert.insertPlaceholder }), _jsx(SystemPlaceholderSection, { validation: railValidation, onInsert: insert.insertPlaceholder }), _jsx(ResourceSection, { resources: resources, pdfTitles: pdfTitles, canUpload: uploadTemplateId !== null, onUpload: () => setUploadOpen(true), onInsert: insert.insertResource, onRemove: (key) => setDialog({ kind: "remove", key }) })] }), center: locked ? (_jsx(MissingLocaleCanvas, { slug: slug, locale: locale, fallbackLocale: props.fallbackLocale, copyScope: isSystemAdmin ? "system" : "tenant", onCreateBlank: () => setCreating(true), onCopied: () => void onReload() })) : (_jsx(MailEditCenter, { draft: draft, vocabulary: vocabulary, resourcePreviews: resourcePreviews, insert: insert, readOnly: false, fieldErrors: fieldErrors, onChange: update }, editorEpoch)), right: _jsxs(_Fragment, { children: [_jsx(PropertiesSection, { draft: draft, layouts: layouts.rows, onChange: update }), _jsx(ChromeSection, { draft: draft, vocabulary: vocabulary, insert: insert, onChange: update }), _jsx(AttachmentSection, { attachments: attachments, pdfTitles: pdfTitles, canEdit: uploadTemplateId !== null, onAddPdf: () => setPdfOpen(true), onRemove: (key) => setDialog({ kind: "remove", key }) }), _jsx(UsageSection, { slug: slug }), _jsx(VersionsSection, { rowId: row?.id ?? null, currentVersion: row?.version ?? 0, currentStatus: row?.status ?? "draft" })] }) })) : (_jsx(MailPreviewMode, { payload: {
|
|
167
177
|
slug,
|
|
168
178
|
kind: "mail",
|
|
169
179
|
locale,
|
|
170
180
|
content: settled.body,
|
|
171
|
-
meta: buildMeta(settled
|
|
181
|
+
meta: buildMeta(settled),
|
|
172
182
|
variableSchema,
|
|
173
|
-
}, validation: validation ?? null, slug: slug, locale: locale,
|
|
183
|
+
}, validation: validation ?? null, slug: slug, locale: locale, fromName: settled.senderName, own: own, origin: origin, controls: controls, testMail: {
|
|
184
|
+
pending: testMail.pending,
|
|
185
|
+
onSend: sendTestMail,
|
|
186
|
+
includeAttachments,
|
|
187
|
+
onIncludeAttachments: setIncludeAttachments,
|
|
188
|
+
prefixSubject,
|
|
189
|
+
onPrefixSubject: setPrefixSubject,
|
|
190
|
+
} })), !locked && (_jsx(EditorFooter, { testIdPrefix: "mail-editor", message: footer, saveError: persistence.error, modifiedAt: row?.modifiedAt ?? null, dirty: dirty, busy: busy, canSave: canSave, canPublish: canPublish, onDiscard: () => setDialog({ kind: "discard" }), onSave: saveDraft, onPublish: publish })), uploadTemplateId !== null && (_jsxs(_Fragment, { children: [_jsx(UploadModal, { open: uploadOpen, onOpenChange: setUploadOpen, target: {
|
|
174
191
|
templateId: uploadTemplateId,
|
|
175
192
|
takenKeys,
|
|
176
193
|
onUploaded: (uploaded) => {
|
|
@@ -181,10 +198,8 @@ export function MailEditorBody(props) {
|
|
|
181
198
|
} }), _jsx(PdfLinkModal, { open: pdfOpen, onOpenChange: setPdfOpen, templates: pdfTemplates.rows, variableLabels: vocabulary.labels, templateId: uploadTemplateId, takenKeys: takenKeys, onLinked: () => void onRefreshRow() })] })), _jsx(MailConfirmDialogs, { dialog: dialog, onClose: () => setDialog({ kind: "none" }), onDiscard: () => {
|
|
182
199
|
reset();
|
|
183
200
|
setDialog({ kind: "none" });
|
|
184
|
-
}, onSaveDraft: async () => {
|
|
185
|
-
await saveAndReload(false);
|
|
186
201
|
}, onRemove: removeResource, onLeaveSave: async (target) => {
|
|
187
|
-
if (await
|
|
202
|
+
if ((await persistence.save(draft, false)) === "saved")
|
|
188
203
|
perform(target);
|
|
189
204
|
}, onLeaveDiscard: (target) => {
|
|
190
205
|
setDialog({ kind: "none" });
|
package/dist/web/mail-editor.js
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
// @runtime client
|
|
3
3
|
import { TemplateResolverQueries } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
|
-
import { useNav, useQuery, useUserRoles } from "@cosmicdrift/kumiko-renderer";
|
|
4
|
+
import { useLocale, useNav, useQuery, useTranslation, useUserRoles, } from "@cosmicdrift/kumiko-renderer";
|
|
5
5
|
import { LoadingState } from "@cosmicdrift/kumiko-renderer-web";
|
|
6
6
|
import { useState } from "react";
|
|
7
|
-
import { DEFAULT_TEMPLATE_LOCALES
|
|
7
|
+
import { DEFAULT_TEMPLATE_LOCALES } from "../constants.js";
|
|
8
|
+
import { defaultLocaleOf } from "./editor-locale.js";
|
|
8
9
|
import { MailEditorBody } from "./mail-editor-body.js";
|
|
9
10
|
import { useOverviewRows } from "./use-overview-rows.js";
|
|
10
|
-
|
|
11
|
-
const preferred = appLocales[0] ?? DEFAULT_TEMPLATE_LOCALES[0] ?? "de";
|
|
12
|
-
if (rowLocales.length === 0 || rowLocales.includes(preferred))
|
|
13
|
-
return preferred;
|
|
14
|
-
return rowLocales[0] ?? preferred;
|
|
15
|
-
}
|
|
11
|
+
import { templateTitle } from "./used-by-label.js";
|
|
16
12
|
function fallbackLocaleOf(locale, rowLocales) {
|
|
17
13
|
const others = rowLocales.filter((candidate) => candidate !== locale);
|
|
18
14
|
const preferred = DEFAULT_TEMPLATE_LOCALES[0];
|
|
@@ -25,7 +21,7 @@ function shownSummaryOf(summaries, slug, isSystemAdmin) {
|
|
|
25
21
|
return (isSystemAdmin ? system : (tenant ?? system)) ?? null;
|
|
26
22
|
}
|
|
27
23
|
function MailEditorData({ slug, locale, locales, overviewRow, isSystemAdmin, onLocaleChange, refreshOverview, }) {
|
|
28
|
-
const
|
|
24
|
+
const t = useTranslation();
|
|
29
25
|
const [generation, setGeneration] = useState(0);
|
|
30
26
|
const list = useQuery(TemplateResolverQueries.list, {
|
|
31
27
|
kind: "mail",
|
|
@@ -44,15 +40,14 @@ function MailEditorData({ slug, locale, locales, overviewRow, isSystemAdmin, onL
|
|
|
44
40
|
setGeneration((current) => current + 1);
|
|
45
41
|
};
|
|
46
42
|
const rowLocales = overviewRow?.locales ?? [];
|
|
47
|
-
return (_jsx(MailEditorBody, { slug: slug, locale: locale, locales: locales, title: overviewRow
|
|
43
|
+
return (_jsx(MailEditorBody, { slug: slug, locale: locale, locales: locales, title: overviewRow === null ? slug : templateTitle(t, overviewRow), isSystemAdmin: isSystemAdmin, row: row, systemVersion: overviewRow?.systemVersion ?? null, fallbackLocale: fallbackLocaleOf(locale, rowLocales), onLocaleChange: onLocaleChange, onReload: reload, onRefreshRow: async () => {
|
|
48
44
|
await stored.refetch();
|
|
49
|
-
},
|
|
50
|
-
screenId: isSystemAdmin ? PLATFORM_TEMPLATES_SCREEN_ID : TEMPLATES_SCREEN_ID,
|
|
51
|
-
}) }, `${locale}|${generation}|${row?.id ?? "none"}`));
|
|
45
|
+
} }, `${locale}|${generation}|${row?.id ?? "none"}`));
|
|
52
46
|
}
|
|
53
47
|
function MailEditorEntry({ appLocales }) {
|
|
54
48
|
const nav = useNav();
|
|
55
49
|
const roles = useUserRoles();
|
|
50
|
+
const uiLocale = useLocale().locale();
|
|
56
51
|
const slug = nav.searchParams["slug"] ?? "";
|
|
57
52
|
const overview = useOverviewRows("mail", slug);
|
|
58
53
|
const [picked, setPicked] = useState(nav.searchParams["locale"] ?? null);
|
|
@@ -60,7 +55,7 @@ function MailEditorEntry({ appLocales }) {
|
|
|
60
55
|
return _jsx(LoadingState, {});
|
|
61
56
|
const overviewRow = overview.rows.find((candidate) => candidate.slug === slug) ?? null;
|
|
62
57
|
const rowLocales = overviewRow?.locales ?? [];
|
|
63
|
-
const locale = picked ?? defaultLocaleOf(appLocales, rowLocales);
|
|
58
|
+
const locale = picked ?? defaultLocaleOf(uiLocale, appLocales, rowLocales);
|
|
64
59
|
const locales = [...new Set([...appLocales, ...rowLocales])];
|
|
65
60
|
return (_jsx(MailEditorData, { slug: slug, locale: locale, locales: locales, overviewRow: overviewRow, isSystemAdmin: roles?.includes("SystemAdmin") === true, onLocaleChange: setPicked, refreshOverview: overview.refetch }, locale));
|
|
66
61
|
}
|
|
@@ -1,21 +1,10 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
1
|
import type { MailValidation } from "./mail-types.js";
|
|
3
2
|
type Translate = (key: string, params?: Readonly<Record<string, unknown>>) => string;
|
|
4
3
|
export declare function footerMessage(t: Translate, validation: MailValidation, previewMode: boolean): {
|
|
5
4
|
readonly tone: "bad" | "warn" | "ok";
|
|
6
5
|
readonly text: string;
|
|
7
6
|
};
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
readonly saveError: string | null;
|
|
12
|
-
readonly modifiedAt: string | null;
|
|
13
|
-
readonly dirty: boolean;
|
|
14
|
-
readonly busy: boolean;
|
|
15
|
-
readonly canSave: boolean;
|
|
16
|
-
readonly canPublish: boolean;
|
|
17
|
-
readonly onDiscard: () => void;
|
|
18
|
-
readonly onSave: () => void;
|
|
19
|
-
readonly onPublish: () => void;
|
|
20
|
-
}): ReactNode;
|
|
7
|
+
declare const MAIL_META_FIELDS: readonly ["subject", "previewText"];
|
|
8
|
+
export type MailMetaField = (typeof MAIL_META_FIELDS)[number];
|
|
9
|
+
export declare function metaFieldMessages(t: Translate, validation: MailValidation | null): Partial<Record<MailMetaField, string>>;
|
|
21
10
|
export {};
|
package/dist/web/mail-footer.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
|
-
import { formatWhen, usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
4
1
|
function issueText(t, issue) {
|
|
5
2
|
const translated = t(issue.i18nKey, issue.params);
|
|
6
3
|
return translated === issue.i18nKey ? issue.code : translated;
|
|
@@ -31,14 +28,16 @@ export function footerMessage(t, validation, previewMode) {
|
|
|
31
28
|
}
|
|
32
29
|
return { tone: "ok", text: t("documentDesigner.mail.footer.ok") };
|
|
33
30
|
}
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
const MAIL_META_FIELDS = ["subject", "previewText"];
|
|
32
|
+
// The server names the setting and the reason per issue; the field itself shows that sentence.
|
|
33
|
+
export function metaFieldMessages(t, validation) {
|
|
34
|
+
if (validation === null)
|
|
35
|
+
return {};
|
|
36
|
+
const messages = {};
|
|
37
|
+
for (const field of MAIL_META_FIELDS) {
|
|
38
|
+
const issue = validation.issues.find((candidate) => candidate.path === `meta.${field}`);
|
|
39
|
+
if (issue !== undefined)
|
|
40
|
+
messages[field] = issueText(t, issue);
|
|
41
|
+
}
|
|
42
|
+
return messages;
|
|
44
43
|
}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { LinkedResourceView, MailValidation } from "./mail-types.js";
|
|
3
|
-
export
|
|
4
|
-
|
|
3
|
+
export type PlaceholderSource = Pick<MailValidation, "variables" | "used" | "missingRequired" | "systemPlaceholders">;
|
|
4
|
+
export declare function PlaceholderSection({ validation, onInsert, idPrefix, }: {
|
|
5
|
+
readonly validation: PlaceholderSource | null;
|
|
5
6
|
readonly onInsert: (name: string) => void;
|
|
7
|
+
readonly idPrefix?: string;
|
|
6
8
|
}): ReactNode;
|
|
7
|
-
export declare function SystemPlaceholderSection({ validation, onInsert, }: {
|
|
8
|
-
readonly validation:
|
|
9
|
+
export declare function SystemPlaceholderSection({ validation, onInsert, idPrefix, isLayoutOwned, }: {
|
|
10
|
+
readonly validation: PlaceholderSource | null;
|
|
9
11
|
readonly onInsert: (name: string) => void;
|
|
12
|
+
readonly idPrefix?: string;
|
|
13
|
+
/** Placeholders the layout fills in, so a template that never uses them is fine. */
|
|
14
|
+
readonly isLayoutOwned?: (name: string) => boolean;
|
|
10
15
|
}): ReactNode;
|
|
11
16
|
export declare function ResourceSection({ resources, pdfTitles, canUpload, onUpload, onInsert, onRemove, }: {
|
|
12
17
|
readonly resources: readonly LinkedResourceView[];
|
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// @runtime client
|
|
3
3
|
import { usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
4
|
-
import { PLACEHOLDER_SYMBOL } from "./mail-draft.js";
|
|
4
|
+
import { LAYOUT_OWNED_PLACEHOLDERS, PLACEHOLDER_SYMBOL, SYSTEM_PLACEHOLDER_TYPE, systemPlaceholderLabel, } from "./mail-draft.js";
|
|
5
5
|
import { RailHint, RailRow, RailSection } from "./rail.js";
|
|
6
6
|
function placeholderStatus(t, validation, name) {
|
|
7
|
-
if (validation.missingRequired.includes(name))
|
|
8
|
-
return t("documentDesigner.mail.placeholder.missing");
|
|
9
|
-
|
|
7
|
+
if (validation.missingRequired.includes(name)) {
|
|
8
|
+
return { text: t("documentDesigner.mail.placeholder.missing"), tone: "bad" };
|
|
9
|
+
}
|
|
10
|
+
return validation.used.includes(name) ? { text: "✓", tone: "ok" } : { text: "–", tone: "muted" };
|
|
10
11
|
}
|
|
11
|
-
export function PlaceholderSection({ validation, onInsert, }) {
|
|
12
|
+
export function PlaceholderSection({ validation, onInsert, idPrefix = "mail", }) {
|
|
12
13
|
const t = useTranslation();
|
|
13
14
|
const entries = Object.entries(validation?.variables ?? {});
|
|
14
|
-
return (_jsxs(RailSection, { title: t("documentDesigner.mail.placeholder.title"), testId:
|
|
15
|
-
entries.map(([name, variable]) =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const translated = t(key);
|
|
20
|
-
return translated === key ? name : translated;
|
|
15
|
+
return (_jsxs(RailSection, { title: t("documentDesigner.mail.placeholder.title"), testId: `${idPrefix}-editor-placeholders`, children: [validation !== null &&
|
|
16
|
+
entries.map(([name, variable]) => {
|
|
17
|
+
const status = placeholderStatus(t, validation, name);
|
|
18
|
+
return (_jsx(RailRow, { testId: `${idPrefix}-placeholder-${name}`, symbol: PLACEHOLDER_SYMBOL[variable.type], label: variable.label ?? name, required: variable.required === true, bad: validation.missingRequired.includes(name), trailing: status.text, trailingTone: status.tone, onPress: () => onInsert(name) }, name));
|
|
19
|
+
}), _jsx(RailHint, { children: t("documentDesigner.mail.placeholder.hint") })] }));
|
|
21
20
|
}
|
|
22
|
-
export function SystemPlaceholderSection({ validation, onInsert, }) {
|
|
21
|
+
export function SystemPlaceholderSection({ validation, onInsert, idPrefix = "mail", isLayoutOwned = (name) => LAYOUT_OWNED_PLACEHOLDERS.has(name), }) {
|
|
23
22
|
const t = useTranslation();
|
|
24
|
-
return (
|
|
23
|
+
return (_jsxs(RailSection, { title: t("documentDesigner.mail.system.title"), testId: `${idPrefix}-editor-system-placeholders`, children: [(validation?.systemPlaceholders ?? []).map((name) => {
|
|
24
|
+
const used = validation?.used.includes(name) === true;
|
|
25
|
+
const layoutOwned = !used && isLayoutOwned(name);
|
|
26
|
+
return (_jsx(RailRow, { testId: `${idPrefix}-system-${name}`, symbol: PLACEHOLDER_SYMBOL[SYSTEM_PLACEHOLDER_TYPE[name] ?? "text"], label: systemPlaceholderLabel(t, name), trailing: used ? "✓" : layoutOwned ? t("documentDesigner.mail.system.layout") : "–", trailingTone: used ? "ok" : "muted", onPress: () => onInsert(name) }, name));
|
|
27
|
+
}), _jsx(RailHint, { children: t("documentDesigner.mail.system.hint") })] }));
|
|
25
28
|
}
|
|
26
29
|
function resourceRow(t, resource, pdfTitles) {
|
|
27
30
|
switch (resource.kind) {
|
|
@@ -48,6 +51,6 @@ export function ResourceSection({ resources, pdfTitles, canUpload, onUpload, onI
|
|
|
48
51
|
const { Button } = usePrimitives();
|
|
49
52
|
return (_jsxs(RailSection, { title: t("documentDesigner.mail.resource.title"), testId: "mail-editor-resources", action: _jsx(Button, { variant: "link", disabled: !canUpload, onClick: onUpload, testId: "mail-resource-upload-open", children: t("documentDesigner.mail.resource.upload") }), children: [!canUpload && _jsx(RailHint, { children: t("documentDesigner.mail.resource.saveFirst") }), resources.map((resource) => {
|
|
50
53
|
const row = resourceRow(t, resource, pdfTitles);
|
|
51
|
-
return (
|
|
54
|
+
return (_jsx(RailRow, { testId: "mail-resource-row", symbol: row.symbol, label: row.label, trailing: row.meta, action: _jsx(Button, { variant: "danger-ghost", size: "sm", onClick: () => onRemove(resource.key), testId: `mail-resource-remove-${resource.key}`, children: t("documentDesigner.mail.resource.remove") }), ...(resource.kind === "image" && { onPress: () => onInsert(resource.key) }) }, resource.key));
|
|
52
55
|
}), _jsx(RailHint, { children: t("documentDesigner.mail.resource.hint") })] }));
|
|
53
56
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export declare function languageAdjective(t: (key: string, params?: Readonly<Record<string, unknown>>) => string, locale: string): string;
|
|
3
|
+
export declare function MissingLocaleCanvas({ slug, locale, fallbackLocale, copyScope, onCreateBlank, onCopied, }: {
|
|
4
|
+
readonly slug: string;
|
|
5
|
+
readonly locale: string;
|
|
6
|
+
readonly fallbackLocale: string | null;
|
|
7
|
+
readonly copyScope: "tenant" | "system";
|
|
8
|
+
readonly onCreateBlank: () => void;
|
|
9
|
+
readonly onCopied: () => void;
|
|
10
|
+
}): ReactNode;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// @runtime client
|
|
3
|
+
import { TemplateResolverHandlers } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
|
+
import { dispatcherErrorText, useMutation, usePrimitives, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { languageName } from "./mail-origin-bar.js";
|
|
7
|
+
export function languageAdjective(t, locale) {
|
|
8
|
+
const key = `documentDesigner.mail.languageAdjective.${locale}`;
|
|
9
|
+
const translated = t(key);
|
|
10
|
+
return translated === key ? locale : translated;
|
|
11
|
+
}
|
|
12
|
+
// Shown in place of the editor while a language has no version yet: nothing to edit, so no
|
|
13
|
+
// subject line, toolbar or properties; the two ways to get a version sit right here.
|
|
14
|
+
export function MissingLocaleCanvas({ slug, locale, fallbackLocale, copyScope, onCreateBlank, onCopied, }) {
|
|
15
|
+
const t = useTranslation();
|
|
16
|
+
const { Banner, Button } = usePrimitives();
|
|
17
|
+
const copyLocale = useMutation(TemplateResolverHandlers.copyLocale);
|
|
18
|
+
const [error, setError] = useState(null);
|
|
19
|
+
const copy = async (from) => {
|
|
20
|
+
setError(null);
|
|
21
|
+
const result = await copyLocale.mutate({
|
|
22
|
+
slug,
|
|
23
|
+
kind: "mail",
|
|
24
|
+
fromLocale: from,
|
|
25
|
+
toLocale: locale,
|
|
26
|
+
overwrite: false,
|
|
27
|
+
scope: copyScope,
|
|
28
|
+
});
|
|
29
|
+
if (result.isSuccess)
|
|
30
|
+
onCopied();
|
|
31
|
+
else
|
|
32
|
+
setError(dispatcherErrorText(result.error, t));
|
|
33
|
+
};
|
|
34
|
+
return (_jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center p-8", "data-testid": "mail-missing-locale", children: _jsxs("div", { className: "flex max-w-md flex-col items-center gap-4 text-center", children: [_jsx("p", { className: "m-0 text-base", children: fallbackLocale === null
|
|
35
|
+
? t("documentDesigner.mail.missing.textNoFallback", {
|
|
36
|
+
language: languageName(t, locale),
|
|
37
|
+
})
|
|
38
|
+
: t("documentDesigner.mail.missing.text", {
|
|
39
|
+
language: languageName(t, locale),
|
|
40
|
+
locale,
|
|
41
|
+
fallbackAdjective: languageAdjective(t, fallbackLocale),
|
|
42
|
+
}) }), _jsxs("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [fallbackLocale !== null && (_jsx(Button, { variant: "primary", disabled: copyLocale.pending, onClick: () => copy(fallbackLocale), testId: "mail-copy-locale", children: t("documentDesigner.mail.missing.copy", {
|
|
43
|
+
language: languageName(t, fallbackLocale),
|
|
44
|
+
}) })), _jsx(Button, { variant: "secondary", onClick: onCreateBlank, testId: "mail-create-blank", children: t("documentDesigner.mail.origin.createBlank") })] }), fallbackLocale !== null && (_jsx("p", { className: "m-0 text-xs text-muted-foreground", children: t("documentDesigner.mail.origin.copyNote") })), error !== null && (_jsx(Banner, { variant: "error", testId: "mail-copy-error", children: error }))] }) }));
|
|
45
|
+
}
|
|
@@ -2,16 +2,14 @@ import { type ReactNode } from "react";
|
|
|
2
2
|
import type { TemplateRowView } from "./mail-types.js";
|
|
3
3
|
type Translate = (key: string, params?: Readonly<Record<string, unknown>>) => string;
|
|
4
4
|
export declare function languageName(t: Translate, locale: string): string;
|
|
5
|
-
export declare function MailOriginBar({ row,
|
|
5
|
+
export declare function MailOriginBar({ row, systemVersion, locale, isSystemAdmin, creating, controls, onReload, onResetError, }: {
|
|
6
6
|
readonly row: TemplateRowView | null;
|
|
7
|
-
readonly title: string;
|
|
8
7
|
readonly systemVersion: number | null;
|
|
9
|
-
readonly slug: string;
|
|
10
8
|
readonly locale: string;
|
|
11
|
-
readonly fallbackLocale: string | null;
|
|
12
9
|
readonly isSystemAdmin: boolean;
|
|
13
10
|
readonly creating: boolean;
|
|
14
|
-
readonly
|
|
11
|
+
readonly controls: ReactNode;
|
|
15
12
|
readonly onReload: () => void;
|
|
13
|
+
readonly onResetError: (message: string) => void;
|
|
16
14
|
}): ReactNode;
|
|
17
15
|
export {};
|
|
@@ -3,13 +3,19 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
import { TemplateResolverHandlers } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
4
|
import { dispatcherErrorText, formatWhen, useMutation, usePrimitives, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
5
|
import { useState } from "react";
|
|
6
|
-
import {
|
|
6
|
+
import { originOf } from "./editor-header.js";
|
|
7
|
+
import { EditorInfoBar } from "./editor-shell.js";
|
|
8
|
+
import { DiffDrawer } from "./origin-bar.js";
|
|
9
|
+
import { draftBesideActiveSentence } from "./status-label.js";
|
|
7
10
|
export function languageName(t, locale) {
|
|
8
11
|
const key = `documentDesigner.mail.language.${locale}`;
|
|
9
12
|
const translated = t(key);
|
|
10
13
|
return translated === key ? locale : translated;
|
|
11
14
|
}
|
|
12
15
|
function statusSentence(t, row) {
|
|
16
|
+
const besideActive = draftBesideActiveSentence(t, row);
|
|
17
|
+
if (besideActive !== null)
|
|
18
|
+
return besideActive;
|
|
13
19
|
if (row.status === "active") {
|
|
14
20
|
return t("documentDesigner.mail.origin.activeSince", {
|
|
15
21
|
when: row.modifiedAt === null ? "–" : formatWhen(row.modifiedAt),
|
|
@@ -19,66 +25,36 @@ function statusSentence(t, row) {
|
|
|
19
25
|
? "documentDesigner.mail.origin.archived"
|
|
20
26
|
: "documentDesigner.mail.origin.notPublished");
|
|
21
27
|
}
|
|
22
|
-
|
|
23
|
-
function MissingLocaleBar({ slug, locale, fallbackLocale, copyScope, creating, onCreateBlank, onCopied, }) {
|
|
28
|
+
function MissingLocaleBar({ locale, creating, controls, }) {
|
|
24
29
|
const t = useTranslation();
|
|
25
|
-
|
|
26
|
-
const copyLocale = useMutation(TemplateResolverHandlers.copyLocale);
|
|
27
|
-
const [error, setError] = useState(null);
|
|
28
|
-
if (creating) {
|
|
29
|
-
return (_jsx("div", { className: `${BAR_CLASS} bg-muted`, "data-testid": "mail-origin-bar", children: _jsx(Text, { children: t("documentDesigner.mail.origin.creating", { language: languageName(t, locale) }) }) }));
|
|
30
|
-
}
|
|
31
|
-
const copy = async (from) => {
|
|
32
|
-
setError(null);
|
|
33
|
-
const result = await copyLocale.mutate({
|
|
34
|
-
slug,
|
|
35
|
-
kind: "mail",
|
|
36
|
-
fromLocale: from,
|
|
37
|
-
toLocale: locale,
|
|
38
|
-
overwrite: false,
|
|
39
|
-
scope: copyScope,
|
|
40
|
-
});
|
|
41
|
-
if (result.isSuccess)
|
|
42
|
-
onCopied();
|
|
43
|
-
else
|
|
44
|
-
setError(dispatcherErrorText(result.error, t));
|
|
45
|
-
};
|
|
46
|
-
return (_jsxs("div", { className: `${BAR_CLASS} border-status-warn bg-status-warn-surface`, "data-testid": "mail-origin-bar", "data-variant": "warn", children: [_jsxs(Text, { children: [t(fallbackLocale === null
|
|
47
|
-
? "documentDesigner.mail.origin.missingNoFallback"
|
|
48
|
-
: "documentDesigner.mail.origin.missing", {
|
|
49
|
-
language: languageName(t, locale),
|
|
50
|
-
locale,
|
|
51
|
-
fallback: fallbackLocale ?? "",
|
|
52
|
-
}), fallbackLocale !== null && ` ${t("documentDesigner.mail.origin.copyNote")}`] }), _jsx("div", { className: "grow" }), fallbackLocale !== null && (_jsx(Button, { size: "sm", variant: "secondary", loading: copyLocale.pending, onClick: () => copy(fallbackLocale), testId: "mail-copy-locale", children: t("documentDesigner.mail.origin.copyFrom", { fallback: fallbackLocale }) })), _jsx(Button, { size: "sm", variant: "secondary", onClick: onCreateBlank, testId: "mail-create-blank", children: t("documentDesigner.mail.origin.createBlank") }), error !== null && (_jsx(Banner, { variant: "error", testId: "mail-copy-error", children: error }))] }));
|
|
30
|
+
return creating ? (_jsx(EditorInfoBar, { tone: "muted", testId: "mail-origin-bar", controls: controls, children: t("documentDesigner.mail.origin.creating", { language: languageName(t, locale) }) })) : (_jsx(EditorInfoBar, { tone: "warn", testId: "mail-origin-bar", controls: controls, children: t("documentDesigner.mail.origin.missing", { language: languageName(t, locale) }) }));
|
|
53
31
|
}
|
|
54
|
-
function TenantOriginBar({ row,
|
|
32
|
+
function TenantOriginBar({ row, systemVersion, controls, onReset, onResetError, }) {
|
|
55
33
|
const t = useTranslation();
|
|
56
|
-
const { Button, Dialog
|
|
34
|
+
const { Button, Dialog } = usePrimitives();
|
|
57
35
|
const [diffOpen, setDiffOpen] = useState(false);
|
|
58
36
|
const [resetOpen, setResetOpen] = useState(false);
|
|
59
37
|
const resetToSystem = useMutation(TemplateResolverHandlers.resetToSystem);
|
|
60
38
|
const hasSystem = systemVersion !== null;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
} })] }));
|
|
39
|
+
return (_jsxs(EditorInfoBar, { tone: "active", testId: "mail-origin-bar", origin: originOf(false, hasSystem), controls: controls, overlays: _jsxs(_Fragment, { children: [diffOpen && _jsx(DiffDrawer, { tenantId: row.id, onClose: () => setDiffOpen(false) }), _jsx(Dialog, { open: resetOpen, onOpenChange: setResetOpen, title: t("documentDesigner.mail.reset.title"), description: t("documentDesigner.mail.reset.description"), confirmLabel: t("documentDesigner.mail.reset.confirm"), variant: "danger", onConfirm: async () => {
|
|
40
|
+
const result = await resetToSystem.mutate({ id: row.id });
|
|
41
|
+
if (result.isSuccess)
|
|
42
|
+
onReset();
|
|
43
|
+
else
|
|
44
|
+
onResetError(dispatcherErrorText(result.error, t));
|
|
45
|
+
} })] }), links: hasSystem && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "link", onClick: () => setDiffOpen(true), testId: "document-designer-diff-open", children: t("documentDesigner.editor.diff.open") }), _jsx(Button, { variant: "link", onClick: () => setResetOpen(true), testId: "document-designer-reset-open", children: t("documentDesigner.mail.origin.reset") })] })), children: [hasSystem
|
|
46
|
+
? t("documentDesigner.mail.origin.overrides", { version: systemVersion })
|
|
47
|
+
: t("documentDesigner.mail.origin.tenantOnly"), " ", statusSentence(t, row)] }));
|
|
71
48
|
}
|
|
72
|
-
export function MailOriginBar({ row,
|
|
49
|
+
export function MailOriginBar({ row, systemVersion, locale, isSystemAdmin, creating, controls, onReload, onResetError, }) {
|
|
73
50
|
const t = useTranslation();
|
|
74
|
-
const { Text } = usePrimitives();
|
|
75
51
|
if (row === null) {
|
|
76
|
-
return
|
|
52
|
+
return _jsx(MissingLocaleBar, { locale: locale, creating: creating, controls: controls });
|
|
77
53
|
}
|
|
78
54
|
if (row.scope === "tenant") {
|
|
79
|
-
return (_jsx(TenantOriginBar, { row: row,
|
|
55
|
+
return (_jsx(TenantOriginBar, { row: row, systemVersion: systemVersion, controls: controls, onReset: onReload, onResetError: onResetError }));
|
|
80
56
|
}
|
|
81
|
-
return (_jsx(
|
|
82
|
-
|
|
83
|
-
|
|
57
|
+
return (_jsx(EditorInfoBar, { tone: "muted", testId: "mail-origin-bar", origin: "system", controls: controls, children: t(isSystemAdmin
|
|
58
|
+
? "documentDesigner.mail.origin.platform"
|
|
59
|
+
: "documentDesigner.mail.origin.system", { version: row.version }) }));
|
|
84
60
|
}
|