@bygd/nc-report-ui 0.1.10 → 0.1.12

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