@burdenoff/fe-libs 2026.1021.4 → 2026.1021.6
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/README.md +35 -0
- package/dist/shared/assistant/quota.d.ts +6 -3
- package/dist/shared/assistant/ui/AssistantOverlay.js +8 -8
- package/dist/shared/components/QuotaUpgradeBridge.d.ts +99 -0
- package/dist/shared/components/QuotaUpgradeBridge.js +106 -0
- package/dist/shared/components/UpgradePromptModal.d.ts +7 -3
- package/dist/shared/components/index.d.ts +2 -0
- package/dist/shared/utils/canvasTokens.d.ts +65 -0
- package/dist/shared/utils/canvasTokens.js +159 -0
- package/dist/shared/utils/index.d.ts +2 -0
- package/dist/shared-assistant.js +11 -11
- package/dist/shared-components.js +7 -6
- package/dist/shared-utils.js +19 -18
- package/dist/shared.js +135 -133
- package/dist/utils/index.js +1 -0
- package/package.json +6 -2
- package/shared/config/eslint.config.d.mts +21 -0
- package/shared/config/eslint.config.mjs +80 -18
- package/src/shared/styles/app-shell.css +3 -0
- package/src/shared/styles/canvas-theme.css +82 -0
- package/src/shared/tokens/build/semantic.css +83 -0
- package/src/shared/tokens/build/tailwind.preset.js +65 -0
package/README.md
CHANGED
|
@@ -122,6 +122,41 @@ plain browser (persisted in `sessionStorage`, cleared with `off`). It is
|
|
|
122
122
|
`public/manifest.json` and `public/sw.js` from its `native.config.json`
|
|
123
123
|
(`NativeConfig`).
|
|
124
124
|
|
|
125
|
+
## Raw colours, canvas tokens and the shared ESLint guard
|
|
126
|
+
|
|
127
|
+
UI code uses semantic tokens only. `createEslintConfig()` from
|
|
128
|
+
`@burdenoff/fe-libs/shared/config/eslint.config.mjs` reports, as an **error**,
|
|
129
|
+
hex / `rgb()` / `hsl()` / `oklch()` literals and Tailwind palette classes
|
|
130
|
+
(`bg-red-500`, `text-white`, `border-t-gray-200`, …) in string literals and
|
|
131
|
+
template strings. Comments and test files are not checked.
|
|
132
|
+
|
|
133
|
+
- A repo that still carries raw-colour debt can pass `rawColors: 'warn'` while
|
|
134
|
+
it sweeps; treat that as a tracked, temporary opt-out.
|
|
135
|
+
- A repo with a standalone ESLint config applies the same guard with
|
|
136
|
+
`'no-restricted-syntax': ['error', ...rawColorRestrictedSyntax()]`.
|
|
137
|
+
|
|
138
|
+
Workflow builders, graphs and mappers use the canvas tokens in `tokens.css`.
|
|
139
|
+
Each one aliases an existing `chart-*` / `status-*` / surface token, so it
|
|
140
|
+
follows light/dark mode, the brand and the expressive themes:
|
|
141
|
+
|
|
142
|
+
| Group | Tokens |
|
|
143
|
+
|---|---|
|
|
144
|
+
| Canvas | `--color-canvas-{bg,grid,selection,minimap-bg,minimap-node,minimap-mask,control-bg}` |
|
|
145
|
+
| Node surface | `--color-node-{bg,bg-hover,border,border-hover,border-selected,text,text-muted,handle,handle-connected}` |
|
|
146
|
+
| Node category | `--color-node-{trigger,action,logic,loop,data,integration,ai,human,utility,end,default}` plus `-subtle` |
|
|
147
|
+
| Node state | `--color-node-state-{idle,queued,running,success,warning,error,skipped}` |
|
|
148
|
+
| Edge | `--color-edge-{default,hover,selected,active,success,error,compatible,incompatible,label-bg,label-text}` |
|
|
149
|
+
| Data type | `--color-datatype-{string,number,boolean,object,array,date,binary,any}` |
|
|
150
|
+
|
|
151
|
+
`app-shell.css` maps them to Tailwind utilities (`bg-node-trigger`,
|
|
152
|
+
`stroke-edge-default`, `ring-node-state-running`, …). A shell with its own
|
|
153
|
+
`@theme` imports `@burdenoff/fe-libs/shared/styles/canvas-theme.css` instead.
|
|
154
|
+
For React Flow props, SVG attributes and inline styles, use the helpers in
|
|
155
|
+
`@burdenoff/fe-libs/shared/utils` (`nodeCategoryColor`, `edgeColor`,
|
|
156
|
+
`nodeStateColor`, `dataTypeColor`, `chartSeriesColor(chartSeriesIndex(key))`)
|
|
157
|
+
and the literal class records (`nodeCategoryClasses`, `nodeStateRingClasses`,
|
|
158
|
+
`dataTypeTextClasses`).
|
|
159
|
+
|
|
125
160
|
## Tech Stack
|
|
126
161
|
|
|
127
162
|
- React 19
|
|
@@ -111,9 +111,12 @@ export type QuotaKind = "sandbox" | "ai-credits" | "generic";
|
|
|
111
111
|
* product keeps HealthyBowl's existing `healthybowl:quota-exhausted` byte for
|
|
112
112
|
* byte, and stops two products in one page colliding.
|
|
113
113
|
*
|
|
114
|
-
* ★
|
|
115
|
-
*
|
|
116
|
-
*
|
|
114
|
+
* ★ Who listens is up to the product, and no census is kept here (the last one,
|
|
115
|
+
* "nothing listens", was false by the time it was read: VibeControls' shell and
|
|
116
|
+
* microfrontend both did). A shell answers it by mounting `QuotaUpgradeBridge`
|
|
117
|
+
* (`@burdenoff/fe-libs/shared/components`) beside its `UpgradePromptModal`; a
|
|
118
|
+
* product microfrontend that renders its own dialog claims the event with
|
|
119
|
+
* `withQuotaDialogOwnership` / `useQuotaDialogOwnership` so only one opens.
|
|
117
120
|
*/
|
|
118
121
|
export declare function quotaExhaustedEventName(product: string): string;
|
|
119
122
|
export interface QuotaExhaustedEventDetail {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { quotaExhaustedEventName as e } from "../quota.js";
|
|
2
|
+
import { useAssistantTr as t } from "../i18n.js";
|
|
3
3
|
import { assistantPanelOwnsEscape as n } from "./panelOverlays.js";
|
|
4
4
|
import { AssistantPreviewBridgeHost as r } from "../preview/bridgeHost.js";
|
|
5
5
|
import { ASSISTANT_DOCK_WIDTH_VAR as i, ASSISTANT_OVERLAY_DESKTOP_QUERY as a, ASSISTANT_OVERLAY_TOP_VAR as o, ASSISTANT_PANEL_INSET_VAR as s, ASSISTANT_SHEET_BOTTOM_VAR as c, assistantLauncherBottom as l, assistantOverlayClassName as u, assistantOverlayEscapeAction as d, assistantOverlayKeys as f, assistantQuotaKindOf as p, closestAround as m, createAssistantNavigate as h, isAssistantToggleShortcut as g, nextAssistantOpenState as _, publishedAssistantDockWidth as v, publishedAssistantPanelInset as y, readAssistantOverlayFlag as b, requestedAssistantOpenState as x, writeAssistantOverlayFlag as S } from "./assistantOverlayState.js";
|
|
@@ -31,15 +31,15 @@ function U() {
|
|
|
31
31
|
function W() {
|
|
32
32
|
return M(H, U, () => !1);
|
|
33
33
|
}
|
|
34
|
-
function G(
|
|
34
|
+
function G(t, n) {
|
|
35
35
|
let r = A(n);
|
|
36
36
|
O(() => {
|
|
37
37
|
r.current = n;
|
|
38
38
|
}, [n]), O(() => {
|
|
39
|
-
if (!
|
|
40
|
-
let n = t
|
|
39
|
+
if (!t || typeof window > "u") return;
|
|
40
|
+
let n = e(t), i = (e) => r.current(p(e), e);
|
|
41
41
|
return window.addEventListener(n, i), () => window.removeEventListener(n, i);
|
|
42
|
-
}, [
|
|
42
|
+
}, [t]);
|
|
43
43
|
}
|
|
44
44
|
var K = () => {};
|
|
45
45
|
function q({ keyPrefix: e, quota: t, children: n }) {
|
|
@@ -121,8 +121,8 @@ function Y(e) {
|
|
|
121
121
|
...e
|
|
122
122
|
}) : null;
|
|
123
123
|
}
|
|
124
|
-
function X({ state:
|
|
125
|
-
let { isOpen: b, close: x, toggle: S, docked: w, toggleDock: T } =
|
|
124
|
+
function X({ state: e, panelId: i = "ai-assistant", panelProps: a, renderPanel: s, navigate: f, isShellLessTarget: p, topOffsetPx: g = 56, launcherIcon: _, launcherBottomInset: v = "1.5rem", showLauncher: y = !0 }) {
|
|
125
|
+
let { isOpen: b, close: x, toggle: S, docked: w, toggleDock: T } = e, E = t();
|
|
126
126
|
C(a?.serverHistory === !0);
|
|
127
127
|
let [D, A] = j(!1), M = k(() => f ? h({
|
|
128
128
|
navigate: f,
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The words for one kind of quota wall. `title`/`message` are the English
|
|
4
|
+
* fallbacks; the optional keys are looked up in the shell's i18n layer first,
|
|
5
|
+
* and an untranslated key falls back rather than showing the raw key.
|
|
6
|
+
*/
|
|
7
|
+
export interface QuotaUpgradeCopy {
|
|
8
|
+
titleKey?: string;
|
|
9
|
+
title: string;
|
|
10
|
+
messageKey?: string;
|
|
11
|
+
message: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Copy per `detail.kind` (e.g. `sandbox`, `ai-credits`, `runs`). `generic` is
|
|
15
|
+
* used for any kind not listed — and for an event with no kind at all.
|
|
16
|
+
*/
|
|
17
|
+
export type QuotaUpgradeCopyByKind = Readonly<Partial<Record<string, QuotaUpgradeCopy>>>;
|
|
18
|
+
/** Used when a product supplies no `generic` copy of its own. */
|
|
19
|
+
export declare const DEFAULT_QUOTA_UPGRADE_COPY: QuotaUpgradeCopy;
|
|
20
|
+
/** Detail carried by a `<product>:quota-exhausted` event. */
|
|
21
|
+
export interface ProductQuotaExhaustedDetail {
|
|
22
|
+
/** Which wall — the key into the product's {@link QuotaUpgradeCopyByKind}. */
|
|
23
|
+
kind: string;
|
|
24
|
+
/** The server's phrasing. Never shown: it names the wall, not the way past it. */
|
|
25
|
+
message?: string;
|
|
26
|
+
operationName?: string | null;
|
|
27
|
+
/** WHICH ceiling (e.g. `fluidgrids.runs.monthly`), forwarded to the prompt. */
|
|
28
|
+
quotaName?: string | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The `kind` of a quota event, or null when it carries none. Tolerates the
|
|
32
|
+
* shapes real dispatchers produce: a plain `Event`, a null detail, a detail
|
|
33
|
+
* without a kind.
|
|
34
|
+
*/
|
|
35
|
+
export declare function quotaEventKind(event: Event): string | null;
|
|
36
|
+
/** The copy for a kind; anything unlisted (or no kind) is the generic copy. */
|
|
37
|
+
export declare function resolveQuotaUpgradeCopy(copy: QuotaUpgradeCopyByKind | undefined, kind: string | null): QuotaUpgradeCopy;
|
|
38
|
+
/**
|
|
39
|
+
* Report a product quota wall from code that is not the assistant — e.g. a
|
|
40
|
+
* product SDK whose run mutation came back `QUOTA_EXHAUSTED`. The shell's
|
|
41
|
+
* bridge (or the product microfrontend that owns the dialog) answers it.
|
|
42
|
+
* Safe no-op on SSR.
|
|
43
|
+
*/
|
|
44
|
+
export declare function dispatchProductQuotaExhausted(product: string, detail: ProductQuotaExhaustedDetail): void;
|
|
45
|
+
/**
|
|
46
|
+
* Record that something which shows its own quota dialog for `product` is
|
|
47
|
+
* mounted. Returns the release to call on unmount. Each claim is distinct, so
|
|
48
|
+
* Strict Mode's mount → unmount → mount stays balanced.
|
|
49
|
+
*/
|
|
50
|
+
export declare function claimQuotaDialog(product: string): () => void;
|
|
51
|
+
/**
|
|
52
|
+
* Note who owns `product`'s dialog NOW, and return a check to run LATER: is an
|
|
53
|
+
* owner that was mounted at capture time still mounted?
|
|
54
|
+
*
|
|
55
|
+
* ★★ Both halves matter. An owning provider does not open its dialog when the
|
|
56
|
+
* event arrives — it defers a tick (so a page with a local dialog can claim the
|
|
57
|
+
* failure first) and clears that timer if it unmounts. So it shows a dialog
|
|
58
|
+
* only if it was listening at dispatch AND is still mounted when its timer
|
|
59
|
+
* fires:
|
|
60
|
+
*
|
|
61
|
+
* - mounted at dispatch, unmounted before the tick: its timer was cleared, so
|
|
62
|
+
* nobody shows anything unless the bridge does.
|
|
63
|
+
* - not mounted at dispatch, mounted before the tick: it never heard the
|
|
64
|
+
* event, so again the bridge must.
|
|
65
|
+
*
|
|
66
|
+
* A single "is anyone mounted?" read, at either moment, gets one of those wrong.
|
|
67
|
+
*/
|
|
68
|
+
export declare function captureQuotaDialogOwners(product: string): () => boolean;
|
|
69
|
+
/** Claim `product`'s quota dialog for as long as the calling component is mounted. */
|
|
70
|
+
export declare function useQuotaDialogOwnership(product: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* Wrap a component that renders its own quota dialog for `product`, so the
|
|
73
|
+
* shell's bridge stands down while it is mounted.
|
|
74
|
+
*
|
|
75
|
+
* Apply it where a lazy chunk RESOLVES (`lazy(() => import(...).then(m => ({
|
|
76
|
+
* default: withQuotaDialogOwnership(m.Root, 'product') })))`), so the claim can
|
|
77
|
+
* only exist once the real root — and the provider inside it — does.
|
|
78
|
+
*/
|
|
79
|
+
export declare function withQuotaDialogOwnership<P extends object>(Root: ComponentType<P>, product: string): ComponentType<P>;
|
|
80
|
+
export interface QuotaUpgradeBridgeOptions {
|
|
81
|
+
/** The product id the events are namespaced under (`<product>:quota-exhausted`). */
|
|
82
|
+
product: string;
|
|
83
|
+
/** Copy per quota kind; `generic` (or {@link DEFAULT_QUOTA_UPGRADE_COPY}) for the rest. */
|
|
84
|
+
copy?: QuotaUpgradeCopyByKind;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Listen for `<product>:quota-exhausted` and open the shell's upgrade prompt,
|
|
88
|
+
* unless a mounted owner shows its own dialog. Mount ONCE per shell, beside
|
|
89
|
+
* `UpgradePromptModal`.
|
|
90
|
+
*
|
|
91
|
+
* ★ The listener is registered once per product. The copy and the translator
|
|
92
|
+
* are read through refs: re-subscribing when a host passed a fresh copy object
|
|
93
|
+
* or the locale changed would run the cleanup, and the cleanup cancels pending
|
|
94
|
+
* timers — dropping a refusal that arrived just before the re-render.
|
|
95
|
+
*/
|
|
96
|
+
export declare function useQuotaUpgradeBridge({ product, copy }: QuotaUpgradeBridgeOptions): void;
|
|
97
|
+
export type QuotaUpgradeBridgeProps = QuotaUpgradeBridgeOptions;
|
|
98
|
+
/** {@link useQuotaUpgradeBridge} as a component. Renders nothing. */
|
|
99
|
+
export declare function QuotaUpgradeBridge(props: QuotaUpgradeBridgeProps): null;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { QUOTA_EXHAUSTED_CODE as e } from "../utils/quotaErrors.js";
|
|
2
|
+
import { useOptionalI18n as t } from "../providers/shell/I18nProvider.js";
|
|
3
|
+
import { dispatchUpgradePrompt as n } from "./UpgradePromptModal.js";
|
|
4
|
+
import { quotaExhaustedEventName as r } from "../assistant/quota.js";
|
|
5
|
+
import { useEffect as i, useRef as a } from "react";
|
|
6
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
7
|
+
//#region src/shared/components/QuotaUpgradeBridge.tsx
|
|
8
|
+
var s = {
|
|
9
|
+
title: "Plan Quota Reached",
|
|
10
|
+
message: "You've reached a limit on your current plan. Upgrade to continue using this feature."
|
|
11
|
+
};
|
|
12
|
+
function c(e) {
|
|
13
|
+
if (typeof CustomEvent > "u" || !(e instanceof CustomEvent)) return null;
|
|
14
|
+
let t = e.detail;
|
|
15
|
+
if (typeof t != "object" || !t || !("kind" in t)) return null;
|
|
16
|
+
let n = t.kind;
|
|
17
|
+
return typeof n == "string" && n.length > 0 ? n : null;
|
|
18
|
+
}
|
|
19
|
+
function l(e) {
|
|
20
|
+
if (typeof CustomEvent > "u" || !(e instanceof CustomEvent)) return;
|
|
21
|
+
let t = e.detail;
|
|
22
|
+
if (typeof t != "object" || !t || !("quotaName" in t)) return;
|
|
23
|
+
let n = t.quotaName;
|
|
24
|
+
return typeof n == "string" && n.length > 0 ? n : void 0;
|
|
25
|
+
}
|
|
26
|
+
function u(e, t) {
|
|
27
|
+
return (t !== null && t !== "generic" ? e?.[t] : void 0) ?? e?.generic ?? s;
|
|
28
|
+
}
|
|
29
|
+
function d(e, t) {
|
|
30
|
+
typeof window > "u" || window.dispatchEvent(new CustomEvent(r(e), { detail: t }));
|
|
31
|
+
}
|
|
32
|
+
var f = Symbol.for("burdenoff.fe-libs.quotaDialogOwners");
|
|
33
|
+
function p() {
|
|
34
|
+
let e = globalThis, t = e[f];
|
|
35
|
+
return t || (t = /* @__PURE__ */ new Map(), e[f] = t), t;
|
|
36
|
+
}
|
|
37
|
+
function m(e) {
|
|
38
|
+
let t = p(), n = t.get(e);
|
|
39
|
+
return n || (n = /* @__PURE__ */ new Set(), t.set(e, n)), n;
|
|
40
|
+
}
|
|
41
|
+
function h(e) {
|
|
42
|
+
let t = Symbol(`${e}-quota-dialog-owner`);
|
|
43
|
+
return m(e).add(t), () => {
|
|
44
|
+
m(e).delete(t);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function g(e) {
|
|
48
|
+
let t = [...m(e)];
|
|
49
|
+
return () => {
|
|
50
|
+
let n = m(e);
|
|
51
|
+
return t.some((e) => n.has(e));
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function _(e) {
|
|
55
|
+
i(() => h(e), [e]);
|
|
56
|
+
}
|
|
57
|
+
function v(e, t) {
|
|
58
|
+
function n(n) {
|
|
59
|
+
return _(t), /* @__PURE__ */ o(e, { ...n });
|
|
60
|
+
}
|
|
61
|
+
return n.displayName = `withQuotaDialogOwnership(${e.displayName ?? e.name ?? "Component"})`, n;
|
|
62
|
+
}
|
|
63
|
+
function y({ product: o, copy: s }) {
|
|
64
|
+
let d = t()?.t, f = a({
|
|
65
|
+
copy: s,
|
|
66
|
+
translate: d
|
|
67
|
+
});
|
|
68
|
+
i(() => {
|
|
69
|
+
f.current = {
|
|
70
|
+
copy: s,
|
|
71
|
+
translate: d
|
|
72
|
+
};
|
|
73
|
+
}, [s, d]), i(() => {
|
|
74
|
+
if (!o || typeof window > "u") return;
|
|
75
|
+
let t = r(o), i = /* @__PURE__ */ new Set(), a = (e, t) => {
|
|
76
|
+
let n = f.current.translate;
|
|
77
|
+
if (!e || !n) return t;
|
|
78
|
+
let r = n(e, t);
|
|
79
|
+
return r && r !== e ? r : t;
|
|
80
|
+
}, s = (t) => {
|
|
81
|
+
let r = c(t), s = l(t), d = g(o), p = setTimeout(() => {
|
|
82
|
+
if (i.delete(p), d()) return;
|
|
83
|
+
let t = u(f.current.copy, r);
|
|
84
|
+
n({
|
|
85
|
+
extensions: s ? {
|
|
86
|
+
code: e,
|
|
87
|
+
quotaName: s
|
|
88
|
+
} : { code: e },
|
|
89
|
+
title: a(t.titleKey, t.title),
|
|
90
|
+
description: a(t.messageKey, t.message)
|
|
91
|
+
});
|
|
92
|
+
}, 0);
|
|
93
|
+
i.add(p);
|
|
94
|
+
};
|
|
95
|
+
return window.addEventListener(t, s), () => {
|
|
96
|
+
window.removeEventListener(t, s);
|
|
97
|
+
for (let e of i) clearTimeout(e);
|
|
98
|
+
i.clear();
|
|
99
|
+
};
|
|
100
|
+
}, [o]);
|
|
101
|
+
}
|
|
102
|
+
function b(e) {
|
|
103
|
+
return y(e), null;
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { s as DEFAULT_QUOTA_UPGRADE_COPY, b as QuotaUpgradeBridge, g as captureQuotaDialogOwners, h as claimQuotaDialog, d as dispatchProductQuotaExhausted, c as quotaEventKind, u as resolveQuotaUpgradeCopy, _ as useQuotaDialogOwnership, y as useQuotaUpgradeBridge, v as withQuotaDialogOwnership };
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { UpgradeErrorExtensions } from '../utils/quotaErrors';
|
|
2
2
|
/**
|
|
3
3
|
* Global window event the shell listens for to open the upgrade modal.
|
|
4
|
-
* Dispatched by the Apollo error link
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Dispatched by the Apollo error link for STORAGE_QUOTA_EXCEEDED /
|
|
5
|
+
* RESOURCE_CAP_EXCEEDED, by `QuotaUpgradeBridge` for a product's
|
|
6
|
+
* `<product>:quota-exhausted` walls, and by any imperative caller.
|
|
7
|
+
*
|
|
8
|
+
* ★ The Apollo link deliberately does NOT dispatch for QUOTA_EXHAUSTED: several
|
|
9
|
+
* product pages still answer that code with a local dialog, and a global
|
|
10
|
+
* dispatch would stack a second one on top.
|
|
7
11
|
*/
|
|
8
12
|
export declare const UPGRADE_PROMPT_EVENT = "burdenoff:upgrade-prompt";
|
|
9
13
|
export interface UpgradePromptDetail {
|
|
@@ -25,6 +25,8 @@ export { UpgradePromptModal, dispatchUpgradePrompt, UPGRADE_PROMPT_EVENT, } from
|
|
|
25
25
|
export type { UpgradePromptModalProps, UpgradePromptDetail } from './UpgradePromptModal';
|
|
26
26
|
export { UpgradeInlineBanner } from './UpgradeInlineBanner';
|
|
27
27
|
export type { UpgradeInlineBannerProps } from './UpgradeInlineBanner';
|
|
28
|
+
export { QuotaUpgradeBridge, useQuotaUpgradeBridge, dispatchProductQuotaExhausted, resolveQuotaUpgradeCopy, quotaEventKind, claimQuotaDialog, captureQuotaDialogOwners, useQuotaDialogOwnership, withQuotaDialogOwnership, DEFAULT_QUOTA_UPGRADE_COPY, } from './QuotaUpgradeBridge';
|
|
29
|
+
export type { QuotaUpgradeBridgeProps, QuotaUpgradeBridgeOptions, QuotaUpgradeCopy, QuotaUpgradeCopyByKind, ProductQuotaExhaustedDetail, } from './QuotaUpgradeBridge';
|
|
28
30
|
export { getSSORedirectUrl, redirectToSSO, SSORedirectSpinner, checkSLO, checkRemoteSLO, clearLocalAuthState, } from './SSORedirectGuard';
|
|
29
31
|
export { LandingOrDashboardRedirect, LandingGateView, resolveLandingGate, hasStoredValidSession, } from './LandingOrDashboardRedirect';
|
|
30
32
|
export type { LandingOrDashboardRedirectProps, LandingGateViewProps, LandingGateDecision, LandingGateInput, } from './LandingOrDashboardRedirect';
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canvas / node / edge / data-type design tokens (G19).
|
|
3
|
+
*
|
|
4
|
+
* TypeScript handles for the builder tokens in fe-libs/shared/tokens
|
|
5
|
+
* (`--color-node-*`, `--color-edge-*`, `--color-canvas-*`,
|
|
6
|
+
* `--color-datatype-*`). Every token aliases an existing chart-* / status-* /
|
|
7
|
+
* surface token, so values follow light/dark mode, the brand and the
|
|
8
|
+
* expressive / high-contrast themes.
|
|
9
|
+
*
|
|
10
|
+
* Use the `var(--…)` helpers where a value goes outside Tailwind (React Flow
|
|
11
|
+
* props, SVG attributes, inline styles), and the class records for className
|
|
12
|
+
* strings. The class records are written out literally on purpose: Tailwind
|
|
13
|
+
* only generates utilities for class names it can find verbatim in source.
|
|
14
|
+
*/
|
|
15
|
+
/** What a workflow node does, for colouring its accent / header / icon well. */
|
|
16
|
+
export declare const NODE_CATEGORIES: readonly ["trigger", "action", "logic", "loop", "data", "integration", "ai", "human", "utility", "end", "default"];
|
|
17
|
+
export type NodeCategory = (typeof NODE_CATEGORIES)[number];
|
|
18
|
+
/** Execution state of a node in a run (ring / badge / status dot). */
|
|
19
|
+
export declare const NODE_STATES: readonly ["idle", "queued", "running", "success", "warning", "error", "skipped"];
|
|
20
|
+
export type NodeState = (typeof NODE_STATES)[number];
|
|
21
|
+
export declare const EDGE_KINDS: readonly ["default", "hover", "selected", "active", "success", "error", "compatible", "incompatible"];
|
|
22
|
+
export type EdgeKind = (typeof EDGE_KINDS)[number];
|
|
23
|
+
/** Data types carried by ports and shown in mappers. */
|
|
24
|
+
export declare const DATA_TYPES: readonly ["string", "number", "boolean", "object", "array", "date", "binary", "any"];
|
|
25
|
+
export type DataType = (typeof DATA_TYPES)[number];
|
|
26
|
+
/** Number of categorical chart-* series in the token set. */
|
|
27
|
+
export declare const CHART_SERIES_COUNT = 12;
|
|
28
|
+
/** Narrows any string to a known category, falling back to `'default'`. */
|
|
29
|
+
export declare function toNodeCategory(value: string | null | undefined): NodeCategory;
|
|
30
|
+
/** Narrows any string to a known data type, falling back to `'any'`. */
|
|
31
|
+
export declare function toDataType(value: string | null | undefined): DataType;
|
|
32
|
+
/** `var(--color-node-<category>)` — the solid category accent. */
|
|
33
|
+
export declare function nodeCategoryColor(category: NodeCategory): string;
|
|
34
|
+
/** `var(--color-node-<category>-subtle)` — a translucent tint of the accent. */
|
|
35
|
+
export declare function nodeCategorySubtleColor(category: NodeCategory): string;
|
|
36
|
+
/** `var(--color-node-state-<state>)`. */
|
|
37
|
+
export declare function nodeStateColor(state: NodeState): string;
|
|
38
|
+
/** `var(--color-edge-<kind>)`. */
|
|
39
|
+
export declare function edgeColor(kind: EdgeKind): string;
|
|
40
|
+
/** `var(--color-datatype-<type>)`. */
|
|
41
|
+
export declare function dataTypeColor(type: DataType): string;
|
|
42
|
+
/**
|
|
43
|
+
* `var(--color-chart-N)` for a stable categorical series — e.g. to give each
|
|
44
|
+
* integration a distinct accent from a hash of its key. Any integer works;
|
|
45
|
+
* it wraps onto chart-1 … chart-12.
|
|
46
|
+
*/
|
|
47
|
+
export declare function chartSeriesColor(index: number): string;
|
|
48
|
+
/** A stable chart series index for a string key (FNV-1a), for `chartSeriesColor`. */
|
|
49
|
+
export declare function chartSeriesIndex(key: string): number;
|
|
50
|
+
export interface NodeCategoryClasses {
|
|
51
|
+
/** Solid accent fill, e.g. an icon well or a header stripe. */
|
|
52
|
+
accent: string;
|
|
53
|
+
/** Translucent tint, e.g. a header background. */
|
|
54
|
+
subtle: string;
|
|
55
|
+
/** Accent-coloured text or icon. */
|
|
56
|
+
text: string;
|
|
57
|
+
/** Accent-coloured border. */
|
|
58
|
+
border: string;
|
|
59
|
+
}
|
|
60
|
+
/** Tailwind classes per node category (needs canvas-theme.css or app-shell.css). */
|
|
61
|
+
export declare const nodeCategoryClasses: Record<NodeCategory, NodeCategoryClasses>;
|
|
62
|
+
/** Ring classes per execution state (needs canvas-theme.css or app-shell.css). */
|
|
63
|
+
export declare const nodeStateRingClasses: Record<NodeState, string>;
|
|
64
|
+
/** Text classes per data type (needs canvas-theme.css or app-shell.css). */
|
|
65
|
+
export declare const dataTypeTextClasses: Record<DataType, string>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
//#region src/shared/utils/canvasTokens.ts
|
|
2
|
+
var e = [
|
|
3
|
+
"trigger",
|
|
4
|
+
"action",
|
|
5
|
+
"logic",
|
|
6
|
+
"loop",
|
|
7
|
+
"data",
|
|
8
|
+
"integration",
|
|
9
|
+
"ai",
|
|
10
|
+
"human",
|
|
11
|
+
"utility",
|
|
12
|
+
"end",
|
|
13
|
+
"default"
|
|
14
|
+
], t = [
|
|
15
|
+
"idle",
|
|
16
|
+
"queued",
|
|
17
|
+
"running",
|
|
18
|
+
"success",
|
|
19
|
+
"warning",
|
|
20
|
+
"error",
|
|
21
|
+
"skipped"
|
|
22
|
+
], n = [
|
|
23
|
+
"default",
|
|
24
|
+
"hover",
|
|
25
|
+
"selected",
|
|
26
|
+
"active",
|
|
27
|
+
"success",
|
|
28
|
+
"error",
|
|
29
|
+
"compatible",
|
|
30
|
+
"incompatible"
|
|
31
|
+
], r = [
|
|
32
|
+
"string",
|
|
33
|
+
"number",
|
|
34
|
+
"boolean",
|
|
35
|
+
"object",
|
|
36
|
+
"array",
|
|
37
|
+
"date",
|
|
38
|
+
"binary",
|
|
39
|
+
"any"
|
|
40
|
+
], i = 12;
|
|
41
|
+
function a(e, t) {
|
|
42
|
+
return e.includes(t);
|
|
43
|
+
}
|
|
44
|
+
function o(t) {
|
|
45
|
+
return t && a(e, t) ? t : "default";
|
|
46
|
+
}
|
|
47
|
+
function s(e) {
|
|
48
|
+
return e && a(r, e) ? e : "any";
|
|
49
|
+
}
|
|
50
|
+
function c(e) {
|
|
51
|
+
return `var(--color-node-${e})`;
|
|
52
|
+
}
|
|
53
|
+
function l(e) {
|
|
54
|
+
return `var(--color-node-${e}-subtle)`;
|
|
55
|
+
}
|
|
56
|
+
function u(e) {
|
|
57
|
+
return `var(--color-node-state-${e})`;
|
|
58
|
+
}
|
|
59
|
+
function d(e) {
|
|
60
|
+
return `var(--color-edge-${e})`;
|
|
61
|
+
}
|
|
62
|
+
function f(e) {
|
|
63
|
+
return `var(--color-datatype-${e})`;
|
|
64
|
+
}
|
|
65
|
+
function p(e) {
|
|
66
|
+
return `var(--color-chart-${(Number.isFinite(e) ? Math.trunc(Math.abs(e)) : 0) % 12 + 1})`;
|
|
67
|
+
}
|
|
68
|
+
function m(e) {
|
|
69
|
+
let t = 2166136261;
|
|
70
|
+
for (let n = 0; n < e.length; n += 1) t ^= e.charCodeAt(n), t = Math.imul(t, 16777619);
|
|
71
|
+
return (t >>> 0) % 12;
|
|
72
|
+
}
|
|
73
|
+
var h = {
|
|
74
|
+
trigger: {
|
|
75
|
+
accent: "bg-node-trigger",
|
|
76
|
+
subtle: "bg-node-trigger-subtle",
|
|
77
|
+
text: "text-node-trigger",
|
|
78
|
+
border: "border-node-trigger"
|
|
79
|
+
},
|
|
80
|
+
action: {
|
|
81
|
+
accent: "bg-node-action",
|
|
82
|
+
subtle: "bg-node-action-subtle",
|
|
83
|
+
text: "text-node-action",
|
|
84
|
+
border: "border-node-action"
|
|
85
|
+
},
|
|
86
|
+
logic: {
|
|
87
|
+
accent: "bg-node-logic",
|
|
88
|
+
subtle: "bg-node-logic-subtle",
|
|
89
|
+
text: "text-node-logic",
|
|
90
|
+
border: "border-node-logic"
|
|
91
|
+
},
|
|
92
|
+
loop: {
|
|
93
|
+
accent: "bg-node-loop",
|
|
94
|
+
subtle: "bg-node-loop-subtle",
|
|
95
|
+
text: "text-node-loop",
|
|
96
|
+
border: "border-node-loop"
|
|
97
|
+
},
|
|
98
|
+
data: {
|
|
99
|
+
accent: "bg-node-data",
|
|
100
|
+
subtle: "bg-node-data-subtle",
|
|
101
|
+
text: "text-node-data",
|
|
102
|
+
border: "border-node-data"
|
|
103
|
+
},
|
|
104
|
+
integration: {
|
|
105
|
+
accent: "bg-node-integration",
|
|
106
|
+
subtle: "bg-node-integration-subtle",
|
|
107
|
+
text: "text-node-integration",
|
|
108
|
+
border: "border-node-integration"
|
|
109
|
+
},
|
|
110
|
+
ai: {
|
|
111
|
+
accent: "bg-node-ai",
|
|
112
|
+
subtle: "bg-node-ai-subtle",
|
|
113
|
+
text: "text-node-ai",
|
|
114
|
+
border: "border-node-ai"
|
|
115
|
+
},
|
|
116
|
+
human: {
|
|
117
|
+
accent: "bg-node-human",
|
|
118
|
+
subtle: "bg-node-human-subtle",
|
|
119
|
+
text: "text-node-human",
|
|
120
|
+
border: "border-node-human"
|
|
121
|
+
},
|
|
122
|
+
utility: {
|
|
123
|
+
accent: "bg-node-utility",
|
|
124
|
+
subtle: "bg-node-utility-subtle",
|
|
125
|
+
text: "text-node-utility",
|
|
126
|
+
border: "border-node-utility"
|
|
127
|
+
},
|
|
128
|
+
end: {
|
|
129
|
+
accent: "bg-node-end",
|
|
130
|
+
subtle: "bg-node-end-subtle",
|
|
131
|
+
text: "text-node-end",
|
|
132
|
+
border: "border-node-end"
|
|
133
|
+
},
|
|
134
|
+
default: {
|
|
135
|
+
accent: "bg-node-default",
|
|
136
|
+
subtle: "bg-node-default-subtle",
|
|
137
|
+
text: "text-node-default",
|
|
138
|
+
border: "border-node-default"
|
|
139
|
+
}
|
|
140
|
+
}, g = {
|
|
141
|
+
idle: "ring-node-state-idle",
|
|
142
|
+
queued: "ring-node-state-queued",
|
|
143
|
+
running: "ring-node-state-running",
|
|
144
|
+
success: "ring-node-state-success",
|
|
145
|
+
warning: "ring-node-state-warning",
|
|
146
|
+
error: "ring-node-state-error",
|
|
147
|
+
skipped: "ring-node-state-skipped"
|
|
148
|
+
}, _ = {
|
|
149
|
+
string: "text-datatype-string",
|
|
150
|
+
number: "text-datatype-number",
|
|
151
|
+
boolean: "text-datatype-boolean",
|
|
152
|
+
object: "text-datatype-object",
|
|
153
|
+
array: "text-datatype-array",
|
|
154
|
+
date: "text-datatype-date",
|
|
155
|
+
binary: "text-datatype-binary",
|
|
156
|
+
any: "text-datatype-any"
|
|
157
|
+
};
|
|
158
|
+
//#endregion
|
|
159
|
+
export { i as CHART_SERIES_COUNT, r as DATA_TYPES, n as EDGE_KINDS, e as NODE_CATEGORIES, t as NODE_STATES, p as chartSeriesColor, m as chartSeriesIndex, f as dataTypeColor, _ as dataTypeTextClasses, d as edgeColor, h as nodeCategoryClasses, c as nodeCategoryColor, l as nodeCategorySubtleColor, u as nodeStateColor, g as nodeStateRingClasses, s as toDataType, o as toNodeCategory };
|
|
@@ -8,6 +8,8 @@ export { createApolloClient } from './apollo';
|
|
|
8
8
|
export type { CreateApolloClientOptions } from './apollo';
|
|
9
9
|
export { statusTokens, trendTokens, progressTokens, categoryTokens, alertTokens, getStatusTokens, getStatusBadgeTokens, getTrendTokens, getProgressTokens, getCategoryTokens, getAlertTokens, } from './tokens';
|
|
10
10
|
export type { SemanticStatus } from './tokens';
|
|
11
|
+
export { NODE_CATEGORIES, NODE_STATES, EDGE_KINDS, DATA_TYPES, CHART_SERIES_COUNT, toNodeCategory, toDataType, nodeCategoryColor, nodeCategorySubtleColor, nodeStateColor, edgeColor, dataTypeColor, chartSeriesColor, chartSeriesIndex, nodeCategoryClasses, nodeStateRingClasses, dataTypeTextClasses, } from './canvasTokens';
|
|
12
|
+
export type { NodeCategory, NodeState, EdgeKind, DataType, NodeCategoryClasses, } from './canvasTokens';
|
|
11
13
|
export { formatCurrency, formatCurrencyCompact, formatDate, formatDateTime, formatRelativeTime, formatDuration, formatTime, formatNumber, formatPercentage, formatBytes, formatCompactNumber, formatOrdinal, truncateText, capitalizeFirst, capitalizeWords, slugify, toCamelCase, toPascalCase, pluralize, formatList, } from './format';
|
|
12
14
|
export { lazyWithRetry, isChunkLoadError } from './lazyWithRetry';
|
|
13
15
|
export { resolveGatewayBases, installGatewayFetchRewrite, suppressConsole, } from './gatewayFetchRewrite';
|