@datalabz_/dashboard-kit 6.0.2 → 6.0.3
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/README.md +22 -0
- package/package.json +1 -1
- package/v4.js +1 -1
- package/v5.js +1 -1
- package/v6.js +68 -1
- package/wrapper.css +9 -0
- package/wrapper.js +35 -5
package/README.md
CHANGED
|
@@ -53,6 +53,28 @@ A major's files are one served bundle; the repo's per-file line budget
|
|
|
53
53
|
(AGENTS.md #2) does not apply to it — it cannot be split without changing the
|
|
54
54
|
URLs already pinned by live dashboards.
|
|
55
55
|
|
|
56
|
+
## Asking a dashboard for its filters
|
|
57
|
+
|
|
58
|
+
A parent may post `{ type: 'DK_GET_FILTERS_INFO' }` to a dashboard's frame; the kit answers the parent with
|
|
59
|
+
`{ type: 'DK_FILTERS_INFO', filters: [...] }`. It needs no token or period, so a parent can ask as soon as
|
|
60
|
+
the frame has loaded. The list is the controls in the dashboard's header — what it can be opened
|
|
61
|
+
with — one entry each:
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
{ id: 'playerUsername', label: 'Player username', type: 'text', // type: the input's type, 'select' or 'textarea'
|
|
65
|
+
required: true, value: '',
|
|
66
|
+
placeholder, min, max, // only when the control sets them
|
|
67
|
+
disabled: true, // only when it is disabled
|
|
68
|
+
multiple: false, optionsTotal: 2, // select only
|
|
69
|
+
options: [{ value: 'BRL', label: 'Real' }] } // select only: the first 100 options
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The whole header is read, so a control the dashboard adds to it after `init` is listed too. Left
|
|
73
|
+
out: a control with no `id`, a second control with an `id` already listed, a password field, and
|
|
74
|
+
radio, file, hidden and button controls, which the kit cannot fill. A select's options are those
|
|
75
|
+
it has when asked: one the dashboard fills by a query later has none yet, and `optionsTotal` says how
|
|
76
|
+
many there were. The answer always goes to the dashboard's parent, whoever asked.
|
|
77
|
+
|
|
56
78
|
## Rules
|
|
57
79
|
|
|
58
80
|
- **Where a change lands — the current `vN` or a new major — is decided by
|
package/package.json
CHANGED
package/v4.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
let _activeTabId = '';
|
|
21
21
|
let _sections = []; // { id, label, load, loaded, errors }
|
|
22
22
|
let _title = '';
|
|
23
|
-
let _gitVer = '
|
|
23
|
+
let _gitVer = '8ed9062'; // replaced at deploy: sed -i "s/8ed9062/$(git rev-parse --short HEAD)/g" v4.js
|
|
24
24
|
let _calls = []; // System Info call log
|
|
25
25
|
let _sectionErrors = {}; // sectionId → error count
|
|
26
26
|
let _generation = 0;
|
package/v5.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
let _activeTabId = '';
|
|
21
21
|
let _sections = []; // { id, label, load, loaded, errors }
|
|
22
22
|
let _title = '';
|
|
23
|
-
let _gitVer = '
|
|
23
|
+
let _gitVer = '8ed9062'; // replaced at deploy: sed -i "s/8ed9062/$(git rev-parse --short HEAD)/g" v4.js
|
|
24
24
|
let _calls = []; // System Info call log
|
|
25
25
|
let _sectionErrors = {}; // sectionId → error count
|
|
26
26
|
let _generation = 0;
|
package/v6.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
let _activeTabId = '';
|
|
21
21
|
let _sections = []; // { id, label, load, loaded, errors }
|
|
22
22
|
let _title = '';
|
|
23
|
-
let _gitVer = '
|
|
23
|
+
let _gitVer = '8ed9062'; // replaced at deploy: sed -i "s/8ed9062/$(git rev-parse --short HEAD)/g" v6.js
|
|
24
24
|
let _calls = []; // System Info call log
|
|
25
25
|
let _sectionErrors = {}; // sectionId → error count
|
|
26
26
|
let _generation = 0;
|
|
@@ -931,8 +931,75 @@ details.dk-call summary::-webkit-details-marker {
|
|
|
931
931
|
} catch { return false; }
|
|
932
932
|
}
|
|
933
933
|
|
|
934
|
+
// ── Filters a parent can ask for ──────────────────────────────────────────────
|
|
935
|
+
// DK_GET_FILTERS_INFO from the parent is answered with DK_FILTERS_INFO: the controls a dashboard keeps in
|
|
936
|
+
// its header, which are what it can be opened with. It needs no token or period, so a parent can
|
|
937
|
+
// ask as soon as the frame has loaded. Left out: controls the kit cannot fill (radio, file,
|
|
938
|
+
// hidden, buttons), a password field, a control with no id, and a second control with an id
|
|
939
|
+
// already listed. The whole header is read, so a control a dashboard adds to it after init is listed.
|
|
940
|
+
const FILTER_SKIP_TYPES = ['radio', 'file', 'hidden', 'button', 'submit', 'reset', 'image', 'password'];
|
|
941
|
+
const FILTER_MAX_OPTIONS = 100;
|
|
942
|
+
const FILTER_MAX_TEXT = 500;
|
|
943
|
+
|
|
944
|
+
function _clip(s, n) {
|
|
945
|
+
s = String(s == null ? '' : s);
|
|
946
|
+
return s.length > n ? s.slice(0, n) : s;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
function _filterLabel(el) {
|
|
950
|
+
const wrap = el.labels && el.labels[0];
|
|
951
|
+
if (wrap) {
|
|
952
|
+
const c = wrap.cloneNode(true);
|
|
953
|
+
c.querySelectorAll('input, select, textarea, .dk-tip, [aria-hidden="true"], script, style').forEach(function (n) { n.remove(); });
|
|
954
|
+
const t = c.textContent.replace(/\s+/g, ' ').trim();
|
|
955
|
+
if (t) return _clip(t, 200);
|
|
956
|
+
}
|
|
957
|
+
return _clip(el.getAttribute('aria-label') || el.getAttribute('placeholder') || '', 200);
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
function _dashboardFilters() {
|
|
961
|
+
const header = document.querySelector('[data-dk-header]');
|
|
962
|
+
const out = [];
|
|
963
|
+
if (!header) return out;
|
|
964
|
+
const seen = {};
|
|
965
|
+
header.querySelectorAll('input, select, textarea').forEach(function (el) {
|
|
966
|
+
if (!el.id || seen[el.id] || FILTER_SKIP_TYPES.indexOf(el.type) >= 0) return;
|
|
967
|
+
seen[el.id] = true;
|
|
968
|
+
const isSelect = el.tagName === 'SELECT';
|
|
969
|
+
const f = {
|
|
970
|
+
id: el.id,
|
|
971
|
+
label: _filterLabel(el),
|
|
972
|
+
type: isSelect ? 'select' : el.tagName === 'TEXTAREA' ? 'textarea' : el.type,
|
|
973
|
+
required: el.required,
|
|
974
|
+
};
|
|
975
|
+
if (el.disabled) f.disabled = true;
|
|
976
|
+
if (!isSelect) {
|
|
977
|
+
['placeholder', 'min', 'max'].forEach(function (a) {
|
|
978
|
+
if (el.getAttribute(a) !== null) f[a] = _clip(el.getAttribute(a), 100);
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
if (isSelect) {
|
|
982
|
+
f.multiple = el.multiple;
|
|
983
|
+
f.optionsTotal = el.options.length;
|
|
984
|
+
f.options = Array.from(el.options).slice(0, FILTER_MAX_OPTIONS).map(function (o) {
|
|
985
|
+
return { value: _clip(o.value, 200), label: _clip(o.textContent.trim(), 200) };
|
|
986
|
+
});
|
|
987
|
+
f.value = el.multiple ? Array.from(el.selectedOptions).map(function (o) { return o.value; }) : el.value;
|
|
988
|
+
} else {
|
|
989
|
+
f.value = el.type === 'checkbox' ? el.checked : _clip(el.value, FILTER_MAX_TEXT);
|
|
990
|
+
}
|
|
991
|
+
out.push(f);
|
|
992
|
+
});
|
|
993
|
+
return out;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
|
|
934
997
|
function _onMessage(e) {
|
|
935
998
|
if (!e.data || typeof e.data !== 'object') return;
|
|
999
|
+
if (e.data.type === 'DK_GET_FILTERS_INFO') {
|
|
1000
|
+
window.parent.postMessage({ type: 'DK_FILTERS_INFO', filters: _dashboardFilters() }, '*');
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
936
1003
|
if (e.data.type === 'RK_SNAPSHOT') { _snapshot(); return; }
|
|
937
1004
|
if (e.data.type === 'CHAT_MODE') { document.documentElement.dataset.chatMode = 'true'; return; }
|
|
938
1005
|
if (e.data.type !== 'CUSTOM_DASHBOARDS_PARAMS') return;
|
package/wrapper.css
CHANGED
|
@@ -52,6 +52,15 @@ header.topbar {
|
|
|
52
52
|
flex-wrap: wrap;
|
|
53
53
|
flex-shrink: 0;
|
|
54
54
|
}
|
|
55
|
+
.platform-badge {
|
|
56
|
+
font-size: 14px;
|
|
57
|
+
font-weight: 700;
|
|
58
|
+
white-space: nowrap;
|
|
59
|
+
color: var(--text);
|
|
60
|
+
}
|
|
61
|
+
.platform-badge b {
|
|
62
|
+
color: var(--brand);
|
|
63
|
+
}
|
|
55
64
|
header .filters {
|
|
56
65
|
display: flex;
|
|
57
66
|
gap: 10px;
|
package/wrapper.js
CHANGED
|
@@ -1,17 +1,41 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
// Where each platform's BackOffice lives; the page picks one with <script src=".../wrapper.js" data-platform="poker">.
|
|
5
|
+
// No data-platform means igaming, as before. An unknown name is an error, never a guess.
|
|
6
|
+
// apiBase — sign-in (the BackOffice's own API)
|
|
7
|
+
// gatewayEndpoint — the SQL gateway a dashboard's queries go to, sent as `endpoint`
|
|
8
|
+
// storagePrefix — localStorage key prefix, so the two keep their own sign-in on one origin
|
|
9
|
+
// label — the name in the top bar, before the word "Platform", that says which BackOffice this page talks to
|
|
10
|
+
const PLATFORMS = {
|
|
11
|
+
igaming: {
|
|
12
|
+
label: "iGaming",
|
|
13
|
+
apiBase: "https://bcproxy.draftplaza.com",
|
|
14
|
+
gatewayEndpoint: "https://aidqgateway.draftplaza.com/aidq",
|
|
15
|
+
storagePrefix: "iqg.harness.",
|
|
16
|
+
},
|
|
17
|
+
poker: {
|
|
18
|
+
label: "Poker",
|
|
19
|
+
apiBase: "https://pokerreporting.pokerplaza.com",
|
|
20
|
+
gatewayEndpoint: "https://aidqgateway.pokerplaza.com/aidq",
|
|
21
|
+
storagePrefix: "iqg.harness.poker.",
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
const platformName = (document.currentScript && document.currentScript.dataset.platform) || "igaming";
|
|
25
|
+
const CFG = PLATFORMS[platformName];
|
|
26
|
+
if (!CFG) throw new Error('wrapper: data-platform "' + platformName + '" is not one of ' + Object.keys(PLATFORMS).join(", "));
|
|
27
|
+
const API_BASE = CFG.apiBase;
|
|
28
|
+
const LS_TIMEZONE = CFG.storagePrefix + "timezone";
|
|
29
|
+
const LS_TOKEN = CFG.storagePrefix + "token";
|
|
30
|
+
const LS_USER = CFG.storagePrefix + "user";
|
|
31
|
+
const LS_THEME = CFG.storagePrefix + "theme";
|
|
9
32
|
|
|
10
33
|
// Capture srcdoc from the inline iframe before DOM rebuild.
|
|
11
34
|
const _srcdoc = document.getElementById("iframe")?.getAttribute("srcdoc") || "";
|
|
12
35
|
|
|
13
36
|
document.body.innerHTML = `
|
|
14
37
|
<header class="topbar">
|
|
38
|
+
<span class="platform-badge" id="platformBadge"></span>
|
|
15
39
|
<div class="filters">
|
|
16
40
|
<label>Date
|
|
17
41
|
<select id="datePreset">
|
|
@@ -94,6 +118,10 @@
|
|
|
94
118
|
<div class="toast" id="toast"></div>`;
|
|
95
119
|
|
|
96
120
|
document.getElementById("iframe").setAttribute("srcdoc", _srcdoc);
|
|
121
|
+
const badge = document.getElementById("platformBadge");
|
|
122
|
+
badge.innerHTML = "<b></b> Platform";
|
|
123
|
+
badge.firstChild.textContent = CFG.label;
|
|
124
|
+
document.title = CFG.label + " · " + document.title;
|
|
97
125
|
|
|
98
126
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
99
127
|
|
|
@@ -179,6 +207,8 @@
|
|
|
179
207
|
const hid = State.filters.hierarchyId;
|
|
180
208
|
return {
|
|
181
209
|
type: "CUSTOM_DASHBOARDS_PARAMS", token: State.token, theme: State.theme,
|
|
210
|
+
// The SQL gateway of this BackOffice; the kit would otherwise use its own default.
|
|
211
|
+
endpoint: CFG.gatewayEndpoint,
|
|
182
212
|
filters: {
|
|
183
213
|
dateFrom: r.dateFromIso, dateTo: r.dateToIso, timezone: tz,
|
|
184
214
|
hierarchyId: hid == null || Number.isNaN(hid) ? null : Number(hid)
|