@cosmicdrift/kumiko-samples 0.391.1 → 0.392.1
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 +1 -1
- package/packages/bundled-features/src/admin-shell/changes.json +6 -0
- package/packages/bundled-features/src/admin-shell/feature.ts +60 -31
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +2 -2
- package/packages/bundled-features/src/cap-overview/changes.json +18 -0
- package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -0
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +3 -2
- package/packages/bundled-features/src/cap-overview/i18n.ts +4 -0
- package/packages/bundled-features/src/cap-overview/types.ts +4 -1
- package/packages/bundled-features/src/cap-overview/web/cap-amount-format.ts +37 -0
- package/packages/bundled-features/src/cap-overview/web/cap-cards-panel.tsx +137 -54
- package/packages/bundled-features/src/cap-overview/web/cap-usage-bar.tsx +18 -4
- package/packages/bundled-features/src/cap-overview/web/cap-usage-cell.tsx +6 -3
- package/packages/bundled-features/src/cap-overview/web/usage-math.ts +5 -1
- package/packages/bundled-features/src/channel-email/app-transport.ts +37 -0
- package/packages/bundled-features/src/channel-email/changes.json +6 -0
- package/packages/bundled-features/src/channel-email/feature.ts +6 -0
- package/packages/bundled-features/src/channel-email/index.ts +5 -0
- package/packages/bundled-features/src/channel-email/smtp-transport.ts +2 -22
- package/packages/bundled-features/src/foundation-shared/changes.json +6 -0
- package/packages/bundled-features/src/foundation-shared/index.ts +1 -0
- package/packages/bundled-features/src/foundation-shared/mail-display-name.ts +20 -0
- package/packages/bundled-features/src/inbound-mail-foundation/account-record.ts +48 -0
- package/packages/bundled-features/src/inbound-mail-foundation/changes.json +18 -0
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +17 -0
- package/packages/bundled-features/src/inbound-mail-foundation/index.ts +18 -0
- package/packages/bundled-features/src/inbound-mail-foundation/outbound-mail.ts +66 -0
- package/packages/bundled-features/src/inbound-mail-foundation/probe.ts +8 -45
- package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +14 -0
- package/packages/bundled-features/src/inbound-mail-foundation/send-from-account.ts +118 -0
- package/packages/bundled-features/src/inbound-mail-foundation/types.ts +8 -0
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +13 -8
- package/packages/bundled-features/src/inbound-provider-imap/changes.json +18 -0
- package/packages/bundled-features/src/inbound-provider-imap/connect-mailbox.ts +158 -0
- package/packages/bundled-features/src/inbound-provider-imap/constants.ts +44 -0
- package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +47 -1
- package/packages/bundled-features/src/inbound-provider-imap/feature.ts +12 -35
- package/packages/bundled-features/src/inbound-provider-imap/i18n.ts +49 -0
- package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +1 -1
- package/packages/bundled-features/src/inbound-provider-imap/screens.ts +52 -0
- package/packages/bundled-features/src/inbound-provider-imap/send-mail.ts +73 -0
- package/packages/bundled-features/src/inbound-provider-imap/sent-folder.ts +49 -0
- package/packages/bundled-features/src/inbound-provider-imap/smtp-client.ts +135 -0
- package/packages/bundled-features/src/legal-pages/README.md +5 -10
- package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
- package/packages/bundled-features/src/mail-foundation/i18n.ts +9 -1
- package/packages/bundled-features/src/mail-foundation/probe.ts +43 -22
- package/packages/bundled-features/src/readiness/built-in-probes.ts +15 -2
- package/packages/bundled-features/src/readiness/changes.json +30 -0
- package/packages/bundled-features/src/readiness/constants.ts +2 -0
- package/packages/bundled-features/src/readiness/i18n.ts +7 -1
- package/packages/bundled-features/src/readiness/index.ts +6 -1
- package/packages/bundled-features/src/readiness/screens.ts +25 -2
- package/packages/bundled-features/src/readiness/visible-results.ts +2 -1
- package/packages/bundled-features/src/renderer-foundation/README.md +19 -21
- package/packages/bundled-features/src/template-resolver/README.md +144 -165
- package/packages/bundled-features/src/tier-engine/changes.json +6 -0
- package/packages/bundled-features/src/tier-engine/feature.ts +17 -6
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +3 -3
- package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +5 -3
- package/packages/bundled-features/src/user-data-rights/token-helpers.ts +5 -4
- package/samples/apps/cap-billing-demo/bin/server.ts +7 -7
- package/samples/apps/cap-billing-demo/src/feature.ts +38 -38
- package/samples/apps/cap-billing-demo/src/run-config.ts +20 -20
- package/samples/apps/cap-billing-demo/src/tier-map.ts +14 -14
- package/samples/apps/config-demo/src/app/server.ts +4 -4
- package/samples/apps/config-demo/src/features/demo/feature.ts +4 -4
- package/samples/apps/marketing-demo/playwright.config.ts +3 -3
- package/samples/apps/marketing-demo/src/app/client.tsx +2 -2
- package/samples/apps/marketing-demo/src/app/seed-data.ts +9 -9
- package/samples/apps/marketing-demo/src/app/seed.ts +14 -14
- package/samples/apps/marketing-demo/src/app/server.ts +7 -7
- package/samples/apps/marketing-demo/src/app/shell.tsx +3 -3
- package/samples/apps/marketing-demo/src/features/assets/feature.ts +3 -3
- package/samples/apps/marketing-demo/src/features/assets/i18n.ts +7 -7
- package/samples/apps/marketing-demo/src/features/assets/web/index.ts +2 -2
- package/samples/apps/showcase/src/app/client.tsx +3 -3
- package/samples/apps/showcase/src/app/seed-items.ts +14 -14
- package/samples/apps/showcase/src/app/server.ts +7 -7
- package/samples/apps/showcase/src/features/demos/feature.ts +13 -13
- package/samples/apps/showcase/src/features/demos/i18n.ts +2 -2
- package/samples/apps/showcase/src/features/demos/web/components/page.tsx +5 -5
- package/samples/apps/showcase/src/features/demos/web/index.ts +4 -4
- package/samples/apps/showcase/src/features/demos/web/pages/dialog.tsx +1 -1
- package/samples/apps/showcase/src/features/demos/web/pages/inputs.tsx +8 -8
- package/samples/apps/showcase/src/features/demos/web/pages/layout.tsx +5 -5
- package/samples/apps/showcase/src/features/demos/web/pages/toast.tsx +3 -3
- package/samples/apps/showcase/src/features/items/feature.ts +8 -8
- package/samples/apps/showcase/src/features/items/i18n.ts +3 -3
- package/samples/apps/showcase/src/features/items/index.ts +3 -3
- package/samples/apps/showcase/src/features/items/schema/index.ts +4 -4
- package/samples/apps/showcase/src/features/items/schema/item.ts +27 -27
- package/samples/apps/showcase/src/features/items/web/index.ts +6 -6
- package/samples/apps/styleguide/src/app/seed.ts +3 -3
- package/samples/apps/styleguide/src/app/server.ts +2 -2
- package/samples/apps/styleguide/src/app/shell.tsx +4 -4
- package/samples/apps/styleguide/src/features/content/web.tsx +6 -6
- package/samples/apps/styleguide/src/features/examples/feature.ts +8 -8
- package/samples/apps/styleguide/src/features/gallery/feature.ts +9 -9
- package/samples/apps/styleguide/src/features/gallery/web/Gallery.tsx +12 -12
- package/samples/apps/styleguide/src/features/widgets/feature.ts +2 -2
- package/samples/apps/styleguide/src/features/widgets/web/DashboardFilterEcho.tsx +3 -3
- package/samples/apps/styleguide/src/features/widgets/web/DashboardKpiIcon.tsx +4 -4
- package/samples/apps/ui-walkthrough/playwright.config.ts +6 -6
- package/samples/apps/ui-walkthrough/scripts/emit-e2e-data.ts +5 -5
- package/samples/apps/ui-walkthrough/src/app/auth-constants.ts +13 -13
- package/samples/apps/ui-walkthrough/src/app/client.tsx +2 -2
- package/samples/apps/ui-walkthrough/src/app/server.ts +14 -14
- package/samples/apps/ui-walkthrough/src/app/shell.tsx +3 -3
- package/samples/apps/use-all-bundled/bin/main.ts +5 -5
- package/samples/apps/use-all-bundled/feature-manifest.json +10 -4
- package/samples/apps/use-all-bundled/kumiko/schema.ts +7 -7
- package/samples/apps/use-all-bundled/scripts/check-coverage.ts +20 -20
- package/samples/apps/use-all-bundled/src/app/auth-constants.ts +4 -4
- package/samples/apps/use-all-bundled/src/app/client.tsx +4 -4
- package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +12 -12
- package/samples/apps/use-all-bundled/src/app/seed.ts +6 -6
- package/samples/apps/user-data-rights-demo/src/feature.ts +23 -23
- package/samples/apps/workspaces/playwright.config.ts +5 -5
- package/samples/apps/workspaces/src/app/auth-constants.ts +3 -3
- package/samples/apps/workspaces/src/app/server.ts +16 -16
- package/samples/apps/workspaces/src/app/shell.tsx +2 -2
- package/samples/apps/workspaces/src/features/demo/schema/order.ts +4 -4
- package/samples/apps/workspaces/src/features/demo-driver/feature.ts +5 -5
- package/samples/recipes/apex-surface-auth/src/feature.ts +31 -31
- package/samples/recipes/designer-demo/src/feature.ts +6 -6
- package/samples/recipes/encrypted-tenant-config/src/feature.ts +20 -20
- package/samples/recipes/lane-routing/src/feature.ts +5 -5
- package/samples/recipes/legal-pages/src/feature.ts +29 -29
- package/samples/recipes/record-detail-layout/src/feature.ts +21 -2
- package/samples/recipes/seed-migration/scripts/smoke.ts +20 -20
- package/samples/recipes/seed-migration/seeds/2026-01-01-initial-tenants.ts +11 -11
- package/samples/recipes/seed-migration/seeds/2026-02-01-fix-admin-roles.ts +13 -13
- package/samples/recipes/user-data-rights/src/feature.ts +13 -13
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
// Demos
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Demos feature — server side. Registers custom screens for the UI
|
|
2
|
+
// demo pages (buttons, inputs, banner, text, layout) and their nav
|
|
3
|
+
// entries. No entity, no handlers — pure custom-screen showcase.
|
|
4
4
|
//
|
|
5
|
-
// FeatureName "showcase-demos" (
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
5
|
+
// FeatureName "showcase-demos" (not "showcase"): two defineFeature
|
|
6
|
+
// calls with the same name would throw `Duplicate feature` in
|
|
7
|
+
// createRegistry. The hyphen separating it from the items feature is
|
|
8
|
+
// therefore not a matter of convention taste but a technical necessity.
|
|
9
9
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
10
|
+
// The React components for the custom screens live in pages/ and
|
|
11
|
+
// are assigned client-side via clientFeatures.components (see
|
|
12
12
|
// client.ts).
|
|
13
13
|
|
|
14
14
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
@@ -95,11 +95,11 @@ export const demosFeature = defineFeature("showcase-demos", (r) => {
|
|
|
95
95
|
"Shows the SidebarPanel shell slot as a mail-client inbox: a resizable message list beside the navigation over the full window height, with the selected message read in the content area.",
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
// Section "Primitives" —
|
|
98
|
+
// Section "Primitives" — click-to-collapse because the parent has no screen.
|
|
99
99
|
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
100
|
+
// Every entry carries an icon: at icon width it is the only thing that
|
|
101
|
+
// remains of it. Without an icon only a dot shows there, and a rail
|
|
102
|
+
// of identical dots does not say where to click.
|
|
103
103
|
r.nav({ id: "primitives", label: "showcase-demos:nav.primitives", icon: "layers", order: 10 });
|
|
104
104
|
r.nav({
|
|
105
105
|
id: "demo-layout",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Demos
|
|
2
|
-
//
|
|
1
|
+
// Demos feature i18n bundle. Only the screen titles for the
|
|
2
|
+
// top action bars of the demo pages.
|
|
3
3
|
|
|
4
4
|
import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
5
5
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Shared
|
|
2
|
-
//
|
|
3
|
-
// (h-12, bg-muted/30, border-b)
|
|
1
|
+
// Shared page layout for the demo custom screens. Not a framework
|
|
2
|
+
// concept — pure sample layout that keeps the top action bar convention
|
|
3
|
+
// (h-12, bg-muted/30, border-b) consistent with form/list.
|
|
4
4
|
|
|
5
5
|
import { usePrimitives } from "@cosmicdrift/kumiko-renderer";
|
|
6
6
|
import type { ReactNode } from "react";
|
|
@@ -32,8 +32,8 @@ export function DemoPage({
|
|
|
32
32
|
);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
// Section
|
|
36
|
-
//
|
|
35
|
+
// Section within a demo page: Card primitive (standard chrome). Samples
|
|
36
|
+
// are a copy template for agents → the same card as everywhere, no special layout.
|
|
37
37
|
export function DemoSection({
|
|
38
38
|
title,
|
|
39
39
|
children,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// Demos
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// Demos feature — web platform plugin. ClientFeatureDefinition with
|
|
2
|
+
// the React DOM components for the custom screens. createKumikoApp
|
|
3
|
+
// merges that into the CustomScreens context, KumikoScreen looks there
|
|
4
|
+
// when a schema screen has `type: "custom"`.
|
|
5
5
|
|
|
6
6
|
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
|
|
7
7
|
import { demosTranslations } from "../i18n";
|
|
@@ -62,7 +62,7 @@ export function DialogDemo(): ReactNode {
|
|
|
62
62
|
</DemoSection>
|
|
63
63
|
|
|
64
64
|
<DemoSection title="Lightbox">
|
|
65
|
-
{/* kumiko-lint-ignore primitives-discipline clickable image thumbnail (
|
|
65
|
+
{/* kumiko-lint-ignore primitives-discipline clickable image thumbnail (lightbox trigger) — not a text button, <Button> cannot wrap a full-bleed <img> */}
|
|
66
66
|
<button
|
|
67
67
|
type="button"
|
|
68
68
|
onClick={() => setLightboxOpen(true)}
|
|
@@ -2,9 +2,9 @@ import { usePrimitives } from "@cosmicdrift/kumiko-renderer";
|
|
|
2
2
|
import { type ReactNode, useMemo, useState } from "react";
|
|
3
3
|
import { DemoPage, DemoSection } from "../components/page";
|
|
4
4
|
|
|
5
|
-
// Combobox
|
|
6
|
-
//
|
|
7
|
-
//
|
|
5
|
+
// Combobox demo data: 3 items with different initial letters.
|
|
6
|
+
// If the user types "A", only "API" must remain — regression
|
|
7
|
+
// surface for the bug "search filters everything away".
|
|
8
8
|
const COMBOBOX_OPTIONS = [
|
|
9
9
|
{ value: "api", label: "API" },
|
|
10
10
|
{ value: "backend", label: "Backend" },
|
|
@@ -27,11 +27,11 @@ export function InputsDemo(): ReactNode {
|
|
|
27
27
|
const [comboMultiLocal, setComboMultiLocal] = useState<readonly string[]>([]);
|
|
28
28
|
const [comboSingleRemote, setComboSingleRemote] = useState("");
|
|
29
29
|
const [comboMultiRemote, setComboMultiRemote] = useState<readonly string[]>([]);
|
|
30
|
-
// Remote-
|
|
31
|
-
// onSearchChange
|
|
32
|
-
// "shouldFilter=false"
|
|
33
|
-
//
|
|
34
|
-
//
|
|
30
|
+
// Remote-mode simulation: the caller receives the search term via
|
|
31
|
+
// onSearchChange and filters the options itself — Combobox gets
|
|
32
|
+
// "shouldFilter=false" mode (cmdk does not filter client-side, the caller
|
|
33
|
+
// is authoritative for visibility). A production setup would send the
|
|
34
|
+
// search term to the server, here we filter in memory.
|
|
35
35
|
const [remoteQ, setRemoteQ] = useState("");
|
|
36
36
|
const remoteOptions = useMemo(() => {
|
|
37
37
|
if (remoteQ === "") return COMBOBOX_OPTIONS;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// Layout
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Layout demo: slot visualization. One mini diagram per primitive
|
|
2
|
+
// of the boxes + slot names inside, plus a code snippet below that
|
|
3
|
+
// shows how the slot is addressed from the caller.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
5
|
+
// The sketches are deliberately sample code with raw <div> + Tailwind —
|
|
6
|
+
// the point here is a picture, not showing the primitives themselves.
|
|
7
7
|
|
|
8
8
|
import type { ReactNode } from "react";
|
|
9
9
|
import { DemoPage, DemoSection } from "../components/page";
|
|
@@ -3,9 +3,9 @@ import { useToast } from "@cosmicdrift/kumiko-renderer/web";
|
|
|
3
3
|
import { type ReactNode, useState } from "react";
|
|
4
4
|
import { DemoPage, DemoSection } from "../components/page";
|
|
5
5
|
|
|
6
|
-
// Toast
|
|
7
|
-
//
|
|
8
|
-
// toasts
|
|
6
|
+
// Toast demo. useToast() is the only public API — the ToastProvider
|
|
7
|
+
// is mounted in createKumikoApp, every component inside may
|
|
8
|
+
// push toasts without caring about state/mounting.
|
|
9
9
|
|
|
10
10
|
export function ToastDemo(): ReactNode {
|
|
11
11
|
const { toast } = useToast();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// Items
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// Items feature — server side. defineFeature() registers the entity,
|
|
2
|
+
// the standard CRUD handlers and the schema items from schema.ts. NO
|
|
3
|
+
// custom server code (no hooks/projections); the feature is
|
|
4
|
+
// deliberately minimal and shows the "kitchen-sink entity" path without
|
|
5
|
+
// domain logic.
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
7
|
+
// Schema definitions used on both sides live in schema.ts. The server
|
|
8
|
+
// attaches the handlers here and calls r.screen/r.nav.
|
|
9
9
|
|
|
10
10
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
11
11
|
import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
@@ -65,7 +65,7 @@ export const itemsFeature = defineFeature("showcase", (r) => {
|
|
|
65
65
|
r.screen(itemActiveScreen);
|
|
66
66
|
r.screen(itemQuickAddScreen);
|
|
67
67
|
|
|
68
|
-
// Section "Data" —
|
|
68
|
+
// Section "Data" — click to expand/collapse because the parent has no screen.
|
|
69
69
|
r.nav({ id: "data", label: "showcase:nav.data", icon: "table", order: 100 });
|
|
70
70
|
r.nav({
|
|
71
71
|
id: "item-list",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Items
|
|
2
|
-
// `showcase:` + `entity:item:field:<name>`
|
|
3
|
-
//
|
|
1
|
+
// Items feature i18n bundle. Convention: feature prefix per
|
|
2
|
+
// `showcase:` + `entity:item:field:<name>` for field labels. Plus
|
|
3
|
+
// the two nav labels referenced in feature.ts.
|
|
4
4
|
|
|
5
5
|
import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Public
|
|
2
|
-
//
|
|
3
|
-
// re-exported —
|
|
1
|
+
// Public surface of the items feature. The server imports `itemsFeature`,
|
|
2
|
+
// the web client imports `itemsClient`. schema/ is internal, not
|
|
3
|
+
// re-exported — only feature.ts and web/index.ts may access it.
|
|
4
4
|
|
|
5
5
|
export { itemsFeature } from "./feature";
|
|
6
6
|
export { itemsClient } from "./web";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// Re-exports —
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// Re-exports — one file per entity, the index collects them. That way
|
|
2
|
+
// the feature can later add further entities (e.g. tag.ts, comment.ts)
|
|
3
|
+
// without feature.ts or web/index.ts having to change
|
|
4
|
+
// their imports.
|
|
5
5
|
|
|
6
6
|
export {
|
|
7
7
|
itemActiveScreen,
|
|
@@ -69,8 +69,8 @@ export const itemEditScreen: EntityEditScreenDefinition = {
|
|
|
69
69
|
title: "References (Tier 2.7e Remote-Combobox-Demo)",
|
|
70
70
|
columns: 1,
|
|
71
71
|
fields: [
|
|
72
|
-
// Single +
|
|
73
|
-
//
|
|
72
|
+
// Single + remote — bug test surface 1: click on a dropdown item
|
|
73
|
+
// must fire onChange (selects the item, closes the popup).
|
|
74
74
|
"parentId",
|
|
75
75
|
// Multi + Remote — Bug-Test-Surface 2: Tippen filtert die Liste
|
|
76
76
|
// serverseitig. Mit ~200 seed-Items echte Search-Last.
|
|
@@ -110,18 +110,18 @@ export const itemListScreen: EntityListScreenDefinition = {
|
|
|
110
110
|
// auf item:list (limit:200), zeigt parentId als parent.title.
|
|
111
111
|
{ field: "parentId", hideOnNarrow: true },
|
|
112
112
|
],
|
|
113
|
-
// Server-side
|
|
114
|
-
//
|
|
113
|
+
// Server-side pagination demo — the showcase seeds ~200 items, the
|
|
114
|
+
// pager has 4 pages to click through at pageSize: 50.
|
|
115
115
|
pagination: "pages",
|
|
116
116
|
pageSize: 50,
|
|
117
117
|
defaultSort: { field: "title", dir: "asc" },
|
|
118
118
|
searchable: true,
|
|
119
|
-
// RowActions
|
|
120
|
-
// delete. Confirm
|
|
121
|
-
// Tier 2.7e-1
|
|
122
|
-
//
|
|
123
|
-
// URL
|
|
124
|
-
// initial value
|
|
119
|
+
// RowActions demo. The default payload is `{ id: row.id }` — enough for
|
|
120
|
+
// delete. Confirm dialog automatically because of style="danger".
|
|
121
|
+
// Tier 2.7e-1 shows the "navigate" kind: a second action button that
|
|
122
|
+
// jumps to an actionForm instead of making a server call + passes row.id as a
|
|
123
|
+
// URL param (the actionForm reads it via searchParams as an
|
|
124
|
+
// initial value for a title field).
|
|
125
125
|
rowActions: [
|
|
126
126
|
{ kind: "navigate", id: "edit", label: "showcase:actions.edit", screen: "item-edit" },
|
|
127
127
|
{
|
|
@@ -129,7 +129,7 @@ export const itemListScreen: EntityListScreenDefinition = {
|
|
|
129
129
|
id: "duplicate",
|
|
130
130
|
label: "showcase:actions.duplicate",
|
|
131
131
|
screen: "item-quick-add",
|
|
132
|
-
// DSL
|
|
132
|
+
// DSL limit: no "Copy of" prefix expressible → solve server-side in the handler.
|
|
133
133
|
params: { pick: ["title", "priority"] },
|
|
134
134
|
},
|
|
135
135
|
{
|
|
@@ -159,7 +159,7 @@ export const itemFeedScreen: EntityListScreenDefinition = {
|
|
|
159
159
|
"dueDate",
|
|
160
160
|
],
|
|
161
161
|
pagination: "infinite",
|
|
162
|
-
pageSize: 30, //
|
|
162
|
+
pageSize: 30, // smaller pages so the scroll effect triggers more often
|
|
163
163
|
defaultSort: { field: "title", dir: "asc" },
|
|
164
164
|
searchable: true,
|
|
165
165
|
rowActions: [
|
|
@@ -167,10 +167,10 @@ export const itemFeedScreen: EntityListScreenDefinition = {
|
|
|
167
167
|
],
|
|
168
168
|
};
|
|
169
169
|
|
|
170
|
-
// Tier 2.7c
|
|
171
|
-
//
|
|
172
|
-
// status="active".
|
|
173
|
-
// vs "All Tasks")
|
|
170
|
+
// Tier 2.7c demo — screen-level filter. Same entity, same query
|
|
171
|
+
// handler as itemListScreen, but with a fixed WHERE: only items with
|
|
172
|
+
// status="active". Classic bucketing pattern (e.g. "Active Tasks"
|
|
173
|
+
// vs "All Tasks") without having to write a custom page.
|
|
174
174
|
export const itemActiveScreen: EntityListScreenDefinition = {
|
|
175
175
|
id: "item-active",
|
|
176
176
|
type: "entityList",
|
|
@@ -186,18 +186,18 @@ export const itemActiveScreen: EntityListScreenDefinition = {
|
|
|
186
186
|
],
|
|
187
187
|
};
|
|
188
188
|
|
|
189
|
-
// Tier 2.7d
|
|
190
|
-
// driven
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
// -
|
|
194
|
-
// -
|
|
195
|
-
//
|
|
196
|
-
// invoice:approve
|
|
197
|
-
// -
|
|
189
|
+
// Tier 2.7d demo — actionForm screen type. A non-CRUD write-handler-
|
|
190
|
+
// driven form, here with the existing item:create handler but a
|
|
191
|
+
// reduced field selection (only title + priority). Demonstrates that
|
|
192
|
+
// an actionForm:
|
|
193
|
+
// - needs no entity reference (fields are inline)
|
|
194
|
+
// - triggers any write handler QN (here item:create,
|
|
195
|
+
// something like item:archive-batch or
|
|
196
|
+
// invoice:approve with dedicated handlers would be typical)
|
|
197
|
+
// - can redirect after submit (here to the list)
|
|
198
198
|
//
|
|
199
|
-
// Default
|
|
200
|
-
// false, priority
|
|
199
|
+
// Default values apply for non-form fields: status=draft, isDone=
|
|
200
|
+
// false, priority comes from the form, notes/dueDate optional.
|
|
201
201
|
export const itemQuickAddScreen: ActionFormScreenDefinition = {
|
|
202
202
|
id: "item-quick-add",
|
|
203
203
|
type: "actionForm",
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
// Items
|
|
2
|
-
//
|
|
3
|
-
// (
|
|
4
|
-
// `components
|
|
1
|
+
// Items feature — web platform plugin. ClientFeatureDefinition with
|
|
2
|
+
// translations. Items currently has no custom-screen components
|
|
3
|
+
// (renders via the standard RenderEdit/RenderList), accordingly no
|
|
4
|
+
// `components` map.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
6
|
+
// A native platform would live alongside it in features/items/native/
|
|
7
|
+
// — translations are shared, components/UI are not.
|
|
8
8
|
|
|
9
9
|
import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
|
|
10
10
|
import { itemsTranslations } from "../i18n";
|
|
@@ -5,9 +5,9 @@ import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
|
|
|
5
5
|
|
|
6
6
|
import { demoEntity } from "../features/demo/feature";
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// Gives the list view real rows with status/flag variety. price (money)
|
|
9
|
+
// stays empty — the money input shows in the edit screen, in the seed we leave
|
|
10
|
+
// it out to avoid depending on the money payload shape.
|
|
11
11
|
const STATUSES = ["draft", "review", "published", "archived"] as const;
|
|
12
12
|
|
|
13
13
|
// Fixed across boots (unlike the framework-minted ids for every other seed
|
|
@@ -39,8 +39,8 @@ await runDevApp({
|
|
|
39
39
|
aiSettingsFeature,
|
|
40
40
|
workboardFeature,
|
|
41
41
|
],
|
|
42
|
-
//
|
|
43
|
-
//
|
|
42
|
+
// Enables the upload routes (/api/files) + ctx.services.files for the avatar
|
|
43
|
+
// stress test. In-memory is enough for the demo (non-persistent).
|
|
44
44
|
files: { storageProvider: createInMemoryFileProvider() },
|
|
45
45
|
port: Number.parseInt(process.env["PORT"] ?? "4180", 10),
|
|
46
46
|
clientEntry: "./src/app/client.tsx",
|
|
@@ -18,10 +18,10 @@ export function AppShell({
|
|
|
18
18
|
children: ReactNode;
|
|
19
19
|
schema: AppSchema;
|
|
20
20
|
}): ReactNode {
|
|
21
|
-
// Content
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
21
|
+
// Content panel switch (= P4 pattern, demo-local): if a target is active in
|
|
22
|
+
// the URL (click on a content page or the "+"), the EditorPanel fills
|
|
23
|
+
// the main area; otherwise the normal screen. "Nothing
|
|
24
|
+
// selected" → children (no "Screen not found" regression).
|
|
25
25
|
const nav = useNav();
|
|
26
26
|
const resolvers = useResolvers();
|
|
27
27
|
const activeTarget = parseTargetFromSearchParams(nav.searchParams);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// Client
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
1
|
+
// Client side of the content stress test: the navProvider attaches to the
|
|
2
|
+
// static `content` nav node (QN "content:nav:content"), loads the pages
|
|
3
|
+
// via /api/query and emits them as tree leaves. navEntities ["page"]
|
|
4
|
+
// subscribes to the live events → after a create the new page appears
|
|
5
|
+
// immediately in the sidebar tree. The content:edit resolver renders the create
|
|
6
|
+
// form (empty target) or the detail view (target with id).
|
|
7
7
|
|
|
8
8
|
import type {
|
|
9
9
|
TargetRef,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// Config
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// 2-
|
|
1
|
+
// Config stress test (server). The shadcn reference designs are NOT hand-built
|
|
2
|
+
// but generated 1:1 from the schema — to see what the auto-UI supports and
|
|
3
|
+
// where it hits limits. First case: "Shipping Address" (flat form,
|
|
4
|
+
// 2-field rows, custom submit label).
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
createBooleanField,
|
|
@@ -83,10 +83,10 @@ export const examplesFeature = defineFeature("examples", (r) => {
|
|
|
83
83
|
r.translations({ keys: EXAMPLES_I18N });
|
|
84
84
|
r.crud("shipping", shippingEntity, editFormOnly);
|
|
85
85
|
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
86
|
+
// ONE untitled section: card title + subtitle (from i18n) carry the
|
|
87
|
+
// context, the fields flow directly below. street/apt/saveAsDefault
|
|
88
|
+
// span both columns (full width), city/state + zip/country share
|
|
89
|
+
// one row each.
|
|
90
90
|
r.screen({
|
|
91
91
|
id: "shipping-edit",
|
|
92
92
|
type: "entityEdit",
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
// Gallery
|
|
2
|
-
// (
|
|
3
|
-
// (
|
|
4
|
-
// React
|
|
1
|
+
// Gallery feature (server). A custom screen showing the foundations
|
|
2
|
+
// (colors/typography/radius/elevation/spacing) + atomic components
|
|
3
|
+
// (buttons, cards) — what the entity auto-screens do not cover.
|
|
4
|
+
// React component assigned client-side via clientFeatures.components.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
6
|
+
// Own FeatureName (not "styleguide") — two defineFeature calls with the same
|
|
7
|
+
// name would throw in createRegistry.
|
|
8
8
|
|
|
9
9
|
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
10
10
|
import type { LocalizedString } from "../shared-i18n";
|
|
11
11
|
|
|
12
|
-
// Server
|
|
13
|
-
//
|
|
14
|
-
//
|
|
12
|
+
// Server counterpart to the nav labels — the boot validator needs screen:gallery.title
|
|
13
|
+
// registered server-side, even if the custom screen itself does not pull a
|
|
14
|
+
// rendered title from i18n.
|
|
15
15
|
const GALLERY_I18N: Readonly<Record<string, LocalizedString>> = {
|
|
16
16
|
"screen:gallery.title": { de: "Foundations & Components", en: "Foundations & Components" },
|
|
17
17
|
"gallery:nav.styleguide": { de: "Styleguide", en: "Styleguide" },
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
import { Check, ChevronDown, Search, X } from "lucide-react";
|
|
8
8
|
import type { ReactNode } from "react";
|
|
9
9
|
|
|
10
|
-
// Literal Tailwind
|
|
11
|
-
//
|
|
10
|
+
// Literal Tailwind classes (no `bg-${token}`) — the v4 scanner only generates
|
|
11
|
+
// classes that appear literally in the source.
|
|
12
12
|
const SWATCHES: ReadonlyArray<readonly [string, string]> = [
|
|
13
13
|
["background", "bg-background"],
|
|
14
14
|
["foreground", "bg-foreground"],
|
|
@@ -114,7 +114,7 @@ interface Dividend {
|
|
|
114
114
|
readonly amount: string;
|
|
115
115
|
readonly bars: readonly Bar[];
|
|
116
116
|
}
|
|
117
|
-
// kumiko-lint-ignore no-logic-in-views demo: inline
|
|
117
|
+
// kumiko-lint-ignore no-logic-in-views demo: inline chart data prep for the gallery fixtures (demo readability > extraction)
|
|
118
118
|
function bars(heights: readonly [number, number, number, number]): readonly Bar[] {
|
|
119
119
|
return heights.map((h, i) => ({ k: "abcd"[i] as string, h }));
|
|
120
120
|
}
|
|
@@ -164,7 +164,7 @@ function Badge({ children }: { children: ReactNode }): ReactNode {
|
|
|
164
164
|
);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
// Select-
|
|
167
|
+
// Select stand-in (shadcn select trigger look) for static showcase blocks.
|
|
168
168
|
function SelectStub({ value }: { value: string }): ReactNode {
|
|
169
169
|
return (
|
|
170
170
|
<div className="border-input bg-background flex h-9 items-center justify-between rounded-md border px-3 text-sm">
|
|
@@ -359,7 +359,7 @@ export function Gallery(): ReactNode {
|
|
|
359
359
|
<div className="flex items-center gap-3 p-2">
|
|
360
360
|
<div className="relative min-w-0 flex-1">
|
|
361
361
|
<Search className="text-muted-foreground absolute left-3 top-1/2 size-4 -translate-y-1/2" />
|
|
362
|
-
{/* kumiko-lint-ignore primitives-discipline readOnly search-pill visual (rounded-full
|
|
362
|
+
{/* kumiko-lint-ignore primitives-discipline readOnly search-pill visual (rounded-full with inset icon) — pattern demo, not a form field */}
|
|
363
363
|
<input
|
|
364
364
|
className="bg-muted/50 placeholder:text-muted-foreground focus-visible:ring-ring h-10 w-full rounded-full border-none pl-9 pr-4 text-sm outline-none focus-visible:ring-2"
|
|
365
365
|
placeholder="Search holdings or tickers…"
|
|
@@ -744,10 +744,10 @@ export function Gallery(): ReactNode {
|
|
|
744
744
|
</Block>
|
|
745
745
|
|
|
746
746
|
<Block id="tags" title="Tags — bundled-feature layout">
|
|
747
|
-
{/* ponytail: faithful
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
747
|
+
{/* ponytail: faithful layout replica of the TagSection (tags/web) with the
|
|
748
|
+
real primitives + static data — the live version hangs off the
|
|
749
|
+
dispatcher. Verifies the inline create row (input grows,
|
|
750
|
+
add button flush beside it). */}
|
|
751
751
|
<div className="flex max-w-md flex-col gap-4">
|
|
752
752
|
<Field id="tg-select" label="Tags">
|
|
753
753
|
<Input
|
|
@@ -778,9 +778,9 @@ export function Gallery(): ReactNode {
|
|
|
778
778
|
</Block>
|
|
779
779
|
|
|
780
780
|
<Block id="nav" title="Navigation">
|
|
781
|
-
{/* ponytail:
|
|
782
|
-
|
|
783
|
-
{/* kumiko-lint-ignore primitives-discipline nav-surface demo (
|
|
781
|
+
{/* ponytail: static replica of the nav standard — the LIVE nav is
|
|
782
|
+
the sidebar on the left (NavTree), isolated here for the docs. */}
|
|
783
|
+
{/* kumiko-lint-ignore primitives-discipline nav-surface demo (navigation surface, not a card) */}
|
|
784
784
|
<div className="bg-card w-60 rounded-lg border p-3 text-sm shadow-sm">
|
|
785
785
|
<div className="text-muted-foreground/70 px-2 pb-1 pt-2 text-[11px] font-medium uppercase tracking-wider">
|
|
786
786
|
Workspace
|
|
@@ -67,8 +67,8 @@ const LOAN_MARKERS = [
|
|
|
67
67
|
const SENDERS = ["William Smith", "Alice Smith", "Bob Johnson", "Emily Davis"] as const;
|
|
68
68
|
const SUBJECTS = ["Meeting Tomorrow", "Re: Project Update", "Weekend Plans", "Re: Budget"] as const;
|
|
69
69
|
|
|
70
|
-
//
|
|
71
|
-
//
|
|
70
|
+
// Static demo inbox (18 messages) for the InfinityList demo — enough
|
|
71
|
+
// rows to load several pages beyond pageSize=6.
|
|
72
72
|
const INBOX_MESSAGES = Array.from({ length: 18 }, (_, i) => ({
|
|
73
73
|
id: `m${i + 1}`,
|
|
74
74
|
// Cast is sound: `i % SENDERS.length` is always in [0, SENDERS.length) —
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Demo
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Demo component for the `custom` dashboard panel type: shows that an
|
|
2
|
+
// attached app component fetches its data itself and sees the currently
|
|
3
|
+
// selected screen filter value via `filterParams` (see
|
|
4
4
|
// DashboardFilterDefinition in feature.ts).
|
|
5
5
|
|
|
6
6
|
import { type ExtensionSectionProps, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// Demo
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// Demo component for the static `icon` field of a dashboard stat panel:
|
|
2
|
+
// resolved via the same extensionSectionComponents registry as custom panels,
|
|
3
|
+
// but ignores the entity/filter context (a plain icon has
|
|
4
|
+
// no relation to it).
|
|
5
5
|
|
|
6
6
|
import type { ReactNode } from "react";
|
|
7
7
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// @runtime test
|
|
2
|
-
// Playwright
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// Playwright config for the ui-walkthrough run-through. Starts the
|
|
3
|
+
// real dev server as a webServer fixture, exactly like `bun dev` — only
|
|
4
|
+
// on the port from samples/e2e/e2e-ports.ts so no dev session collides.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
// setupTestStack
|
|
8
|
-
//
|
|
6
|
+
// The dev server does the HTTP binding based on the PORT env. The
|
|
7
|
+
// setupTestStack default is ephemeral (fresh kumiko_test_<random> DB),
|
|
8
|
+
// so no DB reset logic is needed here.
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
defineAppE2eConfig,
|