drizzle-cube 0.1.53 → 0.1.55

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,161 +1,173 @@
1
- import { useState as S, useRef as b, useEffect as E, useCallback as w, useMemo as V } from "react";
2
- import { u as x } from "./chunks/providers-aaWIe5KD.js";
3
- import { a as H } from "./chunks/providers-aaWIe5KD.js";
4
- function O(r, t = {}) {
5
- const { cubeApi: n, batchCoordinator: u, enableBatching: l } = x(), [i, a] = S({
1
+ import { useState as b, useRef as w, useEffect as y, useCallback as C, useMemo as m } from "react";
2
+ import { u as L } from "./chunks/providers-aaWIe5KD.js";
3
+ import { a as F } from "./chunks/providers-aaWIe5KD.js";
4
+ function W(e, r = {}) {
5
+ const { cubeApi: s, batchCoordinator: u, enableBatching: a } = L(), [l, d] = b({
6
6
  resultSet: null,
7
7
  isLoading: !1,
8
8
  error: null,
9
9
  queryId: null
10
- }), d = b("");
11
- return E(() => {
12
- if (!r || t.skip)
10
+ }), f = w("");
11
+ return y(() => {
12
+ if (!e || r.skip)
13
13
  return;
14
- const c = JSON.stringify(r);
15
- if (c === d.current && !t.resetResultSetOnChange)
14
+ const n = JSON.stringify(e);
15
+ if (n === f.current && !r.resetResultSetOnChange)
16
16
  return;
17
- d.current = c;
17
+ f.current = n;
18
18
  const o = `${Date.now()}_${Math.random().toString(36).substring(7)}`;
19
- a((e) => ({
20
- resultSet: t.resetResultSetOnChange ? null : e.resultSet,
19
+ d((t) => ({
20
+ resultSet: r.resetResultSetOnChange ? null : t.resultSet,
21
21
  isLoading: !0,
22
22
  error: null,
23
23
  queryId: o
24
- })), (l && u ? u.register(r) : n.load(r)).then((e) => {
25
- a((g) => g.queryId === o ? {
26
- resultSet: e,
24
+ })), (a && u ? u.register(e) : s.load(e)).then((t) => {
25
+ d((h) => h.queryId === o ? {
26
+ resultSet: t,
27
27
  isLoading: !1,
28
28
  error: null,
29
29
  queryId: o
30
- } : g);
31
- }).catch((e) => {
32
- a((g) => g.queryId === o ? {
30
+ } : h);
31
+ }).catch((t) => {
32
+ d((h) => h.queryId === o ? {
33
33
  resultSet: null,
34
34
  isLoading: !1,
35
- error: e instanceof Error ? e : new Error(String(e)),
35
+ error: t instanceof Error ? t : new Error(String(t)),
36
36
  queryId: o
37
- } : g);
37
+ } : h);
38
38
  });
39
- }, [r, n, u, l, t.skip, t.resetResultSetOnChange]), i;
39
+ }, [e, s, u, a, r.skip, r.resetResultSetOnChange]), l;
40
40
  }
41
- function W(r, t = !0) {
42
- const [n, u] = S([]), [l, i] = S(null), a = b(null), d = b(""), {
43
- resultSet: c,
41
+ function D(e, r = !0) {
42
+ const [s, u] = b([]), [a, l] = b(null), d = w(null), f = w(""), {
43
+ resultSet: n,
44
44
  isLoading: o,
45
- error: f,
46
- queryId: e
47
- } = O(l, {
48
- skip: !l || !t,
45
+ error: i,
46
+ queryId: t
47
+ } = W(a, {
48
+ skip: !a || !r,
49
49
  resetResultSetOnChange: !0
50
50
  // Clear old results when query changes
51
- }), g = w((s) => {
52
- if (!s || !r)
51
+ }), h = C((c) => {
52
+ if (!c || !e)
53
53
  return [];
54
54
  try {
55
- const y = s.tablePivot(), h = /* @__PURE__ */ new Set();
56
- return y.forEach((q) => {
57
- const R = q[r];
58
- R != null && R !== "" && h.add(R);
59
- }), Array.from(h);
60
- } catch (y) {
61
- return console.error("Error extracting values from result set:", y), [];
55
+ const S = c.tablePivot(), g = /* @__PURE__ */ new Set();
56
+ return S.forEach((v) => {
57
+ const E = v[e];
58
+ E != null && E !== "" && g.add(E);
59
+ }), Array.from(g);
60
+ } catch (S) {
61
+ return console.error("Error extracting values from result set:", S), [];
62
62
  }
63
- }, [r]);
64
- E(() => {
65
- if (e && e !== a.current && !o)
66
- if (a.current = e, f)
63
+ }, [e]);
64
+ y(() => {
65
+ if (t && t !== d.current && !o)
66
+ if (d.current = t, i)
67
67
  u([]);
68
- else if (c) {
69
- const s = g(c);
70
- u(s);
68
+ else if (n) {
69
+ const c = h(n);
70
+ u(c);
71
71
  } else
72
72
  u([]);
73
- }, [c, o, f, e, g]), E(() => {
74
- (!r || !t) && (u([]), i(null), a.current = null, d.current = "");
75
- }, [r, t]);
76
- const I = w(() => {
77
- if (r) {
78
- d.current = "";
73
+ }, [n, o, i, t, h]), y(() => {
74
+ (!e || !r) && (u([]), l(null), d.current = null, f.current = "");
75
+ }, [e, r]);
76
+ const I = C(() => {
77
+ if (e) {
78
+ f.current = "";
79
79
  try {
80
- const s = {
81
- dimensions: [r],
80
+ const c = {
81
+ dimensions: [e],
82
82
  limit: 25,
83
- order: { [r]: "asc" }
83
+ order: { [e]: "asc" }
84
84
  };
85
- i(s);
86
- } catch (s) {
87
- console.error("Error creating query:", s);
85
+ l(c);
86
+ } catch (c) {
87
+ console.error("Error creating query:", c);
88
88
  }
89
89
  }
90
- }, [r]), p = w((s, y = !1) => {
91
- if (r && !(!y && s === d.current)) {
92
- d.current = s;
90
+ }, [e]), V = C((c, S = !1) => {
91
+ if (e && !(!S && c === f.current)) {
92
+ f.current = c;
93
93
  try {
94
- const h = {
95
- dimensions: [r],
94
+ const g = {
95
+ dimensions: [e],
96
96
  limit: 25,
97
- order: { [r]: "asc" }
97
+ order: { [e]: "asc" }
98
98
  };
99
- s && s.trim() && (h.filters = [{
100
- member: r,
99
+ c && c.trim() && (g.filters = [{
100
+ member: e,
101
101
  operator: "contains",
102
- values: [s.trim()]
103
- }]), i(h);
104
- } catch (h) {
105
- console.error("Error creating search query:", h);
102
+ values: [c.trim()]
103
+ }]), l(g);
104
+ } catch (g) {
105
+ console.error("Error creating search query:", g);
106
106
  }
107
107
  }
108
- }, [r]);
108
+ }, [e]);
109
109
  return {
110
- values: n,
110
+ values: s,
111
111
  loading: o,
112
- error: f ? f instanceof Error ? f.message : String(f) : null,
112
+ error: i ? i instanceof Error ? i.message : String(i) : null,
113
113
  refetch: I,
114
- searchValues: p
114
+ searchValues: V
115
115
  };
116
116
  }
117
- function k(r, t) {
118
- const [n, u] = S(r);
119
- return E(() => {
120
- const l = setTimeout(() => {
121
- u(r);
122
- }, t);
117
+ function Q(e, r) {
118
+ const [s, u] = b(e);
119
+ return y(() => {
120
+ const a = setTimeout(() => {
121
+ u(e);
122
+ }, r);
123
123
  return () => {
124
- clearTimeout(l);
124
+ clearTimeout(a);
125
125
  };
126
- }, [r, t]), n;
126
+ }, [e, r]), s;
127
127
  }
128
- const C = 1200, m = 768;
129
- function v() {
130
- const [r, t] = S(
131
- () => typeof window < "u" ? window.innerWidth : C
132
- ), n = b(null), u = b(null), l = w((c) => {
133
- if (n.current && (n.current.disconnect(), n.current = null), u.current = c, c) {
134
- const o = c.offsetWidth;
135
- o > 0 && t(o), n.current = new ResizeObserver((f) => {
136
- const e = f[0]?.contentRect.width;
137
- e && e > 0 && t(e);
138
- }), n.current.observe(c);
128
+ const R = 1200, p = 768;
129
+ function k() {
130
+ const [e, r] = b(
131
+ () => typeof window < "u" ? window.innerWidth : R
132
+ ), s = w(null), u = w(null), a = C((n) => {
133
+ if (s.current && (s.current.disconnect(), s.current = null), u.current = n, n) {
134
+ const o = n.offsetWidth;
135
+ o > 0 && r(o), s.current = new ResizeObserver((i) => {
136
+ const t = i[0]?.contentRect.width;
137
+ t && t > 0 && r(t);
138
+ }), s.current.observe(n);
139
139
  }
140
140
  }, []);
141
- E(() => () => {
142
- n.current && n.current.disconnect();
141
+ y(() => () => {
142
+ s.current && s.current.disconnect();
143
+ }, []), y(() => {
144
+ const n = () => {
145
+ if (u.current) {
146
+ const i = u.current.offsetWidth;
147
+ i > 0 && r(i);
148
+ }
149
+ };
150
+ window.addEventListener("resize", n);
151
+ const o = setTimeout(n, 100);
152
+ return () => {
153
+ window.removeEventListener("resize", n), clearTimeout(o);
154
+ };
143
155
  }, []);
144
- const i = V(() => r >= C ? "desktop" : r >= m ? "scaled" : "mobile", [r]), a = V(() => i !== "scaled" ? 1 : r / C, [r, i]);
156
+ const l = m(() => e >= R ? "desktop" : e >= p ? "scaled" : "mobile", [e]), d = m(() => l !== "scaled" ? 1 : e / R, [e, l]);
145
157
  return {
146
- containerRef: l,
147
- containerWidth: r,
148
- displayMode: i,
149
- scaleFactor: a,
150
- isEditable: i === "desktop",
151
- designWidth: C
158
+ containerRef: a,
159
+ containerWidth: e,
160
+ displayMode: l,
161
+ scaleFactor: d,
162
+ isEditable: l === "desktop",
163
+ designWidth: R
152
164
  };
153
165
  }
154
166
  export {
155
- H as useCubeMeta,
156
- O as useCubeQuery,
157
- k as useDebounce,
158
- W as useFilterValues,
159
- v as useResponsiveDashboard
167
+ F as useCubeMeta,
168
+ W as useCubeQuery,
169
+ Q as useDebounce,
170
+ D as useFilterValues,
171
+ k as useResponsiveDashboard
160
172
  };
161
173
  //# sourceMappingURL=hooks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sources":["../../src/client/hooks/useCubeQuery.ts","../../src/client/hooks/useFilterValues.ts","../../src/client/hooks/useDebounce.ts","../../src/client/hooks/useResponsiveDashboard.ts"],"sourcesContent":["/**\n * React hook for executing Cube queries\n * Replaces @cubejs-client/react useCubeQuery\n */\n\nimport { useState, useEffect, useRef } from 'react'\nimport { useCubeContext } from '../providers/CubeProvider'\nimport type { CubeQuery, CubeQueryOptions, CubeResultSet } from '../types'\n\ninterface UseCubeQueryResult {\n resultSet: CubeResultSet | null\n isLoading: boolean\n error: Error | null\n queryId: string | null\n}\n\nexport function useCubeQuery(\n query: CubeQuery | null,\n options: CubeQueryOptions = {}\n): UseCubeQueryResult {\n const { cubeApi, batchCoordinator, enableBatching } = useCubeContext()\n \n // Use a single state object to ensure atomic updates\n const [state, setState] = useState<UseCubeQueryResult>({\n resultSet: null,\n isLoading: false,\n error: null,\n queryId: null\n })\n \n // Track the last query to avoid unnecessary re-fetches\n const lastQueryRef = useRef<string>('')\n \n useEffect(() => {\n // Skip if query is null or skip option is true\n if (!query || options.skip) {\n return\n }\n\n // Create a stable query string for comparison\n const queryString = JSON.stringify(query)\n \n // Skip if query hasn't changed (unless resetResultSetOnChange is true)\n if (queryString === lastQueryRef.current && !options.resetResultSetOnChange) {\n return\n }\n\n lastQueryRef.current = queryString\n \n // Create a unique ID for this query execution\n const queryId = `${Date.now()}_${Math.random().toString(36).substring(7)}`\n\n // Update state atomically with new query ID and loading state\n setState(prevState => ({\n resultSet: options.resetResultSetOnChange ? null : prevState.resultSet,\n isLoading: true,\n error: null,\n queryId\n }))\n\n // Use batch coordinator if enabled, otherwise use direct API call\n const executeQuery = enableBatching && batchCoordinator\n ? batchCoordinator.register(query)\n : cubeApi.load(query)\n\n executeQuery\n .then((result) => {\n setState(prevState => {\n // Only update if this is still the current query\n if (prevState.queryId === queryId) {\n return {\n resultSet: result,\n isLoading: false,\n error: null,\n queryId\n }\n }\n return prevState\n })\n })\n .catch((err) => {\n setState(prevState => {\n // Only update if this is still the current query\n if (prevState.queryId === queryId) {\n return {\n resultSet: null,\n isLoading: false,\n error: err instanceof Error ? err : new Error(String(err)),\n queryId\n }\n }\n return prevState\n })\n })\n }, [query, cubeApi, batchCoordinator, enableBatching, options.skip, options.resetResultSetOnChange])\n\n return state\n}","/**\n * Hook for fetching distinct field values for filter dropdowns\n * Uses the /load API to get actual data values\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react'\nimport { useCubeQuery } from '../hooks/useCubeQuery'\nimport type { CubeQuery } from '../types'\n\ninterface UseFilterValuesResult {\n values: any[]\n loading: boolean\n error: string | null\n refetch: () => void\n searchValues: (searchTerm: string, force?: boolean) => void\n}\n\n/**\n * Custom hook to fetch distinct values for a field\n */\nexport function useFilterValues(\n fieldName: string | null, \n enabled: boolean = true\n): UseFilterValuesResult {\n const [values, setValues] = useState<any[]>([])\n const [currentQuery, setCurrentQuery] = useState<CubeQuery | null>(null)\n const lastProcessedQueryId = useRef<string | null>(null)\n const lastSearchTerm = useRef<string>('')\n \n // Use cube query hook for actual data fetching\n const { \n resultSet, \n isLoading,\n error: queryError,\n queryId\n } = useCubeQuery(currentQuery, {\n skip: !currentQuery || !enabled,\n resetResultSetOnChange: true // Clear old results when query changes\n })\n \n // Extract unique values from result set\n const extractValuesFromResultSet = useCallback((rs: any): any[] => {\n if (!rs || !fieldName) {\n return []\n }\n \n try {\n const data = rs.tablePivot()\n \n const uniqueValues = new Set<any>()\n \n data.forEach((row: any) => {\n const value = row[fieldName]\n if (value !== null && value !== undefined && value !== '') {\n uniqueValues.add(value)\n }\n })\n \n // Convert to array - already sorted by query\n const sortedValues = Array.from(uniqueValues)\n \n return sortedValues\n } catch (err) {\n console.error('Error extracting values from result set:', err)\n return []\n }\n }, [fieldName])\n \n // Process results only when we have a new matching query result\n useEffect(() => {\n // Skip if no query ID\n if (!queryId) {\n return\n }\n \n // Skip if we've already processed this query\n if (queryId === lastProcessedQueryId.current) {\n return\n }\n \n // Skip if still loading\n if (isLoading) {\n return\n }\n \n // Mark as processed\n lastProcessedQueryId.current = queryId\n \n if (queryError) {\n setValues([])\n } else if (resultSet) {\n const extractedValues = extractValuesFromResultSet(resultSet)\n setValues(extractedValues)\n } else {\n setValues([])\n }\n }, [resultSet, isLoading, queryError, queryId, extractValuesFromResultSet])\n \n // Reset values when fieldName becomes null or enabled changes\n useEffect(() => {\n if (!fieldName || !enabled) {\n setValues([])\n setCurrentQuery(null)\n lastProcessedQueryId.current = null\n lastSearchTerm.current = ''\n }\n }, [fieldName, enabled])\n \n // Refetch function\n const refetch = useCallback(() => {\n if (!fieldName) return\n \n lastSearchTerm.current = ''\n \n try {\n const query: CubeQuery = {\n dimensions: [fieldName], \n limit: 25,\n order: { [fieldName]: 'asc' }\n }\n setCurrentQuery(query)\n } catch (err) {\n console.error('Error creating query:', err)\n }\n }, [fieldName])\n\n // Search function for server-side filtering\n const searchValues = useCallback((searchTerm: string, force: boolean = false) => {\n if (!fieldName) {\n return\n }\n \n // Don't create a new query if the search term hasn't changed (unless forced)\n if (!force && searchTerm === lastSearchTerm.current) {\n return\n }\n \n lastSearchTerm.current = searchTerm\n \n try {\n // Create query inline to avoid dependency issues\n const query: CubeQuery = {\n dimensions: [fieldName], \n limit: 25,\n order: { [fieldName]: 'asc' }\n }\n \n if (searchTerm && searchTerm.trim()) {\n query.filters = [{\n member: fieldName,\n operator: 'contains',\n values: [searchTerm.trim()]\n }]\n }\n \n setCurrentQuery(query)\n } catch (err) {\n console.error('Error creating search query:', err)\n }\n }, [fieldName])\n \n return {\n values,\n loading: isLoading,\n error: queryError ? (queryError instanceof Error ? queryError.message : String(queryError)) : null,\n refetch,\n searchValues\n }\n}","/**\n * Custom hook for debouncing values\n * Delays updating the value until after the specified delay has passed\n * since the last change\n */\n\nimport { useState, useEffect } from 'react'\n\n/**\n * Debounces a value by the specified delay\n * @param value The value to debounce\n * @param delay The delay in milliseconds\n * @returns The debounced value\n */\nexport function useDebounce<T>(value: T, delay: number): T {\n const [debouncedValue, setDebouncedValue] = useState(value)\n\n useEffect(() => {\n // Set up a timer to update the debounced value after the delay\n const handler = setTimeout(() => {\n setDebouncedValue(value)\n }, delay)\n\n // Clean up the timer if the value changes before the delay\n return () => {\n clearTimeout(handler)\n }\n }, [value, delay])\n\n return debouncedValue\n}","/**\n * Custom hook for responsive dashboard layout management\n * Implements a three-tier responsive strategy:\n * - Desktop (1200px+): Normal grid layout with full editing\n * - Scaled (768-1199px): CSS transform scaling, read-only\n * - Mobile (<768px): Single-column stacked layout, read-only\n */\n\nimport { useState, useEffect, useRef, useMemo, useCallback } from 'react'\n\nexport type DashboardDisplayMode = 'desktop' | 'scaled' | 'mobile'\n\nconst DESIGN_WIDTH = 1200\nconst MOBILE_THRESHOLD = 768\n\nexport interface UseResponsiveDashboardResult {\n containerRef: React.RefCallback<HTMLDivElement>\n containerWidth: number\n displayMode: DashboardDisplayMode\n scaleFactor: number\n isEditable: boolean\n designWidth: number\n}\n\n/**\n * Hook for managing responsive dashboard layouts\n * Uses ResizeObserver for accurate width detection and calculates\n * the appropriate display mode and scale factor\n */\nexport function useResponsiveDashboard(): UseResponsiveDashboardResult {\n // Start with window width as initial estimate\n const [containerWidth, setContainerWidth] = useState(() =>\n typeof window !== 'undefined' ? window.innerWidth : DESIGN_WIDTH\n )\n const observerRef = useRef<ResizeObserver | null>(null)\n const elementRef = useRef<HTMLDivElement | null>(null)\n\n // Ref callback - called when element is attached/detached\n // This is key: unlike useEffect, this fires immediately when the DOM element exists\n const containerRef = useCallback((node: HTMLDivElement | null) => {\n // Cleanup previous observer\n if (observerRef.current) {\n observerRef.current.disconnect()\n observerRef.current = null\n }\n\n elementRef.current = node\n\n if (node) {\n // Get initial width immediately (synchronously when element attaches)\n const initialWidth = node.offsetWidth\n if (initialWidth > 0) {\n setContainerWidth(initialWidth)\n }\n\n // Set up ResizeObserver for ongoing changes\n observerRef.current = new ResizeObserver((entries) => {\n const width = entries[0]?.contentRect.width\n if (width && width > 0) {\n setContainerWidth(width)\n }\n })\n observerRef.current.observe(node)\n }\n }, [])\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect()\n }\n }\n }, [])\n\n const displayMode = useMemo<DashboardDisplayMode>(() => {\n if (containerWidth >= DESIGN_WIDTH) return 'desktop'\n if (containerWidth >= MOBILE_THRESHOLD) return 'scaled'\n return 'mobile'\n }, [containerWidth])\n\n const scaleFactor = useMemo(() => {\n if (displayMode !== 'scaled') return 1\n return containerWidth / DESIGN_WIDTH\n }, [containerWidth, displayMode])\n\n const isEditable = displayMode === 'desktop'\n\n return {\n containerRef,\n containerWidth,\n displayMode,\n scaleFactor,\n isEditable,\n designWidth: DESIGN_WIDTH\n }\n}\n"],"names":["useCubeQuery","query","options","cubeApi","batchCoordinator","enableBatching","useCubeContext","state","setState","useState","lastQueryRef","useRef","useEffect","queryString","queryId","prevState","result","err","useFilterValues","fieldName","enabled","values","setValues","currentQuery","setCurrentQuery","lastProcessedQueryId","lastSearchTerm","resultSet","isLoading","queryError","extractValuesFromResultSet","useCallback","rs","data","uniqueValues","row","value","extractedValues","refetch","searchValues","searchTerm","force","useDebounce","delay","debouncedValue","setDebouncedValue","handler","DESIGN_WIDTH","MOBILE_THRESHOLD","useResponsiveDashboard","containerWidth","setContainerWidth","observerRef","elementRef","containerRef","node","initialWidth","entries","width","displayMode","useMemo","scaleFactor"],"mappings":"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"}
1
+ {"version":3,"file":"hooks.js","sources":["../../src/client/hooks/useCubeQuery.ts","../../src/client/hooks/useFilterValues.ts","../../src/client/hooks/useDebounce.ts","../../src/client/hooks/useResponsiveDashboard.ts"],"sourcesContent":["/**\n * React hook for executing Cube queries\n * Replaces @cubejs-client/react useCubeQuery\n */\n\nimport { useState, useEffect, useRef } from 'react'\nimport { useCubeContext } from '../providers/CubeProvider'\nimport type { CubeQuery, CubeQueryOptions, CubeResultSet } from '../types'\n\ninterface UseCubeQueryResult {\n resultSet: CubeResultSet | null\n isLoading: boolean\n error: Error | null\n queryId: string | null\n}\n\nexport function useCubeQuery(\n query: CubeQuery | null,\n options: CubeQueryOptions = {}\n): UseCubeQueryResult {\n const { cubeApi, batchCoordinator, enableBatching } = useCubeContext()\n \n // Use a single state object to ensure atomic updates\n const [state, setState] = useState<UseCubeQueryResult>({\n resultSet: null,\n isLoading: false,\n error: null,\n queryId: null\n })\n \n // Track the last query to avoid unnecessary re-fetches\n const lastQueryRef = useRef<string>('')\n \n useEffect(() => {\n // Skip if query is null or skip option is true\n if (!query || options.skip) {\n return\n }\n\n // Create a stable query string for comparison\n const queryString = JSON.stringify(query)\n \n // Skip if query hasn't changed (unless resetResultSetOnChange is true)\n if (queryString === lastQueryRef.current && !options.resetResultSetOnChange) {\n return\n }\n\n lastQueryRef.current = queryString\n \n // Create a unique ID for this query execution\n const queryId = `${Date.now()}_${Math.random().toString(36).substring(7)}`\n\n // Update state atomically with new query ID and loading state\n setState(prevState => ({\n resultSet: options.resetResultSetOnChange ? null : prevState.resultSet,\n isLoading: true,\n error: null,\n queryId\n }))\n\n // Use batch coordinator if enabled, otherwise use direct API call\n const executeQuery = enableBatching && batchCoordinator\n ? batchCoordinator.register(query)\n : cubeApi.load(query)\n\n executeQuery\n .then((result) => {\n setState(prevState => {\n // Only update if this is still the current query\n if (prevState.queryId === queryId) {\n return {\n resultSet: result,\n isLoading: false,\n error: null,\n queryId\n }\n }\n return prevState\n })\n })\n .catch((err) => {\n setState(prevState => {\n // Only update if this is still the current query\n if (prevState.queryId === queryId) {\n return {\n resultSet: null,\n isLoading: false,\n error: err instanceof Error ? err : new Error(String(err)),\n queryId\n }\n }\n return prevState\n })\n })\n }, [query, cubeApi, batchCoordinator, enableBatching, options.skip, options.resetResultSetOnChange])\n\n return state\n}","/**\n * Hook for fetching distinct field values for filter dropdowns\n * Uses the /load API to get actual data values\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react'\nimport { useCubeQuery } from '../hooks/useCubeQuery'\nimport type { CubeQuery } from '../types'\n\ninterface UseFilterValuesResult {\n values: any[]\n loading: boolean\n error: string | null\n refetch: () => void\n searchValues: (searchTerm: string, force?: boolean) => void\n}\n\n/**\n * Custom hook to fetch distinct values for a field\n */\nexport function useFilterValues(\n fieldName: string | null, \n enabled: boolean = true\n): UseFilterValuesResult {\n const [values, setValues] = useState<any[]>([])\n const [currentQuery, setCurrentQuery] = useState<CubeQuery | null>(null)\n const lastProcessedQueryId = useRef<string | null>(null)\n const lastSearchTerm = useRef<string>('')\n \n // Use cube query hook for actual data fetching\n const { \n resultSet, \n isLoading,\n error: queryError,\n queryId\n } = useCubeQuery(currentQuery, {\n skip: !currentQuery || !enabled,\n resetResultSetOnChange: true // Clear old results when query changes\n })\n \n // Extract unique values from result set\n const extractValuesFromResultSet = useCallback((rs: any): any[] => {\n if (!rs || !fieldName) {\n return []\n }\n \n try {\n const data = rs.tablePivot()\n \n const uniqueValues = new Set<any>()\n \n data.forEach((row: any) => {\n const value = row[fieldName]\n if (value !== null && value !== undefined && value !== '') {\n uniqueValues.add(value)\n }\n })\n \n // Convert to array - already sorted by query\n const sortedValues = Array.from(uniqueValues)\n \n return sortedValues\n } catch (err) {\n console.error('Error extracting values from result set:', err)\n return []\n }\n }, [fieldName])\n \n // Process results only when we have a new matching query result\n useEffect(() => {\n // Skip if no query ID\n if (!queryId) {\n return\n }\n \n // Skip if we've already processed this query\n if (queryId === lastProcessedQueryId.current) {\n return\n }\n \n // Skip if still loading\n if (isLoading) {\n return\n }\n \n // Mark as processed\n lastProcessedQueryId.current = queryId\n \n if (queryError) {\n setValues([])\n } else if (resultSet) {\n const extractedValues = extractValuesFromResultSet(resultSet)\n setValues(extractedValues)\n } else {\n setValues([])\n }\n }, [resultSet, isLoading, queryError, queryId, extractValuesFromResultSet])\n \n // Reset values when fieldName becomes null or enabled changes\n useEffect(() => {\n if (!fieldName || !enabled) {\n setValues([])\n setCurrentQuery(null)\n lastProcessedQueryId.current = null\n lastSearchTerm.current = ''\n }\n }, [fieldName, enabled])\n \n // Refetch function\n const refetch = useCallback(() => {\n if (!fieldName) return\n \n lastSearchTerm.current = ''\n \n try {\n const query: CubeQuery = {\n dimensions: [fieldName], \n limit: 25,\n order: { [fieldName]: 'asc' }\n }\n setCurrentQuery(query)\n } catch (err) {\n console.error('Error creating query:', err)\n }\n }, [fieldName])\n\n // Search function for server-side filtering\n const searchValues = useCallback((searchTerm: string, force: boolean = false) => {\n if (!fieldName) {\n return\n }\n \n // Don't create a new query if the search term hasn't changed (unless forced)\n if (!force && searchTerm === lastSearchTerm.current) {\n return\n }\n \n lastSearchTerm.current = searchTerm\n \n try {\n // Create query inline to avoid dependency issues\n const query: CubeQuery = {\n dimensions: [fieldName], \n limit: 25,\n order: { [fieldName]: 'asc' }\n }\n \n if (searchTerm && searchTerm.trim()) {\n query.filters = [{\n member: fieldName,\n operator: 'contains',\n values: [searchTerm.trim()]\n }]\n }\n \n setCurrentQuery(query)\n } catch (err) {\n console.error('Error creating search query:', err)\n }\n }, [fieldName])\n \n return {\n values,\n loading: isLoading,\n error: queryError ? (queryError instanceof Error ? queryError.message : String(queryError)) : null,\n refetch,\n searchValues\n }\n}","/**\n * Custom hook for debouncing values\n * Delays updating the value until after the specified delay has passed\n * since the last change\n */\n\nimport { useState, useEffect } from 'react'\n\n/**\n * Debounces a value by the specified delay\n * @param value The value to debounce\n * @param delay The delay in milliseconds\n * @returns The debounced value\n */\nexport function useDebounce<T>(value: T, delay: number): T {\n const [debouncedValue, setDebouncedValue] = useState(value)\n\n useEffect(() => {\n // Set up a timer to update the debounced value after the delay\n const handler = setTimeout(() => {\n setDebouncedValue(value)\n }, delay)\n\n // Clean up the timer if the value changes before the delay\n return () => {\n clearTimeout(handler)\n }\n }, [value, delay])\n\n return debouncedValue\n}","/**\n * Custom hook for responsive dashboard layout management\n * Implements a three-tier responsive strategy:\n * - Desktop (1200px+): Normal grid layout with full editing\n * - Scaled (768-1199px): CSS transform scaling, read-only\n * - Mobile (<768px): Single-column stacked layout, read-only\n */\n\nimport { useState, useEffect, useRef, useMemo, useCallback } from 'react'\n\nexport type DashboardDisplayMode = 'desktop' | 'scaled' | 'mobile'\n\nconst DESIGN_WIDTH = 1200\nconst MOBILE_THRESHOLD = 768\n\nexport interface UseResponsiveDashboardResult {\n containerRef: React.RefCallback<HTMLDivElement>\n containerWidth: number\n displayMode: DashboardDisplayMode\n scaleFactor: number\n isEditable: boolean\n designWidth: number\n}\n\n/**\n * Hook for managing responsive dashboard layouts\n * Uses ResizeObserver for accurate width detection and calculates\n * the appropriate display mode and scale factor\n */\nexport function useResponsiveDashboard(): UseResponsiveDashboardResult {\n // Start with window width as initial estimate\n const [containerWidth, setContainerWidth] = useState(() =>\n typeof window !== 'undefined' ? window.innerWidth : DESIGN_WIDTH\n )\n const observerRef = useRef<ResizeObserver | null>(null)\n const elementRef = useRef<HTMLDivElement | null>(null)\n\n // Ref callback - called when element is attached/detached\n // This is key: unlike useEffect, this fires immediately when the DOM element exists\n const containerRef = useCallback((node: HTMLDivElement | null) => {\n // Cleanup previous observer\n if (observerRef.current) {\n observerRef.current.disconnect()\n observerRef.current = null\n }\n\n elementRef.current = node\n\n if (node) {\n // Get initial width immediately (synchronously when element attaches)\n const initialWidth = node.offsetWidth\n if (initialWidth > 0) {\n setContainerWidth(initialWidth)\n }\n\n // Set up ResizeObserver for ongoing changes\n observerRef.current = new ResizeObserver((entries) => {\n const width = entries[0]?.contentRect.width\n if (width && width > 0) {\n setContainerWidth(width)\n }\n })\n observerRef.current.observe(node)\n }\n }, [])\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect()\n }\n }\n }, [])\n\n // Fallback: window resize listener to catch resize events that ResizeObserver might miss\n // This is particularly important for containers in flex/grid layouts or deeply nested elements\n useEffect(() => {\n const handleWindowResize = () => {\n if (elementRef.current) {\n const width = elementRef.current.offsetWidth\n if (width > 0) {\n setContainerWidth(width)\n }\n }\n }\n\n window.addEventListener('resize', handleWindowResize)\n\n // Also measure after a short delay to catch late layout calculations\n const timeoutId = setTimeout(handleWindowResize, 100)\n\n return () => {\n window.removeEventListener('resize', handleWindowResize)\n clearTimeout(timeoutId)\n }\n }, [])\n\n const displayMode = useMemo<DashboardDisplayMode>(() => {\n if (containerWidth >= DESIGN_WIDTH) return 'desktop'\n if (containerWidth >= MOBILE_THRESHOLD) return 'scaled'\n return 'mobile'\n }, [containerWidth])\n\n const scaleFactor = useMemo(() => {\n if (displayMode !== 'scaled') return 1\n return containerWidth / DESIGN_WIDTH\n }, [containerWidth, displayMode])\n\n const isEditable = displayMode === 'desktop'\n\n return {\n containerRef,\n containerWidth,\n displayMode,\n scaleFactor,\n isEditable,\n designWidth: DESIGN_WIDTH\n }\n}\n"],"names":["useCubeQuery","query","options","cubeApi","batchCoordinator","enableBatching","useCubeContext","state","setState","useState","lastQueryRef","useRef","useEffect","queryString","queryId","prevState","result","err","useFilterValues","fieldName","enabled","values","setValues","currentQuery","setCurrentQuery","lastProcessedQueryId","lastSearchTerm","resultSet","isLoading","queryError","extractValuesFromResultSet","useCallback","rs","data","uniqueValues","row","value","extractedValues","refetch","searchValues","searchTerm","force","useDebounce","delay","debouncedValue","setDebouncedValue","handler","DESIGN_WIDTH","MOBILE_THRESHOLD","useResponsiveDashboard","containerWidth","setContainerWidth","observerRef","elementRef","containerRef","node","initialWidth","entries","width","handleWindowResize","timeoutId","displayMode","useMemo","scaleFactor"],"mappings":"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"}