@cosmicdrift/kumiko-renderer 0.342.0 → 0.343.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/app/kumiko-screen.js +35 -1
- package/dist/app/visible-when.d.ts +4 -0
- package/dist/app/visible-when.js +11 -0
- package/dist/i18n-defaults.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +5 -5
- package/src/changes.json +6 -0
|
@@ -42,6 +42,8 @@ import { buildDefaultEditRowAction, buildDrawerRowAction, buildProjectionRowActi
|
|
|
42
42
|
import { findEditScreenFor, navigateTargetAllows, screenAccessAllows } from "./screen-access.js";
|
|
43
43
|
import { SecretMintBody } from "./secret-mint-body.js";
|
|
44
44
|
import { SecretsEditBody } from "./secrets-edit-body.js";
|
|
45
|
+
import { useEmbeddedScreen } from "./use-embedded-screen.js";
|
|
46
|
+
import { evalVisibleWhen } from "./visible-when.js";
|
|
45
47
|
import { dispatcherErrorText, WriteFailedError } from "./write-failed-error.js";
|
|
46
48
|
export { qualifyScreenId };
|
|
47
49
|
/** Mirrors qualifyScreenId for nav QNs (registry form `<feature>:nav:<short-id>`).
|
|
@@ -66,7 +68,16 @@ export function KumikoScreen({ schema, qn, translate, entityId, onRowClick, onCo
|
|
|
66
68
|
if (!screenAccessAllows(screen.access, userRoles)) {
|
|
67
69
|
return (_jsxs(Banner, { padded: true, variant: "error", testId: "kumiko-screen-access-denied", children: ["Access denied: ", _jsx(Text, { variant: "code", children: qn })] }));
|
|
68
70
|
}
|
|
69
|
-
const
|
|
71
|
+
const screenBody = renderScreenBody({
|
|
72
|
+
schema,
|
|
73
|
+
screen,
|
|
74
|
+
translate,
|
|
75
|
+
entityId,
|
|
76
|
+
onRowClick,
|
|
77
|
+
onCopyLink,
|
|
78
|
+
});
|
|
79
|
+
// Gate every entry (incl. direct URL): the body element is only mounted once the condition holds.
|
|
80
|
+
const body = screen.visibleWhen !== undefined ? (_jsx(ScreenVisibilityGate, { featureName: schema.featureName, visibleWhen: screen.visibleWhen, fallback: screen.fallback, translate: translate, children: screenBody })) : (screenBody);
|
|
70
81
|
// An embedded screen (e.g. a dashboard panel) keeps its parent's host and
|
|
71
82
|
// must not portal its page header into the shell that hosts the outer screen.
|
|
72
83
|
if (outerHost !== undefined) {
|
|
@@ -74,6 +85,29 @@ export function KumikoScreen({ schema, qn, translate, entityId, onRowClick, onCo
|
|
|
74
85
|
}
|
|
75
86
|
return _jsx(ReturnHostProvider, { value: ownHost, children: body });
|
|
76
87
|
}
|
|
88
|
+
function ScreenVisibilityGate({ featureName, visibleWhen, fallback, translate, children, }) {
|
|
89
|
+
const { Banner } = usePrimitives();
|
|
90
|
+
const t = useTranslation();
|
|
91
|
+
const result = useQuery(visibleWhen.query, {}, { live: true });
|
|
92
|
+
const verdict = evalVisibleWhen(visibleWhen, result);
|
|
93
|
+
if (verdict === "visible")
|
|
94
|
+
return children;
|
|
95
|
+
if (verdict === "loading") {
|
|
96
|
+
return (_jsx(Banner, { padded: true, variant: "loading", testId: "kumiko-screen-loading", children: "Loading\u2026" }));
|
|
97
|
+
}
|
|
98
|
+
if (fallback !== undefined) {
|
|
99
|
+
return _jsx(FallbackScreen, { featureName: featureName, fallback: fallback, translate: translate });
|
|
100
|
+
}
|
|
101
|
+
return (_jsx(Banner, { padded: true, variant: "info", testId: "kumiko-screen-unavailable", children: t("kumiko.screen.unavailable") }));
|
|
102
|
+
}
|
|
103
|
+
function FallbackScreen({ featureName, fallback, translate, }) {
|
|
104
|
+
const target = useEmbeddedScreen(featureName, fallback);
|
|
105
|
+
const { Banner, Text } = usePrimitives();
|
|
106
|
+
if (target === undefined) {
|
|
107
|
+
return (_jsxs(Banner, { padded: true, variant: "error", testId: "kumiko-screen-not-found", children: ["Screen not found: ", _jsx(Text, { variant: "code", children: fallback })] }));
|
|
108
|
+
}
|
|
109
|
+
return _jsx(KumikoScreen, { schema: target.schema, qn: target.qn, translate: translate });
|
|
110
|
+
}
|
|
77
111
|
function renderScreenBody({ schema, screen, translate, entityId, onRowClick, onCopyLink, }) {
|
|
78
112
|
switch (screen.type) {
|
|
79
113
|
case "entityEdit":
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DashboardPanelVisibility } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
|
+
import type { UseQueryResult } from "../hooks/use-query.js";
|
|
3
|
+
export type VisibleWhenVerdict = "loading" | "visible" | "hidden" | "error";
|
|
4
|
+
export declare function evalVisibleWhen(visibleWhen: DashboardPanelVisibility, result: UseQueryResult<Readonly<Record<string, unknown>>> | undefined): VisibleWhenVerdict;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Shared by dashboard screen panels and screen-level visibleWhen. Anything but a
|
|
2
|
+
// positive match is non-visible (fail-closed); `error` is split out so panels can offer a retry.
|
|
3
|
+
export function evalVisibleWhen(visibleWhen, result) {
|
|
4
|
+
if (result?.error)
|
|
5
|
+
return "error";
|
|
6
|
+
if (result === undefined)
|
|
7
|
+
return "hidden";
|
|
8
|
+
if (result.data === null)
|
|
9
|
+
return result.loading ? "loading" : "hidden";
|
|
10
|
+
return result.data[visibleWhen.field] === visibleWhen.eq ? "visible" : "hidden";
|
|
11
|
+
}
|
package/dist/i18n-defaults.js
CHANGED
|
@@ -106,6 +106,7 @@ export const kumikoDefaultTranslations = {
|
|
|
106
106
|
"kumiko.dashboard.panel.error.retry": "Try again",
|
|
107
107
|
"kumiko.dashboard.panel.error.title": "{label} could not be loaded",
|
|
108
108
|
"kumiko.dashboard.time-range": "Time range",
|
|
109
|
+
"kumiko.screen.unavailable": "This page is not available right now.",
|
|
109
110
|
"kumiko.dashboard.today": "Today",
|
|
110
111
|
"kumiko.dashboard.updated-at": "As of {time}",
|
|
111
112
|
"kumiko.app-boot.loading": "Loading…",
|
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export type { EmbeddedScreenTarget } from "./app/use-embedded-screen.js";
|
|
|
31
31
|
export { useEmbeddedScreen } from "./app/use-embedded-screen.js";
|
|
32
32
|
export type { VariableChipsProps } from "./app/variable-chips.js";
|
|
33
33
|
export { VariableChips } from "./app/variable-chips.js";
|
|
34
|
+
export { evalVisibleWhen, type VisibleWhenVerdict } from "./app/visible-when.js";
|
|
34
35
|
export { dispatcherErrorText, WriteFailedError } from "./app/write-failed-error.js";
|
|
35
36
|
export { RelatedListSection } from "./components/related-list-section.js";
|
|
36
37
|
export type { RenderEditAction, RenderEditChangeState, RenderEditControls, RenderEditProps, } from "./components/render-edit.js";
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ export { lastSegment } from "./app/qn.js";
|
|
|
26
26
|
export { navigateToReturn, navigateToReturnOr, navigateWithReturnTo, RETURN_TO_PARAM, ReturnHostProvider, resolveReturnTarget, splitReturnTo, useReturnHost, useReturnTarget, } from "./app/return-to.js";
|
|
27
27
|
export { useEmbeddedScreen } from "./app/use-embedded-screen.js";
|
|
28
28
|
export { VariableChips } from "./app/variable-chips.js";
|
|
29
|
+
export { evalVisibleWhen } from "./app/visible-when.js";
|
|
29
30
|
export { dispatcherErrorText, WriteFailedError } from "./app/write-failed-error.js";
|
|
30
31
|
export { RelatedListSection } from "./components/related-list-section.js";
|
|
31
32
|
export { RenderEdit } from "./components/render-edit.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmicdrift/kumiko-renderer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.343.0",
|
|
4
4
|
"description": "Platform-agnostic React renderer for Kumiko screens. Contains the shared logic — primitives-contract, hooks, KumikoScreen, navigation & SSE abstractions — that any platform-specific renderer (web, native) composes. No DOM, no EventSource, no react-dom.",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@cosmicdrift/kumiko-framework": "0.
|
|
19
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
20
|
-
"@cosmicdrift/kumiko-types": "0.
|
|
18
|
+
"@cosmicdrift/kumiko-framework": "0.343.0",
|
|
19
|
+
"@cosmicdrift/kumiko-headless": "0.343.0",
|
|
20
|
+
"@cosmicdrift/kumiko-types": "0.343.0",
|
|
21
21
|
"react": "^19.2.6",
|
|
22
22
|
"temporal-polyfill": "^0.3.2",
|
|
23
23
|
"zod": "^4.4.3"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@types/react-dom": "^19.2.3",
|
|
29
29
|
"jsdom": "^29.1.1",
|
|
30
30
|
"react-dom": "^19.2.6",
|
|
31
|
-
"@cosmicdrift/kumiko-locale-de": "0.
|
|
31
|
+
"@cosmicdrift/kumiko-locale-de": "0.343.0"
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
package/src/changes.json
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.343.0",
|
|
4
|
+
"type": "improvement",
|
|
5
|
+
"title": "Screens take visibleWhen and fallback",
|
|
6
|
+
"detail": "Any screen can gate itself on a query field with `visibleWhen`, including on direct URL access. Unmet or failed conditions render the `fallback` screen or a standard notice instead of the content. New i18n key: `kumiko.screen.unavailable`."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.342.0",
|
|
4
10
|
"type": "improvement",
|