myio-js-library 0.1.35 → 0.1.37

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
@@ -5809,6 +5809,7 @@ var DeviceReportModal = class {
5809
5809
  isLoading = false;
5810
5810
  eventHandlers = {};
5811
5811
  dateRangePicker = null;
5812
+ sortState = { key: null, direction: "asc" };
5812
5813
  show() {
5813
5814
  this.modal = createModal({
5814
5815
  title: `Relat\xF3rio - ${this.params.identifier || "SEM IDENTIFICADOR"} - ${this.params.label || "SEM ETIQUETA"}`,
@@ -5963,6 +5964,12 @@ var DeviceReportModal = class {
5963
5964
  const container = document.getElementById("table-container");
5964
5965
  if (!container) return;
5965
5966
  const total = this.calculateTotal();
5967
+ const getSortIndicator = (columnKey) => {
5968
+ if (this.sortState.key === columnKey) {
5969
+ return this.sortState.direction === "asc" ? "\u2191" : "\u2193";
5970
+ }
5971
+ return "\u2195";
5972
+ };
5966
5973
  container.innerHTML = `
5967
5974
  <div style="margin-bottom: 16px; padding: 12px; background: var(--myio-bg); border-radius: 6px;">
5968
5975
  <strong>Total: ${fmtPt(total)} kWh</strong>
@@ -5974,11 +5981,11 @@ var DeviceReportModal = class {
5974
5981
  <tr>
5975
5982
  <th style="cursor: pointer;" data-sort="date">
5976
5983
  Data
5977
- <span style="margin-left: 4px; opacity: 0.5;">\u2195</span>
5984
+ <span style="margin-left: 4px; opacity: ${this.sortState.key === "date" ? "1" : "0.5"};">${getSortIndicator("date")}</span>
5978
5985
  </th>
5979
5986
  <th style="cursor: pointer; text-align: right;" data-sort="consumption">
5980
5987
  Consumo (kWh)
5981
- <span style="margin-left: 4px; opacity: 0.5;">\u2195</span>
5988
+ <span style="margin-left: 4px; opacity: ${this.sortState.key === "consumption" ? "1" : "0.5"};">${getSortIndicator("consumption")}</span>
5982
5989
  </th>
5983
5990
  </tr>
5984
5991
  </thead>
@@ -6006,12 +6013,20 @@ var DeviceReportModal = class {
6006
6013
  });
6007
6014
  }
6008
6015
  sortData(key) {
6016
+ if (this.sortState.key === key) {
6017
+ this.sortState.direction = this.sortState.direction === "asc" ? "desc" : "asc";
6018
+ } else {
6019
+ this.sortState.key = key;
6020
+ this.sortState.direction = "asc";
6021
+ }
6009
6022
  this.data.sort((a, b) => {
6023
+ let comparison = 0;
6010
6024
  if (key === "date") {
6011
- return new Date(a.date).getTime() - new Date(b.date).getTime();
6025
+ comparison = new Date(a.date).getTime() - new Date(b.date).getTime();
6012
6026
  } else {
6013
- return a.consumption - b.consumption;
6027
+ comparison = a.consumption - b.consumption;
6014
6028
  }
6029
+ return this.sortState.direction === "desc" ? -comparison : comparison;
6015
6030
  });
6016
6031
  }
6017
6032
  calculateTotal() {
@@ -7166,15 +7181,15 @@ var AllReportModal = class {
7166
7181
  <tr>
7167
7182
  <th style="cursor: pointer; width: 25%;" data-sort="identifier">
7168
7183
  Identifier
7169
- <span style="margin-left: 4px; opacity: 0.5;">${this.getSortIcon("identifier")}</span>
7184
+ <span style="margin-left: 4px; opacity: ${this.getSortOpacity("identifier")};">${this.getSortIcon("identifier")}</span>
7170
7185
  </th>
7171
7186
  <th style="cursor: pointer; width: 45%;" data-sort="name">
7172
7187
  Name
7173
- <span style="margin-left: 4px; opacity: 0.5;">${this.getSortIcon("name")}</span>
7188
+ <span style="margin-left: 4px; opacity: ${this.getSortOpacity("name")};">${this.getSortIcon("name")}</span>
7174
7189
  </th>
7175
7190
  <th style="cursor: pointer; text-align: right; width: 30%;" data-sort="consumption">
7176
7191
  Consumption (kWh)
7177
- <span style="margin-left: 4px; opacity: 0.5;">${this.getSortIcon("consumption")}</span>
7192
+ <span style="margin-left: 4px; opacity: ${this.getSortOpacity("consumption")};">${this.getSortIcon("consumption")}</span>
7178
7193
  </th>
7179
7194
  </tr>
7180
7195
  </thead>
@@ -7196,6 +7211,9 @@ var AllReportModal = class {
7196
7211
  if (this.sortField !== field) return "\u2195";
7197
7212
  return this.sortDirection === "asc" ? "\u2191" : "\u2193";
7198
7213
  }
7214
+ getSortOpacity(field) {
7215
+ return this.sortField === field ? "1" : "0.5";
7216
+ }
7199
7217
  setupTableSorting() {
7200
7218
  const headers = document.querySelectorAll("[data-sort]");
7201
7219
  headers.forEach((header) => {
@@ -7377,14 +7395,23 @@ var AllReportModal = class {
7377
7395
  }
7378
7396
  const data = await response.json();
7379
7397
  console.log("[AllReportModal] Customer totals response:", data);
7380
- return Array.isArray(data) ? data : [];
7398
+ return data;
7381
7399
  }
7382
- mapCustomerTotalsResponse(apiData) {
7383
- if (!Array.isArray(apiData) || apiData.length === 0) {
7384
- console.warn("[AllReportModal] Empty or invalid API response:", apiData);
7400
+ mapCustomerTotalsResponse(apiResponse) {
7401
+ let dataArray = [];
7402
+ if (apiResponse && apiResponse.data && Array.isArray(apiResponse.data)) {
7403
+ dataArray = apiResponse.data;
7404
+ } else if (Array.isArray(apiResponse)) {
7405
+ dataArray = apiResponse;
7406
+ } else {
7407
+ console.warn("[AllReportModal] Invalid API response structure:", apiResponse);
7408
+ return [];
7409
+ }
7410
+ if (dataArray.length === 0) {
7411
+ console.warn("[AllReportModal] Empty data array in API response");
7385
7412
  return [];
7386
7413
  }
7387
- const mappedData = apiData.map((item) => {
7414
+ const mappedData = dataArray.map((item) => {
7388
7415
  const identifier = item.identifier || item.deviceId || item.id || "N/A";
7389
7416
  const name = item.deviceLabel || item.name || item.label || identifier;
7390
7417
  const consumption = this.parseConsumptionValue(item);
@@ -7394,11 +7421,11 @@ var AllReportModal = class {
7394
7421
  consumption
7395
7422
  };
7396
7423
  }).filter((store) => {
7397
- return !this.shouldExcludeStore(store.name);
7424
+ return !this.shouldExcludeStore(store.name, store.identifier);
7398
7425
  }).filter((store) => {
7399
7426
  return !isNaN(store.consumption) && store.consumption >= 0;
7400
7427
  });
7401
- console.log("[AllReportModal] Mapped customer totals:", mappedData.length, "stores");
7428
+ console.log("[AllReportModal] Mapped customer totals:", mappedData.length, "stores from", dataArray.length, "total devices");
7402
7429
  return mappedData;
7403
7430
  }
7404
7431
  parseConsumptionValue(item) {
@@ -7422,14 +7449,24 @@ var AllReportModal = class {
7422
7449
  console.warn("[AllReportModal] No valid consumption value found in item:", item);
7423
7450
  return 0;
7424
7451
  }
7425
- shouldExcludeStore(storeName) {
7426
- if (!this.params.filters?.excludeLabels) return false;
7427
- return this.params.filters.excludeLabels.some((filter) => {
7428
- if (filter instanceof RegExp) {
7429
- return filter.test(storeName);
7430
- }
7431
- return storeName.toLowerCase().includes(filter.toLowerCase());
7432
- });
7452
+ shouldExcludeStore(storeName, storeId) {
7453
+ const filters = this.params.filters;
7454
+ if (!filters) return false;
7455
+ if (filters.forceOnlyIds && Array.isArray(filters.forceOnlyIds) && filters.forceOnlyIds.length > 0) {
7456
+ return !filters.forceOnlyIds.includes(storeId);
7457
+ }
7458
+ if (filters.excludeIds && Array.isArray(filters.excludeIds) && filters.excludeIds.length > 0) {
7459
+ return filters.excludeIds.includes(storeId);
7460
+ }
7461
+ if (filters.excludeLabels && Array.isArray(filters.excludeLabels) && filters.excludeLabels.length > 0) {
7462
+ return filters.excludeLabels.some((filter) => {
7463
+ if (filter instanceof RegExp) {
7464
+ return filter.test(storeName);
7465
+ }
7466
+ return storeName.toLowerCase().includes(filter.toLowerCase());
7467
+ });
7468
+ }
7469
+ return false;
7433
7470
  }
7434
7471
  downloadCSV(content, filename) {
7435
7472
  const BOM = "\uFEFF";
@@ -8057,16 +8094,16 @@ var DefaultSettingsPersister = class {
8057
8094
  throw this.createHttpError(getRes.status, await getRes.text().catch(() => ""));
8058
8095
  }
8059
8096
  const device = await getRes.json();
8060
- const putRes = await fetch(`${this.tbBaseUrl}/api/device`, {
8061
- method: "PUT",
8097
+ const postRes = await fetch(`${this.tbBaseUrl}/api/device`, {
8098
+ method: "POST",
8062
8099
  headers: {
8063
8100
  "X-Authorization": `Bearer ${this.jwtToken}`,
8064
8101
  "Content-Type": "application/json"
8065
8102
  },
8066
8103
  body: JSON.stringify({ ...device, label: this.sanitizeLabel(label) })
8067
8104
  });
8068
- if (!putRes.ok) {
8069
- throw this.createHttpError(putRes.status, await putRes.text().catch(() => ""));
8105
+ if (!postRes.ok) {
8106
+ throw this.createHttpError(postRes.status, await postRes.text().catch(() => ""));
8070
8107
  }
8071
8108
  return { ok: true };
8072
8109
  } catch (error) {
package/dist/index.d.cts CHANGED
@@ -658,6 +658,8 @@ interface OpenAllReportParams {
658
658
  api: BaseApiCfg;
659
659
  filters?: {
660
660
  excludeLabels?: (RegExp | string)[];
661
+ excludeIds?: string[];
662
+ forceOnlyIds?: string[];
661
663
  };
662
664
  fetcher?: CustomerTotalsFetcher;
663
665
  }
package/dist/index.js CHANGED
@@ -5742,6 +5742,7 @@ var DeviceReportModal = class {
5742
5742
  isLoading = false;
5743
5743
  eventHandlers = {};
5744
5744
  dateRangePicker = null;
5745
+ sortState = { key: null, direction: "asc" };
5745
5746
  show() {
5746
5747
  this.modal = createModal({
5747
5748
  title: `Relat\xF3rio - ${this.params.identifier || "SEM IDENTIFICADOR"} - ${this.params.label || "SEM ETIQUETA"}`,
@@ -5896,6 +5897,12 @@ var DeviceReportModal = class {
5896
5897
  const container = document.getElementById("table-container");
5897
5898
  if (!container) return;
5898
5899
  const total = this.calculateTotal();
5900
+ const getSortIndicator = (columnKey) => {
5901
+ if (this.sortState.key === columnKey) {
5902
+ return this.sortState.direction === "asc" ? "\u2191" : "\u2193";
5903
+ }
5904
+ return "\u2195";
5905
+ };
5899
5906
  container.innerHTML = `
5900
5907
  <div style="margin-bottom: 16px; padding: 12px; background: var(--myio-bg); border-radius: 6px;">
5901
5908
  <strong>Total: ${fmtPt(total)} kWh</strong>
@@ -5907,11 +5914,11 @@ var DeviceReportModal = class {
5907
5914
  <tr>
5908
5915
  <th style="cursor: pointer;" data-sort="date">
5909
5916
  Data
5910
- <span style="margin-left: 4px; opacity: 0.5;">\u2195</span>
5917
+ <span style="margin-left: 4px; opacity: ${this.sortState.key === "date" ? "1" : "0.5"};">${getSortIndicator("date")}</span>
5911
5918
  </th>
5912
5919
  <th style="cursor: pointer; text-align: right;" data-sort="consumption">
5913
5920
  Consumo (kWh)
5914
- <span style="margin-left: 4px; opacity: 0.5;">\u2195</span>
5921
+ <span style="margin-left: 4px; opacity: ${this.sortState.key === "consumption" ? "1" : "0.5"};">${getSortIndicator("consumption")}</span>
5915
5922
  </th>
5916
5923
  </tr>
5917
5924
  </thead>
@@ -5939,12 +5946,20 @@ var DeviceReportModal = class {
5939
5946
  });
5940
5947
  }
5941
5948
  sortData(key) {
5949
+ if (this.sortState.key === key) {
5950
+ this.sortState.direction = this.sortState.direction === "asc" ? "desc" : "asc";
5951
+ } else {
5952
+ this.sortState.key = key;
5953
+ this.sortState.direction = "asc";
5954
+ }
5942
5955
  this.data.sort((a, b) => {
5956
+ let comparison = 0;
5943
5957
  if (key === "date") {
5944
- return new Date(a.date).getTime() - new Date(b.date).getTime();
5958
+ comparison = new Date(a.date).getTime() - new Date(b.date).getTime();
5945
5959
  } else {
5946
- return a.consumption - b.consumption;
5960
+ comparison = a.consumption - b.consumption;
5947
5961
  }
5962
+ return this.sortState.direction === "desc" ? -comparison : comparison;
5948
5963
  });
5949
5964
  }
5950
5965
  calculateTotal() {
@@ -7099,15 +7114,15 @@ var AllReportModal = class {
7099
7114
  <tr>
7100
7115
  <th style="cursor: pointer; width: 25%;" data-sort="identifier">
7101
7116
  Identifier
7102
- <span style="margin-left: 4px; opacity: 0.5;">${this.getSortIcon("identifier")}</span>
7117
+ <span style="margin-left: 4px; opacity: ${this.getSortOpacity("identifier")};">${this.getSortIcon("identifier")}</span>
7103
7118
  </th>
7104
7119
  <th style="cursor: pointer; width: 45%;" data-sort="name">
7105
7120
  Name
7106
- <span style="margin-left: 4px; opacity: 0.5;">${this.getSortIcon("name")}</span>
7121
+ <span style="margin-left: 4px; opacity: ${this.getSortOpacity("name")};">${this.getSortIcon("name")}</span>
7107
7122
  </th>
7108
7123
  <th style="cursor: pointer; text-align: right; width: 30%;" data-sort="consumption">
7109
7124
  Consumption (kWh)
7110
- <span style="margin-left: 4px; opacity: 0.5;">${this.getSortIcon("consumption")}</span>
7125
+ <span style="margin-left: 4px; opacity: ${this.getSortOpacity("consumption")};">${this.getSortIcon("consumption")}</span>
7111
7126
  </th>
7112
7127
  </tr>
7113
7128
  </thead>
@@ -7129,6 +7144,9 @@ var AllReportModal = class {
7129
7144
  if (this.sortField !== field) return "\u2195";
7130
7145
  return this.sortDirection === "asc" ? "\u2191" : "\u2193";
7131
7146
  }
7147
+ getSortOpacity(field) {
7148
+ return this.sortField === field ? "1" : "0.5";
7149
+ }
7132
7150
  setupTableSorting() {
7133
7151
  const headers = document.querySelectorAll("[data-sort]");
7134
7152
  headers.forEach((header) => {
@@ -7310,14 +7328,23 @@ var AllReportModal = class {
7310
7328
  }
7311
7329
  const data = await response.json();
7312
7330
  console.log("[AllReportModal] Customer totals response:", data);
7313
- return Array.isArray(data) ? data : [];
7331
+ return data;
7314
7332
  }
7315
- mapCustomerTotalsResponse(apiData) {
7316
- if (!Array.isArray(apiData) || apiData.length === 0) {
7317
- console.warn("[AllReportModal] Empty or invalid API response:", apiData);
7333
+ mapCustomerTotalsResponse(apiResponse) {
7334
+ let dataArray = [];
7335
+ if (apiResponse && apiResponse.data && Array.isArray(apiResponse.data)) {
7336
+ dataArray = apiResponse.data;
7337
+ } else if (Array.isArray(apiResponse)) {
7338
+ dataArray = apiResponse;
7339
+ } else {
7340
+ console.warn("[AllReportModal] Invalid API response structure:", apiResponse);
7341
+ return [];
7342
+ }
7343
+ if (dataArray.length === 0) {
7344
+ console.warn("[AllReportModal] Empty data array in API response");
7318
7345
  return [];
7319
7346
  }
7320
- const mappedData = apiData.map((item) => {
7347
+ const mappedData = dataArray.map((item) => {
7321
7348
  const identifier = item.identifier || item.deviceId || item.id || "N/A";
7322
7349
  const name = item.deviceLabel || item.name || item.label || identifier;
7323
7350
  const consumption = this.parseConsumptionValue(item);
@@ -7327,11 +7354,11 @@ var AllReportModal = class {
7327
7354
  consumption
7328
7355
  };
7329
7356
  }).filter((store) => {
7330
- return !this.shouldExcludeStore(store.name);
7357
+ return !this.shouldExcludeStore(store.name, store.identifier);
7331
7358
  }).filter((store) => {
7332
7359
  return !isNaN(store.consumption) && store.consumption >= 0;
7333
7360
  });
7334
- console.log("[AllReportModal] Mapped customer totals:", mappedData.length, "stores");
7361
+ console.log("[AllReportModal] Mapped customer totals:", mappedData.length, "stores from", dataArray.length, "total devices");
7335
7362
  return mappedData;
7336
7363
  }
7337
7364
  parseConsumptionValue(item) {
@@ -7355,14 +7382,24 @@ var AllReportModal = class {
7355
7382
  console.warn("[AllReportModal] No valid consumption value found in item:", item);
7356
7383
  return 0;
7357
7384
  }
7358
- shouldExcludeStore(storeName) {
7359
- if (!this.params.filters?.excludeLabels) return false;
7360
- return this.params.filters.excludeLabels.some((filter) => {
7361
- if (filter instanceof RegExp) {
7362
- return filter.test(storeName);
7363
- }
7364
- return storeName.toLowerCase().includes(filter.toLowerCase());
7365
- });
7385
+ shouldExcludeStore(storeName, storeId) {
7386
+ const filters = this.params.filters;
7387
+ if (!filters) return false;
7388
+ if (filters.forceOnlyIds && Array.isArray(filters.forceOnlyIds) && filters.forceOnlyIds.length > 0) {
7389
+ return !filters.forceOnlyIds.includes(storeId);
7390
+ }
7391
+ if (filters.excludeIds && Array.isArray(filters.excludeIds) && filters.excludeIds.length > 0) {
7392
+ return filters.excludeIds.includes(storeId);
7393
+ }
7394
+ if (filters.excludeLabels && Array.isArray(filters.excludeLabels) && filters.excludeLabels.length > 0) {
7395
+ return filters.excludeLabels.some((filter) => {
7396
+ if (filter instanceof RegExp) {
7397
+ return filter.test(storeName);
7398
+ }
7399
+ return storeName.toLowerCase().includes(filter.toLowerCase());
7400
+ });
7401
+ }
7402
+ return false;
7366
7403
  }
7367
7404
  downloadCSV(content, filename) {
7368
7405
  const BOM = "\uFEFF";
@@ -7990,16 +8027,16 @@ var DefaultSettingsPersister = class {
7990
8027
  throw this.createHttpError(getRes.status, await getRes.text().catch(() => ""));
7991
8028
  }
7992
8029
  const device = await getRes.json();
7993
- const putRes = await fetch(`${this.tbBaseUrl}/api/device`, {
7994
- method: "PUT",
8030
+ const postRes = await fetch(`${this.tbBaseUrl}/api/device`, {
8031
+ method: "POST",
7995
8032
  headers: {
7996
8033
  "X-Authorization": `Bearer ${this.jwtToken}`,
7997
8034
  "Content-Type": "application/json"
7998
8035
  },
7999
8036
  body: JSON.stringify({ ...device, label: this.sanitizeLabel(label) })
8000
8037
  });
8001
- if (!putRes.ok) {
8002
- throw this.createHttpError(putRes.status, await putRes.text().catch(() => ""));
8038
+ if (!postRes.ok) {
8039
+ throw this.createHttpError(postRes.status, await postRes.text().catch(() => ""));
8003
8040
  }
8004
8041
  return { ok: true };
8005
8042
  } catch (error) {
@@ -5731,6 +5731,7 @@
5731
5731
  isLoading = false;
5732
5732
  eventHandlers = {};
5733
5733
  dateRangePicker = null;
5734
+ sortState = { key: null, direction: "asc" };
5734
5735
  show() {
5735
5736
  this.modal = createModal({
5736
5737
  title: `Relat\xF3rio - ${this.params.identifier || "SEM IDENTIFICADOR"} - ${this.params.label || "SEM ETIQUETA"}`,
@@ -5885,6 +5886,12 @@
5885
5886
  const container = document.getElementById("table-container");
5886
5887
  if (!container) return;
5887
5888
  const total = this.calculateTotal();
5889
+ const getSortIndicator = (columnKey) => {
5890
+ if (this.sortState.key === columnKey) {
5891
+ return this.sortState.direction === "asc" ? "\u2191" : "\u2193";
5892
+ }
5893
+ return "\u2195";
5894
+ };
5888
5895
  container.innerHTML = `
5889
5896
  <div style="margin-bottom: 16px; padding: 12px; background: var(--myio-bg); border-radius: 6px;">
5890
5897
  <strong>Total: ${fmtPt(total)} kWh</strong>
@@ -5896,11 +5903,11 @@
5896
5903
  <tr>
5897
5904
  <th style="cursor: pointer;" data-sort="date">
5898
5905
  Data
5899
- <span style="margin-left: 4px; opacity: 0.5;">\u2195</span>
5906
+ <span style="margin-left: 4px; opacity: ${this.sortState.key === "date" ? "1" : "0.5"};">${getSortIndicator("date")}</span>
5900
5907
  </th>
5901
5908
  <th style="cursor: pointer; text-align: right;" data-sort="consumption">
5902
5909
  Consumo (kWh)
5903
- <span style="margin-left: 4px; opacity: 0.5;">\u2195</span>
5910
+ <span style="margin-left: 4px; opacity: ${this.sortState.key === "consumption" ? "1" : "0.5"};">${getSortIndicator("consumption")}</span>
5904
5911
  </th>
5905
5912
  </tr>
5906
5913
  </thead>
@@ -5928,12 +5935,20 @@
5928
5935
  });
5929
5936
  }
5930
5937
  sortData(key) {
5938
+ if (this.sortState.key === key) {
5939
+ this.sortState.direction = this.sortState.direction === "asc" ? "desc" : "asc";
5940
+ } else {
5941
+ this.sortState.key = key;
5942
+ this.sortState.direction = "asc";
5943
+ }
5931
5944
  this.data.sort((a, b) => {
5945
+ let comparison = 0;
5932
5946
  if (key === "date") {
5933
- return new Date(a.date).getTime() - new Date(b.date).getTime();
5947
+ comparison = new Date(a.date).getTime() - new Date(b.date).getTime();
5934
5948
  } else {
5935
- return a.consumption - b.consumption;
5949
+ comparison = a.consumption - b.consumption;
5936
5950
  }
5951
+ return this.sortState.direction === "desc" ? -comparison : comparison;
5937
5952
  });
5938
5953
  }
5939
5954
  calculateTotal() {
@@ -7088,15 +7103,15 @@
7088
7103
  <tr>
7089
7104
  <th style="cursor: pointer; width: 25%;" data-sort="identifier">
7090
7105
  Identifier
7091
- <span style="margin-left: 4px; opacity: 0.5;">${this.getSortIcon("identifier")}</span>
7106
+ <span style="margin-left: 4px; opacity: ${this.getSortOpacity("identifier")};">${this.getSortIcon("identifier")}</span>
7092
7107
  </th>
7093
7108
  <th style="cursor: pointer; width: 45%;" data-sort="name">
7094
7109
  Name
7095
- <span style="margin-left: 4px; opacity: 0.5;">${this.getSortIcon("name")}</span>
7110
+ <span style="margin-left: 4px; opacity: ${this.getSortOpacity("name")};">${this.getSortIcon("name")}</span>
7096
7111
  </th>
7097
7112
  <th style="cursor: pointer; text-align: right; width: 30%;" data-sort="consumption">
7098
7113
  Consumption (kWh)
7099
- <span style="margin-left: 4px; opacity: 0.5;">${this.getSortIcon("consumption")}</span>
7114
+ <span style="margin-left: 4px; opacity: ${this.getSortOpacity("consumption")};">${this.getSortIcon("consumption")}</span>
7100
7115
  </th>
7101
7116
  </tr>
7102
7117
  </thead>
@@ -7118,6 +7133,9 @@
7118
7133
  if (this.sortField !== field) return "\u2195";
7119
7134
  return this.sortDirection === "asc" ? "\u2191" : "\u2193";
7120
7135
  }
7136
+ getSortOpacity(field) {
7137
+ return this.sortField === field ? "1" : "0.5";
7138
+ }
7121
7139
  setupTableSorting() {
7122
7140
  const headers = document.querySelectorAll("[data-sort]");
7123
7141
  headers.forEach((header) => {
@@ -7299,14 +7317,23 @@
7299
7317
  }
7300
7318
  const data = await response.json();
7301
7319
  console.log("[AllReportModal] Customer totals response:", data);
7302
- return Array.isArray(data) ? data : [];
7320
+ return data;
7303
7321
  }
7304
- mapCustomerTotalsResponse(apiData) {
7305
- if (!Array.isArray(apiData) || apiData.length === 0) {
7306
- console.warn("[AllReportModal] Empty or invalid API response:", apiData);
7322
+ mapCustomerTotalsResponse(apiResponse) {
7323
+ let dataArray = [];
7324
+ if (apiResponse && apiResponse.data && Array.isArray(apiResponse.data)) {
7325
+ dataArray = apiResponse.data;
7326
+ } else if (Array.isArray(apiResponse)) {
7327
+ dataArray = apiResponse;
7328
+ } else {
7329
+ console.warn("[AllReportModal] Invalid API response structure:", apiResponse);
7330
+ return [];
7331
+ }
7332
+ if (dataArray.length === 0) {
7333
+ console.warn("[AllReportModal] Empty data array in API response");
7307
7334
  return [];
7308
7335
  }
7309
- const mappedData = apiData.map((item) => {
7336
+ const mappedData = dataArray.map((item) => {
7310
7337
  const identifier = item.identifier || item.deviceId || item.id || "N/A";
7311
7338
  const name = item.deviceLabel || item.name || item.label || identifier;
7312
7339
  const consumption = this.parseConsumptionValue(item);
@@ -7316,11 +7343,11 @@
7316
7343
  consumption
7317
7344
  };
7318
7345
  }).filter((store) => {
7319
- return !this.shouldExcludeStore(store.name);
7346
+ return !this.shouldExcludeStore(store.name, store.identifier);
7320
7347
  }).filter((store) => {
7321
7348
  return !isNaN(store.consumption) && store.consumption >= 0;
7322
7349
  });
7323
- console.log("[AllReportModal] Mapped customer totals:", mappedData.length, "stores");
7350
+ console.log("[AllReportModal] Mapped customer totals:", mappedData.length, "stores from", dataArray.length, "total devices");
7324
7351
  return mappedData;
7325
7352
  }
7326
7353
  parseConsumptionValue(item) {
@@ -7344,14 +7371,24 @@
7344
7371
  console.warn("[AllReportModal] No valid consumption value found in item:", item);
7345
7372
  return 0;
7346
7373
  }
7347
- shouldExcludeStore(storeName) {
7348
- if (!this.params.filters?.excludeLabels) return false;
7349
- return this.params.filters.excludeLabels.some((filter) => {
7350
- if (filter instanceof RegExp) {
7351
- return filter.test(storeName);
7352
- }
7353
- return storeName.toLowerCase().includes(filter.toLowerCase());
7354
- });
7374
+ shouldExcludeStore(storeName, storeId) {
7375
+ const filters = this.params.filters;
7376
+ if (!filters) return false;
7377
+ if (filters.forceOnlyIds && Array.isArray(filters.forceOnlyIds) && filters.forceOnlyIds.length > 0) {
7378
+ return !filters.forceOnlyIds.includes(storeId);
7379
+ }
7380
+ if (filters.excludeIds && Array.isArray(filters.excludeIds) && filters.excludeIds.length > 0) {
7381
+ return filters.excludeIds.includes(storeId);
7382
+ }
7383
+ if (filters.excludeLabels && Array.isArray(filters.excludeLabels) && filters.excludeLabels.length > 0) {
7384
+ return filters.excludeLabels.some((filter) => {
7385
+ if (filter instanceof RegExp) {
7386
+ return filter.test(storeName);
7387
+ }
7388
+ return storeName.toLowerCase().includes(filter.toLowerCase());
7389
+ });
7390
+ }
7391
+ return false;
7355
7392
  }
7356
7393
  downloadCSV(content, filename) {
7357
7394
  const BOM = "\uFEFF";
@@ -7979,16 +8016,16 @@
7979
8016
  throw this.createHttpError(getRes.status, await getRes.text().catch(() => ""));
7980
8017
  }
7981
8018
  const device = await getRes.json();
7982
- const putRes = await fetch(`${this.tbBaseUrl}/api/device`, {
7983
- method: "PUT",
8019
+ const postRes = await fetch(`${this.tbBaseUrl}/api/device`, {
8020
+ method: "POST",
7984
8021
  headers: {
7985
8022
  "X-Authorization": `Bearer ${this.jwtToken}`,
7986
8023
  "Content-Type": "application/json"
7987
8024
  },
7988
8025
  body: JSON.stringify({ ...device, label: this.sanitizeLabel(label) })
7989
8026
  });
7990
- if (!putRes.ok) {
7991
- throw this.createHttpError(putRes.status, await putRes.text().catch(() => ""));
8027
+ if (!postRes.ok) {
8028
+ throw this.createHttpError(postRes.status, await postRes.text().catch(() => ""));
7992
8029
  }
7993
8030
  return { ok: true };
7994
8031
  } catch (error) {