@burdenoff/microfe-bigconsole 2026.1004.3 → 2026.1004.5
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/BigConsoleRoutes.d.ts +1 -1
- package/dist/bigconsole/BigConsoleRoutes.d.ts.map +1 -1
- package/dist/bigconsole/BigConsoleRoutes.js +15 -1
- package/dist/bigconsole/BigConsoleRoutes.js.map +1 -1
- package/dist/bigconsole/components/DrilldownDashboardRenderer.d.ts.map +1 -1
- package/dist/bigconsole/components/DrilldownDashboardRenderer.js +57 -56
- package/dist/bigconsole/components/DrilldownDashboardRenderer.js.map +1 -1
- package/dist/bigconsole/components/DrilldownModal.d.ts.map +1 -1
- package/dist/bigconsole/components/DrilldownModal.js +55 -53
- package/dist/bigconsole/components/DrilldownModal.js.map +1 -1
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.d.ts +3 -1
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.d.ts.map +1 -1
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js +40 -39
- package/dist/bigconsole/components/builder/inspector/DataBindingSection.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardCanvas.d.ts.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js +184 -177
- package/dist/bigconsole/components/dashboard/DashboardCanvas.js.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardGrid.d.ts.map +1 -1
- package/dist/bigconsole/components/dashboard/DashboardGrid.js +40 -22
- package/dist/bigconsole/components/dashboard/DashboardGrid.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.d.ts.map +1 -1
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js +31 -25
- package/dist/bigconsole/components/dashboard/ExportDashboardDialog.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.d.ts +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.d.ts.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js +115 -80
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/FilterEditor.js.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.d.ts.map +1 -1
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js +177 -146
- package/dist/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.js.map +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.d.ts +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.d.ts.map +1 -1
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js +375 -325
- package/dist/bigconsole/components/dashboard/ShareDialog/ShareDialog.js.map +1 -1
- package/dist/bigconsole/components/datasink/CacheTTLSelector.d.ts.map +1 -1
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js +7 -1
- package/dist/bigconsole/components/datasink/CacheTTLSelector.js.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.d.ts +3 -1
- package/dist/bigconsole/components/parser/ParserSelector.d.ts.map +1 -1
- package/dist/bigconsole/components/parser/ParserSelector.js +94 -94
- package/dist/bigconsole/components/parser/ParserSelector.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineCard.d.ts.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineCard.js +111 -89
- package/dist/bigconsole/components/pipeline/PipelineCard.js.map +1 -1
- package/dist/bigconsole/components/pipeline/PipelineScopePicker.d.ts +8 -0
- package/dist/bigconsole/components/pipeline/PipelineScopePicker.d.ts.map +1 -0
- package/dist/bigconsole/components/pipeline/PipelineScopePicker.js +52 -0
- package/dist/bigconsole/components/pipeline/PipelineScopePicker.js.map +1 -0
- package/dist/bigconsole/components/widgets/PropertiesPanel.d.ts.map +1 -1
- package/dist/bigconsole/components/widgets/PropertiesPanel.js +257 -221
- package/dist/bigconsole/components/widgets/PropertiesPanel.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetHeader.d.ts +1 -0
- package/dist/bigconsole/components/widgets/WidgetHeader.d.ts.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetHeader.js +29 -29
- package/dist/bigconsole/components/widgets/WidgetHeader.js.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.d.ts +2 -0
- package/dist/bigconsole/components/widgets/WidgetWrapper.d.ts.map +1 -1
- package/dist/bigconsole/components/widgets/WidgetWrapper.js +247 -239
- package/dist/bigconsole/components/widgets/WidgetWrapper.js.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.d.ts.map +1 -1
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js +6 -4
- package/dist/bigconsole/components/widgets/metric-card/MetricCardWidget.js.map +1 -1
- package/dist/bigconsole/components/widgets/states/EmptyState.d.ts +1 -0
- package/dist/bigconsole/components/widgets/states/EmptyState.d.ts.map +1 -1
- package/dist/bigconsole/components/widgets/states/EmptyState.js +4 -4
- package/dist/bigconsole/components/widgets/states/EmptyState.js.map +1 -1
- package/dist/bigconsole/components/workflow/WorkflowDesignPreview.d.ts +7 -0
- package/dist/bigconsole/components/workflow/WorkflowDesignPreview.d.ts.map +1 -0
- package/dist/bigconsole/components/workflow/WorkflowDesignPreview.js +94 -0
- package/dist/bigconsole/components/workflow/WorkflowDesignPreview.js.map +1 -0
- package/dist/bigconsole/components/workflow/WorkflowSinkLinkForm.d.ts +7 -0
- package/dist/bigconsole/components/workflow/WorkflowSinkLinkForm.d.ts.map +1 -0
- package/dist/bigconsole/components/workflow/WorkflowSinkLinkForm.js +101 -0
- package/dist/bigconsole/components/workflow/WorkflowSinkLinkForm.js.map +1 -0
- package/dist/bigconsole/hooks/useBigConsoleSettings.d.ts +16 -0
- package/dist/bigconsole/hooks/useBigConsoleSettings.d.ts.map +1 -0
- package/dist/bigconsole/hooks/useBigConsoleSettings.js +57 -0
- package/dist/bigconsole/hooks/useBigConsoleSettings.js.map +1 -0
- package/dist/bigconsole/hooks/useDashboardOperations.d.ts.map +1 -1
- package/dist/bigconsole/hooks/useDashboardOperations.js +102 -79
- package/dist/bigconsole/hooks/useDashboardOperations.js.map +1 -1
- package/dist/bigconsole/hooks/useExportDashboard.d.ts +3 -1
- package/dist/bigconsole/hooks/useExportDashboard.d.ts.map +1 -1
- package/dist/bigconsole/hooks/useExportDashboard.js +23 -13
- package/dist/bigconsole/hooks/useExportDashboard.js.map +1 -1
- package/dist/bigconsole/hooks/useFilterUrlSync.d.ts +18 -0
- package/dist/bigconsole/hooks/useFilterUrlSync.d.ts.map +1 -1
- package/dist/bigconsole/hooks/useFilterUrlSync.js +87 -57
- package/dist/bigconsole/hooks/useFilterUrlSync.js.map +1 -1
- package/dist/bigconsole/hooks/useGlobalFilters.d.ts.map +1 -1
- package/dist/bigconsole/hooks/useGlobalFilters.js +39 -29
- package/dist/bigconsole/hooks/useGlobalFilters.js.map +1 -1
- package/dist/bigconsole/hooks/usePageOperations.d.ts.map +1 -1
- package/dist/bigconsole/hooks/usePageOperations.js +1 -0
- package/dist/bigconsole/hooks/usePageOperations.js.map +1 -1
- package/dist/bigconsole/hooks/usePipelineOperations.d.ts.map +1 -1
- package/dist/bigconsole/hooks/usePipelineOperations.js +114 -112
- package/dist/bigconsole/hooks/usePipelineOperations.js.map +1 -1
- package/dist/bigconsole/hooks/useShareRecipients.d.ts +22 -0
- package/dist/bigconsole/hooks/useShareRecipients.d.ts.map +1 -0
- package/dist/bigconsole/hooks/useShareRecipients.js +198 -0
- package/dist/bigconsole/hooks/useShareRecipients.js.map +1 -0
- package/dist/bigconsole/pages/DashboardBuilderPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/DashboardBuilderPage.js +198 -193
- package/dist/bigconsole/pages/DashboardBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardViewPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/DashboardViewPage.js +171 -167
- package/dist/bigconsole/pages/DashboardViewPage.js.map +1 -1
- package/dist/bigconsole/pages/DashboardsPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/DashboardsPage.js +313 -266
- package/dist/bigconsole/pages/DashboardsPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/DataSinkBuilderPage.js +84 -79
- package/dist/bigconsole/pages/DataSinkBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/DataSinkViewPage.js +267 -257
- package/dist/bigconsole/pages/DataSinkViewPage.js.map +1 -1
- package/dist/bigconsole/pages/InsightsPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/InsightsPage.js +465 -402
- package/dist/bigconsole/pages/InsightsPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/PipelineBuilderPage.js +169 -157
- package/dist/bigconsole/pages/PipelineBuilderPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/PipelineViewPage.js +370 -230
- package/dist/bigconsole/pages/PipelineViewPage.js.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/PipelinesPage.js +181 -151
- package/dist/bigconsole/pages/PipelinesPage.js.map +1 -1
- package/dist/bigconsole/pages/SettingsPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/SettingsPage.js +188 -208
- package/dist/bigconsole/pages/SettingsPage.js.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/WidgetDemoPage.js +134 -117
- package/dist/bigconsole/pages/WidgetDemoPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/WorkflowViewPage.js +315 -267
- package/dist/bigconsole/pages/WorkflowViewPage.js.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.d.ts.map +1 -1
- package/dist/bigconsole/pages/WorkflowsPage.js +4 -3
- package/dist/bigconsole/pages/WorkflowsPage.js.map +1 -1
- package/dist/bigconsole/types/index.d.ts +4 -0
- package/dist/bigconsole/types/index.d.ts.map +1 -1
- package/dist/bigconsole/utils/drilldownParams.d.ts +3 -0
- package/dist/bigconsole/utils/drilldownParams.d.ts.map +1 -0
- package/dist/bigconsole/utils/drilldownParams.js +8 -0
- package/dist/bigconsole/utils/drilldownParams.js.map +1 -0
- package/dist/generated/wspace-operations.d.ts +148 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -1
- package/dist/generated/wspace-operations.js +172 -133
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.d.ts +21 -0
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/microfe-bigconsole.css +1 -1
- package/dist/translations/en.d.ts.map +1 -1
- package/package.json +2 -1
|
@@ -1,171 +1,202 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useDashboardStore as e, useGlobalFilterValues as t } from "../../../store/dashboardStore.js";
|
|
2
|
+
import "../../../store/index.js";
|
|
3
|
+
import { SECTION_FOCUS_RING as n } from "../../common/sectionStyles.js";
|
|
2
4
|
import "../../common/index.js";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
5
|
+
import ee from "../../../hooks/useGlobalFilters.js";
|
|
6
|
+
import r from "../../../hooks/useFilterUrlSync.js";
|
|
7
|
+
import i from "../../../hooks/useFilterPresets.js";
|
|
6
8
|
import "../../../hooks/index.js";
|
|
7
|
-
import { SEMANTIC_COLORS as
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import { useCallback as
|
|
12
|
-
import { jsx as
|
|
13
|
-
import { useI18n as
|
|
9
|
+
import { SEMANTIC_COLORS as a } from "../../../utils/semanticTokens.js";
|
|
10
|
+
import o from "./FilterChip.js";
|
|
11
|
+
import s from "./FilterEditor.js";
|
|
12
|
+
import c from "./FilterPresetSelector.js";
|
|
13
|
+
import { useCallback as l, useEffect as u, useState as d } from "react";
|
|
14
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
15
|
+
import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
14
16
|
//#region src/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.tsx
|
|
15
|
-
var
|
|
16
|
-
function
|
|
17
|
-
let { t:
|
|
18
|
-
|
|
17
|
+
var h = `inline-flex min-h-control-sm items-center gap-icon-gap rounded-button border border-[var(--color-border-subtle)] bg-bg-surface px-3 py-1 text-sm font-medium text-text-primary motion-safe:transition-colors hover:bg-bg-accentSubtle ${n}`, g = `inline-flex min-h-control-sm items-center gap-icon-gap rounded-button px-2 py-1 text-sm font-medium text-text-secondary motion-safe:transition-colors hover:bg-bg-accentSubtle ${n}`;
|
|
18
|
+
function _({ dashboardId: n, onFilterChange: _, collapsible: v = !0, className: y = "", enableUrlSync: b = !0, enablePresets: x = !0 }) {
|
|
19
|
+
let { t: S } = m(), { filters: C, loading: te, error: ne, fetchFilters: w, createFilter: T, updateFilter: E, deleteFilter: D } = ee(), O = t(), k = e((e) => e.setGlobalFilterValue), A = e((e) => e.setGlobalFilterValues), j = e((e) => e.clearGlobalFilterValue);
|
|
20
|
+
u(() => {
|
|
21
|
+
let t = e.getState().globalFilterValues, n = Object.fromEntries(C.filter((e) => e.defaultValue !== void 0 && !(e.id in t)).map((e) => [e.id, e.defaultValue]));
|
|
22
|
+
Object.keys(n).length && A({
|
|
23
|
+
...n,
|
|
24
|
+
...t
|
|
25
|
+
});
|
|
26
|
+
}, [
|
|
27
|
+
C,
|
|
28
|
+
O,
|
|
29
|
+
A
|
|
30
|
+
]);
|
|
31
|
+
let { getShareableUrl: M, clearUrlParams: N } = r({
|
|
32
|
+
enabled: b,
|
|
19
33
|
paramPrefix: "filter_",
|
|
20
34
|
debounceMs: 300
|
|
21
|
-
}), { presets:
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
}), { presets: P, activePresetId: F, loadPresets: I, applyPreset: L, saveCurrentAsPreset: R, deletePreset: z, clearActivePreset: B } = i(n), [V, re] = d(!1), [H, U] = d(!1), [W, G] = d(null), [K, q] = d(!1);
|
|
36
|
+
u(() => {
|
|
37
|
+
n && (w(n), x && I(n));
|
|
24
38
|
}, [
|
|
25
|
-
|
|
39
|
+
n,
|
|
26
40
|
w,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
]),
|
|
30
|
-
|
|
31
|
-
}, [
|
|
32
|
-
if (
|
|
33
|
-
let e =
|
|
34
|
-
e && JSON.stringify(e.values) !== JSON.stringify(
|
|
41
|
+
I,
|
|
42
|
+
x
|
|
43
|
+
]), u(() => {
|
|
44
|
+
_ && _(e.getState().globalFilterValues);
|
|
45
|
+
}, [O, _]), u(() => {
|
|
46
|
+
if (F && Object.keys(O).length > 0) {
|
|
47
|
+
let e = P.find((e) => e.id === F);
|
|
48
|
+
e && JSON.stringify(e.values) !== JSON.stringify(O) && B();
|
|
35
49
|
}
|
|
36
50
|
}, [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
O,
|
|
52
|
+
F,
|
|
53
|
+
P,
|
|
54
|
+
B
|
|
41
55
|
]);
|
|
42
|
-
let
|
|
43
|
-
|
|
44
|
-
}, [
|
|
45
|
-
|
|
46
|
-
}, []),
|
|
47
|
-
|
|
48
|
-
}, []), X =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
let J = l((e, t) => {
|
|
57
|
+
k(e, t);
|
|
58
|
+
}, [k]), Y = l(() => {
|
|
59
|
+
G(null), U(!0);
|
|
60
|
+
}, []), ie = l((e) => {
|
|
61
|
+
G(e), U(!0);
|
|
62
|
+
}, []), X = l(async (e) => {
|
|
63
|
+
if (W) {
|
|
64
|
+
if (!await E({
|
|
65
|
+
id: W.id,
|
|
66
|
+
name: e.name,
|
|
67
|
+
config: e.config,
|
|
68
|
+
defaultValue: e.defaultValue,
|
|
69
|
+
isRequired: e.isRequired
|
|
70
|
+
})) throw Error("Filter save failed");
|
|
71
|
+
} else if (!await T({
|
|
72
|
+
dashboardId: n,
|
|
73
|
+
name: e.name,
|
|
74
|
+
type: e.type,
|
|
75
|
+
config: e.config,
|
|
76
|
+
defaultValue: e.defaultValue,
|
|
77
|
+
isRequired: e.isRequired
|
|
78
|
+
})) throw Error("Filter save failed");
|
|
79
|
+
U(!1), G(null);
|
|
63
80
|
}, [
|
|
64
|
-
|
|
65
|
-
|
|
81
|
+
n,
|
|
82
|
+
W,
|
|
66
83
|
T,
|
|
67
84
|
E
|
|
68
|
-
]),
|
|
69
|
-
await D(e);
|
|
70
|
-
}, [D]),
|
|
71
|
-
|
|
85
|
+
]), ae = l(async (e) => {
|
|
86
|
+
await D(e) && j(e);
|
|
87
|
+
}, [D, j]), oe = l(() => {
|
|
88
|
+
A(Object.fromEntries(C.filter((e) => e.defaultValue !== void 0).map((e) => [e.id, e.defaultValue]))), N(), B();
|
|
72
89
|
}, [
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
90
|
+
C,
|
|
91
|
+
A,
|
|
92
|
+
N,
|
|
93
|
+
B
|
|
94
|
+
]), se = l(async () => {
|
|
95
|
+
let e = M();
|
|
78
96
|
try {
|
|
79
|
-
await navigator.clipboard.writeText(e),
|
|
97
|
+
await navigator.clipboard.writeText(e), q(!0), setTimeout(() => q(!1), 2e3);
|
|
80
98
|
} catch {}
|
|
81
|
-
}, [
|
|
82
|
-
F(e);
|
|
83
|
-
}, [F]), re = s((e, t) => {
|
|
84
|
-
I(e, t);
|
|
85
|
-
}, [I]), ie = s((e) => {
|
|
99
|
+
}, [M]), ce = l((e) => {
|
|
86
100
|
L(e);
|
|
87
|
-
}, [L]),
|
|
88
|
-
|
|
89
|
-
}, []),
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
}, [L]), Z = l((e, t) => {
|
|
102
|
+
R(e, t);
|
|
103
|
+
}, [R]), le = l((e) => {
|
|
104
|
+
z(e);
|
|
105
|
+
}, [z]), ue = l(() => {
|
|
106
|
+
re((e) => !e);
|
|
107
|
+
}, []), Q = C.filter((e) => O[e.id] !== void 0 && O[e.id] !== null && O[e.id] !== "").length;
|
|
108
|
+
if (te && C.length === 0 && !H) return /* @__PURE__ */ p("div", {
|
|
109
|
+
className: `flex flex-wrap items-center gap-control-gap border-b border-[var(--color-border-subtle)] bg-bg-sunken px-card-padding py-control-gap ${y}`,
|
|
92
110
|
role: "status",
|
|
93
111
|
"aria-live": "polite",
|
|
94
112
|
"data-testid": "global-filters-loading",
|
|
95
|
-
children: [/* @__PURE__ */
|
|
113
|
+
children: [/* @__PURE__ */ f("span", { className: "h-icon-sm w-icon-sm animate-spin rounded-full border-2 border-action-primary-bg border-t-transparent" }), /* @__PURE__ */ f("span", {
|
|
96
114
|
className: "text-sm text-text-secondary",
|
|
97
|
-
children:
|
|
115
|
+
children: S("bigconsole.filters.bar.loading", "Loading filters...")
|
|
116
|
+
})]
|
|
117
|
+
});
|
|
118
|
+
let $ = ne && /* @__PURE__ */ p("div", {
|
|
119
|
+
role: "alert",
|
|
120
|
+
className: "flex flex-wrap items-center gap-2 px-3 py-2 text-sm text-status-error-text",
|
|
121
|
+
children: [/* @__PURE__ */ f("span", { children: S("bigconsole.filters.bar.requestFailed", "Filters could not be loaded or saved. Try again.") }), /* @__PURE__ */ f("button", {
|
|
122
|
+
type: "button",
|
|
123
|
+
onClick: () => void w(n),
|
|
124
|
+
className: g,
|
|
125
|
+
children: S("bigconsole.filters.bar.retry", "Retry")
|
|
98
126
|
})]
|
|
99
|
-
})
|
|
100
|
-
|
|
127
|
+
});
|
|
128
|
+
return C.length === 0 ? /* @__PURE__ */ p("div", {
|
|
129
|
+
className: `flex flex-wrap items-center justify-between gap-control-gap border-b border-[var(--color-border-subtle)] bg-bg-sunken px-card-padding py-control-gap ${y}`,
|
|
101
130
|
"data-testid": "global-filters-empty",
|
|
102
131
|
children: [
|
|
103
|
-
/* @__PURE__ */
|
|
132
|
+
/* @__PURE__ */ p("div", {
|
|
104
133
|
className: "flex min-w-0 flex-wrap items-center gap-icon-gap",
|
|
105
|
-
children: [/* @__PURE__ */
|
|
134
|
+
children: [/* @__PURE__ */ f("h2", {
|
|
106
135
|
className: "text-sm font-semibold text-text-primary",
|
|
107
|
-
children:
|
|
108
|
-
}), /* @__PURE__ */
|
|
136
|
+
children: S("bigconsole.filters.bar.title", "Filters")
|
|
137
|
+
}), /* @__PURE__ */ f("span", {
|
|
109
138
|
className: "text-sm text-text-muted",
|
|
110
|
-
children:
|
|
139
|
+
children: S("bigconsole.filters.bar.noFiltersConfigured", "No filters configured")
|
|
111
140
|
})]
|
|
112
141
|
}),
|
|
113
|
-
/* @__PURE__ */
|
|
142
|
+
/* @__PURE__ */ f("button", {
|
|
114
143
|
type: "button",
|
|
115
|
-
onClick:
|
|
116
|
-
className:
|
|
117
|
-
children:
|
|
144
|
+
onClick: Y,
|
|
145
|
+
className: h,
|
|
146
|
+
children: S("bigconsole.filters.bar.addFilter", "+ Add Filter")
|
|
118
147
|
}),
|
|
119
|
-
|
|
120
|
-
|
|
148
|
+
$,
|
|
149
|
+
H && /* @__PURE__ */ f(s, {
|
|
150
|
+
filter: W,
|
|
121
151
|
onSave: X,
|
|
122
152
|
onClose: () => {
|
|
123
|
-
|
|
153
|
+
U(!1), G(null);
|
|
124
154
|
}
|
|
125
155
|
})
|
|
126
156
|
]
|
|
127
|
-
}) : /* @__PURE__ */
|
|
128
|
-
className: `flex min-w-0 flex-col border-b border-[var(--color-border-subtle)] bg-bg-sunken ${
|
|
157
|
+
}) : /* @__PURE__ */ p("section", {
|
|
158
|
+
className: `flex min-w-0 flex-col border-b border-[var(--color-border-subtle)] bg-bg-sunken ${y}`,
|
|
129
159
|
"aria-labelledby": "global-filters-heading",
|
|
130
160
|
"data-testid": "global-filters-bar",
|
|
131
161
|
children: [
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
162
|
+
$,
|
|
163
|
+
/* @__PURE__ */ p("div", {
|
|
164
|
+
className: `flex flex-wrap items-center justify-between gap-control-gap px-card-padding py-control-gap ${V ? "" : "border-b border-[var(--color-border-subtle)]"}`,
|
|
165
|
+
children: [/* @__PURE__ */ p("div", {
|
|
135
166
|
className: "flex min-w-0 flex-wrap items-center gap-icon-gap",
|
|
136
167
|
children: [
|
|
137
|
-
/* @__PURE__ */
|
|
168
|
+
/* @__PURE__ */ f("h2", {
|
|
138
169
|
id: "global-filters-heading",
|
|
139
170
|
className: "text-sm font-semibold text-text-primary",
|
|
140
|
-
children:
|
|
171
|
+
children: S("bigconsole.filters.bar.title", "Filters")
|
|
141
172
|
}),
|
|
142
|
-
/* @__PURE__ */
|
|
173
|
+
/* @__PURE__ */ f("span", {
|
|
143
174
|
className: "rounded-pill bg-bg-surface px-2 py-0.5 text-xs font-medium text-text-secondary",
|
|
144
|
-
children:
|
|
175
|
+
children: C.length
|
|
145
176
|
}),
|
|
146
|
-
|
|
177
|
+
Q > 0 && /* @__PURE__ */ f("span", {
|
|
147
178
|
className: "rounded-pill bg-[var(--color-status-success-bgSubtle)] px-2 py-0.5 text-xs font-medium text-status-success-text",
|
|
148
|
-
children:
|
|
179
|
+
children: S("bigconsole.filters.bar.activeCount", "{{count}} active", { count: Q ?? "" })
|
|
149
180
|
})
|
|
150
181
|
]
|
|
151
|
-
}), /* @__PURE__ */
|
|
182
|
+
}), /* @__PURE__ */ p("div", {
|
|
152
183
|
className: "flex min-w-0 flex-wrap items-center justify-end gap-control-gap",
|
|
153
184
|
children: [
|
|
154
|
-
|
|
155
|
-
presets:
|
|
156
|
-
activePresetId:
|
|
157
|
-
onApplyPreset:
|
|
158
|
-
onSavePreset:
|
|
159
|
-
onDeletePreset:
|
|
185
|
+
x && /* @__PURE__ */ f(c, {
|
|
186
|
+
presets: P,
|
|
187
|
+
activePresetId: F,
|
|
188
|
+
onApplyPreset: ce,
|
|
189
|
+
onSavePreset: Z,
|
|
190
|
+
onDeletePreset: le
|
|
160
191
|
}),
|
|
161
|
-
|
|
192
|
+
b && Q > 0 && /* @__PURE__ */ p("div", {
|
|
162
193
|
style: { position: "relative" },
|
|
163
|
-
children: [/* @__PURE__ */
|
|
194
|
+
children: [/* @__PURE__ */ p("button", {
|
|
164
195
|
type: "button",
|
|
165
|
-
onClick:
|
|
166
|
-
title:
|
|
167
|
-
className:
|
|
168
|
-
children: [/* @__PURE__ */
|
|
196
|
+
onClick: se,
|
|
197
|
+
title: S("bigconsole.filters.bar.shareUrlTitle", "Copy shareable URL with filters"),
|
|
198
|
+
className: h,
|
|
199
|
+
children: [/* @__PURE__ */ p("svg", {
|
|
169
200
|
width: "14",
|
|
170
201
|
height: "14",
|
|
171
202
|
viewBox: "0 0 24 24",
|
|
@@ -173,17 +204,17 @@ function h({ dashboardId: e, onFilterChange: h, collapsible: g = !0, className:
|
|
|
173
204
|
stroke: "currentColor",
|
|
174
205
|
strokeWidth: "2",
|
|
175
206
|
children: [
|
|
176
|
-
/* @__PURE__ */
|
|
177
|
-
/* @__PURE__ */
|
|
178
|
-
/* @__PURE__ */
|
|
207
|
+
/* @__PURE__ */ f("path", { d: "M4 12v8a2 2 0 002 2h12a2 2 0 002-2v-8" }),
|
|
208
|
+
/* @__PURE__ */ f("polyline", { points: "16,6 12,2 8,6" }),
|
|
209
|
+
/* @__PURE__ */ f("line", {
|
|
179
210
|
x1: "12",
|
|
180
211
|
y1: "2",
|
|
181
212
|
x2: "12",
|
|
182
213
|
y2: "15"
|
|
183
214
|
})
|
|
184
215
|
]
|
|
185
|
-
}),
|
|
186
|
-
}),
|
|
216
|
+
}), S("bigconsole.filters.bar.share", "Share")]
|
|
217
|
+
}), K && /* @__PURE__ */ f("div", {
|
|
187
218
|
style: {
|
|
188
219
|
position: "absolute",
|
|
189
220
|
top: "100%",
|
|
@@ -191,62 +222,62 @@ function h({ dashboardId: e, onFilterChange: h, collapsible: g = !0, className:
|
|
|
191
222
|
transform: "translateX(-50%)",
|
|
192
223
|
marginTop: "4px",
|
|
193
224
|
padding: "6px 12px",
|
|
194
|
-
backgroundColor:
|
|
195
|
-
color:
|
|
225
|
+
backgroundColor: a.textPrimary,
|
|
226
|
+
color: a.bgPrimary,
|
|
196
227
|
fontSize: "12px",
|
|
197
228
|
borderRadius: "4px",
|
|
198
229
|
whiteSpace: "nowrap",
|
|
199
230
|
zIndex: 100001
|
|
200
231
|
},
|
|
201
|
-
children:
|
|
232
|
+
children: S("bigconsole.filters.bar.urlCopied", "URL copied!")
|
|
202
233
|
})]
|
|
203
234
|
}),
|
|
204
|
-
|
|
235
|
+
Q > 0 && /* @__PURE__ */ f("button", {
|
|
205
236
|
type: "button",
|
|
206
|
-
onClick:
|
|
207
|
-
className: `${
|
|
208
|
-
children:
|
|
237
|
+
onClick: oe,
|
|
238
|
+
className: `${g} text-status-error-text`,
|
|
239
|
+
children: S("bigconsole.filters.bar.resetAll", "Reset all")
|
|
209
240
|
}),
|
|
210
|
-
/* @__PURE__ */
|
|
241
|
+
/* @__PURE__ */ f("button", {
|
|
211
242
|
type: "button",
|
|
212
|
-
onClick:
|
|
213
|
-
className:
|
|
214
|
-
children:
|
|
243
|
+
onClick: Y,
|
|
244
|
+
className: h,
|
|
245
|
+
children: S("bigconsole.filters.bar.addFilter", "+ Add Filter")
|
|
215
246
|
}),
|
|
216
|
-
|
|
247
|
+
v && /* @__PURE__ */ f("button", {
|
|
217
248
|
type: "button",
|
|
218
|
-
onClick:
|
|
219
|
-
"aria-expanded": !
|
|
220
|
-
"aria-controls":
|
|
221
|
-
className:
|
|
222
|
-
children:
|
|
249
|
+
onClick: ue,
|
|
250
|
+
"aria-expanded": !V,
|
|
251
|
+
"aria-controls": V ? void 0 : "global-filters-chips",
|
|
252
|
+
className: g,
|
|
253
|
+
children: V ? S("bigconsole.filters.bar.expand", "▼ Expand") : S("bigconsole.filters.bar.collapse", "▲ Collapse")
|
|
223
254
|
})
|
|
224
255
|
]
|
|
225
256
|
})]
|
|
226
257
|
}),
|
|
227
|
-
!
|
|
258
|
+
!V && /* @__PURE__ */ f("div", {
|
|
228
259
|
id: "global-filters-chips",
|
|
229
260
|
className: "relative flex flex-wrap gap-control-gap px-card-padding py-control-gap",
|
|
230
261
|
style: { overflow: "visible" },
|
|
231
|
-
children:
|
|
262
|
+
children: C.map((e) => /* @__PURE__ */ f(o, {
|
|
232
263
|
filter: e,
|
|
233
|
-
value:
|
|
234
|
-
onChange: (t) =>
|
|
235
|
-
onEdit: () =>
|
|
236
|
-
onDelete: () =>
|
|
264
|
+
value: O[e.id],
|
|
265
|
+
onChange: (t) => J(e.id, t),
|
|
266
|
+
onEdit: () => ie(e),
|
|
267
|
+
onDelete: () => ae(e.id)
|
|
237
268
|
}, e.id))
|
|
238
269
|
}),
|
|
239
|
-
|
|
240
|
-
filter:
|
|
270
|
+
H && /* @__PURE__ */ f(s, {
|
|
271
|
+
filter: W,
|
|
241
272
|
onSave: X,
|
|
242
273
|
onClose: () => {
|
|
243
|
-
|
|
274
|
+
U(!1), G(null);
|
|
244
275
|
}
|
|
245
276
|
})
|
|
246
277
|
]
|
|
247
278
|
});
|
|
248
279
|
}
|
|
249
280
|
//#endregion
|
|
250
|
-
export {
|
|
281
|
+
export { _ as default };
|
|
251
282
|
|
|
252
283
|
//# sourceMappingURL=GlobalFiltersBar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GlobalFiltersBar.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.tsx"],"sourcesContent":["/**\n * GlobalFiltersBar Component\n *\n * Displays and manages global dashboard filters.\n * v2.0: Added URL persistence and filter presets support.\n */\n\nimport React, { useState, useEffect, useCallback } from 'react';\nimport {\n useGlobalFilters,\n useFilterUrlSync,\n useFilterPresets,\n type GlobalFilter,\n type FilterType,\n} from '../../../hooks';\nimport { FilterChip } from './FilterChip';\nimport { FilterEditor } from './FilterEditor';\nimport { FilterPresetSelector } from './FilterPresetSelector';\nimport { SEMANTIC_COLORS } from '../../../utils/semanticTokens';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { SECTION_FOCUS_RING } from '../../common';\n\n// ============================================================================\n// Local class vocabulary\n// ============================================================================\n\n/**\n * The filters bar configures the board below it. Before this it shipped a\n * saturated primary \"+ Add Filter\" with an indigo glow and a drop-shadowed\n * container, which made the configuration louder than the data it filtered.\n * Everything here is deliberately secondary weight.\n */\nconst SECONDARY_BUTTON_CLASSES = `inline-flex min-h-control-sm items-center gap-icon-gap rounded-button border border-[var(--color-border-subtle)] bg-bg-surface px-3 py-1 text-sm font-medium text-text-primary motion-safe:transition-colors hover:bg-bg-accentSubtle ${SECTION_FOCUS_RING}`;\n\n/** Text-only affordances (reset, collapse) sit a step below that again. */\nconst QUIET_BUTTON_CLASSES = `inline-flex min-h-control-sm items-center gap-icon-gap rounded-button px-2 py-1 text-sm font-medium text-text-secondary motion-safe:transition-colors hover:bg-bg-accentSubtle ${SECTION_FOCUS_RING}`;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface GlobalFiltersBarProps {\n dashboardId: string;\n onFilterChange?: (values: Record<string, unknown>) => void;\n collapsible?: boolean;\n className?: string;\n /** Enable URL sync for shareable filtered views */\n enableUrlSync?: boolean;\n /** Enable filter presets */\n enablePresets?: boolean;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function GlobalFiltersBar({\n dashboardId,\n onFilterChange,\n collapsible = true,\n className = '',\n enableUrlSync = true,\n enablePresets = true,\n}: GlobalFiltersBarProps) {\n const { t } = useI18n();\n const {\n filters,\n activeValues,\n loading,\n fetchFilters,\n createFilter,\n updateFilter,\n deleteFilter,\n setFilterValue,\n resetFilters,\n } = useGlobalFilters();\n\n // URL Sync hook\n const { getShareableUrl, clearUrlParams } = useFilterUrlSync({\n enabled: enableUrlSync,\n paramPrefix: 'filter_',\n debounceMs: 300,\n });\n\n // Filter Presets hook\n const {\n presets,\n activePresetId,\n loadPresets,\n applyPreset,\n saveCurrentAsPreset,\n deletePreset: removePreset,\n clearActivePreset,\n } = useFilterPresets(dashboardId);\n\n const [isCollapsed, setIsCollapsed] = useState(false);\n const [isEditorOpen, setIsEditorOpen] = useState(false);\n const [editingFilter, setEditingFilter] = useState<GlobalFilter | null>(null);\n const [showShareTooltip, setShowShareTooltip] = useState(false);\n\n // Fetch filters on mount\n useEffect(() => {\n if (dashboardId) {\n fetchFilters(dashboardId);\n if (enablePresets) {\n loadPresets(dashboardId);\n }\n }\n }, [dashboardId, fetchFilters, loadPresets, enablePresets]);\n\n // Notify parent of filter changes\n useEffect(() => {\n if (onFilterChange) {\n onFilterChange(activeValues);\n }\n }, [activeValues, onFilterChange]);\n\n // Clear active preset when filter values change manually\n useEffect(() => {\n if (activePresetId && Object.keys(activeValues).length > 0) {\n // Check if current values differ from active preset\n const preset = presets.find((p) => p.id === activePresetId);\n if (preset) {\n const presetStr = JSON.stringify(preset.values);\n const currentStr = JSON.stringify(activeValues);\n if (presetStr !== currentStr) {\n clearActivePreset();\n }\n }\n }\n }, [activeValues, activePresetId, presets, clearActivePreset]);\n\n // Handle filter value change\n const handleFilterChange = useCallback(\n (filterId: string, value: unknown) => {\n setFilterValue(filterId, value);\n },\n [setFilterValue]\n );\n\n // Handle add new filter\n const handleAddFilter = useCallback(() => {\n setEditingFilter(null);\n setIsEditorOpen(true);\n }, []);\n\n // Handle edit filter\n const handleEditFilter = useCallback((filter: GlobalFilter) => {\n setEditingFilter(filter);\n setIsEditorOpen(true);\n }, []);\n\n // Handle save filter\n const handleSaveFilter = useCallback(\n async (data: {\n name: string;\n type: FilterType;\n config: Record<string, unknown>;\n defaultValue?: unknown;\n isRequired?: boolean;\n }) => {\n if (editingFilter) {\n await updateFilter({\n id: editingFilter.id,\n name: data.name,\n config: data.config,\n defaultValue: data.defaultValue,\n isRequired: data.isRequired,\n });\n } else {\n await createFilter({\n dashboardId,\n name: data.name,\n type: data.type,\n config: data.config,\n defaultValue: data.defaultValue,\n isRequired: data.isRequired,\n });\n }\n setIsEditorOpen(false);\n setEditingFilter(null);\n },\n [dashboardId, editingFilter, createFilter, updateFilter]\n );\n\n // Handle delete filter\n const handleDeleteFilter = useCallback(\n async (filterId: string) => {\n await deleteFilter(filterId);\n },\n [deleteFilter]\n );\n\n // Handle reset all filters\n const handleResetAll = useCallback(() => {\n resetFilters();\n clearUrlParams();\n clearActivePreset();\n }, [resetFilters, clearUrlParams, clearActivePreset]);\n\n // Handle copy shareable URL\n const handleCopyShareableUrl = useCallback(async () => {\n const url = getShareableUrl();\n try {\n await navigator.clipboard.writeText(url);\n setShowShareTooltip(true);\n setTimeout(() => setShowShareTooltip(false), 2000);\n } catch {\n // Failed to copy URL to clipboard\n }\n }, [getShareableUrl]);\n\n // Handle apply preset\n const handleApplyPreset = useCallback(\n (presetId: string) => {\n applyPreset(presetId);\n },\n [applyPreset]\n );\n\n // Handle save current as preset\n const handleSavePreset = useCallback(\n (name: string, description?: string) => {\n saveCurrentAsPreset(name, description);\n },\n [saveCurrentAsPreset]\n );\n\n // Handle delete preset\n const handleDeletePreset = useCallback(\n (presetId: string) => {\n removePreset(presetId);\n },\n [removePreset]\n );\n\n // Toggle collapse\n const toggleCollapse = useCallback(() => {\n setIsCollapsed((prev) => !prev);\n }, []);\n\n // Count active filters\n const activeFilterCount = Object.keys(activeValues).filter(\n (key) => activeValues[key] !== undefined && activeValues[key] !== null && activeValues[key] !== ''\n ).length;\n\n if (loading && filters.length === 0) {\n return (\n <div\n className={`flex flex-wrap items-center gap-control-gap border-b border-[var(--color-border-subtle)] bg-bg-sunken px-card-padding py-control-gap ${className}`}\n role=\"status\"\n aria-live=\"polite\"\n data-testid=\"global-filters-loading\"\n >\n <span className=\"h-icon-sm w-icon-sm animate-spin rounded-full border-2 border-action-primary-bg border-t-transparent\" />\n <span className=\"text-sm text-text-secondary\">{t('bigconsole.filters.bar.loading', 'Loading filters...')}</span>\n </div>\n );\n }\n\n // Show empty state with \"Add Filter\" button when no filters exist\n if (filters.length === 0) {\n return (\n <div\n className={`flex flex-wrap items-center justify-between gap-control-gap border-b border-[var(--color-border-subtle)] bg-bg-sunken px-card-padding py-control-gap ${className}`}\n data-testid=\"global-filters-empty\"\n >\n <div className=\"flex min-w-0 flex-wrap items-center gap-icon-gap\">\n <h2 className=\"text-sm font-semibold text-text-primary\">{t('bigconsole.filters.bar.title', 'Filters')}</h2>\n <span className=\"text-sm text-text-muted\">\n {t('bigconsole.filters.bar.noFiltersConfigured', 'No filters configured')}\n </span>\n </div>\n <button type=\"button\" onClick={handleAddFilter} className={SECONDARY_BUTTON_CLASSES}>\n {t('bigconsole.filters.bar.addFilter', '+ Add Filter')}\n </button>\n\n {/* Filter Editor Modal */}\n {isEditorOpen && (\n <FilterEditor\n filter={editingFilter}\n onSave={handleSaveFilter}\n onClose={() => {\n setIsEditorOpen(false);\n setEditingFilter(null);\n }}\n />\n )}\n </div>\n );\n }\n\n return (\n <section\n // A configuration band, not a result: recessed surface, no drop shadow,\n // secondary-weight controls. It sits directly above the board and must\n // stay quieter than it.\n className={`flex min-w-0 flex-col border-b border-[var(--color-border-subtle)] bg-bg-sunken ${className}`}\n aria-labelledby=\"global-filters-heading\"\n data-testid=\"global-filters-bar\"\n >\n {/* Header */}\n <div\n className={`flex flex-wrap items-center justify-between gap-control-gap px-card-padding py-control-gap ${\n isCollapsed ? '' : 'border-b border-[var(--color-border-subtle)]'\n }`}\n >\n <div className=\"flex min-w-0 flex-wrap items-center gap-icon-gap\">\n <h2 id=\"global-filters-heading\" className=\"text-sm font-semibold text-text-primary\">\n {t('bigconsole.filters.bar.title', 'Filters')}\n </h2>\n <span className=\"rounded-pill bg-bg-surface px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {filters.length}\n </span>\n {activeFilterCount > 0 && (\n <span className=\"rounded-pill bg-[var(--color-status-success-bgSubtle)] px-2 py-0.5 text-xs font-medium text-status-success-text\">\n {t('bigconsole.filters.bar.activeCount', '{{count}} active', {\n count: activeFilterCount ?? '',\n })}\n </span>\n )}\n </div>\n\n <div className=\"flex min-w-0 flex-wrap items-center justify-end gap-control-gap\">\n {/* Filter Presets Selector */}\n {enablePresets && (\n <FilterPresetSelector\n presets={presets}\n activePresetId={activePresetId}\n onApplyPreset={handleApplyPreset}\n onSavePreset={handleSavePreset}\n onDeletePreset={handleDeletePreset}\n />\n )}\n\n {/* Share URL Button */}\n {enableUrlSync && activeFilterCount > 0 && (\n <div style={{ position: 'relative' }}>\n <button\n type=\"button\"\n onClick={handleCopyShareableUrl}\n title={t('bigconsole.filters.bar.shareUrlTitle', 'Copy shareable URL with filters')}\n className={SECONDARY_BUTTON_CLASSES}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M4 12v8a2 2 0 002 2h12a2 2 0 002-2v-8\" />\n <polyline points=\"16,6 12,2 8,6\" />\n <line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"15\" />\n </svg>\n {t('bigconsole.filters.bar.share', 'Share')}\n </button>\n {showShareTooltip && (\n <div\n style={{\n position: 'absolute',\n top: '100%',\n left: '50%',\n transform: 'translateX(-50%)',\n marginTop: '4px',\n padding: '6px 12px',\n backgroundColor: SEMANTIC_COLORS.textPrimary,\n color: SEMANTIC_COLORS.bgPrimary,\n fontSize: '12px',\n borderRadius: '4px',\n whiteSpace: 'nowrap',\n zIndex: 100001,\n }}\n >\n {t('bigconsole.filters.bar.urlCopied', 'URL copied!')}\n </div>\n )}\n </div>\n )}\n\n {/* Reset Button */}\n {activeFilterCount > 0 && (\n <button type=\"button\" onClick={handleResetAll} className={`${QUIET_BUTTON_CLASSES} text-status-error-text`}>\n {t('bigconsole.filters.bar.resetAll', 'Reset all')}\n </button>\n )}\n\n {/* Add Filter Button */}\n <button type=\"button\" onClick={handleAddFilter} className={SECONDARY_BUTTON_CLASSES}>\n {t('bigconsole.filters.bar.addFilter', '+ Add Filter')}\n </button>\n\n {/* Collapse Button */}\n {collapsible && (\n <button\n type=\"button\"\n onClick={toggleCollapse}\n aria-expanded={!isCollapsed}\n // The chips container is unmounted while collapsed; pointing\n // aria-controls at a missing id is an invalid reference, so only\n // advertise it when the target actually exists.\n aria-controls={isCollapsed ? undefined : 'global-filters-chips'}\n className={QUIET_BUTTON_CLASSES}\n >\n {isCollapsed\n ? t('bigconsole.filters.bar.expand', '▼ Expand')\n : t('bigconsole.filters.bar.collapse', '▲ Collapse')}\n </button>\n )}\n </div>\n </div>\n\n {/* Filters List */}\n {!isCollapsed && (\n <div\n id=\"global-filters-chips\"\n className=\"relative flex flex-wrap gap-control-gap px-card-padding py-control-gap\"\n style={{ overflow: 'visible' }}\n >\n {filters.map((filter) => (\n <FilterChip\n key={filter.id}\n filter={filter}\n value={activeValues[filter.id]}\n onChange={(value) => handleFilterChange(filter.id, value)}\n onEdit={() => handleEditFilter(filter)}\n onDelete={() => handleDeleteFilter(filter.id)}\n />\n ))}\n </div>\n )}\n\n {/* Filter Editor Modal */}\n {isEditorOpen && (\n <FilterEditor\n filter={editingFilter}\n onSave={handleSaveFilter}\n onClose={() => {\n setIsEditorOpen(false);\n setEditingFilter(null);\n }}\n />\n )}\n </section>\n );\n}\n\nexport default GlobalFiltersBar;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GlobalFiltersBar.js","names":[],"sources":["../../../../../src/bigconsole/components/dashboard/GlobalFiltersBar/GlobalFiltersBar.tsx"],"sourcesContent":["/**\n * GlobalFiltersBar Component\n *\n * Displays and manages global dashboard filters.\n * v2.0: Added URL persistence and filter presets support.\n */\n\nimport React, { useState, useEffect, useCallback } from 'react';\nimport {\n useGlobalFilters,\n useFilterUrlSync,\n useFilterPresets,\n type GlobalFilter,\n type FilterType,\n} from '../../../hooks';\nimport { FilterChip } from './FilterChip';\nimport { useDashboardStore, useGlobalFilterValues } from '../../../store';\nimport { FilterEditor } from './FilterEditor';\nimport { FilterPresetSelector } from './FilterPresetSelector';\nimport { SEMANTIC_COLORS } from '../../../utils/semanticTokens';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { SECTION_FOCUS_RING } from '../../common';\n\n// ============================================================================\n// Local class vocabulary\n// ============================================================================\n\n/**\n * The filters bar configures the board below it. Before this it shipped a\n * saturated primary \"+ Add Filter\" with an indigo glow and a drop-shadowed\n * container, which made the configuration louder than the data it filtered.\n * Everything here is deliberately secondary weight.\n */\nconst SECONDARY_BUTTON_CLASSES = `inline-flex min-h-control-sm items-center gap-icon-gap rounded-button border border-[var(--color-border-subtle)] bg-bg-surface px-3 py-1 text-sm font-medium text-text-primary motion-safe:transition-colors hover:bg-bg-accentSubtle ${SECTION_FOCUS_RING}`;\n\n/** Text-only affordances (reset, collapse) sit a step below that again. */\nconst QUIET_BUTTON_CLASSES = `inline-flex min-h-control-sm items-center gap-icon-gap rounded-button px-2 py-1 text-sm font-medium text-text-secondary motion-safe:transition-colors hover:bg-bg-accentSubtle ${SECTION_FOCUS_RING}`;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface GlobalFiltersBarProps {\n dashboardId: string;\n onFilterChange?: (values: Record<string, unknown>) => void;\n collapsible?: boolean;\n className?: string;\n /** Enable URL sync for shareable filtered views */\n enableUrlSync?: boolean;\n /** Enable filter presets */\n enablePresets?: boolean;\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function GlobalFiltersBar({\n dashboardId,\n onFilterChange,\n collapsible = true,\n className = '',\n enableUrlSync = true,\n enablePresets = true,\n}: GlobalFiltersBarProps) {\n const { t } = useI18n();\n const { filters, loading, error, fetchFilters, createFilter, updateFilter, deleteFilter } = useGlobalFilters();\n\n // Widgets, presets, URL hydration and the controls share one value store.\n // The definition hook's private defaults must never replace hydrated values.\n const activeValues = useGlobalFilterValues();\n const setFilterValue = useDashboardStore((state) => state.setGlobalFilterValue);\n const setFilterValues = useDashboardStore((state) => state.setGlobalFilterValues);\n const clearFilterValue = useDashboardStore((state) => state.clearGlobalFilterValue);\n\n useEffect(() => {\n const current = useDashboardStore.getState().globalFilterValues;\n const defaults = Object.fromEntries(\n filters\n .filter((filter) => filter.defaultValue !== undefined && !(filter.id in current))\n .map((filter) => [filter.id, filter.defaultValue])\n );\n if (Object.keys(defaults).length) setFilterValues({ ...defaults, ...current });\n }, [filters, activeValues, setFilterValues]);\n\n // URL Sync hook\n const { getShareableUrl, clearUrlParams } = useFilterUrlSync({\n enabled: enableUrlSync,\n paramPrefix: 'filter_',\n debounceMs: 300,\n });\n\n // Filter Presets hook\n const {\n presets,\n activePresetId,\n loadPresets,\n applyPreset,\n saveCurrentAsPreset,\n deletePreset: removePreset,\n clearActivePreset,\n } = useFilterPresets(dashboardId);\n\n const [isCollapsed, setIsCollapsed] = useState(false);\n const [isEditorOpen, setIsEditorOpen] = useState(false);\n const [editingFilter, setEditingFilter] = useState<GlobalFilter | null>(null);\n const [showShareTooltip, setShowShareTooltip] = useState(false);\n\n // Fetch filters on mount\n useEffect(() => {\n if (dashboardId) {\n fetchFilters(dashboardId);\n if (enablePresets) {\n loadPresets(dashboardId);\n }\n }\n }, [dashboardId, fetchFilters, loadPresets, enablePresets]);\n\n // Notify parent of filter changes\n useEffect(() => {\n if (onFilterChange) {\n // URL hydration/default initialization can update the store after this\n // render. Notify with its current values, never an old empty snapshot.\n onFilterChange(useDashboardStore.getState().globalFilterValues);\n }\n }, [activeValues, onFilterChange]);\n\n // Clear active preset when filter values change manually\n useEffect(() => {\n if (activePresetId && Object.keys(activeValues).length > 0) {\n // Check if current values differ from active preset\n const preset = presets.find((p) => p.id === activePresetId);\n if (preset) {\n const presetStr = JSON.stringify(preset.values);\n const currentStr = JSON.stringify(activeValues);\n if (presetStr !== currentStr) {\n clearActivePreset();\n }\n }\n }\n }, [activeValues, activePresetId, presets, clearActivePreset]);\n\n // Handle filter value change\n const handleFilterChange = useCallback(\n (filterId: string, value: unknown) => {\n setFilterValue(filterId, value);\n },\n [setFilterValue]\n );\n\n // Handle add new filter\n const handleAddFilter = useCallback(() => {\n setEditingFilter(null);\n setIsEditorOpen(true);\n }, []);\n\n // Handle edit filter\n const handleEditFilter = useCallback((filter: GlobalFilter) => {\n setEditingFilter(filter);\n setIsEditorOpen(true);\n }, []);\n\n // Handle save filter\n const handleSaveFilter = useCallback(\n async (data: {\n name: string;\n type: FilterType;\n config: Record<string, unknown>;\n defaultValue?: unknown;\n isRequired?: boolean;\n }) => {\n if (editingFilter) {\n const saved = await updateFilter({\n id: editingFilter.id,\n name: data.name,\n config: data.config,\n defaultValue: data.defaultValue,\n isRequired: data.isRequired,\n });\n if (!saved) throw new Error('Filter save failed');\n } else {\n const saved = await createFilter({\n dashboardId,\n name: data.name,\n type: data.type,\n config: data.config,\n defaultValue: data.defaultValue,\n isRequired: data.isRequired,\n });\n if (!saved) throw new Error('Filter save failed');\n }\n setIsEditorOpen(false);\n setEditingFilter(null);\n },\n [dashboardId, editingFilter, createFilter, updateFilter]\n );\n\n // Handle delete filter\n const handleDeleteFilter = useCallback(\n async (filterId: string) => {\n if (await deleteFilter(filterId)) clearFilterValue(filterId);\n },\n [deleteFilter, clearFilterValue]\n );\n\n // Handle reset all filters\n const handleResetAll = useCallback(() => {\n setFilterValues(\n Object.fromEntries(\n filters.filter((filter) => filter.defaultValue !== undefined).map((filter) => [filter.id, filter.defaultValue])\n )\n );\n clearUrlParams();\n clearActivePreset();\n }, [filters, setFilterValues, clearUrlParams, clearActivePreset]);\n\n // Handle copy shareable URL\n const handleCopyShareableUrl = useCallback(async () => {\n const url = getShareableUrl();\n try {\n await navigator.clipboard.writeText(url);\n setShowShareTooltip(true);\n setTimeout(() => setShowShareTooltip(false), 2000);\n } catch {\n // Failed to copy URL to clipboard\n }\n }, [getShareableUrl]);\n\n // Handle apply preset\n const handleApplyPreset = useCallback(\n (presetId: string) => {\n applyPreset(presetId);\n },\n [applyPreset]\n );\n\n // Handle save current as preset\n const handleSavePreset = useCallback(\n (name: string, description?: string) => {\n saveCurrentAsPreset(name, description);\n },\n [saveCurrentAsPreset]\n );\n\n // Handle delete preset\n const handleDeletePreset = useCallback(\n (presetId: string) => {\n removePreset(presetId);\n },\n [removePreset]\n );\n\n // Toggle collapse\n const toggleCollapse = useCallback(() => {\n setIsCollapsed((prev) => !prev);\n }, []);\n\n // Count active filters\n const activeFilterCount = filters.filter(\n (filter) =>\n activeValues[filter.id] !== undefined && activeValues[filter.id] !== null && activeValues[filter.id] !== ''\n ).length;\n\n if (loading && filters.length === 0 && !isEditorOpen) {\n return (\n <div\n className={`flex flex-wrap items-center gap-control-gap border-b border-[var(--color-border-subtle)] bg-bg-sunken px-card-padding py-control-gap ${className}`}\n role=\"status\"\n aria-live=\"polite\"\n data-testid=\"global-filters-loading\"\n >\n <span className=\"h-icon-sm w-icon-sm animate-spin rounded-full border-2 border-action-primary-bg border-t-transparent\" />\n <span className=\"text-sm text-text-secondary\">{t('bigconsole.filters.bar.loading', 'Loading filters...')}</span>\n </div>\n );\n }\n\n const errorFeedback = error && (\n <div role=\"alert\" className=\"flex flex-wrap items-center gap-2 px-3 py-2 text-sm text-status-error-text\">\n <span>{t('bigconsole.filters.bar.requestFailed', 'Filters could not be loaded or saved. Try again.')}</span>\n <button type=\"button\" onClick={() => void fetchFilters(dashboardId)} className={QUIET_BUTTON_CLASSES}>\n {t('bigconsole.filters.bar.retry', 'Retry')}\n </button>\n </div>\n );\n\n // Show empty state with \"Add Filter\" button when no filters exist\n if (filters.length === 0) {\n return (\n <div\n className={`flex flex-wrap items-center justify-between gap-control-gap border-b border-[var(--color-border-subtle)] bg-bg-sunken px-card-padding py-control-gap ${className}`}\n data-testid=\"global-filters-empty\"\n >\n <div className=\"flex min-w-0 flex-wrap items-center gap-icon-gap\">\n <h2 className=\"text-sm font-semibold text-text-primary\">{t('bigconsole.filters.bar.title', 'Filters')}</h2>\n <span className=\"text-sm text-text-muted\">\n {t('bigconsole.filters.bar.noFiltersConfigured', 'No filters configured')}\n </span>\n </div>\n <button type=\"button\" onClick={handleAddFilter} className={SECONDARY_BUTTON_CLASSES}>\n {t('bigconsole.filters.bar.addFilter', '+ Add Filter')}\n </button>\n\n {errorFeedback}\n {/* Filter Editor Modal */}\n {isEditorOpen && (\n <FilterEditor\n filter={editingFilter}\n onSave={handleSaveFilter}\n onClose={() => {\n setIsEditorOpen(false);\n setEditingFilter(null);\n }}\n />\n )}\n </div>\n );\n }\n\n return (\n <section\n // A configuration band, not a result: recessed surface, no drop shadow,\n // secondary-weight controls. It sits directly above the board and must\n // stay quieter than it.\n className={`flex min-w-0 flex-col border-b border-[var(--color-border-subtle)] bg-bg-sunken ${className}`}\n aria-labelledby=\"global-filters-heading\"\n data-testid=\"global-filters-bar\"\n >\n {errorFeedback}\n {/* Header */}\n <div\n className={`flex flex-wrap items-center justify-between gap-control-gap px-card-padding py-control-gap ${\n isCollapsed ? '' : 'border-b border-[var(--color-border-subtle)]'\n }`}\n >\n <div className=\"flex min-w-0 flex-wrap items-center gap-icon-gap\">\n <h2 id=\"global-filters-heading\" className=\"text-sm font-semibold text-text-primary\">\n {t('bigconsole.filters.bar.title', 'Filters')}\n </h2>\n <span className=\"rounded-pill bg-bg-surface px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {filters.length}\n </span>\n {activeFilterCount > 0 && (\n <span className=\"rounded-pill bg-[var(--color-status-success-bgSubtle)] px-2 py-0.5 text-xs font-medium text-status-success-text\">\n {t('bigconsole.filters.bar.activeCount', '{{count}} active', {\n count: activeFilterCount ?? '',\n })}\n </span>\n )}\n </div>\n\n <div className=\"flex min-w-0 flex-wrap items-center justify-end gap-control-gap\">\n {/* Filter Presets Selector */}\n {enablePresets && (\n <FilterPresetSelector\n presets={presets}\n activePresetId={activePresetId}\n onApplyPreset={handleApplyPreset}\n onSavePreset={handleSavePreset}\n onDeletePreset={handleDeletePreset}\n />\n )}\n\n {/* Share URL Button */}\n {enableUrlSync && activeFilterCount > 0 && (\n <div style={{ position: 'relative' }}>\n <button\n type=\"button\"\n onClick={handleCopyShareableUrl}\n title={t('bigconsole.filters.bar.shareUrlTitle', 'Copy shareable URL with filters')}\n className={SECONDARY_BUTTON_CLASSES}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M4 12v8a2 2 0 002 2h12a2 2 0 002-2v-8\" />\n <polyline points=\"16,6 12,2 8,6\" />\n <line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"15\" />\n </svg>\n {t('bigconsole.filters.bar.share', 'Share')}\n </button>\n {showShareTooltip && (\n <div\n style={{\n position: 'absolute',\n top: '100%',\n left: '50%',\n transform: 'translateX(-50%)',\n marginTop: '4px',\n padding: '6px 12px',\n backgroundColor: SEMANTIC_COLORS.textPrimary,\n color: SEMANTIC_COLORS.bgPrimary,\n fontSize: '12px',\n borderRadius: '4px',\n whiteSpace: 'nowrap',\n zIndex: 100001,\n }}\n >\n {t('bigconsole.filters.bar.urlCopied', 'URL copied!')}\n </div>\n )}\n </div>\n )}\n\n {/* Reset Button */}\n {activeFilterCount > 0 && (\n <button type=\"button\" onClick={handleResetAll} className={`${QUIET_BUTTON_CLASSES} text-status-error-text`}>\n {t('bigconsole.filters.bar.resetAll', 'Reset all')}\n </button>\n )}\n\n {/* Add Filter Button */}\n <button type=\"button\" onClick={handleAddFilter} className={SECONDARY_BUTTON_CLASSES}>\n {t('bigconsole.filters.bar.addFilter', '+ Add Filter')}\n </button>\n\n {/* Collapse Button */}\n {collapsible && (\n <button\n type=\"button\"\n onClick={toggleCollapse}\n aria-expanded={!isCollapsed}\n // The chips container is unmounted while collapsed; pointing\n // aria-controls at a missing id is an invalid reference, so only\n // advertise it when the target actually exists.\n aria-controls={isCollapsed ? undefined : 'global-filters-chips'}\n className={QUIET_BUTTON_CLASSES}\n >\n {isCollapsed\n ? t('bigconsole.filters.bar.expand', '▼ Expand')\n : t('bigconsole.filters.bar.collapse', '▲ Collapse')}\n </button>\n )}\n </div>\n </div>\n\n {/* Filters List */}\n {!isCollapsed && (\n <div\n id=\"global-filters-chips\"\n className=\"relative flex flex-wrap gap-control-gap px-card-padding py-control-gap\"\n style={{ overflow: 'visible' }}\n >\n {filters.map((filter) => (\n <FilterChip\n key={filter.id}\n filter={filter}\n value={activeValues[filter.id]}\n onChange={(value) => handleFilterChange(filter.id, value)}\n onEdit={() => handleEditFilter(filter)}\n onDelete={() => handleDeleteFilter(filter.id)}\n />\n ))}\n </div>\n )}\n\n {/* Filter Editor Modal */}\n {isEditorOpen && (\n <FilterEditor\n filter={editingFilter}\n onSave={handleSaveFilter}\n onClose={() => {\n setIsEditorOpen(false);\n setEditingFilter(null);\n }}\n />\n )}\n </section>\n );\n}\n\nexport default GlobalFiltersBar;\n"],"mappings":"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"}
|
|
@@ -18,6 +18,6 @@ export interface ShareDialogProps {
|
|
|
18
18
|
/** False when the actor lacks `bigconsole-dashboard:update`; the control is then read-only. */
|
|
19
19
|
canChangeVisibility?: boolean;
|
|
20
20
|
}
|
|
21
|
-
export declare function ShareDialog(
|
|
21
|
+
export declare function ShareDialog(props: ShareDialogProps): React.JSX.Element;
|
|
22
22
|
export default ShareDialog;
|
|
23
23
|
//# sourceMappingURL=ShareDialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShareDialog.d.ts","sourceRoot":"","sources":["../../../../../src/bigconsole/components/dashboard/ShareDialog/ShareDialog.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"ShareDialog.d.ts","sourceRoot":"","sources":["../../../../../src/bigconsole/components/dashboard/ShareDialog/ShareDialog.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AASxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AA0B1D,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,6EAA6E;IAC7E,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,+FAA+F;IAC/F,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AA4BD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,qBAYlD;AAkuBD,eAAe,WAAW,CAAC"}
|