@burdenoff/microfe-bigconsole 2026.1007.10 → 2026.1007.11
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/bigconsole/assistant/displayCopy.d.ts +33 -0
- package/dist/bigconsole/assistant/displayCopy.d.ts.map +1 -0
- package/dist/bigconsole/assistant/pageContext.d.ts +14 -0
- package/dist/bigconsole/assistant/pageContext.d.ts.map +1 -1
- package/dist/bigconsole/assistant/pageContext.js +6 -1
- package/dist/bigconsole/assistant/pageContext.js.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkCard.d.ts.map +1 -1
- package/dist/bigconsole/components/datasink/DataSinkCard.js +28 -27
- package/dist/bigconsole/components/datasink/DataSinkCard.js.map +1 -1
- package/dist/bigconsole/constants/backendErrors.js +96 -0
- package/dist/bigconsole/constants/backendErrors.js.map +1 -0
- package/dist/bigconsole/hooks/useDataSinkAlerts.d.ts +23 -0
- package/dist/bigconsole/hooks/useDataSinkAlerts.d.ts.map +1 -1
- package/dist/bigconsole/hooks/useDataSinkAlerts.js +138 -113
- package/dist/bigconsole/hooks/useDataSinkAlerts.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkAlertsPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/DataSinkAlertsPage.js +53 -53
- package/dist/bigconsole/pages/DataSinkAlertsPage.js.map +1 -1
- package/dist/bigconsole/utils/backendError.d.ts +18 -0
- package/dist/bigconsole/utils/backendError.d.ts.map +1 -1
- package/dist/bigconsole/utils/backendError.js +44 -0
- package/dist/bigconsole/utils/backendError.js.map +1 -0
- package/dist/bigconsole/workflowOpen.d.ts.map +1 -1
- package/dist/bigconsole/workflowOpen.js +15 -14
- package/dist/bigconsole/workflowOpen.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AssistantModeConfig } from '@burdenoff/fe-libs/shared/assistant/conversation';
|
|
2
|
+
|
|
3
|
+
/** Keys longer than this get a hash suffix instead of the full slug (as fe-libs). */
|
|
4
|
+
export declare const MAX_COPY_SLUG_LENGTH = 64;
|
|
5
|
+
/**
|
|
6
|
+
* lower-camel ASCII of an English string, accents folded and every
|
|
7
|
+
* non-alphanumeric run a word break: `"What can I do on this screen?"` →
|
|
8
|
+
* `whatCanIDoOnThisScreen`. A slug over {@link MAX_COPY_SLUG_LENGTH} keeps a
|
|
9
|
+
* readable prefix plus a hash of the whole English.
|
|
10
|
+
*
|
|
11
|
+
* ★ The same function as fe-libs' `assistantCopySlug` (PR-I18N,
|
|
12
|
+
* `shared/assistant/productCopy.ts`), which derives the keys it looks up at
|
|
13
|
+
* display time. Replace this copy with the fe-libs import once that ships.
|
|
14
|
+
*
|
|
15
|
+
* @throws when nothing ASCII-alphanumeric is left — fe-libs shows such copy as
|
|
16
|
+
* passed, so a key for it could never be asked for.
|
|
17
|
+
*/
|
|
18
|
+
export declare function assistantCopySlug(english: string): string;
|
|
19
|
+
/** The part of a mode whose copy this module keys. */
|
|
20
|
+
export type AssistantModeDisplaySource = Pick<AssistantModeConfig, 'id' | 'description' | 'suggestions'>;
|
|
21
|
+
/**
|
|
22
|
+
* Relative key → English for each mode's description and suggestion chips, and
|
|
23
|
+
* for each page label.
|
|
24
|
+
*
|
|
25
|
+
* @throws when two different English strings would share a key.
|
|
26
|
+
*/
|
|
27
|
+
export declare function assistantDisplayCopy(args: {
|
|
28
|
+
modes: readonly AssistantModeDisplaySource[];
|
|
29
|
+
pageLabels: readonly string[];
|
|
30
|
+
}): Record<string, string>;
|
|
31
|
+
/** BigConsole's display copy as FULL keys (`bigconsole.assistant.…`), for the seed bundle. */
|
|
32
|
+
export declare function bigconsoleAssistantDisplaySeedCopy(): Record<string, string>;
|
|
33
|
+
//# sourceMappingURL=displayCopy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"displayCopy.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/assistant/displayCopy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAO5F,qFAAqF;AACrF,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAcvC;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAYzD;AAED,sDAAsD;AACtD,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAAC,mBAAmB,EAAE,IAAI,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;AAYzG;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,KAAK,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC7C,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUzB;AAED,8FAA8F;AAC9F,wBAAgB,kCAAkC,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ3E"}
|
|
@@ -39,6 +39,20 @@ export type PageContext = {
|
|
|
39
39
|
timestamp: string;
|
|
40
40
|
};
|
|
41
41
|
export declare function gatherPageContext(): PageContext;
|
|
42
|
+
/**
|
|
43
|
+
* Route segment → human label.
|
|
44
|
+
*
|
|
45
|
+
* ★ Every top-level segment BigConsole routes to (`BigConsoleRoutes.tsx`),
|
|
46
|
+
* except `/list`, which only redirects. Anything missing falls through to a
|
|
47
|
+
* title-cased segment, which is right far more often than a wrong
|
|
48
|
+
* label would be — and a wrong answer here is worse than none, because the panel
|
|
49
|
+
* states it as fact.
|
|
50
|
+
*
|
|
51
|
+
* Each label is also seeded as `bigconsole.assistant.page.<slug>`
|
|
52
|
+
* (`displayCopy.ts`) so the panel can SHOW it translated; the English here is
|
|
53
|
+
* what the model is told.
|
|
54
|
+
*/
|
|
55
|
+
export declare const BIGCONSOLE_PAGE_LABELS: Readonly<Record<string, string>>;
|
|
42
56
|
/**
|
|
43
57
|
* A human label for where the user is right now, for the shared panel.
|
|
44
58
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageContext.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/assistant/pageContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,UAAU,wBAAwB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,WAAW,GAAG;IAGxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAGpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAgB,iBAAiB,IAAI,WAAW,CAiB/C;
|
|
1
|
+
{"version":3,"file":"pageContext.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/assistant/pageContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,UAAU,wBAAwB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,WAAW,GAAG;IAGxB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IAGpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAgB,iBAAiB,IAAI,WAAW,CAiB/C;AAKD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcnE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAY5C;AAMD;;;;;;;GAOG;AACH,wBAAgB,oCAAoC,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,wBAAwB,CA4C/G"}
|
|
@@ -18,9 +18,14 @@ var n = "Home", r = {
|
|
|
18
18
|
home: n,
|
|
19
19
|
dashboards: "Dashboards",
|
|
20
20
|
datasinks: "Data sinks",
|
|
21
|
+
datasources: "Data sources",
|
|
22
|
+
insights: "Insights",
|
|
21
23
|
parsers: "Parsers",
|
|
22
24
|
pipelines: "Pipelines",
|
|
23
|
-
|
|
25
|
+
settings: "Settings",
|
|
26
|
+
widgets: "Widgets",
|
|
27
|
+
workflows: "Workflows",
|
|
28
|
+
workflow: "Workflows"
|
|
24
29
|
};
|
|
25
30
|
function i() {
|
|
26
31
|
let { currentPage: e } = t(), i = e.split("/").filter(Boolean), a = (i[0] === "bigconsole" ? i[1] : i[0]) ?? "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageContext.js","names":[],"sources":["../../../src/bigconsole/assistant/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering for BigConsole — captures the user's current browser\n * context to be sent alongside every assistant prompt for better AI awareness.\n *\n * Mirrors microfe-vibecontrols' `utils/pageContext.ts`. The agent filters the\n * payload to an allow-list (`ai-assistant/src/context-loader.ts` →\n * `ALLOWED_CONTEXT_KEYS`), so the keys MUST be `currentUrl` (NOT `activeUrl`)\n * and the generic `entityType` / `entityId`, or the value is silently dropped.\n */\n\nimport { BIGCONSOLE_PRODUCT } from './product';\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * ★★ A `type`, NOT an `interface`, and the difference is load-bearing.\n *\n * fe-libs' product seam declares `gatherPageContext?: () => PageContext` against\n * ITS OWN `PageContext`, which carries an index signature\n * (`[key: string]: unknown`) so a product may add keys of its own. TypeScript\n * gives a type alias an IMPLICIT index signature and an interface NONE —\n * an interface stays open to declaration merging, so the compiler cannot know\n * its full set of keys and refuses the assignment.\n *\n * So this exact shape, written as an interface, is not assignable to fe-libs'\n * parameter: `assistantProduct.ts` fails with TS2322 while the runtime value is\n * perfectly correct. Changing this back to `interface` re-breaks the seam.\n */\nexport type PageContext = {\n // `currentUrl` (NOT `activeUrl`) — must match the agent's allowed-context-key\n // contract, otherwise the agent filters it out.\n currentUrl: string;\n currentPage: string;\n // The entity the user is currently looking at, resolved from the route. Lets\n // the assistant act on \"this / current / here\" without asking for an id.\n entityType?: string;\n entityId?: string;\n platform: string;\n version: string;\n viewportSize: string;\n userAgent: string;\n timestamp: string;\n};\n\nexport function gatherPageContext(): PageContext {\n const url = window.location.href;\n const pathSegments = window.location.pathname.split('/').filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join('/') || 'home';\n const entity = resolveBigConsoleConversationContext(window.location.pathname, window.location.search);\n\n return {\n currentUrl: url,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n platform: BIGCONSOLE_PRODUCT,\n version: import.meta.env.VITE_APP_VERSION ?? '2026.430.500',\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n userAgent: navigator.userAgent,\n timestamp: new Date().toISOString(),\n };\n}\n\n/** Shown to the user as \"where you are\", e.g. in the panel's empty state. */\nconst HOME_LABEL = 'Home';\n\n/**\n * Route segment → human label.\n *\n * ★
|
|
1
|
+
{"version":3,"file":"pageContext.js","names":[],"sources":["../../../src/bigconsole/assistant/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering for BigConsole — captures the user's current browser\n * context to be sent alongside every assistant prompt for better AI awareness.\n *\n * Mirrors microfe-vibecontrols' `utils/pageContext.ts`. The agent filters the\n * payload to an allow-list (`ai-assistant/src/context-loader.ts` →\n * `ALLOWED_CONTEXT_KEYS`), so the keys MUST be `currentUrl` (NOT `activeUrl`)\n * and the generic `entityType` / `entityId`, or the value is silently dropped.\n */\n\nimport { BIGCONSOLE_PRODUCT } from './product';\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * ★★ A `type`, NOT an `interface`, and the difference is load-bearing.\n *\n * fe-libs' product seam declares `gatherPageContext?: () => PageContext` against\n * ITS OWN `PageContext`, which carries an index signature\n * (`[key: string]: unknown`) so a product may add keys of its own. TypeScript\n * gives a type alias an IMPLICIT index signature and an interface NONE —\n * an interface stays open to declaration merging, so the compiler cannot know\n * its full set of keys and refuses the assignment.\n *\n * So this exact shape, written as an interface, is not assignable to fe-libs'\n * parameter: `assistantProduct.ts` fails with TS2322 while the runtime value is\n * perfectly correct. Changing this back to `interface` re-breaks the seam.\n */\nexport type PageContext = {\n // `currentUrl` (NOT `activeUrl`) — must match the agent's allowed-context-key\n // contract, otherwise the agent filters it out.\n currentUrl: string;\n currentPage: string;\n // The entity the user is currently looking at, resolved from the route. Lets\n // the assistant act on \"this / current / here\" without asking for an id.\n entityType?: string;\n entityId?: string;\n platform: string;\n version: string;\n viewportSize: string;\n userAgent: string;\n timestamp: string;\n};\n\nexport function gatherPageContext(): PageContext {\n const url = window.location.href;\n const pathSegments = window.location.pathname.split('/').filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join('/') || 'home';\n const entity = resolveBigConsoleConversationContext(window.location.pathname, window.location.search);\n\n return {\n currentUrl: url,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n platform: BIGCONSOLE_PRODUCT,\n version: import.meta.env.VITE_APP_VERSION ?? '2026.430.500',\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n userAgent: navigator.userAgent,\n timestamp: new Date().toISOString(),\n };\n}\n\n/** Shown to the user as \"where you are\", e.g. in the panel's empty state. */\nconst HOME_LABEL = 'Home';\n\n/**\n * Route segment → human label.\n *\n * ★ Every top-level segment BigConsole routes to (`BigConsoleRoutes.tsx`),\n * except `/list`, which only redirects. Anything missing falls through to a\n * title-cased segment, which is right far more often than a wrong\n * label would be — and a wrong answer here is worse than none, because the panel\n * states it as fact.\n *\n * Each label is also seeded as `bigconsole.assistant.page.<slug>`\n * (`displayCopy.ts`) so the panel can SHOW it translated; the English here is\n * what the model is told.\n */\nexport const BIGCONSOLE_PAGE_LABELS: Readonly<Record<string, string>> = {\n home: HOME_LABEL,\n dashboards: 'Dashboards',\n datasinks: 'Data sinks',\n datasources: 'Data sources',\n insights: 'Insights',\n parsers: 'Parsers',\n pipelines: 'Pipelines',\n settings: 'Settings',\n widgets: 'Widgets',\n workflows: 'Workflows',\n // `/workflow/:id/:version` is the workflow builder's legacy route; it is\n // part of the Workflows area, not a page of its own.\n workflow: 'Workflows',\n};\n\n/**\n * A human label for where the user is right now, for the shared panel.\n *\n * ★★ The `/bigconsole` MOUNT SEGMENT IS SKIPPED. This MFE mounts under\n * `/bigconsole` in the host shell, so the first segment is the product name on\n * every single page — without this, every location would be described as\n * \"Bigconsole\", which is both useless and wrong.\n *\n * ★ Derived from `gatherPageContext().currentPage` rather than reading\n * `window.location` a second time, so the label and the agent's structured\n * context can never disagree about which page they describe.\n */\nexport function describeCurrentPage(): string {\n const { currentPage } = gatherPageContext();\n const segments = currentPage.split('/').filter(Boolean);\n const first = (segments[0] === BIGCONSOLE_PRODUCT ? segments[1] : segments[0]) ?? '';\n if (!first || first === 'home') return HOME_LABEL;\n return (\n BIGCONSOLE_PAGE_LABELS[first] ??\n first\n .split('-')\n .map((word) => (word ? word.charAt(0).toUpperCase() + word.slice(1) : word))\n .join(' ')\n );\n}\n\nfunction matchPath(pattern: RegExp, pathname: string): RegExpMatchArray | null {\n return pathname.match(pattern);\n}\n\n/**\n * Maps the current BigConsole route to `{ entityType, entityId }`. The BigConsole\n * MFE mounts under the `/bigconsole` base path in the host shell, so detail\n * routes are matched as `/bigconsole/<collection>/:id`.\n *\n * More specific routes (e.g. dashboard-scoped parsers, builder/edit sub-routes)\n * are matched before their parent so the most relevant entity wins.\n */\nexport function resolveBigConsoleConversationContext(pathname: string, search: string): ConversationContextShape {\n const params = new URLSearchParams(search);\n\n const directMatches: Array<[RegExp, string]> = [\n // Dashboard-scoped parser detail (more specific than the bare parser route).\n [/^\\/bigconsole\\/dashboards\\/[^/]+\\/parsers\\/([^/]+)(?:\\/edit)?$/, 'BIGCONSOLE_PARSER'],\n // Dashboard detail + builder.\n [/^\\/bigconsole\\/dashboards\\/([^/]+)(?:\\/builder)?$/, 'BIGCONSOLE_DASHBOARD'],\n // Data sinks.\n [/^\\/bigconsole\\/datasinks\\/([^/]+)(?:\\/edit)?$/, 'BIGCONSOLE_DATASINK'],\n // Parsers.\n [/^\\/bigconsole\\/parsers\\/([^/]+)(?:\\/edit)?$/, 'BIGCONSOLE_PARSER'],\n // Pipelines.\n [/^\\/bigconsole\\/pipelines\\/([^/]+)(?:\\/edit)?$/, 'BIGCONSOLE_PIPELINE'],\n // Workflows (BigConsole-native list/view; the SDK builder uses /workflow/...).\n [/^\\/bigconsole\\/workflows\\/([^/]+)(?:\\/edit)?$/, 'BIGCONSOLE_WORKFLOW'],\n ];\n\n for (const [pattern, entityType] of directMatches) {\n const match = matchPath(pattern, pathname);\n if (match && match[1] && !isReservedSegment(match[1])) {\n return {\n entityType,\n entityId: match[1],\n metadata: {\n routePattern: pattern.source,\n },\n };\n }\n }\n\n const activeTab =\n params.get('tab') ??\n (() => {\n const segments = pathname.split('/').filter(Boolean);\n return segments.length > 2 ? segments[segments.length - 1] : undefined;\n })();\n\n return {\n activeTab: activeTab ?? undefined,\n metadata: {\n ...(activeTab ? { activeTab } : {}),\n },\n };\n}\n\n/**\n * Static segments that share a route shape with `:id` detail routes\n * (e.g. `/bigconsole/datasinks/new`, `/bigconsole/parsers/new`). These are\n * pages, not entities, so they must not be reported as an `entityId`.\n */\nfunction isReservedSegment(segment: string): boolean {\n return segment === 'new' || segment === 'builder' || segment === 'list';\n}\n"],"mappings":";;AAiDA,SAAgB,IAAiC;CAC/C,IAAM,IAAM,OAAO,SAAS,MAEtB,IADe,OAAO,SAAS,SAAS,MAAM,IAAI,CAAC,OAAO,QAAQ,CACvC,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,IAAI,QACpD,IAAS,EAAqC,OAAO,SAAS,UAAU,OAAO,SAAS,OAAO;AAErG,QAAO;EACL,YAAY;EACZ;EACA,YAAY,EAAO;EACnB,UAAU,EAAO;EACjB,UAAU;EACV,SAA6C;EAC7C,cAAc,GAAG,OAAO,WAAW,GAAG,OAAO;EAC7C,WAAW,UAAU;EACrB,4BAAW,IAAI,MAAM,EAAC,aAAa;EACpC;;AAIH,IAAM,IAAa,QAeN,IAA2D;CACtE,MAAM;CACN,YAAY;CACZ,WAAW;CACX,aAAa;CACb,UAAU;CACV,SAAS;CACT,WAAW;CACX,UAAU;CACV,SAAS;CACT,WAAW;CAGX,UAAU;CACX;AAcD,SAAgB,IAA8B;CAC5C,IAAM,EAAE,mBAAgB,GAAmB,EACrC,IAAW,EAAY,MAAM,IAAI,CAAC,OAAO,QAAQ,EACjD,KAAS,EAAS,OAAA,eAA4B,EAAS,KAAK,EAAS,OAAO;AAElF,QADI,CAAC,KAAS,MAAU,SAAe,IAErC,EAAuB,MACvB,EACG,MAAM,IAAI,CACV,KAAK,MAAU,KAAO,EAAK,OAAO,EAAE,CAAC,aAAa,GAAG,EAAK,MAAM,EAAE,CAAS,CAC3E,KAAK,IAAI;;AAIhB,SAAS,EAAU,GAAiB,GAA2C;AAC7E,QAAO,EAAS,MAAM,EAAQ;;AAWhC,SAAgB,EAAqC,GAAkB,GAA0C;CAC/G,IAAM,IAAS,IAAI,gBAAgB,EAAO;AAiB1C,MAAK,IAAM,CAAC,GAAS,MAf0B;EAE7C,CAAC,kEAAkE,oBAAoB;EAEvF,CAAC,qDAAqD,uBAAuB;EAE7E,CAAC,iDAAiD,sBAAsB;EAExE,CAAC,+CAA+C,oBAAoB;EAEpE,CAAC,iDAAiD,sBAAsB;EAExE,CAAC,iDAAiD,sBAAsB;EACzE,EAEkD;EACjD,IAAM,IAAQ,EAAU,GAAS,EAAS;AAC1C,MAAI,KAAS,EAAM,MAAM,CAAC,EAAkB,EAAM,GAAG,CACnD,QAAO;GACL;GACA,UAAU,EAAM;GAChB,UAAU,EACR,cAAc,EAAQ,QACvB;GACF;;CAIL,IAAM,IACJ,EAAO,IAAI,MAAM,WACV;EACL,IAAM,IAAW,EAAS,MAAM,IAAI,CAAC,OAAO,QAAQ;AACpD,SAAO,EAAS,SAAS,IAAI,EAAS,EAAS,SAAS,KAAK,KAAA;KAC3D;AAEN,QAAO;EACL,WAAW,KAAa,KAAA;EACxB,UAAU,EACR,GAAI,IAAY,EAAE,cAAW,GAAG,EAAE,EACnC;EACF;;AAQH,SAAS,EAAkB,GAA0B;AACnD,QAAO,MAAY,SAAS,MAAY,aAAa,MAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataSinkCard.d.ts","sourceRoot":"","sources":["../../../../src/bigconsole/components/datasink/DataSinkCard.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"DataSinkCard.d.ts","sourceRoot":"","sources":["../../../../src/bigconsole/components/datasink/DataSinkCard.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAahE,UAAU,iBAAiB;IACzB,oBAAoB;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,2BAA2B;IAC3B,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,oCAAoC;IACpC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,oCAAoC;IACpC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,uCAAuC;IACvC,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,sCAAsC;IACtC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,sCAAsC;IACtC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,iCAAiC;IACjC,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,kGAAkG;IAClG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wGAAwG;IACxG,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sGAAsG;IACtG,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAMD,eAAO,MAAM,YAAY,yDA+MvB,CAAC;AAEH,eAAe,YAAY,CAAC"}
|
|
@@ -4,12 +4,11 @@ import t from "./DataSinkStatusBadge.js";
|
|
|
4
4
|
import { formatByteSize as n } from "../../utils/format.js";
|
|
5
5
|
import { memo as r, useCallback as i } from "react";
|
|
6
6
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
7
|
-
import {
|
|
7
|
+
import { useI18n as s } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
|
+
import { formatDistanceToNow as c } from "date-fns";
|
|
8
9
|
//#region src/bigconsole/components/datasink/DataSinkCard.tsx
|
|
9
|
-
var
|
|
10
|
-
let
|
|
11
|
-
t.stopPropagation(), l?.(e.id);
|
|
12
|
-
}, [e.id, l]), y = i((t) => {
|
|
10
|
+
var l = `inline-flex min-h-[var(--size-controlHeight-md)] items-center justify-center rounded-button px-3 py-1.5 text-xs font-medium motion-safe:transition-colors ${e}`, u = r(function({ dataSink: e, setupState: r, onView: u, onEdit: d, onRefresh: f, onExport: p, onDelete: m, onContinueSetup: h, canEdit: g = !0, canRefresh: _ = !0, canDelete: v = !0 }) {
|
|
11
|
+
let y = i((t) => {
|
|
13
12
|
t.stopPropagation(), u?.(e.id);
|
|
14
13
|
}, [e.id, u]), b = i((t) => {
|
|
15
14
|
t.stopPropagation(), d?.(e.id);
|
|
@@ -19,10 +18,12 @@ var c = `inline-flex min-h-[var(--size-controlHeight-md)] items-center justify-c
|
|
|
19
18
|
t.stopPropagation(), p?.(e.id);
|
|
20
19
|
}, [e.id, p]), C = i((t) => {
|
|
21
20
|
t.stopPropagation(), m?.(e.id);
|
|
22
|
-
}, [e.id, m]), w = (
|
|
21
|
+
}, [e.id, m]), w = i((t) => {
|
|
22
|
+
t.stopPropagation(), h?.(e.id);
|
|
23
|
+
}, [e.id, h]), { t: T } = s(), E = (r ?? e.setupState) === "completed", D = e.lastRefreshedAt ? c(new Date(e.lastRefreshedAt), { addSuffix: !0 }) : T("bigconsole.dataSinks.view.never", "Never");
|
|
23
24
|
return /* @__PURE__ */ o("article", {
|
|
24
25
|
className: "\n min-w-0\n cursor-pointer\n rounded-card\n border border-transparent\n bg-bg-sunken\n p-card-padding\n hover:border-[var(--color-action-primary-bg)]\n motion-safe:transition-colors\n ",
|
|
25
|
-
onClick:
|
|
26
|
+
onClick: y,
|
|
26
27
|
children: [
|
|
27
28
|
/* @__PURE__ */ o("div", {
|
|
28
29
|
className: "mb-3 flex items-start justify-between gap-icon-gap",
|
|
@@ -60,7 +61,7 @@ var c = `inline-flex min-h-[var(--size-controlHeight-md)] items-center justify-c
|
|
|
60
61
|
strokeWidth: 2,
|
|
61
62
|
d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
62
63
|
})
|
|
63
|
-
}),
|
|
64
|
+
}), D]
|
|
64
65
|
}),
|
|
65
66
|
/* @__PURE__ */ o("span", {
|
|
66
67
|
className: "flex items-center gap-1",
|
|
@@ -100,14 +101,14 @@ var c = `inline-flex min-h-[var(--size-controlHeight-md)] items-center justify-c
|
|
|
100
101
|
})
|
|
101
102
|
]
|
|
102
103
|
}),
|
|
103
|
-
!
|
|
104
|
+
!E && /* @__PURE__ */ o("div", {
|
|
104
105
|
className: "mb-3 flex items-center justify-between gap-icon-gap rounded-input border border-[var(--color-status-warning-border)] bg-[var(--color-status-warning-bgSubtle)] p-2",
|
|
105
106
|
children: [/* @__PURE__ */ a("span", {
|
|
106
107
|
className: "text-xs text-[var(--color-status-warning-text)]",
|
|
107
108
|
children: "Setup incomplete"
|
|
108
109
|
}), /* @__PURE__ */ a("button", {
|
|
109
110
|
type: "button",
|
|
110
|
-
onClick:
|
|
111
|
+
onClick: w,
|
|
111
112
|
className: "rounded-button px-1 text-xs font-medium text-text-link hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-bg-surface",
|
|
112
113
|
children: "Continue"
|
|
113
114
|
})]
|
|
@@ -116,34 +117,34 @@ var c = `inline-flex min-h-[var(--size-controlHeight-md)] items-center justify-c
|
|
|
116
117
|
className: "flex flex-wrap items-center gap-2 border-t border-[var(--color-border-subtle)] pt-2",
|
|
117
118
|
children: [
|
|
118
119
|
/* @__PURE__ */ a("button", {
|
|
119
|
-
type: "button",
|
|
120
|
-
onClick: v,
|
|
121
|
-
className: `${c} flex-1 bg-bg-surface text-text-primary hover:bg-bg-elevated`,
|
|
122
|
-
children: "View"
|
|
123
|
-
}),
|
|
124
|
-
h && /* @__PURE__ */ a("button", {
|
|
125
120
|
type: "button",
|
|
126
121
|
onClick: y,
|
|
127
|
-
className: `${
|
|
128
|
-
children: "
|
|
122
|
+
className: `${l} flex-1 bg-bg-surface text-text-primary hover:bg-bg-elevated`,
|
|
123
|
+
children: T("bigconsole.dataSinks.actions.view", "View")
|
|
129
124
|
}),
|
|
130
125
|
g && /* @__PURE__ */ a("button", {
|
|
131
126
|
type: "button",
|
|
132
127
|
onClick: b,
|
|
133
|
-
className: `${
|
|
134
|
-
children: "
|
|
128
|
+
className: `${l} text-text-secondary hover:bg-bg-surface hover:text-text-primary`,
|
|
129
|
+
children: T("bigconsole.dataSinks.actions.edit", "Edit")
|
|
135
130
|
}),
|
|
136
|
-
|
|
131
|
+
_ && /* @__PURE__ */ a("button", {
|
|
137
132
|
type: "button",
|
|
138
133
|
onClick: x,
|
|
139
|
-
className: `${
|
|
140
|
-
children: "
|
|
134
|
+
className: `${l} text-text-secondary hover:bg-bg-surface hover:text-text-primary`,
|
|
135
|
+
children: T("bigconsole.dataSinks.actions.refresh", "Refresh")
|
|
141
136
|
}),
|
|
142
|
-
|
|
137
|
+
p && /* @__PURE__ */ a("button", {
|
|
143
138
|
type: "button",
|
|
144
139
|
onClick: S,
|
|
145
|
-
className: `${
|
|
146
|
-
children: "
|
|
140
|
+
className: `${l} text-text-secondary hover:bg-bg-surface hover:text-text-primary`,
|
|
141
|
+
children: T("bigconsole.dataSinks.actions.export", "Export")
|
|
142
|
+
}),
|
|
143
|
+
v && /* @__PURE__ */ a("button", {
|
|
144
|
+
type: "button",
|
|
145
|
+
onClick: C,
|
|
146
|
+
className: `${l} text-status-error-text hover:bg-[var(--color-status-error-bgSubtle)]`,
|
|
147
|
+
children: T("bigconsole.dataSinks.actions.delete", "Delete")
|
|
147
148
|
})
|
|
148
149
|
]
|
|
149
150
|
})
|
|
@@ -151,6 +152,6 @@ var c = `inline-flex min-h-[var(--size-controlHeight-md)] items-center justify-c
|
|
|
151
152
|
});
|
|
152
153
|
});
|
|
153
154
|
//#endregion
|
|
154
|
-
export {
|
|
155
|
+
export { u as default };
|
|
155
156
|
|
|
156
157
|
//# sourceMappingURL=DataSinkCard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataSinkCard.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/DataSinkCard.tsx"],"sourcesContent":["/**\n * DataSink Card\n *\n * Card component for displaying DataSink information in a list/grid view.\n */\n\nimport { memo, useCallback } from 'react';\nimport { formatDistanceToNow } from 'date-fns';\nimport { DataSinkStatusBadge } from './DataSinkStatusBadge';\nimport { SECTION_FOCUS_RING } from '../common';\nimport { formatByteSize } from '../../utils';\nimport type { DataSink, DataSinkSetupState } from '../../types';\n\n/**\n * Shared class recipe for the card's five action buttons. `min-h-[var(--size-controlHeight-md)]`\n * keeps every one at the 40px touch minimum once the row wraps on mobile.\n */\nconst CARD_ACTION =\n `inline-flex min-h-[var(--size-controlHeight-md)] items-center justify-center rounded-button px-3 py-1.5 text-xs font-medium motion-safe:transition-colors ${SECTION_FOCUS_RING}` as const;\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface DataSinkCardProps {\n /** DataSink data */\n dataSink: DataSink;\n /** Setup state override */\n setupState?: DataSinkSetupState;\n /** Callback when view is clicked */\n onView?: (id: string) => void;\n /** Callback when edit is clicked */\n onEdit?: (id: string) => void;\n /** Callback when refresh is clicked */\n onRefresh?: (id: string) => void;\n /** Callback when export is clicked */\n onExport?: (id: string) => void;\n /** Callback when delete is clicked */\n onDelete?: (id: string) => void;\n /** Callback to continue setup */\n onContinueSetup?: (id: string) => void;\n /** Whether the current actor may edit this DataSink (gates the Edit action). Defaults to true. */\n canEdit?: boolean;\n /** Whether the current actor may refresh this DataSink (gates the Refresh action). Defaults to true. */\n canRefresh?: boolean;\n /** Whether the current actor may delete this DataSink (gates the Delete action). Defaults to true. */\n canDelete?: boolean;\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const DataSinkCard = memo(function DataSinkCard({\n dataSink,\n setupState,\n onView,\n onEdit,\n onRefresh,\n onExport,\n onDelete,\n onContinueSetup,\n canEdit = true,\n canRefresh = true,\n canDelete = true,\n}: DataSinkCardProps) {\n // Event handlers\n const handleView = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onView?.(dataSink.id);\n },\n [dataSink.id, onView]\n );\n\n const handleEdit = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onEdit?.(dataSink.id);\n },\n [dataSink.id, onEdit]\n );\n\n const handleRefresh = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onRefresh?.(dataSink.id);\n },\n [dataSink.id, onRefresh]\n );\n\n const handleExport = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onExport?.(dataSink.id);\n },\n [dataSink.id, onExport]\n );\n\n const handleDelete = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onDelete?.(dataSink.id);\n },\n [dataSink.id, onDelete]\n );\n\n const handleContinueSetup = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onContinueSetup?.(dataSink.id);\n },\n [dataSink.id, onContinueSetup]\n );\n\n const currentSetupState = setupState ?? dataSink.setupState;\n const isSetupComplete = currentSetupState === 'completed';\n\n // Format last refreshed time\n const lastRefreshedText = dataSink.lastRefreshedAt\n ? formatDistanceToNow(new Date(dataSink.lastRefreshedAt), { addSuffix: true })\n : 'Never';\n\n return (\n // A card is a tile inside the page's `primary` results section, so it steps\n // down to the `muted` recipe (recessed surface, transparent border) instead\n // of competing with the panel that contains it.\n <article\n className={`\n min-w-0\n cursor-pointer\n rounded-card\n border border-transparent\n bg-bg-sunken\n p-card-padding\n hover:border-[var(--color-action-primary-bg)]\n motion-safe:transition-colors\n `}\n onClick={handleView}\n >\n {/* Identity */}\n <div className=\"mb-3 flex items-start justify-between gap-icon-gap\">\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">{dataSink.name || 'Untitled data sink'}</h3>\n <p className=\"mt-0.5 truncate font-mono text-xs text-text-secondary\">{dataSink.key}</p>\n </div>\n <DataSinkStatusBadge status={dataSink.status} size=\"sm\" />\n </div>\n\n {/* Description */}\n {dataSink.description && <p className=\"mb-3 line-clamp-2 text-xs text-text-secondary\">{dataSink.description}</p>}\n\n {/* Stats */}\n <div className=\"mb-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n {lastRefreshedText}\n </span>\n {/* `sizeBytes` ships in DataSinkListItem on every list query but was\n never shown here — it is how you tell a populated sink from an empty\n one without opening it. */}\n <span className=\"flex items-center gap-1\" title=\"Stored payload size\">\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4\"\n />\n </svg>\n {formatByteSize(dataSink.sizeBytes)}\n </span>\n {dataSink.linkedWorkflowCount !== undefined && dataSink.linkedWorkflowCount > 0 && (\n <span className=\"flex items-center gap-1\">\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1\"\n />\n </svg>\n {dataSink.linkedWorkflowCount} workflow{dataSink.linkedWorkflowCount !== 1 ? 's' : ''}\n </span>\n )}\n </div>\n\n {/* Setup state — a warning strip, so it carries the warning tone. */}\n {!isSetupComplete && (\n <div className=\"mb-3 flex items-center justify-between gap-icon-gap rounded-input border border-[var(--color-status-warning-border)] bg-[var(--color-status-warning-bgSubtle)] p-2\">\n <span className=\"text-xs text-[var(--color-status-warning-text)]\">Setup incomplete</span>\n <button\n type=\"button\"\n onClick={handleContinueSetup}\n className={`rounded-button px-1 text-xs font-medium text-text-link hover:underline ${SECTION_FOCUS_RING}`}\n >\n Continue\n </button>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-wrap items-center gap-2 border-t border-[var(--color-border-subtle)] pt-2\">\n <button\n type=\"button\"\n onClick={handleView}\n className={`${CARD_ACTION} flex-1 bg-bg-surface text-text-primary hover:bg-bg-elevated`}\n >\n View\n </button>\n {canEdit && (\n <button\n type=\"button\"\n onClick={handleEdit}\n className={`${CARD_ACTION} text-text-secondary hover:bg-bg-surface hover:text-text-primary`}\n >\n Edit\n </button>\n )}\n {canRefresh && (\n <button\n type=\"button\"\n onClick={handleRefresh}\n className={`${CARD_ACTION} text-text-secondary hover:bg-bg-surface hover:text-text-primary`}\n >\n Refresh\n </button>\n )}\n {onExport && (\n <button\n type=\"button\"\n onClick={handleExport}\n className={`${CARD_ACTION} text-text-secondary hover:bg-bg-surface hover:text-text-primary`}\n >\n Export\n </button>\n )}\n {canDelete && (\n <button\n type=\"button\"\n onClick={handleDelete}\n className={`${CARD_ACTION} text-status-error-text hover:bg-[var(--color-status-error-bgSubtle)]`}\n >\n Delete\n </button>\n )}\n </div>\n </article>\n );\n});\n\nexport default DataSinkCard;\n"],"mappings":";;;;;;;;AAiBA,IAAM,IACJ,6JAA6J,KAmClJ,IAAe,EAAK,SAAsB,EACrD,aACA,eACA,WACA,WACA,cACA,aACA,aACA,oBACA,aAAU,IACV,gBAAa,IACb,eAAY,MACQ;CAEpB,IAAM,IAAa,GAChB,MAAwB;AAEvB,EADA,EAAE,iBAAiB,EACnB,IAAS,EAAS,GAAG;IAEvB,CAAC,EAAS,IAAI,EAAO,CACtB,EAEK,IAAa,GAChB,MAAwB;AAEvB,EADA,EAAE,iBAAiB,EACnB,IAAS,EAAS,GAAG;IAEvB,CAAC,EAAS,IAAI,EAAO,CACtB,EAEK,IAAgB,GACnB,MAAwB;AAEvB,EADA,EAAE,iBAAiB,EACnB,IAAY,EAAS,GAAG;IAE1B,CAAC,EAAS,IAAI,EAAU,CACzB,EAEK,IAAe,GAClB,MAAwB;AAEvB,EADA,EAAE,iBAAiB,EACnB,IAAW,EAAS,GAAG;IAEzB,CAAC,EAAS,IAAI,EAAS,CACxB,EAEK,IAAe,GAClB,MAAwB;AAEvB,EADA,EAAE,iBAAiB,EACnB,IAAW,EAAS,GAAG;IAEzB,CAAC,EAAS,IAAI,EAAS,CACxB,EAEK,IAAsB,GACzB,MAAwB;AAEvB,EADA,EAAE,iBAAiB,EACnB,IAAkB,EAAS,GAAG;IAEhC,CAAC,EAAS,IAAI,EAAgB,CAC/B,EAGK,KADoB,KAAc,EAAS,gBACH,aAGxC,IAAoB,EAAS,kBAC/B,EAAoB,IAAI,KAAK,EAAS,gBAAgB,EAAE,EAAE,WAAW,IAAM,CAAC,GAC5E;AAEJ,QAIE,kBAAC,WAAD;EACE,WAAW;EAUX,SAAS;YAXX;GAcE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBAAoD,EAAS,QAAQ;MAA0B,CAAA,EAC7G,kBAAC,KAAD;MAAG,WAAU;gBAAyD,EAAS;MAAQ,CAAA,CACnF;QACN,kBAAC,GAAD;KAAqB,QAAQ,EAAS;KAAQ,MAAK;KAAO,CAAA,CACtD;;GAGL,EAAS,eAAe,kBAAC,KAAD;IAAG,WAAU;cAAiD,EAAS;IAAgB,CAAA;GAGhH,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,OAAD;OAAK,WAAU;OAAc,MAAK;OAAO,QAAO;OAAe,SAAQ;iBACrE,kBAAC,QAAD;QACE,eAAc;QACd,gBAAe;QACf,aAAa;QACb,GAAE;QACF,CAAA;OACE,CAAA,EACL,EACI;;KAIP,kBAAC,QAAD;MAAM,WAAU;MAA0B,OAAM;gBAAhD,CACE,kBAAC,OAAD;OAAK,WAAU;OAAc,MAAK;OAAO,QAAO;OAAe,SAAQ;iBACrE,kBAAC,QAAD;QACE,eAAc;QACd,gBAAe;QACf,aAAa;QACb,GAAE;QACF,CAAA;OACE,CAAA,EACL,EAAe,EAAS,UAAU,CAC9B;;KACN,EAAS,wBAAwB,KAAA,KAAa,EAAS,sBAAsB,KAC5E,kBAAC,QAAD;MAAM,WAAU;gBAAhB;OACE,kBAAC,OAAD;QAAK,WAAU;QAAc,MAAK;QAAO,QAAO;QAAe,SAAQ;kBACrE,kBAAC,QAAD;SACE,eAAc;SACd,gBAAe;SACf,aAAa;SACb,GAAE;SACF,CAAA;QACE,CAAA;OACL,EAAS;OAAoB;OAAU,EAAS,wBAAwB,IAAU,KAAN;OACxE;;KAEL;;GAGL,CAAC,KACA,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eAAkD;KAAuB,CAAA,EACzF,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAW;eACZ;KAEQ,CAAA,CACL;;GAIR,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAW,GAAG,EAAY;gBAC3B;MAEQ,CAAA;KACR,KACC,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAW,GAAG,EAAY;gBAC3B;MAEQ,CAAA;KAEV,KACC,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAW,GAAG,EAAY;gBAC3B;MAEQ,CAAA;KAEV,KACC,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAW,GAAG,EAAY;gBAC3B;MAEQ,CAAA;KAEV,KACC,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAW,GAAG,EAAY;gBAC3B;MAEQ,CAAA;KAEP;;GACE;;EAEZ"}
|
|
1
|
+
{"version":3,"file":"DataSinkCard.js","names":[],"sources":["../../../../src/bigconsole/components/datasink/DataSinkCard.tsx"],"sourcesContent":["/**\n * DataSink Card\n *\n * Card component for displaying DataSink information in a list/grid view.\n */\n\nimport { memo, useCallback } from 'react';\nimport { formatDistanceToNow } from 'date-fns';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { DataSinkStatusBadge } from './DataSinkStatusBadge';\nimport { SECTION_FOCUS_RING } from '../common';\nimport { formatByteSize } from '../../utils';\nimport type { DataSink, DataSinkSetupState } from '../../types';\n\n/**\n * Shared class recipe for the card's five action buttons. `min-h-[var(--size-controlHeight-md)]`\n * keeps every one at the 40px touch minimum once the row wraps on mobile.\n */\nconst CARD_ACTION =\n `inline-flex min-h-[var(--size-controlHeight-md)] items-center justify-center rounded-button px-3 py-1.5 text-xs font-medium motion-safe:transition-colors ${SECTION_FOCUS_RING}` as const;\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\ninterface DataSinkCardProps {\n /** DataSink data */\n dataSink: DataSink;\n /** Setup state override */\n setupState?: DataSinkSetupState;\n /** Callback when view is clicked */\n onView?: (id: string) => void;\n /** Callback when edit is clicked */\n onEdit?: (id: string) => void;\n /** Callback when refresh is clicked */\n onRefresh?: (id: string) => void;\n /** Callback when export is clicked */\n onExport?: (id: string) => void;\n /** Callback when delete is clicked */\n onDelete?: (id: string) => void;\n /** Callback to continue setup */\n onContinueSetup?: (id: string) => void;\n /** Whether the current actor may edit this DataSink (gates the Edit action). Defaults to true. */\n canEdit?: boolean;\n /** Whether the current actor may refresh this DataSink (gates the Refresh action). Defaults to true. */\n canRefresh?: boolean;\n /** Whether the current actor may delete this DataSink (gates the Delete action). Defaults to true. */\n canDelete?: boolean;\n}\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport const DataSinkCard = memo(function DataSinkCard({\n dataSink,\n setupState,\n onView,\n onEdit,\n onRefresh,\n onExport,\n onDelete,\n onContinueSetup,\n canEdit = true,\n canRefresh = true,\n canDelete = true,\n}: DataSinkCardProps) {\n // Event handlers\n const handleView = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onView?.(dataSink.id);\n },\n [dataSink.id, onView]\n );\n\n const handleEdit = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onEdit?.(dataSink.id);\n },\n [dataSink.id, onEdit]\n );\n\n const handleRefresh = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onRefresh?.(dataSink.id);\n },\n [dataSink.id, onRefresh]\n );\n\n const handleExport = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onExport?.(dataSink.id);\n },\n [dataSink.id, onExport]\n );\n\n const handleDelete = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onDelete?.(dataSink.id);\n },\n [dataSink.id, onDelete]\n );\n\n const handleContinueSetup = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onContinueSetup?.(dataSink.id);\n },\n [dataSink.id, onContinueSetup]\n );\n\n // The same keys the table view's icon buttons use, so grid and table read\n // alike in every locale (BOFF-8060 i18n B2).\n const { t } = useI18n();\n\n const currentSetupState = setupState ?? dataSink.setupState;\n const isSetupComplete = currentSetupState === 'completed';\n\n // Format last refreshed time\n const lastRefreshedText = dataSink.lastRefreshedAt\n ? formatDistanceToNow(new Date(dataSink.lastRefreshedAt), { addSuffix: true })\n : t('bigconsole.dataSinks.view.never', 'Never');\n\n return (\n // A card is a tile inside the page's `primary` results section, so it steps\n // down to the `muted` recipe (recessed surface, transparent border) instead\n // of competing with the panel that contains it.\n <article\n className={`\n min-w-0\n cursor-pointer\n rounded-card\n border border-transparent\n bg-bg-sunken\n p-card-padding\n hover:border-[var(--color-action-primary-bg)]\n motion-safe:transition-colors\n `}\n onClick={handleView}\n >\n {/* Identity */}\n <div className=\"mb-3 flex items-start justify-between gap-icon-gap\">\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">{dataSink.name || 'Untitled data sink'}</h3>\n <p className=\"mt-0.5 truncate font-mono text-xs text-text-secondary\">{dataSink.key}</p>\n </div>\n <DataSinkStatusBadge status={dataSink.status} size=\"sm\" />\n </div>\n\n {/* Description */}\n {dataSink.description && <p className=\"mb-3 line-clamp-2 text-xs text-text-secondary\">{dataSink.description}</p>}\n\n {/* Stats */}\n <div className=\"mb-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n {lastRefreshedText}\n </span>\n {/* `sizeBytes` ships in DataSinkListItem on every list query but was\n never shown here — it is how you tell a populated sink from an empty\n one without opening it. */}\n <span className=\"flex items-center gap-1\" title=\"Stored payload size\">\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4\"\n />\n </svg>\n {formatByteSize(dataSink.sizeBytes)}\n </span>\n {dataSink.linkedWorkflowCount !== undefined && dataSink.linkedWorkflowCount > 0 && (\n <span className=\"flex items-center gap-1\">\n <svg className=\"w-3.5 h-3.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1\"\n />\n </svg>\n {dataSink.linkedWorkflowCount} workflow{dataSink.linkedWorkflowCount !== 1 ? 's' : ''}\n </span>\n )}\n </div>\n\n {/* Setup state — a warning strip, so it carries the warning tone. */}\n {!isSetupComplete && (\n <div className=\"mb-3 flex items-center justify-between gap-icon-gap rounded-input border border-[var(--color-status-warning-border)] bg-[var(--color-status-warning-bgSubtle)] p-2\">\n <span className=\"text-xs text-[var(--color-status-warning-text)]\">Setup incomplete</span>\n <button\n type=\"button\"\n onClick={handleContinueSetup}\n className={`rounded-button px-1 text-xs font-medium text-text-link hover:underline ${SECTION_FOCUS_RING}`}\n >\n Continue\n </button>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-wrap items-center gap-2 border-t border-[var(--color-border-subtle)] pt-2\">\n <button\n type=\"button\"\n onClick={handleView}\n className={`${CARD_ACTION} flex-1 bg-bg-surface text-text-primary hover:bg-bg-elevated`}\n >\n {t('bigconsole.dataSinks.actions.view', 'View')}\n </button>\n {canEdit && (\n <button\n type=\"button\"\n onClick={handleEdit}\n className={`${CARD_ACTION} text-text-secondary hover:bg-bg-surface hover:text-text-primary`}\n >\n {t('bigconsole.dataSinks.actions.edit', 'Edit')}\n </button>\n )}\n {canRefresh && (\n <button\n type=\"button\"\n onClick={handleRefresh}\n className={`${CARD_ACTION} text-text-secondary hover:bg-bg-surface hover:text-text-primary`}\n >\n {t('bigconsole.dataSinks.actions.refresh', 'Refresh')}\n </button>\n )}\n {onExport && (\n <button\n type=\"button\"\n onClick={handleExport}\n className={`${CARD_ACTION} text-text-secondary hover:bg-bg-surface hover:text-text-primary`}\n >\n {t('bigconsole.dataSinks.actions.export', 'Export')}\n </button>\n )}\n {canDelete && (\n <button\n type=\"button\"\n onClick={handleDelete}\n className={`${CARD_ACTION} text-status-error-text hover:bg-[var(--color-status-error-bgSubtle)]`}\n >\n {t('bigconsole.dataSinks.actions.delete', 'Delete')}\n </button>\n )}\n </div>\n </article>\n );\n});\n\nexport default DataSinkCard;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//#region src/bigconsole/constants/backendErrors.ts
|
|
2
|
+
var e = {
|
|
3
|
+
DASHBOARD_NOT_FOUND: "That dashboard could not be found.",
|
|
4
|
+
DASHBOARD_NOT_FOUND_AFTER_CREATE: "The dashboard was created but could not be loaded. Refresh and try again.",
|
|
5
|
+
DASHBOARD_ARCHIVED_CANNOT_PUBLISH: "An archived dashboard cannot be published. Restore it first.",
|
|
6
|
+
DASHBOARD_INVALID_STATUS_TRANSITION: "That status change is not allowed for this dashboard.",
|
|
7
|
+
SOURCE_DASHBOARD_NOT_FOUND: "The source dashboard could not be found.",
|
|
8
|
+
DASHBOARD_IMPORT_INVALID_JSON: "The import file is not valid JSON.",
|
|
9
|
+
DASHBOARD_IMPORT_MISSING_DATA: "The import file is missing its dashboard data.",
|
|
10
|
+
DASHBOARD_LOCALE_REQUIRED: "A locale is required.",
|
|
11
|
+
DASHBOARD_NAME_REQUIRED: "A name is required.",
|
|
12
|
+
DASHBOARD_THRESHOLD_REQUIRED: "A threshold is required for the threshold method.",
|
|
13
|
+
DASHBOARD_VERSION_NOT_FOUND: "That dashboard version could not be found.",
|
|
14
|
+
DASHBOARD_COMMENT_BODY_REQUIRED: "A comment cannot be empty.",
|
|
15
|
+
DASHBOARD_PARENT_COMMENT_NOT_FOUND: "The comment you are replying to could not be found.",
|
|
16
|
+
DASHBOARD_COMMENT_NOT_FOUND: "That comment could not be found.",
|
|
17
|
+
RLS_POLICY_NOT_FOUND: "That row-level-security policy could not be found.",
|
|
18
|
+
RLS_POLICY_NOT_FOUND_IN_WORKSPACE: "That row-level-security policy is not in this workspace.",
|
|
19
|
+
TEMPLATE_NOT_FOUND: "That template could not be found.",
|
|
20
|
+
TEMPLATE_NOT_ACTIVE: "That template is not active.",
|
|
21
|
+
TEMPLATE_RATING_OUT_OF_RANGE: "Rating must be between 1 and 5.",
|
|
22
|
+
PAGE_NOT_FOUND: "That page could not be found.",
|
|
23
|
+
PAGE_NOT_FOUND_IN_DASHBOARD: "That page is not part of this dashboard.",
|
|
24
|
+
FILTER_PRESET_NOT_FOUND: "That filter preset could not be found.",
|
|
25
|
+
FILTER_PRESET_UPDATE_FORBIDDEN: "You don't have permission to update this preset.",
|
|
26
|
+
FILTER_PRESET_DELETE_FORBIDDEN: "You don't have permission to delete this preset.",
|
|
27
|
+
PARENT_FILTER_NOT_FOUND: "The parent filter could not be found.",
|
|
28
|
+
PARENT_FILTER_DASHBOARD_MISMATCH: "The parent filter must belong to the same dashboard.",
|
|
29
|
+
FILTER_CASCADE_DEPTH_EXCEEDED: "The filter cascade is too deep (maximum 5 levels).",
|
|
30
|
+
FILTER_NOT_FOUND: "That filter could not be found.",
|
|
31
|
+
FILTER_CIRCULAR_DEPENDENCY: "That change would create a circular filter dependency.",
|
|
32
|
+
FILTER_NOT_FOUND_IN_DASHBOARD: "That filter is not part of this dashboard.",
|
|
33
|
+
SHARE_NOT_FOUND: "That share could not be found.",
|
|
34
|
+
VIEW_NOT_FOUND: "That view could not be found.",
|
|
35
|
+
GENERATION_EMPTY_COMPLETION: "The AI returned an empty result. Try again.",
|
|
36
|
+
GENERATION_NOT_AUTHORIZED: "You don't have permission to use this generation.",
|
|
37
|
+
PROMPT_TOO_LONG: "Your prompt is too long (maximum 5000 characters).",
|
|
38
|
+
TOO_MANY_WIDGETS: "Cannot generate more than 50 widgets.",
|
|
39
|
+
GRID_COLUMNS_OUT_OF_RANGE: "Grid columns must be between 1 and 24.",
|
|
40
|
+
AUTO_CREATE_DISABLED: "Auto-create is disabled. Create the dashboard after generation completes.",
|
|
41
|
+
GENERATION_NOT_FOUND: "That generation could not be found.",
|
|
42
|
+
GENERATION_NO_SPEC: "That generation does not have a spec yet.",
|
|
43
|
+
GENERATION_NOT_FOUND_OR_NO_SPEC: "That generation could not be found or has no spec yet.",
|
|
44
|
+
WIDGET_INDEX_OUT_OF_BOUNDS: "That widget index is out of bounds.",
|
|
45
|
+
WIDGET_NOT_FOUND: "That widget could not be found.",
|
|
46
|
+
WIDGETS_NOT_FOUND: "One or more widgets could not be found.",
|
|
47
|
+
TARGET_PAGE_NOT_FOUND: "The target page could not be found.",
|
|
48
|
+
DRILLDOWN_ALREADY_EXISTS: "A drilldown already exists for this widget.",
|
|
49
|
+
DATA_SOURCE_HTTP_ERROR: "The data source returned an error.",
|
|
50
|
+
DATA_SOURCE_GRAPHQL_ERROR: "The GraphQL data source returned an error.",
|
|
51
|
+
WIDGET_ACTION_NOT_FOUND: "That action could not be found.",
|
|
52
|
+
WIDGET_ACTION_NOT_FOUND_IN_WIDGET: "That action is not part of this widget.",
|
|
53
|
+
EVENT_WEBHOOK_MAPPING_NOT_FOUND: "That webhook mapping could not be found.",
|
|
54
|
+
EVENT_LOG_NOT_FOUND: "That event could not be found.",
|
|
55
|
+
EVENT_NOT_IN_FAILED_STATUS: "Only failed events can be retried.",
|
|
56
|
+
EVENT_LOG_MISSING_WIDGET_ID: "This event has no widget and cannot be retried.",
|
|
57
|
+
NO_ACTIVE_WEBHOOK_MAPPINGS: "No active webhook mappings were found for this event.",
|
|
58
|
+
WIDGET_NOT_ASSOCIATED_WITH_DASHBOARD: "That widget is not associated with a dashboard.",
|
|
59
|
+
WIDGET_TYPE_NOT_REGISTERED: "That widget type is not registered. Register it before installing.",
|
|
60
|
+
INVALID_PUBLISH_TYPE: "That publish type is not valid.",
|
|
61
|
+
INVALID_REGISTRABLE_PUBLISH_TYPE: "That publish type cannot be registered.",
|
|
62
|
+
INVALID_WIDGET_RENDERER: "That widget renderer is not valid.",
|
|
63
|
+
INVALID_WIDGET_CONFIG_STATUS: "That widget status is not valid.",
|
|
64
|
+
WORKFLOW_WORKSPACE_ID_REQUIRED: "A workspace is required.",
|
|
65
|
+
WORKFLOW_WORKSPACE_AND_ACTOR_ID_REQUIRED: "A workspace and an actor are required.",
|
|
66
|
+
WORKFLOW_EXECUTION_TRIGGER_FAILED: "The workflow could not be triggered. Try again.",
|
|
67
|
+
WORKFLOW_GATEWAY_GRAPHQL_ERROR: "The workflow service returned an error.",
|
|
68
|
+
WORKFLOW_NOT_FOUND: "That workflow could not be found.",
|
|
69
|
+
WORKFLOW_KEY_EXISTS: "A workflow with that key already exists in this workspace.",
|
|
70
|
+
INVALID_INITIAL_WORKFLOW_STATUS: "That workflow status cannot be used when creating a workflow.",
|
|
71
|
+
EXTERNAL_WORKFLOW_CREATE_FAILED: "The workflow could not be created in the workflow builder. Retry, or create the definition first and link it.",
|
|
72
|
+
DATASINK_LINK_NOT_FOUND: "That DataSink link could not be found.",
|
|
73
|
+
VERSION_MISMATCH: "This record was changed elsewhere. Reload and try again.",
|
|
74
|
+
PARSER_NOT_FOUND: "That parser could not be found.",
|
|
75
|
+
PARSER_VERSION_MISMATCH: "This parser was changed elsewhere. Reload and try again.",
|
|
76
|
+
PARSER_TYPE_UNSUPPORTED: "Unsupported parser type. Only 'jq' and 'jsonata' are supported.",
|
|
77
|
+
PARSER_EXPRESSION_INVALID: "The parser expression is invalid.",
|
|
78
|
+
PARSER_DATASINK_NOT_FOUND: "The parser’s source DataSink could not be found.",
|
|
79
|
+
PIPELINE_ACTOR_REQUIRED: "A workspace and an actor are required.",
|
|
80
|
+
PIPELINE_STAGE_NO_PARSER: "A pipeline stage has no expression or parser.",
|
|
81
|
+
DATASINK_NOT_FOUND: "That data sink could not be found.",
|
|
82
|
+
E_PIPELINE_NOT_FOUND: "That pipeline could not be found.",
|
|
83
|
+
E_PIPELINE_STAGE_NOT_FOUND: "That pipeline stage could not be found.",
|
|
84
|
+
E_PIPELINE_EXECUTION: "The pipeline execution failed.",
|
|
85
|
+
E_PIPELINE_VERSION_MISMATCH: "This pipeline was changed elsewhere. Reload and try again.",
|
|
86
|
+
E_PIPELINE_INACTIVE: "That pipeline is not active.",
|
|
87
|
+
E_PIPELINE_EXECUTION_NOT_FOUND: "That pipeline execution could not be found.",
|
|
88
|
+
E_PIPELINE_NAME_EXISTS: "A pipeline with that name already exists for this console.",
|
|
89
|
+
E_PIPELINE_DUPLICATE_OUTPUT_KEY: "Each pipeline stage must have a unique output key.",
|
|
90
|
+
E_PIPELINE_VALIDATION_ERROR: "The pipeline input is not valid.",
|
|
91
|
+
BAD_USER_INPUT: "The request is not valid."
|
|
92
|
+
};
|
|
93
|
+
//#endregion
|
|
94
|
+
export { e as BACKEND_ERROR_MESSAGES };
|
|
95
|
+
|
|
96
|
+
//# sourceMappingURL=backendErrors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backendErrors.js","names":[],"sources":["../../../src/bigconsole/constants/backendErrors.ts"],"sourcesContent":["/**\n * BigConsole backend error-code → user-facing English message.\n *\n * The wspace-bigconsole-svc backend now throws `BigConsoleError(code, …)` so\n * every failure carries a stable `extensions.code` (see the svc\n * `src/modules/shared/errors.ts`). This map turns those codes into friendly,\n * generic English strings and — via `resolveBackendErrorMessage` — into\n * localized strings keyed `bigconsole.errors.<CODE>`.\n *\n * Only USER-FACING codes are listed. Server-config / invariant codes\n * (e.g. EMBED_HASH_PEPPER_INVALID, UNIFIED_GRAPH_NO_MODULES,\n * TAG_TEST_SEAM_IN_PRODUCTION) are intentionally omitted — a user never sees\n * them, and the raw server message is a fine last resort.\n *\n * These English values are the source for the `bigconsole.errors.*` seed keys\n * (the bundle generator folds this map into the en bundle; hi/ta live in\n * i18n/locales/). Keep messages generic (no interpolated ids) — the specific\n * id is still available on `error.extensions` for callers that need it.\n */\nexport const BACKEND_ERROR_MESSAGES: Record<string, string> = {\n // Dashboard\n DASHBOARD_NOT_FOUND: 'That dashboard could not be found.',\n DASHBOARD_NOT_FOUND_AFTER_CREATE: 'The dashboard was created but could not be loaded. Refresh and try again.',\n DASHBOARD_ARCHIVED_CANNOT_PUBLISH: 'An archived dashboard cannot be published. Restore it first.',\n DASHBOARD_INVALID_STATUS_TRANSITION: 'That status change is not allowed for this dashboard.',\n SOURCE_DASHBOARD_NOT_FOUND: 'The source dashboard could not be found.',\n DASHBOARD_IMPORT_INVALID_JSON: 'The import file is not valid JSON.',\n DASHBOARD_IMPORT_MISSING_DATA: 'The import file is missing its dashboard data.',\n DASHBOARD_LOCALE_REQUIRED: 'A locale is required.',\n DASHBOARD_NAME_REQUIRED: 'A name is required.',\n DASHBOARD_THRESHOLD_REQUIRED: 'A threshold is required for the threshold method.',\n DASHBOARD_VERSION_NOT_FOUND: 'That dashboard version could not be found.',\n DASHBOARD_COMMENT_BODY_REQUIRED: 'A comment cannot be empty.',\n DASHBOARD_PARENT_COMMENT_NOT_FOUND: 'The comment you are replying to could not be found.',\n DASHBOARD_COMMENT_NOT_FOUND: 'That comment could not be found.',\n\n // Row-level security\n RLS_POLICY_NOT_FOUND: 'That row-level-security policy could not be found.',\n RLS_POLICY_NOT_FOUND_IN_WORKSPACE: 'That row-level-security policy is not in this workspace.',\n\n // Templates\n TEMPLATE_NOT_FOUND: 'That template could not be found.',\n TEMPLATE_NOT_ACTIVE: 'That template is not active.',\n TEMPLATE_RATING_OUT_OF_RANGE: 'Rating must be between 1 and 5.',\n\n // Pages\n PAGE_NOT_FOUND: 'That page could not be found.',\n PAGE_NOT_FOUND_IN_DASHBOARD: 'That page is not part of this dashboard.',\n\n // Filters / presets\n FILTER_PRESET_NOT_FOUND: 'That filter preset could not be found.',\n FILTER_PRESET_UPDATE_FORBIDDEN: \"You don't have permission to update this preset.\",\n FILTER_PRESET_DELETE_FORBIDDEN: \"You don't have permission to delete this preset.\",\n PARENT_FILTER_NOT_FOUND: 'The parent filter could not be found.',\n PARENT_FILTER_DASHBOARD_MISMATCH: 'The parent filter must belong to the same dashboard.',\n FILTER_CASCADE_DEPTH_EXCEEDED: 'The filter cascade is too deep (maximum 5 levels).',\n FILTER_NOT_FOUND: 'That filter could not be found.',\n FILTER_CIRCULAR_DEPENDENCY: 'That change would create a circular filter dependency.',\n FILTER_NOT_FOUND_IN_DASHBOARD: 'That filter is not part of this dashboard.',\n\n // Shares / views\n SHARE_NOT_FOUND: 'That share could not be found.',\n VIEW_NOT_FOUND: 'That view could not be found.',\n\n // Prompt / AI generation\n GENERATION_EMPTY_COMPLETION: 'The AI returned an empty result. Try again.',\n GENERATION_NOT_AUTHORIZED: \"You don't have permission to use this generation.\",\n PROMPT_TOO_LONG: 'Your prompt is too long (maximum 5000 characters).',\n TOO_MANY_WIDGETS: 'Cannot generate more than 50 widgets.',\n GRID_COLUMNS_OUT_OF_RANGE: 'Grid columns must be between 1 and 24.',\n AUTO_CREATE_DISABLED: 'Auto-create is disabled. Create the dashboard after generation completes.',\n GENERATION_NOT_FOUND: 'That generation could not be found.',\n GENERATION_NO_SPEC: 'That generation does not have a spec yet.',\n GENERATION_NOT_FOUND_OR_NO_SPEC: 'That generation could not be found or has no spec yet.',\n WIDGET_INDEX_OUT_OF_BOUNDS: 'That widget index is out of bounds.',\n\n // Widgets / actions / events\n WIDGET_NOT_FOUND: 'That widget could not be found.',\n WIDGETS_NOT_FOUND: 'One or more widgets could not be found.',\n TARGET_PAGE_NOT_FOUND: 'The target page could not be found.',\n DRILLDOWN_ALREADY_EXISTS: 'A drilldown already exists for this widget.',\n DATA_SOURCE_HTTP_ERROR: 'The data source returned an error.',\n DATA_SOURCE_GRAPHQL_ERROR: 'The GraphQL data source returned an error.',\n WIDGET_ACTION_NOT_FOUND: 'That action could not be found.',\n WIDGET_ACTION_NOT_FOUND_IN_WIDGET: 'That action is not part of this widget.',\n EVENT_WEBHOOK_MAPPING_NOT_FOUND: 'That webhook mapping could not be found.',\n EVENT_LOG_NOT_FOUND: 'That event could not be found.',\n EVENT_NOT_IN_FAILED_STATUS: 'Only failed events can be retried.',\n EVENT_LOG_MISSING_WIDGET_ID: 'This event has no widget and cannot be retried.',\n NO_ACTIVE_WEBHOOK_MAPPINGS: 'No active webhook mappings were found for this event.',\n WIDGET_NOT_ASSOCIATED_WITH_DASHBOARD: 'That widget is not associated with a dashboard.',\n WIDGET_TYPE_NOT_REGISTERED: 'That widget type is not registered. Register it before installing.',\n INVALID_PUBLISH_TYPE: 'That publish type is not valid.',\n INVALID_REGISTRABLE_PUBLISH_TYPE: 'That publish type cannot be registered.',\n INVALID_WIDGET_RENDERER: 'That widget renderer is not valid.',\n INVALID_WIDGET_CONFIG_STATUS: 'That widget status is not valid.',\n\n // Workflows\n WORKFLOW_WORKSPACE_ID_REQUIRED: 'A workspace is required.',\n WORKFLOW_WORKSPACE_AND_ACTOR_ID_REQUIRED: 'A workspace and an actor are required.',\n WORKFLOW_EXECUTION_TRIGGER_FAILED: 'The workflow could not be triggered. Try again.',\n WORKFLOW_GATEWAY_GRAPHQL_ERROR: 'The workflow service returned an error.',\n WORKFLOW_NOT_FOUND: 'That workflow could not be found.',\n WORKFLOW_KEY_EXISTS: 'A workflow with that key already exists in this workspace.',\n INVALID_INITIAL_WORKFLOW_STATUS: 'That workflow status cannot be used when creating a workflow.',\n EXTERNAL_WORKFLOW_CREATE_FAILED:\n 'The workflow could not be created in the workflow builder. Retry, or create the definition first and link it.',\n DATASINK_LINK_NOT_FOUND: 'That DataSink link could not be found.',\n VERSION_MISMATCH: 'This record was changed elsewhere. Reload and try again.',\n\n // Parsers\n PARSER_NOT_FOUND: 'That parser could not be found.',\n PARSER_VERSION_MISMATCH: 'This parser was changed elsewhere. Reload and try again.',\n PARSER_TYPE_UNSUPPORTED: \"Unsupported parser type. Only 'jq' and 'jsonata' are supported.\",\n PARSER_EXPRESSION_INVALID: 'The parser expression is invalid.',\n PARSER_DATASINK_NOT_FOUND: 'The parser’s source DataSink could not be found.',\n\n // Pipelines / data sinks\n PIPELINE_ACTOR_REQUIRED: 'A workspace and an actor are required.',\n PIPELINE_STAGE_NO_PARSER: 'A pipeline stage has no expression or parser.',\n DATASINK_NOT_FOUND: 'That data sink could not be found.',\n E_PIPELINE_NOT_FOUND: 'That pipeline could not be found.',\n E_PIPELINE_STAGE_NOT_FOUND: 'That pipeline stage could not be found.',\n E_PIPELINE_EXECUTION: 'The pipeline execution failed.',\n E_PIPELINE_VERSION_MISMATCH: 'This pipeline was changed elsewhere. Reload and try again.',\n E_PIPELINE_INACTIVE: 'That pipeline is not active.',\n E_PIPELINE_EXECUTION_NOT_FOUND: 'That pipeline execution could not be found.',\n E_PIPELINE_NAME_EXISTS: 'A pipeline with that name already exists for this console.',\n E_PIPELINE_DUPLICATE_OUTPUT_KEY: 'Each pipeline stage must have a unique output key.',\n E_PIPELINE_VALIDATION_ERROR: 'The pipeline input is not valid.',\n BAD_USER_INPUT: 'The request is not valid.',\n};\n\nexport type BackendErrorCode = keyof typeof BACKEND_ERROR_MESSAGES;\n"],"mappings":";AAmBA,IAAa,IAAiD;CAE5D,qBAAqB;CACrB,kCAAkC;CAClC,mCAAmC;CACnC,qCAAqC;CACrC,4BAA4B;CAC5B,+BAA+B;CAC/B,+BAA+B;CAC/B,2BAA2B;CAC3B,yBAAyB;CACzB,8BAA8B;CAC9B,6BAA6B;CAC7B,iCAAiC;CACjC,oCAAoC;CACpC,6BAA6B;CAG7B,sBAAsB;CACtB,mCAAmC;CAGnC,oBAAoB;CACpB,qBAAqB;CACrB,8BAA8B;CAG9B,gBAAgB;CAChB,6BAA6B;CAG7B,yBAAyB;CACzB,gCAAgC;CAChC,gCAAgC;CAChC,yBAAyB;CACzB,kCAAkC;CAClC,+BAA+B;CAC/B,kBAAkB;CAClB,4BAA4B;CAC5B,+BAA+B;CAG/B,iBAAiB;CACjB,gBAAgB;CAGhB,6BAA6B;CAC7B,2BAA2B;CAC3B,iBAAiB;CACjB,kBAAkB;CAClB,2BAA2B;CAC3B,sBAAsB;CACtB,sBAAsB;CACtB,oBAAoB;CACpB,iCAAiC;CACjC,4BAA4B;CAG5B,kBAAkB;CAClB,mBAAmB;CACnB,uBAAuB;CACvB,0BAA0B;CAC1B,wBAAwB;CACxB,2BAA2B;CAC3B,yBAAyB;CACzB,mCAAmC;CACnC,iCAAiC;CACjC,qBAAqB;CACrB,4BAA4B;CAC5B,6BAA6B;CAC7B,4BAA4B;CAC5B,sCAAsC;CACtC,4BAA4B;CAC5B,sBAAsB;CACtB,kCAAkC;CAClC,yBAAyB;CACzB,8BAA8B;CAG9B,gCAAgC;CAChC,0CAA0C;CAC1C,mCAAmC;CACnC,gCAAgC;CAChC,oBAAoB;CACpB,qBAAqB;CACrB,iCAAiC;CACjC,iCACE;CACF,yBAAyB;CACzB,kBAAkB;CAGlB,kBAAkB;CAClB,yBAAyB;CACzB,yBAAyB;CACzB,2BAA2B;CAC3B,2BAA2B;CAG3B,yBAAyB;CACzB,0BAA0B;CAC1B,oBAAoB;CACpB,sBAAsB;CACtB,4BAA4B;CAC5B,sBAAsB;CACtB,6BAA6B;CAC7B,qBAAqB;CACrB,gCAAgC;CAChC,wBAAwB;CACxB,iCAAiC;CACjC,6BAA6B;CAC7B,gBAAgB;CACjB"}
|
|
@@ -7,6 +7,25 @@ export type AlertChannel = BigConsoleDataSinkAlertChannelsQuery['dataSinkAlertCh
|
|
|
7
7
|
export type AlertExecution = BigConsoleDataSinkAlertExecutionsQuery['dataSinkAlertExecutions'][number];
|
|
8
8
|
export type AlertPreview = BigConsolePreviewDataSinkAlertQuery['previewDataSinkAlert'];
|
|
9
9
|
export declare const alertErrorMessage: (error: unknown) => string;
|
|
10
|
+
/**
|
|
11
|
+
* "This data sink is not here": the client's own check (`getDataSink` answers
|
|
12
|
+
* `null`, or a sink from another workspace) and the server's codes for it.
|
|
13
|
+
*/
|
|
14
|
+
export declare const ALERT_SINK_NOT_FOUND = "DATASINK_NOT_FOUND";
|
|
15
|
+
type Translate = (key: string, fallback: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* What the alerts page says when the data sink could not be loaded
|
|
18
|
+
* (BOFF-8060 i18n B3). The server's English never wins over a keyed string:
|
|
19
|
+
*
|
|
20
|
+
* - not found (or nothing recorded) → `bigconsole.alerts.notFound`;
|
|
21
|
+
* - a coded failure → `bigconsole.errors.<CODE>`, the catalog the rest of
|
|
22
|
+
* BigConsole localizes backend errors with;
|
|
23
|
+
* - only an uncoded failure falls back to its raw message, which has no key.
|
|
24
|
+
*/
|
|
25
|
+
export declare function describeAlertLoadFailure(t: Translate, failure: {
|
|
26
|
+
error: string | null;
|
|
27
|
+
errorCode: string | null;
|
|
28
|
+
}): string;
|
|
10
29
|
/** Every read and write uses the selected workspace; late requests cannot populate a new owner. */
|
|
11
30
|
export declare function useDataSinkAlerts(dataSinkId: string, enabled: boolean): {
|
|
12
31
|
owner: string;
|
|
@@ -43,6 +62,7 @@ export declare function useDataSinkAlerts(dataSinkId: string, enabled: boolean):
|
|
|
43
62
|
}> | null;
|
|
44
63
|
} | null | undefined>;
|
|
45
64
|
reloadChannels: () => Promise<void>;
|
|
65
|
+
reloadSinkThenChannels: () => Promise<void>;
|
|
46
66
|
save: (alert: DataSinkAlertInput, expectedVersion: number) => Promise<{
|
|
47
67
|
__typename?: "DataSink";
|
|
48
68
|
id: string;
|
|
@@ -141,6 +161,9 @@ export declare function useDataSinkAlerts(dataSinkId: string, enabled: boolean):
|
|
|
141
161
|
channels: AlertChannel[];
|
|
142
162
|
loading: boolean;
|
|
143
163
|
error: string | null;
|
|
164
|
+
/** The first GraphQL `extensions.code` behind `error`, or the client's own not-found marker. */
|
|
165
|
+
errorCode: string | null;
|
|
144
166
|
channelError: string | null;
|
|
145
167
|
};
|
|
168
|
+
export {};
|
|
146
169
|
//# sourceMappingURL=useDataSinkAlerts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDataSinkAlerts.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/hooks/useDataSinkAlerts.ts"],"names":[],"mappings":"AAGA,OAAO,EAOL,KAAK,6BAA6B,EAClC,KAAK,oCAAoC,EACzC,KAAK,sCAAsC,EAC3C,KAAK,mCAAmC,EAGzC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"useDataSinkAlerts.d.ts","sourceRoot":"","sources":["../../../src/bigconsole/hooks/useDataSinkAlerts.ts"],"names":[],"mappings":"AAGA,OAAO,EAOL,KAAK,6BAA6B,EAClC,KAAK,oCAAoC,EACzC,KAAK,sCAAsC,EAC3C,KAAK,mCAAmC,EAGzC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAInG,MAAM,MAAM,SAAS,GAAG,WAAW,CAAC,6BAA6B,CAAC,aAAa,CAAC,CAAC,CAAC;AAClF,MAAM,MAAM,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACjE,MAAM,MAAM,YAAY,GAAG,oCAAoC,CAAC,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AACjG,MAAM,MAAM,cAAc,GAAG,sCAAsC,CAAC,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AACvG,MAAM,MAAM,YAAY,GAAG,mCAAmC,CAAC,sBAAsB,CAAC,CAAC;AAqBvF,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,MACuC,CAAC;AAE3F;;;GAGG;AACH,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AAgBzD,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;AAE3D;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,CAAC,EAAE,SAAS,EACZ,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC1D,MAAM,CAMR;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;;;;;;;;;;;sBAwL6/7D,CAAC;;;;;;;;;oBAA8N,CAAC;0BAAc,CAAC;;;;;;0BAA+H,CAAC;;;;;;;;;kBAtEh68D,kBAAkB,mBAAmB,MAAM;;;;;;;;sBAsEsg8D,CAAC;;;;;;;;;oBAA8N,CAAC;0BAAc,CAAC;;;;;;0BAA+H,CAAC;;;;;;;sBAzD958D,MAAM,mBAAmB,MAAM;;;;;;;;sBAyDgh8D,CAAC;;;;;;;;;oBAA8N,CAAC;0BAAc,CAAC;;;;;;0BAA+H,CAAC;;;;;;;yBA5C558D,MAAM,iBAAiB,0BAA0B;;;;;;;;wBAgBlD,MAAM,UAAU,MAAM;;;;;;;;;;;;;;sBA4B2i/D,CAAC;;;;0BAA2H,CAAC;;iBAAsC,CAAC;uBAA4B,CAAC;;;UAvP/w/D,SAAS,GAAG,IAAI;cACZ,YAAY,EAAE;aACf,OAAO;WACT,MAAM,GAAG,IAAI;IACpB,gGAAgG;eACrF,MAAM,GAAG,IAAI;kBACV,MAAM,GAAG,IAAI;EAgP5B"}
|