myio-js-library 0.1.562 → 0.1.563

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/index.cjs CHANGED
@@ -94,6 +94,7 @@ __export(src_exports, {
94
94
  DEFAULT_DEVICE_OPERATIONAL_CARD_FILTER_STATE: () => DEFAULT_DEVICE_OPERATIONAL_CARD_FILTER_STATE,
95
95
  DEFAULT_DEVICE_TYPE_PREFIX: () => DEFAULT_DEVICE_TYPE_PREFIX,
96
96
  DEFAULT_DEVICE_TYPE_TOKEN: () => DEFAULT_DEVICE_TYPE_TOKEN,
97
+ DEFAULT_ENABLED_REPORT_ITEMS: () => DEFAULT_ENABLED_REPORT_ITEMS,
97
98
  DEFAULT_ENERGY_GROUP_COLORS: () => DEFAULT_ENERGY_GROUP_COLORS,
98
99
  DEFAULT_EQUIPMENT_FILTER_STATE: () => DEFAULT_EQUIPMENT_FILTER_STATE,
99
100
  DEFAULT_EQUIPMENT_STATS: () => DEFAULT_EQUIPMENT_STATS,
@@ -120,6 +121,7 @@ __export(src_exports, {
120
121
  DEFAULT_ON_OFF_SETTINGS: () => DEFAULT_ON_OFF_SETTINGS,
121
122
  DEFAULT_ON_OFF_STATE: () => DEFAULT_ON_OFF_STATE,
122
123
  DEFAULT_PARTICIPATION_CHART_SETTINGS: () => DEFAULT_PARTICIPATION_CHART_SETTINGS,
124
+ DEFAULT_REPORTS_CATALOG: () => DEFAULT_REPORTS_CATALOG,
123
125
  DEFAULT_SETPOINT_SCHEDULE: () => DEFAULT_SETPOINT_SCHEDULE,
124
126
  DEFAULT_SETPOINT_SETTINGS: () => DEFAULT_SETPOINT_SETTINGS,
125
127
  DEFAULT_SETPOINT_STATE: () => DEFAULT_SETPOINT_STATE,
@@ -371,6 +373,7 @@ __export(src_exports, {
371
373
  buildListItemsThingsboardByUniqueDatasource: () => buildListItemsThingsboardByUniqueDatasource,
372
374
  buildMoneyVarianceHTML: () => buildMoneyVarianceHTML,
373
375
  buildMyioIngestionAuth: () => buildMyioIngestionAuth,
376
+ buildReportItemsList: () => buildReportItemsList,
374
377
  buildTemplateExport: () => buildTemplateExport,
375
378
  buildTicketServiceOrchestrator: () => buildTicketServiceOrchestrator,
376
379
  buildVerdictHTML: () => buildVerdictHTML,
@@ -432,6 +435,7 @@ __export(src_exports, {
432
435
  createCustomerCardV1: () => createCustomerCardV1,
433
436
  createCustomerCardV2: () => createCustomerCardV2,
434
437
  createCustomerGoalsCard: () => createCustomerGoalsCard,
438
+ createDashboardReportsHubContext: () => createDashboardReportsHubContext,
435
439
  createDateRangePicker: () => createDateRangePicker2,
436
440
  createDaysGrid: () => createDaysGrid,
437
441
  createDefaultAnnotationFilter: () => createDefaultFilter,
@@ -794,6 +798,7 @@ __export(src_exports, {
794
798
  openPowerLimitsSetupModal: () => openPowerLimitsSetupModal,
795
799
  openPricingPanel: () => openPricingPanel,
796
800
  openRealTimeTelemetryModal: () => openRealTimeTelemetryModal,
801
+ openReportsHub: () => openReportsHub,
797
802
  openSettingsHubModal: () => openSettingsHubModal,
798
803
  openTemperatureComparisonModal: () => openTemperatureComparisonModal,
799
804
  openTemperatureModal: () => openTemperatureModal,
@@ -860,6 +865,7 @@ __export(src_exports, {
860
865
  resolveMoneyRollout: () => resolveMoneyRollout,
861
866
  resolveMoneyRowValues: () => resolveMoneyRowValues,
862
867
  resolvePercentDecimals: () => resolvePercentDecimals,
868
+ resolveReportItemStates: () => resolveReportItemStates,
863
869
  resolveSubcategory: () => resolveSubcategory,
864
870
  resolveWithFallback: () => resolveWithFallback,
865
871
  routeMoneyRender: () => routeMoneyRender,
@@ -915,7 +921,7 @@ module.exports = __toCommonJS(src_exports);
915
921
  // package.json
916
922
  var package_default = {
917
923
  name: "myio-js-library",
918
- version: "0.1.562",
924
+ version: "0.1.563",
919
925
  description: "A clean, standalone JS SDK for MYIO projects",
920
926
  license: "MIT",
921
927
  repository: "github:gh-myio/myio-js-library",
@@ -7601,16 +7607,23 @@ function createModalFooter(params = {}) {
7601
7607
  if (params.libVersion !== false) {
7602
7608
  left.appendChild(versionHost);
7603
7609
  const current = params.libVersion?.current;
7604
- try {
7605
- versionChecker = createLibraryVersionChecker(versionHost, {
7606
- packageName: "myio-js-library",
7607
- currentVersion: current || "unknown",
7608
- preferHomolog: params.libVersion?.preferHomolog === true,
7609
- theme: themeMode
7610
- });
7611
- } catch {
7610
+ const showStatic = () => {
7612
7611
  versionHost.textContent = current ? `v${current}` : "";
7613
7612
  versionHost.style.cssText = "font-size:11px;opacity:.7;";
7613
+ };
7614
+ if (params.libVersionMode === "static") {
7615
+ showStatic();
7616
+ } else {
7617
+ try {
7618
+ versionChecker = createLibraryVersionChecker(versionHost, {
7619
+ packageName: "myio-js-library",
7620
+ currentVersion: current || "unknown",
7621
+ preferHomolog: params.libVersion?.preferHomolog === true,
7622
+ theme: themeMode
7623
+ });
7624
+ } catch {
7625
+ showStatic();
7626
+ }
7614
7627
  }
7615
7628
  }
7616
7629
  const center = document.createElement("div");
@@ -7675,9 +7688,9 @@ var MYIO_ACCENT = "var(--myio-brand-700, #3e1a7d)";
7675
7688
  function win() {
7676
7689
  return typeof window !== "undefined" ? window : {};
7677
7690
  }
7678
- function applyDashboardPalette(el2) {
7691
+ function applyDashboardPalette(el2, opts) {
7679
7692
  if (!el2) return;
7680
- const theme = win().MyIOUtils?.theme;
7693
+ const theme = opts && opts.palette !== void 0 ? opts.palette : opts?.useGlobals === false ? null : win().MyIOUtils?.theme;
7681
7694
  if (!theme) return;
7682
7695
  const vars = typeof theme.cssVars === "function" ? theme.cssVars() : theme;
7683
7696
  if (!vars || typeof vars !== "object") return;
@@ -7697,7 +7710,8 @@ function createPremiumModalChrome(opts) {
7697
7710
  let theme = opts.theme === "dark" ? "dark" : "light";
7698
7711
  let maximized = opts.maximized === true;
7699
7712
  let title = opts.title;
7700
- applyDashboardPalette(opts.modalEl);
7713
+ const useGlobals = opts.useGlobals !== false;
7714
+ applyDashboardPalette(opts.modalEl, { palette: opts.palette, useGlobals });
7701
7715
  themeTarget.setAttribute("data-theme", theme);
7702
7716
  opts.modalEl.classList.toggle(maximizedClass, maximized);
7703
7717
  const buildHeader = () => {
@@ -7736,8 +7750,8 @@ function createPremiumModalChrome(opts) {
7736
7750
  const f = opts.footer || {};
7737
7751
  footer = createModalFooter({
7738
7752
  ...f,
7739
- customerName: f.customerName ?? resolveDashboardCustomerName(),
7740
- libVersion: f.libVersion ?? { current: win().MyIOLibrary?.version },
7753
+ customerName: f.customerName ?? (useGlobals ? resolveDashboardCustomerName() : ""),
7754
+ libVersion: f.libVersion ?? (useGlobals ? { current: win().MyIOLibrary?.version } : false),
7741
7755
  themeMode: theme
7742
7756
  });
7743
7757
  footer.element.style.flexShrink = "0";
@@ -80080,7 +80094,6 @@ __export(demand_exports, {
80080
80094
  CATALOG_VERSION: () => CATALOG_VERSION,
80081
80095
  DEFAULT_DEMAND_LABEL: () => DEFAULT_DEMAND_LABEL,
80082
80096
  DEFAULT_RESOLUTION: () => DEFAULT_RESOLUTION,
80083
- DEMAND_LIMITS: () => DEMAND_LIMITS,
80084
80097
  END_TOLERANCE_MS: () => END_TOLERANCE_MS,
80085
80098
  ENVELOPE_SCHEMA_VERSION: () => ENVELOPE_SCHEMA_VERSION,
80086
80099
  HASH_ALGORITHM: () => HASH_ALGORITHM,
@@ -80094,6 +80107,7 @@ __export(demand_exports, {
80094
80107
  TELEMETRY_CATALOG: () => TELEMETRY_CATALOG,
80095
80108
  TELEMETRY_GROUPS: () => TELEMETRY_GROUPS,
80096
80109
  auditEvent: () => auditEvent,
80110
+ availableResolutions: () => availableResolutions,
80097
80111
  bucketCount: () => bucketCount,
80098
80112
  buildEnvelope: () => buildEnvelope,
80099
80113
  buildRequest: () => buildRequest,
@@ -80110,6 +80124,7 @@ __export(demand_exports, {
80110
80124
  humanizeKey: () => humanizeKey,
80111
80125
  isLocalMidnight: () => isLocalMidnight,
80112
80126
  isUncertainStatus: () => isUncertainStatus,
80127
+ limitsFromConfig: () => limitsFromConfig,
80113
80128
  localMidnightOf: () => localMidnightOf,
80114
80129
  maxPeriodDays: () => maxPeriodDays,
80115
80130
  mergeBatch: () => mergeBatch,
@@ -80128,6 +80143,7 @@ __export(demand_exports, {
80128
80143
  toSubmitCommand: () => toSubmitCommand,
80129
80144
  toValidateCommand: () => toValidateCommand,
80130
80145
  uuidv7: () => uuidv7,
80146
+ warningText: () => warningText,
80131
80147
  webCryptoSha256: () => webCryptoSha256
80132
80148
  });
80133
80149
 
@@ -80182,11 +80198,11 @@ var TELEMETRY_GROUPS = [
80182
80198
  ];
80183
80199
  var TELEMETRY_CATALOG = TELEMETRY_GROUPS.flatMap((g) => g.items);
80184
80200
  var RESOLUTIONS = [
80185
- { id: "1m", label: "1 min", ms: 6e4, maxDays: 1 },
80186
- { id: "5m", label: "5 min", ms: 3e5, maxDays: 7 },
80187
- { id: "15m", label: "15 min", ms: 9e5, maxDays: 31 },
80188
- { id: "1h", label: "1 hora", ms: 36e5, maxDays: 92 },
80189
- { id: "1d", label: "1 dia", ms: 864e5, maxDays: 92 }
80201
+ { id: "1m", label: "1 min", ms: 6e4 },
80202
+ { id: "5m", label: "5 min", ms: 3e5 },
80203
+ { id: "15m", label: "15 min", ms: 9e5 },
80204
+ { id: "1h", label: "1 hora", ms: 36e5 },
80205
+ { id: "1d", label: "1 dia", ms: 864e5 }
80190
80206
  ];
80191
80207
  var DEFAULT_RESOLUTION = "1h";
80192
80208
  var RESOLUTION_BY_ID = Object.fromEntries(
@@ -80194,7 +80210,31 @@ var RESOLUTION_BY_ID = Object.fromEntries(
80194
80210
  );
80195
80211
  var BUCKET_STATS_LABEL = "m\xE9dia, m\xE1ximo, m\xEDnimo e n\xBA de amostras";
80196
80212
  var DEFAULT_DEMAND_LABEL = "Pot\xEAncia m\xE9dia em 15 min (demanda estimada)";
80197
- var DEMAND_LIMITS = { devices: 50, telemetries: 15, points: 2e6, activeJobsPerUser: 10 };
80213
+ var posInt = (v) => {
80214
+ const n = typeof v === "string" && v.trim() !== "" ? Number(v) : v;
80215
+ return typeof n === "number" && Number.isFinite(n) && n > 0 ? n : void 0;
80216
+ };
80217
+ function limitsFromConfig(config2) {
80218
+ const l = config2?.limits || null;
80219
+ const raw = l?.maxDaysByResolution || null;
80220
+ if (!raw || typeof raw !== "object") return null;
80221
+ const maxDaysByResolution = {};
80222
+ RESOLUTIONS.forEach((r) => {
80223
+ const d = posInt(raw[r.id]);
80224
+ if (d) maxDaysByResolution[r.id] = d;
80225
+ });
80226
+ if (!Object.keys(maxDaysByResolution).length) return null;
80227
+ return {
80228
+ maxDaysByResolution,
80229
+ maxDevices: posInt(l?.maxDevices),
80230
+ maxTelemetries: posInt(l?.maxTelemetries),
80231
+ maxPoints: posInt(l?.maxPoints),
80232
+ maxActivePerUser: posInt(l?.maxActivePerUser)
80233
+ };
80234
+ }
80235
+ function availableResolutions(limits) {
80236
+ return limits ? RESOLUTIONS.filter((r) => limits.maxDaysByResolution[r.id] != null) : [...RESOLUTIONS];
80237
+ }
80198
80238
  function telemetriesInCatalogOrder(keys) {
80199
80239
  const wanted = new Set(keys);
80200
80240
  return TELEMETRY_CATALOG.filter((t) => wanted.has(t.key)).map((t) => ({ ...t }));
@@ -80257,22 +80297,26 @@ function bucketCount(start, end, resolution) {
80257
80297
  if (resolution === "1d") return Math.ceil((localMidnightOf(end - 1) - localMidnightOf(start)) / DAY_MS) + 1;
80258
80298
  return Math.ceil((end - start) / RESOLUTION_BY_ID[resolution].ms);
80259
80299
  }
80260
- function finestFittingResolution(range) {
80300
+ function finestFittingResolution(range, limits) {
80301
+ if (!limits) return null;
80261
80302
  const len = range.end - range.start;
80262
- return RESOLUTIONS.find((r) => len <= r.maxDays * DAY_MS)?.id ?? null;
80303
+ return RESOLUTIONS.find((r) => {
80304
+ const d = limits.maxDaysByResolution[r.id];
80305
+ return d != null && len <= d * DAY_MS;
80306
+ })?.id ?? null;
80263
80307
  }
80264
- function maxPeriodDays(resolution) {
80265
- return RESOLUTION_BY_ID[resolution].maxDays;
80308
+ function maxPeriodDays(resolution, limits) {
80309
+ return limits?.maxDaysByResolution[resolution] ?? null;
80266
80310
  }
80267
- function periodErrors(range, resolution, now) {
80311
+ function periodErrors(range, resolution, now, limits = null) {
80268
80312
  if (!Number.isFinite(range.start) || !Number.isFinite(range.end)) return ["Informe in\xEDcio e fim."];
80269
80313
  if (range.end <= range.start) return ["O fim precisa ser depois do in\xEDcio."];
80270
80314
  const errs = [];
80271
80315
  if (range.start < MIN_PERIOD_START_MS) errs.push("Per\xEDodos antes de 01/03/2019 n\xE3o s\xE3o suportados.");
80272
80316
  if (range.start > now) errs.push("O in\xEDcio est\xE1 no futuro.");
80273
80317
  if (range.end > now + END_TOLERANCE_MS) errs.push("O fim n\xE3o pode estar no futuro.");
80274
- const maxDays = maxPeriodDays(resolution);
80275
- if (range.end - range.start > maxDays * DAY_MS) {
80318
+ const maxDays = maxPeriodDays(resolution, limits);
80319
+ if (maxDays != null && range.end - range.start > maxDays * DAY_MS) {
80276
80320
  errs.push(`Com intervalos de ${RESOLUTION_BY_ID[resolution].label}, o per\xEDodo m\xE1ximo \xE9 ${maxDays} dia(s).`);
80277
80321
  }
80278
80322
  if (resolution === "1d" && !isLocalMidnight(range.start)) {
@@ -80566,7 +80610,7 @@ var REASON_TEXT = {
80566
80610
  PERIOD_NOT_ALIGNED: "Com intervalos de 1 dia, o in\xEDcio precisa ser \xE0 meia-noite.",
80567
80611
  PERIOD_INVALID: "O per\xEDodo \xE9 inv\xE1lido.",
80568
80612
  DEVICE_NOT_IN_CUSTOMER: "Um dos medidores n\xE3o pertence a este cliente.",
80569
- DEVICE_NOT_ENERGY: "Um dos dispositivos n\xE3o \xE9 um medidor de energia.",
80613
+ DEVICE_NOT_ENERGY: "O servidor de relat\xF3rios ainda n\xE3o aceita este tipo de medidor \u2014 contate o suporte.",
80570
80614
  DEVICE_NO_SOURCE: "Um dos medidores n\xE3o tem fonte de dados para as telemetrias escolhidas.",
80571
80615
  POINTS_LIMIT: "O relat\xF3rio ficaria grande demais \u2014 reduza medidores, telemetrias ou per\xEDodo.",
80572
80616
  NO_DATA_IN_PERIOD: "N\xE3o h\xE1 dados no per\xEDodo escolhido.",
@@ -80598,6 +80642,16 @@ function rejectionText(code, reason, message, details) {
80598
80642
  return message || code || "Pedido recusado.";
80599
80643
  }
80600
80644
  }
80645
+ var WARNING_TEXT = {
80646
+ NOTIFY_REQUESTER_UNMAPPED: "Seu usu\xE1rio n\xE3o tem cadastro no servidor de relat\xF3rios \u2014 n\xE3o haver\xE1 aviso quando ficar pronto; acompanhe em Relat\xF3rios.",
80647
+ DEVICE_NO_DI_SOURCE: "Sem fonte para a demanda estimada de 15 min neste medidor \u2014 a s\xE9rie de demanda sair\xE1 vazia.",
80648
+ TB_ID_MISMATCH: "O v\xEDnculo deste medidor entre ThingsBoard e GCDR est\xE1 divergente.",
80649
+ SOURCE_UNKNOWN_PREVIEW: "N\xE3o foi poss\xEDvel confirmar se h\xE1 dados no per\xEDodo para este medidor.",
80650
+ SOURCE_EMPTY_PREVIEW: "Este medidor parece n\xE3o ter dados no per\xEDodo."
80651
+ };
80652
+ function warningText(code, message) {
80653
+ return code && WARNING_TEXT[code] || message || code || "Aviso.";
80654
+ }
80601
80655
  function failureText(code) {
80602
80656
  switch (code) {
80603
80657
  case "SOURCE_UNAVAILABLE":
@@ -80649,6 +80703,8 @@ var DP2_CSS = `
80649
80703
  font-family: Nunito, var(--myio-font, system-ui, sans-serif); color: var(--myio-text, #1e293b); font-size: 13px;
80650
80704
  height: 100%; display: flex; flex-direction: column; min-height: 0; }
80651
80705
  .dp2-root * { box-sizing: border-box; }
80706
+ .dp2-root p, .dp2-root li, .dp2-root dt, .dp2-root dd, .dp2-root label { font-size: inherit; line-height: 1.45; letter-spacing: normal; }
80707
+ .dp2-root p { margin: 8px 0 0; }
80652
80708
  .dp2-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--myio-border, #e2e8f0); margin: -4px 0 0; }
80653
80709
  .dp2-tab { border: none; background: none; font: inherit; font-weight: 700; color: var(--myio-text-muted, #64748b); padding: 9px 14px; cursor: pointer; border-bottom: 3px solid transparent; }
80654
80710
  .dp2-tab[aria-selected="true"] { color: var(--dp2-ac); border-bottom-color: var(--dp2-ac); }
@@ -80700,8 +80756,9 @@ var DP2_CSS = `
80700
80756
  .dp2-row { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-end; }
80701
80757
  .dp2-field { display: flex; flex-direction: column; gap: 4px; font-weight: 700; font-size: 12px; color: var(--myio-text-muted, #64748b); }
80702
80758
  .dp2-field input { border: 1px solid var(--myio-border, #e2e8f0); background: var(--myio-bg, #f8fafc); color: var(--myio-text, #1e293b); border-radius: 8px; padding: 7px 9px; font: inherit; }
80703
- .dp2-info { color: var(--myio-text-muted, #64748b); }
80704
- .dp2-err { color: var(--dp2-err); font-weight: 700; }
80759
+ .dp2-root .dp2-info { color: var(--myio-text-muted, #64748b); font-size: 12px; }
80760
+ .dp2-root .dp2-err { color: var(--dp2-err); font-weight: 600; font-size: 12px; }
80761
+ .dp2-root p.dp2-err { padding: 7px 10px; border-radius: 8px; background: color-mix(in srgb, var(--dp2-err) 8%, transparent); border: 1px solid color-mix(in srgb, var(--dp2-err) 30%, transparent); }
80705
80762
  .dp2-fix { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-top: 8px; }
80706
80763
  .dp2-tgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 14px; }
80707
80764
  .dp2-check { display: flex; align-items: center; gap: 8px; padding: 6px 4px; cursor: pointer; border-radius: 7px; }
@@ -80850,6 +80907,8 @@ var DemandPanelV2 = class {
80850
80907
  /** Validação no servidor (dry-run) do pedido do passo 4 — antes de gravar o envelope (L-10). */
80851
80908
  validation: { state: "idle", result: null, error: "", seq: 0 },
80852
80909
  config: null,
80910
+ /** GET …/config status: limits are only applied client-side once 'ok'. */
80911
+ configState: "loading",
80853
80912
  telemetries: /* @__PURE__ */ new Set(["consumption"]),
80854
80913
  snapshot: null,
80855
80914
  submitting: false,
@@ -81003,24 +81062,39 @@ var DemandPanelV2 = class {
81003
81062
  const l = this.s.config?.demandLabel;
81004
81063
  return typeof l === "string" && l ? l : DEFAULT_DEMAND_LABEL;
81005
81064
  }
81065
+ /** Limits in force from GCDR (`GET …/config`); null while loading or when unavailable. */
81066
+ limits() {
81067
+ return limitsFromConfig(this.s.config);
81068
+ }
81006
81069
  stepErrors(step) {
81007
81070
  if (step === 1) return this.s.selected.length ? [] : ["Adicione ao menos 1 medidor."];
81008
- if (step === 2) return periodErrors(this.s.period, this.s.resolution, this.now());
81071
+ if (step === 2) return periodErrors(this.s.period, this.s.resolution, this.now(), this.limits());
81009
81072
  if (step === 3) return this.s.telemetries.size ? [] : ["Escolha ao menos 1 telemetria."];
81010
81073
  const errs = [];
81011
81074
  [1, 2, 3].forEach((n) => {
81012
81075
  if (this.stepErrors(n).length) errs.push(`Etapa ${n} incompleta.`);
81013
81076
  });
81014
81077
  const pts = this.s.snapshot?.request.estimate?.points;
81015
- if (pts != null && pts > DEMAND_LIMITS.points) {
81016
- errs.push(`O relat\xF3rio passa do tamanho m\xE1ximo (${fmtN(DEMAND_LIMITS.points)} pontos).`);
81078
+ const maxPoints = this.limits()?.maxPoints;
81079
+ if (pts != null && maxPoints != null && pts > maxPoints) {
81080
+ errs.push(`O relat\xF3rio passa do tamanho m\xE1ximo (${fmtN(maxPoints)} pontos).`);
81017
81081
  }
81018
81082
  const v = this.s.validation;
81019
81083
  if (v.state === "ok" && v.result && !v.result.ok) {
81020
- (v.result.errors || []).forEach((e) => errs.push(rejectionText(e.code || "VALIDATION_FAILED", e.reason, e.message, e.details)));
81084
+ (v.result.errors || []).forEach((e) => errs.push(rejectionText(e.code || "VALIDATION_FAILED", e.reason, e.message, e.details) + this.devicesSuffix(e.details)));
81021
81085
  }
81022
81086
  return errs;
81023
81087
  }
81088
+ /** " (Label A, Label B)" for GCDR issues that list `details.devices[].deviceId` (gcdrDeviceId). */
81089
+ devicesSuffix(details) {
81090
+ const list = details?.devices;
81091
+ if (!Array.isArray(list) || !list.length) return "";
81092
+ const names = list.map((x) => {
81093
+ const d = this.p.devices.find((dev) => dev.gcdrDeviceId === x.deviceId);
81094
+ return d?.label || d?.name || x.deviceId || "?";
81095
+ });
81096
+ return ` (${names.join(", ")})`;
81097
+ }
81024
81098
  view(e) {
81025
81099
  return deriveJobView({
81026
81100
  envelope: e,
@@ -81153,6 +81227,7 @@ var DemandPanelV2 = class {
81153
81227
  const visible = this.p.devices.filter((d) => this.categoryOf.get(d.tbDeviceId) !== null).length;
81154
81228
  const addable = results.filter((d) => !this.s.selected.includes(d.tbDeviceId) && this.eligibility(d).ok).length;
81155
81229
  const sel = this.selectedDevices();
81230
+ const maxDevices = this.limits()?.maxDevices;
81156
81231
  const active = document.activeElement;
81157
81232
  const hadFocus = active?.dataset?.role === "search";
81158
81233
  const caret = hadFocus ? active.selectionStart : null;
@@ -81168,9 +81243,9 @@ var DemandPanelV2 = class {
81168
81243
  <div class="dp2-list" data-role="results">${results.length ? results.map((d) => this.deviceRow(d, "result")).join("") : `<div class="dp2-empty">${this.p.devices.length ? "Nenhum medidor encontrado para essa busca." : "Nenhum medidor de energia neste cliente."}</div>`}</div>
81169
81244
  </section>
81170
81245
  <section class="dp2-col" aria-label="Medidores selecionados">
81171
- <div class="dp2-col-head"><h3><span>Selecionados \xB7 ${sel.length} de ${DEMAND_LIMITS.devices}</span>
81246
+ <div class="dp2-col-head"><h3><span>Selecionados \xB7 ${sel.length}${maxDevices != null ? ` de ${maxDevices}` : ""}</span>
81172
81247
  <button class="dp2-btn link" type="button" data-action="clear" ${sel.length ? "" : "disabled"}>Limpar lista</button></h3>
81173
- <div class="dp2-meter"><span style="width:${Math.min(100, sel.length / DEMAND_LIMITS.devices * 100)}%"></span></div></div>
81248
+ ${maxDevices != null ? `<div class="dp2-meter"><span style="width:${Math.min(100, sel.length / maxDevices * 100)}%"></span></div>` : ""}</div>
81174
81249
  <div class="dp2-list" data-role="selected">${sel.length ? sel.map((d) => this.deviceRow(d, "selected")).join("") : '<div class="dp2-empty">Nenhum medidor na lista.<br>Busque \xE0 esquerda e clique em <b>+ Adicionar</b>.</div>'}</div>
81175
81250
  </section>
81176
81251
  </div>`;
@@ -81183,16 +81258,18 @@ var DemandPanelV2 = class {
81183
81258
  renderStep2() {
81184
81259
  const { start, end, preset } = this.s.period;
81185
81260
  const r = RESOLUTION_BY_ID[this.s.resolution];
81186
- const maxDays = maxPeriodDays(this.s.resolution);
81261
+ const limits = this.limits();
81262
+ const maxDays = maxPeriodDays(this.s.resolution, limits);
81187
81263
  const errs = this.stepErrors(2);
81188
81264
  const valid = Number.isFinite(start) && Number.isFinite(end) && end > start;
81189
- const tooLong = valid && end - start > maxDays * 864e5;
81190
- const fit = tooLong ? finestFittingResolution(this.s.period) : null;
81265
+ const tooLong = valid && maxDays != null && end - start > maxDays * 864e5;
81266
+ const fit = tooLong ? finestFittingResolution(this.s.period, limits) : null;
81191
81267
  const misaligned = valid && this.s.resolution === "1d" && !isLocalMidnight(start);
81192
81268
  const presetTooLong = (id) => {
81193
81269
  const x = presetRange(id, this.now());
81194
- return !!x && x.end - x.start > maxDays * 864e5;
81270
+ return maxDays != null && !!x && x.end - x.start > maxDays * 864e5;
81195
81271
  };
81272
+ const limitsNote = limits ? "" : this.s.configState === "loading" ? '<p class="dp2-info" style="margin:0 0 8px">\u23F3 Carregando os limites vigentes do servidor\u2026</p>' : '<p class="dp2-info" style="margin:0 0 8px">N\xE3o foi poss\xEDvel carregar os limites vigentes \u2014 o per\xEDodo ser\xE1 conferido pelo servidor no resumo.</p>';
81196
81273
  const otherErrs = errs.filter((e) => !/período máximo|meia-noite/.test(e));
81197
81274
  this.el.body.innerHTML = `
81198
81275
  <div class="dp2-card"><h3 tabindex="-1" data-role="step-title">Per\xEDodo</h3>
@@ -81206,7 +81283,11 @@ var DemandPanelV2 = class {
81206
81283
  <div class="dp2-info">${valid ? `Dura\xE7\xE3o: <b>${fmtDuration(end - start)}</b> \xB7 hor\xE1rio de Bras\xEDlia` : ""}</div>
81207
81284
  </div></div>
81208
81285
  <div class="dp2-card"><h3>Resolu\xE7\xE3o</h3>
81209
- <div class="dp2-chips" role="group" aria-label="Resolu\xE7\xE3o">${RESOLUTIONS.map((x) => `<button class="dp2-chip" type="button" data-action="resolution" data-res="${x.id}" aria-pressed="${this.s.resolution === x.id}">${x.label} <small>(at\xE9 ${x.maxDays} d)</small></button>`).join("")}</div>
81286
+ ${limitsNote}
81287
+ <div class="dp2-chips" role="group" aria-label="Resolu\xE7\xE3o">${availableResolutions(limits).map((x) => {
81288
+ const d = limits?.maxDaysByResolution[x.id];
81289
+ return `<button class="dp2-chip" type="button" data-action="resolution" data-res="${x.id}" aria-pressed="${this.s.resolution === x.id}">${x.label}${d != null ? ` <small>(at\xE9 ${d} d)</small>` : ""}</button>`;
81290
+ }).join("")}</div>
81210
81291
  <p class="dp2-info" style="margin:10px 0 0">Cada linha do relat\xF3rio \xE9 um intervalo com <b>${esc4(BUCKET_STATS_LABEL)}</b> de cada telemetria. Os intervalos contam a partir do in\xEDcio do per\xEDodo${this.s.resolution === "1d" ? " (com 1 dia, cada linha \xE9 um dia do calend\xE1rio)" : ""}.
81211
81292
  ${this.s.telemetries.has("consumption") ? `Com <b>Pot\xEAncia Total</b>, o arquivo traz tamb\xE9m a <b>${esc4(this.demandLabel())}</b>, em janelas de 15 min alinhadas ao rel\xF3gio.` : ""}</p>
81212
81293
  ${valid && !tooLong ? `<p class="dp2-info" style="margin:6px 0 0">${fmtN(bucketCount(start, end, this.s.resolution))} intervalo(s) por medidor.</p>` : ""}
@@ -81247,7 +81328,10 @@ var DemandPanelV2 = class {
81247
81328
  validation = `<div class="dp2-err">N\xE3o foi poss\xEDvel validar agora: ${esc4(v.error)}
81248
81329
  <button class="dp2-btn link" type="button" data-action="revalidate">Tentar de novo</button></div>`;
81249
81330
  } else if (vr) {
81250
- const warns = (vr.warnings || []).map((w) => `<li>${esc4(w.message || w.code || "aviso")}</li>`).join("");
81331
+ const warns = (vr.warnings || []).map((w) => {
81332
+ const dev = w.deviceId;
81333
+ return `<li>${esc4(warningText(w.code, w.message) + (dev ? this.devicesSuffix({ devices: [{ deviceId: dev }] }) : ""))}</li>`;
81334
+ }).join("");
81251
81335
  const reuse = vr.reusable ? `<div class="dp2-banner info" style="margin-top:8px">\u267B J\xE1 existe um relat\xF3rio id\xEAntico${vr.reusable.generatedAt ? ` gerado em ${esc4(formatLocalDateTime(Date.parse(vr.reusable.generatedAt)))}` : ""}${vr.reusable.generatedBy?.userId ? ` por ${esc4(vr.reusable.generatedBy.userId)}` : ""}. Confirmar reaproveita o arquivo (sem custo de cota).
81252
81336
  <label class="dp2-check" style="margin-top:6px"><input type="checkbox" data-role="force" ${this.s.force ? "checked" : ""}> Gerar novamente mesmo assim</label></div>` : "";
81253
81337
  validation = `${vr.ok ? '<div class="dp2-info">\u2713 Pedido validado no servidor.</div>' : ""}
@@ -81263,7 +81347,7 @@ var DemandPanelV2 = class {
81263
81347
  <dt>Telemetrias (${req.telemetries.length})</dt><dd><div class="dp2-pills">${req.telemetries.map((t) => `<span class="dp2-pill">${esc4(t.label)} \xB7 ${esc4(t.unit)}</span>`).join("")}</div>
81264
81348
  ${req.telemetries.some((t) => t.key === "consumption") ? `<div class="dp2-info" style="margin-top:4px">Inclui a ${esc4(this.demandLabel())}.</div>` : ""}</dd>
81265
81349
  <dt>Tamanho</dt><dd><span class="dp2-size ${cls}">${txt}</span> <span class="dp2-info">\u2248 ${fmtN(pts)} pontos</span>
81266
- <details class="dp2-details"><summary>Detalhes</summary><span class="dp2-info">${fmtN(est.buckets)} intervalos \xD7 ${req.devices.length} medidores \xD7 ${req.telemetries.length} telemetrias \xB7 limite ${fmtN(DEMAND_LIMITS.points)}</span></details></dd>
81350
+ <details class="dp2-details"><summary>Detalhes</summary><span class="dp2-info">${fmtN(est.buckets)} intervalos \xD7 ${req.devices.length} medidores \xD7 ${req.telemetries.length} telemetrias${this.limits()?.maxPoints != null ? ` \xB7 limite ${fmtN(this.limits().maxPoints)}` : ""}</span></details></dd>
81267
81351
  <dt>Entrega</dt><dd>Arquivos XLSX, CSV e JSON <span class="dp2-info">(dispon\xEDveis por 3 dias; o resumo fica por 1 ano)</span></dd>
81268
81352
  </dl>
81269
81353
  <div style="margin-top:12px">${validation}</div>
@@ -81359,9 +81443,15 @@ var DemandPanelV2 = class {
81359
81443
  async loadConfig() {
81360
81444
  try {
81361
81445
  this.s.config = await this.p.api.config(this.opts());
81362
- if (!this.destroyed) this.render();
81446
+ this.s.configState = "ok";
81447
+ const offered = availableResolutions(this.limits()).map((r) => r.id);
81448
+ if (offered.length && !offered.includes(this.s.resolution)) {
81449
+ this.s.resolution = offered.includes(DEFAULT_RESOLUTION) ? DEFAULT_RESOLUTION : offered[0];
81450
+ }
81363
81451
  } catch {
81452
+ this.s.configState = "error";
81364
81453
  }
81454
+ if (!this.destroyed) this.render();
81365
81455
  }
81366
81456
  async refreshActive() {
81367
81457
  try {
@@ -81659,10 +81749,11 @@ O cancelamento fica registrado na auditoria.`, "Sim, cancelar", "Manter")) retur
81659
81749
  /* ------------------------------------------------------------------ wizard actions */
81660
81750
  async addDevices(ids) {
81661
81751
  const fresh = ids.filter((id) => !this.s.selected.includes(id) && this.deviceById.has(id) && this.eligibility(this.deviceById.get(id)).ok);
81662
- const room = DEMAND_LIMITS.devices - this.s.selected.length;
81752
+ const maxDevices = this.limits()?.maxDevices;
81753
+ const room = maxDevices != null ? maxDevices - this.s.selected.length : Infinity;
81663
81754
  if (fresh.length > room) {
81664
81755
  if (room <= 0) {
81665
- this.toast("warning", `A lista j\xE1 tem ${DEMAND_LIMITS.devices} medidores.`);
81756
+ this.toast("warning", `A lista j\xE1 tem ${maxDevices} medidores.`);
81666
81757
  return;
81667
81758
  }
81668
81759
  if (!await this.confirmDialog("Limite de medidores", `Cabem ${room} de ${fresh.length}. Adicionar os ${room} primeiros?`, `Adicionar ${room}`)) return;
@@ -81671,7 +81762,7 @@ O cancelamento fica registrado na auditoria.`, "Sim, cancelar", "Manter")) retur
81671
81762
  this.s.selected.push(...added);
81672
81763
  if (added.length) {
81673
81764
  const first = this.deviceById.get(added[0]);
81674
- this.announce(`${added.length === 1 ? first.label + " adicionado" : added.length + " medidores adicionados"} \xB7 ${this.s.selected.length} de ${DEMAND_LIMITS.devices}`);
81765
+ this.announce(`${added.length === 1 ? first.label + " adicionado" : added.length + " medidores adicionados"} \xB7 ${this.s.selected.length}${maxDevices != null ? ` de ${maxDevices}` : ""}`);
81675
81766
  }
81676
81767
  }
81677
81768
  resetWizard() {
@@ -81753,7 +81844,7 @@ O cancelamento fica registrado na auditoria.`, "Sim, cancelar", "Manter")) retur
81753
81844
  else {
81754
81845
  const d = this.deviceById.get(t.dataset.id);
81755
81846
  this.s.selected = this.s.selected.filter((id) => id !== t.dataset.id);
81756
- if (d) this.announce(`${d.label} removido \xB7 ${this.s.selected.length} de ${DEMAND_LIMITS.devices}`);
81847
+ if (d) this.announce(`${d.label} removido \xB7 ${this.s.selected.length}`);
81757
81848
  }
81758
81849
  this.render();
81759
81850
  const next = Array.from(this.el.body.querySelectorAll(sel));
@@ -81785,7 +81876,8 @@ O cancelamento fica registrado na auditoria.`, "Sim, cancelar", "Manter")) retur
81785
81876
  void this.validateSnapshot();
81786
81877
  return;
81787
81878
  case "shorten": {
81788
- const maxDays = maxPeriodDays(this.s.resolution);
81879
+ const maxDays = maxPeriodDays(this.s.resolution, this.limits());
81880
+ if (maxDays == null) break;
81789
81881
  this.s.period = { preset: "custom", start: this.s.period.end - maxDays * 864e5, end: this.s.period.end };
81790
81882
  break;
81791
81883
  }
@@ -82019,6 +82111,728 @@ function tbUserFromJwt(token) {
82019
82111
  }
82020
82112
  }
82021
82113
 
82114
+ // src/components/premium-modals/reports-hub/catalog.ts
82115
+ var REPORT_DOMAINS = ["energy", "water", "temperature", "alarms"];
82116
+ var DEFAULT_REPORTS_CATALOG = [
82117
+ {
82118
+ id: "energy",
82119
+ label: "\u26A1 Energia",
82120
+ items: [
82121
+ { id: "entrada", label: "Entrada", icon: "\u{1F4E5}", tint: { bg: "#fff8e1", fg: "#f57f17" }, description: "Medidores de entrada", kind: "group-report" },
82122
+ { id: "area_comum", label: "\xC1rea Comum", icon: "\u{1F3E2}", tint: { bg: "#f3e5f5", fg: "#6a1b9a" }, description: "Consumo de \xE1reas comuns", kind: "group-report" },
82123
+ { id: "lojas", label: "Lojas", icon: "\u{1F3EC}", tint: { bg: "#e8f5e9", fg: "#2e7d32" }, description: "Consumo por loja", kind: "group-report" },
82124
+ { id: "todos", label: "Todos Dispositivos", icon: "\u{1F4CB}", tint: { bg: "#e3f2fd", fg: "#1565c0" }, description: "Todos os medidores", kind: "group-report" },
82125
+ { id: "demand_telemetry", label: "Demandas e Telemetrias", icon: "\u26A1", tint: { bg: "#ede7f6", fg: "#3e1a7d" }, description: "V\xE1rios medidores \xB7 per\xEDodo \xB7 telemetrias", kind: "demand-panel" }
82126
+ ]
82127
+ },
82128
+ {
82129
+ id: "water",
82130
+ label: "\u{1F4A7} \xC1gua",
82131
+ items: [
82132
+ { id: "entrada", label: "Entrada", icon: "\u{1F4E5}", tint: { bg: "#fff8e1", fg: "#f57f17" }, description: "Medidores de entrada", kind: "group-report" },
82133
+ { id: "area_comum", label: "\xC1rea Comum", icon: "\u{1F3E2}", tint: { bg: "#f3e5f5", fg: "#6a1b9a" }, description: "Consumo de \xE1reas comuns", kind: "group-report" },
82134
+ { id: "lojas", label: "Lojas", icon: "\u{1F3EC}", tint: { bg: "#e0f2f1", fg: "#00695c" }, description: "Consumo por loja", kind: "group-report" },
82135
+ { id: "todos", label: "Todos Dispositivos", icon: "\u{1F4CB}", tint: { bg: "#e3f2fd", fg: "#1565c0" }, description: "Todos os hidr\xF4metros", kind: "group-report" }
82136
+ ]
82137
+ },
82138
+ {
82139
+ id: "temperature",
82140
+ label: "\u{1F321}\uFE0F Temperatura",
82141
+ items: [
82142
+ { id: "climatizavel", label: "Ambientes Climatiz\xE1veis", icon: "\u2744\uFE0F", tint: { bg: "#e1f5fe", fg: "#0277bd" }, description: "Ambientes com termostato", kind: "group-report" },
82143
+ { id: "nao_climatizavel", label: "Ambientes N\xE3o Climatiz\xE1veis", icon: "\u{1F324}\uFE0F", tint: { bg: "#fff3e0", fg: "#e65100" }, description: "Ambientes sem climatiza\xE7\xE3o", kind: "group-report" },
82144
+ { id: "todos", label: "Todos Ambientes", icon: "\u{1F4CB}", tint: { bg: "#e3f2fd", fg: "#1565c0" }, description: "Todos os termostatos", kind: "group-report" }
82145
+ ]
82146
+ },
82147
+ {
82148
+ id: "alarms",
82149
+ label: "\u{1F514} Alarmes",
82150
+ items: [
82151
+ { id: "por_dispositivo", label: "Por Dispositivo", icon: "\u{1F4DF}", tint: { bg: "#fce4ec", fg: "#880e4f" }, description: "Alarmes por dispositivo", kind: "alarm-report" },
82152
+ { id: "dispositivo_x_alarme", label: "Por Dispositivo \xD7 Tipo", icon: "\u{1F500}", tint: { bg: "#fff3e0", fg: "#bf360c" }, description: "Cruzamento dispositivo \xD7 regra", kind: "alarm-report" },
82153
+ { id: "por_tipo", label: "Por Tipo de Alarme", icon: "\u{1F3F7}\uFE0F", tint: { bg: "#ede7f6", fg: "#4527a0" }, description: "Alarmes agrupados por tipo", kind: "alarm-report" }
82154
+ ]
82155
+ }
82156
+ ];
82157
+ var DEFAULT_ENABLED_REPORT_ITEMS = Object.freeze({
82158
+ energy_lojas: true,
82159
+ energy_entrada: false,
82160
+ energy_area_comum: false,
82161
+ energy_todos: false,
82162
+ energy_demand_telemetry: false,
82163
+ water_lojas: false,
82164
+ water_entrada: false,
82165
+ water_area_comum: false,
82166
+ water_todos: false,
82167
+ temperature_climatizavel: false,
82168
+ temperature_nao_climatizavel: false,
82169
+ temperature_todos: false,
82170
+ alarms_por_dispositivo: false,
82171
+ alarms_dispositivo_x_alarme: false,
82172
+ alarms_por_tipo: false
82173
+ });
82174
+ var itemKey = (domain, itemId) => `${domain}_${itemId}`;
82175
+ function validateCatalog(catalog, onDrop) {
82176
+ const seenDomains = /* @__PURE__ */ new Set();
82177
+ const out = [];
82178
+ for (const d of catalog || []) {
82179
+ if (!d || !REPORT_DOMAINS.includes(d.id)) {
82180
+ onDrop?.(`unknown domain "${String(d?.id)}"`);
82181
+ continue;
82182
+ }
82183
+ if (seenDomains.has(d.id)) {
82184
+ onDrop?.(`duplicate domain "${d.id}"`);
82185
+ continue;
82186
+ }
82187
+ seenDomains.add(d.id);
82188
+ const seenItems = /* @__PURE__ */ new Set();
82189
+ const items = [];
82190
+ for (const it of d.items || []) {
82191
+ if (!it || typeof it.id !== "string" || !it.id) {
82192
+ onDrop?.(`item without id in "${d.id}"`);
82193
+ continue;
82194
+ }
82195
+ if (seenItems.has(it.id)) {
82196
+ onDrop?.(`duplicate item "${d.id}_${it.id}"`);
82197
+ continue;
82198
+ }
82199
+ seenItems.add(it.id);
82200
+ items.push(it);
82201
+ }
82202
+ out.push({ ...d, items });
82203
+ }
82204
+ return out;
82205
+ }
82206
+ function resolveReportItemStates(catalog, raw, available) {
82207
+ const flags = raw && typeof raw === "object" ? raw : {};
82208
+ const out = /* @__PURE__ */ new Map();
82209
+ for (const d of catalog) {
82210
+ for (const it of d.items) {
82211
+ const key = itemKey(d.id, it.id);
82212
+ if (!available(d.id, it)) {
82213
+ out.set(key, "hidden");
82214
+ continue;
82215
+ }
82216
+ const v = flags[key];
82217
+ const enabled = typeof v === "boolean" ? v : DEFAULT_ENABLED_REPORT_ITEMS[key] ?? false;
82218
+ out.set(key, enabled ? "enabled" : "locked");
82219
+ }
82220
+ }
82221
+ return out;
82222
+ }
82223
+ function resolveInitialDomain(catalog, states, initialDomain) {
82224
+ const has = (d, want) => (catalog.find((c) => c.id === d)?.items || []).some((it) => want(states.get(itemKey(d, it.id))));
82225
+ const visible = (s) => s === "enabled" || s === "locked";
82226
+ if (initialDomain && has(initialDomain, visible)) return initialDomain;
82227
+ const enabled = catalog.find((d) => has(d.id, (s) => s === "enabled"));
82228
+ if (enabled) return enabled.id;
82229
+ const firstVisible = catalog.find((d) => has(d.id, visible));
82230
+ return firstVisible ? firstVisible.id : null;
82231
+ }
82232
+
82233
+ // src/components/premium-modals/reports-hub/items.ts
82234
+ var GROUP_LABELS = {
82235
+ lojas: "Lojas",
82236
+ entrada: "Entrada",
82237
+ area_comum: "\xC1rea Comum",
82238
+ areacomum: "\xC1rea Comum",
82239
+ banheiros: "Banheiros",
82240
+ climatizavel: "Climatiz\xE1vel",
82241
+ nao_climatizavel: "N\xE3o Climatiz\xE1vel"
82242
+ };
82243
+ function toItem(d, domain, groupLabel) {
82244
+ return {
82245
+ id: d.ingestionId || d.id || "",
82246
+ identifier: d.identifier || d.label || d.name || "",
82247
+ label: d.label || d.name || d.identifier || "",
82248
+ ...groupLabel ? { groupLabel } : {},
82249
+ // RFC-0128: the report drops devices the dashboard KPIs already exclude
82250
+ excludeGroupsTotals: d.excludeGroupsTotals || null,
82251
+ // Temperature: sensor offset added to every reading by the report
82252
+ ...domain === "temperature" ? { temperatureOffset: Number(d.offSetTemperature) || 0 } : {}
82253
+ };
82254
+ }
82255
+ function buildReportItemsList(groups, domain, group) {
82256
+ const g = groups || {};
82257
+ if (group === "todos") {
82258
+ return Object.entries(g).filter(([key]) => key !== "ocultos").flatMap(([key, items]) => (items || []).map((d) => toItem(d, domain, GROUP_LABELS[key] || key)));
82259
+ }
82260
+ const groupKey = group === "area_comum" ? "areacomum" : group;
82261
+ return (g[groupKey] || []).map((d) => toItem(d, domain, null));
82262
+ }
82263
+
82264
+ // src/components/premium-modals/reports-hub/handlers.ts
82265
+ var ReportsHubUserError = class extends Error {
82266
+ };
82267
+ var GROUP_DOMAINS = ["energy", "water", "temperature"];
82268
+ var groupReportHandler = {
82269
+ domains: GROUP_DOMAINS,
82270
+ isAvailable: (ctx, domain) => (ctx.domains || []).includes(domain),
82271
+ async prepare({ domain, item, context, visual, signal }) {
82272
+ const d = domain;
82273
+ if (!context.domains.includes(d)) throw new ReportsHubUserError("Relat\xF3rio indispon\xEDvel para este cliente.");
82274
+ await context.ensureDomainLoaded?.(d, signal);
82275
+ const base = context.getAllReportBase();
82276
+ const itemsList = buildReportItemsList(context.getGroups(d), d, item.id);
82277
+ const temperature = d === "temperature" ? {
82278
+ ...context.temperature?.validRange ? { temperatureValidRange: context.temperature.validRange } : {},
82279
+ ...context.temperature?.idealRange ? { temperatureIdealRange: context.temperature.idealRange } : {}
82280
+ } : {};
82281
+ const theme = visual.palette ?? base.theme;
82282
+ const customerName = visual.customerName || base.customerName;
82283
+ return () => {
82284
+ openDashboardPopupAllReport({
82285
+ ...base,
82286
+ ...temperature,
82287
+ domain: d,
82288
+ group: item.id,
82289
+ itemsList,
82290
+ ...theme ? { theme } : {},
82291
+ ...customerName ? { customerName } : {}
82292
+ });
82293
+ };
82294
+ }
82295
+ };
82296
+ var demandPanelHandler = {
82297
+ domains: ["energy"],
82298
+ isAvailable: (ctx) => (ctx.domains || []).includes("energy") && typeof ctx.getDemandPanelParams === "function",
82299
+ prepare({ context, visual }) {
82300
+ const dp = context.getDemandPanelParams?.();
82301
+ if (!dp) throw new ReportsHubUserError("Relat\xF3rio de demanda indispon\xEDvel para este cliente.");
82302
+ const items = Object.entries(context.getGroups("energy") || {}).filter(([key]) => key !== "ocultos").flatMap(([, list]) => list || []);
82303
+ const devices = demandDevicesFromItems(items);
82304
+ const theme = visual.palette ?? dp.theme;
82305
+ const name = visual.customerName || dp.customer.name;
82306
+ return () => {
82307
+ openDemandPanelV2({ ...dp, devices, theme, customer: { ...dp.customer, name } });
82308
+ };
82309
+ }
82310
+ };
82311
+ var DEFAULT_HANDLERS = {
82312
+ "group-report": groupReportHandler,
82313
+ "demand-panel": demandPanelHandler
82314
+ };
82315
+
82316
+ // src/components/premium-modals/reports-hub/ReportsHubView.ts
82317
+ var LOCKED_HINT = "Indispon\xEDvel para este cliente";
82318
+ var SAFE_COLOR = /^(#[0-9a-f]{3,8}|(rgb|rgba|hsl|hsla)\([0-9.,%\s/]+\)|var\(--[a-z0-9-]+(,\s*#[0-9a-f]{3,8})?\)|[a-z]+)$/i;
82319
+ var safeColor = (c) => typeof c === "string" && SAFE_COLOR.test(c.trim()) ? c.trim() : "";
82320
+ function buildCard(doc, domainId, item, state6) {
82321
+ const cell = doc.createElement("div");
82322
+ cell.className = "rh-cell";
82323
+ const card = doc.createElement("button");
82324
+ card.type = "button";
82325
+ card.className = "rh-card";
82326
+ card.dataset.domain = domainId;
82327
+ card.dataset.item = item.id;
82328
+ card.dataset.state = state6;
82329
+ const ico = doc.createElement("span");
82330
+ ico.className = "rh-ico";
82331
+ ico.setAttribute("aria-hidden", "true");
82332
+ ico.textContent = item.icon || "";
82333
+ const bg = safeColor(item.tint?.bg);
82334
+ const fg = safeColor(item.tint?.fg);
82335
+ if (bg) ico.style.background = bg;
82336
+ if (fg) ico.style.color = fg;
82337
+ const text2 = doc.createElement("span");
82338
+ text2.className = "rh-text";
82339
+ const title = doc.createElement("span");
82340
+ title.className = "rh-title";
82341
+ title.textContent = item.label;
82342
+ const desc = doc.createElement("span");
82343
+ desc.className = "rh-desc";
82344
+ desc.textContent = item.description || "";
82345
+ text2.append(title, desc);
82346
+ card.append(ico, text2);
82347
+ if (state6 === "locked") {
82348
+ card.setAttribute("aria-disabled", "true");
82349
+ card.title = LOCKED_HINT;
82350
+ card.setAttribute("aria-label", `${item.label} \u2014 ${LOCKED_HINT}`);
82351
+ const lock = doc.createElement("span");
82352
+ lock.className = "rh-lock";
82353
+ lock.setAttribute("aria-hidden", "true");
82354
+ lock.textContent = "\u{1F512}";
82355
+ const hint = doc.createElement("span");
82356
+ hint.className = "rh-hint";
82357
+ hint.textContent = LOCKED_HINT;
82358
+ text2.appendChild(hint);
82359
+ card.appendChild(lock);
82360
+ } else {
82361
+ card.setAttribute("aria-label", item.label);
82362
+ }
82363
+ const err = doc.createElement("div");
82364
+ err.className = "rh-err";
82365
+ err.setAttribute("aria-live", "polite");
82366
+ cell.append(card, err);
82367
+ return { cell, card, text: text2, err };
82368
+ }
82369
+
82370
+ // src/components/premium-modals/reports-hub/styles.ts
82371
+ var RH_STYLE_ID = "myio-reports-hub-styles";
82372
+ var RH_CSS = `
82373
+ .rh-overlay{position:fixed;inset:0;z-index:999998;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.5);backdrop-filter:blur(4px);font-family:'Nunito',system-ui,sans-serif;}
82374
+ .rh-modal{--rh-ac:var(--myio-brand-700,#3e1a7d);--rh-bg:#fff;--rh-panel:#f9fafb;--rh-card:#fafafa;--rh-border:#e5e7eb;--rh-text:#1f2937;--rh-muted:#6b7280;--rh-err:#dc2626;
82375
+ position:relative;background:var(--rh-bg);color:var(--rh-text);border-radius:16px;box-shadow:0 20px 60px rgba(0,0,0,.25);width:min(680px,92vw);max-height:90vh;overflow:hidden;display:flex;flex-direction:column;font-size:13px;}
82376
+ .rh-modal[data-theme="dark"]{--rh-bg:#111827;--rh-panel:#0f172a;--rh-card:#1f2937;--rh-border:#334155;--rh-text:#e5e7eb;--rh-muted:#94a3b8;--rh-err:#f87171;
82377
+ --rh-ac:color-mix(in srgb,var(--myio-brand-700,#3e1a7d) 45%,#fff);}
82378
+ .rh-modal.is-maximized{width:100vw;max-height:100vh;height:100vh;border-radius:0;}
82379
+ .rh-modal *{box-sizing:border-box;}
82380
+ .rh-tabs{display:flex;border-bottom:1px solid var(--rh-border);background:var(--rh-panel);flex-shrink:0;overflow-x:auto;}
82381
+ .rh-tab{flex:1 1 auto;padding:12px 8px;border:none;background:transparent;cursor:pointer;font:inherit;font-weight:600;color:var(--rh-muted);border-bottom:3px solid transparent;white-space:nowrap;}
82382
+ .rh-tab:hover{color:var(--rh-ac);}
82383
+ .rh-tab[aria-selected="true"]{color:var(--rh-ac);border-bottom-color:var(--rh-ac);background:var(--rh-bg);}
82384
+ .rh-tab:focus-visible,.rh-card:focus-visible,.rh-retry:focus-visible{outline:2px solid var(--rh-ac);outline-offset:2px;}
82385
+ .rh-body{padding:20px;overflow-y:auto;flex:1;min-height:0;}
82386
+ .rh-panel[hidden]{display:none;}
82387
+ .rh-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:10px;}
82388
+ .rh-card{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1.5px solid var(--rh-border);border-radius:12px;background:var(--rh-card);color:inherit;cursor:pointer;position:relative;text-align:left;width:100%;font:inherit;transition:border-color .15s,box-shadow .15s,transform .15s;}
82389
+ .rh-card[data-state="enabled"]:hover:not([aria-busy="true"]):not(:disabled){border-color:color-mix(in srgb,var(--rh-ac) 45%,transparent);box-shadow:0 4px 12px rgba(0,0,0,.10);transform:translateY(-1px);}
82390
+ .rh-card[data-state="locked"]{opacity:.6;cursor:not-allowed;}
82391
+ .rh-card:disabled{cursor:progress;}
82392
+ .rh-ico{width:40px;height:40px;display:flex;align-items:center;justify-content:center;border-radius:10px;font-size:20px;flex-shrink:0;}
82393
+ .rh-text{display:flex;flex-direction:column;gap:2px;min-width:0;}
82394
+ .rh-title{font-size:14px;font-weight:600;}
82395
+ .rh-desc{font-size:11px;color:var(--rh-muted);}
82396
+ .rh-lock{position:absolute;top:8px;right:8px;font-size:12px;color:var(--rh-muted);background:var(--rh-panel);border:1px solid var(--rh-border);padding:2px 5px;border-radius:20px;line-height:1.4;}
82397
+ .rh-hint{font-size:11px;color:var(--rh-muted);}
82398
+ .rh-spin{width:16px;height:16px;border-radius:50%;border:2px solid var(--rh-border);border-top-color:var(--rh-ac);animation:rh-spin .8s linear infinite;margin-left:auto;flex-shrink:0;}
82399
+ @keyframes rh-spin{to{transform:rotate(360deg);}}
82400
+ .rh-err{font-size:11px;font-weight:600;color:var(--rh-err);display:flex;gap:6px;align-items:center;flex-wrap:wrap;}
82401
+ .rh-retry{border:none;background:none;color:var(--rh-ac);font:inherit;font-weight:700;cursor:pointer;padding:0;text-decoration:underline;}
82402
+ .rh-empty{color:var(--rh-muted);text-align:center;padding:40px 12px;}
82403
+ .rh-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;}
82404
+ `;
82405
+ function injectReportsHubStyles(doc) {
82406
+ if (doc.getElementById(RH_STYLE_ID)) return;
82407
+ const style = doc.createElement("style");
82408
+ style.id = RH_STYLE_ID;
82409
+ style.textContent = RH_CSS;
82410
+ (doc.head || doc.documentElement).appendChild(style);
82411
+ }
82412
+
82413
+ // src/components/premium-modals/reports-hub/openReportsHub.ts
82414
+ var LIB_VERSION = package_default.version || "";
82415
+ var MODAL_ID = "myio-reports-hub";
82416
+ var GENERIC_ERROR = "N\xE3o foi poss\xEDvel abrir este relat\xF3rio.";
82417
+ var registry = /* @__PURE__ */ new WeakMap();
82418
+ function defaultDocument() {
82419
+ try {
82420
+ const top = window.top;
82421
+ if (top && top.document) return top.document;
82422
+ } catch {
82423
+ }
82424
+ return document;
82425
+ }
82426
+ function logWarn(...a) {
82427
+ if (typeof console !== "undefined") console.warn("[ReportsHub]", ...a);
82428
+ }
82429
+ var ReportsHub = class {
82430
+ doc;
82431
+ p;
82432
+ visual;
82433
+ catalog;
82434
+ handlers;
82435
+ states;
82436
+ opener;
82437
+ overlay;
82438
+ modal;
82439
+ chrome = null;
82440
+ tabs = [];
82441
+ panels = /* @__PURE__ */ new Map();
82442
+ cards = [];
82443
+ inflight = null;
82444
+ seq = 0;
82445
+ done = false;
82446
+ constructor(doc, p) {
82447
+ this.doc = doc;
82448
+ this.p = p;
82449
+ this.visual = {
82450
+ palette: p.theme,
82451
+ mode: p.themeMode ?? (p.theme?.mode === "dark" ? "dark" : "light"),
82452
+ customerName: p.customerName ?? ""
82453
+ };
82454
+ this.catalog = validateCatalog(p.catalog ?? DEFAULT_REPORTS_CATALOG, (w) => logWarn("catalog:", w));
82455
+ this.handlers = { ...DEFAULT_HANDLERS };
82456
+ Object.entries(p.handlers || {}).forEach(([k, h3]) => {
82457
+ if (h3) this.handlers[k] = h3;
82458
+ });
82459
+ this.states = resolveReportItemStates(
82460
+ this.catalog,
82461
+ p.enabledItems,
82462
+ (domain, item) => this.isAvailable(domain, item)
82463
+ );
82464
+ this.opener = doc.activeElement;
82465
+ }
82466
+ get isOpen() {
82467
+ return !this.done;
82468
+ }
82469
+ isAvailable(domain, item) {
82470
+ const h3 = this.handlers[item.kind];
82471
+ if (!h3 || typeof h3.prepare !== "function") return false;
82472
+ if (h3.domains && !h3.domains.includes(domain)) return false;
82473
+ try {
82474
+ return h3.isAvailable ? h3.isAvailable(this.p.context, domain) !== false : true;
82475
+ } catch {
82476
+ return false;
82477
+ }
82478
+ }
82479
+ mount() {
82480
+ const doc = this.doc;
82481
+ injectReportsHubStyles(doc);
82482
+ this.overlay = doc.createElement("div");
82483
+ this.overlay.className = "rh-overlay";
82484
+ this.overlay.id = MODAL_ID;
82485
+ this.modal = doc.createElement("div");
82486
+ this.modal.className = "rh-modal";
82487
+ this.modal.setAttribute("role", "dialog");
82488
+ this.modal.setAttribute("aria-modal", "true");
82489
+ this.modal.setAttribute("aria-label", "Relat\xF3rios");
82490
+ const headerSlot = doc.createElement("div");
82491
+ const tabsEl = doc.createElement("div");
82492
+ tabsEl.className = "rh-tabs";
82493
+ tabsEl.setAttribute("role", "tablist");
82494
+ tabsEl.setAttribute("aria-label", "Dom\xEDnios de relat\xF3rio");
82495
+ const body = doc.createElement("div");
82496
+ body.className = "rh-body";
82497
+ this.modal.append(headerSlot, tabsEl, body);
82498
+ this.overlay.appendChild(this.modal);
82499
+ const initial = resolveInitialDomain(this.catalog, this.states, this.p.initialDomain);
82500
+ const visibleDomains = this.catalog.filter(
82501
+ (d) => d.items.some((it) => this.states.get(itemKey(d.id, it.id)) !== "hidden")
82502
+ );
82503
+ if (!initial || !visibleDomains.length) {
82504
+ tabsEl.remove();
82505
+ const empty = doc.createElement("div");
82506
+ empty.className = "rh-empty";
82507
+ empty.textContent = "Nenhum relat\xF3rio dispon\xEDvel";
82508
+ body.appendChild(empty);
82509
+ } else {
82510
+ visibleDomains.forEach((d) => {
82511
+ const tab = doc.createElement("button");
82512
+ tab.type = "button";
82513
+ tab.className = "rh-tab";
82514
+ tab.id = `${MODAL_ID}-tab-${d.id}`;
82515
+ tab.dataset.domain = d.id;
82516
+ tab.setAttribute("role", "tab");
82517
+ tab.setAttribute("aria-controls", `${MODAL_ID}-panel-${d.id}`);
82518
+ tab.textContent = d.label;
82519
+ tab.addEventListener("click", () => this.selectTab(d.id, false));
82520
+ tabsEl.appendChild(tab);
82521
+ this.tabs.push(tab);
82522
+ const panel = doc.createElement("div");
82523
+ panel.className = "rh-panel";
82524
+ panel.id = `${MODAL_ID}-panel-${d.id}`;
82525
+ panel.setAttribute("role", "tabpanel");
82526
+ panel.setAttribute("aria-labelledby", tab.id);
82527
+ const grid = doc.createElement("div");
82528
+ grid.className = "rh-cards";
82529
+ d.items.forEach((item) => {
82530
+ const state6 = this.states.get(itemKey(d.id, item.id));
82531
+ if (!state6 || state6 === "hidden") return;
82532
+ const refs = buildCard(doc, d.id, item, state6);
82533
+ refs.card.addEventListener("click", () => this.onCardClick(d.id, item, refs));
82534
+ grid.appendChild(refs.cell);
82535
+ this.cards.push({ ...refs, domain: d.id, item });
82536
+ });
82537
+ panel.appendChild(grid);
82538
+ body.appendChild(panel);
82539
+ this.panels.set(d.id, panel);
82540
+ });
82541
+ tabsEl.addEventListener("keydown", this.onTabsKeydown);
82542
+ }
82543
+ this.chrome = createPremiumModalChrome({
82544
+ modalId: MODAL_ID,
82545
+ icon: "\u{1F4CA}",
82546
+ title: "Relat\xF3rios",
82547
+ modalEl: this.modal,
82548
+ headerSlot,
82549
+ theme: this.visual.mode,
82550
+ showThemeToggle: false,
82551
+ showMaximize: true,
82552
+ useGlobals: false,
82553
+ palette: this.visual.palette ?? null,
82554
+ onClose: () => this.finish("cancel"),
82555
+ footer: {
82556
+ customerName: this.visual.customerName,
82557
+ libVersion: LIB_VERSION ? { current: LIB_VERSION } : false,
82558
+ libVersionMode: "static"
82559
+ }
82560
+ });
82561
+ this.overlay.addEventListener("click", this.onOverlayClick);
82562
+ this.overlay.addEventListener("keydown", this.onKeydown);
82563
+ (doc.body || doc.documentElement).appendChild(this.overlay);
82564
+ if (initial) this.selectTab(initial, true);
82565
+ else this.modal.setAttribute("tabindex", "-1");
82566
+ if (!initial) this.modal.focus();
82567
+ }
82568
+ selectTab(domain, focus) {
82569
+ this.tabs.forEach((t) => {
82570
+ const on = t.dataset.domain === domain;
82571
+ t.setAttribute("aria-selected", String(on));
82572
+ t.tabIndex = on ? 0 : -1;
82573
+ if (on && focus) t.focus();
82574
+ });
82575
+ this.panels.forEach((panel, d) => {
82576
+ panel.hidden = d !== domain;
82577
+ });
82578
+ }
82579
+ onTabsKeydown = (e) => {
82580
+ const i = this.tabs.findIndex((t) => t === e.target);
82581
+ if (i < 0) return;
82582
+ let next = -1;
82583
+ if (e.key === "ArrowRight") next = (i + 1) % this.tabs.length;
82584
+ else if (e.key === "ArrowLeft") next = (i - 1 + this.tabs.length) % this.tabs.length;
82585
+ else if (e.key === "Home") next = 0;
82586
+ else if (e.key === "End") next = this.tabs.length - 1;
82587
+ if (next < 0) return;
82588
+ e.preventDefault();
82589
+ this.selectTab(this.tabs[next].dataset.domain, true);
82590
+ };
82591
+ onOverlayClick = (e) => {
82592
+ if (e.target === this.overlay) this.finish("cancel");
82593
+ };
82594
+ onKeydown = (e) => {
82595
+ if (e.key === "Escape") {
82596
+ e.preventDefault();
82597
+ e.stopPropagation();
82598
+ this.finish("cancel");
82599
+ return;
82600
+ }
82601
+ if (e.key !== "Tab") return;
82602
+ const focusables = Array.from(
82603
+ this.modal.querySelectorAll("button, [href], input, select, textarea, [tabindex]")
82604
+ ).filter((el2) => !el2.disabled && el2.tabIndex >= 0 && !el2.closest("[hidden]"));
82605
+ if (!focusables.length) return;
82606
+ const first = focusables[0];
82607
+ const last = focusables[focusables.length - 1];
82608
+ const active = this.doc.activeElement;
82609
+ if (e.shiftKey && (active === first || !this.modal.contains(active))) {
82610
+ e.preventDefault();
82611
+ last.focus();
82612
+ } else if (!e.shiftKey && (active === last || !this.modal.contains(active))) {
82613
+ e.preventDefault();
82614
+ first.focus();
82615
+ }
82616
+ };
82617
+ setBusy(chosen) {
82618
+ this.cards.forEach((c) => {
82619
+ const busy = !!chosen;
82620
+ if (c.card === chosen?.card) {
82621
+ c.card.setAttribute("aria-busy", "true");
82622
+ } else {
82623
+ c.card.disabled = busy;
82624
+ c.card.removeAttribute("aria-busy");
82625
+ }
82626
+ });
82627
+ if (!chosen) this.cards.forEach((c) => c.card.removeAttribute("aria-busy"));
82628
+ }
82629
+ onCardClick(domain, item, refs) {
82630
+ if (this.done || this.inflight) return;
82631
+ if (refs.card.dataset.state !== "enabled") return;
82632
+ void this.select(domain, item, refs);
82633
+ }
82634
+ async select(domain, item, refs) {
82635
+ const handler = this.handlers[item.kind];
82636
+ if (!handler) return;
82637
+ const id = ++this.seq;
82638
+ const controller = new AbortController();
82639
+ this.inflight = { id, controller, card: refs };
82640
+ refs.err.textContent = "";
82641
+ const spin = this.doc.createElement("span");
82642
+ spin.className = "rh-spin";
82643
+ spin.setAttribute("aria-hidden", "true");
82644
+ refs.card.appendChild(spin);
82645
+ this.setBusy(refs);
82646
+ let open;
82647
+ try {
82648
+ open = await handler.prepare({
82649
+ domain,
82650
+ item,
82651
+ context: this.p.context,
82652
+ visual: this.visual,
82653
+ signal: controller.signal
82654
+ });
82655
+ } catch (err) {
82656
+ if (controller.signal.aborted || this.done || this.inflight?.id !== id) return;
82657
+ spin.remove();
82658
+ this.inflight = null;
82659
+ this.setBusy(null);
82660
+ const message = err instanceof ReportsHubUserError ? err.message : GENERIC_ERROR;
82661
+ logWarn(`prepare failed (${domain}/${item.id}):`, err?.message || err);
82662
+ this.showError(domain, item, refs, message);
82663
+ this.p.onError?.({ domain, item: item.id, phase: "prepare", message });
82664
+ return;
82665
+ }
82666
+ if (controller.signal.aborted || this.done || this.inflight?.id !== id) return;
82667
+ this.inflight = null;
82668
+ this.finish("success");
82669
+ try {
82670
+ this.p.onOpenReport?.({ domain, item: item.id });
82671
+ } catch {
82672
+ }
82673
+ try {
82674
+ if (typeof open !== "function") throw new Error("handler returned no opener");
82675
+ open();
82676
+ } catch (err) {
82677
+ logWarn(`open failed (${domain}/${item.id}):`, err?.message || err);
82678
+ this.p.onError?.({ domain, item: item.id, phase: "open", message: GENERIC_ERROR });
82679
+ try {
82680
+ MyIOToast.error(GENERIC_ERROR);
82681
+ } catch {
82682
+ }
82683
+ }
82684
+ }
82685
+ showError(domain, item, refs, message) {
82686
+ refs.err.textContent = "";
82687
+ const msg = this.doc.createElement("span");
82688
+ msg.textContent = message;
82689
+ const retry = this.doc.createElement("button");
82690
+ retry.type = "button";
82691
+ retry.className = "rh-retry";
82692
+ retry.textContent = "Tentar de novo";
82693
+ retry.addEventListener("click", () => {
82694
+ if (this.done || this.inflight) return;
82695
+ void this.select(domain, item, refs);
82696
+ });
82697
+ refs.err.append(msg, retry);
82698
+ }
82699
+ /** Single, idempotent cleanup. 'cancel' aborts the in-flight selection; 'success' does not. */
82700
+ finish(reason) {
82701
+ if (this.done) return;
82702
+ this.done = true;
82703
+ if (reason === "cancel") this.inflight?.controller.abort();
82704
+ this.inflight = null;
82705
+ this.overlay.removeEventListener("click", this.onOverlayClick);
82706
+ this.overlay.removeEventListener("keydown", this.onKeydown);
82707
+ this.chrome?.destroy();
82708
+ this.chrome = null;
82709
+ this.overlay.remove();
82710
+ if (registry.get(this.doc) === this) registry.delete(this.doc);
82711
+ if (reason === "cancel" && this.opener instanceof HTMLElement && this.opener.isConnected) {
82712
+ try {
82713
+ this.opener.focus();
82714
+ } catch {
82715
+ }
82716
+ }
82717
+ }
82718
+ handle() {
82719
+ const hub = this;
82720
+ return {
82721
+ close: () => hub.finish("cancel"),
82722
+ get isOpen() {
82723
+ return hub.isOpen;
82724
+ }
82725
+ };
82726
+ }
82727
+ };
82728
+ function openReportsHub(params) {
82729
+ if (!params || !params.context) throw new Error("openReportsHub: `context` is required");
82730
+ const doc = params.document ?? defaultDocument();
82731
+ const existing = registry.get(doc);
82732
+ if (existing && existing.isOpen) {
82733
+ if (params.toggle !== false) existing.finish("cancel");
82734
+ return existing.handle();
82735
+ }
82736
+ const hub = new ReportsHub(doc, params);
82737
+ registry.set(doc, hub);
82738
+ try {
82739
+ hub.mount();
82740
+ } catch (err) {
82741
+ registry.delete(doc);
82742
+ throw err;
82743
+ }
82744
+ return hub.handle();
82745
+ }
82746
+
82747
+ // src/components/premium-modals/reports-hub/dashboardAdapter.ts
82748
+ var GETTERS = {
82749
+ energy: "getEnergyGroups",
82750
+ water: "getWaterGroups",
82751
+ temperature: "getTemperatureGroups"
82752
+ };
82753
+ function numericRange(min, max) {
82754
+ if (min == null || max == null || min === "" || max === "") return void 0;
82755
+ const a = Number(min);
82756
+ const b = Number(max);
82757
+ return Number.isFinite(a) && Number.isFinite(b) ? { min: a, max: b } : void 0;
82758
+ }
82759
+ function createDashboardReportsHubContext(opts) {
82760
+ const orch = opts.orchestrator || {};
82761
+ const log = opts.log || { warn: (...a) => console.warn("[ReportsHub adapter]", ...a) };
82762
+ const domains = Object.keys(GETTERS).filter(
82763
+ (d) => typeof orch[GETTERS[d]] === "function"
82764
+ );
82765
+ const getGroups = (domain) => {
82766
+ const fn = orch[GETTERS[domain]];
82767
+ try {
82768
+ return (typeof fn === "function" ? fn.call(orch) : null) || {};
82769
+ } catch (err) {
82770
+ log.warn(`${GETTERS[domain]} failed:`, err?.message || err);
82771
+ return {};
82772
+ }
82773
+ };
82774
+ const ensureDomainLoaded = async (domain) => {
82775
+ if (domain === "energy" || typeof orch.hydrateDomain !== "function") return;
82776
+ if (opts.isDomainLoaded?.(domain)) return;
82777
+ const period = orch.getCurrentPeriod?.();
82778
+ if (!period) {
82779
+ log.warn(`${domain} not loaded and no current period \u2014 report may be empty`);
82780
+ return;
82781
+ }
82782
+ try {
82783
+ await orch.hydrateDomain(domain, period);
82784
+ } catch (err) {
82785
+ log.warn(`hydrateDomain(${domain}) failed:`, err?.message || err);
82786
+ }
82787
+ };
82788
+ const getAllReportBase = () => {
82789
+ const creds = orch.getCredentials?.() || {};
82790
+ return {
82791
+ customerId: creds.CUSTOMER_ING_ID || "",
82792
+ debug: 0,
82793
+ api: {
82794
+ clientId: creds.CLIENT_ID || "",
82795
+ clientSecret: creds.CLIENT_SECRET || "",
82796
+ dataApiBaseUrl: opts.getDataApiHost?.() || void 0,
82797
+ ingestionToken: orch.tokenManager?.getToken("ingestionToken") || ""
82798
+ },
82799
+ ui: { theme: "light" }
82800
+ };
82801
+ };
82802
+ const validRange = opts.temperatureClampRange ? numericRange(opts.temperatureClampRange.min, opts.temperatureClampRange.max) : void 0;
82803
+ const idealRange = opts.temperatureLimits ? numericRange(opts.temperatureLimits.minTemperature, opts.temperatureLimits.maxTemperature) : void 0;
82804
+ const demandPossible = domains.includes("energy") && !!opts.tbCustomerId;
82805
+ const getDemandPanelParams = () => {
82806
+ const gcdrCustomerId = orch.gcdrCustomerId || "";
82807
+ const baseUrl = orch.gcdrApiBaseUrl || "";
82808
+ if (!opts.tbCustomerId || !gcdrCustomerId || !baseUrl) return null;
82809
+ const jwt = opts.getJwt() || "";
82810
+ return {
82811
+ customer: { tbCustomerId: opts.tbCustomerId, gcdrCustomerId, name: "" },
82812
+ user: tbUserFromJwt(jwt) || { tbUserId: "unknown", name: "Usu\xE1rio" },
82813
+ store: createTbEnvelopeStore({
82814
+ tbBaseUrl: opts.tbBaseUrl || "",
82815
+ customerId: opts.tbCustomerId,
82816
+ getToken: () => opts.getJwt() || ""
82817
+ }),
82818
+ api: createGcdrReportJobsApi({
82819
+ baseUrl,
82820
+ gcdrCustomerId,
82821
+ // read per request: rotated keys are picked up
82822
+ getHeaders: () => ({ "X-API-Key": orch.gcdrApiKey || "", "X-Tenant-ID": orch.gcdrTenantId || "" })
82823
+ })
82824
+ };
82825
+ };
82826
+ return {
82827
+ domains,
82828
+ getGroups,
82829
+ ensureDomainLoaded,
82830
+ getAllReportBase,
82831
+ ...validRange || idealRange ? { temperature: { ...validRange ? { validRange } : {}, ...idealRange ? { idealRange } : {} } } : {},
82832
+ ...demandPossible ? { getDemandPanelParams } : {}
82833
+ };
82834
+ }
82835
+
82022
82836
  // src/utils/goalsCoverage.ts
82023
82837
  var MONTHS_PT = ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"];
82024
82838
  function formatCoverageRefPtBR(ref) {
@@ -82097,7 +82911,7 @@ function openGoalsPanel(params) {
82097
82911
  fontFamily: styles.fontFamily || "'Nunito', system-ui, sans-serif",
82098
82912
  zIndex: styles.zIndex || 1e6
82099
82913
  };
82100
- const MODAL_ID6 = "goals-gcdr-modal";
82914
+ const MODAL_ID7 = "goals-gcdr-modal";
82101
82915
  const ROOT_ID2 = "myio-goals-gcdr-root";
82102
82916
  const state6 = {
82103
82917
  domain: DOMAINS2.includes(p.domain) ? p.domain : "ENERGY",
@@ -82763,7 +83577,7 @@ function openGoalsPanel(params) {
82763
83577
  const headerHTML = ModalHeader.generateInlineHTML({
82764
83578
  icon: "\u{1F3AF}",
82765
83579
  title: i18n2.modalTitle,
82766
- modalId: MODAL_ID6,
83580
+ modalId: MODAL_ID7,
82767
83581
  theme: "dark",
82768
83582
  isMaximized: false,
82769
83583
  showThemeToggle: false,
@@ -82787,7 +83601,7 @@ function openGoalsPanel(params) {
82787
83601
  </div>
82788
83602
  ${state6.importOpen ? renderImportModal() : ""}
82789
83603
  `;
82790
- ModalHeader.setupHandlers({ modalId: MODAL_ID6, onClose: () => closeModal2() });
83604
+ ModalHeader.setupHandlers({ modalId: MODAL_ID7, onClose: () => closeModal2() });
82791
83605
  attachCoverageTooltip();
82792
83606
  }
82793
83607
  function renderToolbar() {
@@ -102010,7 +102824,7 @@ function createMyIOTheme(settings, mode) {
102010
102824
 
102011
102825
  // src/components/settings-hub/openSettingsHubModal.ts
102012
102826
  var ROUTE_DELAY_MS = 250;
102013
- var MODAL_ID = "myio-conf-picker";
102827
+ var MODAL_ID2 = "myio-conf-picker";
102014
102828
  var STYLE_ID10 = "myio-conf-picker-styles";
102015
102829
  var HUB_OPTIONS = [
102016
102830
  {
@@ -102228,7 +103042,7 @@ function openSettingsHubModal(options) {
102228
103042
  style.textContent = HUB_CSS;
102229
103043
  doc.head.appendChild(style);
102230
103044
  }
102231
- doc.getElementById(MODAL_ID)?.remove();
103045
+ doc.getElementById(MODAL_ID2)?.remove();
102232
103046
  const visibleOptions = HUB_OPTIONS.filter(
102233
103047
  (opt) => typeof handlers[opt.action] === "function" && (!opt.superAdminOnly || isSuperAdmin2)
102234
103048
  );
@@ -102243,7 +103057,7 @@ function openSettingsHubModal(options) {
102243
103057
  </button>`
102244
103058
  ).join("");
102245
103059
  const modal = doc.createElement("div");
102246
- modal.id = MODAL_ID;
103060
+ modal.id = MODAL_ID2;
102247
103061
  modal.className = "myio-conf-picker";
102248
103062
  modal.innerHTML = `
102249
103063
  <div class="myio-conf-picker__overlay"></div>
@@ -103443,7 +104257,7 @@ function createTariffApiAdapter(client, opts) {
103443
104257
  }
103444
104258
 
103445
104259
  // src/components/pricing-panel/openPricingPanel.ts
103446
- var MODAL_ID2 = "myio-pricing-panel";
104260
+ var MODAL_ID3 = "myio-pricing-panel";
103447
104261
  function escapeHtml10(value) {
103448
104262
  return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
103449
104263
  }
@@ -103519,7 +104333,7 @@ function openPricingPanel(params) {
103519
104333
  }
103520
104334
  };
103521
104335
  injectPricingPanelStyles(doc);
103522
- doc.getElementById(MODAL_ID2)?.remove();
104336
+ doc.getElementById(MODAL_ID3)?.remove();
103523
104337
  const allowed = isPricingAllowed(params.currentUserEmail, isSuperAdmin());
103524
104338
  const customers = params.customers || [];
103525
104339
  const tariffApi = params.tariffApi;
@@ -103537,7 +104351,7 @@ function openPricingPanel(params) {
103537
104351
  let entries = allowed ? adapter ? (params.initialEntries || []).map((e) => ({ ...e })) : mergeEntries(loadJson(doc, keyEntries, []), params.initialEntries || [], author) : [];
103538
104352
  let auditLog = allowed && !adapter ? loadJson(doc, keyAudit, []) : [];
103539
104353
  const modal = doc.createElement("div");
103540
- modal.id = MODAL_ID2;
104354
+ modal.id = MODAL_ID3;
103541
104355
  modal.className = "myio-pricing";
103542
104356
  function applyTheme() {
103543
104357
  const themeVars = resolveThemeVars(params.theme);
@@ -161810,7 +162624,7 @@ function injectAmbienteModalStyles() {
161810
162624
  }
161811
162625
 
161812
162626
  // src/components/ambiente-detail-modal/AmbienteDetailModal.ts
161813
- var MODAL_ID3 = "ambiente-detail";
162627
+ var MODAL_ID4 = "ambiente-detail";
161814
162628
  function formatTemperature3(value) {
161815
162629
  if (value === null || value === void 0 || isNaN(value)) return "-";
161816
162630
  return value.toLocaleString("pt-BR", {
@@ -162051,7 +162865,7 @@ function renderModalHTML(data, source, config2) {
162051
162865
  const headerHTML = ModalHeader.generateHTML({
162052
162866
  icon: "\u{1F3E2}",
162053
162867
  title: data.label,
162054
- modalId: MODAL_ID3,
162868
+ modalId: MODAL_ID4,
162055
162869
  theme: config2.themeMode || "dark",
162056
162870
  isMaximized: false,
162057
162871
  showThemeToggle: false,
@@ -162100,7 +162914,7 @@ function createAmbienteDetailModal(data, source, config2 = {}) {
162100
162914
  }
162101
162915
  });
162102
162916
  ModalHeader.setupHandlers({
162103
- modalId: MODAL_ID3,
162917
+ modalId: MODAL_ID4,
162104
162918
  onClose: close
162105
162919
  });
162106
162920
  footerCloseBtn?.addEventListener("click", close);
@@ -165402,9 +166216,9 @@ var GCDRSyncController = class {
165402
166216
  var TEAL = "#0a6d5e";
165403
166217
  var TEAL_DARK = "#084f44";
165404
166218
  var TEAL_LIGHT = "#0d8570";
165405
- var MODAL_ID4 = "myio-gcdr-sync-modal";
166219
+ var MODAL_ID5 = "myio-gcdr-sync-modal";
165406
166220
  var STYLES2 = `
165407
- #${MODAL_ID4} {
166221
+ #${MODAL_ID5} {
165408
166222
  position: fixed;
165409
166223
  inset: 0;
165410
166224
  background: rgba(0, 0, 0, 0.60);
@@ -165416,7 +166230,7 @@ var STYLES2 = `
165416
166230
  justify-content: center;
165417
166231
  font-family: 'Nunito', system-ui, sans-serif;
165418
166232
  }
165419
- #${MODAL_ID4} .gcdr-card {
166233
+ #${MODAL_ID5} .gcdr-card {
165420
166234
  background: #fff;
165421
166235
  color: #1a1a1a;
165422
166236
  border-radius: 16px;
@@ -165427,7 +166241,7 @@ var STYLES2 = `
165427
166241
  flex-direction: column;
165428
166242
  overflow: hidden;
165429
166243
  }
165430
- #${MODAL_ID4} .gcdr-header {
166244
+ #${MODAL_ID5} .gcdr-header {
165431
166245
  background: ${TEAL};
165432
166246
  color: #fff;
165433
166247
  padding: 20px 24px 16px;
@@ -165436,25 +166250,25 @@ var STYLES2 = `
165436
166250
  gap: 12px;
165437
166251
  flex-shrink: 0;
165438
166252
  }
165439
- #${MODAL_ID4} .gcdr-header-icon {
166253
+ #${MODAL_ID5} .gcdr-header-icon {
165440
166254
  font-size: 24px;
165441
166255
  flex-shrink: 0;
165442
166256
  }
165443
- #${MODAL_ID4} .gcdr-header-text {
166257
+ #${MODAL_ID5} .gcdr-header-text {
165444
166258
  flex: 1;
165445
166259
  }
165446
- #${MODAL_ID4} .gcdr-header-title {
166260
+ #${MODAL_ID5} .gcdr-header-title {
165447
166261
  font-size: 18px;
165448
166262
  font-weight: 700;
165449
166263
  line-height: 1.2;
165450
166264
  margin: 0;
165451
166265
  }
165452
- #${MODAL_ID4} .gcdr-header-sub {
166266
+ #${MODAL_ID5} .gcdr-header-sub {
165453
166267
  font-size: 13px;
165454
166268
  opacity: 0.80;
165455
166269
  margin: 4px 0 0;
165456
166270
  }
165457
- #${MODAL_ID4} .gcdr-close-btn {
166271
+ #${MODAL_ID5} .gcdr-close-btn {
165458
166272
  background: none;
165459
166273
  border: none;
165460
166274
  color: #fff;
@@ -165467,13 +166281,13 @@ var STYLES2 = `
165467
166281
  transition: opacity 0.15s;
165468
166282
  flex-shrink: 0;
165469
166283
  }
165470
- #${MODAL_ID4} .gcdr-close-btn:hover { opacity: 1; }
165471
- #${MODAL_ID4} .gcdr-body {
166284
+ #${MODAL_ID5} .gcdr-close-btn:hover { opacity: 1; }
166285
+ #${MODAL_ID5} .gcdr-body {
165472
166286
  padding: 24px;
165473
166287
  overflow-y: auto;
165474
166288
  flex: 1;
165475
166289
  }
165476
- #${MODAL_ID4} .gcdr-footer {
166290
+ #${MODAL_ID5} .gcdr-footer {
165477
166291
  padding: 16px 24px;
165478
166292
  border-top: 1px solid #e8ecef;
165479
166293
  display: flex;
@@ -165481,7 +166295,7 @@ var STYLES2 = `
165481
166295
  justify-content: flex-end;
165482
166296
  flex-shrink: 0;
165483
166297
  }
165484
- #${MODAL_ID4} .gcdr-btn {
166298
+ #${MODAL_ID5} .gcdr-btn {
165485
166299
  padding: 10px 20px;
165486
166300
  border-radius: 8px;
165487
166301
  font-size: 14px;
@@ -165493,53 +166307,53 @@ var STYLES2 = `
165493
166307
  align-items: center;
165494
166308
  gap: 6px;
165495
166309
  }
165496
- #${MODAL_ID4} .gcdr-btn:active { transform: scale(0.97); }
165497
- #${MODAL_ID4} .gcdr-btn-primary {
166310
+ #${MODAL_ID5} .gcdr-btn:active { transform: scale(0.97); }
166311
+ #${MODAL_ID5} .gcdr-btn-primary {
165498
166312
  background: ${TEAL};
165499
166313
  color: #fff;
165500
166314
  }
165501
- #${MODAL_ID4} .gcdr-btn-primary:hover { background: ${TEAL_LIGHT}; }
165502
- #${MODAL_ID4} .gcdr-btn-secondary {
166315
+ #${MODAL_ID5} .gcdr-btn-primary:hover { background: ${TEAL_LIGHT}; }
166316
+ #${MODAL_ID5} .gcdr-btn-secondary {
165503
166317
  background: #f0f4f3;
165504
166318
  color: ${TEAL_DARK};
165505
166319
  border: 1px solid #d0dbd9;
165506
166320
  }
165507
- #${MODAL_ID4} .gcdr-btn-secondary:hover { background: #e0ecea; }
165508
- #${MODAL_ID4} .gcdr-btn-danger {
166321
+ #${MODAL_ID5} .gcdr-btn-secondary:hover { background: #e0ecea; }
166322
+ #${MODAL_ID5} .gcdr-btn-danger {
165509
166323
  background: #d32f2f;
165510
166324
  color: #fff;
165511
166325
  }
165512
- #${MODAL_ID4} .gcdr-btn-danger:hover { background: #b71c1c; }
165513
- #${MODAL_ID4} .gcdr-counts {
166326
+ #${MODAL_ID5} .gcdr-btn-danger:hover { background: #b71c1c; }
166327
+ #${MODAL_ID5} .gcdr-counts {
165514
166328
  display: grid;
165515
166329
  grid-template-columns: repeat(3, 1fr);
165516
166330
  gap: 12px;
165517
166331
  margin-bottom: 20px;
165518
166332
  }
165519
- #${MODAL_ID4} .gcdr-count-card {
166333
+ #${MODAL_ID5} .gcdr-count-card {
165520
166334
  background: #f8faf9;
165521
166335
  border: 1px solid #e0eceb;
165522
166336
  border-radius: 10px;
165523
166337
  padding: 14px 12px;
165524
166338
  text-align: center;
165525
166339
  }
165526
- #${MODAL_ID4} .gcdr-count-num {
166340
+ #${MODAL_ID5} .gcdr-count-num {
165527
166341
  font-size: 28px;
165528
166342
  font-weight: 700;
165529
166343
  line-height: 1;
165530
166344
  margin-bottom: 4px;
165531
166345
  }
165532
- #${MODAL_ID4} .gcdr-count-label {
166346
+ #${MODAL_ID5} .gcdr-count-label {
165533
166347
  font-size: 12px;
165534
166348
  color: #666;
165535
166349
  text-transform: uppercase;
165536
166350
  letter-spacing: 0.04em;
165537
166351
  }
165538
- #${MODAL_ID4} .gcdr-count-create { color: ${TEAL}; }
165539
- #${MODAL_ID4} .gcdr-count-update { color: #e67e00; }
165540
- #${MODAL_ID4} .gcdr-count-skip { color: #888; }
165541
- #${MODAL_ID4} .gcdr-count-recreate { color: #9c27b0; }
165542
- #${MODAL_ID4} .gcdr-info-box {
166352
+ #${MODAL_ID5} .gcdr-count-create { color: ${TEAL}; }
166353
+ #${MODAL_ID5} .gcdr-count-update { color: #e67e00; }
166354
+ #${MODAL_ID5} .gcdr-count-skip { color: #888; }
166355
+ #${MODAL_ID5} .gcdr-count-recreate { color: #9c27b0; }
166356
+ #${MODAL_ID5} .gcdr-info-box {
165543
166357
  background: #f0f9f7;
165544
166358
  border: 1px solid #c3e6e2;
165545
166359
  border-radius: 8px;
@@ -165548,7 +166362,7 @@ var STYLES2 = `
165548
166362
  color: #1a4a45;
165549
166363
  line-height: 1.5;
165550
166364
  }
165551
- #${MODAL_ID4} .gcdr-error-box {
166365
+ #${MODAL_ID5} .gcdr-error-box {
165552
166366
  background: #fff0f0;
165553
166367
  border: 1px solid #ffb3b3;
165554
166368
  border-radius: 8px;
@@ -165560,7 +166374,7 @@ var STYLES2 = `
165560
166374
  gap: 10px;
165561
166375
  align-items: flex-start;
165562
166376
  }
165563
- #${MODAL_ID4} .gcdr-section-title {
166377
+ #${MODAL_ID5} .gcdr-section-title {
165564
166378
  font-size: 14px;
165565
166379
  font-weight: 600;
165566
166380
  color: #333;
@@ -165569,7 +166383,7 @@ var STYLES2 = `
165569
166383
  align-items: center;
165570
166384
  gap: 6px;
165571
166385
  }
165572
- #${MODAL_ID4} .gcdr-action-list {
166386
+ #${MODAL_ID5} .gcdr-action-list {
165573
166387
  list-style: none;
165574
166388
  margin: 0 0 12px;
165575
166389
  padding: 0;
@@ -165578,7 +166392,7 @@ var STYLES2 = `
165578
166392
  border: 1px solid #e8ecef;
165579
166393
  border-radius: 8px;
165580
166394
  }
165581
- #${MODAL_ID4} .gcdr-action-item {
166395
+ #${MODAL_ID5} .gcdr-action-item {
165582
166396
  padding: 8px 12px;
165583
166397
  display: flex;
165584
166398
  align-items: center;
@@ -165586,8 +166400,8 @@ var STYLES2 = `
165586
166400
  font-size: 13px;
165587
166401
  border-bottom: 1px solid #f0f4f3;
165588
166402
  }
165589
- #${MODAL_ID4} .gcdr-action-item:last-child { border-bottom: none; }
165590
- #${MODAL_ID4} .gcdr-badge {
166403
+ #${MODAL_ID5} .gcdr-action-item:last-child { border-bottom: none; }
166404
+ #${MODAL_ID5} .gcdr-badge {
165591
166405
  padding: 2px 7px;
165592
166406
  border-radius: 4px;
165593
166407
  font-size: 10px;
@@ -165596,10 +166410,10 @@ var STYLES2 = `
165596
166410
  letter-spacing: 0.05em;
165597
166411
  flex-shrink: 0;
165598
166412
  }
165599
- #${MODAL_ID4} .gcdr-badge-create { background: #e6f4f1; color: ${TEAL_DARK}; }
165600
- #${MODAL_ID4} .gcdr-badge-update { background: #fff3e0; color: #e67e00; }
165601
- #${MODAL_ID4} .gcdr-badge-recreate { background: #f3e5f5; color: #7b1fa2; }
165602
- #${MODAL_ID4} .gcdr-progress-overlay {
166413
+ #${MODAL_ID5} .gcdr-badge-create { background: #e6f4f1; color: ${TEAL_DARK}; }
166414
+ #${MODAL_ID5} .gcdr-badge-update { background: #fff3e0; color: #e67e00; }
166415
+ #${MODAL_ID5} .gcdr-badge-recreate { background: #f3e5f5; color: #7b1fa2; }
166416
+ #${MODAL_ID5} .gcdr-progress-overlay {
165603
166417
  position: absolute;
165604
166418
  inset: 0;
165605
166419
  background: rgba(255,255,255,0.92);
@@ -165613,17 +166427,17 @@ var STYLES2 = `
165613
166427
  text-align: center;
165614
166428
  z-index: 10;
165615
166429
  }
165616
- #${MODAL_ID4} .gcdr-progress-title {
166430
+ #${MODAL_ID5} .gcdr-progress-title {
165617
166431
  font-size: 16px;
165618
166432
  font-weight: 600;
165619
166433
  color: ${TEAL_DARK};
165620
166434
  }
165621
- #${MODAL_ID4} .gcdr-progress-entity {
166435
+ #${MODAL_ID5} .gcdr-progress-entity {
165622
166436
  font-size: 13px;
165623
166437
  color: #555;
165624
166438
  min-height: 20px;
165625
166439
  }
165626
- #${MODAL_ID4} .gcdr-progress-bar-wrap {
166440
+ #${MODAL_ID5} .gcdr-progress-bar-wrap {
165627
166441
  width: 100%;
165628
166442
  max-width: 360px;
165629
166443
  background: #e0ece9;
@@ -165631,46 +166445,46 @@ var STYLES2 = `
165631
166445
  height: 8px;
165632
166446
  overflow: hidden;
165633
166447
  }
165634
- #${MODAL_ID4} .gcdr-progress-bar {
166448
+ #${MODAL_ID5} .gcdr-progress-bar {
165635
166449
  height: 100%;
165636
166450
  background: ${TEAL};
165637
166451
  border-radius: 99px;
165638
166452
  transition: width 0.3s ease;
165639
166453
  width: 0%;
165640
166454
  }
165641
- #${MODAL_ID4} .gcdr-progress-counter {
166455
+ #${MODAL_ID5} .gcdr-progress-counter {
165642
166456
  font-size: 12px;
165643
166457
  color: #888;
165644
166458
  }
165645
- #${MODAL_ID4} .gcdr-result-counts {
166459
+ #${MODAL_ID5} .gcdr-result-counts {
165646
166460
  display: grid;
165647
166461
  grid-template-columns: repeat(3, 1fr);
165648
166462
  gap: 12px;
165649
166463
  margin-bottom: 20px;
165650
166464
  }
165651
- #${MODAL_ID4} .gcdr-result-card {
166465
+ #${MODAL_ID5} .gcdr-result-card {
165652
166466
  background: #f8faf9;
165653
166467
  border: 1px solid #e0eceb;
165654
166468
  border-radius: 10px;
165655
166469
  padding: 14px 12px;
165656
166470
  text-align: center;
165657
166471
  }
165658
- #${MODAL_ID4} .gcdr-result-num {
166472
+ #${MODAL_ID5} .gcdr-result-num {
165659
166473
  font-size: 28px;
165660
166474
  font-weight: 700;
165661
166475
  line-height: 1;
165662
166476
  margin-bottom: 4px;
165663
166477
  }
165664
- #${MODAL_ID4} .gcdr-result-label {
166478
+ #${MODAL_ID5} .gcdr-result-label {
165665
166479
  font-size: 12px;
165666
166480
  color: #666;
165667
166481
  text-transform: uppercase;
165668
166482
  letter-spacing: 0.04em;
165669
166483
  }
165670
- #${MODAL_ID4} .gcdr-result-ok { color: ${TEAL}; }
165671
- #${MODAL_ID4} .gcdr-result-fail { color: #d32f2f; }
165672
- #${MODAL_ID4} .gcdr-result-skip { color: #888; }
165673
- #${MODAL_ID4} .gcdr-fail-list {
166484
+ #${MODAL_ID5} .gcdr-result-ok { color: ${TEAL}; }
166485
+ #${MODAL_ID5} .gcdr-result-fail { color: #d32f2f; }
166486
+ #${MODAL_ID5} .gcdr-result-skip { color: #888; }
166487
+ #${MODAL_ID5} .gcdr-fail-list {
165674
166488
  background: #fff5f5;
165675
166489
  border: 1px solid #ffcdd2;
165676
166490
  border-radius: 8px;
@@ -165678,23 +166492,23 @@ var STYLES2 = `
165678
166492
  max-height: 160px;
165679
166493
  overflow-y: auto;
165680
166494
  }
165681
- #${MODAL_ID4} .gcdr-fail-item {
166495
+ #${MODAL_ID5} .gcdr-fail-item {
165682
166496
  font-size: 12px;
165683
166497
  color: #b71c1c;
165684
166498
  padding: 4px 0;
165685
166499
  border-bottom: 1px solid #ffebee;
165686
166500
  }
165687
- #${MODAL_ID4} .gcdr-fail-item:last-child { border-bottom: none; }
166501
+ #${MODAL_ID5} .gcdr-fail-item:last-child { border-bottom: none; }
165688
166502
  `;
165689
166503
  function injectStyles20() {
165690
- if (document.getElementById(`${MODAL_ID4}-styles`)) return;
166504
+ if (document.getElementById(`${MODAL_ID5}-styles`)) return;
165691
166505
  const style = document.createElement("style");
165692
- style.id = `${MODAL_ID4}-styles`;
166506
+ style.id = `${MODAL_ID5}-styles`;
165693
166507
  style.textContent = STYLES2;
165694
166508
  document.head.appendChild(style);
165695
166509
  }
165696
166510
  function removeExistingModal() {
165697
- const existing = document.getElementById(MODAL_ID4);
166511
+ const existing = document.getElementById(MODAL_ID5);
165698
166512
  existing?.remove();
165699
166513
  }
165700
166514
  function badgeHtml(type) {
@@ -165806,7 +166620,7 @@ async function openGCDRSyncModal(params) {
165806
166620
  return;
165807
166621
  }
165808
166622
  const overlay = document.createElement("div");
165809
- overlay.id = MODAL_ID4;
166623
+ overlay.id = MODAL_ID5;
165810
166624
  const card = document.createElement("div");
165811
166625
  card.className = "gcdr-card";
165812
166626
  card.style.position = "relative";
@@ -166036,13 +166850,13 @@ async function openGCDRSyncModal(params) {
166036
166850
  }
166037
166851
 
166038
166852
  // src/components/premium-modals/alarm-bundle-map/openAlarmBundleMapModal.ts
166039
- var MODAL_ID5 = "myio-alarm-bundle-map-modal";
166853
+ var MODAL_ID6 = "myio-alarm-bundle-map-modal";
166040
166854
  var GCDR_INTEGRATION_API_KEY = "gcdr_cust_tb_integration_key_2026";
166041
166855
  var TEAL2 = "#0a6d5e";
166042
166856
  var TEAL_DARK2 = "#084f44";
166043
166857
  var TEAL_LIGHT2 = "#0d8570";
166044
166858
  var STYLES3 = `
166045
- #${MODAL_ID5} {
166859
+ #${MODAL_ID6} {
166046
166860
  position: fixed;
166047
166861
  inset: 0;
166048
166862
  background: rgba(0, 0, 0, 0.60);
@@ -166054,7 +166868,7 @@ var STYLES3 = `
166054
166868
  justify-content: center;
166055
166869
  font-family: 'Nunito', system-ui, sans-serif;
166056
166870
  }
166057
- #${MODAL_ID5} .abm-card {
166871
+ #${MODAL_ID6} .abm-card {
166058
166872
  background: #fff;
166059
166873
  color: #1a1a1a;
166060
166874
  border-radius: 16px;
@@ -166065,12 +166879,12 @@ var STYLES3 = `
166065
166879
  flex-direction: column;
166066
166880
  overflow: hidden;
166067
166881
  }
166068
- #${MODAL_ID5} .abm-card.is-maximized {
166882
+ #${MODAL_ID6} .abm-card.is-maximized {
166069
166883
  width: 100vw !important; max-width: 100vw !important;
166070
166884
  height: 100vh !important; max-height: 100vh !important; border-radius: 0;
166071
166885
  }
166072
- #${MODAL_ID5} .myio-premium-chrome-header .abm-view-toggle { margin-left: 0; margin-right: 6px; }
166073
- #${MODAL_ID5} .abm-header {
166886
+ #${MODAL_ID6} .myio-premium-chrome-header .abm-view-toggle { margin-left: 0; margin-right: 6px; }
166887
+ #${MODAL_ID6} .abm-header {
166074
166888
  background: ${TEAL2};
166075
166889
  color: #fff;
166076
166890
  padding: 18px 24px 14px;
@@ -166079,123 +166893,123 @@ var STYLES3 = `
166079
166893
  gap: 12px;
166080
166894
  flex-shrink: 0;
166081
166895
  }
166082
- #${MODAL_ID5} .abm-header-icon { font-size: 22px; flex-shrink: 0; }
166083
- #${MODAL_ID5} .abm-header-text { flex: 1; }
166084
- #${MODAL_ID5} .abm-header-title {
166896
+ #${MODAL_ID6} .abm-header-icon { font-size: 22px; flex-shrink: 0; }
166897
+ #${MODAL_ID6} .abm-header-text { flex: 1; }
166898
+ #${MODAL_ID6} .abm-header-title {
166085
166899
  font-size: 17px; font-weight: 700; line-height: 1.2; margin: 0;
166086
166900
  }
166087
- #${MODAL_ID5} .abm-header-sub {
166901
+ #${MODAL_ID6} .abm-header-sub {
166088
166902
  font-size: 12px; opacity: 0.80; margin: 3px 0 0;
166089
166903
  }
166090
- #${MODAL_ID5} .abm-close-btn {
166904
+ #${MODAL_ID6} .abm-close-btn {
166091
166905
  background: none; border: none; color: #fff;
166092
166906
  font-size: 20px; cursor: pointer; padding: 4px 8px;
166093
166907
  border-radius: 6px; line-height: 1; opacity: 0.80; transition: opacity 0.15s; flex-shrink: 0;
166094
166908
  }
166095
- #${MODAL_ID5} .abm-close-btn:hover { opacity: 1; }
166096
- #${MODAL_ID5} .abm-body {
166909
+ #${MODAL_ID6} .abm-close-btn:hover { opacity: 1; }
166910
+ #${MODAL_ID6} .abm-body {
166097
166911
  padding: 20px 24px; overflow-y: auto; flex: 1;
166098
166912
  }
166099
- #${MODAL_ID5} .abm-footer {
166913
+ #${MODAL_ID6} .abm-footer {
166100
166914
  padding: 14px 24px; border-top: 1px solid #e8ecef;
166101
166915
  display: flex; gap: 12px; justify-content: flex-end; flex-shrink: 0;
166102
166916
  }
166103
- #${MODAL_ID5} .abm-btn {
166917
+ #${MODAL_ID6} .abm-btn {
166104
166918
  padding: 9px 18px; border-radius: 8px; font-size: 14px;
166105
166919
  font-weight: 600; cursor: pointer; border: none;
166106
166920
  transition: background 0.15s;
166107
166921
  display: inline-flex; align-items: center; gap: 6px;
166108
166922
  }
166109
- #${MODAL_ID5} .abm-btn-secondary {
166923
+ #${MODAL_ID6} .abm-btn-secondary {
166110
166924
  background: #f0f4f3; color: ${TEAL_DARK2}; border: 1px solid #d0dbd9;
166111
166925
  }
166112
- #${MODAL_ID5} .abm-btn-secondary:hover { background: #e0ecea; }
166113
- #${MODAL_ID5} .abm-error-box {
166926
+ #${MODAL_ID6} .abm-btn-secondary:hover { background: #e0ecea; }
166927
+ #${MODAL_ID6} .abm-error-box {
166114
166928
  background: #fff0f0; border: 1px solid #ffb3b3; border-radius: 8px;
166115
166929
  padding: 14px 16px; font-size: 14px; color: #b71c1c;
166116
166930
  line-height: 1.5; display: flex; gap: 10px; align-items: flex-start;
166117
166931
  }
166118
- #${MODAL_ID5} .abm-empty-box {
166932
+ #${MODAL_ID6} .abm-empty-box {
166119
166933
  background: #f0f9f7; border: 1px solid #c3e6e2; border-radius: 8px;
166120
166934
  padding: 16px; font-size: 14px; color: #1a4a45; line-height: 1.5;
166121
166935
  text-align: center;
166122
166936
  }
166123
- #${MODAL_ID5} .abm-loading {
166937
+ #${MODAL_ID6} .abm-loading {
166124
166938
  text-align: center; padding: 32px; color: #555; font-size: 14px;
166125
166939
  }
166126
- #${MODAL_ID5} .abm-summary-bar {
166940
+ #${MODAL_ID6} .abm-summary-bar {
166127
166941
  display: flex; gap: 20px; margin-bottom: 18px;
166128
166942
  padding: 12px 16px; background: #f8faf9;
166129
166943
  border: 1px solid #e0eceb; border-radius: 10px;
166130
166944
  }
166131
- #${MODAL_ID5} .abm-summary-item { text-align: center; flex: 1; }
166132
- #${MODAL_ID5} .abm-summary-num {
166945
+ #${MODAL_ID6} .abm-summary-item { text-align: center; flex: 1; }
166946
+ #${MODAL_ID6} .abm-summary-num {
166133
166947
  font-size: 22px; font-weight: 700; color: ${TEAL2}; line-height: 1;
166134
166948
  }
166135
- #${MODAL_ID5} .abm-summary-label {
166949
+ #${MODAL_ID6} .abm-summary-label {
166136
166950
  font-size: 11px; color: #666; text-transform: uppercase; letter-spacing: 0.04em;
166137
166951
  margin-top: 2px;
166138
166952
  }
166139
- #${MODAL_ID5} .abm-asset-group { margin-bottom: 16px; }
166140
- #${MODAL_ID5} .abm-asset-label {
166953
+ #${MODAL_ID6} .abm-asset-group { margin-bottom: 16px; }
166954
+ #${MODAL_ID6} .abm-asset-label {
166141
166955
  font-size: 11px; font-weight: 700; color: #888;
166142
166956
  text-transform: uppercase; letter-spacing: 0.07em;
166143
166957
  margin-bottom: 6px; padding-left: 2px;
166144
166958
  }
166145
- #${MODAL_ID5} .abm-device-card {
166959
+ #${MODAL_ID6} .abm-device-card {
166146
166960
  border: 1px solid #e0eceb; border-radius: 10px;
166147
166961
  margin-bottom: 8px; overflow: hidden;
166148
166962
  }
166149
- #${MODAL_ID5} .abm-device-header {
166963
+ #${MODAL_ID6} .abm-device-header {
166150
166964
  display: flex; align-items: center; gap: 10px;
166151
166965
  padding: 10px 14px; background: #f8faf9;
166152
166966
  border-bottom: 1px solid #e0eceb;
166153
166967
  }
166154
- #${MODAL_ID5} .abm-device-name {
166968
+ #${MODAL_ID6} .abm-device-name {
166155
166969
  flex: 1; font-size: 14px; font-weight: 600; color: #1a1a1a;
166156
166970
  }
166157
- #${MODAL_ID5} .abm-device-type {
166971
+ #${MODAL_ID6} .abm-device-type {
166158
166972
  font-size: 11px; font-weight: 600; padding: 2px 8px;
166159
166973
  border-radius: 4px; background: #e6f4f1; color: ${TEAL_DARK2};
166160
166974
  text-transform: uppercase; letter-spacing: 0.04em;
166161
166975
  }
166162
- #${MODAL_ID5} .abm-rule-list { padding: 0; list-style: none; margin: 0; }
166163
- #${MODAL_ID5} .abm-rule-item {
166976
+ #${MODAL_ID6} .abm-rule-list { padding: 0; list-style: none; margin: 0; }
166977
+ #${MODAL_ID6} .abm-rule-item {
166164
166978
  padding: 10px 14px; border-bottom: 1px solid #f0f4f3;
166165
166979
  font-size: 13px;
166166
166980
  }
166167
- #${MODAL_ID5} .abm-rule-item:last-child { border-bottom: none; }
166168
- #${MODAL_ID5} .abm-rule-name {
166981
+ #${MODAL_ID6} .abm-rule-item:last-child { border-bottom: none; }
166982
+ #${MODAL_ID6} .abm-rule-name {
166169
166983
  font-weight: 600; color: #333; margin-bottom: 4px;
166170
166984
  display: flex; align-items: center; gap: 6px;
166171
166985
  }
166172
- #${MODAL_ID5} .abm-rule-detail {
166986
+ #${MODAL_ID6} .abm-rule-detail {
166173
166987
  color: #555; line-height: 1.6;
166174
166988
  display: flex; flex-wrap: wrap; gap: 4px 12px;
166175
166989
  }
166176
- #${MODAL_ID5} .abm-rule-chip {
166990
+ #${MODAL_ID6} .abm-rule-chip {
166177
166991
  display: inline-flex; align-items: center; gap: 3px;
166178
166992
  font-size: 12px; background: #f0f4f3; border-radius: 4px;
166179
166993
  padding: 1px 7px; color: #444;
166180
166994
  }
166181
- #${MODAL_ID5} .abm-day-chip {
166995
+ #${MODAL_ID6} .abm-day-chip {
166182
166996
  font-size: 10px; font-weight: 700; padding: 1px 5px;
166183
166997
  border-radius: 3px; background: ${TEAL2}; color: #fff;
166184
166998
  }
166185
- #${MODAL_ID5} .abm-day-chip.off {
166999
+ #${MODAL_ID6} .abm-day-chip.off {
166186
167000
  background: #e8ecef; color: #aaa;
166187
167001
  }
166188
- #${MODAL_ID5} .abm-rule-name {
167002
+ #${MODAL_ID6} .abm-rule-name {
166189
167003
  justify-content: space-between;
166190
167004
  }
166191
- #${MODAL_ID5} .abm-edit-rule-btn {
167005
+ #${MODAL_ID6} .abm-edit-rule-btn {
166192
167006
  background: none; border: none; cursor: pointer;
166193
167007
  font-size: 13px; padding: 2px 5px; border-radius: 4px;
166194
167008
  color: #888; line-height: 1; transition: background 0.12s, color 0.12s;
166195
167009
  flex-shrink: 0;
166196
167010
  }
166197
- #${MODAL_ID5} .abm-edit-rule-btn:hover { background: #e6f4f1; color: ${TEAL2}; }
166198
- #${MODAL_ID5} .abm-edit-form {
167011
+ #${MODAL_ID6} .abm-edit-rule-btn:hover { background: #e6f4f1; color: ${TEAL2}; }
167012
+ #${MODAL_ID6} .abm-edit-form {
166199
167013
  margin-top: 8px; padding: 10px 12px;
166200
167014
  background: #f4fbf9; border: 1px solid #c3e6e2; border-radius: 8px;
166201
167015
  display: flex; flex-direction: column; gap: 10px;
@@ -166203,136 +167017,136 @@ var STYLES3 = `
166203
167017
  ele s\xF3 ocupava a largura do conte\xFAdo. For\xE7a ocupar a linha inteira. */
166204
167018
  flex: 1 1 100%; width: 100%; box-sizing: border-box;
166205
167019
  }
166206
- #${MODAL_ID5} .abm-ef-row {
167020
+ #${MODAL_ID6} .abm-ef-row {
166207
167021
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
166208
167022
  }
166209
- #${MODAL_ID5} .abm-ef-label {
167023
+ #${MODAL_ID6} .abm-ef-label {
166210
167024
  font-size: 11px; font-weight: 600; color: #555; min-width: 60px; flex-shrink: 0;
166211
167025
  }
166212
- #${MODAL_ID5} .abm-ef-input {
167026
+ #${MODAL_ID6} .abm-ef-input {
166213
167027
  border: 1px solid #b0d8d2; border-radius: 5px; padding: 4px 8px;
166214
167028
  font-size: 13px; color: #1a1a1a; background: #fff;
166215
167029
  outline: none; transition: border-color 0.15s;
166216
167030
  }
166217
- #${MODAL_ID5} .abm-ef-input:focus { border-color: ${TEAL2}; }
166218
- #${MODAL_ID5} .abm-ef-input--value { width: 80px; }
166219
- #${MODAL_ID5} .abm-ef-input--time { width: 88px; }
166220
- #${MODAL_ID5} .abm-ef-days { display: flex; gap: 4px; flex-wrap: wrap; }
166221
- #${MODAL_ID5} .abm-ef-day-btn {
167031
+ #${MODAL_ID6} .abm-ef-input:focus { border-color: ${TEAL2}; }
167032
+ #${MODAL_ID6} .abm-ef-input--value { width: 80px; }
167033
+ #${MODAL_ID6} .abm-ef-input--time { width: 88px; }
167034
+ #${MODAL_ID6} .abm-ef-days { display: flex; gap: 4px; flex-wrap: wrap; }
167035
+ #${MODAL_ID6} .abm-ef-day-btn {
166222
167036
  font-size: 10px; font-weight: 700; padding: 2px 6px; border-radius: 3px;
166223
167037
  cursor: pointer; border: 1px solid #b0d8d2; background: #e8ecef; color: #aaa;
166224
167038
  transition: background 0.12s, color 0.12s;
166225
167039
  }
166226
- #${MODAL_ID5} .abm-ef-day-btn.on { background: ${TEAL2}; color: #fff; border-color: ${TEAL2}; }
166227
- #${MODAL_ID5} .abm-ef-actions { display: flex; gap: 8px; justify-content: flex-end; }
166228
- #${MODAL_ID5} .abm-ef-save-btn {
167040
+ #${MODAL_ID6} .abm-ef-day-btn.on { background: ${TEAL2}; color: #fff; border-color: ${TEAL2}; }
167041
+ #${MODAL_ID6} .abm-ef-actions { display: flex; gap: 8px; justify-content: flex-end; }
167042
+ #${MODAL_ID6} .abm-ef-save-btn {
166229
167043
  padding: 5px 14px; border-radius: 6px; font-size: 12px; font-weight: 700;
166230
167044
  cursor: pointer; border: none; background: ${TEAL2}; color: #fff;
166231
167045
  transition: background 0.15s;
166232
167046
  }
166233
- #${MODAL_ID5} .abm-ef-save-btn:hover { background: ${TEAL_LIGHT2}; }
166234
- #${MODAL_ID5} .abm-ef-save-btn:disabled { opacity: 0.55; cursor: not-allowed; }
166235
- #${MODAL_ID5} .abm-ef-cancel-btn {
167047
+ #${MODAL_ID6} .abm-ef-save-btn:hover { background: ${TEAL_LIGHT2}; }
167048
+ #${MODAL_ID6} .abm-ef-save-btn:disabled { opacity: 0.55; cursor: not-allowed; }
167049
+ #${MODAL_ID6} .abm-ef-cancel-btn {
166236
167050
  padding: 5px 14px; border-radius: 6px; font-size: 12px; font-weight: 600;
166237
167051
  cursor: pointer; background: #e8ecef; color: #555; border: 1px solid #ccc;
166238
167052
  transition: background 0.15s;
166239
167053
  }
166240
- #${MODAL_ID5} .abm-ef-cancel-btn:hover { background: #d8dfe0; }
166241
- #${MODAL_ID5} .abm-ef-error {
167054
+ #${MODAL_ID6} .abm-ef-cancel-btn:hover { background: #d8dfe0; }
167055
+ #${MODAL_ID6} .abm-ef-error {
166242
167056
  font-size: 11px; color: #c0392b; font-weight: 600;
166243
167057
  }
166244
- #${MODAL_ID5} .abm-view-toggle {
167058
+ #${MODAL_ID6} .abm-view-toggle {
166245
167059
  display: flex; gap: 0; border: 1px solid rgba(255,255,255,0.3); border-radius: 6px; overflow: hidden;
166246
167060
  margin-left: auto; flex-shrink: 0;
166247
167061
  }
166248
- #${MODAL_ID5} .abm-view-btn {
167062
+ #${MODAL_ID6} .abm-view-btn {
166249
167063
  background: none; border: none; color: rgba(255,255,255,0.7); font-size: 12px; font-weight: 600;
166250
167064
  padding: 5px 12px; cursor: pointer; transition: background 0.15s, color 0.15s; white-space: nowrap;
166251
167065
  }
166252
- #${MODAL_ID5} .abm-view-btn.active { background: rgba(255,255,255,0.25); color: #fff; }
166253
- #${MODAL_ID5} .abm-view-btn:hover:not(.active) { background: rgba(255,255,255,0.1); color: #fff; }
166254
- #${MODAL_ID5} .abm-restore-btn {
167066
+ #${MODAL_ID6} .abm-view-btn.active { background: rgba(255,255,255,0.25); color: #fff; }
167067
+ #${MODAL_ID6} .abm-view-btn:hover:not(.active) { background: rgba(255,255,255,0.1); color: #fff; }
167068
+ #${MODAL_ID6} .abm-restore-btn {
166255
167069
  background: none; border: none; cursor: pointer; font-size: 13px;
166256
167070
  padding: 2px 4px; border-radius: 4px; color: #e67e22; line-height: 1;
166257
167071
  flex-shrink: 0; transition: background 0.12s;
166258
167072
  title: "Restaurar valor padr\xE3o";
166259
167073
  }
166260
- #${MODAL_ID5} .abm-restore-btn:hover { background: #fef0e4; }
166261
- #${MODAL_ID5} .abm-override-badge {
167074
+ #${MODAL_ID6} .abm-restore-btn:hover { background: #fef0e4; }
167075
+ #${MODAL_ID6} .abm-override-badge {
166262
167076
  font-size: 10px; font-weight: 700; padding: 1px 5px; border-radius: 3px;
166263
167077
  background: #e67e22; color: #fff; letter-spacing: 0.03em;
166264
167078
  }
166265
- #${MODAL_ID5} .abm-rule-group {
167079
+ #${MODAL_ID6} .abm-rule-group {
166266
167080
  border: 1px solid #e0eceb; border-radius: 10px; margin-bottom: 16px; overflow: hidden;
166267
167081
  }
166268
- #${MODAL_ID5} .abm-rule-group-header {
167082
+ #${MODAL_ID6} .abm-rule-group-header {
166269
167083
  display: flex; align-items: center; gap: 10px;
166270
167084
  padding: 10px 14px; background: #f0f9f7; border-bottom: 1px solid #e0eceb;
166271
167085
  }
166272
- #${MODAL_ID5} .abm-rule-group-name { flex: 1; font-size: 14px; font-weight: 600; color: #1a1a1a; }
166273
- #${MODAL_ID5} .abm-rule-group-devices { padding: 0; list-style: none; margin: 0; }
166274
- #${MODAL_ID5} .abm-rule-group-device {
167086
+ #${MODAL_ID6} .abm-rule-group-name { flex: 1; font-size: 14px; font-weight: 600; color: #1a1a1a; }
167087
+ #${MODAL_ID6} .abm-rule-group-devices { padding: 0; list-style: none; margin: 0; }
167088
+ #${MODAL_ID6} .abm-rule-group-device {
166275
167089
  padding: 8px 14px; border-bottom: 1px solid #f0f4f3;
166276
167090
  font-size: 13px; color: #555; display: flex; align-items: center; gap: 8px;
166277
167091
  }
166278
- #${MODAL_ID5} .abm-rule-group-device:last-child { border-bottom: none; }
166279
- #${MODAL_ID5} .abm-rule-description {
167092
+ #${MODAL_ID6} .abm-rule-group-device:last-child { border-bottom: none; }
167093
+ #${MODAL_ID6} .abm-rule-description {
166280
167094
  font-size: 12px; color: #777; font-style: italic;
166281
167095
  margin: 2px 0 6px; line-height: 1.4;
166282
167096
  }
166283
- #${MODAL_ID5} .abm-ef-input--desc {
167097
+ #${MODAL_ID6} .abm-ef-input--desc {
166284
167098
  flex: 1; min-width: 0; resize: vertical;
166285
167099
  font-family: inherit; line-height: 1.4;
166286
167100
  }
166287
167101
  /* Override value chip in por-regra device row */
166288
- #${MODAL_ID5} .abm-override-value {
167102
+ #${MODAL_ID6} .abm-override-value {
166289
167103
  font-size: 12px; font-weight: 600; color: #e67e22;
166290
167104
  background: #fef3e8; border-radius: 4px; padding: 1px 6px;
166291
167105
  }
166292
167106
  /* Collapse/expand */
166293
- #${MODAL_ID5} .abm-device-card.collapsed .abm-rule-list { display: none; }
166294
- #${MODAL_ID5} .abm-rule-group.collapsed .abm-rule-group-devices,
166295
- #${MODAL_ID5} .abm-rule-group.collapsed .abm-rule-detail-wrap { display: none; }
166296
- #${MODAL_ID5} .abm-chevron {
167107
+ #${MODAL_ID6} .abm-device-card.collapsed .abm-rule-list { display: none; }
167108
+ #${MODAL_ID6} .abm-rule-group.collapsed .abm-rule-group-devices,
167109
+ #${MODAL_ID6} .abm-rule-group.collapsed .abm-rule-detail-wrap { display: none; }
167110
+ #${MODAL_ID6} .abm-chevron {
166297
167111
  font-size: 11px; color: #94a3b8; transition: transform 0.18s; flex-shrink: 0; user-select: none;
166298
167112
  }
166299
- #${MODAL_ID5} .abm-device-card.collapsed .abm-chevron,
166300
- #${MODAL_ID5} .abm-rule-group.collapsed .abm-chevron { transform: rotate(-90deg); }
166301
- #${MODAL_ID5} .abm-device-header { cursor: pointer; }
166302
- #${MODAL_ID5} .abm-device-header:hover { background: #f0f9f7; }
166303
- #${MODAL_ID5} .abm-rule-group-header { cursor: pointer; }
166304
- #${MODAL_ID5} .abm-rule-group-header:hover { background: #e6f4f1; }
167113
+ #${MODAL_ID6} .abm-device-card.collapsed .abm-chevron,
167114
+ #${MODAL_ID6} .abm-rule-group.collapsed .abm-chevron { transform: rotate(-90deg); }
167115
+ #${MODAL_ID6} .abm-device-header { cursor: pointer; }
167116
+ #${MODAL_ID6} .abm-device-header:hover { background: #f0f9f7; }
167117
+ #${MODAL_ID6} .abm-rule-group-header { cursor: pointer; }
167118
+ #${MODAL_ID6} .abm-rule-group-header:hover { background: #e6f4f1; }
166305
167119
  /* Alarm badge */
166306
- #${MODAL_ID5} .abm-alarm-badge {
167120
+ #${MODAL_ID6} .abm-alarm-badge {
166307
167121
  display: inline-flex; align-items: center; gap: 3px;
166308
167122
  background: #fee2e2; color: #b91c1c; border-radius: 10px;
166309
167123
  font-size: 10px; font-weight: 700; padding: 1px 7px; flex-shrink: 0;
166310
167124
  }
166311
- #${MODAL_ID5} .abm-alarm-badge.zero { background: #f0f9f7; color: #6b7280; }
167125
+ #${MODAL_ID6} .abm-alarm-badge.zero { background: #f0f9f7; color: #6b7280; }
166312
167126
  /* Filter bar */
166313
- #${MODAL_ID5} .abm-filter-bar {
167127
+ #${MODAL_ID6} .abm-filter-bar {
166314
167128
  display: flex; gap: 8px; align-items: center; margin-bottom: 14px;
166315
167129
  padding: 10px 12px; background: #f8faf9; border: 1px solid #e0eceb; border-radius: 8px;
166316
167130
  }
166317
- #${MODAL_ID5} .abm-filter-input {
167131
+ #${MODAL_ID6} .abm-filter-input {
166318
167132
  flex: 1; border: 1px solid #d1d5db; border-radius: 6px; padding: 6px 10px;
166319
167133
  font-size: 12px; outline: none; transition: border-color 0.15s;
166320
167134
  }
166321
- #${MODAL_ID5} .abm-filter-input:focus { border-color: ${TEAL2}; }
166322
- #${MODAL_ID5} .abm-filter-select {
167135
+ #${MODAL_ID6} .abm-filter-input:focus { border-color: ${TEAL2}; }
167136
+ #${MODAL_ID6} .abm-filter-select {
166323
167137
  border: 1px solid #d1d5db; border-radius: 6px; padding: 5px 8px;
166324
167138
  font-size: 12px; outline: none; min-width: 140px; max-width: 220px;
166325
167139
  background: #fff; cursor: pointer;
166326
167140
  }
166327
- #${MODAL_ID5} .abm-filter-count {
167141
+ #${MODAL_ID6} .abm-filter-count {
166328
167142
  font-size: 11px; color: #64748b; white-space: nowrap; flex-shrink: 0;
166329
167143
  }
166330
- #${MODAL_ID5} .abm-filter-clear {
167144
+ #${MODAL_ID6} .abm-filter-clear {
166331
167145
  background: none; border: 1px solid #e0eceb; border-radius: 6px; cursor: pointer;
166332
167146
  font-size: 11px; color: #64748b; padding: 4px 8px; white-space: nowrap; flex-shrink: 0;
166333
167147
  transition: background 0.12s;
166334
167148
  }
166335
- #${MODAL_ID5} .abm-filter-clear:hover { background: #f0f4f3; color: #1e293b; }
167149
+ #${MODAL_ID6} .abm-filter-clear:hover { background: #f0f4f3; color: #1e293b; }
166336
167150
  /* Confirmation modal \u2014 value edit overwrite warning */
166337
167151
  .abm-confirm-overlay {
166338
167152
  position: fixed; inset: 0;
@@ -166369,14 +167183,14 @@ var STYLES3 = `
166369
167183
  .abm-confirm-btn--confirm:hover { background: #cf6d17; }
166370
167184
  `;
166371
167185
  function injectStyles21() {
166372
- if (document.getElementById(`${MODAL_ID5}-styles`)) return;
167186
+ if (document.getElementById(`${MODAL_ID6}-styles`)) return;
166373
167187
  const style = document.createElement("style");
166374
- style.id = `${MODAL_ID5}-styles`;
167188
+ style.id = `${MODAL_ID6}-styles`;
166375
167189
  style.textContent = STYLES3;
166376
167190
  document.head.appendChild(style);
166377
167191
  }
166378
167192
  function removeExistingModal2() {
166379
- document.getElementById(MODAL_ID5)?.remove();
167193
+ document.getElementById(MODAL_ID6)?.remove();
166380
167194
  }
166381
167195
  function escHtml5(str) {
166382
167196
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
@@ -167063,7 +167877,7 @@ async function openAlarmBundleMapModal(params) {
167063
167877
  }
167064
167878
  const baseUrl = params.gcdrApiBaseUrl;
167065
167879
  const overlay = document.createElement("div");
167066
- overlay.id = MODAL_ID5;
167880
+ overlay.id = MODAL_ID6;
167067
167881
  const card = document.createElement("div");
167068
167882
  card.className = "abm-card";
167069
167883
  overlay.appendChild(card);
@@ -174405,6 +175219,7 @@ var version = package_default.version || "0.0.0";
174405
175219
  DEFAULT_DEVICE_OPERATIONAL_CARD_FILTER_STATE,
174406
175220
  DEFAULT_DEVICE_TYPE_PREFIX,
174407
175221
  DEFAULT_DEVICE_TYPE_TOKEN,
175222
+ DEFAULT_ENABLED_REPORT_ITEMS,
174408
175223
  DEFAULT_ENERGY_GROUP_COLORS,
174409
175224
  DEFAULT_EQUIPMENT_FILTER_STATE,
174410
175225
  DEFAULT_EQUIPMENT_STATS,
@@ -174431,6 +175246,7 @@ var version = package_default.version || "0.0.0";
174431
175246
  DEFAULT_ON_OFF_SETTINGS,
174432
175247
  DEFAULT_ON_OFF_STATE,
174433
175248
  DEFAULT_PARTICIPATION_CHART_SETTINGS,
175249
+ DEFAULT_REPORTS_CATALOG,
174434
175250
  DEFAULT_SETPOINT_SCHEDULE,
174435
175251
  DEFAULT_SETPOINT_SETTINGS,
174436
175252
  DEFAULT_SETPOINT_STATE,
@@ -174682,6 +175498,7 @@ var version = package_default.version || "0.0.0";
174682
175498
  buildListItemsThingsboardByUniqueDatasource,
174683
175499
  buildMoneyVarianceHTML,
174684
175500
  buildMyioIngestionAuth,
175501
+ buildReportItemsList,
174685
175502
  buildTemplateExport,
174686
175503
  buildTicketServiceOrchestrator,
174687
175504
  buildVerdictHTML,
@@ -174743,6 +175560,7 @@ var version = package_default.version || "0.0.0";
174743
175560
  createCustomerCardV1,
174744
175561
  createCustomerCardV2,
174745
175562
  createCustomerGoalsCard,
175563
+ createDashboardReportsHubContext,
174746
175564
  createDateRangePicker,
174747
175565
  createDaysGrid,
174748
175566
  createDefaultAnnotationFilter,
@@ -175105,6 +175923,7 @@ var version = package_default.version || "0.0.0";
175105
175923
  openPowerLimitsSetupModal,
175106
175924
  openPricingPanel,
175107
175925
  openRealTimeTelemetryModal,
175926
+ openReportsHub,
175108
175927
  openSettingsHubModal,
175109
175928
  openTemperatureComparisonModal,
175110
175929
  openTemperatureModal,
@@ -175171,6 +175990,7 @@ var version = package_default.version || "0.0.0";
175171
175990
  resolveMoneyRollout,
175172
175991
  resolveMoneyRowValues,
175173
175992
  resolvePercentDecimals,
175993
+ resolveReportItemStates,
175174
175994
  resolveSubcategory,
175175
175995
  resolveWithFallback,
175176
175996
  routeMoneyRender,