@bygd/nc-report-ui 0.1.13 → 0.1.14

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,1140 +1 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var React = require('react');
6
- var Paper = require('@material-ui/core/Paper');
7
- var styles = require('@material-ui/core/styles');
8
- var LinearProgress = require('@material-ui/core/LinearProgress');
9
- var reactGoogleCharts = require('react-google-charts');
10
- var numeral = require('numeral');
11
- var axios = require('axios');
12
- var Typography = require('@material-ui/core/Typography');
13
- var nunjucks = require('nunjucks');
14
- var FormControl$1 = require('@material-ui/core/FormControl');
15
- var Select$1 = require('@material-ui/core/Select');
16
- var MenuItem$1 = require('@material-ui/core/MenuItem');
17
- var reactIntersectionObserver = require('react-intersection-observer');
18
- var material = require('@mui/material');
19
- var CheckBoxOutlineBlankIcon = require('@mui/icons-material/CheckBoxOutlineBlank');
20
- var CheckBoxIcon = require('@mui/icons-material/CheckBox');
21
- var Box = require('@mui/material/Box');
22
- var InputLabel = require('@mui/material/InputLabel');
23
- var MenuItem = require('@mui/material/MenuItem');
24
- var FormControl = require('@mui/material/FormControl');
25
- var Select = require('@mui/material/Select');
26
- var EventEmitter = require('eventemitter3');
27
- var Grid = require('@material-ui/core/Grid');
28
- var Container = require('@material-ui/core/Container');
29
-
30
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
31
-
32
- function _interopNamespace(e) {
33
- if (e && e.__esModule) return e;
34
- var n = Object.create(null);
35
- if (e) {
36
- Object.keys(e).forEach(function (k) {
37
- if (k !== 'default') {
38
- var d = Object.getOwnPropertyDescriptor(e, k);
39
- Object.defineProperty(n, k, d.get ? d : {
40
- enumerable: true,
41
- get: function () { return e[k]; }
42
- });
43
- }
44
- });
45
- }
46
- n.default = e;
47
- return Object.freeze(n);
48
- }
49
-
50
- var React__namespace = /*#__PURE__*/_interopNamespace(React);
51
- var Paper__default = /*#__PURE__*/_interopDefault(Paper);
52
- var LinearProgress__default = /*#__PURE__*/_interopDefault(LinearProgress);
53
- var numeral__default = /*#__PURE__*/_interopDefault(numeral);
54
- var axios__default = /*#__PURE__*/_interopDefault(axios);
55
- var Typography__default = /*#__PURE__*/_interopDefault(Typography);
56
- var nunjucks__default = /*#__PURE__*/_interopDefault(nunjucks);
57
- var FormControl__default$1 = /*#__PURE__*/_interopDefault(FormControl$1);
58
- var Select__default$1 = /*#__PURE__*/_interopDefault(Select$1);
59
- var MenuItem__default$1 = /*#__PURE__*/_interopDefault(MenuItem$1);
60
- var CheckBoxOutlineBlankIcon__default = /*#__PURE__*/_interopDefault(CheckBoxOutlineBlankIcon);
61
- var CheckBoxIcon__default = /*#__PURE__*/_interopDefault(CheckBoxIcon);
62
- var Box__default = /*#__PURE__*/_interopDefault(Box);
63
- var InputLabel__default = /*#__PURE__*/_interopDefault(InputLabel);
64
- var MenuItem__default = /*#__PURE__*/_interopDefault(MenuItem);
65
- var FormControl__default = /*#__PURE__*/_interopDefault(FormControl);
66
- var Select__default = /*#__PURE__*/_interopDefault(Select);
67
- var EventEmitter__default = /*#__PURE__*/_interopDefault(EventEmitter);
68
- var Grid__default = /*#__PURE__*/_interopDefault(Grid);
69
- var Container__default = /*#__PURE__*/_interopDefault(Container);
70
-
71
- function _extends() {
72
- return _extends = Object.assign ? Object.assign.bind() : function (n) {
73
- for (var e = 1; e < arguments.length; e++) {
74
- var t = arguments[e];
75
- for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
76
- }
77
- return n;
78
- }, _extends.apply(null, arguments);
79
- }
80
-
81
- const useStyles$1 = styles.makeStyles(theme => ({
82
- root: {
83
- width: '100%',
84
- '& > * + *': {
85
- marginTop: theme.spacing(2)
86
- }
87
- }
88
- }));
89
- function LinearIndeterminate(props) {
90
- const classes = useStyles$1();
91
- return /*#__PURE__*/React__namespace.default.createElement("div", _extends({
92
- className: classes.root
93
- }, props), /*#__PURE__*/React__namespace.default.createElement(LinearProgress__default.default, null));
94
- }
95
-
96
- function ValuePicker(view, schema, outputFormat = 'array') {
97
- const columns = view.columns;
98
- const metrics = schema.doc.metrics;
99
- const dimensions = schema.doc.dimensions;
100
- const all = [...metrics, ...dimensions];
101
- const mapped = all.reduce((result, item) => {
102
- result[item.name] = item;
103
- return result;
104
- }, {});
105
- const _get = row => {
106
- const output = outputFormat === 'array' ? [] : {};
107
- const resp = columns.reduce((result, item) => {
108
- const value = row[item.name];
109
- const ref = mapped[item.name];
110
- let formatted = value;
111
- if (ref.type === 'timestamp') formatted = new Date(value);else if (!ref.format) formatted = value;else if (ref.format && ref.prefix) formatted = {
112
- v: +value,
113
- f: ref.prefix + " " + numeral__default.default(value).format(ref.format)
114
- };else if (ref.format) formatted = {
115
- v: +value,
116
- f: numeral__default.default(value).format(ref.format)
117
- };else formatted = value;
118
- if (outputFormat === 'array') result.push(formatted);else result[item.name] = formatted?.f || formatted;
119
- return result;
120
- }, output);
121
- return resp;
122
- };
123
- return _get;
124
- }
125
- function HeaderPicker(view, schema) {
126
- const metrics = schema.doc.metrics;
127
- const dimensions = schema.doc.dimensions;
128
- const all = [...metrics, ...dimensions];
129
- const result = view.columns.reduce((result, item) => {
130
- const column = all.find(f => f.name === item.name) || item;
131
- result.push(column.title || column.name);
132
- return result;
133
- }, []);
134
- return result;
135
- }
136
-
137
- //const BASE_URL = 'http://localhost:8081';
138
- const BASE_URL = 'https://report-api.netcapital.pro';
139
- const apiClient = axios__default.default.create({
140
- baseURL: BASE_URL,
141
- headers: {
142
- 'Content-Type': 'application/json'
143
- }
144
- });
145
-
146
- // Cache for dashboard metadata
147
- const dashboardMetaCache = {};
148
-
149
- /**
150
- * Helper function to get the first available dashboard ID from cache
151
- * @returns {string|null} First dashboard ID or null if cache is empty
152
- */
153
- const getFirstCachedDashboardId = () => {
154
- const cachedIds = Object.keys(dashboardMetaCache);
155
- return cachedIds.length > 0 ? cachedIds[0] : null;
156
- };
157
- const Api = {
158
- setAuth(auth) {
159
- this.auth = auth;
160
- const token = auth?.token;
161
- const accessToken = token?.accessToken;
162
- if (!accessToken) return;
163
- apiClient.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
164
- },
165
- /**
166
- * Load and cache dashboard metadata
167
- * @param {Object} params - Parameters object
168
- * @param {string} params.dashboardId - Dashboard ID
169
- * @returns {Promise} Dashboard metadata object
170
- */
171
- loadDashboardMeta: async ({
172
- dashboardId
173
- }) => {
174
- const {
175
- data
176
- } = await apiClient.get(`/dashboard-meta/${dashboardId}`);
177
-
178
- // Cache the metadata
179
- dashboardMetaCache[dashboardId] = {
180
- dashboards: data.dashboards || {},
181
- charts: data.charts || {},
182
- reports: data.reports || {},
183
- reportMetadata: data.reportMetadata || {},
184
- dateRanges: data.dateRanges || []
185
- };
186
- return dashboardMetaCache[dashboardId];
187
- },
188
- getDashboard: async ({
189
- id,
190
- dashboardId
191
- }) => {
192
- // Use provided dashboardId or fall back to first cached dashboard
193
- const cacheKey = dashboardId || getFirstCachedDashboardId();
194
-
195
- // Check cache first
196
- if (cacheKey && dashboardMetaCache[cacheKey]?.dashboards?.[id]) {
197
- return dashboardMetaCache[cacheKey].dashboards[id];
198
- }
199
-
200
- // Fall back to HTTP request
201
- const {
202
- data
203
- } = await apiClient.get(`/entity/dashboards/${id}`);
204
- return data;
205
- },
206
- /**
207
- * Get chart by ID
208
- * @param {Object} params - Parameters object
209
- * @param {string} params.id - Chart ID
210
- * @param {string} [params.dashboardId] - Optional dashboard ID for cache lookup
211
- * @returns {Promise} Axios response promise
212
- */
213
- getChart: async ({
214
- id,
215
- dashboardId
216
- }) => {
217
- // Use provided dashboardId or fall back to first cached dashboard
218
- const cacheKey = dashboardId || getFirstCachedDashboardId();
219
-
220
- // Check cache first
221
- if (cacheKey && dashboardMetaCache[cacheKey]?.charts?.[id]) {
222
- return dashboardMetaCache[cacheKey].charts[id];
223
- }
224
-
225
- // Fall back to HTTP request
226
- const {
227
- data
228
- } = await apiClient.get(`/entity/charts/${id}`);
229
- return data;
230
- },
231
- /**
232
- * Get report by ID
233
- * @param {Object} params - Parameters object
234
- * @param {string} params.id - Report ID
235
- * @param {string} [params.dashboardId] - Optional dashboard ID for cache lookup
236
- * @returns {Promise} Axios response promise
237
- */
238
- getReport: async ({
239
- id,
240
- dashboardId
241
- }) => {
242
- // Use provided dashboardId or fall back to first cached dashboard
243
- const cacheKey = dashboardId || getFirstCachedDashboardId();
244
-
245
- // Check cache first
246
- if (cacheKey && dashboardMetaCache[cacheKey]?.reports?.[id]) {
247
- return dashboardMetaCache[cacheKey].reports[id];
248
- }
249
-
250
- // Fall back to HTTP request
251
- const {
252
- data
253
- } = await apiClient.get(`/entity/reports/${id}`);
254
- return data;
255
- },
256
- /**
257
- * Get report schema/metadata by ID
258
- * @param {Object} params - Parameters object
259
- * @param {string} params.id - Report ID
260
- * @param {string} [params.dashboardId] - Optional dashboard ID for cache lookup
261
- * @returns {Promise} Axios response promise
262
- */
263
- getReportSchema: async ({
264
- id,
265
- dashboardId,
266
- query = {}
267
- }) => {
268
- // Use provided dashboardId or fall back to first cached dashboard
269
- const cacheKey = dashboardId || getFirstCachedDashboardId();
270
-
271
- // Check cache first
272
- if (cacheKey && dashboardMetaCache[cacheKey]?.reportMetadata?.[id]) {
273
- return dashboardMetaCache[cacheKey].reportMetadata[id];
274
- }
275
-
276
- // Fall back to HTTP request
277
- // console.log({getReportSchema:{id,query}});
278
- const {
279
- data
280
- } = await apiClient.post(`/reports/${id}/metadata`, query);
281
- return data;
282
- },
283
- /**
284
- * Run report with optional query parameters
285
- * @param {Object} params - Parameters object
286
- * @param {string} params.id - Report ID
287
- * @param {Object} [params.query] - Optional query object to send in request body
288
- * @returns {Promise} Axios response promise
289
- */
290
- runReport: async ({
291
- id,
292
- query = {}
293
- }) => {
294
- // console.log({runReport:{id,query}});
295
-
296
- const {
297
- data
298
- } = await apiClient.post(`/reports/${id}/run`, query);
299
- return data;
300
- },
301
- getDateRanges: async ({
302
- dashboardId
303
- } = {}) => {
304
- // Use provided dashboardId or fall back to first cached dashboard
305
- const cacheKey = dashboardId || getFirstCachedDashboardId();
306
-
307
- // Check cache first
308
- if (cacheKey && dashboardMetaCache[cacheKey]?.dateRanges) {
309
- return dashboardMetaCache[cacheKey].dateRanges;
310
- }
311
-
312
- // Fall back to HTTP request
313
- const {
314
- data
315
- } = await apiClient.get(`/globals/date-ranges`);
316
- return data;
317
- }
318
- };
319
-
320
- const useStyles = styles.makeStyles(theme => ({
321
- headerRow: {
322
- fontFamily: theme.typography.fontFamily,
323
- fontSize: theme.typography.fontSize
324
- },
325
- tableRow: {
326
- fontFamily: theme.typography.fontFamily,
327
- fontSize: theme.typography.fontSize
328
- },
329
- oddTableRow: {
330
- fontFamily: theme.typography.fontFamily,
331
- fontSize: theme.typography.fontSize
332
- },
333
- headerCell: {
334
- backgroundColor: "white",
335
- padding: "4px !important"
336
- }
337
- // tableCell:{
338
- // // padding:"4px !important"
339
- // },
340
- }));
341
- const dateRangeFormats = {
342
- "none": "YYYY-MM-dd",
343
- "day": "MMM dd",
344
- "week": "MMM dd",
345
- "month": "YYYY MMM",
346
- "year": "YYYY"
347
- };
348
- function GoogleChart({
349
- chart,
350
- source,
351
- view,
352
- report,
353
- schema,
354
- dashboard,
355
- query
356
- }) {
357
- const [data, setData] = React__namespace.default.useState([]);
358
- const classes = useStyles();
359
- const [dateRanges, setDateRanges] = React__namespace.default.useState([]);
360
- React.useEffect(() => {
361
- (async () => {
362
- const data = await Api.getDateRanges();
363
- setDateRanges(data);
364
- })();
365
- }, []);
366
- const dateRangeFormat = React.useMemo(() => {
367
- const defaultFormat = 'YYYY-MM-dd';
368
- const name = query?.date_range?.name;
369
- const dateRange = dateRanges.find(f => f.name === name);
370
- if (!dateRange) return defaultFormat;
371
- const format = dateRangeFormats[dateRange?.granularity] || defaultFormat;
372
- return format;
373
- }, [dateRanges, query]);
374
- const getOptions = data => {
375
- if (chart?.doc.chart?.type === 'Table') {
376
- return {
377
- ...chart?.doc.chart?.options,
378
- cssClassNames: classes
379
- };
380
- } else if (chart?.doc.chart?.type === 'AreaChart') {
381
- const hAxisFromChart = chart?.doc.chart?.options?.hAxis || {};
382
- const hAxisDefaults = {
383
- ticks: data.slice(1).map(row => row[0]),
384
- format: dateRangeFormat
385
- };
386
- const hAxis = {
387
- ...hAxisDefaults,
388
- ...hAxisFromChart
389
- };
390
-
391
- // console.log({GoogleChart:{chart,source,view,report,schema,query,dateRanges,dateRangeFormat,ticks:hAxis.ticks}})
392
-
393
- return {
394
- ...chart?.doc.chart?.options,
395
- ...{
396
- hAxis,
397
- focusTarget: 'category'
398
- }
399
- };
400
- } else return chart?.doc.chart?.options;
401
- };
402
- React__namespace.default.useEffect(() => {
403
- if (!chart || !view || !source || !report || !schema) return;
404
- let result = [];
405
- result.push(HeaderPicker(view, schema));
406
- const valuePicker = ValuePicker(view, schema);
407
- source?.forEach(item => {
408
- const val = valuePicker(item);
409
- result.push(val);
410
- });
411
- source?.length ? setData(result) : setData();
412
- }, [chart, source, view, report, schema]);
413
- return data ? /*#__PURE__*/React__namespace.default.createElement(reactGoogleCharts.Chart, _extends({
414
- width: chart?.doc.size?.width || '100%',
415
- height: dashboard ? chart?.doc.size?.height || '300px' : '100%',
416
- chartType: chart?.doc.chart?.type,
417
- data: data,
418
- options: getOptions(data)
419
- }, chart?.doc.chart?.props)) : /*#__PURE__*/React__namespace.default.createElement("div", null);
420
- }
421
-
422
- function LabelChart({
423
- chart,
424
- source,
425
- view,
426
- report,
427
- schema
428
- }) {
429
- const [data, setData] = React__namespace.default.useState([]);
430
- const [value, setValue] = React__namespace.default.useState();
431
- const [subText, setSubText] = React__namespace.default.useState();
432
- React__namespace.default.useEffect(() => {
433
- if (!chart || !view || !source || !report || !schema) return;
434
- let result = [];
435
- // result.push(HeaderPicker(view, schema));
436
- const valuePicker = ValuePicker(view, schema);
437
- source.forEach(item => result.push(valuePicker(item)));
438
- setData(result);
439
- const options = chart?.doc?.chart?.options || {};
440
- const valueIndex = options?.index || 0;
441
- if (result.length > 0) setValue(result[0][valueIndex]);
442
- if (options.subText?.format) {
443
- nunjucks__default.default.configure({
444
- autoescape: false
445
- });
446
- const valuePickerObj = ValuePicker(view, schema, 'object');
447
- const val = valuePickerObj(source[0]);
448
- const subTextRendered = nunjucks__default.default.renderString(options.subText?.format, val);
449
- setSubText(subTextRendered);
450
- }
451
- }, [chart, source, view, report, schema]);
452
- return /*#__PURE__*/React__namespace.default.createElement("div", {
453
- style: {
454
- display: "flex",
455
- justifyContent: "center",
456
- alignContent: "center",
457
- alignItems: "center",
458
- height: "100%",
459
- flexDirection: "column"
460
- }
461
- }, /*#__PURE__*/React__namespace.default.createElement(Typography__default.default, {
462
- variant: "h6"
463
- }, value?.f || value), /*#__PURE__*/React__namespace.default.createElement(Typography__default.default, {
464
- variant: "subtitle1"
465
- }, subText));
466
- }
467
-
468
- const Components = {
469
- GoogleChart,
470
- LabelChart
471
- };
472
- function Internal(name, props) {
473
- if (typeof Components[name] !== "undefined") {
474
- return /*#__PURE__*/React__namespace.default.createElement(Components[name], props);
475
- } else return /*#__PURE__*/React__namespace.default.createElement(LinearIndeterminate, props);
476
- }
477
-
478
- /**
479
- * CheckboxMultiAutocomplete
480
- *
481
- * Props:
482
- * - items: Array<{ key: string, value: string }>
483
- * - selectedKeys?: string[] (controlled)
484
- * - defaultSelectedKeys?: string[] (uncontrolled)
485
- * - onChange?: (selectedKeys: string[], selectedItems: {key, value}[]) => void
486
- * - inputValue?: string (controlled input)
487
- * - defaultInputValue?: string (uncontrolled input)
488
- * - onInputChange?: (text: string) => void (debounced by debounceMs)
489
- * - debounceMs?: number (default 300)
490
- * - label?, placeholder?, loading?, disabled?, size? = 'small', error?, helperText?,
491
- * limitTags? = 3, disableClearable?, id?, textFieldProps?
492
- */
493
-
494
- function useDebouncedCallback(fn, delay = 300) {
495
- const fnRef = React.useRef(fn);
496
- const timer = React.useRef(null);
497
- fnRef.current = fn;
498
- React.useEffect(() => () => {
499
- if (timer.current) window.clearTimeout(timer.current);
500
- }, []);
501
- return React__namespace.useCallback((...args) => {
502
- if (!fnRef.current) return;
503
- if (timer.current) window.clearTimeout(timer.current);
504
- timer.current = window.setTimeout(() => {
505
- fnRef.current && fnRef.current(...args);
506
- }, delay);
507
- }, [delay]);
508
- }
509
- const icon = /*#__PURE__*/React__namespace.createElement(CheckBoxOutlineBlankIcon__default.default, {
510
- fontSize: "small"
511
- });
512
- const checkedIcon = /*#__PURE__*/React__namespace.createElement(CheckBoxIcon__default.default, {
513
- fontSize: "small"
514
- });
515
- function CheckboxMultiAutocomplete({
516
- items,
517
- selectedKeys,
518
- defaultSelectedKeys,
519
- onChange,
520
- inputValue,
521
- defaultInputValue,
522
- onInputChange,
523
- debounceMs = 300,
524
- label,
525
- placeholder,
526
- loading,
527
- disabled,
528
- size = "small",
529
- error,
530
- helperText,
531
- limitTags = 3,
532
- disableClearable,
533
- id,
534
- textFieldProps
535
- }) {
536
- // Normalize props to avoid "is not iterable" and similar runtime errors
537
- const safeItems = React.useMemo(() => Array.isArray(items) ? items : [], [items]);
538
-
539
- // Controlled/uncontrolled selection
540
- const isSelectionControlled = Array.isArray(selectedKeys);
541
- const [innerKeys, setInnerKeys] = React.useState(Array.isArray(defaultSelectedKeys) ? defaultSelectedKeys : []);
542
- const currentKeys = isSelectionControlled ? selectedKeys : innerKeys;
543
-
544
- // Map lookups for efficiency
545
- const byKey = React.useMemo(() => {
546
- const m = new Map();
547
- for (const it of safeItems) m.set(it && it.key, it);
548
- return m;
549
- }, [safeItems]);
550
- const selectedItems = React.useMemo(() => (Array.isArray(currentKeys) ? currentKeys : []).map(k => byKey.get(k)).filter(Boolean), [currentKeys, byKey]);
551
-
552
- // Controlled/uncontrolled input
553
- const isInputControlled = typeof inputValue === "string";
554
- const [innerInput, setInnerInput] = React.useState(typeof defaultInputValue === "string" ? defaultInputValue : "");
555
- const currentInput = isInputControlled ? inputValue : innerInput;
556
- const debouncedInput = useDebouncedCallback(text => {
557
- onInputChange && onInputChange(text);
558
- }, debounceMs);
559
- const valueForAutocomplete = selectedItems; // MUI expects full option objects
560
-
561
- return /*#__PURE__*/React__namespace.createElement(material.FormControl, {
562
- fullWidth: true,
563
- error: error,
564
- disabled: disabled
565
- }, /*#__PURE__*/React__namespace.createElement(material.Autocomplete, {
566
- openOnFocus: true,
567
- forcePopupIcon: true,
568
- id: id,
569
- multiple: true,
570
- disableCloseOnSelect: true,
571
- options: safeItems,
572
- value: valueForAutocomplete,
573
- inputValue: currentInput,
574
- getOptionLabel: o => o && typeof o === "object" ? o.value ?? "" : "",
575
- isOptionEqualToValue: (option, value) => option && value && option.key === value.key,
576
- loading: loading,
577
- limitTags: limitTags,
578
- disableClearable: disableClearable,
579
- onChange: (event, newValue /* array of option objects */) => {
580
- const newKeys = Array.isArray(newValue) ? newValue.map(o => o && o.key) : [];
581
- if (!isSelectionControlled) setInnerKeys(newKeys);
582
- onChange && onChange(newKeys, Array.isArray(newValue) ? newValue : []);
583
- },
584
- onInputChange: (event, newInput, reason) => {
585
- if (!isInputControlled) setInnerInput(newInput ?? "");
586
- if (reason === "input") {
587
- debouncedInput(newInput ?? "");
588
- } else if (reason === "clear") {
589
- debouncedInput("");
590
- }
591
- },
592
- renderOption: (props, option, {
593
- selected
594
- }) => /*#__PURE__*/React__namespace.createElement("li", _extends({}, props, {
595
- key: option && option.key || Math.random().toString(36)
596
- }), /*#__PURE__*/React__namespace.createElement(material.Checkbox, {
597
- icon: icon,
598
- checkedIcon: checkedIcon,
599
- style: {
600
- marginRight: 8
601
- },
602
- checked: !!selected
603
- }), option && option.value),
604
- renderTags: (tagValue, getTagProps) => (Array.isArray(tagValue) ? tagValue : []).map((option, index) => /*#__PURE__*/React__namespace.createElement(material.Chip, _extends({}, getTagProps({
605
- index
606
- }), {
607
- key: option && option.key || index,
608
- label: option && option.value || ""
609
- }))),
610
- renderInput: params => /*#__PURE__*/React__namespace.createElement(material.TextField, _extends({}, params, {
611
- label: label,
612
- placeholder: placeholder,
613
- InputProps: {
614
- ...params.InputProps,
615
- endAdornment: /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, loading ? /*#__PURE__*/React__namespace.createElement(material.CircularProgress, {
616
- size: 18
617
- }) : null, params.InputProps.endAdornment)
618
- },
619
- size: size
620
- }, textFieldProps))
621
- }), helperText ? /*#__PURE__*/React__namespace.createElement(material.FormHelperText, null, helperText) : null);
622
- }
623
-
624
- async function fetchItems(query, filter) {
625
- if (!filter?.source) return [];
626
- const data = await Api.runReport({
627
- id: filter.source
628
- });
629
- return data.map(d => {
630
- const m = {
631
- key: d[filter.field],
632
- value: d[filter.field]
633
- };
634
- return m;
635
- });
636
- }
637
- const ChartFilterMultiSelect = ({
638
- filter,
639
- channel,
640
- query
641
- }) => {
642
- const [items, setItems] = React.useState([]);
643
- const [selected, setSelected] = React.useState([]);
644
- const [loading, setLoading] = React.useState(false);
645
- const [inputQuery, setInputQuery] = React.useState("");
646
- React.useEffect(() => {
647
- setSelected(query?.filter?.[filter?.filter] || []);
648
- }, [query]);
649
- React.useEffect(() => {
650
- (async () => {
651
- setLoading(true);
652
- const data = await fetchItems(query, filter);
653
- setItems(data);
654
- setLoading(false);
655
- })();
656
- }, [inputQuery]);
657
- return /*#__PURE__*/React__namespace.default.createElement("div", {
658
- style: {
659
- display: "flex"
660
- }
661
- }, /*#__PURE__*/React__namespace.default.createElement("div", {
662
- style: {
663
- maxWidth: 640,
664
- minWidth: 200
665
- }
666
- }, /*#__PURE__*/React__namespace.default.createElement(CheckboxMultiAutocomplete, {
667
- id: filter?.title,
668
- label: filter?.title,
669
- placeholder: "Type to search\u2026",
670
- items: items,
671
- selectedKeys: selected,
672
- onChange: (keys, selectedItems) => {
673
- setSelected(keys);
674
- channel.emit('filterChanged', filter, {
675
- [filter.filter]: keys
676
- });
677
- },
678
- onInputChange: text => {
679
- setInputQuery(text);
680
- },
681
- loading: loading,
682
- debounceMs: 300,
683
- helperText: selected.length ? `${selected.length} selected` : ""
684
- })));
685
- };
686
-
687
- function SingleSelect({
688
- items,
689
- value,
690
- label,
691
- onChange,
692
- sx = {
693
- width: '100%'
694
- }
695
- }) {
696
- // Check if the current value exists in items, otherwise use empty string
697
- const validValue = items.some(itm => itm.key === value) ? value : '';
698
- return /*#__PURE__*/React__namespace.default.createElement(Box__default.default, {
699
- sx: sx
700
- }, /*#__PURE__*/React__namespace.default.createElement(FormControl__default.default, {
701
- fullWidth: true
702
- }, /*#__PURE__*/React__namespace.default.createElement(InputLabel__default.default, {
703
- id: "demo-simple-select-label"
704
- }, label), /*#__PURE__*/React__namespace.default.createElement(Select__default.default, {
705
- labelId: "demo-simple-select-label",
706
- id: "demo-simple-select",
707
- value: validValue,
708
- label: label,
709
- onChange: onChange,
710
- MenuProps: {
711
- style: {
712
- maxHeight: '300px'
713
- }
714
- }
715
- // sx={{height:'40px'}}
716
- ,
717
- size: "small"
718
- }, items.map(itm => {
719
- const {
720
- key,
721
- value
722
- } = itm;
723
- return /*#__PURE__*/React__namespace.default.createElement(MenuItem__default.default, {
724
- key: key,
725
- value: key
726
- }, value);
727
- }))));
728
- }
729
-
730
- const ChartFilterDateRange = ({
731
- filter,
732
- channel,
733
- query
734
- }) => {
735
- const [items, setItems] = React.useState([]);
736
- const [selected, setSelected] = React.useState("");
737
- React.useEffect(() => {
738
- setSelected(query?.date_range?.name);
739
- }, [query]);
740
- React.useEffect(() => {
741
- (async () => {
742
- const data = await Api.getDateRanges();
743
- const items = data.filter(f => filter.allowedOptions.length > 0 ? filter.allowedOptions.some(o => o === f.name) : true).map(d => {
744
- return {
745
- key: d.name,
746
- value: d.title
747
- };
748
- });
749
- setItems(items);
750
- })();
751
- }, []);
752
- return /*#__PURE__*/React__namespace.default.createElement("div", {
753
- style: {
754
- minWidth: "200px",
755
- maxWidth: "640px"
756
- }
757
- }, /*#__PURE__*/React__namespace.default.createElement(SingleSelect, {
758
- items: items,
759
- value: selected,
760
- label: filter?.title,
761
- onChange: (e, newValue) => {
762
- const val = e.target.value;
763
- setSelected(val);
764
- channel.emit('filterChanged', filter, {
765
- date_range: {
766
- name: val
767
- }
768
- });
769
- }
770
- }));
771
- };
772
-
773
- const ChartFilters = ({
774
- filters = [],
775
- channel,
776
- query
777
- }) => {
778
- return /*#__PURE__*/React__namespace.default.createElement("div", {
779
- style: {
780
- display: "flex",
781
- flexWrap: "wrap",
782
- gap: "8px"
783
- }
784
- }, filters.map(f => {
785
- if (f.type === 'multi-select') {
786
- return /*#__PURE__*/React__namespace.default.createElement(ChartFilterMultiSelect, {
787
- key: f.title,
788
- channel: channel,
789
- filter: f,
790
- query: query
791
- });
792
- } else if (f.type === 'date-range') {
793
- return /*#__PURE__*/React__namespace.default.createElement(ChartFilterDateRange, {
794
- key: f.title,
795
- channel: channel,
796
- filter: f,
797
- query: query
798
- });
799
- } else {
800
- return null;
801
- }
802
- }));
803
- };
804
-
805
- var useChannel = channel => {
806
- const channelRef = React__namespace.default.useRef(channel || new EventEmitter__default.default());
807
- // React.useEffect(() => {
808
- // }, []);
809
- return channelRef.current;
810
- };
811
-
812
- var useFilterManager = channel => {
813
- const filterRef = React__namespace.default.useState({});
814
- const onFilterChanged = React__namespace.default.useCallback((entity, value) => {
815
- let merged = {
816
- ...filterRef.current,
817
- ...value
818
- };
819
- filterRef.current = merged;
820
- for (var field in merged) {
821
- if (field !== 'date_range' && !merged[field].length) delete merged[field];
822
- }
823
- channel?.emit('mergedFilterChanged', {
824
- value: merged
825
- });
826
- }, [channel]);
827
- React__namespace.default.useEffect(() => {
828
- channel?.on('filterChanged', onFilterChanged);
829
- return () => {
830
- channel?.off('filterChanged', onFilterChanged);
831
- };
832
- }, [channel]);
833
- };
834
-
835
- var Chart = ({
836
- id,
837
- cache,
838
- dashboard,
839
- channel,
840
- ...props
841
- }) => {
842
- const [chart, setChart] = React__namespace.default.useState();
843
- const [report, setReport] = React__namespace.default.useState();
844
- const [schema, setSchema] = React__namespace.default.useState();
845
- const [source, setSource] = React__namespace.default.useState();
846
- const [chartType, setChartType] = React__namespace.default.useState(Internal());
847
- const [activeView, setActiveView] = React__namespace.default.useState();
848
- const [activeViewIndex, setActiveViewIndex] = React__namespace.default.useState(0);
849
- const [loading, setLoading] = React__namespace.default.useState(false);
850
- const [filter, setFilter] = React__namespace.default.useState();
851
- const [dirty, setDirty] = React__namespace.default.useState(false);
852
- const filterRef = React__namespace.default.useRef({
853
- value: props?.filter
854
- });
855
- const [currentQuery, setCurrentQuery] = React__namespace.default.useState({});
856
- const {
857
- ref,
858
- inView,
859
- entry
860
- } = reactIntersectionObserver.useInView({
861
- /* Optional options */
862
- threshold: 0.10,
863
- delay: 1000
864
- });
865
- const channelUsed = useChannel(channel);
866
- useFilterManager(channelUsed);
867
-
868
- // console.log(id, inView);
869
-
870
- const init = async () => {
871
- // CHART
872
- const chartId = id;
873
- const chartTemp = cache?.[chartId] || (await Api.getChart({
874
- id: chartId
875
- }));
876
-
877
- // console.log({chartTemp});
878
-
879
- // REPORT
880
- const reportId = chartTemp.doc.source?.id;
881
- const reportTemp = reportId ? cache?.[reportId] || (await Api.getReport({
882
- id: reportId
883
- })) : undefined;
884
-
885
- // SCHEMA
886
- const schemaTemp = cache?.[`schema_${reportId}`] || props?.schema || (await Api.getReportSchema({
887
- id: reportId
888
- }));
889
-
890
- // console.log({schemaTemp});
891
-
892
- // ACTIVE VIEW
893
- const activeViewTemp = chartTemp.doc?.view?.[0];
894
- setActiveViewIndex(0);
895
- setReport(reportTemp);
896
- setChart(chartTemp);
897
- setActiveView(activeViewTemp);
898
- setSchema(schemaTemp);
899
- //setSchema({});
900
-
901
- setDirty(true);
902
-
903
- // // SOURCE
904
- // if (inView) {
905
- // const sourceId = chartTemp.doc.source.id;
906
- // const sourceTemp = await Report.run(undefined, { id: sourceId });
907
- // setSource(chartTemp.doc.source.reverse ? sourceTemp.reverse() : sourceTemp);
908
- // }
909
- };
910
- const reload = async () => {
911
- setChartType(Internal(chart.doc.chart?.component, {
912
- view: activeView,
913
- source: source,
914
- chart: chart,
915
- report: report,
916
- schema: schema,
917
- dashboard: dashboard,
918
- query: currentQuery
919
- }));
920
- };
921
- const onViewChanged = React__namespace.default.useCallback(event => {
922
- const viewIndex = event.target.value;
923
- setActiveViewIndex(viewIndex);
924
- setActiveView(chart.doc.view[viewIndex]);
925
- }, [chart]);
926
- React__namespace.default.useEffect(() => {
927
- if (!id) return;
928
- init().catch(error => {
929
- console.error(error.message);
930
- });
931
- }, [id]);
932
- React__namespace.default.useEffect(() => {
933
- if (!chart || !source || chart?.doc?.source?.id && !report || !schema) return;
934
- reload().catch(error => {
935
- console.error(error.message);
936
- });
937
- }, [chart, source, activeView, report, schema]);
938
- const loadSource = userFilter => {
939
- const queryFilter = report?.doc.query.filter || {};
940
- const finalFilter = {
941
- ...queryFilter,
942
- ...props?.filter,
943
- ...userFilter?.value
944
- };
945
-
946
- // const finalFilter = {...props?.filter,...userFilter?.value };
947
-
948
- // console.log({queryFilter,userFilter,propsFilter:props.filter,finalFilter});
949
-
950
- const date_range = finalFilter.date_range || report?.doc.query.date_range;
951
- delete finalFilter.date_range;
952
- setDirty(false);
953
- setFilter();
954
- setLoading(true);
955
- if (chart?.doc?.source?.type === 'context') {
956
- setSource({
957
- filter: finalFilter
958
- });
959
- setLoading(false);
960
- return;
961
- }
962
- const query = {
963
- filter: finalFilter,
964
- date_range,
965
- parameters: props?.params
966
- };
967
-
968
- //console.log('loadSource',{reportId: report.id, query});
969
-
970
- setCurrentQuery(query);
971
- Api.runReport({
972
- id: report.id,
973
- query
974
- }).then(response => {
975
- setSource(chart.doc.source.reverse ? response.reverse() : response);
976
- }).catch(error => {
977
- setSource([]);
978
- }).finally(() => {
979
- setLoading(false);
980
- });
981
- };
982
- const onMergedFilterChanged = merged => {
983
- // console.log({onMergedFilterChanged:merged});
984
- filterRef.current = merged;
985
- if (inView) loadSource(merged);else {
986
- setFilter(merged);
987
- setDirty(true);
988
- }
989
- };
990
- React__namespace.default.useEffect(() => {
991
- channelUsed?.on('mergedFilterChanged', onMergedFilterChanged);
992
- return () => {
993
- channelUsed?.off('mergedFilterChanged', onMergedFilterChanged);
994
- };
995
- }, [channelUsed, report, chart, inView]);
996
- React__namespace.default.useEffect(() => {
997
- if (inView && dirty) loadSource(filter);
998
- }, [inView, dirty]);
999
- return /*#__PURE__*/React__namespace.default.createElement(Paper__default.default, {
1000
- ref: ref,
1001
- style: {
1002
- margin: "4px",
1003
- padding: "16px",
1004
- flexGrow: dashboard ? undefined : 1,
1005
- display: "flex",
1006
- flexDirection: "column",
1007
- gap: '16px'
1008
- },
1009
- elevation: 0
1010
- }, /*#__PURE__*/React__namespace.default.createElement(LinearIndeterminate, {
1011
- style: {
1012
- visibility: loading ? 'visible' : 'hidden'
1013
- }
1014
- }), /*#__PURE__*/React__namespace.default.createElement("div", {
1015
- style: {
1016
- display: "flex"
1017
- }
1018
- }, /*#__PURE__*/React__namespace.default.createElement("div", null, chart && /*#__PURE__*/React__namespace.default.createElement("div", {
1019
- style: {
1020
- display: "flex",
1021
- alignItems: "center",
1022
- lineHeight: 0
1023
- }
1024
- }, /*#__PURE__*/React__namespace.default.createElement(Typography__default.default, {
1025
- noWrap: true,
1026
- variant: "h6"
1027
- }, props?.title || chart.doc.name, " "))), /*#__PURE__*/React__namespace.default.createElement("div", {
1028
- style: {
1029
- flexGrow: 1
1030
- }
1031
- }), /*#__PURE__*/React__namespace.default.createElement("div", null, chart?.doc?.view?.length > 1 && /*#__PURE__*/React__namespace.default.createElement(FormControl__default$1.default, null, /*#__PURE__*/React__namespace.default.createElement(Select__default$1.default, {
1032
- labelId: "date-range-select-label",
1033
- id: "date-range-select",
1034
- value: activeViewIndex,
1035
- onChange: onViewChanged,
1036
- style: {
1037
- fontSize: "12px"
1038
- },
1039
- disableUnderline: true
1040
- }, chart.doc.view.map((item, index) => /*#__PURE__*/React__namespace.default.createElement(MenuItem__default$1.default, {
1041
- key: index,
1042
- value: index
1043
- }, item.title)))))), /*#__PURE__*/React__namespace.default.createElement("div", {
1044
- style: {
1045
- minHeight: chart?.doc?.size?.height || (dashboard ? "300px" : "0"),
1046
- position: "relative",
1047
- paddingTop: chart?.doc?.size?.vpad,
1048
- paddingBottom: chart?.doc?.size?.vpad,
1049
- flexGrow: dashboard ? undefined : 1
1050
- }
1051
- }, /*#__PURE__*/React__namespace.default.createElement(ChartFilters, {
1052
- filters: chart?.doc?.filters,
1053
- channel: channelUsed,
1054
- query: currentQuery
1055
- }), chartType));
1056
- };
1057
-
1058
- function Dashboard({
1059
- id = "sample_dashboard",
1060
- auth,
1061
- params
1062
- }) {
1063
- const [dashboard, setDashboard] = React__namespace.default.useState();
1064
- //const [schema, setSchema] = React.useState();
1065
- const [schema] = React__namespace.default.useState();
1066
- const [rows, setRows] = React__namespace.default.useState([]);
1067
- const cache = React__namespace.default.useRef({});
1068
- const channel = useChannel();
1069
- useFilterManager(channel);
1070
- const init = async () => {
1071
- Api.setAuth(auth);
1072
- await Api.loadDashboardMeta({
1073
- dashboardId: id
1074
- });
1075
-
1076
- // get dashboard entity
1077
- const dashboardTemp = await Api.getDashboard({
1078
- id: id
1079
- });
1080
- cache.current[dashboardTemp?.id] = dashboardTemp;
1081
- setDashboard(dashboardTemp);
1082
-
1083
- // create rows and columns
1084
- await create_rows_and_columns(dashboardTemp);
1085
- };
1086
- const create_rows_and_columns = async entity => {
1087
- const srcRows = entity?.doc?.rows || [];
1088
- const targetRows = [];
1089
- for (let i = 0; i < srcRows.length; i++) {
1090
- const row = srcRows[i];
1091
- row.columns?.forEach(column => {
1092
- // filter
1093
- if (column.override?.filter?.length) {
1094
- const filter = {};
1095
- column.override.filter.forEach(item => {
1096
- if (item.hasOwnProperty('value')) filter[item.field] = [item.value];
1097
- // else filter[item.field] = [sourceDataRow[item.field]];
1098
- });
1099
- column.filter = filter;
1100
- }
1101
- });
1102
- targetRows.push(row);
1103
- }
1104
- setRows(targetRows);
1105
- };
1106
- React__namespace.default.useEffect(() => {
1107
- if (!id) return;
1108
- init().catch(error => console.error(error.message));
1109
- }, [id]);
1110
- return /*#__PURE__*/React__namespace.default.createElement(Container__default.default, null, /*#__PURE__*/React__namespace.default.createElement(Grid__default.default, {
1111
- container: true
1112
- }, rows?.map((row, index) =>
1113
- /*#__PURE__*/
1114
- // hasResourceRole(row) &&
1115
- React__namespace.default.createElement(Grid__default.default, {
1116
- key: index,
1117
- container: true,
1118
- item: true
1119
- }, row?.columns?.map((column, index) => /*#__PURE__*/React__namespace.default.createElement(Grid__default.default, _extends({
1120
- key: index,
1121
- item: true
1122
- }, column.layout), /*#__PURE__*/React__namespace.default.createElement(Chart, {
1123
- auth: auth,
1124
- cache: cache.current,
1125
- id: column.id,
1126
- dashboard: dashboard,
1127
- schema: schema,
1128
- channel: null,
1129
- title: column.title,
1130
- filter: column.filter,
1131
- params: params
1132
- })))))));
1133
- }
1134
-
1135
- var index = {
1136
- Chart,
1137
- Dashboard
1138
- };
1139
-
1140
- exports.default = index;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("@material-ui/core/Paper"),a=require("@material-ui/core/styles"),r=require("@material-ui/core/LinearProgress"),n=require("react-google-charts"),l=require("numeral"),o=require("axios"),u=require("@material-ui/core/Typography"),i=require("nunjucks"),s=require("@material-ui/core/FormControl"),d=require("@material-ui/core/Select"),c=require("@material-ui/core/MenuItem"),f=require("react-intersection-observer"),m=require("@mui/material"),p=require("@mui/icons-material/CheckBoxOutlineBlank"),h=require("@mui/icons-material/CheckBox"),y=require("@mui/material/Box"),g=require("@mui/material/InputLabel"),b=require("@mui/material/MenuItem"),v=require("@mui/material/FormControl"),E=require("@mui/material/Select"),w=require("eventemitter3"),x=require("@material-ui/core/Grid"),S=require("@material-ui/core/Container");function C(e){return e&&e.__esModule?e:{default:e}}function k(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach(function(a){if("default"!==a){var r=Object.getOwnPropertyDescriptor(e,a);Object.defineProperty(t,a,r.get?r:{enumerable:!0,get:function(){return e[a]}})}}),t.default=e,Object.freeze(t)}var q=k(e),M=C(t),I=C(r),R=C(l),T=C(o),A=C(u),z=C(i),O=C(s),F=C(d),_=C(c),Y=C(p),j=C(h),P=C(y),D=C(g),B=C(b),$=C(v),W=C(E),L=C(w),V=C(x),G=C(S);function U(){return U=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var r in a)({}).hasOwnProperty.call(a,r)&&(e[r]=a[r])}return e},U.apply(null,arguments)}const H=a.makeStyles(e=>({root:{width:"100%","& > * + *":{marginTop:e.spacing(2)}}}));function K(e){const t=H();return q.default.createElement("div",U({className:t.root},e),q.default.createElement(I.default,null))}function N(e,t,a="array"){const r=e.columns,n=[...t.doc.metrics,...t.doc.dimensions].reduce((e,t)=>(e[t.name]=t,e),{});return e=>{const t="array"===a?[]:{};return r.reduce((t,r)=>{const l=e[r.name],o=n[r.name];let u=l;return u="timestamp"===o.type?new Date(l):o.format?o.format&&o.prefix?{v:+l,f:o.prefix+" "+R.default(l).format(o.format)}:o.format?{v:+l,f:R.default(l).format(o.format)}:l:l,"array"===a?t.push(u):t[r.name]=u?.f||u,t},t)}}const J="https://report-api.netcapital.pro",Q=T.default.create({baseURL:J,headers:{"Content-Type":"application/json"}}),X={},Z=()=>{const e=Object.keys(X);return e.length>0?e[0]:null},ee={setBaseUrl(e){Q.defaults.baseURL=e||J},setToken(e){e&&(Q.defaults.headers.common.Authorization=`Bearer ${e}`)},loadDashboardMeta:async({dashboardId:e})=>{const{data:t}=await Q.get(`/dashboard-meta/${e}`);return X[e]={dashboards:t.dashboards||{},charts:t.charts||{},reports:t.reports||{},reportMetadata:t.reportMetadata||{},dateRanges:t.dateRanges||[]},X[e]},getDashboard:async({id:e,dashboardId:t})=>{const a=t||Z();if(a&&X[a]?.dashboards?.[e])return X[a].dashboards[e];const{data:r}=await Q.get(`/entity/dashboards/${e}`);return r},getChart:async({id:e,dashboardId:t})=>{const a=t||Z();if(a&&X[a]?.charts?.[e])return X[a].charts[e];const{data:r}=await Q.get(`/entity/charts/${e}`);return r},getReport:async({id:e,dashboardId:t})=>{const a=t||Z();if(a&&X[a]?.reports?.[e])return X[a].reports[e];const{data:r}=await Q.get(`/entity/reports/${e}`);return r},getReportSchema:async({id:e,dashboardId:t,query:a={}})=>{const r=t||Z();if(r&&X[r]?.reportMetadata?.[e])return X[r].reportMetadata[e];const{data:n}=await Q.post(`/reports/${e}/metadata`,a);return n},runReport:async({id:e,query:t={}})=>{const{data:a}=await Q.post(`/reports/${e}/run`,t);return a},getDateRanges:async({dashboardId:e}={})=>{const t=e||Z();if(t&&X[t]?.dateRanges)return X[t].dateRanges;const{data:a}=await Q.get("/globals/date-ranges");return a}},te=a.makeStyles(e=>({headerRow:{fontFamily:e.typography.fontFamily,fontSize:e.typography.fontSize},tableRow:{fontFamily:e.typography.fontFamily,fontSize:e.typography.fontSize},oddTableRow:{fontFamily:e.typography.fontFamily,fontSize:e.typography.fontSize},headerCell:{backgroundColor:"white",padding:"4px !important"}})),ae={none:"YYYY-MM-dd",day:"MMM dd",week:"MMM dd",month:"YYYY MMM",year:"YYYY"};const re={GoogleChart:function({chart:t,source:a,view:r,report:l,schema:o,dashboard:u,query:i}){const[s,d]=q.default.useState([]),c=te(),[f,m]=q.default.useState([]);e.useEffect(()=>{(async()=>{const e=await ee.getDateRanges();m(e)})()},[]);const p=e.useMemo(()=>{const e="YYYY-MM-dd",t=i?.date_range?.name,a=f.find(e=>e.name===t);if(!a)return e;return ae[a?.granularity]||e},[f,i]);return q.default.useEffect(()=>{if(!(t&&r&&a&&l&&o))return;let e=[];e.push(function(e,t){const a=[...t.doc.metrics,...t.doc.dimensions];return e.columns.reduce((e,t)=>{const r=a.find(e=>e.name===t.name)||t;return e.push(r.title||r.name),e},[])}(r,o));const n=N(r,o);a?.forEach(t=>{const a=n(t);e.push(a)}),a?.length?d(e):d()},[t,a,r,l,o]),s?q.default.createElement(n.Chart,U({width:t?.doc.size?.width||"100%",height:u?t?.doc.size?.height||"300px":"100%",chartType:t?.doc.chart?.type,data:s,options:(e=>{if("Table"===t?.doc.chart?.type)return{...t?.doc.chart?.options,cssClassNames:c};if("AreaChart"===t?.doc.chart?.type){const a=t?.doc.chart?.options?.hAxis||{},r={...{ticks:e.slice(1).map(e=>e[0]),format:p},...a};return{...t?.doc.chart?.options,hAxis:r,focusTarget:"category"}}return t?.doc.chart?.options})(s)},t?.doc.chart?.props)):q.default.createElement("div",null)},LabelChart:function({chart:e,source:t,view:a,report:r,schema:n}){const[l,o]=q.default.useState([]),[u,i]=q.default.useState(),[s,d]=q.default.useState();return q.default.useEffect(()=>{if(!(e&&a&&t&&r&&n))return;let l=[];const u=N(a,n);t.forEach(e=>l.push(u(e))),o(l);const s=e?.doc?.chart?.options||{},c=s?.index||0;if(l.length>0&&i(l[0][c]),s.subText?.format){z.default.configure({autoescape:!1});const e=N(a,n,"object")(t[0]),r=z.default.renderString(s.subText?.format,e);d(r)}},[e,t,a,r,n]),q.default.createElement("div",{style:{display:"flex",justifyContent:"center",alignContent:"center",alignItems:"center",height:"100%",flexDirection:"column"}},q.default.createElement(A.default,{variant:"h6"},u?.f||u),q.default.createElement(A.default,{variant:"subtitle1"},s))}};function ne(e,t){return void 0!==re[e]?q.default.createElement(re[e],t):q.default.createElement(K,t)}const le=q.createElement(Y.default,{fontSize:"small"}),oe=q.createElement(j.default,{fontSize:"small"});function ue({items:t,selectedKeys:a,defaultSelectedKeys:r,onChange:n,inputValue:l,defaultInputValue:o,onInputChange:u,debounceMs:i=300,label:s,placeholder:d,loading:c,disabled:f,size:p="small",error:h,helperText:y,limitTags:g=3,disableClearable:b,id:v,textFieldProps:E}){const w=e.useMemo(()=>Array.isArray(t)?t:[],[t]),x=Array.isArray(a),[S,C]=e.useState(Array.isArray(r)?r:[]),k=x?a:S,M=e.useMemo(()=>{const e=new Map;for(const t of w)e.set(t&&t.key,t);return e},[w]),I=e.useMemo(()=>(Array.isArray(k)?k:[]).map(e=>M.get(e)).filter(Boolean),[k,M]),R="string"==typeof l,[T,A]=e.useState("string"==typeof o?o:""),z=R?l:T,O=function(t,a=300){const r=e.useRef(t),n=e.useRef(null);return r.current=t,e.useEffect(()=>()=>{n.current&&window.clearTimeout(n.current)},[]),q.useCallback((...e)=>{r.current&&(n.current&&window.clearTimeout(n.current),n.current=window.setTimeout(()=>{r.current&&r.current(...e)},a))},[a])}(e=>{u&&u(e)},i),F=I;return q.createElement(m.FormControl,{fullWidth:!0,error:h,disabled:f},q.createElement(m.Autocomplete,{openOnFocus:!0,forcePopupIcon:!0,id:v,multiple:!0,disableCloseOnSelect:!0,options:w,value:F,inputValue:z,getOptionLabel:e=>e&&"object"==typeof e?e.value??"":"",isOptionEqualToValue:(e,t)=>e&&t&&e.key===t.key,loading:c,limitTags:g,disableClearable:b,onChange:(e,t)=>{const a=Array.isArray(t)?t.map(e=>e&&e.key):[];x||C(a),n&&n(a,Array.isArray(t)?t:[])},onInputChange:(e,t,a)=>{R||A(t??""),"input"===a?O(t??""):"clear"===a&&O("")},renderOption:(e,t,{selected:a})=>q.createElement("li",U({},e,{key:t&&t.key||Math.random().toString(36)}),q.createElement(m.Checkbox,{icon:le,checkedIcon:oe,style:{marginRight:8},checked:!!a}),t&&t.value),renderTags:(e,t)=>(Array.isArray(e)?e:[]).map((e,a)=>q.createElement(m.Chip,U({},t({index:a}),{key:e&&e.key||a,label:e&&e.value||""}))),renderInput:e=>q.createElement(m.TextField,U({},e,{label:s,placeholder:d,InputProps:{...e.InputProps,endAdornment:q.createElement(q.Fragment,null,c?q.createElement(m.CircularProgress,{size:18}):null,e.InputProps.endAdornment)},size:p},E))}),y?q.createElement(m.FormHelperText,null,y):null)}const ie=({filter:t,channel:a,query:r})=>{const[n,l]=e.useState([]),[o,u]=e.useState([]),[i,s]=e.useState(!1),[d,c]=e.useState("");return e.useEffect(()=>{u(r?.filter?.[t?.filter]||[])},[r]),e.useEffect(()=>{(async()=>{s(!0);const e=await async function(e,t){return t?.source?(await ee.runReport({id:t.source})).map(e=>({key:e[t.field],value:e[t.field]})):[]}(0,t);l(e),s(!1)})()},[d]),q.default.createElement("div",{style:{display:"flex"}},q.default.createElement("div",{style:{maxWidth:640,minWidth:200}},q.default.createElement(ue,{id:t?.title,label:t?.title,placeholder:"Type to search…",items:n,selectedKeys:o,onChange:(e,r)=>{u(e),a.emit("filterChanged",t,{[t.filter]:e})},onInputChange:e=>{c(e)},loading:i,debounceMs:300,helperText:o.length?`${o.length} selected`:""})))};function se({items:e,value:t,label:a,onChange:r,sx:n={width:"100%"}}){const l=e.some(e=>e.key===t)?t:"";return q.default.createElement(P.default,{sx:n},q.default.createElement($.default,{fullWidth:!0},q.default.createElement(D.default,{id:"demo-simple-select-label"},a),q.default.createElement(W.default,{labelId:"demo-simple-select-label",id:"demo-simple-select",value:l,label:a,onChange:r,MenuProps:{style:{maxHeight:"300px"}},size:"small"},e.map(e=>{const{key:t,value:a}=e;return q.default.createElement(B.default,{key:t,value:t},a)}))))}const de=({filter:t,channel:a,query:r})=>{const[n,l]=e.useState([]),[o,u]=e.useState("");return e.useEffect(()=>{u(r?.date_range?.name)},[r]),e.useEffect(()=>{(async()=>{const e=(await ee.getDateRanges()).filter(e=>!(t.allowedOptions.length>0)||t.allowedOptions.some(t=>t===e.name)).map(e=>({key:e.name,value:e.title}));l(e)})()},[]),q.default.createElement("div",{style:{minWidth:"200px",maxWidth:"640px"}},q.default.createElement(se,{items:n,value:o,label:t?.title,onChange:(e,r)=>{const n=e.target.value;u(n),a.emit("filterChanged",t,{date_range:{name:n}})}}))},ce=({filters:e=[],channel:t,query:a})=>q.default.createElement("div",{style:{display:"flex",flexWrap:"wrap",gap:"8px"}},e.map(e=>"multi-select"===e.type?q.default.createElement(ie,{key:e.title,channel:t,filter:e,query:a}):"date-range"===e.type?q.default.createElement(de,{key:e.title,channel:t,filter:e,query:a}):null));var fe=e=>q.default.useRef(e||new L.default).current,me=e=>{const t=q.default.useState({}),a=q.default.useCallback((a,r)=>{let n={...t.current,...r};for(var l in t.current=n,n)"date_range"===l||n[l].length||delete n[l];e?.emit("mergedFilterChanged",{value:n})},[e]);q.default.useEffect(()=>(e?.on("filterChanged",a),()=>{e?.off("filterChanged",a)}),[e])},pe=({id:e,cache:t,dashboard:a,channel:r,...n})=>{const[l,o]=q.default.useState(),[u,i]=q.default.useState(),[s,d]=q.default.useState(),[c,m]=q.default.useState(),[p,h]=q.default.useState(ne()),[y,g]=q.default.useState(),[b,v]=q.default.useState(0),[E,w]=q.default.useState(!1),[x,S]=q.default.useState(),[C,k]=q.default.useState(!1),I=q.default.useRef({value:n?.filter}),[R,T]=q.default.useState({}),{ref:z,inView:Y,entry:j}=f.useInView({threshold:.1,delay:1e3}),P=fe(r);me(P);const D=q.default.useCallback(e=>{const t=e.target.value;v(t),g(l.doc.view[t])},[l]);q.default.useEffect(()=>{e&&(async()=>{const a=e,r=t?.[a]||await ee.getChart({id:a}),l=r.doc.source?.id,u=l?t?.[l]||await ee.getReport({id:l}):void 0,s=t?.[`schema_${l}`]||n?.schema||await ee.getReportSchema({id:l}),c=r.doc?.view?.[0];v(0),i(u),o(r),g(c),d(s),k(!0)})().catch(e=>{console.error(e.message)})},[e]),q.default.useEffect(()=>{l&&c&&(!l?.doc?.source?.id||u)&&s&&(async()=>{h(ne(l.doc.chart?.component,{view:y,source:c,chart:l,report:u,schema:s,dashboard:a,query:R}))})().catch(e=>{console.error(e.message)})},[l,c,y,u,s]);const B=e=>{const t={...u?.doc.query.filter||{},...n?.filter,...e?.value},a=t.date_range||u?.doc.query.date_range;if(delete t.date_range,k(!1),S(),w(!0),"context"===l?.doc?.source?.type)return m({filter:t}),void w(!1);const r={filter:t,date_range:a,parameters:n?.params};T(r),ee.runReport({id:u.id,query:r}).then(e=>{m(l.doc.source.reverse?e.reverse():e)}).catch(e=>{m([])}).finally(()=>{w(!1)})},$=e=>{I.current=e,Y?B(e):(S(e),k(!0))};return q.default.useEffect(()=>(P?.on("mergedFilterChanged",$),()=>{P?.off("mergedFilterChanged",$)}),[P,u,l,Y]),q.default.useEffect(()=>{Y&&C&&B(x)},[Y,C]),q.default.createElement(M.default,{ref:z,style:{margin:"4px",padding:"16px",flexGrow:a?void 0:1,display:"flex",flexDirection:"column",gap:"16px"},elevation:0},q.default.createElement(K,{style:{visibility:E?"visible":"hidden"}}),q.default.createElement("div",{style:{display:"flex"}},q.default.createElement("div",null,l&&q.default.createElement("div",{style:{display:"flex",alignItems:"center",lineHeight:0}},q.default.createElement(A.default,{noWrap:!0,variant:"h6"},n?.title||l.doc.name," "))),q.default.createElement("div",{style:{flexGrow:1}}),q.default.createElement("div",null,l?.doc?.view?.length>1&&q.default.createElement(O.default,null,q.default.createElement(F.default,{labelId:"date-range-select-label",id:"date-range-select",value:b,onChange:D,style:{fontSize:"12px"},disableUnderline:!0},l.doc.view.map((e,t)=>q.default.createElement(_.default,{key:t,value:t},e.title)))))),q.default.createElement("div",{style:{minHeight:l?.doc?.size?.height||(a?"300px":"0"),position:"relative",paddingTop:l?.doc?.size?.vpad,paddingBottom:l?.doc?.size?.vpad,flexGrow:a?void 0:1}},q.default.createElement(ce,{filters:l?.doc?.filters,channel:P,query:R}),p))};var he={Chart:pe,Dashboard:function({id:e="sample_dashboard",token:t,params:a,base_url:r}){const[n,l]=q.default.useState(),[o]=q.default.useState(),[u,i]=q.default.useState([]),s=q.default.useRef({}),d=fe();me(d);const c=async e=>{const t=e?.doc?.rows||[],a=[];for(let e=0;e<t.length;e++){const r=t[e];r.columns?.forEach(e=>{if(e.override?.filter?.length){const t={};e.override.filter.forEach(e=>{e.hasOwnProperty("value")&&(t[e.field]=[e.value])}),e.filter=t}}),a.push(r)}i(a)};return q.default.useEffect(()=>{e&&(async()=>{ee.setBaseUrl(r),ee.setToken(t),await ee.loadDashboardMeta({dashboardId:e});const a=await ee.getDashboard({id:e});s.current[a?.id]=a,l(a),await c(a)})().catch(e=>console.error(e.message))},[e]),q.default.createElement(G.default,null,q.default.createElement(V.default,{container:!0},u?.map((e,r)=>q.default.createElement(V.default,{key:r,container:!0,item:!0},e?.columns?.map((e,r)=>q.default.createElement(V.default,U({key:r,item:!0},e.layout),q.default.createElement(pe,{token:t,cache:s.current,id:e.id,dashboard:n,schema:o,channel:null,title:e.title,filter:e.filter,params:a})))))))}};exports.default=he;