@cosmicdrift/kumiko-samples 0.374.0 → 0.378.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/package.json +1 -1
- package/packages/bundled-features/package.json +6 -4
- package/packages/bundled-features/src/account-security/changes.json +6 -0
- package/packages/bundled-features/src/account-security/constants.ts +1 -0
- package/packages/bundled-features/src/account-security/index.ts +1 -0
- package/packages/bundled-features/src/admin-shell/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/audit/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/auth-email-password/mail-notifications.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +1 -1
- package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +1 -1
- package/packages/bundled-features/src/auth-email-password/web/index.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/web/session.tsx +1 -1
- package/packages/bundled-features/src/auth-email-password/web/tenant-menu-items.tsx +1 -1
- package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +1 -1
- package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +1 -1
- package/packages/bundled-features/src/auth-foundation/changes.json +6 -0
- package/packages/bundled-features/src/auth-foundation/env.ts +27 -0
- package/packages/bundled-features/src/auth-foundation/index.ts +1 -0
- package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-pages.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/contact-card.ts +14 -0
- package/packages/bundled-features/src/billing-foundation/handlers/billing-plans.query.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/index.ts +1 -0
- package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +1 -0
- package/packages/bundled-features/src/billing-foundation/types.ts +12 -0
- package/packages/bundled-features/src/billing-foundation/validate-options.ts +16 -0
- package/packages/bundled-features/src/billing-foundation/web/billing-contact-plan.tsx +32 -0
- package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +5 -15
- package/packages/bundled-features/src/billing-foundation/web/cancel-contract-dialog.tsx +2 -2
- package/packages/bundled-features/src/billing-foundation/web/checkout-consent-dialog.tsx +1 -1
- package/packages/bundled-features/src/billing-foundation/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/billing-foundation/web/localized-params.ts +14 -0
- package/packages/bundled-features/src/cap-counter/changes.json +12 -0
- package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +9 -0
- package/packages/bundled-features/src/cap-overview/web/cap-cards-panel.tsx +3 -3
- package/packages/bundled-features/src/cap-overview/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/channel-email/changes.json +6 -0
- package/packages/bundled-features/src/channel-email/email-channel.ts +2 -1
- package/packages/bundled-features/src/compliance-profiles/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/config/feature.ts +2 -2
- package/packages/bundled-features/src/config/web/i18n.ts +1 -0
- package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
- package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/delivery/unsubscribe-page.ts +1 -1
- package/packages/bundled-features/src/delivery/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/delivery/web/delivery-status-cell.tsx +1 -1
- package/packages/bundled-features/src/feature-toggles/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/file-provider-s3/changes.json +6 -0
- package/packages/bundled-features/src/file-provider-s3/env-named-feature.ts +45 -0
- package/packages/bundled-features/src/file-provider-s3/env-schema.ts +20 -13
- package/packages/bundled-features/src/file-provider-s3/index.ts +4 -0
- package/packages/bundled-features/src/folders/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/folders/web/folder-section.tsx +3 -4
- package/packages/bundled-features/src/host-routing/README.md +7 -0
- package/packages/bundled-features/src/host-routing/changes.json +6 -0
- package/packages/bundled-features/src/host-routing/constants.ts +4 -0
- package/packages/bundled-features/src/host-routing/dispatch.ts +34 -26
- package/packages/bundled-features/src/host-routing/feature.ts +122 -41
- package/packages/bundled-features/src/host-routing/host.ts +28 -1
- package/packages/bundled-features/src/host-routing/index.ts +3 -0
- package/packages/bundled-features/src/host-routing/options.ts +45 -2
- package/packages/bundled-features/src/host-routing/redirects.ts +33 -0
- package/packages/bundled-features/src/host-routing/tenant-lookup.ts +65 -0
- package/packages/bundled-features/src/host-routing/validate-options.ts +48 -1
- package/packages/bundled-features/src/inbound-mail-foundation/changes.json +13 -0
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +8 -0
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +11 -4
- package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +42 -0
- package/packages/bundled-features/src/inbound-mail-foundation/index.ts +4 -0
- package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +100 -0
- package/packages/bundled-features/src/inbound-mail-foundation/types.ts +2 -2
- package/packages/bundled-features/src/jobs/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/legal-pages/changes.json +6 -0
- package/packages/bundled-features/src/legal-pages/feature.ts +14 -1
- package/packages/bundled-features/src/legal-pages/layout.ts +6 -6
- package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +1 -1
- package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
- package/packages/bundled-features/src/mail-foundation/feature.ts +21 -22
- package/packages/bundled-features/src/mail-foundation/i18n.ts +3 -2
- package/packages/bundled-features/src/mail-transport-smtp/i18n.ts +1 -1
- package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/notes-history/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/page-render/branding.ts +1 -1
- package/packages/bundled-features/src/page-render/layout.ts +2 -2
- package/packages/bundled-features/src/page-render/markdown.ts +1 -1
- package/packages/bundled-features/src/personal-access-tokens/i18n.ts +1 -1
- package/packages/bundled-features/src/personal-access-tokens/screens.ts +1 -1
- package/packages/bundled-features/src/secrets/feature.ts +4 -4
- package/packages/bundled-features/src/seo/sitemap.ts +1 -1
- package/packages/bundled-features/src/shared/mail-template-body.ts +1 -1
- package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +127 -2
- package/packages/bundled-features/src/tags/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/template-resolver/changes.json +38 -0
- package/packages/bundled-features/src/template-resolver/compile-document-body.ts +61 -3
- package/packages/bundled-features/src/template-resolver/constants.ts +3 -0
- package/packages/bundled-features/src/template-resolver/document-blocks.ts +36 -0
- package/packages/bundled-features/src/template-resolver/document-images.ts +29 -0
- package/packages/bundled-features/src/template-resolver/document-ops.ts +515 -0
- package/packages/bundled-features/src/template-resolver/document-sanitizer.ts +44 -0
- package/packages/bundled-features/src/template-resolver/document-schema.ts +5 -0
- package/packages/bundled-features/src/template-resolver/feature.ts +79 -34
- package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +1 -0
- package/packages/bundled-features/src/template-resolver/handlers/collection-item.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/collection-list.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +2 -6
- package/packages/bundled-features/src/template-resolver/handlers/collection-shared.ts +0 -6
- package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +67 -58
- package/packages/bundled-features/src/template-resolver/handlers/discard-draft.write.ts +36 -13
- package/packages/bundled-features/src/template-resolver/handlers/document-base.ts +86 -0
- package/packages/bundled-features/src/template-resolver/handlers/document-blocks.query.ts +48 -0
- package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +11 -3
- package/packages/bundled-features/src/template-resolver/handlers/import-bundle.write.ts +37 -28
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +66 -62
- package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +134 -0
- package/packages/bundled-features/src/template-resolver/handlers/preview.query.ts +2 -1
- package/packages/bundled-features/src/template-resolver/handlers/reset-to-system.write.ts +62 -49
- package/packages/bundled-features/src/template-resolver/handlers/resource-link-pdf.write.ts +44 -29
- package/packages/bundled-features/src/template-resolver/handlers/resource-remove.write.ts +52 -36
- package/packages/bundled-features/src/template-resolver/handlers/resource-upload.write.ts +126 -106
- package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +38 -0
- package/packages/bundled-features/src/template-resolver/handlers/send-test-status.query.ts +31 -0
- package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +105 -110
- package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +110 -103
- package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +22 -1
- package/packages/bundled-features/src/template-resolver/handlers/toggle-status.write.ts +56 -28
- package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +38 -29
- package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +24 -9
- package/packages/bundled-features/src/template-resolver/index.ts +8 -1
- package/packages/bundled-features/src/template-resolver/{web/placeholder-text.ts → placeholder-text.ts} +1 -1
- package/packages/bundled-features/src/template-resolver/qualified-names.ts +4 -0
- package/packages/bundled-features/src/template-resolver/seeding.ts +3 -1
- package/packages/bundled-features/src/template-resolver/template-bundle.ts +6 -1
- package/packages/bundled-features/src/template-resolver/template-edit-policy.ts +91 -0
- package/packages/bundled-features/src/template-resolver/template-preview.ts +32 -10
- package/packages/bundled-features/src/template-resolver/template-validation.ts +32 -11
- package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +3 -3
- package/packages/bundled-features/src/template-resolver/web/document-editor-extensions.ts +29 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +43 -5
- package/packages/bundled-features/src/template-resolver/web/document-toolbar-blocks.ts +9 -33
- package/packages/bundled-features/src/template-resolver/web/i18n.ts +30 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +2 -2
- package/packages/bundled-features/src/tenant/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/tenant/web/member-status-cell.tsx +1 -1
- package/packages/bundled-features/src/tier-engine/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/user-data-rights/changes.json +6 -0
- package/packages/bundled-features/src/user-data-rights/env.ts +15 -0
- package/packages/bundled-features/src/user-data-rights/feature.ts +4 -2
- package/packages/bundled-features/src/user-data-rights/index.ts +1 -0
- package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/mail-notifications.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +1 -1
- package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +2 -2
- package/packages/bundled-features/src/waitlist/changes.json +6 -0
- package/packages/bundled-features/src/waitlist/legacy-migrate.ts +51 -2
- package/samples/apps/admin-console/package.json +0 -3
- package/samples/apps/admin-console/src/app/client.tsx +1 -1
- package/samples/apps/admin-console/src/app/shell.tsx +1 -1
- package/samples/apps/config-demo/package.json +1 -3
- package/samples/apps/config-demo/src/app/client.tsx +1 -1
- package/samples/apps/config-demo/src/app/shell.tsx +2 -2
- package/samples/apps/config-demo/src/features/demo/web/index.ts +1 -1
- package/samples/apps/config-demo/tsconfig.json +0 -12
- package/samples/apps/marketing-demo/package.json +1 -3
- package/samples/apps/marketing-demo/src/app/client.tsx +1 -1
- package/samples/apps/marketing-demo/src/app/shell.tsx +1 -1
- package/samples/apps/marketing-demo/src/features/assets/web/index.ts +1 -1
- package/samples/apps/marketing-demo/src/features/helpdesk/web/index.ts +1 -1
- package/samples/apps/showcase/package.json +1 -3
- package/samples/apps/showcase/src/app/client.tsx +1 -1
- package/samples/apps/showcase/src/app/shell.tsx +1 -1
- package/samples/apps/showcase/src/features/demos/web/index.ts +1 -1
- package/samples/apps/showcase/src/features/demos/web/pages/sidebar-panel.tsx +1 -1
- package/samples/apps/showcase/src/features/demos/web/pages/toast.tsx +1 -1
- package/samples/apps/showcase/src/features/items/web/index.ts +1 -1
- package/samples/apps/styleguide/package.json +1 -3
- package/samples/apps/styleguide/src/app/client.tsx +1 -1
- package/samples/apps/styleguide/src/app/shell.tsx +2 -2
- package/samples/apps/styleguide/src/features/ai-settings/web.ts +1 -1
- package/samples/apps/styleguide/src/features/content/web.tsx +2 -2
- package/samples/apps/styleguide/src/features/demo/web.ts +1 -1
- package/samples/apps/styleguide/src/features/examples/web.ts +1 -1
- package/samples/apps/styleguide/src/features/gallery/web/Gallery.tsx +1 -1
- package/samples/apps/styleguide/src/features/gallery/web/index.ts +1 -1
- package/samples/apps/styleguide/src/features/widgets/demo-locale.ts +1 -1
- package/samples/apps/styleguide/src/features/widgets/lib/format.ts +1 -1
- package/samples/apps/styleguide/src/features/widgets/web/DashboardFilterEcho.tsx +1 -1
- package/samples/apps/styleguide/src/features/widgets/web/FormExamples.tsx +1 -1
- package/samples/apps/styleguide/src/features/widgets/web/Widgets.tsx +1 -1
- package/samples/apps/styleguide/src/features/widgets/web/index.ts +1 -1
- package/samples/apps/styleguide/tsconfig.json +0 -12
- package/samples/apps/ui-walkthrough/package.json +1 -3
- package/samples/apps/ui-walkthrough/src/app/client.tsx +1 -1
- package/samples/apps/ui-walkthrough/src/app/help-action.tsx +37 -0
- package/samples/apps/ui-walkthrough/src/app/seed-templates.ts +2 -0
- package/samples/apps/ui-walkthrough/src/app/shell.tsx +7 -1
- package/samples/apps/ui-walkthrough/src/app/template-seed-data.ts +20 -0
- package/samples/apps/ui-walkthrough/src/features/billing/web/index.ts +1 -1
- package/samples/apps/ui-walkthrough/src/features/rental/feature.ts +65 -1
- package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +70 -0
- package/samples/apps/ui-walkthrough/src/features/rental/invoice-receive.ts +20 -0
- package/samples/apps/ui-walkthrough/src/features/rental/lease-support.ts +15 -0
- package/samples/apps/ui-walkthrough/src/features/rental/qualified-names.ts +2 -0
- package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +79 -0
- package/samples/apps/ui-walkthrough/src/features/rental/web/index.ts +3 -1
- package/samples/apps/ui-walkthrough/src/features/rental/web/upload-standard-layout.tsx +61 -0
- package/samples/apps/ui-walkthrough/src/features/tasks/i18n.ts +8 -0
- package/samples/apps/ui-walkthrough/src/features/tasks/web/index.ts +1 -1
- package/samples/apps/ui-walkthrough/src/features/vehicles/web/index.ts +1 -1
- package/samples/apps/ui-walkthrough/src/run-config.ts +32 -3
- package/samples/apps/use-all-bundled/bin/main.ts +3 -2
- package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +12 -0
- package/samples/apps/use-all-bundled/e2e-billing-gallery/server.ts +1 -1
- package/samples/apps/use-all-bundled/feature-manifest.json +3 -2
- package/samples/apps/use-all-bundled/package.json +1 -3
- package/samples/apps/use-all-bundled/src/app/client.tsx +1 -1
- package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +5 -4
- package/samples/apps/use-all-bundled/src/app/shell.tsx +1 -1
- package/samples/apps/use-all-bundled/src/run-config.ts +10 -1
- package/samples/apps/workspaces/package.json +1 -3
- package/samples/apps/workspaces/src/app/client.tsx +1 -1
- package/samples/apps/workspaces/src/app/shell.tsx +1 -1
- package/samples/apps/workspaces/src/features/demo/web/index.ts +1 -1
- package/samples/apps/workspaces/src/features/demo-driver/web/index.ts +1 -1
- package/samples/recipes/apex-landing/package.json +1 -1
- package/samples/recipes/apex-landing/src/feature.ts +1 -1
- package/samples/recipes/apex-surface-auth/README.md +1 -1
- package/samples/recipes/apex-surface-auth/src/feature.ts +2 -2
- package/samples/recipes/compose-stacks/README.md +7 -4
- package/samples/recipes/delivery-notifications/README.md +1 -1
- package/samples/recipes/embedded/README.md +8 -0
- package/samples/recipes/embedded/src/feature.ts +8 -0
- package/samples/recipes/embedded/src/handlers/invoice-receive.write.ts +38 -0
- package/samples/recipes/embedded/src/screens/invoice-receive.screen.ts +59 -0
- package/samples/recipes/embedded-entity-form/package.json +0 -1
- package/samples/recipes/embedded-entity-form/src/web/accept-suggestion-drawer.tsx +1 -1
- package/samples/recipes/notes-history-basic/README.md +1 -1
- package/samples/recipes/record-detail-layout/package.json +0 -1
- package/samples/recipes/tags-basic/README.md +1 -1
- package/samples/recipes/user-profile/README.md +1 -1
- package/samples/recipes/wizard-form/package.json +0 -1
- package/samples/recipes/wizard-form/src/web/index.ts +2 -2
- package/samples/recipes/wizard-form/src/web/listing-review-section.tsx +2 -2
- package/samples/recipes/writeform-section/package.json +0 -1
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
useTranslation,
|
|
13
13
|
VariableChips,
|
|
14
14
|
} from "@cosmicdrift/kumiko-renderer";
|
|
15
|
-
import { cn } from "@cosmicdrift/kumiko-renderer
|
|
15
|
+
import { cn } from "@cosmicdrift/kumiko-renderer/web";
|
|
16
16
|
import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
17
17
|
import type { Editor, JSONContent } from "@tiptap/core";
|
|
18
18
|
import { EditorContent, useEditor, useEditorState } from "@tiptap/react";
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
Bold as BoldIcon,
|
|
26
26
|
Braces,
|
|
27
27
|
ChevronDown,
|
|
28
|
+
GalleryThumbnails,
|
|
28
29
|
Image as ImageIcon,
|
|
29
30
|
Italic as ItalicIcon,
|
|
30
31
|
Link as LinkIcon,
|
|
@@ -72,7 +73,15 @@ function previewsKey(previews: Readonly<Record<string, DocumentResourcePreview>>
|
|
|
72
73
|
.join("\n");
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
type PanelKind =
|
|
76
|
+
type PanelKind =
|
|
77
|
+
| "link"
|
|
78
|
+
| "placeholder"
|
|
79
|
+
| "image"
|
|
80
|
+
| "button"
|
|
81
|
+
| "repeat"
|
|
82
|
+
| "align"
|
|
83
|
+
| "steps"
|
|
84
|
+
| "images";
|
|
76
85
|
|
|
77
86
|
// Blocks that stay in the canvas toolbar; the rest moves into the overflow menu.
|
|
78
87
|
const CANVAS_INLINE_BLOCKS: readonly DocumentToolbarBlock[] = ["image", "table"];
|
|
@@ -83,6 +92,7 @@ const BLOCK_PANEL: Partial<Record<DocumentToolbarBlock, PanelKind>> = {
|
|
|
83
92
|
repeat: "repeat",
|
|
84
93
|
align: "align",
|
|
85
94
|
steps: "steps",
|
|
95
|
+
images: "images",
|
|
86
96
|
};
|
|
87
97
|
|
|
88
98
|
const ALIGNMENT_ICONS: Record<DocumentTextAlignment, ReactNode> = {
|
|
@@ -392,7 +402,11 @@ function InsertPanel({
|
|
|
392
402
|
};
|
|
393
403
|
|
|
394
404
|
const needsVariables =
|
|
395
|
-
kind === "button" ||
|
|
405
|
+
kind === "button" ||
|
|
406
|
+
kind === "repeat" ||
|
|
407
|
+
kind === "placeholder" ||
|
|
408
|
+
kind === "steps" ||
|
|
409
|
+
kind === "images";
|
|
396
410
|
const noVariables = needsVariables && selectable.length === 0;
|
|
397
411
|
const idPrefix = `${editorId}-panel`;
|
|
398
412
|
|
|
@@ -498,6 +512,16 @@ function InsertPanel({
|
|
|
498
512
|
onChange={setChosenName}
|
|
499
513
|
/>
|
|
500
514
|
)}
|
|
515
|
+
{kind === "images" && !noVariables && (
|
|
516
|
+
<NameSelect
|
|
517
|
+
id={`${idPrefix}-images-variable`}
|
|
518
|
+
label={t("template-resolver.documentEditor.imagesVariable")}
|
|
519
|
+
names={selectable}
|
|
520
|
+
labels={variableLabels}
|
|
521
|
+
value={selectedName}
|
|
522
|
+
onChange={setChosenName}
|
|
523
|
+
/>
|
|
524
|
+
)}
|
|
501
525
|
{kind === "steps" && !noVariables && (
|
|
502
526
|
<>
|
|
503
527
|
<NameSelect
|
|
@@ -551,6 +575,10 @@ function InsertPanel({
|
|
|
551
575
|
{...(kind === "repeat" &&
|
|
552
576
|
!noVariables && { onInsert: () => insertAndClose(repeatTableContent(selectedName)) })}
|
|
553
577
|
{...(kind === "steps" && !noVariables && { onInsert: submitSteps })}
|
|
578
|
+
{...(kind === "images" &&
|
|
579
|
+
!noVariables && {
|
|
580
|
+
onInsert: () => insertAndClose({ type: "images", attrs: { variable: selectedName } }),
|
|
581
|
+
})}
|
|
554
582
|
/>
|
|
555
583
|
</div>
|
|
556
584
|
</div>
|
|
@@ -563,7 +591,8 @@ export default function DocumentTiptapEditor({
|
|
|
563
591
|
onChange,
|
|
564
592
|
variables,
|
|
565
593
|
readOnly,
|
|
566
|
-
blocks = MAIL_DOCUMENT_BLOCKS,
|
|
594
|
+
blocks: configuredBlocks = MAIL_DOCUMENT_BLOCKS,
|
|
595
|
+
imageVariables = NO_NAMES,
|
|
567
596
|
variableLabels = NO_LABELS,
|
|
568
597
|
systemVariables = NO_NAMES,
|
|
569
598
|
resourcePreviews = NO_PREVIEWS,
|
|
@@ -581,6 +610,11 @@ export default function DocumentTiptapEditor({
|
|
|
581
610
|
const canvas = chrome === "canvas";
|
|
582
611
|
const compact = toolbar === "compact" && !canvas;
|
|
583
612
|
const hosted = toolbarHost !== undefined;
|
|
613
|
+
// A photo block needs an images variable to bind to; without one the button would open an empty panel.
|
|
614
|
+
const blocks =
|
|
615
|
+
imageVariables.length === 0
|
|
616
|
+
? configuredBlocks.filter((block) => block !== "images")
|
|
617
|
+
: configuredBlocks;
|
|
584
618
|
|
|
585
619
|
const placeholderLabel = t("template-resolver.documentEditor.placeholder");
|
|
586
620
|
const imageLabel = t("template-resolver.documentEditor.image");
|
|
@@ -588,6 +622,7 @@ export default function DocumentTiptapEditor({
|
|
|
588
622
|
const pageBreakLabel = t("template-resolver.documentEditor.pageBreak");
|
|
589
623
|
const buttonLabel = t("template-resolver.documentEditor.button");
|
|
590
624
|
const stepsLabel = t("template-resolver.documentEditor.steps");
|
|
625
|
+
const imagesLabel = t("template-resolver.documentEditor.images");
|
|
591
626
|
const stableLabels = useStableByKey(variableLabels, JSON.stringify(variableLabels));
|
|
592
627
|
const stableSystem = useStableByKey(systemVariables, systemVariables.join("\n"));
|
|
593
628
|
const stablePreviews = useStableByKey(resourcePreviews, previewsKey(resourcePreviews));
|
|
@@ -599,6 +634,7 @@ export default function DocumentTiptapEditor({
|
|
|
599
634
|
pageBreak: pageBreakLabel,
|
|
600
635
|
button: buttonLabel,
|
|
601
636
|
steps: stepsLabel,
|
|
637
|
+
images: imagesLabel,
|
|
602
638
|
imageBlock: imageBlockLabel,
|
|
603
639
|
variableLabels: stableLabels,
|
|
604
640
|
systemVariables: stableSystem,
|
|
@@ -612,6 +648,7 @@ export default function DocumentTiptapEditor({
|
|
|
612
648
|
pageBreakLabel,
|
|
613
649
|
buttonLabel,
|
|
614
650
|
stepsLabel,
|
|
651
|
+
imagesLabel,
|
|
615
652
|
stableLabels,
|
|
616
653
|
stableSystem,
|
|
617
654
|
stablePreviews,
|
|
@@ -731,6 +768,7 @@ export default function DocumentTiptapEditor({
|
|
|
731
768
|
pageBreak: { label: pageBreakLabel, icon: <Scissors size={16} /> },
|
|
732
769
|
align: { label: t("template-resolver.documentEditor.align"), icon: <AlignLeft size={16} /> },
|
|
733
770
|
steps: { label: stepsLabel, icon: <ListChecks size={16} /> },
|
|
771
|
+
images: { label: imagesLabel, icon: <GalleryThumbnails size={16} /> },
|
|
734
772
|
};
|
|
735
773
|
|
|
736
774
|
const repeatTable = activeState?.repeatTable ?? null;
|
|
@@ -1058,7 +1096,7 @@ export default function DocumentTiptapEditor({
|
|
|
1058
1096
|
editor={editor}
|
|
1059
1097
|
editorId={id}
|
|
1060
1098
|
kind={openPanel}
|
|
1061
|
-
variables={variables}
|
|
1099
|
+
variables={openPanel === "images" ? imageVariables : variables}
|
|
1062
1100
|
variableLabels={stableLabels}
|
|
1063
1101
|
onClose={() => setOpenPanel(null)}
|
|
1064
1102
|
/>
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
// @runtime client
|
|
2
2
|
import type { ContentEditorProps } from "@cosmicdrift/kumiko-renderer";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
|
-
|
|
5
|
-
export type DocumentToolbarBlock =
|
|
6
|
-
| "image"
|
|
7
|
-
| "table"
|
|
8
|
-
| "button"
|
|
9
|
-
| "divider"
|
|
10
|
-
| "repeat"
|
|
11
|
-
| "pageBreak"
|
|
12
|
-
| "align"
|
|
13
|
-
| "steps";
|
|
4
|
+
import type { DocumentToolbarBlock } from "../document-blocks.ts";
|
|
14
5
|
|
|
15
6
|
/** Imperative access for an outside panel (placeholder list, resource list). */
|
|
16
7
|
export type DocumentEditorHandle = {
|
|
@@ -31,6 +22,8 @@ export type DocumentEditorChrome = "default" | "canvas";
|
|
|
31
22
|
|
|
32
23
|
export type DocumentEditorProps = ContentEditorProps & {
|
|
33
24
|
readonly blocks?: readonly DocumentToolbarBlock[];
|
|
25
|
+
/** Names of the template's images variables; the photo block offers exactly these and is hidden without any. */
|
|
26
|
+
readonly imageVariables?: readonly string[];
|
|
34
27
|
/** Display label per variable name, as inserted (list item fields use the
|
|
35
28
|
* dotted form, e.g. "lines.description"). A chip shows label and name. */
|
|
36
29
|
readonly variableLabels?: Readonly<Record<string, string>>;
|
|
@@ -50,26 +43,9 @@ export type DocumentEditorProps = ContentEditorProps & {
|
|
|
50
43
|
readonly onEditorReady?: (handle: DocumentEditorHandle | null) => void;
|
|
51
44
|
};
|
|
52
45
|
|
|
53
|
-
export
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"steps",
|
|
60
|
-
] as const satisfies readonly DocumentToolbarBlock[];
|
|
61
|
-
|
|
62
|
-
export const PDF_DOCUMENT_BLOCKS = [
|
|
63
|
-
"align",
|
|
64
|
-
"image",
|
|
65
|
-
"table",
|
|
66
|
-
"divider",
|
|
67
|
-
"repeat",
|
|
68
|
-
"steps",
|
|
69
|
-
"pageBreak",
|
|
70
|
-
] as const satisfies readonly DocumentToolbarBlock[];
|
|
71
|
-
|
|
72
|
-
/** Block set for a template-resource kind; every kind except "document-pdf" gets the mail set. */
|
|
73
|
-
export function documentBlocksForKind(kind: string | undefined): readonly DocumentToolbarBlock[] {
|
|
74
|
-
return kind === "document-pdf" ? PDF_DOCUMENT_BLOCKS : MAIL_DOCUMENT_BLOCKS;
|
|
75
|
-
}
|
|
46
|
+
export {
|
|
47
|
+
type DocumentToolbarBlock,
|
|
48
|
+
documentBlocksForKind,
|
|
49
|
+
MAIL_DOCUMENT_BLOCKS,
|
|
50
|
+
PDF_DOCUMENT_BLOCKS,
|
|
51
|
+
} from "../document-blocks.ts";
|
|
@@ -43,6 +43,8 @@ export const defaultTranslations: TranslationsByLocale = {
|
|
|
43
43
|
"template-resolver.documentEditor.removeLink": "Remove link",
|
|
44
44
|
"template-resolver.documentEditor.repeat": "Repeat",
|
|
45
45
|
"template-resolver.documentEditor.repeatList": "List to repeat",
|
|
46
|
+
"template-resolver.documentEditor.images": "Photos",
|
|
47
|
+
"template-resolver.documentEditor.imagesVariable": "Photos from",
|
|
46
48
|
"template-resolver.documentEditor.steps": "Steps",
|
|
47
49
|
"template-resolver.documentEditor.stepsVariable": "Current step from",
|
|
48
50
|
"template-resolver.documentEditor.stepsList": "Steps, separated by commas (value=label)",
|
|
@@ -58,6 +60,8 @@ export const defaultTranslations: TranslationsByLocale = {
|
|
|
58
60
|
"template-resolver.editor.saving": "Saving…",
|
|
59
61
|
"template-resolver.editor.created": "Created.",
|
|
60
62
|
"template-resolver.editor.saved": "Saved.",
|
|
63
|
+
"templateResolver.errors.document.imagesBlockPdfOnly":
|
|
64
|
+
"Photo blocks are only allowed in PDF documents.",
|
|
61
65
|
"templateResolver.errors.document.buttonHrefNotPlaceholder":
|
|
62
66
|
"The button target “{detail}” must be a placeholder.",
|
|
63
67
|
"templateResolver.errors.document.disallowedLinkHref":
|
|
@@ -80,6 +84,30 @@ export const defaultTranslations: TranslationsByLocale = {
|
|
|
80
84
|
"templateResolver.checks.sizeUnderCap": "The mail is within the 10 MiB size limit",
|
|
81
85
|
"templateResolver.checks.requiredPlaceholders": "All required placeholders are used",
|
|
82
86
|
"templateResolver.errors.preview.renderFailed": "The preview could not be rendered.",
|
|
87
|
+
"templateResolver.errors.patch.unknownBlock":
|
|
88
|
+
"The block {blockId} does not exist in the template.",
|
|
89
|
+
"templateResolver.errors.patch.blockRemoved":
|
|
90
|
+
"The block {blockId} was already removed by an earlier step.",
|
|
91
|
+
"templateResolver.errors.patch.textNotFound": "The text {find} was not found in the block.",
|
|
92
|
+
"templateResolver.errors.patch.textAmbiguous":
|
|
93
|
+
"The text {find} occurs {count} times in the block; use a longer text.",
|
|
94
|
+
"templateResolver.errors.patch.blockNotAllowed":
|
|
95
|
+
"The block type {type} is not available in {kind} templates.",
|
|
96
|
+
"templateResolver.errors.patch.blockTypeMismatch":
|
|
97
|
+
"This step needs a {expected} block, but the block is a {actual}.",
|
|
98
|
+
"templateResolver.errors.patch.invalidResourceKey": "The image key {resource} is not valid.",
|
|
99
|
+
"templateResolver.errors.patch.invalidButtonHref":
|
|
100
|
+
"A button target must be a placeholder in double curly braces.",
|
|
101
|
+
"templateResolver.errors.patch.invalidVariableName": "The variable name {name} is not valid.",
|
|
102
|
+
"templateResolver.errors.patch.invalidVariableDefinition":
|
|
103
|
+
"The definition of the variable {name} is not valid.",
|
|
104
|
+
"templateResolver.errors.patch.invalidDocument":
|
|
105
|
+
"The change would produce an invalid document.",
|
|
106
|
+
"templateResolver.errors.patch.invalidMetaKey": "The meta key {key} is not allowed.",
|
|
107
|
+
"templateResolver.errors.patch.variablesDeclaredByFeature":
|
|
108
|
+
"The variables of {slug} are fixed by the application and cannot be changed.",
|
|
109
|
+
"templateResolver.errors.patch.requiredPlaceholderRemoved":
|
|
110
|
+
"The change removes required placeholders: {names}",
|
|
83
111
|
"templateResolver.errors.testMail.noChannel":
|
|
84
112
|
"No email channel is set up, so no test mail can be sent.",
|
|
85
113
|
"templateResolver.errors.testMail.noAddress":
|
|
@@ -98,6 +126,8 @@ export const defaultTranslations: TranslationsByLocale = {
|
|
|
98
126
|
"templateResolver.errors.noDraft": "There is no draft to discard.",
|
|
99
127
|
"templateResolver.errors.systemOnlyTemplate":
|
|
100
128
|
"Only the platform maintains this template; it cannot be overridden per tenant.",
|
|
129
|
+
"templateResolver.errors.templateNotTenantEditable":
|
|
130
|
+
"Only the platform may edit this template.",
|
|
101
131
|
"templateResolver.errors.template.invalidMeta": "The template settings are invalid.",
|
|
102
132
|
"templateResolver.errors.template.meta.subject.required": "The subject is missing.",
|
|
103
133
|
"templateResolver.errors.template.meta.subject.invalid":
|
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
// (subject, preheader). The stored value stays plain text; placeholders show
|
|
5
5
|
// as chips while editing. Lives in the same lazy chunk as the document editor.
|
|
6
6
|
|
|
7
|
-
import { cn } from "@cosmicdrift/kumiko-renderer
|
|
7
|
+
import { cn } from "@cosmicdrift/kumiko-renderer/web";
|
|
8
8
|
import { Extension, Node } from "@tiptap/core";
|
|
9
9
|
import { Placeholder, UndoRedo } from "@tiptap/extensions";
|
|
10
10
|
import { EditorContent, useEditor } from "@tiptap/react";
|
|
11
11
|
import StarterKit from "@tiptap/starter-kit";
|
|
12
12
|
import { type ReactNode, useMemo, useState } from "react";
|
|
13
13
|
import { DocumentVariable } from "../document-schema.ts";
|
|
14
|
+
import { contentToLine, lineToContent, singleLine } from "../placeholder-text.ts";
|
|
14
15
|
import { createVariableView } from "./document-editor-extensions.ts";
|
|
15
16
|
import type { DocumentEditorHandle } from "./document-toolbar-blocks.ts";
|
|
16
17
|
import { createEditorHandle } from "./editor-handle.ts";
|
|
17
|
-
import { contentToLine, lineToContent, singleLine } from "./placeholder-text.ts";
|
|
18
18
|
import { useStableByKey } from "./use-stable-by-key.ts";
|
|
19
19
|
|
|
20
20
|
export type PlaceholderLineEditorProps = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @runtime client
|
|
2
2
|
import { mergeTranslations, type TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
3
|
-
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer
|
|
3
|
+
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
|
|
4
4
|
import {
|
|
5
5
|
MEMBER_ROLES_CELL_COMPONENT,
|
|
6
6
|
MEMBER_STATUS_CELL_COMPONENT,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// projectionList renderer — only this one cell stays TSX.
|
|
6
6
|
|
|
7
7
|
import { type ColumnRendererProps, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
8
|
-
import { StatusBadge, type StatusTone } from "@cosmicdrift/kumiko-renderer
|
|
8
|
+
import { StatusBadge, type StatusTone } from "@cosmicdrift/kumiko-renderer/web";
|
|
9
9
|
import type { ReactNode } from "react";
|
|
10
10
|
import { translateOrRaw } from "../../shared/web/translate-or-raw.ts";
|
|
11
11
|
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
type TranslationsByLocale,
|
|
9
9
|
translationsByLocaleFromKeys,
|
|
10
10
|
} from "@cosmicdrift/kumiko-renderer";
|
|
11
|
-
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer
|
|
11
|
+
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
|
|
12
12
|
import { TIER_ENGINE_FEATURE } from "../constants.ts";
|
|
13
13
|
import { TIER_ENGINE_I18N } from "../i18n.ts";
|
|
14
14
|
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.376.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "DELETION_TOKEN_SECRET is part of the env schema",
|
|
6
|
+
"detail": "The feature declares DELETION_TOKEN_SECRET through its env schema, so the dry run and the pulumi inventory list it. Unset, it is derived from JWT_SECRET as before."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.372.0",
|
|
4
10
|
"type": "fix",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
|
|
3
|
+
const MIN_DELETION_TOKEN_SECRET_LENGTH = 32;
|
|
4
|
+
|
|
5
|
+
/** Optional dedicated HMAC key of the anonymous deletion-confirmation links. */
|
|
6
|
+
export const deletionTokenSecretEnvSchema = z.object({
|
|
7
|
+
DELETION_TOKEN_SECRET: z
|
|
8
|
+
.string()
|
|
9
|
+
.min(MIN_DELETION_TOKEN_SECRET_LENGTH)
|
|
10
|
+
.optional()
|
|
11
|
+
.describe(
|
|
12
|
+
"Dedicated HMAC secret for the anonymous deletion-confirmation links. Unset: derived from JWT_SECRET.",
|
|
13
|
+
)
|
|
14
|
+
.meta({ kumiko: { pulumi: { generator: "openssl rand -hex 24", secret: true } } }),
|
|
15
|
+
});
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
USER_ME_QUERY,
|
|
26
26
|
UserDataRightsHandlers,
|
|
27
27
|
} from "./constants.ts";
|
|
28
|
+
import { deletionTokenSecretEnvSchema } from "./env.ts";
|
|
28
29
|
import { cancelDeletionWrite } from "./handlers/cancel-deletion.write.ts";
|
|
29
30
|
import { createConfirmDeletionByTokenHandler } from "./handlers/confirm-deletion-by-token.write.ts";
|
|
30
31
|
import { downloadAttemptListQuery } from "./handlers/download-attempt-list.query.ts";
|
|
@@ -198,6 +199,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
198
199
|
recommended: false,
|
|
199
200
|
});
|
|
200
201
|
r.requires({ features: ["user", "data-retention", "compliance-profiles", "sessions"] });
|
|
202
|
+
r.envSchema(deletionTokenSecretEnvSchema);
|
|
201
203
|
r.usesApi("compliance.forTenant");
|
|
202
204
|
r.usesApi("retention.policyFor");
|
|
203
205
|
// S2.U6 — restrict-account ruft sessions.revokeAllForUser cross-feature.
|
|
@@ -615,7 +617,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
615
617
|
// SYSTEM_USER_ID ist die framework-weite Konvention. Der job-
|
|
616
618
|
// Discriminator wird via handlerName="user-data-rights:run-export-
|
|
617
619
|
// jobs" im Secret-Read-Audit erfasst.
|
|
618
|
-
const exportUserId =
|
|
620
|
+
const exportUserId = SYSTEM_USER_ID;
|
|
619
621
|
const exportDb =
|
|
620
622
|
ctx.db.unsafeRaw() as import("@cosmicdrift/kumiko-framework/db").DbConnection; // @cast-boundary db-operator — jobs never run inside a DbTx
|
|
621
623
|
const exportRegistry = ctx.registry;
|
|
@@ -708,7 +710,7 @@ export function createUserDataRightsFeature(opts: UserDataRightsOptions = {}): F
|
|
|
708
710
|
throw new Error("run-forget-cleanup: ctx.registry required (JobContext incomplete)");
|
|
709
711
|
}
|
|
710
712
|
const T = (await import("@cosmicdrift/kumiko-framework/time")).getTemporal();
|
|
711
|
-
const forgetUserId =
|
|
713
|
+
const forgetUserId = SYSTEM_USER_ID;
|
|
712
714
|
const forgetDb =
|
|
713
715
|
ctx.db.unsafeRaw() as import("@cosmicdrift/kumiko-framework/db").DbConnection; // @cast-boundary db-operator — jobs never run inside a DbTx
|
|
714
716
|
const forgetRegistry = ctx.registry;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { TENANT_MODEL_CONFIG_KEY } from "./constants.ts";
|
|
2
|
+
export { deletionTokenSecretEnvSchema } from "./env.ts";
|
|
2
3
|
export { createUserDataRightsFeature, type UserDataRightsOptions } from "./feature.ts";
|
|
3
4
|
export type { SendDeletionVerificationEmailFn } from "./handlers/request-deletion-by-email.write.ts";
|
|
4
5
|
export {
|
|
@@ -42,7 +42,7 @@ export function makeTenantMailTransportResolver(
|
|
|
42
42
|
ctx.db,
|
|
43
43
|
);
|
|
44
44
|
return createTransportForTenant(
|
|
45
|
-
{ config, registry: ctx.registry, secrets: ctx.secrets,
|
|
45
|
+
{ config, registry: ctx.registry, secrets: ctx.secrets, auditUserId: ctx.userId },
|
|
46
46
|
tenantId,
|
|
47
47
|
ctx.handlerName,
|
|
48
48
|
);
|
|
@@ -41,7 +41,7 @@ export function makeTenantStorageProviderResolver(
|
|
|
41
41
|
ctx.db,
|
|
42
42
|
);
|
|
43
43
|
return createFileProviderForTenant(
|
|
44
|
-
{ config, registry: ctx.registry, secrets: ctx.secrets,
|
|
44
|
+
{ config, registry: ctx.registry, secrets: ctx.secrets, auditUserId: ctx.userId },
|
|
45
45
|
tenantId,
|
|
46
46
|
ctx.handlerName,
|
|
47
47
|
);
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
mailT,
|
|
13
13
|
resolveMailLocale,
|
|
14
14
|
} from "@cosmicdrift/kumiko-framework/i18n";
|
|
15
|
-
import { escapeHtml } from "@cosmicdrift/kumiko-headless";
|
|
15
|
+
import { escapeHtml } from "@cosmicdrift/kumiko-renderer/headless";
|
|
16
16
|
import { mailParagraph } from "../shared/index.ts";
|
|
17
17
|
import { USER_DATA_RIGHTS_FEATURE } from "./constants.ts";
|
|
18
18
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// money-horse) must carry the option over at feature setup.
|
|
17
17
|
|
|
18
18
|
import { mergeTranslations, type TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
19
|
-
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer
|
|
19
|
+
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
|
|
20
20
|
import { EXPORT_SECTION_EXTENSION_NAME, USER_DATA_RIGHTS_FEATURE } from "../constants.ts";
|
|
21
21
|
import { defaultTranslations } from "./i18n.ts";
|
|
22
22
|
import { ExportSection } from "./privacy-center-screen.tsx";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-headless";
|
|
1
|
+
import { EMPTY_VALUE_PLACEHOLDER } from "@cosmicdrift/kumiko-renderer/headless";
|
|
2
2
|
// @runtime client
|
|
3
3
|
// Export section (Art. 20) — the one part of user-data-rights' privacy-center
|
|
4
4
|
// screen that stays custom (fw#2312). Registered as an EditExtensionSection
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
useQuery,
|
|
18
18
|
useTranslation,
|
|
19
19
|
} from "@cosmicdrift/kumiko-renderer";
|
|
20
|
-
import { postWithDownload } from "@cosmicdrift/kumiko-renderer
|
|
20
|
+
import { postWithDownload } from "@cosmicdrift/kumiko-renderer/web";
|
|
21
21
|
import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
22
22
|
import { type ReactNode, useEffect, useState } from "react";
|
|
23
23
|
import {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.377.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "migrateLegacyWaitlist no longer replays legacy events on rebuild",
|
|
6
|
+
"detail": "The legacy event stream of each migrated row is archived, so a projection rebuild does not resurrect the old id next to the imported entry. The report gains archivedStreams."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.370.0",
|
|
4
10
|
"type": "breaking",
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
PII_ERASED_SENTINEL,
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/crypto";
|
|
7
7
|
import {
|
|
8
|
+
countWhere,
|
|
8
9
|
createTenantDb,
|
|
9
10
|
selectMany,
|
|
10
11
|
table,
|
|
@@ -14,10 +15,16 @@ import {
|
|
|
14
15
|
uuid,
|
|
15
16
|
} from "@cosmicdrift/kumiko-framework/db";
|
|
16
17
|
import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
18
|
+
import {
|
|
19
|
+
archiveStream,
|
|
20
|
+
createArchivedStreamsTable,
|
|
21
|
+
eventsTable,
|
|
22
|
+
isStreamArchived,
|
|
23
|
+
} from "@cosmicdrift/kumiko-framework/event-store";
|
|
17
24
|
import type { DbConnection } from "@cosmicdrift/kumiko-types/db-connection";
|
|
18
25
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
19
26
|
import { WAITLIST_STATUS, type WaitlistStatus } from "./constants.ts";
|
|
20
|
-
import { importWaitlistEntry, type WaitlistImportEntry } from "./import.ts";
|
|
27
|
+
import { importWaitlistEntry, type WaitlistImportEntry, waitlistImportId } from "./import.ts";
|
|
21
28
|
|
|
22
29
|
export const LEGACY_WAITLIST_SOURCES = ["offlot", "publicstatus"] as const;
|
|
23
30
|
export type LegacyWaitlistSource = (typeof LEGACY_WAITLIST_SOURCES)[number];
|
|
@@ -46,8 +53,13 @@ export type LegacyWaitlistMigrateReport = {
|
|
|
46
53
|
readonly created: number;
|
|
47
54
|
readonly skipped: number;
|
|
48
55
|
readonly unreadable: number;
|
|
56
|
+
/** Event streams of the legacy rows (same aggregate type) taken out of projection replay. */
|
|
57
|
+
readonly archivedStreams: number;
|
|
49
58
|
};
|
|
50
59
|
|
|
60
|
+
const LEGACY_AGGREGATE_TYPE = "waitlistEntry";
|
|
61
|
+
const LEGACY_STREAM_ARCHIVE_REASON = "migrated to a new waitlist entry id by waitlist-migrate";
|
|
62
|
+
|
|
51
63
|
type LegacyRow = Readonly<Record<string, unknown>>;
|
|
52
64
|
|
|
53
65
|
function toInstant(value: unknown): Temporal.Instant | undefined {
|
|
@@ -189,6 +201,34 @@ async function readLegacyRows(
|
|
|
189
201
|
});
|
|
190
202
|
}
|
|
191
203
|
|
|
204
|
+
// A legacy offlot row is the projection of an event stream of the same aggregate type under the
|
|
205
|
+
// old row id, written in the system tenant like every waitlist entry. The imported entry gets a
|
|
206
|
+
// new id, so a rebuild would replay the old stream next to it and bring every migrated entry back
|
|
207
|
+
// twice; archived streams are excluded from replay. The offlot default source table is the entity
|
|
208
|
+
// table itself, so its row ids are live entries by design and no id check can tell a wrong table.
|
|
209
|
+
async function archiveLegacyStream(
|
|
210
|
+
db: DbConnection,
|
|
211
|
+
legacyId: string,
|
|
212
|
+
importedId: string,
|
|
213
|
+
): Promise<number> {
|
|
214
|
+
if (legacyId === importedId) return 0;
|
|
215
|
+
if (await isStreamArchived(db, SYSTEM_TENANT_ID, legacyId)) return 0;
|
|
216
|
+
const legacyEvents = await countWhere(db, eventsTable, {
|
|
217
|
+
tenantId: SYSTEM_TENANT_ID,
|
|
218
|
+
aggregateId: legacyId,
|
|
219
|
+
aggregateType: LEGACY_AGGREGATE_TYPE,
|
|
220
|
+
});
|
|
221
|
+
if (legacyEvents === 0) return 0;
|
|
222
|
+
await archiveStream(db, {
|
|
223
|
+
tenantId: SYSTEM_TENANT_ID,
|
|
224
|
+
aggregateId: legacyId,
|
|
225
|
+
aggregateType: LEGACY_AGGREGATE_TYPE,
|
|
226
|
+
archivedBy: "waitlist-migrate",
|
|
227
|
+
reason: LEGACY_STREAM_ARCHIVE_REASON,
|
|
228
|
+
});
|
|
229
|
+
return 1;
|
|
230
|
+
}
|
|
231
|
+
|
|
192
232
|
// Idempotent: the new entry id derives from the source row id, so a re-run finds
|
|
193
233
|
// what an earlier run wrote and skips it. Writes go through the waitlist entity
|
|
194
234
|
// executor (events, projection, subject encryption), never into tables directly.
|
|
@@ -200,6 +240,8 @@ export async function migrateLegacyWaitlist(
|
|
|
200
240
|
let created = 0;
|
|
201
241
|
let skipped = 0;
|
|
202
242
|
let unreadable = 0;
|
|
243
|
+
let archivedStreams = 0;
|
|
244
|
+
if (!options.dryRun && options.from === "offlot") await createArchivedStreamsTable(db);
|
|
203
245
|
for (const row of rows) {
|
|
204
246
|
const entry =
|
|
205
247
|
options.from === "offlot"
|
|
@@ -215,6 +257,13 @@ export async function migrateLegacyWaitlist(
|
|
|
215
257
|
if (outcome === "created") created += 1;
|
|
216
258
|
else skipped += 1;
|
|
217
259
|
});
|
|
260
|
+
if (!options.dryRun && options.from === "offlot") {
|
|
261
|
+
archivedStreams += await archiveLegacyStream(
|
|
262
|
+
db,
|
|
263
|
+
String(row["id"]),
|
|
264
|
+
waitlistImportId(entry.sourceKey),
|
|
265
|
+
);
|
|
266
|
+
}
|
|
218
267
|
}
|
|
219
|
-
return { read: rows.length, created, skipped, unreadable };
|
|
268
|
+
return { read: rows.length, created, skipped, unreadable, archivedStreams };
|
|
220
269
|
}
|
|
@@ -9,11 +9,8 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@cosmicdrift/kumiko-bundled-features": "workspace:*",
|
|
11
11
|
"@cosmicdrift/kumiko-dev-server": "workspace:*",
|
|
12
|
-
"@cosmicdrift/kumiko-dispatcher-live": "workspace:*",
|
|
13
12
|
"@cosmicdrift/kumiko-framework": "workspace:*",
|
|
14
|
-
"@cosmicdrift/kumiko-headless": "workspace:*",
|
|
15
13
|
"@cosmicdrift/kumiko-renderer": "workspace:*",
|
|
16
|
-
"@cosmicdrift/kumiko-renderer-web": "workspace:*",
|
|
17
14
|
"lucide-react": "^1.14.0",
|
|
18
15
|
"react": "^19.2.6",
|
|
19
16
|
"react-dom": "^19.2.6",
|
|
@@ -5,7 +5,7 @@ import { jobsClient } from "@cosmicdrift/kumiko-bundled-features/jobs/web";
|
|
|
5
5
|
import { tenantClient } from "@cosmicdrift/kumiko-bundled-features/tenant/web";
|
|
6
6
|
import { tierEngineClient } from "@cosmicdrift/kumiko-bundled-features/tier-engine/web";
|
|
7
7
|
import { localeDeClient } from "@cosmicdrift/kumiko-locale-de/web";
|
|
8
|
-
import { createKumikoApp } from "@cosmicdrift/kumiko-renderer
|
|
8
|
+
import { createKumikoApp } from "@cosmicdrift/kumiko-renderer/web";
|
|
9
9
|
import { HomeScreen } from "./home-screen";
|
|
10
10
|
import { AppShell } from "./shell";
|
|
11
11
|
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
DefaultTopbarActions,
|
|
3
3
|
useShellUser,
|
|
4
4
|
} from "@cosmicdrift/kumiko-bundled-features/auth-email-password/web";
|
|
5
|
-
import { type AppSchema, WorkspaceShell } from "@cosmicdrift/kumiko-renderer
|
|
5
|
+
import { type AppSchema, WorkspaceShell } from "@cosmicdrift/kumiko-renderer/web";
|
|
6
6
|
import { MoonStar, Sun } from "lucide-react";
|
|
7
7
|
import type { ReactNode } from "react";
|
|
8
8
|
|
|
@@ -11,10 +11,8 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@cosmicdrift/kumiko-bundled-features": "workspace:*",
|
|
13
13
|
"@cosmicdrift/kumiko-dev-server": "workspace:*",
|
|
14
|
-
"@cosmicdrift/kumiko-
|
|
14
|
+
"@cosmicdrift/kumiko-renderer": "workspace:*",
|
|
15
15
|
"@cosmicdrift/kumiko-framework": "workspace:*",
|
|
16
|
-
"@cosmicdrift/kumiko-headless": "workspace:*",
|
|
17
|
-
"@cosmicdrift/kumiko-renderer-web": "workspace:*",
|
|
18
16
|
"react": "^19.2.6",
|
|
19
17
|
"react-dom": "^19.2.6",
|
|
20
18
|
"@cosmicdrift/kumiko-locale-de": "workspace:*"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { configClient } from "@cosmicdrift/kumiko-bundled-features/config/web";
|
|
2
2
|
import { localeDeClient } from "@cosmicdrift/kumiko-locale-de/web";
|
|
3
|
-
import { createKumikoApp } from "@cosmicdrift/kumiko-renderer
|
|
3
|
+
import { createKumikoApp } from "@cosmicdrift/kumiko-renderer/web";
|
|
4
4
|
import { configDemoClient } from "../features/demo/web";
|
|
5
5
|
import { AppShell } from "./shell";
|
|
6
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AppSchema } from "@cosmicdrift/kumiko-renderer
|
|
2
|
-
import { DefaultAppShell } from "@cosmicdrift/kumiko-renderer
|
|
1
|
+
import type { AppSchema } from "@cosmicdrift/kumiko-renderer/web";
|
|
2
|
+
import { DefaultAppShell } from "@cosmicdrift/kumiko-renderer/web";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
|
|
5
5
|
// Logo-Kachel + Wortmarke — wie SidebarBrand (sidebar-brand.tsx). Die
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer
|
|
1
|
+
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
|
|
2
2
|
import { configDemoTranslations } from "../i18n";
|
|
3
3
|
|
|
4
4
|
export const configDemoClient: ClientFeatureDefinition = {
|
|
@@ -14,18 +14,6 @@
|
|
|
14
14
|
"@cosmicdrift/kumiko-dev-server/*": [
|
|
15
15
|
"../../../packages/dev-server/src/*"
|
|
16
16
|
],
|
|
17
|
-
"@cosmicdrift/kumiko-renderer-web": [
|
|
18
|
-
"../../../packages/renderer-web/src/index.ts"
|
|
19
|
-
],
|
|
20
|
-
"@cosmicdrift/kumiko-renderer-web/*": [
|
|
21
|
-
"../../../packages/renderer-web/src/*"
|
|
22
|
-
],
|
|
23
|
-
"@cosmicdrift/kumiko-dispatcher-live": [
|
|
24
|
-
"../../../packages/dispatcher-live/src/index.ts"
|
|
25
|
-
],
|
|
26
|
-
"@cosmicdrift/kumiko-headless": [
|
|
27
|
-
"../../../packages/headless/src/index.ts"
|
|
28
|
-
],
|
|
29
17
|
"@cosmicdrift/kumiko-renderer": [
|
|
30
18
|
"../../../packages/renderer/src/index.ts"
|
|
31
19
|
],
|