@burdenoff/microfe-bigconsole 2026.925.1 → 2026.928.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js +142 -145
  2. package/dist/bigconsole/components/dashboard/ShareDialog/EmbedTab.js.map +1 -1
  3. package/dist/bigconsole/components/embed/EmbedWidgetRenderer.js +43 -13
  4. package/dist/bigconsole/components/embed/EmbedWidgetRenderer.js.map +1 -1
  5. package/dist/bigconsole/components/embed/ReadOnlyDashboardRenderer.js +5 -5
  6. package/dist/bigconsole/components/embed/ReadOnlyDashboardRenderer.js.map +1 -1
  7. package/dist/bigconsole/components/embed/renderer-manifest.js +14 -47
  8. package/dist/bigconsole/components/embed/renderer-manifest.js.map +1 -1
  9. package/dist/bigconsole/components/embed/types.js.map +1 -1
  10. package/dist/bigconsole/components/embed/widgetShim.js +28 -0
  11. package/dist/bigconsole/components/embed/widgetShim.js.map +1 -0
  12. package/dist/bigconsole/components/embed/widgets/CalendarEmbed.js +38 -0
  13. package/dist/bigconsole/components/embed/widgets/CalendarEmbed.js.map +1 -0
  14. package/dist/bigconsole/components/embed/widgets/ChartEmbed.js +225 -0
  15. package/dist/bigconsole/components/embed/widgets/ChartEmbed.js.map +1 -0
  16. package/dist/bigconsole/components/embed/widgets/EmbedFrame.js +18 -0
  17. package/dist/bigconsole/components/embed/widgets/EmbedFrame.js.map +1 -0
  18. package/dist/bigconsole/components/embed/widgets/FormEmbed.js +147 -0
  19. package/dist/bigconsole/components/embed/widgets/FormEmbed.js.map +1 -0
  20. package/dist/bigconsole/components/embed/widgets/GaugeEmbed.js +44 -0
  21. package/dist/bigconsole/components/embed/widgets/GaugeEmbed.js.map +1 -0
  22. package/dist/bigconsole/components/embed/widgets/HeatmapEmbed.js +35 -0
  23. package/dist/bigconsole/components/embed/widgets/HeatmapEmbed.js.map +1 -0
  24. package/dist/bigconsole/components/embed/widgets/KanbanEmbed.js +50 -0
  25. package/dist/bigconsole/components/embed/widgets/KanbanEmbed.js.map +1 -0
  26. package/dist/bigconsole/components/embed/widgets/PivotEmbed.js +146 -0
  27. package/dist/bigconsole/components/embed/widgets/PivotEmbed.js.map +1 -0
  28. package/dist/bigconsole/components/embed/widgets/ProgressEmbed.js +30 -0
  29. package/dist/bigconsole/components/embed/widgets/ProgressEmbed.js.map +1 -0
  30. package/dist/bigconsole/components/embed/widgets/RetentionEmbed.js +41 -0
  31. package/dist/bigconsole/components/embed/widgets/RetentionEmbed.js.map +1 -0
  32. package/dist/bigconsole/components/embed/widgets/TimelineEmbed.js +40 -0
  33. package/dist/bigconsole/components/embed/widgets/TimelineEmbed.js.map +1 -0
  34. package/dist/bigconsole/components/embed/widgets/shared.js +13 -1
  35. package/dist/bigconsole/components/embed/widgets/shared.js.map +1 -1
  36. package/dist/bigconsole/components/widgets/calendar/CalendarView.js +152 -0
  37. package/dist/bigconsole/components/widgets/calendar/CalendarView.js.map +1 -0
  38. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js +10 -147
  39. package/dist/bigconsole/components/widgets/calendar/CalendarWidget.js.map +1 -1
  40. package/dist/bigconsole/components/widgets/chart/ChartWidget.js +19 -19
  41. package/dist/bigconsole/components/widgets/chart/index.js +8 -8
  42. package/dist/bigconsole/components/widgets/index.js +5 -5
  43. package/dist/bigconsole/components/widgets/kanban/KanbanView.js +192 -0
  44. package/dist/bigconsole/components/widgets/kanban/KanbanView.js.map +1 -0
  45. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js +10 -187
  46. package/dist/bigconsole/components/widgets/kanban/KanbanWidget.js.map +1 -1
  47. package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +20 -20
  48. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js +23 -22
  49. package/dist/bigconsole/components/widgets/timeline/TimelineWidget.js.map +1 -1
  50. package/dist/bigconsole/components/widgets/utils/translate.js +9 -0
  51. package/dist/bigconsole/components/widgets/utils/translate.js.map +1 -0
  52. package/dist/bigconsole/hooks/useDashboardEmbedPolicy.js +2 -4
  53. package/dist/bigconsole/hooks/useDashboardEmbedPolicy.js.map +1 -1
  54. package/dist/generated/wspace-operations.js +0 -1
  55. package/dist/generated/wspace-operations.js.map +1 -1
  56. package/package.json +1 -1
@@ -1,153 +1,16 @@
1
- import { memo as e, useMemo as t } from "react";
2
- import { jsx as n, jsxs as r } from "react/jsx-runtime";
3
- import { useI18n as i } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
1
+ import e from "./CalendarView.js";
2
+ import { memo as t } from "react";
3
+ import { jsx as n } from "react/jsx-runtime";
4
+ import { useI18n as r } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
4
5
  //#region src/bigconsole/components/widgets/calendar/CalendarWidget.tsx
5
- function a(e, t) {
6
- for (let n of t) if (e[n] !== void 0 && e[n] !== null) return e[n];
7
- }
8
- function o(e) {
9
- let t = Array.isArray(e) ? e : Array.isArray(e?.events) ? e.events : Array.isArray(e?.items) ? e.items : Array.isArray(e?.data) ? e.data : void 0;
10
- return Array.isArray(t) ? t.map((e, t) => {
11
- if (!e || typeof e != "object") return null;
12
- let n = e, r = a(n, [
13
- "start",
14
- "startDate",
15
- "date",
16
- "startTime"
17
- ]);
18
- if (!r) return null;
19
- let i = a(n, [
20
- "end",
21
- "endDate",
22
- "endTime"
23
- ]) ?? r, o = a(n, [
24
- "title",
25
- "name",
26
- "label",
27
- "summary"
28
- ]) ?? "Untitled event", s = a(n, [
29
- "id",
30
- "eventId",
31
- "_id"
32
- ]) ?? `${o}-${r}-${t}`;
33
- return {
34
- id: String(s),
35
- title: String(o),
36
- start: String(r),
37
- end: String(i),
38
- color: typeof n.color == "string" ? n.color : void 0,
39
- allDay: typeof n.allDay == "boolean" ? n.allDay : void 0,
40
- category: a(n, [
41
- "category",
42
- "group",
43
- "type"
44
- ])
45
- };
46
- }).filter((e) => e !== null) : [];
47
- }
48
- var s = e(function({ widget: e, data: a, onClick: s }) {
49
- let { t: c } = i(), l = t(() => o(a), [a]), u = t(() => {
50
- let e = /* @__PURE__ */ new Date(), t = new Date(e.getTime() + 10080 * 60 * 1e3);
51
- return l.filter((n) => {
52
- let r = new Date(n.start);
53
- return r >= e && r <= t;
54
- }).sort((e, t) => new Date(e.start).getTime() - new Date(t.start).getTime()).slice(0, 8);
55
- }, [l]);
56
- return l.length ? /* @__PURE__ */ r("div", {
57
- className: "flex flex-col h-full p-4 overflow-auto",
58
- children: [
59
- /* @__PURE__ */ r("div", {
60
- className: "flex items-center justify-between mb-4",
61
- children: [/* @__PURE__ */ n("h3", {
62
- className: "text-sm font-medium text-text-primary",
63
- children: c("bigconsole.widget.calendar.upcomingEvents", "Upcoming Events")
64
- }), /* @__PURE__ */ n("span", {
65
- className: "text-xs text-text-secondary",
66
- children: c("bigconsole.widget.calendar.eventCount", "{{count}} events", { count: l.length })
67
- })]
68
- }),
69
- /* @__PURE__ */ n("div", {
70
- className: "flex-1 space-y-2 overflow-auto",
71
- children: u.map((e) => {
72
- let t = new Date(e.start), i = t.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
73
- return /* @__PURE__ */ n("div", {
74
- className: `
75
- p-3 rounded-lg border border-border-default
76
- ${s ? "cursor-pointer hover:border-action-primary-bg" : ""}
77
- transition-colors
78
- `,
79
- onClick: () => s?.(e),
80
- children: /* @__PURE__ */ r("div", {
81
- className: "flex items-start gap-3",
82
- children: [/* @__PURE__ */ n("div", {
83
- className: "w-1 h-full min-h-[40px] rounded-full flex-shrink-0",
84
- style: { backgroundColor: e.color || "var(--color-action-primary-bg)" }
85
- }), /* @__PURE__ */ r("div", {
86
- className: "flex-1 min-w-0",
87
- children: [
88
- /* @__PURE__ */ n("p", {
89
- className: "text-sm font-medium text-text-primary truncate",
90
- children: e.title
91
- }),
92
- /* @__PURE__ */ r("p", {
93
- className: "text-xs text-text-secondary mt-1",
94
- children: [
95
- i ? /* @__PURE__ */ n("span", {
96
- className: "text-status-success-text font-medium",
97
- children: c("bigconsole.widget.calendar.today", "Today")
98
- }) : t.toLocaleDateString("en-US", {
99
- weekday: "short",
100
- month: "short",
101
- day: "numeric"
102
- }),
103
- !e.allDay && /* @__PURE__ */ n("span", {
104
- className: "ml-2",
105
- children: t.toLocaleTimeString("en-US", {
106
- hour: "numeric",
107
- minute: "2-digit"
108
- })
109
- }),
110
- e.allDay && /* @__PURE__ */ n("span", {
111
- className: "ml-2",
112
- children: c("bigconsole.widget.calendar.allDay", "All day")
113
- })
114
- ]
115
- }),
116
- e.category && /* @__PURE__ */ n("span", {
117
- className: "inline-block mt-1 px-2 py-0.5 text-[10px] rounded bg-bg-sunken text-text-secondary",
118
- children: e.category
119
- })
120
- ]
121
- })]
122
- })
123
- }, e.id);
124
- })
125
- }),
126
- l.length > u.length && /* @__PURE__ */ n("p", {
127
- className: "text-xs text-text-muted text-center mt-3",
128
- children: c("bigconsole.widget.calendar.moreEvents", "+{{count}} more events", { count: l.length - u.length })
129
- })
130
- ]
131
- }) : /* @__PURE__ */ n("div", {
132
- className: "flex items-center justify-center h-full text-text-secondary text-sm",
133
- children: /* @__PURE__ */ r("div", {
134
- className: "text-center",
135
- children: [/* @__PURE__ */ n("svg", {
136
- className: "w-12 h-12 mx-auto mb-2 text-text-muted",
137
- fill: "none",
138
- stroke: "currentColor",
139
- viewBox: "0 0 24 24",
140
- children: /* @__PURE__ */ n("path", {
141
- strokeLinecap: "round",
142
- strokeLinejoin: "round",
143
- strokeWidth: 1.5,
144
- d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
145
- })
146
- }), /* @__PURE__ */ n("p", { children: c("bigconsole.widget.calendar.emptyState", "No events to display") })]
147
- })
6
+ var i = t(function(t) {
7
+ let { t: i } = r();
8
+ return /* @__PURE__ */ n(e, {
9
+ ...t,
10
+ t: i
148
11
  });
149
12
  });
150
13
  //#endregion
151
- export { s as default };
14
+ export { i as default };
152
15
 
153
16
  //# sourceMappingURL=CalendarWidget.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CalendarWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/calendar/CalendarWidget.tsx"],"sourcesContent":["/**\n * CalendarWidget Component\n *\n * Simple calendar view showing events.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { Widget } from '../../../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CalendarWidgetProps {\n widget: Widget;\n data?: CalendarData;\n onClick?: (event: CalendarEvent) => void;\n}\n\nexport interface CalendarEvent {\n id: string;\n title: string;\n start: string;\n end: string;\n color?: string;\n allDay?: boolean;\n category?: string;\n}\n\nexport interface CalendarData {\n events?: CalendarEvent[];\n currentDate?: string;\n view?: 'month' | 'week' | 'day';\n}\n\n// ============================================================================\n// Normalization\n// ============================================================================\n\nfunction firstDefined<T = unknown>(obj: Record<string, unknown>, keys: string[]): T | undefined {\n for (const key of keys) {\n if (obj[key] !== undefined && obj[key] !== null) return obj[key] as T;\n }\n return undefined;\n}\n\n/**\n * Normalize whatever the widget is bound to into `CalendarEvent[]`. Accepts the\n * documented `{ events, ... }` shape, an events array under a different common\n * key, or a bare array of event-like records — a DataSink parser naturally\n * outputs a bare array, and WidgetWrapper has no calendar-specific reshaping\n * step (unlike table/list/chart), so this widget has to tolerate it itself, the\n * same way MapWidget tolerates a bare marker array instead of requiring\n * `{ markers }`. Field names are matched against common aliases so a parser\n * doesn't have to emit the exact `title`/`start`/`end` keys.\n */\nexport function normalizeCalendarEvents(\n data: CalendarData | CalendarEvent[] | Record<string, unknown> | undefined\n): CalendarEvent[] {\n const rawEvents: unknown = Array.isArray(data)\n ? data\n : Array.isArray((data as CalendarData | undefined)?.events)\n ? (data as CalendarData).events\n : Array.isArray((data as Record<string, unknown> | undefined)?.items)\n ? (data as Record<string, unknown>).items\n : Array.isArray((data as Record<string, unknown> | undefined)?.data)\n ? (data as Record<string, unknown>).data\n : undefined;\n\n if (!Array.isArray(rawEvents)) return [];\n\n return rawEvents\n .map((raw, i): CalendarEvent | null => {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n const start = firstDefined<string>(r, ['start', 'startDate', 'date', 'startTime']);\n if (!start) return null;\n const end = firstDefined<string>(r, ['end', 'endDate', 'endTime']) ?? start;\n const title = firstDefined<string>(r, ['title', 'name', 'label', 'summary']) ?? 'Untitled event';\n const id = firstDefined<string>(r, ['id', 'eventId', '_id']) ?? `${title}-${start}-${i}`;\n return {\n id: String(id),\n title: String(title),\n start: String(start),\n end: String(end),\n color: typeof r.color === 'string' ? r.color : undefined,\n allDay: typeof r.allDay === 'boolean' ? r.allDay : undefined,\n category: firstDefined<string>(r, ['category', 'group', 'type']),\n };\n })\n .filter((e): e is CalendarEvent => e !== null);\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const CalendarWidget: FC<CalendarWidgetProps> = memo(function CalendarWidget({\n widget: _widget,\n data,\n onClick,\n}) {\n const { t } = useI18n();\n const events = useMemo(() => normalizeCalendarEvents(data), [data]);\n\n // Get upcoming events (next 7 days)\n const upcomingEvents = useMemo(() => {\n const now = new Date();\n const weekFromNow = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000);\n return events\n .filter((e) => {\n const eventDate = new Date(e.start);\n return eventDate >= now && eventDate <= weekFromNow;\n })\n .sort((a, b) => new Date(a.start).getTime() - new Date(b.start).getTime())\n .slice(0, 8);\n }, [events]);\n\n if (!events.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg className=\"w-12 h-12 mx-auto mb-2 text-text-muted\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n <p>{t('bigconsole.widget.calendar.emptyState', 'No events to display')}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col h-full p-4 overflow-auto\">\n {/* Header */}\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-sm font-medium text-text-primary\">\n {t('bigconsole.widget.calendar.upcomingEvents', 'Upcoming Events')}\n </h3>\n <span className=\"text-xs text-text-secondary\">\n {t('bigconsole.widget.calendar.eventCount', '{{count}} events', { count: events.length })}\n </span>\n </div>\n\n {/* Event List */}\n <div className=\"flex-1 space-y-2 overflow-auto\">\n {upcomingEvents.map((event) => {\n const eventDate = new Date(event.start);\n const isToday = eventDate.toDateString() === new Date().toDateString();\n\n return (\n <div\n key={event.id}\n className={`\n p-3 rounded-lg border border-border-default\n ${onClick ? 'cursor-pointer hover:border-action-primary-bg' : ''}\n transition-colors\n `}\n onClick={() => onClick?.(event)}\n >\n <div className=\"flex items-start gap-3\">\n {/* Color indicator */}\n <div\n className=\"w-1 h-full min-h-[40px] rounded-full flex-shrink-0\"\n style={{ backgroundColor: event.color || 'var(--color-action-primary-bg)' }}\n />\n\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{event.title}</p>\n <p className=\"text-xs text-text-secondary mt-1\">\n {isToday ? (\n <span className=\"text-status-success-text font-medium\">\n {t('bigconsole.widget.calendar.today', 'Today')}\n </span>\n ) : (\n eventDate.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' })\n )}\n {!event.allDay && (\n <span className=\"ml-2\">\n {eventDate.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}\n </span>\n )}\n {event.allDay && <span className=\"ml-2\">{t('bigconsole.widget.calendar.allDay', 'All day')}</span>}\n </p>\n {event.category && (\n <span className=\"inline-block mt-1 px-2 py-0.5 text-[10px] rounded bg-bg-sunken text-text-secondary\">\n {event.category}\n </span>\n )}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n\n {events.length > upcomingEvents.length && (\n <p className=\"text-xs text-text-muted text-center mt-3\">\n {t('bigconsole.widget.calendar.moreEvents', '+{{count}} more events', {\n count: events.length - upcomingEvents.length,\n })}\n </p>\n )}\n </div>\n );\n});\n\nexport default CalendarWidget;\n"],"mappings":"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"}
1
+ {"version":3,"file":"CalendarWidget.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/calendar/CalendarWidget.tsx"],"sourcesContent":["/**\n * CalendarWidget — in-app wrapper around the pure CalendarView (BOFF-7926).\n *\n * The view is i18n-provider-free so the public embed bundle can render it with a\n * static translator (the fe-libs I18nProvider touches localStorage, which throws\n * in third-party iframes when the visitor blocks third-party storage).\n */\n\nimport { type FC, memo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { CalendarView, type CalendarWidgetProps } from './CalendarView';\n\nexport * from './CalendarView';\n\nexport const CalendarWidget: FC<CalendarWidgetProps> = memo(function CalendarWidget(props) {\n const { t } = useI18n();\n return <CalendarView {...props} t={t} />;\n});\n\nexport default CalendarWidget;\n"],"mappings":";;;;;AAcA,IAAa,IAA0C,EAAK,SAAwB,GAAO;CACzF,IAAM,EAAE,SAAM,GAAS;AACvB,QAAO,kBAAC,GAAD;EAAc,GAAI;EAAU;EAAK,CAAA;EACxC"}
@@ -1,14 +1,14 @@
1
1
  import { useCrossFilterContext as e, useWidgetCrossFilter as t } from "../../../contexts/CrossFilterContext.js";
2
2
  import "../../../contexts/index.js";
3
- import n from "./charts/LineChart.js";
4
- import r from "./charts/BarChart.js";
5
- import i from "./charts/AreaChart.js";
6
- import a from "./charts/PieChart.js";
7
- import o from "./charts/FunnelChart.js";
8
- import s from "./charts/ComboChart.js";
9
- import c from "./charts/WaterfallChart.js";
10
- import l from "./charts/ScatterChart.js";
11
- import u from "./ChartLegend.js";
3
+ import n from "./ChartLegend.js";
4
+ import r from "./charts/LineChart.js";
5
+ import i from "./charts/BarChart.js";
6
+ import a from "./charts/AreaChart.js";
7
+ import o from "./charts/PieChart.js";
8
+ import s from "./charts/FunnelChart.js";
9
+ import c from "./charts/ComboChart.js";
10
+ import l from "./charts/WaterfallChart.js";
11
+ import u from "./charts/ScatterChart.js";
12
12
  import { memo as d, useCallback as f, useMemo as p, useState as m } from "react";
13
13
  import { jsx as h, jsxs as g } from "react/jsx-runtime";
14
14
  //#region src/bigconsole/components/widgets/chart/ChartWidget.tsx
@@ -109,7 +109,7 @@ var _ = [
109
109
  }), "Clear Filter"]
110
110
  })
111
111
  }),
112
- O.legendPosition === "top" && k.length > 0 && /* @__PURE__ */ h(u, {
112
+ O.legendPosition === "top" && k.length > 0 && /* @__PURE__ */ h(n, {
113
113
  items: k,
114
114
  position: "top",
115
115
  onItemClick: A
@@ -117,50 +117,50 @@ var _ = [
117
117
  /* @__PURE__ */ h("div", {
118
118
  className: "flex-1 min-h-0",
119
119
  children: (() => {
120
- if (M) return /* @__PURE__ */ h(s, {
120
+ if (M) return /* @__PURE__ */ h(c, {
121
121
  data: v,
122
122
  config: O,
123
123
  hiddenSeries: S,
124
124
  onDataClick: j
125
125
  });
126
126
  switch (O.type) {
127
- case "waterfall": return /* @__PURE__ */ h(c, {
127
+ case "waterfall": return /* @__PURE__ */ h(l, {
128
128
  data: v,
129
129
  config: O,
130
130
  onDataClick: j
131
131
  });
132
- case "scatter": return /* @__PURE__ */ h(l, {
132
+ case "scatter": return /* @__PURE__ */ h(u, {
133
133
  data: v,
134
134
  config: O,
135
135
  onDataClick: j
136
136
  });
137
- case "bar": return /* @__PURE__ */ h(r, {
137
+ case "bar": return /* @__PURE__ */ h(i, {
138
138
  data: v,
139
139
  config: O,
140
140
  hiddenSeries: S,
141
141
  onDataClick: j
142
142
  });
143
- case "area": return /* @__PURE__ */ h(i, {
143
+ case "area": return /* @__PURE__ */ h(a, {
144
144
  data: v,
145
145
  config: O,
146
146
  hiddenSeries: S,
147
147
  onDataClick: j
148
148
  });
149
- case "pie": return /* @__PURE__ */ h(a, {
149
+ case "pie": return /* @__PURE__ */ h(o, {
150
150
  data: v,
151
151
  config: O,
152
152
  dataKey: x?.valueField || "value",
153
153
  nameKey: x?.labelField || "name",
154
154
  onDataClick: j
155
155
  });
156
- case "funnel": return /* @__PURE__ */ h(o, {
156
+ case "funnel": return /* @__PURE__ */ h(s, {
157
157
  data: v,
158
158
  config: O,
159
159
  dataKey: x?.valueField || "value",
160
160
  nameKey: x?.labelField || "name",
161
161
  onDataClick: j
162
162
  });
163
- default: return /* @__PURE__ */ h(n, {
163
+ default: return /* @__PURE__ */ h(r, {
164
164
  data: v,
165
165
  config: O,
166
166
  hiddenSeries: S,
@@ -169,7 +169,7 @@ var _ = [
169
169
  }
170
170
  })()
171
171
  }),
172
- O.legendPosition === "bottom" && k.length > 0 && /* @__PURE__ */ h(u, {
172
+ O.legendPosition === "bottom" && k.length > 0 && /* @__PURE__ */ h(n, {
173
173
  items: k,
174
174
  position: "bottom",
175
175
  onItemClick: A
@@ -1,11 +1,11 @@
1
- import e from "./ChartTooltip.js";
2
- import t from "./charts/LineChart.js";
3
- import n from "./charts/BarChart.js";
4
- import r from "./charts/AreaChart.js";
5
- import i from "./charts/PieChart.js";
6
- import a from "./charts/FunnelChart.js";
7
- import o from "./ChartLegend.js";
1
+ import e from "./ChartLegend.js";
2
+ import t from "./ChartTooltip.js";
3
+ import n from "./charts/LineChart.js";
4
+ import r from "./charts/BarChart.js";
5
+ import i from "./charts/AreaChart.js";
6
+ import a from "./charts/PieChart.js";
7
+ import o from "./charts/FunnelChart.js";
8
8
  import s from "./ChartWidget.js";
9
9
  import c from "./ChartConfig.js";
10
10
  import "./charts/index.js";
11
- export { r as AreaChart, n as BarChart, c as ChartConfig, o as ChartLegend, e as ChartTooltip, s as ChartWidget, a as FunnelChart, t as LineChart, i as PieChart };
11
+ export { i as AreaChart, r as BarChart, c as ChartConfig, e as ChartLegend, t as ChartTooltip, s as ChartWidget, o as FunnelChart, n as LineChart, a as PieChart };
@@ -8,6 +8,11 @@ import "./WidgetErrorBoundary.js";
8
8
  import "./widget-actions/WidgetActions.js";
9
9
  import "./widget-actions/index.js";
10
10
  import "./WidgetWrapper.js";
11
+ import "./gauge/GaugeWidget.js";
12
+ import "./progress/ProgressWidget.js";
13
+ import "./heatmap/HeatmapWidget.js";
14
+ import "./retention/RetentionWidget.js";
15
+ import "./timeline/TimelineWidget.js";
11
16
  import "./adaptive-card/AdaptiveCardWidget.js";
12
17
  import "./adaptive-card/index.js";
13
18
  import "./calendar/CalendarWidget.js";
@@ -18,9 +23,7 @@ import "./custom/CustomWidget.js";
18
23
  import "./custom/index.js";
19
24
  import "./form/FormWidget.js";
20
25
  import "./form/index.js";
21
- import "./gauge/GaugeWidget.js";
22
26
  import "./gauge/index.js";
23
- import "./heatmap/HeatmapWidget.js";
24
27
  import "./heatmap/index.js";
25
28
  import "./iframe-widget/IframeWidget.js";
26
29
  import "./iframe-widget/index.js";
@@ -34,15 +37,12 @@ import "./map-widget/MapWidget.js";
34
37
  import "./map-widget/index.js";
35
38
  import "./metric-card/MetricCardWidget.js";
36
39
  import "./metric-card/index.js";
37
- import "./progress/ProgressWidget.js";
38
40
  import "./progress/index.js";
39
- import "./retention/RetentionWidget.js";
40
41
  import "./retention/index.js";
41
42
  import "./table/TableWidget.js";
42
43
  import "./table/index.js";
43
44
  import "./text-widget/TextWidget.js";
44
45
  import "./text-widget/index.js";
45
- import "./timeline/TimelineWidget.js";
46
46
  import "./timeline/index.js";
47
47
  import "./webhook-config/WebhookConfigPanel.js";
48
48
  import "./webhook-config/index.js";
@@ -0,0 +1,192 @@
1
+ import { memo as e, useMemo as t } from "react";
2
+ import { jsx as n, jsxs as r } from "react/jsx-runtime";
3
+ //#region src/bigconsole/components/widgets/kanban/KanbanView.tsx
4
+ function i(e) {
5
+ switch (e) {
6
+ case "high": return "bg-status-error-bg/20 text-status-error-text";
7
+ case "medium": return "bg-status-warning-bg/20 text-[var(--color-status-warning-text)]";
8
+ case "low": return "bg-status-success-bg/20 text-status-success-text";
9
+ default: return "bg-bg-sunken text-text-secondary";
10
+ }
11
+ }
12
+ var a = [
13
+ "status",
14
+ "state",
15
+ "column",
16
+ "stage",
17
+ "category",
18
+ "phase",
19
+ "group"
20
+ ], o = [
21
+ "title",
22
+ "name",
23
+ "summary",
24
+ "label",
25
+ "identifier",
26
+ "id"
27
+ ];
28
+ function s(e) {
29
+ return typeof e == "string" && e.length > 0 ? e : void 0;
30
+ }
31
+ function c(e) {
32
+ let t = (e) => e.filter((e) => !!e && typeof e == "object" && !Array.isArray(e));
33
+ if (Array.isArray(e)) return t(e);
34
+ if (e && typeof e == "object") {
35
+ let n = e;
36
+ for (let e of [
37
+ "tasks",
38
+ "rows",
39
+ "items",
40
+ "data",
41
+ "nodes",
42
+ "results",
43
+ "records"
44
+ ]) if (Array.isArray(n[e])) return t(n[e]);
45
+ let r = Object.values(n).find((e) => Array.isArray(e));
46
+ if (Array.isArray(r)) return t(r);
47
+ }
48
+ return [];
49
+ }
50
+ function l(e, t) {
51
+ for (let n of t) if (n && n in e) return n;
52
+ }
53
+ function u(e) {
54
+ let t = s(e)?.toLowerCase();
55
+ if (t) {
56
+ if (t === "urgent" || t === "high") return "high";
57
+ if (t === "medium" || t === "normal") return "medium";
58
+ if (t === "low") return "low";
59
+ }
60
+ }
61
+ function d(e, t) {
62
+ if (e && typeof e == "object" && !Array.isArray(e) && Array.isArray(e.columns)) {
63
+ let t = e;
64
+ return {
65
+ columns: t.columns ?? [],
66
+ tasks: t.tasks ?? []
67
+ };
68
+ }
69
+ let n = c(e);
70
+ if (n.length === 0) return {
71
+ columns: [],
72
+ tasks: []
73
+ };
74
+ let r = n[0], i = l(r, [
75
+ s(t?.columnField),
76
+ s(t?.groupField),
77
+ s(t?.statusField),
78
+ ...a,
79
+ s(t?.xAxisField),
80
+ s(t?.labelField)
81
+ ]);
82
+ if (!i) return {
83
+ columns: [],
84
+ tasks: []
85
+ };
86
+ let d = l(r, [
87
+ s(t?.cardTitleField),
88
+ s(t?.titleField),
89
+ ...o,
90
+ s(t?.labelField)
91
+ ]), f = {}, p = [], m = n.map((e, t) => {
92
+ let n = e[i], r = n == null || n === "" ? "Uncategorized" : String(n);
93
+ r in f || (f[r] = r, p.push(r));
94
+ let a = e.id ?? e.identifier ?? e.key, o = Array.isArray(e.labels) ? e.labels.filter((e) => typeof e == "string") : void 0;
95
+ return {
96
+ id: a == null ? `task-${t}` : String(a),
97
+ title: d && e[d] != null ? String(e[d]) : `Item ${t + 1}`,
98
+ column: r,
99
+ assignee: s(e.assignee),
100
+ priority: u(e.priority ?? e.priorityLabel),
101
+ labels: o && o.length > 0 ? o : void 0
102
+ };
103
+ });
104
+ return {
105
+ columns: p.map((e) => ({
106
+ id: e,
107
+ title: f[e] ?? e
108
+ })),
109
+ tasks: m
110
+ };
111
+ }
112
+ var f = e(function({ widget: e, data: a, onClick: o, t: s }) {
113
+ let c = e.config, { columns: l, tasks: u } = t(() => d(a, c), [a, c]), f = t(() => {
114
+ let e = {};
115
+ return l.forEach((t) => {
116
+ e[t.id] = u.filter((e) => e.column === t.id);
117
+ }), e;
118
+ }, [l, u]);
119
+ return l.length ? /* @__PURE__ */ n("div", {
120
+ className: "flex h-full p-2 gap-2 overflow-x-auto",
121
+ children: l.map((e) => {
122
+ let t = f[e.id] || [];
123
+ return /* @__PURE__ */ r("div", {
124
+ className: "flex-shrink-0 w-48 flex flex-col bg-bg-sunken/50 rounded-lg",
125
+ children: [/* @__PURE__ */ r("div", {
126
+ className: "flex items-center gap-2 p-2 border-b border-border-default",
127
+ children: [
128
+ /* @__PURE__ */ n("div", {
129
+ className: "w-2 h-2 rounded-full",
130
+ style: { backgroundColor: e.color || "var(--color-text-muted)" }
131
+ }),
132
+ /* @__PURE__ */ n("span", {
133
+ className: "text-xs font-medium text-text-primary truncate",
134
+ children: e.title
135
+ }),
136
+ /* @__PURE__ */ n("span", {
137
+ className: "ml-auto text-xs text-text-muted",
138
+ children: t.length
139
+ })
140
+ ]
141
+ }), /* @__PURE__ */ r("div", {
142
+ className: "flex-1 p-2 space-y-2 overflow-y-auto",
143
+ children: [t.map((e) => /* @__PURE__ */ r("div", {
144
+ className: `
145
+ p-2 bg-bg-surface rounded border border-border-default
146
+ ${o ? "cursor-pointer hover:border-action-primary-bg" : ""}
147
+ transition-colors
148
+ `,
149
+ onClick: () => o?.(e),
150
+ children: [/* @__PURE__ */ n("p", {
151
+ className: "text-xs font-medium text-text-primary line-clamp-2",
152
+ children: e.title
153
+ }), /* @__PURE__ */ r("div", {
154
+ className: "flex items-center gap-1 mt-2 flex-wrap",
155
+ children: [e.priority && /* @__PURE__ */ n("span", {
156
+ className: `px-1.5 py-0.5 text-[10px] rounded ${i(e.priority)}`,
157
+ children: e.priority
158
+ }), e.assignee && /* @__PURE__ */ n("span", {
159
+ className: "px-1.5 py-0.5 text-[10px] rounded bg-action-primary-bg/10 text-action-primary-text",
160
+ children: e.assignee
161
+ })]
162
+ })]
163
+ }, e.id)), t.length === 0 && /* @__PURE__ */ n("p", {
164
+ className: "text-[10px] text-text-muted text-center py-4",
165
+ children: s("bigconsole.widget.kanban.noTasks", "No tasks")
166
+ })]
167
+ })]
168
+ }, e.id);
169
+ })
170
+ }) : /* @__PURE__ */ n("div", {
171
+ className: "flex items-center justify-center h-full text-text-secondary text-sm",
172
+ children: /* @__PURE__ */ r("div", {
173
+ className: "text-center",
174
+ children: [/* @__PURE__ */ n("svg", {
175
+ className: "w-12 h-12 mx-auto mb-2 text-text-muted",
176
+ fill: "none",
177
+ stroke: "currentColor",
178
+ viewBox: "0 0 24 24",
179
+ children: /* @__PURE__ */ n("path", {
180
+ strokeLinecap: "round",
181
+ strokeLinejoin: "round",
182
+ strokeWidth: 1.5,
183
+ d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"
184
+ })
185
+ }), /* @__PURE__ */ n("p", { children: s("bigconsole.widget.kanban.emptyState", "No board data") })]
186
+ })
187
+ });
188
+ });
189
+ //#endregion
190
+ export { f as default };
191
+
192
+ //# sourceMappingURL=KanbanView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KanbanView.js","names":[],"sources":["../../../../../src/bigconsole/components/widgets/kanban/KanbanView.tsx"],"sourcesContent":["/**\n * KanbanWidget Component\n *\n * Simple kanban board view with columns and tasks.\n */\n\nimport { type FC, memo, useMemo } from 'react';\nimport type { Widget } from '../../../types';\nimport type { WidgetTranslateFn } from '../utils/translate';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface KanbanViewProps extends KanbanWidgetProps {\n /** Translator — the app passes useI18n().t; the public embed passes a static fallback translator. */\n t: WidgetTranslateFn;\n}\n\nexport interface KanbanWidgetProps {\n widget: Widget;\n data?: KanbanData;\n onClick?: (task: KanbanTask) => void;\n}\n\nexport interface KanbanColumn {\n id: string;\n title: string;\n color?: string;\n}\n\nexport interface KanbanTask {\n id: string;\n title: string;\n column: string;\n priority?: 'high' | 'medium' | 'low';\n assignee?: string;\n labels?: string[];\n dueDate?: string;\n}\n\nexport interface KanbanData {\n columns?: KanbanColumn[];\n tasks?: KanbanTask[];\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction getPriorityColor(priority?: string): string {\n switch (priority) {\n case 'high':\n return 'bg-status-error-bg/20 text-status-error-text';\n case 'medium':\n return 'bg-status-warning-bg/20 text-[var(--color-status-warning-text)]';\n case 'low':\n return 'bg-status-success-bg/20 text-status-success-text';\n default:\n return 'bg-bg-sunken text-text-secondary';\n }\n}\n\n// Field names we try, in order, when the widget config doesn't name one\n// explicitly. A DataSink/parser typically emits a flat array of rows (e.g. the\n// Linear \"Kanban board\" parser -> [{ id, title, status, assignee, ... }]), so\n// the board is derived from a status/column field on those rows.\nconst COLUMN_FIELD_CANDIDATES = ['status', 'state', 'column', 'stage', 'category', 'phase', 'group'];\nconst TITLE_FIELD_CANDIDATES = ['title', 'name', 'summary', 'label', 'identifier', 'id'];\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/** Coerce parser output into an array of object rows (handles common envelopes). */\nfunction asRows(data: unknown): Record<string, unknown>[] {\n const onlyObjects = (arr: unknown[]): Record<string, unknown>[] =>\n arr.filter((r): r is Record<string, unknown> => !!r && typeof r === 'object' && !Array.isArray(r));\n\n if (Array.isArray(data)) return onlyObjects(data);\n\n if (data && typeof data === 'object') {\n const obj = data as Record<string, unknown>;\n for (const key of ['tasks', 'rows', 'items', 'data', 'nodes', 'results', 'records']) {\n if (Array.isArray(obj[key])) return onlyObjects(obj[key] as unknown[]);\n }\n const firstArray = Object.values(obj).find((v) => Array.isArray(v));\n if (Array.isArray(firstArray)) return onlyObjects(firstArray);\n }\n return [];\n}\n\n/** First key that actually exists on the sample row. */\nfunction firstPresent(row: Record<string, unknown>, keys: (string | undefined)[]): string | undefined {\n for (const key of keys) {\n if (key && key in row) return key;\n }\n return undefined;\n}\n\nfunction normalizePriority(value: unknown): KanbanTask['priority'] {\n const v = asString(value)?.toLowerCase();\n if (!v) return undefined;\n if (v === 'urgent' || v === 'high') return 'high';\n if (v === 'medium' || v === 'normal') return 'medium';\n if (v === 'low') return 'low';\n return undefined;\n}\n\n/**\n * Normalize widget data into the board's { columns, tasks } shape.\n *\n * KanbanWidget previously required the exact canonical shape and rendered\n * \"No board data\" for any DataSink/parser output that was a plain array of\n * rows (which is what parsers actually emit) — BOFF-4110. This adapts a flat\n * array into columns (distinct values of a status/column field, in first-seen\n * order) plus one card per row, honoring config field mappings with fallbacks.\n */\nfunction normalizeKanban(\n data: unknown,\n config?: Record<string, unknown>\n): { columns: KanbanColumn[]; tasks: KanbanTask[] } {\n // Canonical shape passes through untouched (back-compat).\n if (data && typeof data === 'object' && !Array.isArray(data) && Array.isArray((data as KanbanData).columns)) {\n const d = data as KanbanData;\n return { columns: d.columns ?? [], tasks: d.tasks ?? [] };\n }\n\n const rows = asRows(data);\n if (rows.length === 0) return { columns: [], tasks: [] };\n\n const sample = rows[0];\n const columnField = firstPresent(sample, [\n asString(config?.columnField),\n asString(config?.groupField),\n asString(config?.statusField),\n ...COLUMN_FIELD_CANDIDATES,\n asString(config?.xAxisField),\n asString(config?.labelField),\n ]);\n if (!columnField) return { columns: [], tasks: [] };\n\n const titleField = firstPresent(sample, [\n asString(config?.cardTitleField),\n asString(config?.titleField),\n ...TITLE_FIELD_CANDIDATES,\n asString(config?.labelField),\n ]);\n\n const columnTitles: Record<string, string> = {};\n const columnOrder: string[] = [];\n const tasks: KanbanTask[] = rows.map((row, i) => {\n const columnRaw = row[columnField];\n const column = columnRaw == null || columnRaw === '' ? 'Uncategorized' : String(columnRaw);\n if (!(column in columnTitles)) {\n columnTitles[column] = column;\n columnOrder.push(column);\n }\n const idRaw = row.id ?? row.identifier ?? row.key;\n const labels = Array.isArray(row.labels) ? row.labels.filter((l): l is string => typeof l === 'string') : undefined;\n return {\n id: idRaw != null ? String(idRaw) : `task-${i}`,\n title: titleField && row[titleField] != null ? String(row[titleField]) : `Item ${i + 1}`,\n column,\n assignee: asString(row.assignee),\n priority: normalizePriority(row.priority ?? row.priorityLabel),\n labels: labels && labels.length > 0 ? labels : undefined,\n };\n });\n\n const columns: KanbanColumn[] = columnOrder.map((id) => ({ id, title: columnTitles[id] ?? id }));\n return { columns, tasks };\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const KanbanView: FC<KanbanViewProps> = memo(function KanbanView({ widget, data, onClick, t }) {\n const config = widget.config as Record<string, unknown> | undefined;\n const { columns, tasks } = useMemo(() => normalizeKanban(data, config), [data, config]);\n\n // Group tasks by column\n const tasksByColumn = useMemo(() => {\n const grouped: Record<string, KanbanTask[]> = {};\n columns.forEach((col) => {\n grouped[col.id] = tasks.filter((t) => t.column === col.id);\n });\n return grouped;\n }, [columns, tasks]);\n\n if (!columns.length) {\n return (\n <div className=\"flex items-center justify-center h-full text-text-secondary text-sm\">\n <div className=\"text-center\">\n <svg className=\"w-12 h-12 mx-auto mb-2 text-text-muted\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2\"\n />\n </svg>\n <p>{t('bigconsole.widget.kanban.emptyState', 'No board data')}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"flex h-full p-2 gap-2 overflow-x-auto\">\n {columns.map((column) => {\n const columnTasks = tasksByColumn[column.id] || [];\n\n return (\n <div key={column.id} className=\"flex-shrink-0 w-48 flex flex-col bg-bg-sunken/50 rounded-lg\">\n {/* Column Header */}\n <div className=\"flex items-center gap-2 p-2 border-b border-border-default\">\n <div\n className=\"w-2 h-2 rounded-full\"\n style={{ backgroundColor: column.color || 'var(--color-text-muted)' }}\n />\n <span className=\"text-xs font-medium text-text-primary truncate\">{column.title}</span>\n <span className=\"ml-auto text-xs text-text-muted\">{columnTasks.length}</span>\n </div>\n\n {/* Tasks */}\n <div className=\"flex-1 p-2 space-y-2 overflow-y-auto\">\n {columnTasks.map((task) => (\n <div\n key={task.id}\n className={`\n p-2 bg-bg-surface rounded border border-border-default\n ${onClick ? 'cursor-pointer hover:border-action-primary-bg' : ''}\n transition-colors\n `}\n onClick={() => onClick?.(task)}\n >\n <p className=\"text-xs font-medium text-text-primary line-clamp-2\">{task.title}</p>\n\n <div className=\"flex items-center gap-1 mt-2 flex-wrap\">\n {task.priority && (\n <span className={`px-1.5 py-0.5 text-[10px] rounded ${getPriorityColor(task.priority)}`}>\n {task.priority}\n </span>\n )}\n {task.assignee && (\n <span className=\"px-1.5 py-0.5 text-[10px] rounded bg-action-primary-bg/10 text-action-primary-text\">\n {task.assignee}\n </span>\n )}\n </div>\n </div>\n ))}\n\n {columnTasks.length === 0 && (\n <p className=\"text-[10px] text-text-muted text-center py-4\">\n {t('bigconsole.widget.kanban.noTasks', 'No tasks')}\n </p>\n )}\n </div>\n </div>\n );\n })}\n </div>\n );\n});\n\nexport default KanbanView;\n"],"mappings":";;;AAkDA,SAAS,EAAiB,GAA2B;AACnD,SAAQ,GAAR;EACE,KAAK,OACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,MACH,QAAO;EACT,QACE,QAAO;;;AAQb,IAAM,IAA0B;CAAC;CAAU;CAAS;CAAU;CAAS;CAAY;CAAS;CAAQ,EAC9F,IAAyB;CAAC;CAAS;CAAQ;CAAW;CAAS;CAAc;CAAK;AAExF,SAAS,EAAS,GAAoC;AACpD,QAAO,OAAO,KAAU,YAAY,EAAM,SAAS,IAAI,IAAQ,KAAA;;AAIjE,SAAS,EAAO,GAA0C;CACxD,IAAM,KAAe,MACnB,EAAI,QAAQ,MAAoC,CAAC,CAAC,KAAK,OAAO,KAAM,YAAY,CAAC,MAAM,QAAQ,EAAE,CAAC;AAEpG,KAAI,MAAM,QAAQ,EAAK,CAAE,QAAO,EAAY,EAAK;AAEjD,KAAI,KAAQ,OAAO,KAAS,UAAU;EACpC,IAAM,IAAM;AACZ,OAAK,IAAM,KAAO;GAAC;GAAS;GAAQ;GAAS;GAAQ;GAAS;GAAW;GAAU,CACjF,KAAI,MAAM,QAAQ,EAAI,GAAK,CAAE,QAAO,EAAY,EAAI,GAAkB;EAExE,IAAM,IAAa,OAAO,OAAO,EAAI,CAAC,MAAM,MAAM,MAAM,QAAQ,EAAE,CAAC;AACnE,MAAI,MAAM,QAAQ,EAAW,CAAE,QAAO,EAAY,EAAW;;AAE/D,QAAO,EAAE;;AAIX,SAAS,EAAa,GAA8B,GAAkD;AACpG,MAAK,IAAM,KAAO,EAChB,KAAI,KAAO,KAAO,EAAK,QAAO;;AAKlC,SAAS,EAAkB,GAAwC;CACjE,IAAM,IAAI,EAAS,EAAM,EAAE,aAAa;AACnC,QACL;MAAI,MAAM,YAAY,MAAM,OAAQ,QAAO;AAC3C,MAAI,MAAM,YAAY,MAAM,SAAU,QAAO;AAC7C,MAAI,MAAM,MAAO,QAAO;;;AAa1B,SAAS,EACP,GACA,GACkD;AAElD,KAAI,KAAQ,OAAO,KAAS,YAAY,CAAC,MAAM,QAAQ,EAAK,IAAI,MAAM,QAAS,EAAoB,QAAQ,EAAE;EAC3G,IAAM,IAAI;AACV,SAAO;GAAE,SAAS,EAAE,WAAW,EAAE;GAAE,OAAO,EAAE,SAAS,EAAE;GAAE;;CAG3D,IAAM,IAAO,EAAO,EAAK;AACzB,KAAI,EAAK,WAAW,EAAG,QAAO;EAAE,SAAS,EAAE;EAAE,OAAO,EAAE;EAAE;CAExD,IAAM,IAAS,EAAK,IACd,IAAc,EAAa,GAAQ;EACvC,EAAS,GAAQ,YAAY;EAC7B,EAAS,GAAQ,WAAW;EAC5B,EAAS,GAAQ,YAAY;EAC7B,GAAG;EACH,EAAS,GAAQ,WAAW;EAC5B,EAAS,GAAQ,WAAW;EAC7B,CAAC;AACF,KAAI,CAAC,EAAa,QAAO;EAAE,SAAS,EAAE;EAAE,OAAO,EAAE;EAAE;CAEnD,IAAM,IAAa,EAAa,GAAQ;EACtC,EAAS,GAAQ,eAAe;EAChC,EAAS,GAAQ,WAAW;EAC5B,GAAG;EACH,EAAS,GAAQ,WAAW;EAC7B,CAAC,EAEI,IAAuC,EAAE,EACzC,IAAwB,EAAE,EAC1B,IAAsB,EAAK,KAAK,GAAK,MAAM;EAC/C,IAAM,IAAY,EAAI,IAChB,IAAS,KAAa,QAAQ,MAAc,KAAK,kBAAkB,OAAO,EAAU;AAC1F,EAAM,KAAU,MACd,EAAa,KAAU,GACvB,EAAY,KAAK,EAAO;EAE1B,IAAM,IAAQ,EAAI,MAAM,EAAI,cAAc,EAAI,KACxC,IAAS,MAAM,QAAQ,EAAI,OAAO,GAAG,EAAI,OAAO,QAAQ,MAAmB,OAAO,KAAM,SAAS,GAAG,KAAA;AAC1G,SAAO;GACL,IAAI,KAAS,OAAuB,QAAQ,MAAxB,OAAO,EAAM;GACjC,OAAO,KAAc,EAAI,MAAe,OAAO,OAAO,EAAI,GAAY,GAAG,QAAQ,IAAI;GACrF;GACA,UAAU,EAAS,EAAI,SAAS;GAChC,UAAU,EAAkB,EAAI,YAAY,EAAI,cAAc;GAC9D,QAAQ,KAAU,EAAO,SAAS,IAAI,IAAS,KAAA;GAChD;GACD;AAGF,QAAO;EAAE,SADuB,EAAY,KAAK,OAAQ;GAAE;GAAI,OAAO,EAAa,MAAO;GAAI,EAAE;EAC9E;EAAO;;AAO3B,IAAa,IAAkC,EAAK,SAAoB,EAAE,WAAQ,SAAM,YAAS,QAAK;CACpG,IAAM,IAAS,EAAO,QAChB,EAAE,YAAS,aAAU,QAAc,EAAgB,GAAM,EAAO,EAAE,CAAC,GAAM,EAAO,CAAC,EAGjF,IAAgB,QAAc;EAClC,IAAM,IAAwC,EAAE;AAIhD,SAHA,EAAQ,SAAS,MAAQ;AACvB,KAAQ,EAAI,MAAM,EAAM,QAAQ,MAAM,EAAE,WAAW,EAAI,GAAG;IAC1D,EACK;IACN,CAAC,GAAS,EAAM,CAAC;AAoBpB,QAlBK,EAAQ,SAmBX,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAQ,KAAK,MAAW;GACvB,IAAM,IAAc,EAAc,EAAO,OAAO,EAAE;AAElD,UACE,kBAAC,OAAD;IAAqB,WAAU;cAA/B,CAEE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,iBAAiB,EAAO,SAAS,2BAA2B;OACrE,CAAA;MACF,kBAAC,QAAD;OAAM,WAAU;iBAAkD,EAAO;OAAa,CAAA;MACtF,kBAAC,QAAD;OAAM,WAAU;iBAAmC,EAAY;OAAc,CAAA;MACzE;QAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAY,KAAK,MAChB,kBAAC,OAAD;MAEE,WAAW;;wBAEL,IAAU,kDAAkD,GAAG;;;MAGrE,eAAe,IAAU,EAAK;gBAPhC,CASE,kBAAC,KAAD;OAAG,WAAU;iBAAsD,EAAK;OAAU,CAAA,EAElF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAW,qCAAqC,EAAiB,EAAK,SAAS;kBAClF,EAAK;QACD,CAAA,EAER,EAAK,YACJ,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAK;QACD,CAAA,CAEL;SACF;QAtBC,EAAK,GAsBN,CACN,EAED,EAAY,WAAW,KACtB,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAE,oCAAoC,WAAW;MAChD,CAAA,CAEF;OACF;MA9CI,EAAO,GA8CX;IAER;EACE,CAAA,GAvEJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;IAAyC,MAAK;IAAO,QAAO;IAAe,SAAQ;cAChG,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA;IACE,CAAA,EACN,kBAAC,KAAD,EAAA,UAAI,EAAE,uCAAuC,gBAAgB,EAAK,CAAA,CAC9D;;EACF,CAAA;EA6DV"}