@bygd/nc-report-ui 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/default/cjs/index.cjs +1 -1140
- package/dist/default/esm/index.js +100 -48
- package/dist/default/iife/index.js +110 -45143
- package/package.json +1 -1
- package/dist/app/esm/index.html +0 -21
- package/dist/app/esm/index.js +0 -45216
|
@@ -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"),c=require("@material-ui/core/Select"),d=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"),E=require("@mui/material/FormControl"),v=require("@mui/material/Select"),w=require("eventemitter3"),x=require("@material-ui/core/Grid"),S=require("@material-ui/core/Box"),C=require("@material-ui/core/Container");function k(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 M=q(e),R=k(t),I=k(r),T=k(l),A=k(o),O=k(u),F=k(i),_=k(s),z=k(c),Y=k(d),j=k(p),D=k(h),P=k(y),B=k(g),$=k(b),W=k(E),L=k(v),V=k(w),G=k(x),U=k(S),H=k(C);function K(){return K=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},K.apply(null,arguments)}const N=a.makeStyles(e=>({root:{width:"100%","& > * + *":{marginTop:e.spacing(2)}}}));function J(e){const t=N();return M.default.createElement("div",K({className:t.root},e),M.default.createElement(I.default,null))}function Q(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+" "+T.default(l).format(o.format)}:o.format?{v:+l,f:T.default(l).format(o.format)}:l:l,"array"===a?t.push(u):t[r.name]=u?.f||u,t},t)}}const X="https://report-api.netcapital.pro",Z=A.default.create({baseURL:X,headers:{"Content-Type":"application/json"}}),ee={},te=()=>{const e=Object.keys(ee);return e.length>0?e[0]:null},ae={setBaseUrl(e){Z.defaults.baseURL=e||X},setToken(e){e&&(Z.defaults.headers.common.Authorization=`Bearer ${e}`)},loadDashboardMeta:async({dashboardId:e})=>{const{data:t}=await Z.get(`/dashboard-meta/${e}`);return ee[e]={dashboards:t.dashboards||{},charts:t.charts||{},reports:t.reports||{},reportMetadata:t.reportMetadata||{},dateRanges:t.dateRanges||[]},ee[e]},getDashboard:async({id:e,dashboardId:t})=>{const a=t||te();if(a&&ee[a]?.dashboards?.[e])return ee[a].dashboards[e];const{data:r}=await Z.get(`/entity/dashboards/${e}`);return r},getChart:async({id:e,dashboardId:t})=>{const a=t||te();if(a&&ee[a]?.charts?.[e])return ee[a].charts[e];const{data:r}=await Z.get(`/entity/charts/${e}`);return r},getReport:async({id:e,dashboardId:t})=>{const a=t||te();if(a&&ee[a]?.reports?.[e])return ee[a].reports[e];const{data:r}=await Z.get(`/entity/reports/${e}`);return r},getReportSchema:async({id:e,dashboardId:t,query:a={}})=>{const r=t||te();if(r&&ee[r]?.reportMetadata?.[e])return ee[r].reportMetadata[e];const{data:n}=await Z.post(`/reports/${e}/metadata`,a);return n},runReport:async({id:e,query:t={}})=>{const{data:a}=await Z.post(`/reports/${e}/run`,t);return a},getDateRanges:async({dashboardId:e}={})=>{const t=e||te();if(t&&ee[t]?.dateRanges)return ee[t].dateRanges;const{data:a}=await Z.get("/globals/date-ranges");return a}},re=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"}})),ne={none:"YYYY-MM-dd",day:"MMM dd",week:"MMM dd",month:"YYYY MMM",year:"YYYY"};const le={GoogleChart:function({chart:t,source:a,view:r,report:l,schema:o,dashboard:u,query:i}){const[s,c]=M.default.useState([]),d=re(),[f,m]=M.default.useState([]);e.useEffect(()=>{(async()=>{const e=await ae.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 ne[a?.granularity]||e},[f,i]);return M.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=Q(r,o);a?.forEach(t=>{const a=n(t);e.push(a)}),a?.length?c(e):c()},[t,a,r,l,o]),s?M.default.createElement("div",{style:{}},M.default.createElement(n.Chart,K({width:t?.doc.size?.width||"100%",chartType:t?.doc.chart?.type,data:s,options:(e=>{if("Table"===t?.doc.chart?.type)return{...t?.doc.chart?.options,cssClassNames:d};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))):M.default.createElement("div",null)},LabelChart:function({chart:e,source:t,view:a,report:r,schema:n}){const[l,o]=M.default.useState([]),[u,i]=M.default.useState(),[s,c]=M.default.useState();return M.default.useEffect(()=>{if(!(e&&a&&t&&r&&n))return;let l=[];const u=Q(a,n);t.forEach(e=>l.push(u(e))),o(l);const s=e?.doc?.chart?.options||{},d=s?.index||0;if(l.length>0&&i(l[0][d]),s.subText?.format){F.default.configure({autoescape:!1});const e=Q(a,n,"object")(t[0]),r=F.default.renderString(s.subText?.format,e);c(r)}},[e,t,a,r,n]),M.default.createElement("div",{style:{display:"flex",justifyContent:"center",alignContent:"center",height:"100%",flexDirection:"column"}},M.default.createElement(O.default,{variant:"h6"},u?.f||u),M.default.createElement(O.default,{variant:"caption"},s))}};function oe(e,t){return void 0!==le[e]?M.default.createElement(le[e],t):M.default.createElement(J,t)}const ue=M.createElement(j.default,{fontSize:"small"}),ie=M.createElement(D.default,{fontSize:"small"});function se({items:t,selectedKeys:a,defaultSelectedKeys:r,onChange:n,inputValue:l,defaultInputValue:o,onInputChange:u,debounceMs:i=300,label:s,placeholder:c,loading:d,disabled:f,size:p="small",error:h,helperText:y,limitTags:g=3,disableClearable:b,id:E,textFieldProps:v}){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,q=e.useMemo(()=>{const e=new Map;for(const t of w)e.set(t&&t.key,t);return e},[w]),R=e.useMemo(()=>(Array.isArray(k)?k:[]).map(e=>q.get(e)).filter(Boolean),[k,q]),I="string"==typeof l,[T,A]=e.useState("string"==typeof o?o:""),O=I?l:T,F=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)},[]),M.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),_=R;return M.createElement(m.FormControl,{fullWidth:!0,error:h,disabled:f},M.createElement(m.Autocomplete,{openOnFocus:!0,forcePopupIcon:!0,id:E,multiple:!0,disableCloseOnSelect:!0,options:w,value:_,inputValue:O,getOptionLabel:e=>e&&"object"==typeof e?e.value??"":"",isOptionEqualToValue:(e,t)=>e&&t&&e.key===t.key,loading:d,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)=>{I||A(t??""),"input"===a?F(t??""):"clear"===a&&F("")},renderOption:(e,t,{selected:a})=>M.createElement("li",K({},e,{key:t&&t.key||Math.random().toString(36)}),M.createElement(m.Checkbox,{icon:ue,checkedIcon:ie,style:{marginRight:8},checked:!!a}),t&&t.value),renderTags:(e,t)=>(Array.isArray(e)?e:[]).map((e,a)=>M.createElement(m.Chip,K({},t({index:a}),{key:e&&e.key||a,label:e&&e.value||""}))),renderInput:e=>M.createElement(m.TextField,K({},e,{label:s,placeholder:c,InputProps:{...e.InputProps,endAdornment:M.createElement(M.Fragment,null,d?M.createElement(m.CircularProgress,{size:18}):null,e.InputProps.endAdornment)},size:p},v))}),y?M.createElement(m.FormHelperText,null,y):null)}const ce=({filter:t,channel:a,query:r})=>{const[n,l]=e.useState([]),[o,u]=e.useState([]),[i,s]=e.useState(!1),[c,d]=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 ae.runReport({id:t.source})).map(e=>({key:e[t.field],value:e[t.field]})):[]}(0,t);l(e),s(!1)})()},[c]),M.default.createElement("div",{style:{display:"flex"}},M.default.createElement("div",{style:{maxWidth:640,minWidth:200}},M.default.createElement(se,{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=>{d(e)},loading:i,debounceMs:300,helperText:o.length?`${o.length} selected`:""})))};function de({items:e,value:t,label:a,onChange:r,sx:n={width:"100%"}}){const l=e.some(e=>e.key===t)?t:"";return M.default.createElement(P.default,{sx:n},M.default.createElement(W.default,{fullWidth:!0},M.default.createElement(B.default,{id:"demo-simple-select-label"},a),M.default.createElement(L.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 M.default.createElement($.default,{key:t,value:t},a)}))))}const fe=({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 ae.getDateRanges()).filter(e=>!(t.allowedOptions.length>0)||t.allowedOptions.some(t=>t===e.name)).map(e=>({key:e.name,value:e.title}));l(e)})()},[]),M.default.createElement("div",{style:{minWidth:"200px",maxWidth:"640px"}},M.default.createElement(de,{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}})}}))},me=({filters:e=[],channel:t,query:a})=>M.default.createElement("div",{style:{display:"flex",flexWrap:"wrap",gap:"8px"}},e.map(e=>"multi-select"===e.type?M.default.createElement(ce,{key:e.title,channel:t,filter:e,query:a}):"date-range"===e.type?M.default.createElement(fe,{key:e.title,channel:t,filter:e,query:a}):null));var pe=e=>M.default.useRef(e||new V.default).current,he=e=>{const t=M.default.useState({}),a=M.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]);M.default.useEffect(()=>(e?.on("filterChanged",a),()=>{e?.off("filterChanged",a)}),[e])},ye=({id:e,cache:t,dashboard:a,channel:r,...n})=>{const[l,o]=M.default.useState(),[u,i]=M.default.useState(),[s,c]=M.default.useState(),[d,m]=M.default.useState(),[p,h]=M.default.useState(oe()),[y,g]=M.default.useState(),[b,E]=M.default.useState(0),[v,w]=M.default.useState(!1),[x,S]=M.default.useState(),[C,k]=M.default.useState(!1),q=M.default.useRef({value:n?.filter}),[I,T]=M.default.useState({}),{ref:A,inView:F,entry:j}=f.useInView({threshold:.1,delay:1e3}),D=pe(r);he(D);const P=M.default.useCallback(e=>{const t=e.target.value;E(t),g(l.doc.view[t])},[l]);M.default.useEffect(()=>{e&&(async()=>{const a=e,r=t?.[a]||await ae.getChart({id:a}),l=r.doc.source?.id,u=l?t?.[l]||await ae.getReport({id:l}):void 0,s=t?.[`schema_${l}`]||n?.schema||await ae.getReportSchema({id:l}),d=r.doc?.view?.[0];E(0),i(u),o(r),g(d),c(s),k(!0)})().catch(e=>{console.error(e.message)})},[e]),M.default.useEffect(()=>{l&&d&&(!l?.doc?.source?.id||u)&&s&&(async()=>{h(oe(l.doc.chart?.component,{view:y,source:d,chart:l,report:u,schema:s,dashboard:a,query:I}))})().catch(e=>{console.error(e.message)})},[l,d,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),ae.runReport({id:u.id,query:r}).then(e=>{m(l.doc.source.reverse?e.reverse():e)}).catch(e=>{m([])}).finally(()=>{w(!1)})},$=e=>{q.current=e,F?B(e):(S(e),k(!0))};return M.default.useEffect(()=>(D?.on("mergedFilterChanged",$),()=>{D?.off("mergedFilterChanged",$)}),[D,u,l,F]),M.default.useEffect(()=>{F&&C&&B(x)},[F,C]),M.default.createElement(R.default,{ref:A,style:{padding:"16px",paddingTop:0,flexGrow:1,borderRadius:12,display:"flex",flexDirection:"column",gap:"16px"},elevation:2},M.default.createElement(J,{style:{visibility:v?"visible":"hidden"}}),M.default.createElement("div",{style:{display:"flex"}},M.default.createElement("div",null,l&&M.default.createElement("div",{style:{display:"flex",alignItems:"center",lineHeight:0}},M.default.createElement(O.default,{noWrap:!0,variant:"caption"},n?.title||l.doc.name," "))),M.default.createElement("div",{style:{flexGrow:1}}),M.default.createElement("div",null,l?.doc?.view?.length>1&&M.default.createElement(_.default,null,M.default.createElement(z.default,{labelId:"date-range-select-label",id:"date-range-select",value:b,onChange:P,style:{fontSize:"12px"},disableUnderline:!0},l.doc.view.map((e,t)=>M.default.createElement(Y.default,{key:t,value:t},e.title)))))),M.default.createElement("div",{style:{position:"relative",flexGrow:a?void 0:1,display:"flex",flexDirection:"column"}},M.default.createElement(me,{filters:l?.doc?.filters,channel:D,query:I}),p))};var ge={Chart:ye,Dashboard:function({id:e="sample_dashboard",token:t,params:a,base_url:r}){const[n,l]=M.default.useState(),[o]=M.default.useState(),[u,i]=M.default.useState([]),s=M.default.useRef({}),c=pe();he(c);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)}i(a)};return M.default.useEffect(()=>{e&&(async()=>{ae.setBaseUrl(r),ae.setToken(t),await ae.loadDashboardMeta({dashboardId:e});const a=await ae.getDashboard({id:e});s.current[a?.id]=a,l(a),await d(a)})().catch(e=>console.error(e.message))},[e]),M.default.createElement(H.default,null,M.default.createElement(G.default,{container:!0,spacing:2},u?.map((e,r)=>M.default.createElement(G.default,{key:r,container:!0,item:!0,alignItems:"stretch",spacing:2},e?.columns?.map((e,r)=>M.default.createElement(G.default,{key:r,item:!0,xs:!0,style:{display:"flex"}},M.default.createElement(U.default,{style:{flex:1,display:"flex",flexDirection:"column"}},M.default.createElement(ye,{token:t,cache:s.current,id:e.id,dashboard:n,schema:o,channel:null,title:e.title,filter:e.filter,params:a}))))))))}};exports.default=ge;
|