deepspotscreen-sdk 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,24 @@
1
- class K {
1
+ class B {
2
2
  constructor(e, t) {
3
3
  this.tokenCache = /* @__PURE__ */ new Map(), this.baseUrl = e.replace(/\/$/, ""), this.apiKey = t;
4
4
  }
5
5
  // ── Embed Token ─────────────────────────────────────────────────────────────
6
6
  async getEmbedToken(e) {
7
- var r, a, o, c;
7
+ var o, i, a, f;
8
8
  const t = [
9
9
  e.dashboardId,
10
10
  e.embedType,
11
- (r = e.embedLevel) != null ? r : "",
12
- (a = e.componentId) != null ? a : "",
13
- (o = e.userId) != null ? o : ""
11
+ (o = e.embedLevel) != null ? o : "",
12
+ (i = e.componentId) != null ? i : "",
13
+ (a = e.userId) != null ? a : ""
14
14
  ].join(":"), s = this.tokenCache.get(t);
15
15
  if (s && s.expiresAt > Date.now() + 6e4) return s.token;
16
- const i = await this.post(
16
+ const r = await this.post(
17
17
  "/dashboard-builder/embed-token",
18
18
  {
19
19
  dashboardId: e.dashboardId,
20
20
  embedType: e.embedType,
21
- embedLevel: (c = e.embedLevel) != null ? c : "dashboard",
21
+ embedLevel: (f = e.embedLevel) != null ? f : "dashboard",
22
22
  componentId: e.componentId,
23
23
  userId: e.userId,
24
24
  tenantId: e.tenantId,
@@ -27,35 +27,40 @@ class K {
27
27
  { "x-deepspot-api-key": this.apiKey }
28
28
  );
29
29
  return this.tokenCache.set(t, {
30
- token: i.token,
31
- expiresAt: new Date(i.expiresAt).getTime()
32
- }), i.token;
30
+ token: r.token,
31
+ expiresAt: new Date(r.expiresAt).getTime()
32
+ }), r.token;
33
33
  }
34
34
  // ── Dashboard Render (lazy — loads one tab at a time) ──────────────────────
35
35
  async getDashboardRender(e, t, s = {}) {
36
- var r;
37
- const i = new URLSearchParams({
36
+ var o;
37
+ const r = new URLSearchParams({
38
38
  embedType: "dashboard",
39
- embedLevel: (r = s.embedLevel) != null ? r : "dashboard"
39
+ embedLevel: (o = s.embedLevel) != null ? o : "dashboard"
40
40
  });
41
- return s.pageId && i.set("pageId", s.pageId), s.tabId && i.set("tabId", s.tabId), s.filters && Object.entries(s.filters).forEach(([a, o]) => {
42
- o != null && o !== "" && i.set(`filter[${a}]`, Array.isArray(o) ? o.join(",") : String(o));
41
+ return s.pageId && r.set("pageId", s.pageId), s.tabId && r.set("tabId", s.tabId), s.filters && Object.entries(s.filters).forEach(([i, a]) => {
42
+ a != null && a !== "" && r.set(`filter[${i}]`, Array.isArray(a) ? a.join(",") : String(a));
43
+ }), s.filterOperators && Object.entries(s.filterOperators).forEach(([i, a]) => {
44
+ a && r.set(`filterOp[${i}]`, a);
45
+ }), s.localFilters && Object.entries(s.localFilters).forEach(([i, { value: a, operator: f }]) => {
46
+ const h = Array.isArray(a) ? a.join(",") : String(a);
47
+ h && (r.set(`localFilter[${i}]`, h), f && r.set(`localFilterOp[${i}]`, f));
43
48
  }), this.get(
44
- `/dashboard-builder/embed/${e}/render?${i}`,
49
+ `/dashboard-builder/embed/${e}/render?${r}`,
45
50
  { "x-embed-token": t }
46
51
  );
47
52
  }
48
53
  // ── Single Report Render ────────────────────────────────────────────────────
49
- async getReportRender(e, t, s, i = {}) {
50
- const r = new URLSearchParams({
54
+ async getReportRender(e, t, s, r = {}) {
55
+ const o = new URLSearchParams({
51
56
  embedType: "report",
52
57
  embedLevel: "report",
53
58
  componentId: t
54
59
  });
55
- return i.filters && Object.entries(i.filters).forEach(([a, o]) => {
56
- o != null && o !== "" && r.set(`filter[${a}]`, Array.isArray(o) ? o.join(",") : String(o));
60
+ return r.filters && Object.entries(r.filters).forEach(([i, a]) => {
61
+ a != null && a !== "" && o.set(`filter[${i}]`, Array.isArray(a) ? a.join(",") : String(a));
57
62
  }), this.get(
58
- `/dashboard-builder/embed/${e}/render?${r}`,
63
+ `/dashboard-builder/embed/${e}/render?${o}`,
59
64
  { "x-embed-token": s }
60
65
  );
61
66
  }
@@ -81,10 +86,10 @@ class K {
81
86
  * Called by TableRenderer whenever the user navigates to a different page.
82
87
  * Mirrors: GET /dashboard-builder/embed/:dashboardId/table/:componentId/data
83
88
  */
84
- async getTablePage(e, t, s, i, r) {
89
+ async getTablePage(e, t, s, r, o) {
85
90
  return this.get(
86
- `/dashboard-builder/embed/${e}/table/${t}/data?page=${s}&pageSize=${i}`,
87
- { "x-embed-token": r }
91
+ `/dashboard-builder/embed/${e}/table/${t}/data?page=${s}&pageSize=${r}`,
92
+ { "x-embed-token": o }
88
93
  );
89
94
  }
90
95
  // ── Filter Options ──────────────────────────────────────────────────────────
@@ -97,12 +102,12 @@ class K {
97
102
  */
98
103
  async getFilterOptions(e, t, s) {
99
104
  try {
100
- const i = await this.get(
105
+ const r = await this.get(
101
106
  `/dashboard-builder/embed/${e}/filters/${t}/options`,
102
107
  { "x-embed-token": s }
103
108
  );
104
- return Array.isArray(i) ? i : Array.isArray(i == null ? void 0 : i.options) ? i.options : Array.isArray(i == null ? void 0 : i.data) ? i.data : [];
105
- } catch (i) {
109
+ return Array.isArray(r) ? r : Array.isArray(r == null ? void 0 : r.options) ? r.options : Array.isArray(r == null ? void 0 : r.data) ? r.data : [];
110
+ } catch (r) {
106
111
  return [];
107
112
  }
108
113
  }
@@ -118,12 +123,12 @@ class K {
118
123
  return this.handleResponse(s);
119
124
  }
120
125
  async post(e, t, s = {}) {
121
- const i = await fetch(`${this.baseUrl}${e}`, {
126
+ const r = await fetch(`${this.baseUrl}${e}`, {
122
127
  method: "POST",
123
128
  headers: { "Content-Type": "application/json", ...s },
124
129
  body: JSON.stringify(t)
125
130
  });
126
- return this.handleResponse(i);
131
+ return this.handleResponse(r);
127
132
  }
128
133
  async delete(e, t = {}) {
129
134
  const s = await fetch(`${this.baseUrl}${e}`, {
@@ -136,9 +141,9 @@ class K {
136
141
  if (!e.ok) {
137
142
  let s = `HTTP ${e.status}`;
138
143
  try {
139
- const i = await e.json();
140
- s = (i == null ? void 0 : i.message) || (i == null ? void 0 : i.error) || s;
141
- } catch (i) {
144
+ const r = await e.json();
145
+ s = (r == null ? void 0 : r.message) || (r == null ? void 0 : r.error) || s;
146
+ } catch (r) {
142
147
  }
143
148
  throw new Error(`Deepspot SDK: ${s}`);
144
149
  }
@@ -146,7 +151,7 @@ class K {
146
151
  return (t == null ? void 0 : t.data) !== void 0 ? t.data : t;
147
152
  }
148
153
  }
149
- class E {
154
+ class z {
150
155
  constructor(e) {
151
156
  var t, s;
152
157
  this.destroyed = !1, this.refreshTimer = null, this.opts = e, this.filters = { ...e.activeFilters }, this.activePageId = (t = e.activePageId) != null ? t : "", this.activeTabId = (s = e.activeTabId) != null ? s : "";
@@ -203,19 +208,19 @@ class E {
203
208
  this.refreshTimer && clearTimeout(this.refreshTimer), this.refreshTimer = setTimeout(() => this.refresh(), 300);
204
209
  }
205
210
  async fetchData() {
206
- const { apiClient: e, dashboardId: t, componentId: s, token: i, embedType: r, embedLevel: a } = this.opts;
207
- return r === "report" && s ? e.getReportRender(t, s, i, {
211
+ const { apiClient: e, dashboardId: t, componentId: s, token: r, embedType: o, embedLevel: i } = this.opts;
212
+ return o === "report" && s ? e.getReportRender(t, s, r, {
208
213
  filters: this.filters
209
- }) : e.getDashboardRender(t, i, {
210
- embedLevel: a,
214
+ }) : e.getDashboardRender(t, r, {
215
+ embedLevel: i,
211
216
  pageId: this.activePageId || void 0,
212
217
  tabId: this.activeTabId || void 0,
213
218
  filters: this.filters
214
219
  });
215
220
  }
216
221
  }
217
- const be = 24, O = 10, M = 12;
218
- class ae {
222
+ const he = 24, D = 10, M = 12;
223
+ class ie {
219
224
  /**
220
225
  * @param containerWidth Actual pixel width of the grid container.
221
226
  * @param minY Minimum y value across all components (normalises
@@ -226,23 +231,23 @@ class ae {
226
231
  }
227
232
  /** Pixel width of one column unit */
228
233
  get colWidth() {
229
- return this.containerWidth / be;
234
+ return this.containerWidth / he;
230
235
  }
231
236
  /** Convert grid position {x,y,w,h} → CSS absolute pixel values */
232
237
  toPx(e) {
233
238
  const t = this.colWidth, s = M / 2;
234
239
  return {
235
240
  left: e.x * t + s,
236
- top: (e.y - this.minY) * O + s,
241
+ top: (e.y - this.minY) * D + s,
237
242
  width: e.w * t - M,
238
- height: e.h * O - M
243
+ height: e.h * D - M
239
244
  };
240
245
  }
241
246
  /** Total pixel height required to fit all positioned components */
242
247
  static totalHeight(e) {
243
248
  if (!e.length) return 400;
244
- const t = Math.min(...e.map((i) => i.y));
245
- return (Math.max(...e.map((i) => i.y + i.h)) - t) * O + 40;
249
+ const t = Math.min(...e.map((r) => r.y));
250
+ return (Math.max(...e.map((r) => r.y + r.h)) - t) * D + 40;
246
251
  }
247
252
  /** Apply absolute positioning styles directly to a DOM element */
248
253
  applyStyles(e, t) {
@@ -250,21 +255,21 @@ class ae {
250
255
  e.style.position = "absolute", e.style.left = `${s.left}px`, e.style.top = `${s.top}px`, e.style.width = `${s.width}px`, e.style.height = `${s.height}px`;
251
256
  }
252
257
  }
253
- let N = null;
258
+ let H = null;
254
259
  function fe() {
255
- return N || (N = import("./apexcharts.common-k3hLWpB8.js").then((k) => k.a)), N;
260
+ return H || (H = import("./apexcharts.common-k3hLWpB8.js").then((A) => A.a)), H;
256
261
  }
257
262
  class ne {
258
263
  constructor(e) {
259
264
  this.chart = null, this.container = e;
260
265
  }
261
- async render(e, t, s, i) {
266
+ async render(e, t, s, r) {
262
267
  if (!t || t.length === 0) {
263
268
  this.renderEmpty(e.title);
264
269
  return;
265
270
  }
266
- const r = this.buildOptions(e, t, s, i);
267
- if (!r) {
271
+ const o = this.buildOptions(e, t, s, r);
272
+ if (!o) {
268
273
  this.renderEmpty(e.title);
269
274
  return;
270
275
  }
@@ -274,14 +279,14 @@ class ne {
274
279
  <div class="ds-chart-body" id="ds-chart-body-${e.id}"></div>
275
280
  </div>
276
281
  `;
277
- const a = this.container.querySelector(`#ds-chart-body-${e.id}`);
278
- if (a)
282
+ const i = this.container.querySelector(`#ds-chart-body-${e.id}`);
283
+ if (i)
279
284
  try {
280
285
  this.chart && this.chart.destroy();
281
- const { default: o } = await fe();
282
- this.chart = new o(a, r), this.chart.render();
283
- } catch (o) {
284
- console.error("[Deepspot SDK] ChartRenderer error:", o), a.innerHTML = '<div class="ds-chart-empty">Chart render error</div>';
286
+ const { default: a } = await fe();
287
+ this.chart = new a(i, o), this.chart.render();
288
+ } catch (a) {
289
+ console.error("[Deepspot SDK] ChartRenderer error:", a), i.innerHTML = '<div class="ds-chart-empty">Chart render error</div>';
285
290
  }
286
291
  }
287
292
  async update(e, t, s) {
@@ -289,14 +294,14 @@ class ne {
289
294
  await this.render(e, t, s);
290
295
  return;
291
296
  }
292
- const { series: i, categories: r } = this.extractSeriesAndCategories(e, t);
297
+ const { series: r, categories: o } = this.extractSeriesAndCategories(e, t);
293
298
  try {
294
299
  this.chart.updateOptions({
295
- series: i,
296
- xaxis: { categories: r },
300
+ series: r,
301
+ xaxis: { categories: o },
297
302
  theme: { mode: s }
298
303
  });
299
- } catch (a) {
304
+ } catch (i) {
300
305
  this.render(e, t, s);
301
306
  }
302
307
  }
@@ -309,19 +314,19 @@ class ne {
309
314
  this.chart = null;
310
315
  }
311
316
  // ── Private ─────────────────────────────────────────────────────────────────
312
- buildOptions(e, t, s, i) {
313
- const r = e.type;
314
- return r === "pie" || r === "donut" ? this.buildPieOptions(e, t, s, i) : r === "bar" || r === "line" || r === "area" ? this.buildCartesianOptions(e, t, s, i) : null;
315
- }
316
- buildCartesianOptions(e, t, s, i) {
317
- var f;
318
- const { series: r, categories: a, xAxisLabel: o, yAxisLabel: c, seriesColors: d } = this.extractSeriesAndCategories(e, t), b = e.properties || {}, u = ["#4f46e5", "#10b981", "#f59e0b", "#ef4444", "#3b82f6", "#8b5cf6", "#ec4899", "#14b8a6"];
319
- let g;
320
- if (d.length > 0 && d.length === r.length)
321
- g = d;
317
+ buildOptions(e, t, s, r) {
318
+ const o = e.type;
319
+ return o === "pie" || o === "donut" ? this.buildPieOptions(e, t, s, r) : o === "bar" || o === "line" || o === "area" ? this.buildCartesianOptions(e, t, s, r) : null;
320
+ }
321
+ buildCartesianOptions(e, t, s, r) {
322
+ var g;
323
+ const { series: o, categories: i, xAxisLabel: a, yAxisLabel: f, seriesColors: h } = this.extractSeriesAndCategories(e, t), v = e.properties || {}, m = ["#4f46e5", "#10b981", "#f59e0b", "#ef4444", "#3b82f6", "#8b5cf6", "#ec4899", "#14b8a6"];
324
+ let p;
325
+ if (h.length > 0 && h.length === o.length)
326
+ p = h;
322
327
  else {
323
- const p = b.colors ? Object.values(b.colors).filter(Boolean) : [];
324
- g = p.length > 0 ? p : u;
328
+ const u = v.colors ? Object.values(v.colors).filter(Boolean) : [];
329
+ p = u.length > 0 ? u : m;
325
330
  }
326
331
  const n = s === "dark";
327
332
  return {
@@ -333,27 +338,27 @@ class ne {
333
338
  fontFamily: "inherit",
334
339
  // Explicit height prevents ApexCharts from guessing the flex-child height
335
340
  // at render time (which can read as 0 before the browser settles layout).
336
- height: i != null ? i : "100%"
341
+ height: r != null ? r : "100%"
337
342
  },
338
343
  theme: { mode: s },
339
- series: r,
344
+ series: o,
340
345
  xaxis: {
341
- categories: a,
342
- title: { text: o },
346
+ categories: i,
347
+ title: { text: a },
343
348
  labels: {
344
- rotate: a.length > 8 ? -45 : 0,
349
+ rotate: i.length > 8 ? -45 : 0,
345
350
  style: { colors: n ? "#94a3b8" : "#6b7280", fontSize: "11px" }
346
351
  },
347
352
  axisBorder: { color: n ? "#334155" : "#e5e7eb" },
348
353
  axisTicks: { color: n ? "#334155" : "#e5e7eb" }
349
354
  },
350
355
  yaxis: {
351
- title: { text: c },
356
+ title: { text: f },
352
357
  labels: { style: { colors: n ? "#94a3b8" : "#6b7280", fontSize: "11px" } }
353
358
  },
354
- colors: g,
359
+ colors: p,
355
360
  legend: {
356
- show: r.length > 1 || ((f = b.showLegend) != null ? f : !1),
361
+ show: o.length > 1 || ((g = v.showLegend) != null ? g : !1),
357
362
  position: "bottom",
358
363
  labels: { colors: n ? "#94a3b8" : "#6b7280" }
359
364
  },
@@ -361,7 +366,7 @@ class ne {
361
366
  borderColor: n ? "#1e293b" : "#f3f4f6",
362
367
  strokeDashArray: 4,
363
368
  padding: {
364
- bottom: a.length > 8 ? 60 : 10
369
+ bottom: i.length > 8 ? 60 : 10
365
370
  }
366
371
  },
367
372
  tooltip: { theme: s },
@@ -374,34 +379,34 @@ class ne {
374
379
  plotOptions: {
375
380
  bar: {
376
381
  borderRadius: 4,
377
- distributed: r.length === 1
382
+ distributed: o.length === 1
378
383
  }
379
384
  }
380
385
  };
381
386
  }
382
- buildPieOptions(e, t, s, i) {
383
- const r = e.properties || {}, a = t.length > 0 ? Object.keys(t[0]) : [], o = a[0] || "label", c = a[1] || "value", d = t.map((p) => {
384
- var l;
385
- return String((l = p[o]) != null ? l : "");
386
- }), b = t.map((p) => Number(p[c]) || 0), u = s === "dark", g = ["#4f46e5", "#10b981", "#f59e0b", "#ef4444", "#3b82f6", "#8b5cf6", "#ec4899", "#14b8a6"], n = r.colors ? Object.values(r.colors).filter(Boolean) : [], f = n.length > 0 ? n : g;
387
+ buildPieOptions(e, t, s, r) {
388
+ const o = e.properties || {}, i = t.length > 0 ? Object.keys(t[0]) : [], a = i[0] || "label", f = i[1] || "value", h = t.map((u) => {
389
+ var b;
390
+ return String((b = u[a]) != null ? b : "");
391
+ }), v = t.map((u) => Number(u[f]) || 0), m = s === "dark", p = ["#4f46e5", "#10b981", "#f59e0b", "#ef4444", "#3b82f6", "#8b5cf6", "#ec4899", "#14b8a6"], n = o.colors ? Object.values(o.colors).filter(Boolean) : [], g = n.length > 0 ? n : p;
387
392
  return {
388
393
  chart: {
389
394
  type: e.type,
390
395
  toolbar: { show: !1 },
391
396
  background: "transparent",
392
397
  fontFamily: "inherit",
393
- height: i != null ? i : "100%"
398
+ height: r != null ? r : "100%"
394
399
  },
395
400
  theme: { mode: s },
396
- series: b,
397
- labels: d,
398
- colors: f,
401
+ series: v,
402
+ labels: h,
403
+ colors: g,
399
404
  legend: {
400
405
  position: "bottom",
401
- labels: { colors: u ? "#94a3b8" : "#6b7280" }
406
+ labels: { colors: m ? "#94a3b8" : "#6b7280" }
402
407
  },
403
408
  tooltip: { theme: s },
404
- dataLabels: { enabled: d.length <= 8 },
409
+ dataLabels: { enabled: h.length <= 8 },
405
410
  plotOptions: {
406
411
  pie: {
407
412
  donut: { size: e.type === "donut" ? "65%" : "0%" }
@@ -410,40 +415,40 @@ class ne {
410
415
  };
411
416
  }
412
417
  extractSeriesAndCategories(e, t) {
413
- const s = e.properties || {}, i = t.length > 0 ? Object.keys(t[0]) : [], r = s.xAxis || i[0] || "x";
414
- let a = [];
418
+ const s = e.properties || {}, r = t.length > 0 ? Object.keys(t[0]) : [], o = s.xAxis || r[0] || "x";
419
+ let i = [];
415
420
  if (s.selectedYAxisColumn)
416
421
  try {
417
422
  const n = typeof s.selectedYAxisColumn == "string" ? JSON.parse(s.selectedYAxisColumn) : s.selectedYAxisColumn;
418
- Array.isArray(n) && (a = n.map(
419
- (f) => typeof f == "string" ? { column: f } : f
423
+ Array.isArray(n) && (i = n.map(
424
+ (g) => typeof g == "string" ? { column: g } : g
420
425
  ));
421
426
  } catch (n) {
422
427
  }
423
- if (!a.length && s.yAxis) {
428
+ if (!i.length && s.yAxis) {
424
429
  const n = s.yAxis;
425
- a = (Array.isArray(n) ? n : [n]).map((p) => ({ column: String(p) }));
430
+ i = (Array.isArray(n) ? n : [n]).map((u) => ({ column: String(u) }));
426
431
  }
427
- !a.length && i.length > 1 && (a = i.slice(1).map((n) => ({ column: n })));
428
- const o = t.map((n) => {
429
- var f;
430
- return String((f = n[r]) != null ? f : "");
431
- }), c = t.length > 0 ? Object.keys(t[0]) : [], d = a.map((n) => {
432
- const f = c.includes(n.column) ? n.column : null, p = f ? null : c.find((h) => h.includes(n.column) || n.column.includes(h)), l = !f && !p ? c.find((h) => {
433
- var y;
434
- return h !== r && !isNaN(Number((y = t[0]) == null ? void 0 : y[h]));
435
- }) : null, x = f || p || l || n.column;
432
+ !i.length && r.length > 1 && (i = r.slice(1).map((n) => ({ column: n })));
433
+ const a = t.map((n) => {
434
+ var g;
435
+ return String((g = n[o]) != null ? g : "");
436
+ }), f = t.length > 0 ? Object.keys(t[0]) : [], h = i.map((n) => {
437
+ const g = f.includes(n.column) ? n.column : null, u = g ? null : f.find((d) => d.includes(n.column) || n.column.includes(d)), b = !g && !u ? f.find((d) => {
438
+ var l;
439
+ return d !== o && !isNaN(Number((l = t[0]) == null ? void 0 : l[d]));
440
+ }) : null, c = g || u || b || n.column;
436
441
  return {
437
442
  // Use the column name directly as the series label (matches builder behaviour).
438
443
  // col.label often stores the chart title, not the series name — ignore it.
439
444
  name: n.column,
440
- data: t.map((h) => {
441
- const y = h[x];
442
- return y != null ? Number(y) : null;
445
+ data: t.map((d) => {
446
+ const l = d[c];
447
+ return l != null ? Number(l) : null;
443
448
  })
444
449
  };
445
- }), b = a.map((n) => n.color || n.colorHex || "").filter(Boolean), u = s.xAxisLabel || r, g = s.yAxisLabel || (a.length === 1 ? a[0].column : "");
446
- return { series: d, categories: o, xAxisLabel: u, yAxisLabel: g, seriesColors: b };
450
+ }), v = i.map((n) => n.color || n.colorHex || "").filter(Boolean), m = s.xAxisLabel || o, p = s.yAxisLabel || (i.length === 1 ? i[0].column : "");
451
+ return { series: h, categories: a, xAxisLabel: m, yAxisLabel: p, seriesColors: v };
447
452
  }
448
453
  renderEmpty(e) {
449
454
  this.container.innerHTML = `
@@ -459,16 +464,16 @@ class le {
459
464
  this.columns = [], this.allData = [], this.currentRows = [], this.totalRows = 0, this.currentPage = 1, this.currentPageSize = 10, this.searchTerm = "", this.isLoading = !1;
460
465
  }
461
466
  // ── Public API ─────────────────────────────────────────────────────────────
462
- render(e, t, s, i) {
463
- var b;
464
- this.container = e, this.component = t, this.fetchPage = i, this.searchTerm = "", this.currentPage = 1, this.currentPageSize = 10;
465
- const r = s && !Array.isArray(s) && "rows" in s;
466
- if (r) {
467
- const u = s;
468
- this.currentRows = u.rows, this.allData = [], this.totalRows = u.total, this.currentPage = u.page, this.currentPageSize = u.pageSize;
467
+ render(e, t, s, r) {
468
+ var v;
469
+ this.container = e, this.component = t, this.fetchPage = r, this.searchTerm = "", this.currentPage = 1, this.currentPageSize = 10;
470
+ const o = s && !Array.isArray(s) && "rows" in s;
471
+ if (o) {
472
+ const m = s;
473
+ this.currentRows = m.rows, this.allData = [], this.totalRows = m.total, this.currentPage = m.page, this.currentPageSize = m.pageSize;
469
474
  } else
470
475
  this.allData = s || [], this.currentRows = [], this.totalRows = this.allData.length, this.currentPage = 1;
471
- if (r && s.rows.length === 0 && s.total === 0 || !r && this.allData.length === 0) {
476
+ if (o && s.rows.length === 0 && s.total === 0 || !o && this.allData.length === 0) {
472
477
  e.innerHTML = `
473
478
  <div class="ds-table-card">
474
479
  <div class="ds-table-header-row">
@@ -480,18 +485,18 @@ class le {
480
485
  `;
481
486
  return;
482
487
  }
483
- const a = r ? s.rows[0] : this.allData[0], o = a ? Object.keys(a) : [], c = ((b = t.properties) == null ? void 0 : b.columns) || [], d = c.length ? c.filter((u) => o.includes(u)) : [];
484
- this.columns = d.length ? d : o, this.paint();
488
+ const i = o ? s.rows[0] : this.allData[0], a = i ? Object.keys(i) : [], f = ((v = t.properties) == null ? void 0 : v.columns) || [], h = f.length ? f.filter((m) => a.includes(m)) : [];
489
+ this.columns = h.length ? h : a, this.paint();
485
490
  }
486
491
  // ── Rendering ──────────────────────────────────────────────────────────────
487
492
  paint() {
488
- const { rows: e, startNum: t } = this.getPageRows(), s = Math.max(1, Math.ceil(this.totalRows / this.currentPageSize)), i = (this.currentPage - 1) * this.currentPageSize + 1, r = this.fetchPage ? Math.min(i - 1 + (this.isLoading ? this.currentPageSize : e.length), this.totalRows) : Math.min(this.currentPage * this.currentPageSize, this.totalRows), a = this.columns.map((g) => `<th>${this.escape(this.formatHeader(g))}</th>`).join(""), o = e.length === 0 ? `<tr><td colspan="${this.columns.length + 1}" style="text-align:center;padding:20px;color:#9ca3af">No results found</td></tr>` : e.map((g, n) => {
489
- const f = this.columns.map((p) => {
490
- const l = g[p];
491
- return `<td title="${this.escape(String(l != null ? l : ""))}">${this.escape(this.formatValue(l))}</td>`;
493
+ const { rows: e, startNum: t } = this.getPageRows(), s = Math.max(1, Math.ceil(this.totalRows / this.currentPageSize)), r = (this.currentPage - 1) * this.currentPageSize + 1, o = this.fetchPage ? Math.min(r - 1 + (this.isLoading ? this.currentPageSize : e.length), this.totalRows) : Math.min(this.currentPage * this.currentPageSize, this.totalRows), i = this.columns.map((p) => `<th>${this.escape(this.formatHeader(p))}</th>`).join(""), a = e.length === 0 ? `<tr><td colspan="${this.columns.length + 1}" style="text-align:center;padding:20px;color:#9ca3af">No results found</td></tr>` : e.map((p, n) => {
494
+ const g = this.columns.map((u) => {
495
+ const b = p[u];
496
+ return `<td title="${this.escape(String(b != null ? b : ""))}">${this.escape(this.formatValue(b))}</td>`;
492
497
  }).join("");
493
- return `<tr><td class="ds-table-sno">${t + n}</td>${f}</tr>`;
494
- }).join(""), c = this.currentPageSize, d = [10, 25, 50, 100].map((g) => `<option value="${g}"${g === c ? " selected" : ""}>${g}</option>`).join(""), b = this.currentPage <= 1, u = this.currentPage >= s;
498
+ return `<tr><td class="ds-table-sno">${t + n}</td>${g}</tr>`;
499
+ }).join(""), f = this.currentPageSize, h = [10, 25, 50, 100].map((p) => `<option value="${p}"${p === f ? " selected" : ""}>${p}</option>`).join(""), v = this.currentPage <= 1, m = this.currentPage >= s;
495
500
  this.container.innerHTML = `
496
501
  <div class="ds-table-card">
497
502
  <div class="ds-table-header-row">
@@ -502,22 +507,22 @@ class le {
502
507
  </div>
503
508
  <div class="ds-table-scroll">
504
509
  <table class="ds-table">
505
- <thead><tr><th class="ds-table-sno-th">S.No</th>${a}</tr></thead>
506
- <tbody>${o}</tbody>
510
+ <thead><tr><th class="ds-table-sno-th">S.No</th>${i}</tr></thead>
511
+ <tbody>${a}</tbody>
507
512
  </table>
508
513
  </div>
509
514
  <div class="ds-table-footer">
510
515
  <div class="ds-table-info">
511
- <span>${i.toLocaleString()}–${r.toLocaleString()} of ${this.totalRows.toLocaleString()}</span>
516
+ <span>${r.toLocaleString()}–${o.toLocaleString()} of ${this.totalRows.toLocaleString()}</span>
512
517
  <span class="ds-table-rows-label">Rows:</span>
513
- <select class="ds-table-page-size">${d}</select>
518
+ <select class="ds-table-page-size">${h}</select>
514
519
  </div>
515
520
  <div class="ds-table-pagination">
516
- <button class="ds-table-pg-btn" data-action="first" ${b ? "disabled" : ""}>&#171;</button>
517
- <button class="ds-table-pg-btn" data-action="prev" ${b ? "disabled" : ""}>Previous</button>
521
+ <button class="ds-table-pg-btn" data-action="first" ${v ? "disabled" : ""}>&#171;</button>
522
+ <button class="ds-table-pg-btn" data-action="prev" ${v ? "disabled" : ""}>Previous</button>
518
523
  <span class="ds-table-pg-info">Page ${this.currentPage} of ${s}</span>
519
- <button class="ds-table-pg-btn" data-action="next" ${u ? "disabled" : ""}>Next</button>
520
- <button class="ds-table-pg-btn" data-action="last" ${u ? "disabled" : ""}>&#187;</button>
524
+ <button class="ds-table-pg-btn" data-action="next" ${m ? "disabled" : ""}>Next</button>
525
+ <button class="ds-table-pg-btn" data-action="last" ${m ? "disabled" : ""}>&#187;</button>
521
526
  </div>
522
527
  </div>
523
528
  ${this.isLoading ? '<div class="ds-table-loading-overlay"><div class="ds-embed-spinner"></div></div>' : ""}
@@ -535,9 +540,9 @@ class le {
535
540
  }), this.container.querySelectorAll("[data-action]").forEach((s) => {
536
541
  s.addEventListener("click", () => {
537
542
  if (s.disabled) return;
538
- const i = Math.max(1, Math.ceil(this.totalRows / this.currentPageSize)), r = s.dataset.action;
539
- let a = this.currentPage;
540
- r === "first" ? a = 1 : r === "prev" ? a = Math.max(1, this.currentPage - 1) : r === "next" ? a = Math.min(i, this.currentPage + 1) : r === "last" && (a = i), (a !== this.currentPage || r === "first" || r === "last") && (this.currentPage = a, this.fetchPage ? this.loadPage(a) : this.paint());
543
+ const r = Math.max(1, Math.ceil(this.totalRows / this.currentPageSize)), o = s.dataset.action;
544
+ let i = this.currentPage;
545
+ o === "first" ? i = 1 : o === "prev" ? i = Math.max(1, this.currentPage - 1) : o === "next" ? i = Math.min(r, this.currentPage + 1) : o === "last" && (i = r), (i !== this.currentPage || o === "first" || o === "last") && (this.currentPage = i, this.fetchPage ? this.loadPage(i) : this.paint());
541
546
  });
542
547
  });
543
548
  }
@@ -568,8 +573,8 @@ class le {
568
573
  const e = this.searchTerm.toLowerCase();
569
574
  return this.allData.filter(
570
575
  (t) => this.columns.some((s) => {
571
- var i;
572
- return String((i = t[s]) != null ? i : "").toLowerCase().includes(e);
576
+ var r;
577
+ return String((r = t[s]) != null ? r : "").toLowerCase().includes(e);
573
578
  })
574
579
  );
575
580
  }
@@ -586,35 +591,35 @@ class le {
586
591
  }
587
592
  class ce {
588
593
  render(e, t, s) {
589
- var f;
590
- const i = t.properties || {};
591
- let r = null;
594
+ var g;
595
+ const r = t.properties || {};
596
+ let o = null;
592
597
  if (s && s.length > 0) {
593
- const p = s[0], l = i.metric || Object.keys(p)[0], x = p[l];
594
- if (x !== void 0)
595
- r = x;
598
+ const u = s[0], b = r.metric || Object.keys(u)[0], c = u[b];
599
+ if (c !== void 0)
600
+ o = c;
596
601
  else {
597
- const h = Object.keys(p).find(
598
- (y) => y.includes(l) || l.includes(y)
602
+ const d = Object.keys(u).find(
603
+ (l) => l.includes(b) || b.includes(l)
599
604
  );
600
- r = p[h != null ? h : Object.keys(p)[0]];
605
+ o = u[d != null ? d : Object.keys(u)[0]];
601
606
  }
602
607
  }
603
- let a;
604
- if (r == null)
608
+ let i;
609
+ if (o == null)
605
610
  try {
606
- const p = (f = i == null ? void 0 : i.data) == null ? void 0 : f.dataContent, l = p ? typeof p == "string" ? JSON.parse(p) : p : null;
607
- a = l != null && l.value ? String(l.value) : "—";
608
- } catch (p) {
609
- a = "—";
611
+ const u = (g = r == null ? void 0 : r.data) == null ? void 0 : g.dataContent, b = u ? typeof u == "string" ? JSON.parse(u) : u : null;
612
+ i = b != null && b.value ? String(b.value) : "—";
613
+ } catch (u) {
614
+ i = "—";
610
615
  }
611
616
  else
612
- a = this.formatValue(r, i);
613
- const o = i.styleConfig || {}, c = o.backgroundColor || i.backgroundColor || "", d = o.color || o.textColor || i.textColor || "", b = t.title || "", u = c ? `background:${c};border:none;` : "", g = d ? `color:${d};` : "", n = d ? `color:${d};opacity:0.7;` : "";
617
+ i = this.formatValue(o, r);
618
+ const a = r.styleConfig || {}, f = a.backgroundColor || r.backgroundColor || "", h = a.color || a.textColor || r.textColor || "", v = t.title || "", m = f ? `background:${f};border:none;` : "", p = h ? `color:${h};` : "", n = h ? `color:${h};opacity:0.7;` : "";
614
619
  e.innerHTML = `
615
- <div class="ds-card"${u ? ` style="${u}"` : ""}>
616
- <div class="ds-card-label"${n ? ` style="${n}"` : ""}>${b}</div>
617
- <div class="ds-card-value"${g ? ` style="${g}"` : ""}>${a}</div>
620
+ <div class="ds-card"${m ? ` style="${m}"` : ""}>
621
+ <div class="ds-card-label"${n ? ` style="${n}"` : ""}>${v}</div>
622
+ <div class="ds-card-value"${p ? ` style="${p}"` : ""}>${i}</div>
618
623
  </div>
619
624
  `;
620
625
  }
@@ -622,125 +627,394 @@ class ce {
622
627
  if (e == null) return "—";
623
628
  const s = Number(e);
624
629
  if (isNaN(s)) return String(e);
625
- const i = (t == null ? void 0 : t.prefix) || (t == null ? void 0 : t.currencySymbol) || "", r = (t == null ? void 0 : t.suffix) || "", a = s % 1 === 0 ? s.toLocaleString() : parseFloat(s.toFixed(2)).toLocaleString();
626
- return `${i}${a}${r}`;
630
+ const r = (t == null ? void 0 : t.prefix) || (t == null ? void 0 : t.currencySymbol) || "", o = (t == null ? void 0 : t.suffix) || "", i = s % 1 === 0 ? s.toLocaleString() : parseFloat(s.toFixed(2)).toLocaleString();
631
+ return `${r}${i}${o}`;
627
632
  }
628
633
  }
629
- class pe {
634
+ const be = [
635
+ { value: "=", label: "Equals (=)" },
636
+ { value: "!=", label: "Not Equals (!=)" },
637
+ { value: "LIKE", label: "Contains" },
638
+ { value: "NOT LIKE", label: "Not Contains" },
639
+ { value: "STARTS_WITH", label: "Starts With" },
640
+ { value: "IN", label: "In (Multiple)" },
641
+ { value: "NOT IN", label: "Not In" },
642
+ { value: ">", label: "Greater Than (>)" },
643
+ { value: ">=", label: "Greater or Equal (>=)" },
644
+ { value: "<", label: "Less Than (<)" },
645
+ { value: "<=", label: "Less or Equal (<=)" },
646
+ { value: "IS NULL", label: "Is Empty" },
647
+ { value: "IS NOT NULL", label: "Is Not Empty" }
648
+ ];
649
+ class ge {
630
650
  constructor(e, t) {
631
- this.currentValues = {}, this.container = e, this.onFilterChange = t;
651
+ this.filters = [], this.state = /* @__PURE__ */ new Map(), this.activePopoverId = null, this.container = e, this.onFilterChange = t;
632
652
  }
653
+ // ── Public API ─────────────────────────────────────────────────────────────
633
654
  render(e, t = {}) {
655
+ var s, r, o;
634
656
  if (!e || e.length === 0) {
635
657
  this.container.style.display = "none";
636
658
  return;
637
659
  }
638
- this.container.style.display = "", this.currentValues = { ...t }, this.container.innerHTML = `<div class="ds-filter-bar">${e.map((s) => this.renderFilter(s, t[s.applyToField || s.filterId])).join("")}</div>`, this.attachListeners(e);
660
+ this.container.style.display = "", this.filters = e, this.state.clear();
661
+ for (const i of e) {
662
+ const a = i.applyToField || i.filterId, f = (s = t[i.filterId]) != null ? s : t[a], h = f ? Array.isArray(f) ? f.map(String) : [String(f)] : [];
663
+ this.state.set(i.filterId, {
664
+ operator: i.filterOperator || "=",
665
+ tempValues: [...h],
666
+ activeValues: [...h],
667
+ options: (o = (r = i.options) == null ? void 0 : r.map((v) => v)) != null ? o : [],
668
+ loading: !1,
669
+ search: ""
670
+ });
671
+ }
672
+ this.paint();
639
673
  }
640
- /**
641
- * Populate a dropdown / multi-select with options fetched from the API.
642
- * Called asynchronously after the filter bar is rendered.
643
- */
644
674
  updateOptions(e, t) {
645
- const s = this.container.querySelector(
646
- `select[data-filter-id="${e}"]`
647
- );
648
- if (!s) return;
649
- const i = s.value;
650
- s.innerHTML = '<option value="">All</option>' + t.map(
651
- (r) => `<option value="${this.escAttr(r)}">${this.escText(r)}</option>`
652
- ).join(""), i && t.includes(i) && (s.value = i);
675
+ const s = this.state.get(e);
676
+ s && (s.loading = !1, s.options = t, this.refreshPopoverOpts(e));
677
+ }
678
+ setLoading(e, t) {
679
+ const s = this.state.get(e);
680
+ s && (s.loading = t, this.refreshPopoverOpts(e));
653
681
  }
654
- /** Update the stored values without re-rendering (for programmatic setFilter) */
655
682
  updateValues(e) {
656
- Object.assign(this.currentValues, e), Object.entries(e).forEach(([t, s]) => {
657
- const i = this.container.querySelector(`[data-filter-id="${t}"]`);
658
- i && s !== void 0 && (i.value = String(s));
659
- });
683
+ for (const [t, s] of Object.entries(e)) {
684
+ const r = this.filters.find(
685
+ (a) => (a.applyToField || a.filterId) === t || a.filterId === t
686
+ );
687
+ if (!r) continue;
688
+ const o = this.state.get(r.filterId);
689
+ if (!o) continue;
690
+ const i = s ? Array.isArray(s) ? s.map(String) : [String(s)] : [];
691
+ o.activeValues = i, o.tempValues = [...i];
692
+ }
693
+ this.repaintBadges();
660
694
  }
661
- // ── Private ─────────────────────────────────────────────────────────────────
662
- renderFilter(e, t) {
663
- const s = `ds-filter-${e.filterId}`, i = `<label class="ds-filter-label" for="${s}">${e.label}</label>`;
664
- switch (e.type) {
665
- case "dropdown":
666
- return `
667
- <div class="ds-filter-item">
668
- ${i}
669
- <select class="ds-filter-select" id="${s}" data-filter-id="${e.filterId}">
670
- <option value="">All</option>
671
- ${(e.options || []).map((o) => `
672
- <option value="${this.escAttr(o)}" ${t === o ? "selected" : ""}>
673
- ${this.escText(o)}
674
- </option>
675
- `).join("")}
676
- </select>
677
- </div>`;
678
- case "multi-select":
679
- return `
680
- <div class="ds-filter-item">
681
- ${i}
682
- <select class="ds-filter-select" id="${s}" data-filter-id="${e.filterId}" multiple size="1">
683
- ${(e.options || []).map((o) => `
684
- <option value="${this.escAttr(o)}">${this.escText(o)}</option>
685
- `).join("")}
695
+ // ── Paint badge bar ─────────────────────────────────────────────────────────
696
+ paint() {
697
+ this.container.innerHTML = `
698
+ <div class="ds-fp-v3">
699
+ <div class="ds-fp-v3-bar" id="ds-fp-v3-bar">
700
+ <span class="ds-fp-v3-label">
701
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
702
+ stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
703
+ <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>
704
+ </svg>
705
+ Filters:
706
+ </span>
707
+ <div class="ds-fp-v3-badges" id="ds-fp-v3-badges">
708
+ ${this.filters.map((e) => this.renderBadge(e)).join("")}
709
+ </div>
710
+ </div>
711
+ <!-- Popovers rendered per filter -->
712
+ ${this.filters.map((e) => this.renderPopoverHtml(e)).join("")}
713
+ </div>`, this.bindAll(), this.closePopoverOnOutsideClick();
714
+ }
715
+ renderBadge(e) {
716
+ return `
717
+ <button type="button"
718
+ class="ds-fp-v3-badge${this.state.get(e.filterId).activeValues.length > 0 ? " ds-fp-v3-badge-active" : ""}"
719
+ data-filter-id="${this.escAttr(e.filterId)}">
720
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
721
+ stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
722
+ <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>
723
+ </svg>
724
+ ${this.escText(e.label)}
725
+ </button>`;
726
+ }
727
+ renderPopoverHtml(e) {
728
+ const t = this.state.get(e.filterId);
729
+ return `
730
+ <div class="ds-fp-v3-pop" id="ds-fp-pop-${this.escAttr(e.filterId)}" style="display:none">
731
+ <div class="ds-fp-v3-pop-hd">
732
+ <span class="ds-fp-v3-pop-title">
733
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
734
+ stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
735
+ <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>
736
+ </svg>
737
+ Filter
738
+ </span>
739
+ <div class="ds-fp-v3-pop-actions">
740
+ <button type="button" class="ds-fp-v3-pop-icon-btn ds-fp-v3-pop-close-btn"
741
+ data-filter-id="${this.escAttr(e.filterId)}" title="Close">
742
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
743
+ stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
744
+ <line x1="18" y1="6" x2="6" y2="18"/>
745
+ <line x1="6" y1="6" x2="18" y2="18"/>
746
+ </svg>
747
+ </button>
748
+ </div>
749
+ </div>
750
+ <div class="ds-fp-v3-pop-body">
751
+ <div class="ds-fp-v3-field">
752
+ <label class="ds-fp-v3-field-lbl">CONDITION</label>
753
+ <select class="ds-fp-v3-condition" data-filter-id="${this.escAttr(e.filterId)}">
754
+ ${be.map(
755
+ (s) => `<option value="${this.escAttr(s.value)}"${s.value === t.operator ? " selected" : ""}>${s.label}</option>`
756
+ ).join("")}
686
757
  </select>
687
- </div>`;
688
- case "date-range":
689
- const r = (t == null ? void 0 : t.from) || "", a = (t == null ? void 0 : t.to) || "";
690
- return `
691
- <div class="ds-filter-item">
692
- ${i}
693
- <div class="ds-date-range-inputs">
694
- <input type="date" class="ds-filter-input"
695
- data-filter-id="${e.filterId}" data-date-part="from"
696
- value="${r}" />
697
- <span>–</span>
698
- <input type="date" class="ds-filter-input"
699
- data-filter-id="${e.filterId}" data-date-part="to"
700
- value="${a}" />
701
- </div>
702
- </div>`;
703
- case "text-input":
704
- return `
705
- <div class="ds-filter-item">
706
- ${i}
707
- <input type="text" class="ds-filter-input" id="${s}"
708
- data-filter-id="${e.filterId}"
709
- value="${this.escAttr(String(t != null ? t : ""))}"
710
- placeholder="Search..." />
711
- </div>`;
712
- case "number-input":
713
- return `
714
- <div class="ds-filter-item">
715
- ${i}
716
- <input type="number" class="ds-filter-input" id="${s}"
717
- data-filter-id="${e.filterId}"
718
- value="${this.escAttr(String(t != null ? t : ""))}" />
719
- </div>`;
720
- default:
721
- return "";
722
- }
758
+ </div>
759
+ <div class="ds-fp-v3-field">
760
+ <label class="ds-fp-v3-field-lbl">VALUES</label>
761
+ ${this.renderValuesControl(e, t)}
762
+ </div>
763
+ </div>
764
+ <div class="ds-fp-v3-pop-footer">
765
+ <button type="button" class="ds-fp-v3-clear-btn"
766
+ data-filter-id="${this.escAttr(e.filterId)}">Clear</button>
767
+ <button type="button" class="ds-fp-v3-apply-btn"
768
+ data-filter-id="${this.escAttr(e.filterId)}">Apply Filter</button>
769
+ </div>
770
+ </div>`;
723
771
  }
724
- attachListeners(e) {
725
- const t = {};
726
- this.container.querySelectorAll("[data-filter-id]").forEach((s) => {
727
- const i = s.dataset.filterId, r = s.dataset.datePart, a = e.find((c) => c.filterId === i), o = () => {
728
- let c;
729
- if ((a == null ? void 0 : a.type) === "date-range" && r)
730
- t[i] = t[i] || {}, t[i][r] = s.value, c = { ...t[i] };
731
- else if ((a == null ? void 0 : a.type) === "multi-select") {
732
- const d = s;
733
- c = Array.from(d.selectedOptions).map((b) => b.value).filter(Boolean);
734
- } else
735
- c = s.value;
736
- this.currentValues[i] = c, this.onFilterChange(i, c);
737
- };
738
- s.addEventListener(
739
- (a == null ? void 0 : a.type) === "text-input" ? "input" : "change",
740
- o
772
+ renderValuesControl(e, t) {
773
+ var s, r, o;
774
+ return e.type === "date-range" ? `
775
+ <div class="ds-fp-v3-date-range">
776
+ <input type="date" class="ds-fp-v3-date" data-part="from"
777
+ data-filter-id="${this.escAttr(e.filterId)}"
778
+ value="${this.escAttr((s = t.tempValues[0]) != null ? s : "")}" placeholder="From"/>
779
+ <span class="ds-fp-v3-date-sep">–</span>
780
+ <input type="date" class="ds-fp-v3-date" data-part="to"
781
+ data-filter-id="${this.escAttr(e.filterId)}"
782
+ value="${this.escAttr((r = t.tempValues[1]) != null ? r : "")}" placeholder="To"/>
783
+ </div>` : e.type === "text-input" || e.type === "number-input" ? `<input type="${e.type === "number-input" ? "number" : "text"}"
784
+ class="ds-fp-v3-text-input"
785
+ data-filter-id="${this.escAttr(e.filterId)}"
786
+ value="${this.escAttr((o = t.tempValues[0]) != null ? o : "")}"
787
+ placeholder="Enter value…"/>` : this.renderMultiSelectControl(e, t);
788
+ }
789
+ renderMultiSelectControl(e, t) {
790
+ const s = t.tempValues.length === 0 ? "" : t.tempValues.length === 1 ? this.optLabel(e.filterId, t.tempValues[0]) : `${t.tempValues.length} selected`;
791
+ return `
792
+ <div class="ds-fp-v3-ms-wrap" data-filter-id="${this.escAttr(e.filterId)}">
793
+ <div class="ds-fp-v3-ms-trigger" data-filter-id="${this.escAttr(e.filterId)}">
794
+ <span class="ds-fp-v3-ms-display">${s || "Type to search..."}</span>
795
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
796
+ stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
797
+ <polyline points="6 9 12 15 18 9"/>
798
+ </svg>
799
+ </div>
800
+ <div class="ds-fp-v3-ms-drop" id="ds-fp-drop-${this.escAttr(e.filterId)}" style="display:none">
801
+ <input type="text" class="ds-fp-v3-ms-search"
802
+ data-filter-id="${this.escAttr(e.filterId)}"
803
+ placeholder="Search ${this.escAttr(e.label)}…"
804
+ value="${this.escAttr(t.search)}"/>
805
+ <div class="ds-fp-v3-ms-opts" id="ds-fp-opts-${this.escAttr(e.filterId)}">
806
+ ${this.renderOpts(e.filterId, t)}
807
+ </div>
808
+ </div>
809
+ ${t.tempValues.length > 0 ? `
810
+ <div class="ds-fp-v3-chips" id="ds-fp-chips-${this.escAttr(e.filterId)}">
811
+ ${t.tempValues.map((r) => `
812
+ <span class="ds-fp-v3-chip">
813
+ ${this.escText(this.optLabel(e.filterId, r))}
814
+ <button type="button" class="ds-fp-v3-chip-x"
815
+ data-val="${this.escAttr(r)}"
816
+ data-filter-id="${this.escAttr(e.filterId)}">✕</button>
817
+ </span>`).join("")}
818
+ </div>` : `<div class="ds-fp-v3-chips" id="ds-fp-chips-${this.escAttr(e.filterId)}"></div>`}
819
+ </div>`;
820
+ }
821
+ renderOpts(e, t) {
822
+ if (t.loading) return '<div class="ds-fp-v3-opts-msg"><span class="ds-dd-spinner"></span> Loading…</div>';
823
+ const s = t.search.toLowerCase(), r = t.options.filter(
824
+ (o) => (typeof o == "string" ? o : o.label).toLowerCase().includes(s)
825
+ );
826
+ return t.options.length ? r.length ? r.map((o) => {
827
+ const i = typeof o == "string" ? o : o.value, a = typeof o == "string" ? o : o.label, f = t.tempValues.includes(i);
828
+ return `
829
+ <label class="ds-fp-v3-opt${f ? " ds-fp-v3-opt-on" : ""}" data-val="${this.escAttr(i)}"
830
+ data-filter-id="${this.escAttr(e)}">
831
+ <span class="ds-fp-v3-cb${f ? " ds-fp-v3-cb-on" : ""}">
832
+ ${f ? `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"
833
+ stroke-linecap="round" stroke-linejoin="round" width="10" height="10">
834
+ <polyline points="20 6 9 17 4 12"/>
835
+ </svg>` : ""}
836
+ </span>
837
+ <span>${this.escText(a)}</span>
838
+ </label>`;
839
+ }).join("") : '<div class="ds-fp-v3-opts-msg">No matches</div>' : '<div class="ds-fp-v3-opts-msg">No options yet</div>';
840
+ }
841
+ // ── Event binding ──────────────────────────────────────────────────────────
842
+ bindAll() {
843
+ var e;
844
+ this.container.querySelectorAll(".ds-fp-v3-badge").forEach((t) => {
845
+ t.addEventListener("click", (s) => {
846
+ s.stopPropagation();
847
+ const r = t.dataset.filterId;
848
+ this.togglePopover(r, t);
849
+ });
850
+ }), (e = this.container.querySelector("#ds-fp-v3-add")) == null || e.addEventListener("click", (t) => {
851
+ t.stopPropagation();
852
+ const s = this.filters.find((o) => this.state.get(o.filterId).activeValues.length === 0);
853
+ if (!s) return;
854
+ const r = this.container.querySelector(
855
+ `.ds-fp-v3-badge[data-filter-id="${s.filterId}"]`
741
856
  );
857
+ r && this.togglePopover(s.filterId, r);
858
+ }), this.filters.forEach((t) => this.bindPopover(t));
859
+ }
860
+ bindPopover(e) {
861
+ var o, i, a, f, h, v, m;
862
+ const t = this.container.querySelector(`#ds-fp-pop-${e.filterId}`);
863
+ if (!t) return;
864
+ const s = this.state.get(e.filterId);
865
+ (o = t.querySelector(`.ds-fp-v3-condition[data-filter-id="${e.filterId}"]`)) == null || o.addEventListener("change", (p) => {
866
+ s.operator = p.target.value;
867
+ }), (i = t.querySelector(`.ds-fp-v3-text-input[data-filter-id="${e.filterId}"]`)) == null || i.addEventListener("input", (p) => {
868
+ const n = p.target.value;
869
+ s.tempValues = n ? [n] : [];
870
+ }), t.querySelectorAll(`.ds-fp-v3-date[data-filter-id="${e.filterId}"]`).forEach((p) => {
871
+ p.addEventListener("change", () => {
872
+ var u, b, c, d;
873
+ const n = (b = (u = t.querySelector(`[data-part="from"][data-filter-id="${e.filterId}"]`)) == null ? void 0 : u.value) != null ? b : "", g = (d = (c = t.querySelector(`[data-part="to"][data-filter-id="${e.filterId}"]`)) == null ? void 0 : c.value) != null ? d : "";
874
+ s.tempValues = [n, g];
875
+ });
876
+ }), (a = t.querySelector(`.ds-fp-v3-ms-trigger[data-filter-id="${e.filterId}"]`)) == null || a.addEventListener("click", (p) => {
877
+ p.stopPropagation();
878
+ const n = t.querySelector(`#ds-fp-drop-${e.filterId}`);
879
+ if (n) {
880
+ const g = n.style.display !== "none";
881
+ if (n.style.display = g ? "none" : "", !g) {
882
+ const u = n.querySelector(".ds-fp-v3-ms-search");
883
+ u == null || u.focus();
884
+ }
885
+ }
886
+ });
887
+ const r = t.querySelector(`.ds-fp-v3-ms-search[data-filter-id="${e.filterId}"]`);
888
+ r && r.addEventListener("input", () => {
889
+ s.search = r.value, this.repaintOpts(e.filterId);
890
+ }), this.bindOpts(e.filterId, t), this.bindChips(e.filterId, t), (f = t.querySelector(`.ds-fp-v3-pop-clear-btn[data-filter-id="${e.filterId}"]`)) == null || f.addEventListener("click", () => this.clearFilter(e.filterId)), (h = t.querySelector(`.ds-fp-v3-pop-close-btn[data-filter-id="${e.filterId}"]`)) == null || h.addEventListener("click", () => this.closePopover(e.filterId)), (v = t.querySelector(`.ds-fp-v3-clear-btn[data-filter-id="${e.filterId}"]`)) == null || v.addEventListener("click", () => this.clearFilter(e.filterId)), (m = t.querySelector(`.ds-fp-v3-apply-btn[data-filter-id="${e.filterId}"]`)) == null || m.addEventListener("click", () => this.applyFilter(e.filterId));
891
+ }
892
+ bindOpts(e, t) {
893
+ const s = this.state.get(e);
894
+ t.querySelectorAll(`.ds-fp-v3-opt[data-filter-id="${e}"]`).forEach((r) => {
895
+ r.addEventListener("click", (o) => {
896
+ var a;
897
+ o.stopPropagation();
898
+ const i = (a = r.dataset.val) != null ? a : "";
899
+ s.tempValues.includes(i) ? s.tempValues = s.tempValues.filter((f) => f !== i) : s.tempValues = [...s.tempValues, i], this.repaintOpts(e), this.repaintChips(e);
900
+ });
901
+ });
902
+ }
903
+ bindChips(e, t) {
904
+ const s = this.state.get(e);
905
+ t.querySelectorAll(`.ds-fp-v3-chip-x[data-filter-id="${e}"]`).forEach((r) => {
906
+ r.addEventListener("click", (o) => {
907
+ o.stopPropagation(), s.tempValues = s.tempValues.filter((i) => {
908
+ var a;
909
+ return i !== ((a = r.dataset.val) != null ? a : "");
910
+ }), this.repaintOpts(e), this.repaintChips(e);
911
+ });
742
912
  });
743
913
  }
914
+ // ── Popover show/hide ──────────────────────────────────────────────────────
915
+ togglePopover(e, t) {
916
+ if (this.activePopoverId === e) {
917
+ this.closePopover(e);
918
+ return;
919
+ }
920
+ this.activePopoverId && this.closePopover(this.activePopoverId);
921
+ const s = this.container.querySelector(`#ds-fp-pop-${e}`);
922
+ if (!s) return;
923
+ const r = this.container.getBoundingClientRect(), o = t.getBoundingClientRect();
924
+ s.style.top = `${o.bottom - r.top + 4}px`, s.style.left = `${o.left - r.left}px`, s.style.display = "", this.activePopoverId = e;
925
+ const i = this.state.get(e);
926
+ i.tempValues = [...i.activeValues], i.search = "", this.repaintOpts(e), this.repaintChips(e);
927
+ const a = s.querySelector(`#ds-fp-drop-${e}`);
928
+ a && (a.style.display = "none");
929
+ }
930
+ closePopover(e) {
931
+ const t = this.container.querySelector(`#ds-fp-pop-${e}`);
932
+ t && (t.style.display = "none"), this.activePopoverId === e && (this.activePopoverId = null);
933
+ }
934
+ closePopoverOnOutsideClick() {
935
+ document.addEventListener("mousedown", (e) => {
936
+ if (!this.activePopoverId) return;
937
+ const t = this.container.querySelector(`#ds-fp-pop-${this.activePopoverId}`), s = this.container.querySelector("#ds-fp-v3-bar");
938
+ t && !t.contains(e.target) && s && !s.contains(e.target) && this.closePopover(this.activePopoverId);
939
+ }, { capture: !0 });
940
+ }
941
+ // ── Apply / clear ──────────────────────────────────────────────────────────
942
+ applyFilter(e) {
943
+ var o;
944
+ const t = this.state.get(e), s = this.filters.find((i) => i.filterId === e);
945
+ t.activeValues = [...t.tempValues];
946
+ let r;
947
+ s.type === "date-range" ? r = t.tempValues.length >= 2 && (t.tempValues[0] || t.tempValues[1]) ? { from: t.tempValues[0], to: t.tempValues[1] } : "" : s.type === "multi-select" || t.tempValues.length > 1 ? r = t.tempValues.length > 0 ? [...t.tempValues] : "" : r = (o = t.tempValues[0]) != null ? o : "", this.repaintBadge(e), this.closePopover(e), this.onFilterChange(e, r, t.operator);
948
+ }
949
+ clearFilter(e) {
950
+ const t = this.state.get(e);
951
+ t.tempValues = [], t.activeValues = [], this.repaintBadge(e), this.repaintOpts(e), this.repaintChips(e), this.closePopover(e), this.onFilterChange(e, "", void 0);
952
+ }
953
+ // ── Repaint helpers ────────────────────────────────────────────────────────
954
+ repaintBadge(e) {
955
+ const t = this.state.get(e), s = this.container.querySelector(`.ds-fp-v3-badge[data-filter-id="${e}"]`);
956
+ s && (t.activeValues.length > 0 ? s.classList.add("ds-fp-v3-badge-active") : s.classList.remove("ds-fp-v3-badge-active"));
957
+ }
958
+ repaintBadges() {
959
+ this.filters.forEach((e) => this.repaintBadge(e.filterId));
960
+ }
961
+ repaintOpts(e) {
962
+ const t = this.state.get(e);
963
+ if (!t) return;
964
+ const s = this.container.querySelector(`#ds-fp-opts-${e}`);
965
+ if (!s) return;
966
+ s.innerHTML = this.renderOpts(e, t);
967
+ const r = this.container.querySelector(`#ds-fp-pop-${e}`);
968
+ r && this.bindOpts(e, r);
969
+ }
970
+ refreshPopoverOpts(e) {
971
+ this.repaintOpts(e);
972
+ const t = this.state.get(e);
973
+ if (!t) return;
974
+ const s = this.container.querySelector(
975
+ `.ds-fp-v3-ms-trigger[data-filter-id="${e}"] .ds-fp-v3-ms-display`
976
+ );
977
+ s && (s.textContent = t.tempValues.length === 0 ? "Type to search..." : t.tempValues.length === 1 ? this.optLabel(e, t.tempValues[0]) : `${t.tempValues.length} selected`);
978
+ }
979
+ repaintChips(e) {
980
+ const t = this.state.get(e);
981
+ if (!t) return;
982
+ const s = this.container.querySelector(`#ds-fp-chips-${e}`);
983
+ if (!s) return;
984
+ if (t.tempValues.length === 0) {
985
+ s.innerHTML = "";
986
+ const i = this.container.querySelector(
987
+ `.ds-fp-v3-ms-trigger[data-filter-id="${e}"] .ds-fp-v3-ms-display`
988
+ );
989
+ i && (i.textContent = "Type to search...");
990
+ return;
991
+ }
992
+ const r = this.filters.find((i) => i.filterId === e);
993
+ s.innerHTML = t.tempValues.map((i) => `
994
+ <span class="ds-fp-v3-chip">
995
+ ${this.escText(this.optLabel(r.filterId, i))}
996
+ <button type="button" class="ds-fp-v3-chip-x"
997
+ data-val="${this.escAttr(i)}"
998
+ data-filter-id="${this.escAttr(e)}">✕</button>
999
+ </span>`).join(""), this.bindChips(e, s);
1000
+ const o = this.container.querySelector(
1001
+ `.ds-fp-v3-ms-trigger[data-filter-id="${e}"] .ds-fp-v3-ms-display`
1002
+ );
1003
+ o && (o.textContent = t.tempValues.length === 1 ? this.optLabel(e, t.tempValues[0]) : `${t.tempValues.length} selected`);
1004
+ }
1005
+ // ── Emit reset-all signal ──────────────────────────────────────────────────
1006
+ resetAll() {
1007
+ this.state.forEach((e) => {
1008
+ e.tempValues = [], e.activeValues = [];
1009
+ }), this.repaintBadges(), this.activePopoverId && this.closePopover(this.activePopoverId), this.onFilterChange("__reset_all__", null);
1010
+ }
1011
+ // ── Utils ──────────────────────────────────────────────────────────────────
1012
+ optLabel(e, t) {
1013
+ const s = this.state.get(e);
1014
+ if (!s) return t;
1015
+ const r = s.options.find((o) => (typeof o == "string" ? o : o.value) === t);
1016
+ return r ? typeof r == "string" ? r : r.label : t;
1017
+ }
744
1018
  escAttr(e) {
745
1019
  return String(e != null ? e : "").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
746
1020
  }
@@ -748,9 +1022,9 @@ class pe {
748
1022
  return String(e != null ? e : "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
749
1023
  }
750
1024
  }
751
- const H = class H {
1025
+ const N = class N {
752
1026
  constructor(e, t) {
753
- this.activePageId = "", this.activeTabId = "", this.activeFilters = {}, this.chartRenderers = /* @__PURE__ */ new Map(), this.tableRenderer = new le(), this.cardRenderer = new ce(), this.isLoadingTab = !1, this.tooltipEl = null, this.root = e, this.opts = t, this.activeFilters = { ...t.initialFilters };
1027
+ this.activePageId = "", this.activeTabId = "", this.activeFilters = {}, this.activeFilterOperators = {}, this.activeLocalFilters = {}, this.chartRenderers = /* @__PURE__ */ new Map(), this.tableRenderer = new le(), this.cardRenderer = new ce(), this.isLoadingTab = !1, this.tooltipEl = null, this.root = e, this.opts = t, this.activeFilters = { ...t.initialFilters };
754
1028
  }
755
1029
  // ── Initial full render ───────────────────────────────────────────────────
756
1030
  render(e) {
@@ -772,45 +1046,45 @@ const H = class H {
772
1046
  this.chartRenderers.forEach((e) => e.destroy()), this.chartRenderers.clear(), this.root.innerHTML = "";
773
1047
  }
774
1048
  exportPDF() {
775
- var g, n;
1049
+ var p, n;
776
1050
  const e = this.root.querySelector("#ds-grid");
777
1051
  if (!e) return;
778
1052
  const t = this.root.style.height, s = this.root.style.overflow;
779
1053
  this.root.style.height = "auto", this.root.style.overflow = "visible";
780
- const i = this.root.querySelector("#ds-canvas"), r = (g = i == null ? void 0 : i.style.height) != null ? g : "", a = (n = i == null ? void 0 : i.style.overflow) != null ? n : "";
781
- i && (i.style.height = "auto", i.style.overflow = "visible");
782
- const o = Array.from(e.querySelectorAll(".ds-table-scroll")), c = o.map((f) => ({
783
- el: f,
784
- overflow: f.style.overflow,
785
- maxHeight: f.style.maxHeight,
786
- height: f.style.height
1054
+ const r = this.root.querySelector("#ds-canvas"), o = (p = r == null ? void 0 : r.style.height) != null ? p : "", i = (n = r == null ? void 0 : r.style.overflow) != null ? n : "";
1055
+ r && (r.style.height = "auto", r.style.overflow = "visible");
1056
+ const a = Array.from(e.querySelectorAll(".ds-table-scroll")), f = a.map((g) => ({
1057
+ el: g,
1058
+ overflow: g.style.overflow,
1059
+ maxHeight: g.style.maxHeight,
1060
+ height: g.style.height
787
1061
  }));
788
- o.forEach((f) => {
789
- f.style.overflow = "visible", f.style.maxHeight = "none", f.style.height = "auto";
1062
+ a.forEach((g) => {
1063
+ g.style.overflow = "visible", g.style.maxHeight = "none", g.style.height = "auto";
790
1064
  });
791
- const d = e.offsetWidth, b = parseInt(e.style.height, 10) || e.offsetHeight, u = e.getBoundingClientRect().top + window.scrollY;
1065
+ const h = e.offsetWidth, v = parseInt(e.style.height, 10) || e.offsetHeight, m = e.getBoundingClientRect().top + window.scrollY;
792
1066
  import("./html2canvas.esm-CzwMv54K.js").then(
793
- ({ default: f }) => f(e, {
1067
+ ({ default: g }) => g(e, {
794
1068
  scale: 2,
795
1069
  useCORS: !0,
796
1070
  allowTaint: !0,
797
1071
  logging: !1,
798
- width: d,
799
- height: b,
800
- windowWidth: d,
801
- windowHeight: b,
1072
+ width: h,
1073
+ height: v,
1074
+ windowWidth: h,
1075
+ windowHeight: v,
802
1076
  scrollX: 0,
803
- scrollY: -u
804
- }).then((p) => {
805
- this.root.style.height = t, this.root.style.overflow = s, i && (i.style.height = r, i.style.overflow = a), c.forEach(({ el: l, overflow: x, maxHeight: h, height: y }) => {
806
- l.style.overflow = x, l.style.maxHeight = h, l.style.height = y;
807
- }), import("./jspdf.es.min-d9hlG26J.js").then((l) => l.j).then(({ jsPDF: l }) => {
808
- const x = p.width / 2, h = p.height / 2, y = new l({
809
- orientation: x >= h ? "landscape" : "portrait",
1077
+ scrollY: -m
1078
+ }).then((u) => {
1079
+ this.root.style.height = t, this.root.style.overflow = s, r && (r.style.height = o, r.style.overflow = i), f.forEach(({ el: b, overflow: c, maxHeight: d, height: l }) => {
1080
+ b.style.overflow = c, b.style.maxHeight = d, b.style.height = l;
1081
+ }), import("./jspdf.es.min-d9hlG26J.js").then((b) => b.j).then(({ jsPDF: b }) => {
1082
+ const c = u.width / 2, d = u.height / 2, l = new b({
1083
+ orientation: c >= d ? "landscape" : "portrait",
810
1084
  unit: "px",
811
- format: [x, h]
1085
+ format: [c, d]
812
1086
  });
813
- y.addImage(p.toDataURL("image/png"), "PNG", 0, 0, x, h), y.save(`${this.renderData.dashboard.name || "dashboard"}.pdf`);
1087
+ l.addImage(u.toDataURL("image/png"), "PNG", 0, 0, c, d), l.save(`${this.renderData.dashboard.name || "dashboard"}.pdf`);
814
1088
  });
815
1089
  })
816
1090
  );
@@ -819,30 +1093,42 @@ const H = class H {
819
1093
  this.renderData.components.forEach((e) => {
820
1094
  const t = this.renderData.data[e.id];
821
1095
  if (!(t != null && t.length) || !["table", "bar", "line", "area"].includes(e.type)) return;
822
- const s = Object.keys(t[0]), i = [s.join(","), ...t.map(
823
- (a) => s.map((o) => {
824
- var c;
825
- return JSON.stringify((c = a[o]) != null ? c : "");
1096
+ const s = Object.keys(t[0]), r = [s.join(","), ...t.map(
1097
+ (i) => s.map((a) => {
1098
+ var f;
1099
+ return JSON.stringify((f = i[a]) != null ? f : "");
826
1100
  }).join(",")
827
1101
  )].join(`
828
1102
  `);
829
1103
  Object.assign(document.createElement("a"), {
830
- href: URL.createObjectURL(new Blob([i], { type: "text/csv" })),
1104
+ href: URL.createObjectURL(new Blob([r], { type: "text/csv" })),
831
1105
  download: `${e.title || e.id}.csv`
832
1106
  }).click();
833
1107
  });
834
1108
  }
1109
+ /** Returns a snapshot of the currently active filter values (used by DeepspotSDK onTabSwitch). */
1110
+ getActiveFilters() {
1111
+ return { ...this.activeFilters };
1112
+ }
1113
+ /** Returns a snapshot of the active filter operators (=, LIKE, IN, etc.) keyed by applyToField. */
1114
+ getActiveFilterOperators() {
1115
+ return { ...this.activeFilterOperators };
1116
+ }
1117
+ /** Returns local (component-scoped) filter values keyed by filterId. */
1118
+ getActiveLocalFilters() {
1119
+ return { ...this.activeLocalFilters };
1120
+ }
835
1121
  updateFilterValues(e) {
836
1122
  var t;
837
1123
  Object.assign(this.activeFilters, e), (t = this.filterRenderer) == null || t.updateValues(e);
838
1124
  }
839
1125
  // ── Shell ─────────────────────────────────────────────────────────────────
840
1126
  buildShell() {
841
- const e = this.opts.embedLevel, t = this.renderData.dashboard.pages, s = e === "dashboard" && t.length > 1, i = e === "page" || e === "dashboard";
1127
+ const e = this.opts.embedLevel, t = this.renderData.dashboard.pages, s = e === "dashboard" && t.length > 1, r = e === "page" || e === "dashboard";
842
1128
  this.root.innerHTML = `
843
1129
  ${this.opts.hideExport ? "" : '<div class="ds-toolbar" id="ds-toolbar"></div>'}
844
1130
  ${s ? '<nav class="ds-page-nav" id="ds-page-nav"></nav>' : ""}
845
- ${i ? '<nav class="ds-page-nav" id="ds-tab-nav"></nav>' : ""}
1131
+ ${r ? '<nav class="ds-page-nav" id="ds-tab-nav"></nav>' : ""}
846
1132
  <div id="ds-filter-container"></div>
847
1133
  <div class="ds-canvas" id="ds-canvas">
848
1134
  <div class="ds-grid" id="ds-grid"></div>
@@ -852,13 +1138,17 @@ const H = class H {
852
1138
  <div class="ds-embed-spinner"></div>
853
1139
  </div>
854
1140
  `, this.root.style.position = "relative", this.opts.hideExport || this.buildExportToolbar();
855
- const r = this.root.querySelector("#ds-filter-container");
856
- this.filterRenderer = new pe(r, (a, o) => {
857
- var u, g, n, f, p;
858
- const c = (u = this.renderData.filters) == null ? void 0 : u.find((l) => l.filterId === a), d = (g = this.renderData.components) == null ? void 0 : g.find(
859
- (l) => l.type === "inline-filter" && l.id === a
860
- ), b = (c == null ? void 0 : c.applyToField) || ((n = d == null ? void 0 : d.properties) == null ? void 0 : n.applyToField) || a;
861
- this.activeFilters[b] = o, (p = (f = this.opts).onFilterChange) == null || p.call(f, this.activeFilters), this.opts.onTabSwitch(this.activePageId, this.activeTabId);
1141
+ const o = this.root.querySelector("#ds-filter-container");
1142
+ this.filterRenderer = new ge(o, (i, a, f) => {
1143
+ var b, c, d, l, T, w, k, x, $, y, S;
1144
+ if (i === "__reset_all__") {
1145
+ this.activeFilters = {}, this.activeFilterOperators = {}, this.activeLocalFilters = {}, (c = (b = this.opts).onFilterChange) == null || c.call(b, this.activeFilters), this.opts.onTabSwitch(this.activePageId, this.activeTabId);
1146
+ return;
1147
+ }
1148
+ const h = (d = this.renderData.filters) == null ? void 0 : d.find((C) => C.filterId === i), v = (l = this.renderData.components) == null ? void 0 : l.find(
1149
+ (C) => C.type === "inline-filter" && C.id === i
1150
+ ), m = (h == null ? void 0 : h.applyToField) || ((T = v == null ? void 0 : v.properties) == null ? void 0 : T.applyToField) || i, p = (x = (k = h == null ? void 0 : h.columnMappings) != null ? k : (w = v == null ? void 0 : v.properties) == null ? void 0 : w.columnMappings) != null ? x : {}, g = (($ = h == null ? void 0 : h.targetComponents) != null ? $ : []).length > 0 || Object.keys(p).length > 0, u = a === "" || a === null || a === void 0 || Array.isArray(a) && a.length === 0;
1151
+ g ? u ? delete this.activeLocalFilters[i] : this.activeLocalFilters[i] = { value: a, operator: f || "=" } : u ? (delete this.activeFilters[m], delete this.activeFilterOperators[m]) : (this.activeFilters[m] = a, f ? this.activeFilterOperators[m] = f : delete this.activeFilterOperators[m]), (S = (y = this.opts).onFilterChange) == null || S.call(y, this.activeFilters), this.opts.onTabSwitch(this.activePageId, this.activeTabId);
862
1152
  });
863
1153
  }
864
1154
  buildExportToolbar() {
@@ -880,9 +1170,9 @@ const H = class H {
880
1170
  data-page-id="${t.pageId}">${t.title}</button>
881
1171
  `).join(""), e.querySelectorAll(".ds-page-tab").forEach((t) => {
882
1172
  t.addEventListener("click", () => {
883
- var i, r;
1173
+ var r, o;
884
1174
  const s = t.dataset.pageId;
885
- s === this.activePageId && !this.isLoadingTab || this.triggerTabSwitch(s, (r = (i = this.getTabsForPage(s)[0]) == null ? void 0 : i.id) != null ? r : "");
1175
+ s === this.activePageId && !this.isLoadingTab || this.triggerTabSwitch(s, (o = (r = this.getTabsForPage(s)[0]) == null ? void 0 : r.id) != null ? o : "");
886
1176
  });
887
1177
  }));
888
1178
  }
@@ -896,13 +1186,13 @@ const H = class H {
896
1186
  e.style.display = "none";
897
1187
  return;
898
1188
  }
899
- e.style.display = "", e.innerHTML = s.map((i) => `
900
- <button class="ds-page-tab ${i.id === this.activeTabId ? "ds-active" : ""}"
901
- data-tab-id="${i.id}" data-page-id="${t}">${i.title}</button>
902
- `).join(""), e.querySelectorAll(".ds-page-tab").forEach((i) => {
903
- i.addEventListener("click", () => {
904
- const r = i.dataset.tabId, a = i.dataset.pageId;
905
- r === this.activeTabId && a === this.activePageId && !this.isLoadingTab || this.triggerTabSwitch(a, r);
1189
+ e.style.display = "", e.innerHTML = s.map((r) => `
1190
+ <button class="ds-page-tab ${r.id === this.activeTabId ? "ds-active" : ""}"
1191
+ data-tab-id="${r.id}" data-page-id="${t}">${r.title}</button>
1192
+ `).join(""), e.querySelectorAll(".ds-page-tab").forEach((r) => {
1193
+ r.addEventListener("click", () => {
1194
+ const o = r.dataset.tabId, i = r.dataset.pageId;
1195
+ o === this.activeTabId && i === this.activePageId && !this.isLoadingTab || this.triggerTabSwitch(i, o);
906
1196
  });
907
1197
  });
908
1198
  }
@@ -921,100 +1211,133 @@ const H = class H {
921
1211
  // components (type='inline-filter' in renderData.components[]).
922
1212
  // Inline-filter components are NOT rendered in the grid — they appear here.
923
1213
  renderFilterBar() {
924
- if (this.opts.hideGlobalFilters) return;
925
- const e = [
926
- ...this.renderData.filters || [],
927
- ...this.inlineFiltersAsDefinitions()
928
- ];
929
- this.filterRenderer.render(e, this.activeFilters), this.fetchFilterOptions();
1214
+ this.opts.hideGlobalFilters || (this.filterRenderer.render(this.globalFilters(), this.mergedFilterValues()), this.fetchFilterOptions());
930
1215
  }
931
1216
  updateFilterBar() {
932
- if (this.opts.hideGlobalFilters) return;
933
- const e = [
934
- ...this.renderData.filters || [],
935
- ...this.inlineFiltersAsDefinitions()
936
- ];
937
- this.filterRenderer.render(e, this.activeFilters), this.fetchFilterOptions();
938
- }
939
- /** Convert inline-filter ComponentConfig entries to FilterDefinition shape */
1217
+ this.opts.hideGlobalFilters || (this.filterRenderer.render(this.globalFilters(), this.mergedFilterValues()), this.fetchFilterOptions());
1218
+ }
1219
+ /** Combines global activeFilters and local filter values (keyed by filterId)
1220
+ * so FilterRenderer can show correct active state for targeted filters. */
1221
+ mergedFilterValues() {
1222
+ const e = { ...this.activeFilters };
1223
+ for (const [t, { value: s }] of Object.entries(this.activeLocalFilters))
1224
+ e[t] = s;
1225
+ return e;
1226
+ }
1227
+ /**
1228
+ * Returns true when a filter should appear in the global top filter bar.
1229
+ * A filter is global when the matching inline-filter component has
1230
+ * filter_scope/scope !== 'local' and filterLevel !== 'component'.
1231
+ */
1232
+ filterIsGlobal(e) {
1233
+ var r, o;
1234
+ const t = (this.renderData.components || []).find(
1235
+ (i) => i.type === "inline-filter" && i.id === e
1236
+ );
1237
+ if (t) {
1238
+ const i = ((r = t.properties) == null ? void 0 : r.filter_scope) || ((o = t.properties) == null ? void 0 : o.scope);
1239
+ if (i === "local") return !1;
1240
+ if (i === "global") return !0;
1241
+ }
1242
+ const s = (this.renderData.filters || []).find((i) => i.filterId === e);
1243
+ return !(s != null && s.filterLevel) || s.filterLevel === "global";
1244
+ }
1245
+ /** Filters from renderData.filters[] that should appear in the global top panel. */
1246
+ globalFilters() {
1247
+ return (this.renderData.filters || []).filter((e) => this.filterIsGlobal(e.filterId));
1248
+ }
1249
+ /**
1250
+ * Filters that are component-scoped (filter_scope='local').
1251
+ * Source of truth is filters[] — which has applyToField, targetComponents, etc.
1252
+ * The matching inline-filter component in components[] provides the scope signal.
1253
+ */
940
1254
  inlineFiltersAsDefinitions() {
941
- return this.opts.hideInlineFilters ? [] : (this.renderData.components || []).filter((e) => e.type === "inline-filter").map((e) => {
942
- var t, s, i, r, a, o, c, d;
943
- return {
944
- filterId: e.id,
945
- label: ((t = e.properties) == null ? void 0 : t.filterLabel) || e.title || "",
946
- type: ((s = e.properties) == null ? void 0 : s.filterType) || "dropdown",
947
- options: ((i = e.properties) == null ? void 0 : i.filterOptions) || ((r = e.properties) == null ? void 0 : r.options) || [],
948
- defaultValue: (a = e.properties) == null ? void 0 : a.defaultValue,
949
- targetComponents: ((o = e.properties) == null ? void 0 : o.targetComponents) || [],
950
- filterOperator: (c = e.properties) == null ? void 0 : c.filterOperator,
951
- applyToField: ((d = e.properties) == null ? void 0 : d.applyToField) || e.id
952
- };
953
- });
1255
+ return this.opts.hideInlineFilters ? [] : (this.renderData.filters || []).filter((e) => {
1256
+ var t, s;
1257
+ return !this.filterIsGlobal(e.filterId) && ((s = (t = e.targetComponents) == null ? void 0 : t.length) != null ? s : 0) > 0;
1258
+ }).map((e) => ({ ...e, filterLevel: "component" }));
954
1259
  }
955
1260
  async fetchFilterOptions() {
956
- if (this.opts.onFetchFilterOptions)
957
- for (const e of this.renderData.filters) {
958
- if (e.type !== "dropdown" && e.type !== "multi-select" || e.options && e.options.length > 0) continue;
959
- const t = await this.opts.onFetchFilterOptions(e.filterId);
960
- t.length > 0 && this.filterRenderer.updateOptions(e.filterId, t);
961
- }
1261
+ if (this.opts.onFetchFilterOptions) {
1262
+ for (const e of this.globalFilters())
1263
+ if (!(e.type !== "dropdown" && e.type !== "multi-select") && !(e.options && e.options.length > 0)) {
1264
+ this.filterRenderer.setLoading(e.filterId, !0);
1265
+ try {
1266
+ const t = await this.opts.onFetchFilterOptions(e.filterId);
1267
+ this.filterRenderer.updateOptions(e.filterId, t);
1268
+ } catch (t) {
1269
+ this.filterRenderer.setLoading(e.filterId, !1);
1270
+ }
1271
+ }
1272
+ }
962
1273
  }
963
1274
  // ── Grid ──────────────────────────────────────────────────────────────────
964
1275
  renderGrid() {
1276
+ var m;
965
1277
  this.hideTabSpinner();
966
1278
  const e = this.root.querySelector("#ds-grid");
967
1279
  if (!e) return;
968
1280
  if (!this.opts.hideBackground) {
969
- const d = this.root.querySelector("#ds-canvas"), b = this.renderData.dashboard.pages.find(
970
- (g) => g.pageId === this.activePageId
971
- ), u = (b == null ? void 0 : b.backgroundColor) || "";
972
- d && (d.style.background = u), this.root.style.background = u;
1281
+ const p = this.root.querySelector("#ds-canvas"), n = this.renderData.dashboard.pages.find(
1282
+ (u) => u.pageId === this.activePageId
1283
+ ), g = (n == null ? void 0 : n.backgroundColor) || "";
1284
+ p && (p.style.background = g), this.root.style.background = g;
973
1285
  }
974
- this.chartRenderers.forEach((d) => d.destroy()), this.chartRenderers.clear();
1286
+ this.chartRenderers.forEach((p) => p.destroy()), this.chartRenderers.clear();
975
1287
  const t = (this.renderData.components || []).filter(
976
- (d) => d.type !== "inline-filter"
1288
+ (p) => p.type !== "inline-filter"
977
1289
  );
978
1290
  if (!t.length) {
979
1291
  e.style.height = "200px", e.innerHTML = '<div class="ds-chart-empty" style="padding-top:80px;">No components on this tab.</div>';
980
1292
  return;
981
1293
  }
982
- const s = e.clientWidth || this.root.clientWidth || 800, i = t.map((d) => d.position), r = i.length ? Math.min(...i.map((d) => d.y)) : 0, a = new ae(s, r);
983
- e.style.height = `${ae.totalHeight(i)}px`, e.innerHTML = "";
984
- const o = 36, c = [];
985
- t.forEach((d) => {
986
- var p, l, x;
987
- const b = document.createElement("div");
988
- if (b.className = "ds-component-wrapper", b.dataset.componentId = d.id, a.applyStyles(b, d.position), !this.opts.hideBackground) {
989
- const h = ((l = (p = d.properties) == null ? void 0 : p.styleConfig) == null ? void 0 : l.backgroundColor) || ((x = d.properties) == null ? void 0 : x.backgroundColor);
990
- h && (b.style.background = h);
1294
+ const s = e.clientWidth || this.root.clientWidth || 800, r = t.map((p) => p.position), o = r.length ? Math.min(...r.map((p) => p.y)) : 0, i = new ie(s, o);
1295
+ e.style.height = `${ie.totalHeight(r)}px`, e.innerHTML = "";
1296
+ const a = 36, f = this.inlineFiltersAsDefinitions(), h = /* @__PURE__ */ new Map();
1297
+ for (const p of f)
1298
+ for (const n of (m = p.targetComponents) != null ? m : [])
1299
+ h.has(n) || h.set(n, []), h.get(n).push(p);
1300
+ const v = [];
1301
+ t.forEach((p) => {
1302
+ var d, l, T, w, k;
1303
+ const n = document.createElement("div");
1304
+ if (n.className = "ds-component-wrapper", n.dataset.componentId = p.id, i.applyStyles(n, p.position), !this.opts.hideBackground) {
1305
+ const x = ((l = (d = p.properties) == null ? void 0 : d.styleConfig) == null ? void 0 : l.backgroundColor) || ((T = p.properties) == null ? void 0 : T.backgroundColor);
1306
+ x && (n.style.background = x);
991
1307
  }
992
- e.appendChild(b);
993
- const u = a.toPx(d.position), g = Math.max(50, u.height - o), n = document.createElement("div");
994
- n.style.cssText = "width:100%;height:100%;", b.appendChild(n);
995
- const f = this.getComponentDescription(d);
996
- if (f) {
997
- const h = this.getTooltipEl();
998
- b.addEventListener("mouseenter", () => {
999
- h.textContent = f, h.style.display = "block";
1000
- const y = b.getBoundingClientRect(), T = h.offsetHeight || 36;
1001
- window.innerHeight - y.bottom >= T + 6 ? h.style.top = `${y.bottom + 4}px` : h.style.top = `${y.top - T - 4}px`, h.style.left = `${y.left}px`, h.style.width = `${y.width}px`;
1002
- }), b.addEventListener("mouseleave", () => {
1003
- h.style.display = "none";
1308
+ e.appendChild(n);
1309
+ const g = i.toPx(p.position), u = Math.max(50, g.height - a), b = document.createElement("div");
1310
+ b.style.cssText = "width:100%;height:100%;", n.appendChild(b);
1311
+ const c = this.getComponentDescription(p);
1312
+ if (c) {
1313
+ const x = this.getTooltipEl();
1314
+ n.addEventListener("mouseenter", () => {
1315
+ x.textContent = c, x.style.display = "block";
1316
+ const $ = n.getBoundingClientRect(), y = x.offsetHeight || 36;
1317
+ window.innerHeight - $.bottom >= y + 6 ? x.style.top = `${$.bottom + 4}px` : x.style.top = `${$.top - y - 4}px`, x.style.left = `${$.left}px`, x.style.width = `${$.width}px`;
1318
+ }), n.addEventListener("mouseleave", () => {
1319
+ x.style.display = "none";
1004
1320
  });
1005
1321
  }
1006
- c.push(
1007
- this.renderComponent(n, d, g).catch((h) => {
1008
- console.error(`[Deepspot SDK] Failed to render component ${d.id} (${d.type}):`, h), n.innerHTML = `<div style="padding:8px;color:#ef4444;font-size:12px;">⚠ ${d.type} render error</div>`;
1322
+ if (!this.opts.hideInlineFilters) {
1323
+ const x = [
1324
+ ...(w = h.get(p.id)) != null ? w : [],
1325
+ ...(k = h.get("__all__")) != null ? k : []
1326
+ ].filter(($, y, S) => S.findIndex((C) => C.filterId === $.filterId) === y);
1327
+ x.length > 0 && this.attachInlineFilterBtn(n, x);
1328
+ }
1329
+ v.push(
1330
+ this.renderComponent(b, p, u).catch((x) => {
1331
+ console.error(`[Deepspot SDK] Failed to render component ${p.id} (${p.type}):`, x), b.innerHTML = `<div style="padding:8px;color:#ef4444;font-size:12px;">⚠ ${p.type} render error</div>`;
1009
1332
  })
1010
1333
  );
1011
- }), Promise.all(c).catch(() => {
1334
+ }), Promise.all(v).catch(() => {
1012
1335
  });
1013
1336
  }
1014
1337
  // ── Component renderer switch ─────────────────────────────────────────────
1015
1338
  async renderComponent(e, t, s) {
1016
- var a, o, c, d, b, u, g, n, f, p, l, x, h, y, T, C, $, R, I, L, F, U, W, _, Y, J, V, X, Z, Q, ee, te, se, ie, re;
1017
- const i = this.renderData.data[t.id] || [], r = this.opts.theme;
1339
+ var i, a, f, h, v, m, p, n, g, u, b, c, d, l, T, w, k, x, $, y, S, C, P, U, W, Y, J, X, Z, Q, ee, te, se, re, oe;
1340
+ const r = this.renderData.data[t.id] || [], o = this.opts.theme;
1018
1341
  switch (t.type) {
1019
1342
  case "bar":
1020
1343
  case "line":
@@ -1023,82 +1346,307 @@ const H = class H {
1023
1346
  case "area":
1024
1347
  case "scatter":
1025
1348
  case "stacked-bar": {
1026
- const w = new ne(e);
1027
- await w.render(t, i, r, s), this.chartRenderers.set(t.id, w);
1349
+ const F = new ne(e);
1350
+ await F.render(t, r, o, s), this.chartRenderers.set(t.id, F);
1028
1351
  break;
1029
1352
  }
1030
1353
  case "table": {
1031
- const w = this.opts.onFetchTablePage ? (v, S) => this.opts.onFetchTablePage(t.id, v, S) : void 0;
1032
- this.tableRenderer.render(e, t, i, w);
1354
+ const F = this.opts.onFetchTablePage ? (L, E) => this.opts.onFetchTablePage(t.id, L, E) : void 0;
1355
+ this.tableRenderer.render(e, t, r, F);
1033
1356
  break;
1034
1357
  }
1035
1358
  case "number-card":
1036
- this.cardRenderer.render(e, t, i);
1359
+ this.cardRenderer.render(e, t, r);
1037
1360
  break;
1038
1361
  case "text-heading": {
1039
1362
  if (this.opts.hideText) break;
1040
- const w = ((o = (a = t.properties) == null ? void 0 : a.data) == null ? void 0 : o.dataContent) || ((c = t.properties) == null ? void 0 : c.content) || t.title || "", v = ((d = t.properties) == null ? void 0 : d.styleConfig) || {}, S = this.scToInlineStyle(v), m = this.opts.hideBackground ? {} : this.parseTwColor((u = (b = t.properties) == null ? void 0 : b.color) != null ? u : ""), P = [[
1041
- m.bg ? `background:${m.bg}` : "",
1042
- m.text ? `color:${m.text}` : ""
1043
- ].filter(Boolean).join(";"), S].filter(Boolean).join(";");
1044
- e.innerHTML = `<div class="ds-text-heading" style="${P}">${w}</div>`;
1363
+ const F = ((a = (i = t.properties) == null ? void 0 : i.data) == null ? void 0 : a.dataContent) || ((f = t.properties) == null ? void 0 : f.content) || t.title || "", L = ((h = t.properties) == null ? void 0 : h.styleConfig) || {}, E = this.scToInlineStyle(L), I = this.opts.hideBackground ? {} : this.parseTwColor((m = (v = t.properties) == null ? void 0 : v.color) != null ? m : ""), R = [[
1364
+ I.bg ? `background:${I.bg}` : "",
1365
+ I.text ? `color:${I.text}` : ""
1366
+ ].filter(Boolean).join(";"), E].filter(Boolean).join(";");
1367
+ e.innerHTML = `<div class="ds-text-heading" style="${R}">${F}</div>`;
1045
1368
  break;
1046
1369
  }
1047
1370
  case "text-subheading": {
1048
1371
  if (this.opts.hideText) break;
1049
- const w = ((n = (g = t.properties) == null ? void 0 : g.data) == null ? void 0 : n.dataContent) || ((f = t.properties) == null ? void 0 : f.content) || t.title || "", v = ((p = t.properties) == null ? void 0 : p.styleConfig) || {}, S = this.scToInlineStyle(v), m = this.opts.hideBackground ? {} : this.parseTwColor((x = (l = t.properties) == null ? void 0 : l.color) != null ? x : ""), P = [[
1050
- m.bg ? `background:${m.bg}` : "",
1051
- m.text ? `color:${m.text}` : ""
1052
- ].filter(Boolean).join(";"), S].filter(Boolean).join(";");
1053
- e.innerHTML = `<div class="ds-text-subheading" style="${P}">${w}</div>`;
1372
+ const F = ((n = (p = t.properties) == null ? void 0 : p.data) == null ? void 0 : n.dataContent) || ((g = t.properties) == null ? void 0 : g.content) || t.title || "", L = ((u = t.properties) == null ? void 0 : u.styleConfig) || {}, E = this.scToInlineStyle(L), I = this.opts.hideBackground ? {} : this.parseTwColor((c = (b = t.properties) == null ? void 0 : b.color) != null ? c : ""), R = [[
1373
+ I.bg ? `background:${I.bg}` : "",
1374
+ I.text ? `color:${I.text}` : ""
1375
+ ].filter(Boolean).join(";"), E].filter(Boolean).join(";");
1376
+ e.innerHTML = `<div class="ds-text-subheading" style="${R}">${F}</div>`;
1054
1377
  break;
1055
1378
  }
1056
1379
  case "text-body": {
1057
1380
  if (this.opts.hideText) break;
1058
- const w = ((y = (h = t.properties) == null ? void 0 : h.data) == null ? void 0 : y.dataContent) || ((T = t.properties) == null ? void 0 : T.content) || "", v = ((C = t.properties) == null ? void 0 : C.styleConfig) || {}, S = this.scToInlineStyle(v), m = this.opts.hideBackground ? {} : this.parseTwColor((R = ($ = t.properties) == null ? void 0 : $.color) != null ? R : ""), P = [[
1059
- m.bg ? `background:${m.bg}` : "",
1060
- m.text ? `color:${m.text}` : ""
1061
- ].filter(Boolean).join(";"), S].filter(Boolean).join(";");
1062
- e.innerHTML = `<div class="ds-text-body" style="${P}">${w}</div>`;
1381
+ const F = ((l = (d = t.properties) == null ? void 0 : d.data) == null ? void 0 : l.dataContent) || ((T = t.properties) == null ? void 0 : T.content) || "", L = ((w = t.properties) == null ? void 0 : w.styleConfig) || {}, E = this.scToInlineStyle(L), I = this.opts.hideBackground ? {} : this.parseTwColor((x = (k = t.properties) == null ? void 0 : k.color) != null ? x : ""), R = [[
1382
+ I.bg ? `background:${I.bg}` : "",
1383
+ I.text ? `color:${I.text}` : ""
1384
+ ].filter(Boolean).join(";"), E].filter(Boolean).join(";");
1385
+ e.innerHTML = `<div class="ds-text-body" style="${R}">${F}</div>`;
1063
1386
  break;
1064
1387
  }
1065
1388
  case "text-box": {
1066
1389
  if (this.opts.hideText) break;
1067
- const w = ((L = (I = t.properties) == null ? void 0 : I.data) == null ? void 0 : L.dataContent) || ((F = t.properties) == null ? void 0 : F.content) || "", v = ((U = t.properties) == null ? void 0 : U.styleConfig) || {}, S = this.scToInlineStyle(v), m = this.opts.hideBackground ? {} : this.parseTwColor((_ = (W = t.properties) == null ? void 0 : W.color) != null ? _ : ""), P = [[
1068
- m.bg ? `background:${m.bg}` : "",
1069
- m.text ? `color:${m.text}` : ""
1070
- ].filter(Boolean).join(";"), S].filter(Boolean).join(";");
1071
- e.innerHTML = `<div class="ds-text-box" style="${P}">${w}</div>`;
1390
+ const F = ((y = ($ = t.properties) == null ? void 0 : $.data) == null ? void 0 : y.dataContent) || ((S = t.properties) == null ? void 0 : S.content) || "", L = ((C = t.properties) == null ? void 0 : C.styleConfig) || {}, E = this.scToInlineStyle(L), I = this.opts.hideBackground ? {} : this.parseTwColor((U = (P = t.properties) == null ? void 0 : P.color) != null ? U : ""), R = [[
1391
+ I.bg ? `background:${I.bg}` : "",
1392
+ I.text ? `color:${I.text}` : ""
1393
+ ].filter(Boolean).join(";"), E].filter(Boolean).join(";");
1394
+ e.innerHTML = `<div class="ds-text-box" style="${R}">${F}</div>`;
1072
1395
  break;
1073
1396
  }
1074
1397
  case "text": {
1075
1398
  if (this.opts.hideText) break;
1076
- const w = ((J = (Y = t.properties) == null ? void 0 : Y.data) == null ? void 0 : J.dataContent) || ((V = t.properties) == null ? void 0 : V.content) || "", v = ((X = t.properties) == null ? void 0 : X.styleConfig) || {}, S = this.scToInlineStyle(v), m = this.opts.hideBackground ? {} : this.parseTwColor((Q = (Z = t.properties) == null ? void 0 : Z.color) != null ? Q : ""), P = [[
1077
- m.bg ? `background:${m.bg}` : "",
1078
- m.text ? `color:${m.text}` : ""
1079
- ].filter(Boolean).join(";"), S].filter(Boolean).join(";");
1080
- e.innerHTML = `<div class="ds-text-body" style="${P}">${w}</div>`;
1399
+ const F = ((Y = (W = t.properties) == null ? void 0 : W.data) == null ? void 0 : Y.dataContent) || ((J = t.properties) == null ? void 0 : J.content) || "", L = ((X = t.properties) == null ? void 0 : X.styleConfig) || {}, E = this.scToInlineStyle(L), I = this.opts.hideBackground ? {} : this.parseTwColor((Q = (Z = t.properties) == null ? void 0 : Z.color) != null ? Q : ""), R = [[
1400
+ I.bg ? `background:${I.bg}` : "",
1401
+ I.text ? `color:${I.text}` : ""
1402
+ ].filter(Boolean).join(";"), E].filter(Boolean).join(";");
1403
+ e.innerHTML = `<div class="ds-text-body" style="${R}">${F}</div>`;
1081
1404
  break;
1082
1405
  }
1083
1406
  case "header": {
1084
1407
  if (this.opts.hideHeader) break;
1085
- const w = ((te = (ee = t.properties) == null ? void 0 : ee.data) == null ? void 0 : te.dataContent) || ((se = t.properties) == null ? void 0 : se.content) || t.title || "", v = ((ie = t.properties) == null ? void 0 : ie.styleConfig) || {}, S = !this.opts.hideBackground && v.backgroundColor ? `background:${v.backgroundColor};` : "", m = v.color ? `color:${v.color};` : v.textColor ? `color:${v.textColor};` : "";
1408
+ const F = ((te = (ee = t.properties) == null ? void 0 : ee.data) == null ? void 0 : te.dataContent) || ((se = t.properties) == null ? void 0 : se.content) || t.title || "", L = ((re = t.properties) == null ? void 0 : re.styleConfig) || {}, E = !this.opts.hideBackground && L.backgroundColor ? `background:${L.backgroundColor};` : "", I = L.color ? `color:${L.color};` : L.textColor ? `color:${L.textColor};` : "";
1086
1409
  e.innerHTML = `
1087
- <div class="ds-header-component" style="${S}${m}">
1088
- <div class="ds-header-content">${w}</div>
1410
+ <div class="ds-header-component" style="${E}${I}">
1411
+ <div class="ds-header-content">${F}</div>
1089
1412
  </div>`;
1090
1413
  break;
1091
1414
  }
1092
1415
  case "section": {
1093
- const w = ((re = t.properties) == null ? void 0 : re.styleConfig) || {}, v = !this.opts.hideBackground && w.backgroundColor ? `background:${w.backgroundColor};` : "";
1416
+ const F = ((oe = t.properties) == null ? void 0 : oe.styleConfig) || {}, L = !this.opts.hideBackground && F.backgroundColor ? `background:${F.backgroundColor};` : "";
1094
1417
  e.innerHTML = `
1095
- <div class="ds-section-wrapper" style="${v}">
1418
+ <div class="ds-section-wrapper" style="${L}">
1096
1419
  ${t.title ? `<div class="ds-section-title">${t.title}</div>` : ""}
1097
1420
  </div>`;
1098
1421
  break;
1099
1422
  }
1100
1423
  }
1101
1424
  }
1425
+ // ── Inline-filter funnel button on chart wrappers ────────────────────────
1426
+ attachInlineFilterBtn(e, t) {
1427
+ var a;
1428
+ e.style.overflow = "visible";
1429
+ const s = (a = e.dataset.componentId) != null ? a : "", r = document.createElement("button");
1430
+ r.type = "button", r.className = "ds-comp-filter-btn", r.title = "Filter", r.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
1431
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1432
+ <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>
1433
+ </svg>`;
1434
+ const o = document.createElement("div");
1435
+ o.className = "ds-comp-filter-pop", o.style.display = "none", this.buildInlineFilterPop(o, t, s), r.addEventListener("click", (f) => {
1436
+ f.stopPropagation();
1437
+ const h = o.style.display !== "none";
1438
+ document.querySelectorAll(".ds-comp-filter-pop").forEach((v) => {
1439
+ v.style.display = "none";
1440
+ }), o.style.display = h ? "none" : "";
1441
+ }), document.addEventListener("mousedown", (f) => {
1442
+ e.contains(f.target) || (o.style.display = "none");
1443
+ }), (() => {
1444
+ const f = t.some((h) => {
1445
+ const v = h.applyToField || h.filterId, m = this.activeFilters[v] !== void 0 && this.activeFilters[v] !== "", p = this.activeLocalFilters[h.filterId] !== void 0;
1446
+ return m || p;
1447
+ });
1448
+ r.classList.toggle("ds-comp-filter-btn-active", f);
1449
+ })(), e.appendChild(r), e.appendChild(o);
1450
+ }
1451
+ buildInlineFilterPop(e, t, s) {
1452
+ var g, u, b;
1453
+ const r = (c) => {
1454
+ var T;
1455
+ const d = (this.renderData.components || []).find(
1456
+ (w) => w.type === "inline-filter" && w.id === c.filterId
1457
+ ), l = (T = d == null ? void 0 : d.properties) == null ? void 0 : T.columnMappings;
1458
+ return (l == null ? void 0 : l[s]) || c.applyToField || c.filterId;
1459
+ }, o = (c) => c.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"), i = (c) => c.replace(/"/g, "&quot;").replace(/'/g, "&#39;"), a = [
1460
+ { value: "=", label: "Equals (=)" },
1461
+ { value: "!=", label: "Not Equals (!=)" },
1462
+ { value: "LIKE", label: "Contains" },
1463
+ { value: "NOT LIKE", label: "Not Contains" },
1464
+ { value: "STARTS_WITH", label: "Starts With" },
1465
+ { value: "IN", label: "In (Multiple)" },
1466
+ { value: "NOT IN", label: "Not In" },
1467
+ { value: ">", label: "Greater Than (>)" },
1468
+ { value: ">=", label: "Greater or Equal (>=)" },
1469
+ { value: "<", label: "Less Than (<)" },
1470
+ { value: "<=", label: "Less or Equal (<=)" },
1471
+ { value: "IS NULL", label: "Is Empty" },
1472
+ { value: "IS NOT NULL", label: "Is Not Empty" }
1473
+ ], f = /* @__PURE__ */ new Map();
1474
+ for (const c of t) {
1475
+ const d = this.activeLocalFilters[c.filterId], l = (g = d == null ? void 0 : d.value) != null ? g : this.activeFilters[r(c)], T = l ? Array.isArray(l) ? l.map(String) : [String(l)] : [], w = (d == null ? void 0 : d.operator) || c.filterOperator || "=";
1476
+ f.set(c.filterId, { pendingValues: [...T], operator: w, search: "" });
1477
+ }
1478
+ const h = (c) => `<select class="ds-fp-op-select">
1479
+ ${a.map(
1480
+ (d) => `<option value="${i(d.value)}"${d.value === c ? " selected" : ""}>${d.label}</option>`
1481
+ ).join("")}
1482
+ </select>`, v = (c, d) => {
1483
+ const l = c.options || [];
1484
+ if (!l.length)
1485
+ return '<div class="ds-fp-opts-msg"><span class="ds-dd-spinner"></span> Loading…</div>';
1486
+ const T = d.search.toLowerCase(), w = l.filter(
1487
+ (k) => (typeof k == "string" ? k : k.label).toLowerCase().includes(T)
1488
+ );
1489
+ return w.length ? w.map((k) => {
1490
+ const x = typeof k == "string" ? k : k.value, $ = typeof k == "string" ? k : k.label, y = d.pendingValues.includes(x);
1491
+ return `<label class="ds-fp-opt${y ? " ds-fp-opt-on" : ""}" data-val="${i(x)}">
1492
+ <span class="ds-fp-cb${y ? " ds-fp-cb-on" : ""}">
1493
+ ${y ? `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"
1494
+ stroke-linecap="round" stroke-linejoin="round">
1495
+ <polyline points="20 6 9 17 4 12"/>
1496
+ </svg>` : ""}
1497
+ </span>
1498
+ <span class="ds-fp-opt-lbl">${o($)}</span>
1499
+ </label>`;
1500
+ }).join("") : '<div class="ds-fp-opts-msg">No matches</div>';
1501
+ }, m = (c) => {
1502
+ const d = f.get(c.filterId);
1503
+ return `
1504
+ <div class="ds-fp-item ds-fp-item-expanded" data-filter-id="${i(c.filterId)}">
1505
+ <div class="ds-fp-item-hd">
1506
+ <span class="ds-fp-item-name">${o(c.label)}</span>
1507
+ <svg class="ds-fp-chevron" style="transform:rotate(180deg)"
1508
+ viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
1509
+ stroke-linecap="round" stroke-linejoin="round">
1510
+ <polyline points="6 9 12 15 18 9"/>
1511
+ </svg>
1512
+ </div>
1513
+ <div class="ds-fp-item-body">
1514
+ <div class="ds-fp-op-row">
1515
+ <span class="ds-fp-op-lbl">Operator</span>
1516
+ ${h(d.operator)}
1517
+ </div>
1518
+ <div class="ds-fp-ms">
1519
+ ${d.pendingValues.length ? `<div class="ds-fp-chips-row">
1520
+ ${d.pendingValues.map(
1521
+ (l) => `<span class="ds-fp-chip">${o(l)}<button type="button" class="ds-fp-chip-x" data-val="${i(l)}">✕</button></span>`
1522
+ ).join("")}
1523
+ </div>` : ""}
1524
+ <div class="ds-fp-search-wrap">
1525
+ <input type="text" class="ds-fp-ms-search"
1526
+ placeholder="Search ${i(c.label)}…"
1527
+ value="${i(d.search)}"/>
1528
+ <svg class="ds-fp-search-caret" viewBox="0 0 24 24" fill="none" stroke="currentColor"
1529
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1530
+ <polyline points="18 15 12 9 6 15"/>
1531
+ </svg>
1532
+ </div>
1533
+ <div class="ds-fp-opts" data-filter-id="${i(c.filterId)}">
1534
+ ${v(c, d)}
1535
+ </div>
1536
+ </div>
1537
+ <button type="button" class="ds-fp-apply" data-apply-id="${i(c.filterId)}">✓ Apply Filter</button>
1538
+ </div>
1539
+ </div>`;
1540
+ }, p = t.filter((c) => {
1541
+ if (this.activeLocalFilters[c.filterId] !== void 0) return !0;
1542
+ const d = this.activeFilters[r(c)];
1543
+ return d !== void 0 && d !== "" && !(Array.isArray(d) && d.length === 0);
1544
+ }).length;
1545
+ e.innerHTML = `
1546
+ <div class="ds-fp-panel ds-fp-panel-pop">
1547
+ <div class="ds-fp-panel-hd">
1548
+ <div class="ds-fp-panel-title">
1549
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
1550
+ stroke-linecap="round" stroke-linejoin="round">
1551
+ <line x1="3" y1="6" x2="21" y2="6"/>
1552
+ <line x1="3" y1="12" x2="21" y2="12"/>
1553
+ <line x1="3" y1="18" x2="21" y2="18"/>
1554
+ </svg>
1555
+ <span>Filters</span>
1556
+ </div>
1557
+ <button type="button" class="ds-fp-close-btn ds-pop-close">
1558
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
1559
+ stroke-linecap="round" stroke-linejoin="round">
1560
+ <line x1="18" y1="6" x2="6" y2="18"/>
1561
+ <line x1="6" y1="6" x2="18" y2="18"/>
1562
+ </svg>
1563
+ </button>
1564
+ </div>
1565
+ <div class="ds-fp-reset-section" style="display:${p ? "" : "none"}">
1566
+ <button type="button" class="ds-fp-reset-all ds-pop-reset">
1567
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
1568
+ stroke-linecap="round" stroke-linejoin="round">
1569
+ <polyline points="1 4 1 10 7 10"/>
1570
+ <path d="M3.51 15a9 9 0 1 0 .49-3.5"/>
1571
+ </svg>
1572
+ Reset All Filters
1573
+ </button>
1574
+ </div>
1575
+ <div class="ds-fp-items">
1576
+ ${t.map(m).join("")}
1577
+ </div>
1578
+ </div>`, (u = e.querySelector(".ds-pop-close")) == null || u.addEventListener("click", () => {
1579
+ e.style.display = "none";
1580
+ }), (b = e.querySelector(".ds-pop-reset")) == null || b.addEventListener("click", () => {
1581
+ var c, d;
1582
+ t.forEach((l) => {
1583
+ delete this.activeLocalFilters[l.filterId];
1584
+ }), (d = (c = this.opts).onFilterChange) == null || d.call(c, this.activeFilters), this.opts.onTabSwitch(this.activePageId, this.activeTabId), e.style.display = "none";
1585
+ });
1586
+ const n = (c, d, l) => {
1587
+ const T = t.find((x) => x.filterId === c), w = d.querySelector(".ds-fp-ms");
1588
+ if (w) {
1589
+ let x = w.querySelector(".ds-fp-chips-row");
1590
+ if (l.pendingValues.length) {
1591
+ const $ = l.pendingValues.map(
1592
+ (y) => `<span class="ds-fp-chip">${o(y)}<button type="button" class="ds-fp-chip-x" data-val="${i(y)}">✕</button></span>`
1593
+ ).join("");
1594
+ x ? x.innerHTML = $ : (x = document.createElement("div"), x.className = "ds-fp-chips-row", x.innerHTML = $, w.insertBefore(x, w.querySelector(".ds-fp-search-wrap"))), x.querySelectorAll(".ds-fp-chip-x").forEach((y) => {
1595
+ y.addEventListener("click", (S) => {
1596
+ S.stopPropagation(), l.pendingValues = l.pendingValues.filter((C) => {
1597
+ var P;
1598
+ return C !== ((P = y.dataset.val) != null ? P : "");
1599
+ }), n(c, d, l);
1600
+ });
1601
+ });
1602
+ } else
1603
+ x == null || x.remove();
1604
+ }
1605
+ const k = d.querySelector(`.ds-fp-opts[data-filter-id="${c}"]`);
1606
+ k && (k.innerHTML = v(T, l), k.querySelectorAll(".ds-fp-opt").forEach((x) => {
1607
+ x.addEventListener("click", () => {
1608
+ var y;
1609
+ const $ = (y = x.dataset.val) != null ? y : "";
1610
+ l.pendingValues.includes($) ? l.pendingValues = l.pendingValues.filter((S) => S !== $) : l.pendingValues = [...l.pendingValues, $], n(c, d, l);
1611
+ });
1612
+ }));
1613
+ };
1614
+ t.forEach((c) => {
1615
+ var w, k, x, $;
1616
+ const d = f.get(c.filterId), l = e.querySelector(`.ds-fp-item[data-filter-id="${c.filterId}"]`);
1617
+ if (!l) return;
1618
+ (w = l.querySelector(".ds-fp-op-select")) == null || w.addEventListener("change", (y) => {
1619
+ d.operator = y.target.value;
1620
+ });
1621
+ const T = l.querySelector(".ds-fp-ms-search");
1622
+ T && (T.addEventListener("input", () => {
1623
+ d.search = T.value, n(c.filterId, l, d);
1624
+ }), (k = l.querySelector(".ds-fp-search-caret")) == null || k.addEventListener("click", () => {
1625
+ const y = l.querySelector(".ds-fp-opts");
1626
+ y && (y.style.display = y.style.display === "none" ? "" : "none");
1627
+ })), l.querySelectorAll(".ds-fp-chip-x").forEach((y) => {
1628
+ y.addEventListener("click", (S) => {
1629
+ S.stopPropagation(), d.pendingValues = d.pendingValues.filter((C) => {
1630
+ var P;
1631
+ return C !== ((P = y.dataset.val) != null ? P : "");
1632
+ }), n(c.filterId, l, d);
1633
+ });
1634
+ }), l.querySelectorAll(".ds-fp-opt").forEach((y) => {
1635
+ y.addEventListener("click", () => {
1636
+ var C;
1637
+ const S = (C = y.dataset.val) != null ? C : "";
1638
+ d.pendingValues.includes(S) ? d.pendingValues = d.pendingValues.filter((P) => P !== S) : d.pendingValues = [...d.pendingValues, S], n(c.filterId, l, d);
1639
+ });
1640
+ }), (x = l.querySelector(`.ds-fp-apply[data-apply-id="${c.filterId}"]`)) == null || x.addEventListener("click", () => {
1641
+ var S, C, P;
1642
+ const y = d.pendingValues.length > 1 ? [...d.pendingValues] : (S = d.pendingValues[0]) != null ? S : "";
1643
+ !y || Array.isArray(y) && !y.length ? delete this.activeLocalFilters[c.filterId] : this.activeLocalFilters[c.filterId] = { value: y, operator: d.operator || "=" }, (P = (C = this.opts).onFilterChange) == null || P.call(C, this.activeFilters), this.opts.onTabSwitch(this.activePageId, this.activeTabId), e.style.display = "none";
1644
+ }), !(($ = c.options) != null && $.length) && this.opts.onFetchFilterOptions && this.opts.onFetchFilterOptions(c.filterId).then((y) => {
1645
+ l.querySelector(`.ds-fp-opts[data-filter-id="${c.filterId}"]`) && (c.options = y.map((C) => typeof C == "string" ? C : C.value), n(c.filterId, l, d));
1646
+ }).catch(() => {
1647
+ });
1648
+ });
1649
+ }
1102
1650
  // ── Spinner ───────────────────────────────────────────────────────────────
1103
1651
  showTabSpinner() {
1104
1652
  const e = this.root.querySelector("#ds-tab-loading"), t = this.root.querySelector("#ds-grid");
@@ -1116,8 +1664,8 @@ const H = class H {
1116
1664
  * (so it can support CSS gradients via `background` shorthand).
1117
1665
  */
1118
1666
  scToInlineStyle(e) {
1119
- const t = /* @__PURE__ */ new Set(["backgroundColor"]), s = (i) => i.replace(/([A-Z])/g, "-$1").toLowerCase();
1120
- return Object.entries(e).filter(([i, r]) => !t.has(i) && r != null && r !== "").map(([i, r]) => `${s(i)}:${r}`).join(";");
1667
+ const t = /* @__PURE__ */ new Set(["backgroundColor"]), s = (r) => r.replace(/([A-Z])/g, "-$1").toLowerCase();
1668
+ return Object.entries(e).filter(([r, o]) => !t.has(r) && o != null && o !== "").map(([r, o]) => `${s(r)}:${o}`).join(";");
1121
1669
  }
1122
1670
  /**
1123
1671
  * Parse a Tailwind utility class string (e.g. "bg-violet-100 text-violet-600")
@@ -1149,10 +1697,10 @@ const H = class H {
1149
1697
  t.text = "#000000";
1150
1698
  continue;
1151
1699
  }
1152
- const i = /^(bg|text)-([a-z]+)-(\d+)$/.exec(s);
1153
- if (!i) continue;
1154
- const r = H.TW_PALETTE[i[2]], a = r == null ? void 0 : r[Number(i[3])];
1155
- a && (i[1] === "bg" && (t.bg = a), i[1] === "text" && (t.text = a));
1700
+ const r = /^(bg|text)-([a-z]+)-(\d+)$/.exec(s);
1701
+ if (!r) continue;
1702
+ const o = N.TW_PALETTE[r[2]], i = o == null ? void 0 : o[Number(r[3])];
1703
+ i && (r[1] === "bg" && (t.bg = i), r[1] === "text" && (t.text = i));
1156
1704
  }
1157
1705
  return t;
1158
1706
  }
@@ -1164,24 +1712,24 @@ const H = class H {
1164
1712
  return this.tooltipEl;
1165
1713
  }
1166
1714
  getComponentDescription(e) {
1167
- var t, s, i, r;
1715
+ var t, s, r, o;
1168
1716
  if ((t = e.properties) != null && t.description) return String(e.properties.description);
1169
1717
  try {
1170
- const a = (i = (s = e.properties) == null ? void 0 : s.data) == null ? void 0 : i.dataContent;
1171
- if (a) {
1172
- const o = typeof a == "string" ? JSON.parse(a) : a;
1173
- return (o == null ? void 0 : o.description) || ((r = o == null ? void 0 : o.config) == null ? void 0 : r.description) || "";
1718
+ const i = (r = (s = e.properties) == null ? void 0 : s.data) == null ? void 0 : r.dataContent;
1719
+ if (i) {
1720
+ const a = typeof i == "string" ? JSON.parse(i) : i;
1721
+ return (a == null ? void 0 : a.description) || ((o = a == null ? void 0 : a.config) == null ? void 0 : o.description) || "";
1174
1722
  }
1175
- } catch (a) {
1723
+ } catch (i) {
1176
1724
  }
1177
1725
  return "";
1178
1726
  }
1179
1727
  getTabsForPage(e) {
1180
1728
  var t, s;
1181
- return (s = (t = this.renderData.dashboard.pages.find((i) => i.pageId === e)) == null ? void 0 : t.tabs) != null ? s : [];
1729
+ return (s = (t = this.renderData.dashboard.pages.find((r) => r.pageId === e)) == null ? void 0 : t.tabs) != null ? s : [];
1182
1730
  }
1183
1731
  };
1184
- H.TW_PALETTE = {
1732
+ N.TW_PALETTE = {
1185
1733
  slate: { 50: "#f8fafc", 100: "#f1f5f9", 200: "#e2e8f0", 300: "#cbd5e1", 400: "#94a3b8", 500: "#64748b", 600: "#475569", 700: "#334155", 800: "#1e293b", 900: "#0f172a" },
1186
1734
  gray: { 50: "#f9fafb", 100: "#f3f4f6", 200: "#e5e7eb", 300: "#d1d5db", 400: "#9ca3af", 500: "#6b7280", 600: "#4b5563", 700: "#374151", 800: "#1f2937", 900: "#111827" },
1187
1735
  zinc: { 50: "#fafafa", 100: "#f4f4f5", 200: "#e4e4e7", 300: "#d4d4d8", 400: "#a1a1aa", 500: "#71717a", 600: "#52525b", 700: "#3f3f46", 800: "#27272a", 900: "#18181b" },
@@ -1205,8 +1753,8 @@ H.TW_PALETTE = {
1205
1753
  pink: { 50: "#fdf2f8", 100: "#fce7f3", 200: "#fbcfe8", 300: "#f9a8d4", 400: "#f472b6", 500: "#ec4899", 600: "#db2777", 700: "#be185d", 800: "#9d174d", 900: "#831843" },
1206
1754
  rose: { 50: "#fff1f2", 100: "#ffe4e6", 200: "#fecdd3", 300: "#fda4af", 400: "#fb7185", 500: "#f43f5e", 600: "#e11d48", 700: "#be123c", 800: "#9f1239", 900: "#881337" }
1207
1755
  };
1208
- let D = H;
1209
- class he {
1756
+ let j = N;
1757
+ class pe {
1210
1758
  constructor(e, t) {
1211
1759
  this.chartRenderer = null, this.tableRenderer = new le(), this.cardRenderer = new ce(), this.root = e, this.theme = t;
1212
1760
  }
@@ -1219,8 +1767,8 @@ class he {
1219
1767
  </div>`;
1220
1768
  return;
1221
1769
  }
1222
- const i = e.data[s.id] || [];
1223
- this.renderComponent(s, i), t == null || t();
1770
+ const r = e.data[s.id] || [];
1771
+ this.renderComponent(s, r), t == null || t();
1224
1772
  }
1225
1773
  update(e) {
1226
1774
  const t = e.components[0];
@@ -1267,12 +1815,12 @@ class he {
1267
1815
  }
1268
1816
  }
1269
1817
  }
1270
- let oe = !1;
1271
- function B() {
1272
- if (!(oe || typeof document == "undefined")) {
1273
- oe = !0;
1818
+ let ae = !1;
1819
+ function K() {
1820
+ if (!(ae || typeof document == "undefined")) {
1821
+ ae = !0;
1274
1822
  try {
1275
- const k = `/* ─────────────────────────────────────────────────────────────────────────────
1823
+ const A = `/* ─────────────────────────────────────────────────────────────────────────────
1276
1824
  Deepspot SDK — Base Embed Styles
1277
1825
  Injected once into the host page's <head> by the SDK.
1278
1826
  All selectors are scoped under .ds-embed-* to avoid leaking into host styles.
@@ -2034,121 +2582,1788 @@ function B() {
2034
2582
  border-bottom-color: #334155;
2035
2583
  }
2036
2584
 
2037
- /* ── v2: Inline filter (selection-filter placed in-grid) ───────────────────── */
2585
+ /* ── Filter panel (publish-page style: toggle + collapsible items + Apply) ─── */
2038
2586
 
2039
- .ds-inline-filter {
2040
- width: 100%;
2041
- height: 100%;
2042
- display: flex;
2043
- flex-direction: column;
2044
- justify-content: center;
2045
- gap: 4px;
2046
- padding: 6px 10px;
2587
+ .ds-fp {
2588
+ border-bottom: 1px solid #e5e7eb;
2589
+ background: inherit;
2047
2590
  }
2048
2591
 
2049
- .ds-inline-filter-select,
2050
- .ds-inline-filter-input {
2051
- width: 100%;
2052
- height: 34px;
2053
- padding: 0 10px;
2054
- border: 1px solid #d1d5db;
2055
- border-radius: 6px;
2056
- font-size: 13px;
2057
- background: #ffffff;
2058
- color: #111827;
2059
- cursor: pointer;
2060
- outline: none;
2061
- transition: border-color 0.15s, box-shadow 0.15s;
2592
+ .ds-theme-dark .ds-fp {
2593
+ border-bottom-color: #1e293b;
2062
2594
  }
2063
2595
 
2064
- .ds-inline-filter-select:focus,
2065
- .ds-inline-filter-input:focus {
2066
- border-color: #6366f1;
2067
- box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
2596
+ /* ── Toggle bar ────────────────────────────────────────────────────────────── */
2597
+ .ds-fp-bar {
2598
+ display: flex;
2599
+ align-items: center;
2600
+ gap: 12px;
2601
+ padding: 8px 16px;
2068
2602
  }
2069
2603
 
2070
- .ds-theme-dark .ds-inline-filter-select,
2071
- .ds-theme-dark .ds-inline-filter-input {
2072
- background: #1e293b;
2073
- border-color: #334155;
2074
- color: #f1f5f9;
2604
+ /* ── Panel header ──────────────────────────────────────────────────────────── */
2605
+ .ds-fp-panel-hd {
2606
+ display: flex;
2607
+ align-items: center;
2608
+ justify-content: space-between;
2609
+ padding: 14px 16px 12px;
2610
+ border-bottom: 1px solid #e5e7eb;
2075
2611
  }
2076
2612
 
2077
- /* ── Export toolbar ────────────────────────────────────────────────────────── */
2078
- .ds-toolbar {
2613
+ .ds-theme-dark .ds-fp-panel-hd {
2614
+ border-bottom-color: #334155;
2615
+ }
2616
+
2617
+ .ds-fp-panel-title {
2079
2618
  display: flex;
2080
- justify-content: flex-end;
2081
- padding: 8px 16px 0;
2619
+ align-items: center;
2082
2620
  gap: 8px;
2621
+ font-size: 14px;
2622
+ font-weight: 600;
2623
+ color: #111827;
2083
2624
  }
2084
2625
 
2085
- .ds-toolbar-btn {
2086
- height: 30px;
2087
- padding: 0 12px;
2088
- border: 1px solid #d1d5db;
2089
- border-radius: 6px;
2090
- font-size: 12px;
2091
- font-weight: 500;
2092
- background: #ffffff;
2093
- color: #374151;
2094
- cursor: pointer;
2626
+ .ds-theme-dark .ds-fp-panel-title {
2627
+ color: #f1f5f9;
2628
+ }
2629
+
2630
+ .ds-fp-panel-title svg {
2631
+ width: 16px;
2632
+ height: 16px;
2633
+ color: #6b7280;
2634
+ flex-shrink: 0;
2635
+ }
2636
+
2637
+ .ds-fp-close-btn {
2638
+ width: 28px;
2639
+ height: 28px;
2095
2640
  display: flex;
2096
2641
  align-items: center;
2097
- gap: 5px;
2098
- transition: background 0.15s, border-color 0.15s;
2642
+ justify-content: center;
2643
+ border: 1px solid #e5e7eb;
2644
+ border-radius: 6px;
2645
+ background: transparent;
2646
+ color: #6b7280;
2647
+ cursor: pointer;
2648
+ padding: 0;
2649
+ transition: border-color 0.15s, color 0.15s, background 0.15s;
2650
+ flex-shrink: 0;
2099
2651
  }
2100
2652
 
2101
- .ds-toolbar-btn:hover {
2102
- background: #f9fafb;
2103
- border-color: #9ca3af;
2653
+ .ds-fp-close-btn svg {
2654
+ width: 14px;
2655
+ height: 14px;
2104
2656
  }
2105
2657
 
2106
- .ds-theme-dark .ds-toolbar-btn {
2107
- background: #1e293b;
2658
+ .ds-fp-close-btn:hover {
2659
+ border-color: #6366f1;
2660
+ color: #6366f1;
2661
+ background: #eef2ff;
2662
+ }
2663
+
2664
+ .ds-theme-dark .ds-fp-close-btn {
2108
2665
  border-color: #334155;
2109
- color: #e2e8f0;
2666
+ color: #94a3b8;
2110
2667
  }
2111
2668
 
2112
- .ds-theme-dark .ds-toolbar-btn:hover {
2113
- background: #0f172a;
2669
+ /* ── Reset All section (inside panel) ─────────────────────────────────────── */
2670
+ .ds-fp-reset-section {
2671
+ padding: 10px 16px;
2672
+ border-bottom: 1px solid #f3f4f6;
2114
2673
  }
2115
- `, e = document.createElement("style");
2116
- e.id = "deepspot-sdk-styles", e.textContent = k, document.head.appendChild(e);
2117
- } catch (k) {
2118
- }
2119
- }
2674
+
2675
+ .ds-theme-dark .ds-fp-reset-section {
2676
+ border-bottom-color: #1e293b;
2120
2677
  }
2121
- function de(k) {
2122
- if (typeof k == "string") {
2123
- const e = document.querySelector(k);
2124
- if (!e) throw new Error(`Deepspot SDK: container "${k}" not found in DOM`);
2678
+
2679
+ .ds-fp-reset-all {
2680
+ display: inline-flex;
2681
+ align-items: center;
2682
+ gap: 6px;
2683
+ border: none;
2684
+ background: transparent;
2685
+ color: #6366f1;
2686
+ font-size: 13px;
2687
+ font-weight: 500;
2688
+ cursor: pointer;
2689
+ padding: 0;
2690
+ transition: color 0.15s;
2691
+ }
2692
+
2693
+ .ds-fp-reset-all svg {
2694
+ width: 13px;
2695
+ height: 13px;
2696
+ }
2697
+
2698
+ .ds-fp-reset-all:hover {
2699
+ color: #4338ca;
2700
+ }
2701
+
2702
+ .ds-theme-dark .ds-fp-reset-all {
2703
+ color: #818cf8;
2704
+ }
2705
+
2706
+ .ds-fp-toggle {
2707
+ display: flex;
2708
+ align-items: center;
2709
+ gap: 6px;
2710
+ padding: 6px 12px;
2711
+ border: 1px solid #d1d5db;
2712
+ border-radius: 8px;
2713
+ background: #ffffff;
2714
+ color: #374151;
2715
+ font-size: 13px;
2716
+ font-weight: 500;
2717
+ cursor: pointer;
2718
+ transition: border-color 0.15s, background 0.15s;
2719
+ }
2720
+
2721
+ .ds-fp-toggle:hover {
2722
+ border-color: #6366f1;
2723
+ background: #f5f3ff;
2724
+ }
2725
+
2726
+ .ds-theme-dark .ds-fp-toggle {
2727
+ background: #1e293b;
2728
+ border-color: #334155;
2729
+ color: #e2e8f0;
2730
+ }
2731
+
2732
+ .ds-fp-funnel {
2733
+ width: 13px;
2734
+ height: 13px;
2735
+ flex-shrink: 0;
2736
+ }
2737
+
2738
+ .ds-fp-badge {
2739
+ display: inline-flex;
2740
+ align-items: center;
2741
+ justify-content: center;
2742
+ min-width: 18px;
2743
+ height: 18px;
2744
+ padding: 0 5px;
2745
+ border-radius: 9px;
2746
+ background: #6366f1;
2747
+ color: #fff;
2748
+ font-size: 11px;
2749
+ font-weight: 700;
2750
+ line-height: 1;
2751
+ }
2752
+
2753
+ .ds-fp-reset-all {
2754
+ border: none;
2755
+ background: transparent;
2756
+ color: #6366f1;
2757
+ font-size: 12px;
2758
+ font-weight: 500;
2759
+ cursor: pointer;
2760
+ padding: 0;
2761
+ text-decoration: underline;
2762
+ transition: color 0.15s;
2763
+ }
2764
+
2765
+ .ds-fp-reset-all:hover {
2766
+ color: #4338ca;
2767
+ }
2768
+
2769
+ .ds-theme-dark .ds-fp-reset-all {
2770
+ color: #818cf8;
2771
+ }
2772
+
2773
+ /* ── Expandable panel ──────────────────────────────────────────────────────── */
2774
+ .ds-fp-panel {
2775
+ padding: 0 16px 10px;
2776
+ }
2777
+
2778
+ .ds-fp-items {
2779
+ display: flex;
2780
+ flex-direction: column;
2781
+ gap: 4px;
2782
+ }
2783
+
2784
+ /* ── Filter item ───────────────────────────────────────────────────────────── */
2785
+ .ds-fp-item {
2786
+ border: 1px solid #e5e7eb;
2787
+ border-radius: 8px;
2788
+ overflow: hidden;
2789
+ background: #fafafa;
2790
+ }
2791
+
2792
+ .ds-theme-dark .ds-fp-item {
2793
+ border-color: #334155;
2794
+ background: #1e293b;
2795
+ }
2796
+
2797
+ .ds-fp-item-hd {
2798
+ display: flex;
2799
+ align-items: center;
2800
+ gap: 8px;
2801
+ padding: 9px 12px;
2802
+ cursor: pointer;
2803
+ user-select: none;
2804
+ transition: background 0.12s;
2805
+ }
2806
+
2807
+ .ds-fp-item-hd:hover {
2808
+ background: #f0f0ff;
2809
+ }
2810
+
2811
+ .ds-theme-dark .ds-fp-item-hd:hover {
2812
+ background: #0f172a;
2813
+ }
2814
+
2815
+ .ds-fp-item-name {
2816
+ flex: 1;
2817
+ font-size: 13px;
2818
+ font-weight: 600;
2819
+ color: #374151;
2820
+ }
2821
+
2822
+ .ds-theme-dark .ds-fp-item-name {
2823
+ color: #e2e8f0;
2824
+ }
2825
+
2826
+ .ds-fp-val-badge {
2827
+ font-size: 11px;
2828
+ font-weight: 600;
2829
+ padding: 2px 7px;
2830
+ border-radius: 10px;
2831
+ background: #e0e7ff;
2832
+ color: #4338ca;
2833
+ white-space: nowrap;
2834
+ max-width: 120px;
2835
+ overflow: hidden;
2836
+ text-overflow: ellipsis;
2837
+ }
2838
+
2839
+ .ds-theme-dark .ds-fp-val-badge {
2840
+ background: #312e81;
2841
+ color: #a5b4fc;
2842
+ }
2843
+
2844
+ .ds-fp-item-clear {
2845
+ border: none;
2846
+ background: transparent;
2847
+ color: #9ca3af;
2848
+ cursor: pointer;
2849
+ padding: 2px;
2850
+ line-height: 1;
2851
+ flex-shrink: 0;
2852
+ transition: color 0.12s;
2853
+ display: flex;
2854
+ align-items: center;
2855
+ }
2856
+
2857
+ .ds-fp-item-clear svg {
2858
+ width: 13px;
2859
+ height: 13px;
2860
+ }
2861
+
2862
+ .ds-fp-item-clear:hover {
2863
+ color: #6366f1;
2864
+ }
2865
+
2866
+ .ds-fp-chevron {
2867
+ width: 14px;
2868
+ height: 14px;
2869
+ color: #9ca3af;
2870
+ flex-shrink: 0;
2871
+ transition: transform 0.2s ease;
2872
+ }
2873
+
2874
+ /* Indigo border + highlight when expanded */
2875
+ .ds-fp-item-expanded,
2876
+ .ds-fp-item:has(.ds-fp-item-body) {
2877
+ border-color: #6366f1;
2878
+ background: #fafafe;
2879
+ }
2880
+
2881
+ .ds-theme-dark .ds-fp-item-expanded,
2882
+ .ds-theme-dark .ds-fp-item:has(.ds-fp-item-body) {
2883
+ border-color: #6366f1;
2884
+ background: #1e1e3a;
2885
+ }
2886
+
2887
+ /* ── Item body (expanded content) ──────────────────────────────────────────── */
2888
+ .ds-fp-item-body {
2889
+ padding: 4px 12px 12px;
2890
+ display: flex;
2891
+ flex-direction: column;
2892
+ gap: 8px;
2893
+ border-top: 1px solid #e5e7eb;
2894
+ }
2895
+
2896
+ .ds-theme-dark .ds-fp-item-body {
2897
+ border-top-color: #334155;
2898
+ }
2899
+
2900
+ /* ── Operator row ──────────────────────────────────────────────────────────── */
2901
+ .ds-fp-op-row {
2902
+ display: flex;
2903
+ align-items: center;
2904
+ gap: 8px;
2905
+ }
2906
+
2907
+ .ds-fp-op-lbl {
2908
+ font-size: 11px;
2909
+ font-weight: 600;
2910
+ text-transform: uppercase;
2911
+ letter-spacing: 0.04em;
2912
+ color: #9ca3af;
2913
+ white-space: nowrap;
2914
+ flex-shrink: 0;
2915
+ }
2916
+
2917
+ .ds-fp-op-select {
2918
+ flex: 1;
2919
+ height: 30px;
2920
+ padding: 0 8px;
2921
+ border: 1px solid #d1d5db;
2922
+ border-radius: 6px;
2923
+ font-size: 12px;
2924
+ background: #fff;
2925
+ color: #374151;
2926
+ cursor: pointer;
2927
+ outline: none;
2928
+ transition: border-color 0.15s;
2929
+ }
2930
+
2931
+ .ds-fp-op-select:focus {
2932
+ border-color: #6366f1;
2933
+ box-shadow: 0 0 0 2px rgba(99,102,241,0.15);
2934
+ }
2935
+
2936
+ .ds-theme-dark .ds-fp-op-select {
2937
+ background: #0f172a;
2938
+ border-color: #334155;
2939
+ color: #e2e8f0;
2940
+ }
2941
+
2942
+ /* ── Search wrap (input + caret button) ────────────────────────────────────── */
2943
+ .ds-fp-search-wrap {
2944
+ display: flex;
2945
+ align-items: center;
2946
+ border: 1px solid #6366f1;
2947
+ border-radius: 8px;
2948
+ background: #fff;
2949
+ overflow: hidden;
2950
+ transition: box-shadow 0.15s;
2951
+ }
2952
+
2953
+ .ds-fp-search-wrap:focus-within {
2954
+ box-shadow: 0 0 0 3px rgba(99,102,241,0.15);
2955
+ }
2956
+
2957
+ .ds-theme-dark .ds-fp-search-wrap {
2958
+ background: #0f172a;
2959
+ border-color: #6366f1;
2960
+ }
2961
+
2962
+ .ds-fp-ms-search {
2963
+ flex: 1;
2964
+ height: 36px;
2965
+ padding: 0 10px;
2966
+ border: none;
2967
+ outline: none;
2968
+ font-size: 13px;
2969
+ background: transparent;
2970
+ color: #374151;
2971
+ }
2972
+
2973
+ .ds-theme-dark .ds-fp-ms-search {
2974
+ color: #e2e8f0;
2975
+ }
2976
+
2977
+ .ds-fp-ms-search::placeholder {
2978
+ color: #9ca3af;
2979
+ }
2980
+
2981
+ .ds-fp-search-caret {
2982
+ width: 32px;
2983
+ height: 36px;
2984
+ display: flex;
2985
+ align-items: center;
2986
+ justify-content: center;
2987
+ border: none;
2988
+ border-left: 1px solid #e5e7eb;
2989
+ background: transparent;
2990
+ color: #6b7280;
2991
+ cursor: pointer;
2992
+ padding: 0;
2993
+ flex-shrink: 0;
2994
+ transition: color 0.12s, background 0.12s;
2995
+ }
2996
+
2997
+ .ds-fp-search-caret:hover {
2998
+ color: #6366f1;
2999
+ background: #eef2ff;
3000
+ }
3001
+
3002
+ .ds-theme-dark .ds-fp-search-caret {
3003
+ border-left-color: #334155;
3004
+ }
3005
+
3006
+ /* ── Multi-select container ────────────────────────────────────────────────── */
3007
+ .ds-fp-ms {
3008
+ border: 1px solid #e5e7eb;
3009
+ border-radius: 8px;
3010
+ overflow: hidden;
3011
+ }
3012
+
3013
+ .ds-theme-dark .ds-fp-ms {
3014
+ border-color: #334155;
3015
+ }
3016
+
3017
+ /* Chips row (shown above search when values selected) */
3018
+ .ds-fp-chips-row {
3019
+ display: flex;
3020
+ flex-wrap: wrap;
3021
+ align-items: center;
3022
+ gap: 4px;
3023
+ padding: 6px 0 4px;
3024
+ }
3025
+
3026
+ .ds-fp-chip {
3027
+ display: inline-flex;
3028
+ align-items: center;
3029
+ gap: 4px;
3030
+ padding: 2px 8px 2px 8px;
3031
+ border-radius: 12px;
3032
+ background: #e0e7ff;
3033
+ color: #4338ca;
3034
+ font-size: 11px;
3035
+ font-weight: 600;
3036
+ white-space: nowrap;
3037
+ }
3038
+
3039
+ .ds-theme-dark .ds-fp-chip {
3040
+ background: #312e81;
3041
+ color: #a5b4fc;
3042
+ }
3043
+
3044
+ .ds-fp-chip-x {
3045
+ border: none;
3046
+ background: transparent;
3047
+ color: inherit;
3048
+ font-size: 10px;
3049
+ cursor: pointer;
3050
+ padding: 0;
3051
+ line-height: 1;
3052
+ opacity: 0.7;
3053
+ transition: opacity 0.1s;
3054
+ }
3055
+
3056
+ .ds-fp-chip-x:hover {
3057
+ opacity: 1;
3058
+ }
3059
+
3060
+ /* ds-fp-ms-search styles live in .ds-fp-search-wrap above */
3061
+
3062
+ /* Options list */
3063
+ .ds-fp-opts {
3064
+ max-height: 180px;
3065
+ overflow-y: auto;
3066
+ }
3067
+
3068
+ .ds-fp-opt {
3069
+ display: flex;
3070
+ align-items: center;
3071
+ gap: 8px;
3072
+ padding: 7px 10px;
3073
+ cursor: pointer;
3074
+ transition: background 0.1s;
3075
+ user-select: none;
3076
+ }
3077
+
3078
+ .ds-fp-opt:hover {
3079
+ background: #f0f0ff;
3080
+ }
3081
+
3082
+ .ds-theme-dark .ds-fp-opt:hover {
3083
+ background: #1e293b;
3084
+ }
3085
+
3086
+ .ds-fp-opt-on {
3087
+ background: #eef2ff;
3088
+ }
3089
+
3090
+ .ds-theme-dark .ds-fp-opt-on {
3091
+ background: #1e293b;
3092
+ }
3093
+
3094
+ /* Custom checkbox */
3095
+ .ds-fp-cb {
3096
+ width: 16px;
3097
+ height: 16px;
3098
+ border: 2px solid #d1d5db;
3099
+ border-radius: 4px;
3100
+ flex-shrink: 0;
3101
+ display: flex;
3102
+ align-items: center;
3103
+ justify-content: center;
3104
+ transition: border-color 0.1s, background 0.1s;
3105
+ }
3106
+
3107
+ .ds-fp-cb-on {
3108
+ border-color: #6366f1;
3109
+ background: #6366f1;
3110
+ }
3111
+
3112
+ .ds-fp-cb-on svg {
3113
+ width: 10px;
3114
+ height: 10px;
3115
+ stroke: #fff;
3116
+ }
3117
+
3118
+ .ds-fp-opt-lbl {
3119
+ font-size: 12px;
3120
+ color: #374151;
3121
+ flex: 1;
3122
+ overflow: hidden;
3123
+ text-overflow: ellipsis;
3124
+ white-space: nowrap;
3125
+ }
3126
+
3127
+ .ds-theme-dark .ds-fp-opt-lbl {
3128
+ color: #cbd5e1;
3129
+ }
3130
+
3131
+ .ds-fp-opts-msg {
3132
+ display: flex;
3133
+ align-items: center;
3134
+ justify-content: center;
3135
+ gap: 8px;
3136
+ padding: 14px 12px;
3137
+ font-size: 12px;
3138
+ color: #9ca3af;
3139
+ }
3140
+
3141
+ /* ── Apply Filter button ───────────────────────────────────────────────────── */
3142
+ .ds-fp-apply {
3143
+ width: 100%;
3144
+ padding: 9px 16px;
3145
+ border: none;
3146
+ border-radius: 8px;
3147
+ background: linear-gradient(135deg, #16a34a, #15803d);
3148
+ color: #fff;
3149
+ font-size: 13px;
3150
+ font-weight: 600;
3151
+ cursor: pointer;
3152
+ transition: opacity 0.15s, transform 0.1s;
3153
+ letter-spacing: 0.01em;
3154
+ }
3155
+
3156
+ .ds-fp-apply:hover {
3157
+ opacity: 0.9;
3158
+ }
3159
+
3160
+ .ds-fp-apply:active {
3161
+ transform: scale(0.98);
3162
+ }
3163
+
3164
+ /* ── Text / date inputs inside filter body ─────────────────────────────────── */
3165
+ .ds-fp-text-val {
3166
+ width: 100%;
3167
+ height: 34px;
3168
+ padding: 0 10px;
3169
+ border: 1px solid #d1d5db;
3170
+ border-radius: 6px;
3171
+ font-size: 13px;
3172
+ background: #fff;
3173
+ color: #374151;
3174
+ outline: none;
3175
+ transition: border-color 0.15s;
3176
+ }
3177
+
3178
+ .ds-fp-text-val:focus {
3179
+ border-color: #6366f1;
3180
+ box-shadow: 0 0 0 2px rgba(99,102,241,0.15);
3181
+ }
3182
+
3183
+ .ds-theme-dark .ds-fp-text-val {
3184
+ background: #0f172a;
3185
+ border-color: #334155;
3186
+ color: #e2e8f0;
3187
+ }
3188
+
3189
+ .ds-fp-date-range {
3190
+ display: flex;
3191
+ align-items: center;
3192
+ gap: 6px;
3193
+ }
3194
+
3195
+ .ds-fp-date {
3196
+ flex: 1;
3197
+ height: 34px;
3198
+ padding: 0 8px;
3199
+ border: 1px solid #d1d5db;
3200
+ border-radius: 6px;
3201
+ font-size: 12px;
3202
+ background: #fff;
3203
+ color: #374151;
3204
+ outline: none;
3205
+ transition: border-color 0.15s;
3206
+ }
3207
+
3208
+ .ds-fp-date:focus {
3209
+ border-color: #6366f1;
3210
+ }
3211
+
3212
+ .ds-fp-date-sep {
3213
+ color: #9ca3af;
3214
+ font-size: 12px;
3215
+ }
3216
+
3217
+ .ds-theme-dark .ds-fp-date {
3218
+ background: #0f172a;
3219
+ border-color: #334155;
3220
+ color: #e2e8f0;
3221
+ }
3222
+
3223
+ /* ── Component-level inline filter button (funnel icon on chart card) ──────── */
3224
+ .ds-comp-filter-btn {
3225
+ position: absolute;
3226
+ top: 6px;
3227
+ right: 6px;
3228
+ z-index: 10;
3229
+ width: 28px;
3230
+ height: 28px;
3231
+ display: flex;
3232
+ align-items: center;
3233
+ justify-content: center;
3234
+ border: 1px solid #e5e7eb;
3235
+ border-radius: 6px;
3236
+ background: rgba(255,255,255,0.9);
3237
+ color: #6b7280;
3238
+ cursor: pointer;
3239
+ padding: 0;
3240
+ transition: border-color 0.15s, color 0.15s, background 0.15s;
3241
+ backdrop-filter: blur(4px);
3242
+ }
3243
+
3244
+ .ds-comp-filter-btn:hover {
3245
+ border-color: #6366f1;
3246
+ color: #6366f1;
3247
+ background: #fff;
3248
+ }
3249
+
3250
+ .ds-comp-filter-btn-active {
3251
+ border-color: #6366f1;
3252
+ color: #6366f1;
3253
+ background: #eef2ff;
3254
+ }
3255
+
3256
+ .ds-comp-filter-btn svg {
3257
+ width: 13px;
3258
+ height: 13px;
3259
+ }
3260
+
3261
+ .ds-theme-dark .ds-comp-filter-btn {
3262
+ background: rgba(15,23,42,0.85);
3263
+ border-color: #334155;
3264
+ color: #94a3b8;
3265
+ }
3266
+
3267
+ .ds-theme-dark .ds-comp-filter-btn-active {
3268
+ border-color: #6366f1;
3269
+ color: #818cf8;
3270
+ background: #1e293b;
3271
+ }
3272
+
3273
+ /* ── Inline filter popover ─────────────────────────────────────────────────── */
3274
+ .ds-comp-filter-pop {
3275
+ position: absolute;
3276
+ top: 38px;
3277
+ right: 6px;
3278
+ z-index: 9999;
3279
+ }
3280
+
3281
+ /* Visual shell for the inline popover — same look as global filter panel */
3282
+ .ds-fp-panel-pop {
3283
+ width: 300px;
3284
+ max-height: 440px;
3285
+ overflow-y: auto;
3286
+ background: #fff;
3287
+ border: 1px solid #e5e7eb;
3288
+ border-radius: 10px;
3289
+ box-shadow: 0 8px 24px rgba(0,0,0,0.12), 0 2px 6px rgba(0,0,0,0.06);
3290
+ }
3291
+
3292
+ .ds-theme-dark .ds-fp-panel-pop {
3293
+ background: #1e293b;
3294
+ border-color: #334155;
3295
+ box-shadow: 0 8px 24px rgba(0,0,0,0.4);
3296
+ }
3297
+
3298
+ .ds-cpop-inner {
3299
+ display: flex;
3300
+ flex-direction: column;
3301
+ gap: 6px;
3302
+ padding: 10px;
3303
+ }
3304
+
3305
+ .ds-cpop-title {
3306
+ font-size: 11px;
3307
+ font-weight: 700;
3308
+ text-transform: uppercase;
3309
+ letter-spacing: 0.05em;
3310
+ color: #6b7280;
3311
+ padding-bottom: 4px;
3312
+ border-bottom: 1px solid #f3f4f6;
3313
+ }
3314
+
3315
+ .ds-theme-dark .ds-cpop-title {
3316
+ color: #94a3b8;
3317
+ border-bottom-color: #334155;
3318
+ }
3319
+
3320
+ .ds-cpop-label {
3321
+ font-size: 12px;
3322
+ font-weight: 600;
3323
+ color: #374151;
3324
+ margin-bottom: 4px;
3325
+ }
3326
+
3327
+ .ds-theme-dark .ds-cpop-label {
3328
+ color: #e2e8f0;
3329
+ }
3330
+
3331
+ .ds-cpop-opts-wrap {
3332
+ border: 1px solid #e5e7eb;
3333
+ border-radius: 6px;
3334
+ overflow: hidden;
3335
+ margin-bottom: 6px;
3336
+ }
3337
+
3338
+ .ds-theme-dark .ds-cpop-opts-wrap {
3339
+ border-color: #334155;
3340
+ }
3341
+
3342
+ .ds-cpop-opts {
3343
+ max-height: 160px;
3344
+ overflow-y: auto;
3345
+ }
3346
+
3347
+ .ds-cpop-opt {
3348
+ display: flex;
3349
+ align-items: center;
3350
+ gap: 8px;
3351
+ padding: 6px 8px;
3352
+ cursor: pointer;
3353
+ font-size: 12px;
3354
+ color: #374151;
3355
+ transition: background 0.1s;
3356
+ user-select: none;
3357
+ }
3358
+
3359
+ .ds-cpop-opt:hover {
3360
+ background: #f0f0ff;
3361
+ }
3362
+
3363
+ .ds-theme-dark .ds-cpop-opt {
3364
+ color: #cbd5e1;
3365
+ }
3366
+
3367
+ .ds-theme-dark .ds-cpop-opt:hover {
3368
+ background: #0f172a;
3369
+ }
3370
+
3371
+ .ds-cpop-apply {
3372
+ font-size: 12px;
3373
+ padding: 7px 12px;
3374
+ }
3375
+
3376
+ /* ── Custom dropdown filter (matches publish page SelectFilter) ────────────── */
3377
+
3378
+ .ds-custom-dd {
3379
+ position: relative;
3380
+ min-width: 150px;
3381
+ }
3382
+
3383
+ .ds-dd-trigger {
3384
+ width: 100%;
3385
+ height: 34px;
3386
+ padding: 0 10px;
3387
+ display: flex;
3388
+ align-items: center;
3389
+ justify-content: space-between;
3390
+ gap: 6px;
3391
+ background: #ffffff;
3392
+ border: 1px solid #d1d5db;
3393
+ border-radius: 8px;
3394
+ font-size: 13px;
3395
+ color: #111827;
3396
+ cursor: pointer;
3397
+ text-align: left;
3398
+ transition: border-color 0.15s, box-shadow 0.15s;
3399
+ white-space: nowrap;
3400
+ }
3401
+
3402
+ .ds-dd-trigger:hover {
3403
+ border-color: #6366f1;
3404
+ }
3405
+
3406
+ .ds-dd-trigger:focus {
3407
+ outline: none;
3408
+ border-color: #6366f1;
3409
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
3410
+ }
3411
+
3412
+ .ds-theme-dark .ds-dd-trigger {
3413
+ background: #1e293b;
3414
+ border-color: #334155;
3415
+ color: #f1f5f9;
3416
+ }
3417
+
3418
+ .ds-dd-value {
3419
+ flex: 1;
3420
+ overflow: hidden;
3421
+ text-overflow: ellipsis;
3422
+ color: inherit;
3423
+ }
3424
+
3425
+ /* "All" placeholder style */
3426
+ .ds-dd-trigger:not(.ds-dd-has-value) .ds-dd-value {
3427
+ color: #9ca3af;
3428
+ }
3429
+
3430
+ .ds-dd-actions {
3431
+ display: flex;
3432
+ align-items: center;
3433
+ gap: 4px;
3434
+ flex-shrink: 0;
3435
+ }
3436
+
3437
+ .ds-dd-clear {
3438
+ font-size: 11px;
3439
+ color: #9ca3af;
3440
+ cursor: pointer;
3441
+ padding: 0 2px;
3442
+ line-height: 1;
3443
+ }
3444
+
3445
+ .ds-dd-clear:hover {
3446
+ color: #374151;
3447
+ }
3448
+
3449
+ .ds-theme-dark .ds-dd-clear:hover {
3450
+ color: #e2e8f0;
3451
+ }
3452
+
3453
+ .ds-dd-arrow {
3454
+ color: #9ca3af;
3455
+ transition: transform 0.18s ease;
3456
+ display: block;
3457
+ }
3458
+
3459
+ /* ── Dropdown panel ────────────────────────────────────────────────────────── */
3460
+
3461
+ .ds-dd-panel {
3462
+ position: absolute;
3463
+ top: calc(100% + 4px);
3464
+ left: 0;
3465
+ right: 0;
3466
+ min-width: 180px;
3467
+ background: #ffffff;
3468
+ border: 1px solid #e5e7eb;
3469
+ border-radius: 10px;
3470
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
3471
+ z-index: 9999;
3472
+ overflow: hidden;
3473
+ }
3474
+
3475
+ .ds-theme-dark .ds-dd-panel {
3476
+ background: #1e293b;
3477
+ border-color: #334155;
3478
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
3479
+ }
3480
+
3481
+ /* Search row */
3482
+ .ds-dd-search-wrap {
3483
+ padding: 8px 8px 6px;
3484
+ border-bottom: 1px solid #f3f4f6;
3485
+ }
3486
+
3487
+ .ds-theme-dark .ds-dd-search-wrap {
3488
+ border-bottom-color: #334155;
3489
+ }
3490
+
3491
+ .ds-dd-search {
3492
+ width: 100%;
3493
+ height: 30px;
3494
+ padding: 0 10px;
3495
+ border: 1px solid #e5e7eb;
3496
+ border-radius: 6px;
3497
+ font-size: 12px;
3498
+ background: #f9fafb;
3499
+ color: #374151;
3500
+ outline: none;
3501
+ transition: border-color 0.15s, box-shadow 0.15s;
3502
+ }
3503
+
3504
+ .ds-dd-search:focus {
3505
+ border-color: #6366f1;
3506
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);
3507
+ background: #fff;
3508
+ }
3509
+
3510
+ .ds-theme-dark .ds-dd-search {
3511
+ background: #0f172a;
3512
+ border-color: #334155;
3513
+ color: #e2e8f0;
3514
+ }
3515
+
3516
+ .ds-theme-dark .ds-dd-search:focus {
3517
+ background: #1e293b;
3518
+ }
3519
+
3520
+ /* Options list */
3521
+ .ds-dd-options {
3522
+ max-height: 200px;
3523
+ overflow-y: auto;
3524
+ }
3525
+
3526
+ .ds-dd-opt {
3527
+ width: 100%;
3528
+ padding: 8px 12px;
3529
+ display: flex;
3530
+ align-items: center;
3531
+ justify-content: space-between;
3532
+ gap: 8px;
3533
+ background: transparent;
3534
+ border: none;
3535
+ font-size: 13px;
3536
+ color: #374151;
3537
+ cursor: pointer;
3538
+ text-align: left;
3539
+ transition: background 0.1s;
3540
+ }
3541
+
3542
+ .ds-dd-opt:hover {
3543
+ background: #eef2ff;
3544
+ }
3545
+
3546
+ .ds-dd-opt-active {
3547
+ background: #eef2ff;
3548
+ color: #4338ca;
3549
+ font-weight: 600;
3550
+ }
3551
+
3552
+ .ds-dd-opt-active:hover {
3553
+ background: #e0e7ff;
3554
+ }
3555
+
3556
+ .ds-theme-dark .ds-dd-opt {
3557
+ color: #cbd5e1;
3558
+ }
3559
+
3560
+ .ds-theme-dark .ds-dd-opt:hover {
3561
+ background: #0f172a;
3562
+ }
3563
+
3564
+ .ds-theme-dark .ds-dd-opt-active {
3565
+ background: #1e293b;
3566
+ color: #818cf8;
3567
+ }
3568
+
3569
+ .ds-dd-opt-text {
3570
+ flex: 1;
3571
+ overflow: hidden;
3572
+ text-overflow: ellipsis;
3573
+ white-space: nowrap;
3574
+ }
3575
+
3576
+ .ds-dd-check {
3577
+ color: #4338ca;
3578
+ flex-shrink: 0;
3579
+ }
3580
+
3581
+ .ds-theme-dark .ds-dd-check {
3582
+ color: #818cf8;
3583
+ }
3584
+
3585
+ /* Empty / loading message */
3586
+ .ds-dd-msg {
3587
+ display: flex;
3588
+ align-items: center;
3589
+ justify-content: center;
3590
+ gap: 8px;
3591
+ padding: 14px 12px;
3592
+ font-size: 12px;
3593
+ color: #9ca3af;
3594
+ }
3595
+
3596
+ .ds-theme-dark .ds-dd-msg {
3597
+ color: #64748b;
3598
+ }
3599
+
3600
+ /* Spinner inside dropdown */
3601
+ .ds-dd-spinner {
3602
+ width: 14px;
3603
+ height: 14px;
3604
+ border: 2px solid #e5e7eb;
3605
+ border-top-color: #6366f1;
3606
+ border-radius: 50%;
3607
+ animation: ds-spin 0.8s linear infinite;
3608
+ flex-shrink: 0;
3609
+ }
3610
+
3611
+ /* ── v2: Inline filter (selection-filter placed in-grid) ───────────────────── */
3612
+
3613
+ .ds-inline-filter {
3614
+ width: 100%;
3615
+ height: 100%;
3616
+ display: flex;
3617
+ flex-direction: column;
3618
+ justify-content: center;
3619
+ gap: 4px;
3620
+ padding: 6px 10px;
3621
+ }
3622
+
3623
+ .ds-inline-filter-select,
3624
+ .ds-inline-filter-input {
3625
+ width: 100%;
3626
+ height: 34px;
3627
+ padding: 0 10px;
3628
+ border: 1px solid #d1d5db;
3629
+ border-radius: 6px;
3630
+ font-size: 13px;
3631
+ background: #ffffff;
3632
+ color: #111827;
3633
+ cursor: pointer;
3634
+ outline: none;
3635
+ transition: border-color 0.15s, box-shadow 0.15s;
3636
+ }
3637
+
3638
+ .ds-inline-filter-select:focus,
3639
+ .ds-inline-filter-input:focus {
3640
+ border-color: #6366f1;
3641
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
3642
+ }
3643
+
3644
+ .ds-theme-dark .ds-inline-filter-select,
3645
+ .ds-theme-dark .ds-inline-filter-input {
3646
+ background: #1e293b;
3647
+ border-color: #334155;
3648
+ color: #f1f5f9;
3649
+ }
3650
+
3651
+ /* ── Export toolbar ────────────────────────────────────────────────────────── */
3652
+ .ds-toolbar {
3653
+ display: flex;
3654
+ justify-content: flex-end;
3655
+ padding: 8px 16px 0;
3656
+ gap: 8px;
3657
+ }
3658
+
3659
+ .ds-toolbar-btn {
3660
+ height: 30px;
3661
+ padding: 0 12px;
3662
+ border: 1px solid #d1d5db;
3663
+ border-radius: 6px;
3664
+ font-size: 12px;
3665
+ font-weight: 500;
3666
+ background: #ffffff;
3667
+ color: #374151;
3668
+ cursor: pointer;
3669
+ display: flex;
3670
+ align-items: center;
3671
+ gap: 5px;
3672
+ transition: background 0.15s, border-color 0.15s;
3673
+ }
3674
+
3675
+ .ds-toolbar-btn:hover {
3676
+ background: #f9fafb;
3677
+ border-color: #9ca3af;
3678
+ }
3679
+
3680
+ .ds-theme-dark .ds-toolbar-btn {
3681
+ background: #1e293b;
3682
+ border-color: #334155;
3683
+ color: #e2e8f0;
3684
+ }
3685
+
3686
+ .ds-theme-dark .ds-toolbar-btn:hover {
3687
+ background: #0f172a;
3688
+ }
3689
+
3690
+ /* ─────────────────────────────────────────────────────────────────────────────
3691
+ v3 Badge-bar filter panel
3692
+ Layout: [⊻ Filters:] [Filter A] [Filter B] [+ Add Filter]
3693
+ Per-filter popovers open below the clicked badge.
3694
+ ───────────────────────────────────────────────────────────────────────────── */
3695
+
3696
+ /* Wrapper — relative so popovers can be absolutely positioned inside */
3697
+ .ds-fp-v3 {
3698
+ position: relative;
3699
+ border-bottom: 1px solid #e5e7eb;
3700
+ background: inherit;
3701
+ }
3702
+
3703
+ .ds-theme-dark .ds-fp-v3 {
3704
+ border-bottom-color: #1e293b;
3705
+ }
3706
+
3707
+ /* ── Horizontal bar ─────────────────────────────────────────────────────────── */
3708
+ .ds-fp-v3-bar {
3709
+ display: flex;
3710
+ align-items: center;
3711
+ flex-wrap: wrap;
3712
+ gap: 6px;
3713
+ padding: 8px 16px;
3714
+ }
3715
+
3716
+ /* "⊻ Filters:" label */
3717
+ .ds-fp-v3-label {
3718
+ display: inline-flex;
3719
+ align-items: center;
3720
+ gap: 5px;
3721
+ font-size: 12px;
3722
+ font-weight: 600;
3723
+ color: #6b7280;
3724
+ letter-spacing: 0.03em;
3725
+ white-space: nowrap;
3726
+ flex-shrink: 0;
3727
+ margin-right: 2px;
3728
+ }
3729
+
3730
+ .ds-fp-v3-label svg {
3731
+ color: #9ca3af;
3732
+ }
3733
+
3734
+ .ds-theme-dark .ds-fp-v3-label {
3735
+ color: #94a3b8;
3736
+ }
3737
+
3738
+ /* Container for all badge pills */
3739
+ .ds-fp-v3-badges {
3740
+ display: flex;
3741
+ flex-wrap: wrap;
3742
+ align-items: center;
3743
+ gap: 6px;
3744
+ }
3745
+
3746
+ /* ── Filter badge pill ──────────────────────────────────────────────────────── */
3747
+ .ds-fp-v3-badge {
3748
+ display: inline-flex;
3749
+ align-items: center;
3750
+ gap: 5px;
3751
+ padding: 4px 12px;
3752
+ border: 1.5px solid #d1d5db;
3753
+ border-radius: 20px;
3754
+ background: #ffffff;
3755
+ color: #374151;
3756
+ font-size: 12px;
3757
+ font-weight: 500;
3758
+ cursor: pointer;
3759
+ white-space: nowrap;
3760
+ transition: border-color 0.15s, background 0.15s, color 0.15s, box-shadow 0.15s;
3761
+ line-height: 1.4;
3762
+ }
3763
+
3764
+ .ds-fp-v3-badge svg {
3765
+ flex-shrink: 0;
3766
+ color: #9ca3af;
3767
+ transition: color 0.15s;
3768
+ }
3769
+
3770
+ .ds-fp-v3-badge:hover {
3771
+ border-color: #6366f1;
3772
+ background: #f5f3ff;
3773
+ color: #4338ca;
3774
+ }
3775
+
3776
+ .ds-fp-v3-badge:hover svg {
3777
+ color: #6366f1;
3778
+ }
3779
+
3780
+ .ds-theme-dark .ds-fp-v3-badge {
3781
+ background: #1e293b;
3782
+ border-color: #334155;
3783
+ color: #cbd5e1;
3784
+ }
3785
+
3786
+ .ds-theme-dark .ds-fp-v3-badge:hover {
3787
+ border-color: #6366f1;
3788
+ background: #1e1e3a;
3789
+ color: #a5b4fc;
3790
+ }
3791
+
3792
+ /* Active state — green filled pill */
3793
+ .ds-fp-v3-badge-active {
3794
+ border-color: #16a34a;
3795
+ background: #16a34a;
3796
+ color: #ffffff;
3797
+ }
3798
+
3799
+ .ds-fp-v3-badge-active svg {
3800
+ color: rgba(255, 255, 255, 0.8);
3801
+ }
3802
+
3803
+ .ds-fp-v3-badge-active:hover {
3804
+ border-color: #15803d;
3805
+ background: #15803d;
3806
+ color: #ffffff;
3807
+ }
3808
+
3809
+ .ds-fp-v3-badge-active:hover svg {
3810
+ color: rgba(255, 255, 255, 0.9);
3811
+ }
3812
+
3813
+ .ds-theme-dark .ds-fp-v3-badge-active {
3814
+ border-color: #16a34a;
3815
+ background: #16a34a;
3816
+ color: #ffffff;
3817
+ }
3818
+
3819
+ /* "+ Add Filter" ghost button */
3820
+ .ds-fp-v3-add {
3821
+ display: inline-flex;
3822
+ align-items: center;
3823
+ gap: 4px;
3824
+ padding: 4px 12px;
3825
+ border: 1.5px dashed #d1d5db;
3826
+ border-radius: 20px;
3827
+ background: transparent;
3828
+ color: #9ca3af;
3829
+ font-size: 12px;
3830
+ font-weight: 500;
3831
+ cursor: pointer;
3832
+ white-space: nowrap;
3833
+ transition: border-color 0.15s, color 0.15s;
3834
+ line-height: 1.4;
3835
+ }
3836
+
3837
+ .ds-fp-v3-add:hover {
3838
+ border-color: #6366f1;
3839
+ color: #6366f1;
3840
+ }
3841
+
3842
+ .ds-theme-dark .ds-fp-v3-add {
3843
+ border-color: #334155;
3844
+ color: #64748b;
3845
+ }
3846
+
3847
+ .ds-theme-dark .ds-fp-v3-add:hover {
3848
+ border-color: #6366f1;
3849
+ color: #818cf8;
3850
+ }
3851
+
3852
+ /* ── Popover ────────────────────────────────────────────────────────────────── */
3853
+ .ds-fp-v3-pop {
3854
+ position: absolute;
3855
+ z-index: 9999;
3856
+ width: 300px;
3857
+ background: #ffffff;
3858
+ border: 1px solid #e5e7eb;
3859
+ border-radius: 12px;
3860
+ box-shadow: 0 8px 28px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);
3861
+ overflow: hidden;
3862
+ }
3863
+
3864
+ .ds-theme-dark .ds-fp-v3-pop {
3865
+ background: #1e293b;
3866
+ border-color: #334155;
3867
+ box-shadow: 0 8px 28px rgba(0, 0, 0, 0.4);
3868
+ }
3869
+
3870
+ /* Popover header */
3871
+ .ds-fp-v3-pop-hd {
3872
+ display: flex;
3873
+ align-items: center;
3874
+ justify-content: space-between;
3875
+ padding: 10px 12px 10px 14px;
3876
+ border-bottom: 1px solid #f3f4f6;
3877
+ background: #fafafa;
3878
+ }
3879
+
3880
+ .ds-theme-dark .ds-fp-v3-pop-hd {
3881
+ background: #0f172a;
3882
+ border-bottom-color: #334155;
3883
+ }
3884
+
3885
+ .ds-fp-v3-pop-title {
3886
+ display: inline-flex;
3887
+ align-items: center;
3888
+ gap: 6px;
3889
+ font-size: 13px;
3890
+ font-weight: 600;
3891
+ color: #374151;
3892
+ }
3893
+
3894
+ .ds-fp-v3-pop-title svg {
3895
+ color: #6b7280;
3896
+ flex-shrink: 0;
3897
+ }
3898
+
3899
+ .ds-theme-dark .ds-fp-v3-pop-title {
3900
+ color: #e2e8f0;
3901
+ }
3902
+
3903
+ .ds-theme-dark .ds-fp-v3-pop-title svg {
3904
+ color: #94a3b8;
3905
+ }
3906
+
3907
+ /* Action icon buttons (trash + close) */
3908
+ .ds-fp-v3-pop-actions {
3909
+ display: flex;
3910
+ align-items: center;
3911
+ gap: 4px;
3912
+ }
3913
+
3914
+ .ds-fp-v3-pop-icon-btn {
3915
+ width: 26px;
3916
+ height: 26px;
3917
+ display: flex;
3918
+ align-items: center;
3919
+ justify-content: center;
3920
+ border: 1px solid #e5e7eb;
3921
+ border-radius: 6px;
3922
+ background: transparent;
3923
+ color: #6b7280;
3924
+ cursor: pointer;
3925
+ padding: 0;
3926
+ transition: border-color 0.15s, color 0.15s, background 0.15s;
3927
+ flex-shrink: 0;
3928
+ }
3929
+
3930
+ .ds-fp-v3-pop-icon-btn:hover {
3931
+ border-color: #6366f1;
3932
+ color: #6366f1;
3933
+ background: #eef2ff;
3934
+ }
3935
+
3936
+ .ds-theme-dark .ds-fp-v3-pop-icon-btn {
3937
+ border-color: #334155;
3938
+ color: #94a3b8;
3939
+ }
3940
+
3941
+ .ds-theme-dark .ds-fp-v3-pop-icon-btn:hover {
3942
+ border-color: #6366f1;
3943
+ color: #818cf8;
3944
+ background: #1e1e3a;
3945
+ }
3946
+
3947
+ /* Popover body */
3948
+ .ds-fp-v3-pop-body {
3949
+ display: flex;
3950
+ flex-direction: column;
3951
+ gap: 10px;
3952
+ padding: 12px 14px;
3953
+ }
3954
+
3955
+ /* Field row (label + control) */
3956
+ .ds-fp-v3-field {
3957
+ display: flex;
3958
+ flex-direction: column;
3959
+ gap: 5px;
3960
+ }
3961
+
3962
+ .ds-fp-v3-field-lbl {
3963
+ font-size: 10px;
3964
+ font-weight: 700;
3965
+ text-transform: uppercase;
3966
+ letter-spacing: 0.06em;
3967
+ color: #9ca3af;
3968
+ }
3969
+
3970
+ .ds-theme-dark .ds-fp-v3-field-lbl {
3971
+ color: #64748b;
3972
+ }
3973
+
3974
+ /* Condition select */
3975
+ .ds-fp-v3-condition {
3976
+ width: 100%;
3977
+ height: 32px;
3978
+ padding: 0 8px;
3979
+ border: 1px solid #d1d5db;
3980
+ border-radius: 7px;
3981
+ font-size: 12px;
3982
+ background: #ffffff;
3983
+ color: #374151;
3984
+ cursor: pointer;
3985
+ outline: none;
3986
+ transition: border-color 0.15s;
3987
+ }
3988
+
3989
+ .ds-fp-v3-condition:focus {
3990
+ border-color: #6366f1;
3991
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);
3992
+ }
3993
+
3994
+ .ds-theme-dark .ds-fp-v3-condition {
3995
+ background: #0f172a;
3996
+ border-color: #334155;
3997
+ color: #e2e8f0;
3998
+ }
3999
+
4000
+ /* ── Multi-select widget ────────────────────────────────────────────────────── */
4001
+ .ds-fp-v3-ms-wrap {
4002
+ display: flex;
4003
+ flex-direction: column;
4004
+ gap: 6px;
4005
+ }
4006
+
4007
+ /* Trigger row */
4008
+ .ds-fp-v3-ms-trigger {
4009
+ display: flex;
4010
+ align-items: center;
4011
+ justify-content: space-between;
4012
+ gap: 6px;
4013
+ height: 32px;
4014
+ padding: 0 10px;
4015
+ border: 1px solid #d1d5db;
4016
+ border-radius: 7px;
4017
+ background: #ffffff;
4018
+ cursor: pointer;
4019
+ font-size: 12px;
4020
+ color: #374151;
4021
+ transition: border-color 0.15s;
4022
+ user-select: none;
4023
+ }
4024
+
4025
+ .ds-fp-v3-ms-trigger:hover {
4026
+ border-color: #6366f1;
4027
+ }
4028
+
4029
+ .ds-theme-dark .ds-fp-v3-ms-trigger {
4030
+ background: #0f172a;
4031
+ border-color: #334155;
4032
+ color: #e2e8f0;
4033
+ }
4034
+
4035
+ .ds-fp-v3-ms-display {
4036
+ flex: 1;
4037
+ overflow: hidden;
4038
+ text-overflow: ellipsis;
4039
+ white-space: nowrap;
4040
+ color: inherit;
4041
+ }
4042
+
4043
+ /* When no value selected, show placeholder colour */
4044
+ .ds-fp-v3-ms-trigger:not(.ds-fp-v3-ms-has-value) .ds-fp-v3-ms-display {
4045
+ color: #9ca3af;
4046
+ }
4047
+
4048
+ /* Dropdown panel */
4049
+ .ds-fp-v3-ms-drop {
4050
+ border: 1px solid #e5e7eb;
4051
+ border-radius: 8px;
4052
+ overflow: hidden;
4053
+ background: #ffffff;
4054
+ }
4055
+
4056
+ .ds-theme-dark .ds-fp-v3-ms-drop {
4057
+ background: #0f172a;
4058
+ border-color: #334155;
4059
+ }
4060
+
4061
+ /* Search input inside dropdown */
4062
+ .ds-fp-v3-ms-search {
4063
+ width: 100%;
4064
+ height: 32px;
4065
+ padding: 0 10px;
4066
+ border: none;
4067
+ border-bottom: 1px solid #f3f4f6;
4068
+ outline: none;
4069
+ font-size: 12px;
4070
+ background: #f9fafb;
4071
+ color: #374151;
4072
+ transition: background 0.15s;
4073
+ }
4074
+
4075
+ .ds-fp-v3-ms-search:focus {
4076
+ background: #ffffff;
4077
+ border-bottom-color: #6366f1;
4078
+ }
4079
+
4080
+ .ds-theme-dark .ds-fp-v3-ms-search {
4081
+ background: #0f172a;
4082
+ border-bottom-color: #1e293b;
4083
+ color: #e2e8f0;
4084
+ }
4085
+
4086
+ .ds-fp-v3-ms-search::placeholder {
4087
+ color: #9ca3af;
4088
+ }
4089
+
4090
+ /* Options list */
4091
+ .ds-fp-v3-ms-opts {
4092
+ max-height: 160px;
4093
+ overflow-y: auto;
4094
+ }
4095
+
4096
+ /* Individual option row */
4097
+ .ds-fp-v3-opt {
4098
+ display: flex;
4099
+ align-items: center;
4100
+ gap: 8px;
4101
+ padding: 6px 10px;
4102
+ cursor: pointer;
4103
+ font-size: 12px;
4104
+ color: #374151;
4105
+ transition: background 0.1s;
4106
+ user-select: none;
4107
+ }
4108
+
4109
+ .ds-fp-v3-opt:hover {
4110
+ background: #f0f0ff;
4111
+ }
4112
+
4113
+ .ds-fp-v3-opt-on {
4114
+ background: #eef2ff;
4115
+ }
4116
+
4117
+ .ds-theme-dark .ds-fp-v3-opt {
4118
+ color: #cbd5e1;
4119
+ }
4120
+
4121
+ .ds-theme-dark .ds-fp-v3-opt:hover {
4122
+ background: #1e293b;
4123
+ }
4124
+
4125
+ .ds-theme-dark .ds-fp-v3-opt-on {
4126
+ background: #1e293b;
4127
+ }
4128
+
4129
+ /* Custom checkbox */
4130
+ .ds-fp-v3-cb {
4131
+ width: 15px;
4132
+ height: 15px;
4133
+ border: 2px solid #d1d5db;
4134
+ border-radius: 3px;
4135
+ flex-shrink: 0;
4136
+ display: flex;
4137
+ align-items: center;
4138
+ justify-content: center;
4139
+ transition: border-color 0.1s, background 0.1s;
4140
+ }
4141
+
4142
+ .ds-fp-v3-cb-on {
4143
+ border-color: #6366f1;
4144
+ background: #6366f1;
4145
+ }
4146
+
4147
+ .ds-fp-v3-cb-on svg {
4148
+ stroke: #fff;
4149
+ }
4150
+
4151
+ /* Options empty/loading message */
4152
+ .ds-fp-v3-opts-msg {
4153
+ display: flex;
4154
+ align-items: center;
4155
+ justify-content: center;
4156
+ gap: 8px;
4157
+ padding: 12px;
4158
+ font-size: 12px;
4159
+ color: #9ca3af;
4160
+ }
4161
+
4162
+ /* ── Chips row (selected values) ────────────────────────────────────────────── */
4163
+ .ds-fp-v3-chips {
4164
+ display: flex;
4165
+ flex-wrap: wrap;
4166
+ gap: 4px;
4167
+ }
4168
+
4169
+ .ds-fp-v3-chip {
4170
+ display: inline-flex;
4171
+ align-items: center;
4172
+ gap: 4px;
4173
+ padding: 2px 8px;
4174
+ border-radius: 10px;
4175
+ background: #e0e7ff;
4176
+ color: #4338ca;
4177
+ font-size: 11px;
4178
+ font-weight: 600;
4179
+ white-space: nowrap;
4180
+ }
4181
+
4182
+ .ds-theme-dark .ds-fp-v3-chip {
4183
+ background: #312e81;
4184
+ color: #a5b4fc;
4185
+ }
4186
+
4187
+ .ds-fp-v3-chip-x {
4188
+ border: none;
4189
+ background: transparent;
4190
+ color: inherit;
4191
+ font-size: 10px;
4192
+ cursor: pointer;
4193
+ padding: 0;
4194
+ line-height: 1;
4195
+ opacity: 0.7;
4196
+ transition: opacity 0.1s;
4197
+ }
4198
+
4199
+ .ds-fp-v3-chip-x:hover {
4200
+ opacity: 1;
4201
+ }
4202
+
4203
+ /* ── Popover footer ─────────────────────────────────────────────────────────── */
4204
+ .ds-fp-v3-pop-footer {
4205
+ display: flex;
4206
+ align-items: center;
4207
+ justify-content: flex-end;
4208
+ gap: 8px;
4209
+ padding: 10px 14px;
4210
+ border-top: 1px solid #f3f4f6;
4211
+ background: #fafafa;
4212
+ }
4213
+
4214
+ .ds-theme-dark .ds-fp-v3-pop-footer {
4215
+ background: #0f172a;
4216
+ border-top-color: #334155;
4217
+ }
4218
+
4219
+ .ds-fp-v3-clear-btn {
4220
+ height: 30px;
4221
+ padding: 0 14px;
4222
+ border: 1px solid #d1d5db;
4223
+ border-radius: 7px;
4224
+ background: #ffffff;
4225
+ color: #374151;
4226
+ font-size: 12px;
4227
+ font-weight: 500;
4228
+ cursor: pointer;
4229
+ transition: border-color 0.15s, background 0.15s;
4230
+ }
4231
+
4232
+ .ds-fp-v3-clear-btn:hover {
4233
+ border-color: #9ca3af;
4234
+ background: #f3f4f6;
4235
+ }
4236
+
4237
+ .ds-theme-dark .ds-fp-v3-clear-btn {
4238
+ background: #1e293b;
4239
+ border-color: #334155;
4240
+ color: #e2e8f0;
4241
+ }
4242
+
4243
+ .ds-theme-dark .ds-fp-v3-clear-btn:hover {
4244
+ background: #0f172a;
4245
+ }
4246
+
4247
+ .ds-fp-v3-apply-btn {
4248
+ height: 30px;
4249
+ padding: 0 16px;
4250
+ border: none;
4251
+ border-radius: 7px;
4252
+ background: linear-gradient(135deg, #16a34a, #15803d);
4253
+ color: #ffffff;
4254
+ font-size: 12px;
4255
+ font-weight: 600;
4256
+ cursor: pointer;
4257
+ transition: opacity 0.15s, transform 0.1s;
4258
+ white-space: nowrap;
4259
+ }
4260
+
4261
+ .ds-fp-v3-apply-btn:hover {
4262
+ opacity: 0.9;
4263
+ }
4264
+
4265
+ .ds-fp-v3-apply-btn:active {
4266
+ transform: scale(0.97);
4267
+ }
4268
+
4269
+ /* ── Date range inputs ──────────────────────────────────────────────────────── */
4270
+ .ds-fp-v3-date-range {
4271
+ display: flex;
4272
+ align-items: center;
4273
+ gap: 6px;
4274
+ }
4275
+
4276
+ .ds-fp-v3-date {
4277
+ flex: 1;
4278
+ height: 32px;
4279
+ padding: 0 8px;
4280
+ border: 1px solid #d1d5db;
4281
+ border-radius: 7px;
4282
+ font-size: 12px;
4283
+ background: #ffffff;
4284
+ color: #374151;
4285
+ outline: none;
4286
+ transition: border-color 0.15s;
4287
+ }
4288
+
4289
+ .ds-fp-v3-date:focus {
4290
+ border-color: #6366f1;
4291
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);
4292
+ }
4293
+
4294
+ .ds-theme-dark .ds-fp-v3-date {
4295
+ background: #0f172a;
4296
+ border-color: #334155;
4297
+ color: #e2e8f0;
4298
+ }
4299
+
4300
+ .ds-fp-v3-date-sep {
4301
+ color: #9ca3af;
4302
+ font-size: 12px;
4303
+ flex-shrink: 0;
4304
+ }
4305
+
4306
+ /* ── Text / number input ────────────────────────────────────────────────────── */
4307
+ .ds-fp-v3-text-input {
4308
+ width: 100%;
4309
+ height: 32px;
4310
+ padding: 0 10px;
4311
+ border: 1px solid #d1d5db;
4312
+ border-radius: 7px;
4313
+ font-size: 12px;
4314
+ background: #ffffff;
4315
+ color: #374151;
4316
+ outline: none;
4317
+ transition: border-color 0.15s;
4318
+ }
4319
+
4320
+ .ds-fp-v3-text-input:focus {
4321
+ border-color: #6366f1;
4322
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);
4323
+ }
4324
+
4325
+ .ds-theme-dark .ds-fp-v3-text-input {
4326
+ background: #0f172a;
4327
+ border-color: #334155;
4328
+ color: #e2e8f0;
4329
+ }
4330
+ `, e = document.createElement("style");
4331
+ e.id = "deepspot-sdk-styles", e.textContent = A, document.head.appendChild(e);
4332
+ } catch (A) {
4333
+ }
4334
+ }
4335
+ }
4336
+ function de(A) {
4337
+ if (typeof A == "string") {
4338
+ const e = document.querySelector(A);
4339
+ if (!e) throw new Error(`Deepspot SDK: container "${A}" not found in DOM`);
2125
4340
  return e;
2126
4341
  }
2127
- return k;
4342
+ return A;
2128
4343
  }
2129
- class ge {
4344
+ class ue {
2130
4345
  constructor(e) {
2131
4346
  if (!e.apiKey) throw new Error("Deepspot SDK: apiKey is required");
2132
4347
  if (!e.baseUrl) throw new Error("Deepspot SDK: baseUrl is required");
2133
- this.apiClient = new K(e.baseUrl, e.apiKey), B();
4348
+ this.apiClient = new B(e.baseUrl, e.apiKey), K();
2134
4349
  }
2135
4350
  // ── Embed full dashboard ────────────────────────────────────────────────────
2136
4351
  async embedDashboard(e) {
2137
- var a, o, c, d, b, u, g, n, f, p;
2138
- const t = de(e.container), s = (a = e.embedLevel) != null ? a : "dashboard", i = (o = e.theme) != null ? o : "light";
4352
+ var i, a, f, h, v, m, p, n, g, u;
4353
+ const t = de(e.container), s = (i = e.embedLevel) != null ? i : "dashboard", r = (a = e.theme) != null ? a : "light";
2139
4354
  t.style.height = e.height || "600px", t.style.display = "block";
2140
- const r = this.createRoot(t, i);
2141
- this.showLoading(r);
4355
+ const o = this.createRoot(t, r);
4356
+ this.showLoading(o);
2142
4357
  try {
2143
- const l = await this.apiClient.getEmbedToken({
4358
+ const b = await this.apiClient.getEmbedToken({
2144
4359
  dashboardId: e.dashboardId,
2145
4360
  embedType: "dashboard",
2146
4361
  embedLevel: s,
2147
4362
  userId: e.userId,
2148
4363
  tenantId: e.tenantId
2149
- }), x = await this.apiClient.getDashboardRender(
4364
+ }), c = await this.apiClient.getDashboardRender(
2150
4365
  e.dashboardId,
2151
- l,
4366
+ b,
2152
4367
  {
2153
4368
  embedLevel: s,
2154
4369
  pageId: e.pageId,
@@ -2156,91 +4371,94 @@ class ge {
2156
4371
  filters: e.filters || {}
2157
4372
  }
2158
4373
  );
2159
- let h;
2160
- const y = new D(r, {
4374
+ let d;
4375
+ const l = new j(o, {
2161
4376
  embedLevel: s,
2162
- theme: i,
4377
+ theme: r,
2163
4378
  // v1 backward compat (hideFilters → hideGlobalFilters)
2164
- hideFilters: (c = e.hideGlobalFilters) != null ? c : !1,
2165
- hideExport: (d = e.hideExport) != null ? d : !1,
4379
+ hideFilters: (f = e.hideGlobalFilters) != null ? f : !1,
4380
+ hideExport: (h = e.hideExport) != null ? h : !1,
2166
4381
  // v2 visibility
2167
- hideGlobalFilters: (b = e.hideGlobalFilters) != null ? b : !1,
2168
- hideInlineFilters: (u = e.hideInlineFilters) != null ? u : !1,
2169
- hideText: (g = e.hideText) != null ? g : !1,
4382
+ hideGlobalFilters: (v = e.hideGlobalFilters) != null ? v : !1,
4383
+ hideInlineFilters: (m = e.hideInlineFilters) != null ? m : !1,
4384
+ hideText: (p = e.hideText) != null ? p : !1,
2170
4385
  hideHeader: (n = e.hideHeader) != null ? n : !1,
2171
- hideBackground: (f = e.hideBackground) != null ? f : !1,
4386
+ hideBackground: (g = e.hideBackground) != null ? g : !1,
2172
4387
  initialFilters: e.filters || {},
2173
4388
  onFilterChange: e.onFilterChange,
2174
4389
  onReady: e.onReady,
2175
- onFetchFilterOptions: (T) => this.apiClient.getFilterOptions(e.dashboardId, T, l),
2176
- onFetchTablePage: (T, C, $) => this.apiClient.getTablePage(e.dashboardId, T, C, $, l),
2177
- onTabSwitch: async (T, C) => {
2178
- var $, R, I;
2179
- ($ = e.onTabSwitch) == null || $.call(e, T, C);
4390
+ onFetchFilterOptions: (T) => this.apiClient.getFilterOptions(e.dashboardId, T, b),
4391
+ onFetchTablePage: (T, w, k) => this.apiClient.getTablePage(e.dashboardId, T, w, k, b),
4392
+ onTabSwitch: async (T, w) => {
4393
+ var k;
4394
+ (k = e.onTabSwitch) == null || k.call(e, T, w);
2180
4395
  try {
2181
- const L = await this.apiClient.getDashboardRender(
4396
+ const x = await this.apiClient.getDashboardRender(
2182
4397
  e.dashboardId,
2183
- l,
4398
+ b,
2184
4399
  {
2185
4400
  embedLevel: s,
2186
4401
  pageId: T,
2187
- tabId: C,
2188
- filters: (I = (R = h == null ? void 0 : h.getActiveFilters()) != null ? R : e.filters) != null ? I : {}
4402
+ tabId: w,
4403
+ // Use renderer's live filter state instance.filters is a stale copy
4404
+ filters: l.getActiveFilters(),
4405
+ filterOperators: l.getActiveFilterOperators(),
4406
+ localFilters: l.getActiveLocalFilters()
2189
4407
  }
2190
4408
  );
2191
- y.update(L);
2192
- } catch (L) {
2193
- console.error("Deepspot SDK: tab fetch failed", L);
4409
+ l.update(x);
4410
+ } catch (x) {
4411
+ console.error("Deepspot SDK: tab fetch failed", x);
2194
4412
  }
2195
4413
  }
2196
4414
  });
2197
- return y.render(x), h = new E({
4415
+ return l.render(c), d = new z({
2198
4416
  dashboardId: e.dashboardId,
2199
- token: l,
4417
+ token: b,
2200
4418
  embedType: "dashboard",
2201
4419
  embedLevel: s,
2202
- activePageId: x.activePage,
2203
- activeTabId: x.activeTab,
4420
+ activePageId: c.activePage,
4421
+ activeTabId: c.activeTab,
2204
4422
  activeFilters: e.filters || {},
2205
4423
  apiClient: this.apiClient,
2206
- renderer: y,
4424
+ renderer: l,
2207
4425
  onFilterChange: e.onFilterChange
2208
- }), h;
2209
- } catch (l) {
2210
- throw this.showError(r, (l == null ? void 0 : l.message) || "Failed to load dashboard"), (p = e.onError) == null || p.call(e, (l == null ? void 0 : l.message) || "Failed to load dashboard"), l;
4426
+ }), d;
4427
+ } catch (b) {
4428
+ throw this.showError(o, (b == null ? void 0 : b.message) || "Failed to load dashboard"), (u = e.onError) == null || u.call(e, (b == null ? void 0 : b.message) || "Failed to load dashboard"), b;
2211
4429
  }
2212
4430
  }
2213
4431
  // ── Embed single report (component) ────────────────────────────────────────
2214
4432
  async embedReport(e) {
2215
- var i;
4433
+ var r;
2216
4434
  const t = de(e.container);
2217
4435
  t.style.height = e.height || "400px", t.style.display = "block";
2218
4436
  const s = this.createRoot(t, e.theme || "light");
2219
4437
  this.showLoading(s);
2220
4438
  try {
2221
- const r = await this.apiClient.getEmbedToken({
4439
+ const o = await this.apiClient.getEmbedToken({
2222
4440
  dashboardId: e.dashboardId,
2223
4441
  embedType: "report",
2224
4442
  componentId: e.componentId,
2225
4443
  userId: e.userId,
2226
4444
  tenantId: e.tenantId
2227
- }), a = await this.apiClient.getReportRender(
4445
+ }), i = await this.apiClient.getReportRender(
2228
4446
  e.dashboardId,
2229
4447
  e.componentId,
2230
- r,
4448
+ o,
2231
4449
  { filters: e.filters || {} }
2232
- ), o = new he(s, e.theme || "light");
2233
- return o.render(a, e.onReady), new E({
4450
+ ), a = new pe(s, e.theme || "light");
4451
+ return a.render(i, e.onReady), new z({
2234
4452
  dashboardId: e.dashboardId,
2235
4453
  componentId: e.componentId,
2236
- token: r,
4454
+ token: o,
2237
4455
  embedType: "report",
2238
4456
  activeFilters: e.filters || {},
2239
4457
  apiClient: this.apiClient,
2240
- renderer: o
4458
+ renderer: a
2241
4459
  });
2242
- } catch (r) {
2243
- throw this.showError(s, (r == null ? void 0 : r.message) || "Failed to load report"), (i = e.onError) == null || i.call(e, (r == null ? void 0 : r.message) || "Failed to load report"), r;
4460
+ } catch (o) {
4461
+ throw this.showError(s, (o == null ? void 0 : o.message) || "Failed to load report"), (r = e.onError) == null || r.call(e, (o == null ? void 0 : o.message) || "Failed to load report"), o;
2244
4462
  }
2245
4463
  }
2246
4464
  // ── Private helpers ─────────────────────────────────────────────────────────
@@ -2267,83 +4485,83 @@ class ge {
2267
4485
  `;
2268
4486
  }
2269
4487
  }
2270
- const q = class q extends HTMLElement {
4488
+ const _ = class _ extends HTMLElement {
2271
4489
  constructor() {
2272
4490
  super(...arguments), this.instance = null, this.connected = !1;
2273
4491
  }
2274
4492
  connectedCallback() {
2275
- this.connected = !0, B(), this.style.display = "block", this.renderRoot = document.createElement("div"), this.renderRoot.className = "ds-embed-root", this.appendChild(this.renderRoot), this.mount();
4493
+ this.connected = !0, K(), this.style.display = "block", this.renderRoot = document.createElement("div"), this.renderRoot.className = "ds-embed-root", this.appendChild(this.renderRoot), this.mount();
2276
4494
  }
2277
4495
  disconnectedCallback() {
2278
4496
  var e;
2279
4497
  this.connected = !1, (e = this.instance) == null || e.destroy(), this.instance = null;
2280
4498
  }
2281
4499
  attributeChangedCallback(e, t, s) {
2282
- var i;
2283
- t === s || !this.connected || ((i = this.instance) == null || i.destroy(), this.instance = null, this.mount());
4500
+ var r;
4501
+ t === s || !this.connected || ((r = this.instance) == null || r.destroy(), this.instance = null, this.mount());
2284
4502
  }
2285
4503
  async mount() {
2286
- const e = this.getAttribute("dashboard-id"), t = this.getAttribute("api-key"), s = this.getAttribute("base-url") || "", i = this.getAttribute("user-id") || void 0, r = this.getAttribute("tenant-id") || void 0, a = this.getAttribute("embed-level") || "dashboard", o = this.getAttribute("theme") || "light", c = this.getAttribute("height") || "600px", d = this.getAttribute("page-id") || void 0, b = this.getAttribute("tab-id") || void 0, u = this.getAttribute("hide-filters") === "true", g = this.getAttribute("hide-export") === "true", n = this.getAttribute("hide-global-filters") === "true" || u, f = this.getAttribute("hide-inline-filters") === "true", p = this.getAttribute("hide-text") === "true", l = this.getAttribute("hide-header") === "true", x = this.getAttribute("hide-background") === "true";
4504
+ const e = this.getAttribute("dashboard-id"), t = this.getAttribute("api-key"), s = this.getAttribute("base-url") || "", r = this.getAttribute("user-id") || void 0, o = this.getAttribute("tenant-id") || void 0, i = this.getAttribute("embed-level") || "dashboard", a = this.getAttribute("theme") || "light", f = this.getAttribute("height") || "600px", h = this.getAttribute("page-id") || void 0, v = this.getAttribute("tab-id") || void 0, m = this.getAttribute("hide-filters") === "true", p = this.getAttribute("hide-export") === "true", n = this.getAttribute("hide-global-filters") === "true" || m, g = this.getAttribute("hide-inline-filters") === "true", u = this.getAttribute("hide-text") === "true", b = this.getAttribute("hide-header") === "true", c = this.getAttribute("hide-background") === "true";
2287
4505
  if (!e || !t || !s) {
2288
4506
  this.showError("Missing required attributes: dashboard-id, api-key, base-url");
2289
4507
  return;
2290
4508
  }
2291
- this.renderRoot.style.height = c, this.renderRoot.className = `ds-embed-root ds-theme-${o}`, this.showLoading();
4509
+ this.renderRoot.style.height = f, this.renderRoot.className = `ds-embed-root ds-theme-${a}`, this.showLoading();
2292
4510
  try {
2293
- const h = new K(s, t), y = await h.getEmbedToken({
4511
+ const d = new B(s, t), l = await d.getEmbedToken({
2294
4512
  dashboardId: e,
2295
4513
  embedType: "dashboard",
2296
- embedLevel: a,
2297
- userId: i,
2298
- tenantId: r
2299
- }), T = await h.getDashboardRender(e, y, {
2300
- embedLevel: a,
2301
- pageId: d,
2302
- tabId: b,
4514
+ embedLevel: i,
4515
+ userId: r,
4516
+ tenantId: o
4517
+ }), T = await d.getDashboardRender(e, l, {
4518
+ embedLevel: i,
4519
+ pageId: h,
4520
+ tabId: v,
2303
4521
  filters: {}
2304
- }), C = new D(this.renderRoot, {
2305
- embedLevel: a,
2306
- theme: o,
4522
+ }), w = new j(this.renderRoot, {
4523
+ embedLevel: i,
4524
+ theme: a,
2307
4525
  // v1 backward compat
2308
4526
  hideFilters: n,
2309
- hideExport: g,
4527
+ hideExport: p,
2310
4528
  // v2 visibility
2311
4529
  hideGlobalFilters: n,
2312
- hideInlineFilters: f,
2313
- hideText: p,
2314
- hideHeader: l,
2315
- hideBackground: x,
4530
+ hideInlineFilters: g,
4531
+ hideText: u,
4532
+ hideHeader: b,
4533
+ hideBackground: c,
2316
4534
  initialFilters: {},
2317
- onFetchFilterOptions: ($) => h.getFilterOptions(e, $, y),
2318
- onFetchTablePage: ($, R, I) => h.getTablePage(e, $, R, I, y),
2319
- onTabSwitch: async ($, R) => {
2320
- var I, L;
4535
+ onFetchFilterOptions: (k) => d.getFilterOptions(e, k, l),
4536
+ onFetchTablePage: (k, x, $) => d.getTablePage(e, k, x, $, l),
4537
+ onTabSwitch: async (k, x) => {
4538
+ var $, y;
2321
4539
  try {
2322
- const F = await h.getDashboardRender(e, y, {
2323
- embedLevel: a,
2324
- pageId: $,
2325
- tabId: R,
2326
- filters: (L = (I = this.instance) == null ? void 0 : I.getActiveFilters()) != null ? L : {}
4540
+ const S = await d.getDashboardRender(e, l, {
4541
+ embedLevel: i,
4542
+ pageId: k,
4543
+ tabId: x,
4544
+ filters: (y = ($ = this.instance) == null ? void 0 : $.getActiveFilters()) != null ? y : {}
2327
4545
  });
2328
- C.update(F);
2329
- } catch (F) {
2330
- console.error("Deepspot SDK: tab fetch failed", F);
4546
+ w.update(S);
4547
+ } catch (S) {
4548
+ console.error("Deepspot SDK: tab fetch failed", S);
2331
4549
  }
2332
4550
  }
2333
4551
  });
2334
- C.render(T), this.instance = new E({
4552
+ w.render(T), this.instance = new z({
2335
4553
  dashboardId: e,
2336
- token: y,
2337
- embedLevel: a,
4554
+ token: l,
4555
+ embedLevel: i,
2338
4556
  embedType: "dashboard",
2339
4557
  activePageId: T.activePage,
2340
4558
  activeTabId: T.activeTab,
2341
4559
  activeFilters: {},
2342
- apiClient: h,
2343
- renderer: C
4560
+ apiClient: d,
4561
+ renderer: w
2344
4562
  });
2345
- } catch (h) {
2346
- this.showError((h == null ? void 0 : h.message) || "Failed to load dashboard");
4563
+ } catch (d) {
4564
+ this.showError((d == null ? void 0 : d.message) || "Failed to load dashboard");
2347
4565
  }
2348
4566
  }
2349
4567
  showLoading() {
@@ -2387,7 +4605,7 @@ const q = class q extends HTMLElement {
2387
4605
  (e = this.instance) == null || e.exportPDF();
2388
4606
  }
2389
4607
  };
2390
- q.observedAttributes = [
4608
+ _.observedAttributes = [
2391
4609
  "dashboard-id",
2392
4610
  "api-key",
2393
4611
  "user-id",
@@ -2408,52 +4626,52 @@ q.observedAttributes = [
2408
4626
  "hide-header",
2409
4627
  "hide-background"
2410
4628
  ];
2411
- let z = q;
2412
- customElements.get("deepspot-dashboard") || customElements.define("deepspot-dashboard", z);
4629
+ let V = _;
4630
+ customElements.get("deepspot-dashboard") || customElements.define("deepspot-dashboard", V);
2413
4631
  const G = class G extends HTMLElement {
2414
4632
  constructor() {
2415
4633
  super(...arguments), this.instance = null, this.isConnected_ = !1;
2416
4634
  }
2417
4635
  connectedCallback() {
2418
- this.isConnected_ = !0, B(), this.style.display = "block", this.renderRoot = document.createElement("div"), this.renderRoot.className = "ds-embed-root", this.appendChild(this.renderRoot), this.mount();
4636
+ this.isConnected_ = !0, K(), this.style.display = "block", this.renderRoot = document.createElement("div"), this.renderRoot.className = "ds-embed-root", this.appendChild(this.renderRoot), this.mount();
2419
4637
  }
2420
4638
  disconnectedCallback() {
2421
4639
  var e;
2422
4640
  this.isConnected_ = !1, (e = this.instance) == null || e.destroy(), this.instance = null;
2423
4641
  }
2424
4642
  attributeChangedCallback(e, t, s) {
2425
- var i;
2426
- t !== s && this.isConnected_ && ((i = this.instance) == null || i.destroy(), this.instance = null, this.mount());
4643
+ var r;
4644
+ t !== s && this.isConnected_ && ((r = this.instance) == null || r.destroy(), this.instance = null, this.mount());
2427
4645
  }
2428
4646
  async mount() {
2429
- const e = this.getAttribute("dashboard-id"), t = this.getAttribute("component-id"), s = this.getAttribute("api-key"), i = this.getAttribute("base-url") || "", r = this.getAttribute("user-id") || void 0, a = this.getAttribute("tenant-id") || void 0, o = this.getAttribute("theme") || "light", c = this.getAttribute("height") || "400px";
2430
- if (!e || !t || !s || !i) {
4647
+ const e = this.getAttribute("dashboard-id"), t = this.getAttribute("component-id"), s = this.getAttribute("api-key"), r = this.getAttribute("base-url") || "", o = this.getAttribute("user-id") || void 0, i = this.getAttribute("tenant-id") || void 0, a = this.getAttribute("theme") || "light", f = this.getAttribute("height") || "400px";
4648
+ if (!e || !t || !s || !r) {
2431
4649
  this.showError("Missing required attributes: dashboard-id, component-id, api-key, base-url");
2432
4650
  return;
2433
4651
  }
2434
- this.renderRoot.style.height = c, this.renderRoot.className = `ds-embed-root ds-theme-${o}`, this.showLoading();
4652
+ this.renderRoot.style.height = f, this.renderRoot.className = `ds-embed-root ds-theme-${a}`, this.showLoading();
2435
4653
  try {
2436
- const d = new K(i, s), b = await d.getEmbedToken({
4654
+ const h = new B(r, s), v = await h.getEmbedToken({
2437
4655
  dashboardId: e,
2438
4656
  embedType: "report",
2439
4657
  componentId: t,
2440
- userId: r,
2441
- tenantId: a
2442
- }), u = await d.getReportRender(e, t, b, {
4658
+ userId: o,
4659
+ tenantId: i
4660
+ }), m = await h.getReportRender(e, t, v, {
2443
4661
  filters: {}
2444
- }), g = new he(this.renderRoot, o);
2445
- g.render(u, () => {
2446
- }), this.instance = new E({
4662
+ }), p = new pe(this.renderRoot, a);
4663
+ p.render(m, () => {
4664
+ }), this.instance = new z({
2447
4665
  dashboardId: e,
2448
4666
  componentId: t,
2449
- token: b,
4667
+ token: v,
2450
4668
  embedType: "report",
2451
4669
  activeFilters: {},
2452
- apiClient: d,
2453
- renderer: g
4670
+ apiClient: h,
4671
+ renderer: p
2454
4672
  });
2455
- } catch (d) {
2456
- this.showError((d == null ? void 0 : d.message) || "Failed to load report");
4673
+ } catch (h) {
4674
+ this.showError((h == null ? void 0 : h.message) || "Failed to load report");
2457
4675
  }
2458
4676
  }
2459
4677
  showLoading() {
@@ -2496,10 +4714,10 @@ G.observedAttributes = [
2496
4714
  "theme",
2497
4715
  "height"
2498
4716
  ];
2499
- let j = G;
2500
- customElements.get("deepspot-report") || customElements.define("deepspot-report", j);
2501
- customElements.get("deepspot-dashboard") || customElements.define("deepspot-dashboard", z);
2502
- customElements.get("deepspot-report") || customElements.define("deepspot-report", j);
4717
+ let q = G;
4718
+ customElements.get("deepspot-report") || customElements.define("deepspot-report", q);
4719
+ customElements.get("deepspot-dashboard") || customElements.define("deepspot-dashboard", V);
4720
+ customElements.get("deepspot-report") || customElements.define("deepspot-report", q);
2503
4721
  export {
2504
- ge as DeepspotSDK
4722
+ ue as DeepspotSDK
2505
4723
  };