@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalabz_/dashboard-kit",
3
- "version": "6.0.2",
3
+ "version": "6.0.3",
4
4
  "description": "DashboardKit runtime + styles, served from jsDelivr",
5
5
  "license": "UNLICENSED",
6
6
  "files": [
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 = 'b3d1c2d'; // replaced at deploy: sed -i "s/b3d1c2d/$(git rev-parse --short HEAD)/g" v4.js
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 = 'b3d1c2d'; // replaced at deploy: sed -i "s/b3d1c2d/$(git rev-parse --short HEAD)/g" v4.js
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 = 'b3d1c2d'; // replaced at deploy: sed -i "s/b3d1c2d/$(git rev-parse --short HEAD)/g" v6.js
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
- const API_BASE = "https://bcproxy.draftplaza.com";
5
- const LS_TIMEZONE = "iqg.harness.timezone";
6
- const LS_TOKEN = "iqg.harness.token";
7
- const LS_USER = "iqg.harness.user";
8
- const LS_THEME = "iqg.harness.theme";
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)