@cosmicdrift/kumiko-document-designer 0.378.0 → 0.379.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/feature.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/list-definition.js +14 -2
- package/dist/web/cells.js +3 -4
- package/dist/web/client-plugin.js +3 -4
- package/dist/{constants.js → web/constants.js} +0 -1
- package/dist/web/default-translations.d.ts +2 -0
- package/dist/web/default-translations.js +218 -0
- package/dist/web/editor-header.js +1 -2
- package/dist/web/editor-locale.js +1 -2
- package/dist/web/editor-shell.js +8 -4
- package/dist/web/errors.js +0 -1
- package/dist/web/field-issue-text.js +0 -1
- package/dist/web/file-name.js +0 -1
- package/dist/web/i18n.d.ts +6 -2
- package/dist/web/i18n.js +873 -216
- package/dist/web/index.d.ts +1 -1
- package/dist/web/index.js +1 -2
- package/dist/web/layout-editor-body.js +4 -4
- package/dist/web/layout-editor.js +1 -2
- package/dist/web/layout-html.js +0 -1
- package/dist/web/layout-meta.js +0 -1
- package/dist/web/layout-rails.js +3 -3
- package/dist/web/layout-users.js +1 -2
- package/dist/web/mail-dialogs.js +0 -1
- package/dist/web/mail-draft.js +4 -3
- package/dist/web/mail-edit-center.js +0 -1
- package/dist/web/mail-editor-body.js +3 -3
- package/dist/web/mail-editor.js +1 -2
- package/dist/web/mail-footer.d.ts +1 -1
- package/dist/web/mail-footer.js +2 -2
- package/dist/web/mail-left-rail.js +0 -1
- package/dist/web/mail-missing-locale.js +0 -1
- package/dist/web/mail-origin-bar.js +0 -1
- package/dist/web/mail-pdf-link-modal.js +5 -2
- package/dist/web/mail-preview-side.js +0 -1
- package/dist/web/mail-preview.js +0 -1
- package/dist/web/mail-right-rail.js +1 -2
- package/dist/web/mail-upload-modal.js +0 -1
- package/dist/web/mail-versions.js +0 -1
- package/dist/web/origin-bar.js +2 -3
- package/dist/web/overrides-drawer.js +0 -1
- package/dist/web/overview-row.d.ts +4 -1
- package/dist/web/overview-row.js +3 -1
- package/dist/web/page-canvas.js +0 -1
- package/dist/web/pdf-left-rail.js +0 -1
- package/dist/web/pdf-meta.js +0 -1
- package/dist/web/pdf-template-editor.js +1 -2
- package/dist/web/preview-record-picker.js +0 -1
- package/dist/web/rail.js +8 -4
- package/dist/web/settings-panel.js +0 -1
- package/dist/web/template-rows.js +0 -1
- package/dist/web/use-files-capability.js +1 -2
- package/dist/web/use-mail-persistence.js +0 -1
- package/dist/web/use-overview-rows.js +0 -1
- package/dist/web/use-own-address.js +1 -2
- package/dist/web/use-settled-value.js +0 -1
- package/dist/web/use-test-mail.js +0 -1
- package/dist/web/used-by-label.d.ts +1 -0
- package/dist/web/used-by-label.js +10 -5
- package/package.json +6 -6
- package/src/changes.json +18 -0
- package/dist/i18n.d.ts +0 -6
- package/dist/i18n.js +0 -848
- /package/dist/{constants.d.ts → web/constants.d.ts} +0 -0
package/dist/web/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { type DocumentDesignerClientOptions, documentDesignerClient, PdfTemplateEditorScreen, } from "./client-plugin.tsx";
|
|
2
2
|
export { composeLayoutHtml, type LayoutRegionValues } from "./compose-layout.ts";
|
|
3
|
-
export { documentDesignerTranslations } from "./
|
|
3
|
+
export { documentDesignerTranslations } from "./default-translations.ts";
|
|
4
4
|
export { PdfTemplateEditor, type PdfTemplateEditorProps } from "./pdf-template-editor.tsx";
|
|
5
5
|
export { type PreviewRecordPicker, type PreviewRecordPickerProps, PreviewRecordPickerProvider, } from "./preview-record-picker.tsx";
|
|
6
6
|
export { usageLabel, usedByLabel } from "./used-by-label.ts";
|
package/dist/web/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// @runtime client
|
|
2
1
|
export { documentDesignerClient, PdfTemplateEditorScreen, } from "./client-plugin.js";
|
|
3
2
|
export { composeLayoutHtml } from "./compose-layout.js";
|
|
4
|
-
export { documentDesignerTranslations } from "./
|
|
3
|
+
export { documentDesignerTranslations } from "./default-translations.js";
|
|
5
4
|
export { PdfTemplateEditor } from "./pdf-template-editor.js";
|
|
6
5
|
export { PreviewRecordPickerProvider, } from "./preview-record-picker.js";
|
|
7
6
|
export { usageLabel, usedByLabel } from "./used-by-label.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { DocumentContentEditor, MAIL_DOCUMENT_BLOCKS, PDF_DOCUMENT_BLOCKS, TemplateResolverHandlers, TemplateResolverQueries, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { dispatcherErrorText, useMutation, usePrimitives, useQuery, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
4
|
+
import { pluralKey } from "@cosmicdrift/kumiko-renderer/headless";
|
|
5
5
|
import { cn, ModeSwitch, TextareaField } from "@cosmicdrift/kumiko-renderer/web";
|
|
6
6
|
import { useState } from "react";
|
|
7
|
-
import { BRANDING_QUERY_QN } from "../constants.js";
|
|
8
7
|
import { composeLayoutHtml } from "./compose-layout.js";
|
|
8
|
+
import { BRANDING_QUERY_QN } from "./constants.js";
|
|
9
9
|
import { EditorHeader } from "./editor-header.js";
|
|
10
10
|
import { EditorBody, EditorFooter, EditorFrame } from "./editor-shell.js";
|
|
11
11
|
import { fileUrl } from "./file-name.js";
|
|
@@ -137,9 +137,9 @@ export function LayoutEditorBody({ kind, slug, isSystemAdmin, source, overviewRo
|
|
|
137
137
|
? { tone: "bad", text: issueText(t, blockingIssue) }
|
|
138
138
|
: {
|
|
139
139
|
tone: "ok",
|
|
140
|
-
text: t(isMail
|
|
140
|
+
text: t(pluralKey(isMail
|
|
141
141
|
? "documentDesigner.editor.footer.okMail"
|
|
142
|
-
: "documentDesigner.editor.footer.okPdf", { count: userCount }),
|
|
142
|
+
: "documentDesigner.editor.footer.okPdf", userCount), { count: userCount }),
|
|
143
143
|
};
|
|
144
144
|
const accentColor = branding.data?.accentColor ?? "";
|
|
145
145
|
const showAccentLine = isMail && appearanceEditable && appearance.accentLine === "branding" && isHexColor(accentColor);
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverQueries } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { useNav, useQuery, useUserRoles } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { ErrorState, LoadingState } from "@cosmicdrift/kumiko-renderer/web";
|
|
6
5
|
import { useState } from "react";
|
|
7
|
-
import { DEFAULT_LAYOUT_SLUG } from "
|
|
6
|
+
import { DEFAULT_LAYOUT_SLUG } from "./constants.js";
|
|
8
7
|
import { LayoutEditorBody } from "./layout-editor-body.js";
|
|
9
8
|
import { layoutUserKind } from "./layout-users.js";
|
|
10
9
|
import { parseOverviewRow } from "./overview-row.js";
|
package/dist/web/layout-html.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { cn } from "@cosmicdrift/kumiko-renderer/web";
|
|
4
3
|
import { createElement, useMemo } from "react";
|
|
5
4
|
// Layout regions arrive server-sanitised, but the preview still renders them
|
package/dist/web/layout-meta.js
CHANGED
package/dist/web/layout-rails.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { useAppFeatures, useNav, usePrimitives, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
4
|
-
import { BRANDING_SCREEN_QN } from "
|
|
3
|
+
import { BRANDING_SCREEN_QN } from "./constants.js";
|
|
5
4
|
import { isHexColor, LAYOUT_ACCENT_LINES, LAYOUT_BUTTON_STYLES, LAYOUT_FONTS, LAYOUT_WIDTHS, } from "./layout-meta.js";
|
|
6
5
|
import { layoutUsers } from "./layout-users.js";
|
|
7
6
|
import { PLACEHOLDER_SYMBOL, SYSTEM_PLACEHOLDER_TYPE, systemPlaceholderLabel, } from "./mail-draft.js";
|
|
8
7
|
import { RailField, RailHint, RailRow, RailSection } from "./rail.js";
|
|
9
8
|
import { statusLabel } from "./status-label.js";
|
|
9
|
+
import { templateTitleText } from "./used-by-label.js";
|
|
10
10
|
const BRANDING_SCREEN_SHORT_ID = BRANDING_SCREEN_QN.slice(BRANDING_SCREEN_QN.lastIndexOf(":") + 1);
|
|
11
11
|
function logoName(logoUrl) {
|
|
12
12
|
const path = logoUrl.split("?")[0] ?? "";
|
|
@@ -90,7 +90,7 @@ export function AppearanceRail({ appearance, onChange, fromMjml, }) {
|
|
|
90
90
|
export function UsedByRail({ layoutSlug, kind, rows, }) {
|
|
91
91
|
const t = useTranslation();
|
|
92
92
|
const users = layoutUsers(rows, kind, layoutSlug);
|
|
93
|
-
return (_jsx(RailSection, { title: t("documentDesigner.usedBy.title"), testId: "document-designer-used-by", children: users.length === 0 ? (_jsx(RailHint, { children: t("documentDesigner.usedBy.none") })) : (users.map((row) => (_jsx(RailRow, { testId: `used-by-${row.id}`, label: row.title, trailing: row.origin === "system"
|
|
93
|
+
return (_jsx(RailSection, { title: t("documentDesigner.usedBy.title"), testId: "document-designer-used-by", children: users.length === 0 ? (_jsx(RailHint, { children: t("documentDesigner.usedBy.none") })) : (users.map((row) => (_jsx(RailRow, { testId: `used-by-${row.id}`, label: templateTitleText(t, row.title), trailing: row.origin === "system"
|
|
94
94
|
? t("documentDesigner.source.system")
|
|
95
95
|
: statusLabel(t, row.status, row.version) }, row.id)))) }));
|
|
96
96
|
}
|
package/dist/web/layout-users.js
CHANGED
package/dist/web/mail-dialogs.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
4
3
|
export function MailConfirmDialogs({ dialog, onClose, onDiscard, onRemove, onLeaveSave, onLeaveDiscard, }) {
|
|
5
4
|
const t = useTranslation();
|
package/dist/web/mail-draft.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { DOCUMENT_FALLBACK_CURRENCY, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, } from "@cosmicdrift/kumiko-renderer/headless";
|
|
1
|
+
import { DOCUMENT_FALLBACK_CURRENCY, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, pluralKey, } from "@cosmicdrift/kumiko-renderer/headless";
|
|
3
2
|
import { variableLabelText } from "./used-by-label.js";
|
|
4
3
|
export const EMPTY_DRAFT = {
|
|
5
4
|
subject: "",
|
|
@@ -167,7 +166,9 @@ export function variableLabelMap(t, variables) {
|
|
|
167
166
|
}
|
|
168
167
|
export function displayValue(t, value, type, format) {
|
|
169
168
|
if (Array.isArray(value))
|
|
170
|
-
return t("documentDesigner.mail.preview.entries",
|
|
169
|
+
return t(pluralKey("documentDesigner.mail.preview.entries", value.length), {
|
|
170
|
+
count: value.length,
|
|
171
|
+
});
|
|
171
172
|
if (type === "money") {
|
|
172
173
|
if (typeof value === "number" && format.tenantCurrency === undefined)
|
|
173
174
|
return String(value);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { DocumentContentEditor, MAIL_DOCUMENT_BLOCKS, PlaceholderLineEditor, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
const renderMailPaper = (editable) => (_jsx("div", { className: "mx-auto w-full max-w-[600px] bg-card px-10 py-7 shadow-md", children: editable }));
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverHandlers, TemplateResolverQueries, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { dispatcherErrorText, useMutation, usePrimitives, useQuery, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { useState } from "react";
|
|
@@ -25,6 +24,7 @@ import { useOverviewRows } from "./use-overview-rows.js";
|
|
|
25
24
|
import { useOwnAddress } from "./use-own-address.js";
|
|
26
25
|
import { useSettledValue } from "./use-settled-value.js";
|
|
27
26
|
import { useTestMail } from "./use-test-mail.js";
|
|
27
|
+
import { templateTitleText } from "./used-by-label.js";
|
|
28
28
|
// The editor replaces this token with the decoded image size once the preview image loaded.
|
|
29
29
|
const SIZE_TOKEN = "{size}";
|
|
30
30
|
function uniqueValues(values) {
|
|
@@ -116,7 +116,7 @@ export function MailEditorBody(props) {
|
|
|
116
116
|
perform(target);
|
|
117
117
|
};
|
|
118
118
|
const resources = parseLinkedResources(row?.linkedResources);
|
|
119
|
-
const pdfTitles = new Map(pdfTemplates.rows.map((template) => [template.slug, template.title]));
|
|
119
|
+
const pdfTitles = new Map(pdfTemplates.rows.map((template) => [template.slug, templateTitleText(t, template.title)]));
|
|
120
120
|
const resourcePreviews = Object.fromEntries(resources.flatMap((resource) => resource.kind === "image"
|
|
121
121
|
? [
|
|
122
122
|
[
|
|
@@ -169,7 +169,7 @@ export function MailEditorBody(props) {
|
|
|
169
169
|
const attachments = resources.filter((resource) => resource.kind !== "image");
|
|
170
170
|
const footer = locked || validation === undefined || validation === null
|
|
171
171
|
? null
|
|
172
|
-
: footerMessage(t, validation, mode === "preview");
|
|
172
|
+
: footerMessage(t, validation, mode === "preview" && testMail.availability.canSend);
|
|
173
173
|
const fieldErrors = locked ? {} : metaFieldMessages(t, validation ?? null);
|
|
174
174
|
const publish = () => void saveAndReload(true);
|
|
175
175
|
const controls = (_jsx(EditorLocaleSwitch, { testIdPrefix: "mail", locales: props.locales, locale: locale, onLocale: (next) => leave({ kind: "locale", locale: next }) }));
|
package/dist/web/mail-editor.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverQueries } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { useLocale, useNav, useQuery, useTranslation, useUserRoles, } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { LoadingState } from "@cosmicdrift/kumiko-renderer/web";
|
|
6
5
|
import { useState } from "react";
|
|
7
|
-
import { DEFAULT_TEMPLATE_LOCALES } from "
|
|
6
|
+
import { DEFAULT_TEMPLATE_LOCALES } from "./constants.js";
|
|
8
7
|
import { defaultLocaleOf } from "./editor-locale.js";
|
|
9
8
|
import { MailEditorBody } from "./mail-editor-body.js";
|
|
10
9
|
import { useOverviewRows } from "./use-overview-rows.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { MailValidation } from "./mail-types.ts";
|
|
2
2
|
type Translate = (key: string, params?: Readonly<Record<string, unknown>>) => string;
|
|
3
|
-
export declare function footerMessage(t: Translate, validation: MailValidation,
|
|
3
|
+
export declare function footerMessage(t: Translate, validation: MailValidation, offersTestMail: boolean): {
|
|
4
4
|
readonly tone: "bad" | "warn" | "ok";
|
|
5
5
|
readonly text: string;
|
|
6
6
|
};
|
package/dist/web/mail-footer.js
CHANGED
|
@@ -10,11 +10,11 @@ function missingLabels(t, validation) {
|
|
|
10
10
|
}
|
|
11
11
|
// The footer sentence: missing required placeholders first, then other blocking issues,
|
|
12
12
|
// then hints (not-yet-uploaded resources), else "ready".
|
|
13
|
-
export function footerMessage(t, validation,
|
|
13
|
+
export function footerMessage(t, validation, offersTestMail) {
|
|
14
14
|
if (validation.missingRequired.length > 0) {
|
|
15
15
|
return {
|
|
16
16
|
tone: "bad",
|
|
17
|
-
text: t(
|
|
17
|
+
text: t(offersTestMail
|
|
18
18
|
? "documentDesigner.mail.footer.missingPreview"
|
|
19
19
|
: "documentDesigner.mail.footer.missing", { names: missingLabels(t, validation) }),
|
|
20
20
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
4
3
|
import { LAYOUT_OWNED_PLACEHOLDERS, PLACEHOLDER_SYMBOL, SYSTEM_PLACEHOLDER_TYPE, systemPlaceholderLabel, } from "./mail-draft.js";
|
|
5
4
|
import { RailHint, RailRow, RailSection } from "./rail.js";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverHandlers } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { dispatcherErrorText, useMutation, usePrimitives, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { useState } from "react";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverHandlers } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { dispatcherErrorText, formatWhen, useMutation, usePrimitives, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-renderer/headless";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { PlaceholderLineEditor, TemplateResolverHandlers, TemplateResolverQueries, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { dispatcherErrorText, useMutation, usePrimitives, useQuery, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { EmptyState } from "@cosmicdrift/kumiko-renderer/web";
|
|
6
5
|
import { useState } from "react";
|
|
7
6
|
import { lastSlugSegment, parseJsonRecord, uniqueResourceKey } from "./mail-draft.js";
|
|
7
|
+
import { templateTitleText } from "./used-by-label.js";
|
|
8
8
|
function pdfRowIdOf(summaries, slug) {
|
|
9
9
|
const ofSlug = (summaries ?? []).filter((row) => row.slug === slug);
|
|
10
10
|
return (ofSlug.find((row) => row.scope === "tenant") ?? ofSlug[0])?.id ?? null;
|
|
@@ -42,7 +42,10 @@ function PdfLinkForm({ templates, variableLabels, templateId, takenKeys, onLinke
|
|
|
42
42
|
return (_jsxs("div", { className: "flex flex-col gap-4", children: [error !== null && (_jsx(Banner, { variant: "error", testId: "mail-pdf-link-error", children: error })), _jsx(Field, { id: "mail-pdf-template", label: t("documentDesigner.mail.pdfLink.template"), children: _jsx(Input, { kind: "select", id: "mail-pdf-template", name: "mail-pdf-template", value: slug, onChange: (next) => {
|
|
43
43
|
setSlug(next);
|
|
44
44
|
setEditedName(null);
|
|
45
|
-
}, options: templates.map((template) => ({
|
|
45
|
+
}, options: templates.map((template) => ({
|
|
46
|
+
value: template.slug,
|
|
47
|
+
label: templateTitleText(t, template.title),
|
|
48
|
+
})) }) }), _jsx(Field, { id: "mail-pdf-file-name", label: t("documentDesigner.mail.pdfLink.fileName"), description: t("documentDesigner.mail.pdfLink.fileNameHint"), children: _jsx(PlaceholderLineEditor, { id: "mail-pdf-file-name", value: fileName, onChange: setEditedName, variableLabels: variableLabels, "aria-label": t("documentDesigner.mail.pdfLink.fileName") }) }), _jsx("div", { className: "flex justify-end", children: _jsx(Button, { disabled: slug === "" || fileName === "" || linkPdf.pending, loading: linkPdf.pending, onClick: link, testId: "mail-pdf-link-confirm", children: t("documentDesigner.mail.pdfLink.confirm") }) })] }));
|
|
46
49
|
}
|
|
47
50
|
export function PdfLinkModal({ open, onOpenChange, templates, ...form }) {
|
|
48
51
|
const t = useTranslation();
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { ConfigQueries } from "@cosmicdrift/kumiko-bundled-features/config/web";
|
|
4
3
|
import { useNav, usePrimitives, useQuery, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { DOCUMENT_FALLBACK_CURRENCY } from "@cosmicdrift/kumiko-renderer/headless";
|
package/dist/web/mail-preview.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverQueries } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { dispatcherErrorText, usePrimitives, useQuery, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { LoadingState, ModeSwitch } from "@cosmicdrift/kumiko-renderer/web";
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { MAIL_TONES, PlaceholderLineEditor, TemplateResolverQueries, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { useAppFeatures, useNav, usePrimitives, useQuery, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
6
|
-
import { DEFAULT_LAYOUT_SLUG, TENANT_MAIL_SENDING_SCREEN_ID } from "
|
|
5
|
+
import { DEFAULT_LAYOUT_SLUG, TENANT_MAIL_SENDING_SCREEN_ID } from "./constants.js";
|
|
7
6
|
import { labelPlaceholders } from "./mail-draft.js";
|
|
8
7
|
import { RailField, RailHint, RailRow, RailSection } from "./rail.js";
|
|
9
8
|
import { usageParts } from "./used-by-label.js";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverHandlers } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { dispatcherErrorText, useMutation, usePrimitives, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { useRef, useState } from "react";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { formatWhen, useAppFeatures, useQuery, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
4
3
|
import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-renderer/headless";
|
|
5
4
|
import { StatusBadge } from "@cosmicdrift/kumiko-renderer/web";
|
package/dist/web/origin-bar.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverHandlers, TemplateResolverQueries, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { dispatcherErrorText, useMutation, usePrimitives, useQuery, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
5
|
-
import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-renderer/headless";
|
|
4
|
+
import { EMPTY_VALUE_PLACEHOLDER, pluralKey } from "@cosmicdrift/kumiko-renderer/headless";
|
|
6
5
|
import { EmptyState, ErrorState, LoadingState } from "@cosmicdrift/kumiko-renderer/web";
|
|
7
6
|
import { useState } from "react";
|
|
8
7
|
import { originOf } from "./editor-header.js";
|
|
@@ -73,7 +72,7 @@ function originText(t, args) {
|
|
|
73
72
|
}
|
|
74
73
|
const usesKey = kind === "mail-layout" ? "mails" : "pdfs";
|
|
75
74
|
if (source.tenant !== null) {
|
|
76
|
-
return t(`documentDesigner.editor.origin.tenant.${usesKey}`, {
|
|
75
|
+
return t(pluralKey(`documentDesigner.editor.origin.tenant.${usesKey}`, userCount), {
|
|
77
76
|
version: systemVersion,
|
|
78
77
|
count: userCount,
|
|
79
78
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverQueries } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { formatWhen, usePrimitives, useQuery, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { Drawer, EmptyState, LoadingState } from "@cosmicdrift/kumiko-renderer/web";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TemplateEditorKind } from "
|
|
1
|
+
import type { TemplateEditorKind } from "./constants.ts";
|
|
2
2
|
export type OverviewUsageView = {
|
|
3
3
|
readonly feature: string;
|
|
4
4
|
readonly notification: string;
|
|
@@ -16,6 +16,9 @@ export type OverviewRowView = {
|
|
|
16
16
|
/** An open draft beside the served version, never another tenant's. */
|
|
17
17
|
readonly draftVersion: number | null;
|
|
18
18
|
readonly systemVersion: number | null;
|
|
19
|
+
/** SystemAdmin only: a stored tenant override that is not delivered. */
|
|
20
|
+
readonly lockedOverride: boolean;
|
|
21
|
+
readonly lockedOverrideI18nKey: string | null;
|
|
19
22
|
readonly modifiedAt: string;
|
|
20
23
|
readonly usedBy: readonly OverviewUsageView[];
|
|
21
24
|
readonly usedByCount: number;
|
package/dist/web/overview-row.js
CHANGED
|
@@ -21,7 +21,7 @@ function usageViewOf(value) {
|
|
|
21
21
|
const stringOr = (value, fallback) => typeof value === "string" ? value : fallback;
|
|
22
22
|
const numberOr = (value, fallback) => typeof value === "number" ? value : fallback;
|
|
23
23
|
export function parseOverviewRow(row) {
|
|
24
|
-
const { id, title, layoutSlug, slug, kind, origin, locales, status, version, draftVersion, systemVersion, modifiedAt, usedBy, usedByCount, } = row;
|
|
24
|
+
const { id, title, layoutSlug, slug, kind, origin, locales, status, version, draftVersion, systemVersion, lockedOverride, lockedOverrideI18nKey, modifiedAt, usedBy, usedByCount, } = row;
|
|
25
25
|
if (typeof slug !== "string" || !isTemplateKind(kind) || !isStatus(status))
|
|
26
26
|
return null;
|
|
27
27
|
if (origin !== "tenant" && origin !== "system")
|
|
@@ -41,6 +41,8 @@ export function parseOverviewRow(row) {
|
|
|
41
41
|
version: numberOr(version, 0),
|
|
42
42
|
draftVersion: numberOr(draftVersion, null),
|
|
43
43
|
systemVersion: numberOr(systemVersion, null),
|
|
44
|
+
lockedOverride: lockedOverride === true,
|
|
45
|
+
lockedOverrideI18nKey: typeof lockedOverrideI18nKey === "string" ? lockedOverrideI18nKey : null,
|
|
44
46
|
modifiedAt: stringOr(modifiedAt, ""),
|
|
45
47
|
usedBy: usages,
|
|
46
48
|
usedByCount: numberOr(usedByCount, usages.length),
|
package/dist/web/page-canvas.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { DocumentContentEditor, PDF_DEFAULT_MARGIN_MM, PDF_DOCUMENT_BLOCKS, PDF_FOOTER_MARGIN_MM, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { cn } from "@cosmicdrift/kumiko-renderer/web";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
4
3
|
import { UploadZone } from "@cosmicdrift/kumiko-renderer/web";
|
|
5
4
|
import { RailField, RailHint, RailRow, RailSection } from "./rail.js";
|
package/dist/web/pdf-meta.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { TemplateResolverHandlers, TemplateResolverQueries, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { useDispatcher, usePrimitives, useQuery, useTranslation, useUserRoles, } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { ErrorState, LoadingState, PdfPreview, uploadFileRef, } from "@cosmicdrift/kumiko-renderer/web";
|
|
6
5
|
import { RendererPuppeteerClientQueries } from "@cosmicdrift/kumiko-renderer-puppeteer-client/qualified-names";
|
|
7
6
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
8
|
-
import { BRANDING_QUERY_QN } from "
|
|
7
|
+
import { BRANDING_QUERY_QN } from "./constants.js";
|
|
9
8
|
import { EditorHeader, EditorLocaleSwitch, EditorModeSwitch, originOf, } from "./editor-header.js";
|
|
10
9
|
import { EditorBody, EditorFooter, EditorFrame, EditorInfoBar } from "./editor-shell.js";
|
|
11
10
|
import { describeError, isAlreadyActive } from "./errors.js";
|
package/dist/web/rail.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { cn } from "@cosmicdrift/kumiko-renderer/web";
|
|
4
3
|
export function RailSection({ title, action, testId, children, }) {
|
|
5
|
-
return (_jsxs("section", { className: "flex flex-col border-b pb-1", "data-testid": testId, children: [_jsxs("div", { className: "flex items-center gap-2 px-3.5 pt-2.5 pb-1", children: [_jsx("span", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground", children: title }), _jsx("div", { className: "
|
|
4
|
+
return (_jsxs("section", { className: "flex flex-col border-b pb-1", "data-testid": testId, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1 px-3.5 pt-2.5 pb-1", children: [_jsx("span", { className: "min-w-0 text-xs font-medium uppercase tracking-wider text-muted-foreground", children: title }), action !== undefined && _jsx("div", { className: "ml-auto", children: action })] }), children] }));
|
|
6
5
|
}
|
|
7
6
|
export function RailField({ children }) {
|
|
8
7
|
return _jsx("div", { className: "flex flex-col gap-3 px-3.5 py-2", children: children });
|
|
@@ -18,8 +17,13 @@ function RequiredLabel({ label }) {
|
|
|
18
17
|
return (_jsxs(_Fragment, { children: [label.slice(0, lastSpace + 1), _jsxs("span", { className: "whitespace-nowrap", children: [label.slice(lastSpace + 1), _jsx("span", { className: "font-semibold text-status-bad", children: " *" })] })] }));
|
|
19
18
|
}
|
|
20
19
|
export function RailRow({ symbol, label, nameHint, required, trailing, trailingTone = "muted", action, bad, testId, onPress, }) {
|
|
21
|
-
const content = (_jsxs(_Fragment, { children: [symbol !== undefined && (_jsx("span", { className: "inline-flex h-[18px] w-[22px] shrink-0 items-center justify-center rounded-sm bg-muted font-mono text-xs text-muted-foreground", children: symbol })), _jsx("span", { className: cn(
|
|
22
|
-
|
|
20
|
+
const content = (_jsxs(_Fragment, { children: [symbol !== undefined && (_jsx("span", { className: "inline-flex h-[18px] w-[22px] shrink-0 items-center justify-center rounded-sm bg-muted font-mono text-xs text-muted-foreground", children: symbol })), _jsx("span", { className: cn(
|
|
21
|
+
// anywhere, not break-word: only it lets a file name without spaces narrow the min-content
|
|
22
|
+
// width, so the label wraps instead of running under the action.
|
|
23
|
+
"min-w-0 grow wrap-anywhere text-sm", trailing !== undefined && "min-w-min max-w-[65%] shrink-0", bad === true && "text-status-bad"), title: nameHint !== undefined && nameHint !== label ? nameHint : undefined, children: required === true ? _jsx(RequiredLabel, { label: label }) : label }), trailing !== undefined && (_jsx("span", { className: cn("min-w-0 text-xs", action !== undefined ? "basis-full wrap-anywhere" : "truncate text-right", bad === true ? "text-status-bad" : TRAILING_TONE[trailingTone]), title: typeof trailing === "string" ? trailing : undefined, children: trailing }))] }));
|
|
24
|
+
// Beside an action the row is too narrow for label and trailing text: the trailing text takes its
|
|
25
|
+
// own line and wraps there instead of being clipped to an ellipsis.
|
|
26
|
+
const rowClass = cn("flex min-h-10 min-w-0 grow items-center gap-2 px-3.5 text-left", action !== undefined && "flex-wrap gap-y-0.5 py-1");
|
|
23
27
|
return (_jsxs("div", { className: cn("flex items-center border-b", bad === true && "bg-status-bad-surface"), "data-testid": testId, "data-bad": bad === true ? "true" : undefined, children: [onPress === undefined ? (_jsx("div", { className: rowClass, children: content })) : (_jsx("button", { type: "button", onClick: onPress, className: cn(rowClass, "hover:bg-muted"), ...(testId !== undefined && { "data-testid": `${testId}-insert` }), children: content })), action !== undefined && _jsx("div", { className: "shrink-0 pr-2", children: action })] }));
|
|
24
28
|
}
|
|
25
29
|
export function RailHint({ children }) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// @runtime client
|
|
3
2
|
import { PDF_ORIENTATIONS, PDF_PAGE_FORMATS, PlaceholderLineEditor, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
4
3
|
import { usePrimitives, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
5
4
|
import { languageName } from "./mail-origin-bar.js";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
// @runtime client
|
|
2
1
|
import { useAppFeatures } from "@cosmicdrift/kumiko-renderer";
|
|
3
|
-
import { FILES_FEATURE_NAME } from "
|
|
2
|
+
import { FILES_FEATURE_NAME } from "./constants.js";
|
|
4
3
|
// The app schema lists every mounted feature, screenless ones included, so this is the server's
|
|
5
4
|
// answer: without the files feature there is no upload route.
|
|
6
5
|
export function useFilesCapability() {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
// @runtime client
|
|
2
1
|
import { useAppFeatures, useQuery } from "@cosmicdrift/kumiko-renderer";
|
|
3
|
-
import { PROFILE_FEATURE_NAME, PROFILE_SCREEN_ID, USER_ME_QUERY_QN } from "
|
|
2
|
+
import { PROFILE_FEATURE_NAME, PROFILE_SCREEN_ID, USER_ME_QUERY_QN } from "./constants.js";
|
|
4
3
|
export function useOwnAddress() {
|
|
5
4
|
const features = useAppFeatures();
|
|
6
5
|
const me = useQuery(USER_ME_QUERY_QN, {});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @runtime client
|
|
2
1
|
import { TemplateResolverHandlers, TemplateResolverQueries, } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
|
|
3
2
|
import { dispatcherErrorText, useMutation, useQuery, useTranslation, } from "@cosmicdrift/kumiko-renderer";
|
|
4
3
|
import { useState } from "react";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { OverviewRowView, OverviewUsageView } from "./overview-row.ts";
|
|
2
2
|
type Translate = (key: string, params?: Readonly<Record<string, unknown>>) => string;
|
|
3
3
|
export declare function variableLabelText(t: Translate, name: string, label: string | undefined): string;
|
|
4
|
+
export declare function templateTitleText(t: Translate, title: string): string;
|
|
4
5
|
export declare function templateTitle(t: Translate, row: Pick<OverviewRowView, "title" | "slug" | "kind">): string;
|
|
5
6
|
export declare function usageParts(t: Translate, usage: OverviewUsageView): {
|
|
6
7
|
readonly feature: string;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-renderer/headless";
|
|
2
|
-
|
|
3
|
-
import { DEFAULT_LAYOUT_SLUG } from "../constants.js";
|
|
1
|
+
import { EMPTY_VALUE_PLACEHOLDER, pluralKey } from "@cosmicdrift/kumiko-renderer/headless";
|
|
2
|
+
import { DEFAULT_LAYOUT_SLUG } from "./constants.js";
|
|
4
3
|
// t() returns the key itself when no translation exists.
|
|
5
4
|
function translateOrRaw(t, key, raw) {
|
|
6
5
|
const translated = t(key);
|
|
@@ -11,11 +10,15 @@ export function variableLabelText(t, name, label) {
|
|
|
11
10
|
return label === undefined ? name : translateOrRaw(t, label, label);
|
|
12
11
|
}
|
|
13
12
|
const NOTIFICATION_SLUG = /^([^:]+):notify:([^:]+)$/;
|
|
13
|
+
// A seeded system template may store an i18n key as its title; plain text stays as typed.
|
|
14
|
+
export function templateTitleText(t, title) {
|
|
15
|
+
return translateOrRaw(t, title, title);
|
|
16
|
+
}
|
|
14
17
|
// A seeded system mail has no stored title, so its notification label from the
|
|
15
18
|
// owning feature names it; the slug stays the last resort.
|
|
16
19
|
export function templateTitle(t, row) {
|
|
17
20
|
if (row.title !== row.slug)
|
|
18
|
-
return row.title;
|
|
21
|
+
return templateTitleText(t, row.title);
|
|
19
22
|
const match = row.kind === "mail" ? NOTIFICATION_SLUG.exec(row.slug) : null;
|
|
20
23
|
if (match === null)
|
|
21
24
|
return row.slug;
|
|
@@ -40,7 +43,9 @@ export function usedByLabel(t, row) {
|
|
|
40
43
|
}
|
|
41
44
|
return row.usedByCount === 0
|
|
42
45
|
? EMPTY_VALUE_PLACEHOLDER
|
|
43
|
-
: t("documentDesigner.usedBy.templates",
|
|
46
|
+
: t(pluralKey("documentDesigner.usedBy.templates", row.usedByCount), {
|
|
47
|
+
count: row.usedByCount,
|
|
48
|
+
});
|
|
44
49
|
}
|
|
45
50
|
const first = row.usedBy[0];
|
|
46
51
|
return first === undefined ? EMPTY_VALUE_PLACEHOLDER : usageLabel(t, first);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-document-designer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.379.0",
|
|
4
4
|
"description": "Document designer for Kumiko: template overview, layout editor (mail layout, PDF letterhead) and the PDF template editor.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"./web/styles.css": "./src/web/styles.css"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@cosmicdrift/kumiko-bundled-features": "0.
|
|
24
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
25
|
-
"@cosmicdrift/kumiko-renderer": "0.
|
|
26
|
-
"@cosmicdrift/kumiko-renderer-puppeteer-client": "0.
|
|
27
|
-
"@cosmicdrift/kumiko-types": "0.
|
|
23
|
+
"@cosmicdrift/kumiko-bundled-features": "0.379.0",
|
|
24
|
+
"@cosmicdrift/kumiko-framework": "0.379.0",
|
|
25
|
+
"@cosmicdrift/kumiko-renderer": "0.379.0",
|
|
26
|
+
"@cosmicdrift/kumiko-renderer-puppeteer-client": "0.379.0",
|
|
27
|
+
"@cosmicdrift/kumiko-types": "0.379.0",
|
|
28
28
|
"react": "^19.2.6"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.379.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "Designer rails wrap instead of clipping",
|
|
6
|
+
"detail": "A rail section wraps its action below the heading instead of clipping it, a resource name without spaces wraps inside its row instead of running under \"Remove\" and its meta text takes its own line instead of an ellipsis, the footer no longer offers a test mail when send-test-status says none can be sent, and the header label placeholder reads \"e.g. Reminder\" instead of an incident example. In a narrow window (1024px beside the app sidebar) both rails share the left column so the page keeps its room, and the header leaves save and publish to the footer below 1280px so the template title stays readable."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.379.0",
|
|
10
|
+
"type": "fix",
|
|
11
|
+
"title": "Long template names wrap in the template overview",
|
|
12
|
+
"detail": "In the template overview, a long template name such as \"Kündigungshinweis an den Betreiber\" now wraps to a second line instead of widening the first column. The overview fits at 1280 px again when billing-foundation templates are listed."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.379.0",
|
|
16
|
+
"type": "improvement",
|
|
17
|
+
"title": "Template overview shows locked tenant overrides",
|
|
18
|
+
"detail": "Rows with lockedOverride and lockedOverrideI18nKey show the status text as a warning badge in the status column. The row action \"Remove own version\" calls the existing resetToSystem with the new overview field lockedOverrideId (the tenant row; one locale per click). The status shows a short label with the long sentence as tooltip."
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"version": "0.378.0",
|
|
4
22
|
"type": "fix",
|