myio-js-library 0.1.172 → 0.1.173
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 +1004 -0
- package/dist/index.d.cts +199 -1
- package/dist/index.js +1000 -0
- package/dist/myio-js-library.umd.js +1000 -0
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -588,6 +588,9 @@ __export(index_exports, {
|
|
|
588
588
|
MyIOSelectionStore: () => MyIOSelectionStore,
|
|
589
589
|
MyIOSelectionStoreClass: () => MyIOSelectionStoreClass,
|
|
590
590
|
MyIOToast: () => MyIOToast,
|
|
591
|
+
POWER_LIMITS_DEVICE_TYPES: () => DEVICE_TYPES,
|
|
592
|
+
POWER_LIMITS_STATUS_CONFIG: () => STATUS_CONFIG,
|
|
593
|
+
POWER_LIMITS_TELEMETRY_TYPES: () => TELEMETRY_TYPES2,
|
|
591
594
|
addDetectionContext: () => addDetectionContext,
|
|
592
595
|
addNamespace: () => addNamespace,
|
|
593
596
|
aggregateByDay: () => aggregateByDay,
|
|
@@ -685,6 +688,7 @@ __export(index_exports, {
|
|
|
685
688
|
openDashboardPopupWaterTank: () => openDashboardPopupWaterTank,
|
|
686
689
|
openDemandModal: () => openDemandModal,
|
|
687
690
|
openGoalsPanel: () => openGoalsPanel,
|
|
691
|
+
openPowerLimitsSetupModal: () => openPowerLimitsSetupModal,
|
|
688
692
|
openRealTimeTelemetryModal: () => openRealTimeTelemetryModal,
|
|
689
693
|
openTemperatureComparisonModal: () => openTemperatureComparisonModal,
|
|
690
694
|
openTemperatureModal: () => openTemperatureModal,
|
|
@@ -16780,6 +16784,1002 @@ function validateOptions2(options) {
|
|
|
16780
16784
|
}
|
|
16781
16785
|
}
|
|
16782
16786
|
|
|
16787
|
+
// src/components/premium-modals/power-limits/types.ts
|
|
16788
|
+
var DEVICE_TYPES = [
|
|
16789
|
+
{ value: "ELEVADOR", label: "Elevator" },
|
|
16790
|
+
{ value: "ESCADA_ROLANTE", label: "Escalator" },
|
|
16791
|
+
{ value: "MOTOR", label: "Motor" },
|
|
16792
|
+
{ value: "BOMBA", label: "Pump" },
|
|
16793
|
+
{ value: "CHILLER", label: "Chiller" },
|
|
16794
|
+
{ value: "AR_CONDICIONADO", label: "Air Conditioner" },
|
|
16795
|
+
{ value: "HVAC", label: "HVAC" },
|
|
16796
|
+
{ value: "FANCOIL", label: "Fancoil" },
|
|
16797
|
+
{ value: "3F_MEDIDOR", label: "Three-phase Meter" }
|
|
16798
|
+
];
|
|
16799
|
+
var TELEMETRY_TYPES2 = [
|
|
16800
|
+
{ value: "consumption", label: "Consumption (kW)", unit: "kW" },
|
|
16801
|
+
{ value: "voltage_a", label: "Voltage A (V)", unit: "V" },
|
|
16802
|
+
{ value: "voltage_b", label: "Voltage B (V)", unit: "V" },
|
|
16803
|
+
{ value: "voltage_c", label: "Voltage C (V)", unit: "V" },
|
|
16804
|
+
{ value: "current_a", label: "Current A (A)", unit: "A" },
|
|
16805
|
+
{ value: "current_b", label: "Current B (A)", unit: "A" },
|
|
16806
|
+
{ value: "current_c", label: "Current C (A)", unit: "A" },
|
|
16807
|
+
{ value: "total_current", label: "Total Current (A)", unit: "A" },
|
|
16808
|
+
{ value: "fp_a", label: "Power Factor A", unit: "" },
|
|
16809
|
+
{ value: "fp_b", label: "Power Factor B", unit: "" },
|
|
16810
|
+
{ value: "fp_c", label: "Power Factor C", unit: "" }
|
|
16811
|
+
];
|
|
16812
|
+
var STATUS_CONFIG = {
|
|
16813
|
+
standBy: { label: "StandBy", color: "#22c55e", bgColor: "rgba(34, 197, 94, 0.1)" },
|
|
16814
|
+
normal: { label: "Normal", color: "#3b82f6", bgColor: "rgba(59, 130, 246, 0.1)" },
|
|
16815
|
+
alert: { label: "Alert", color: "#f59e0b", bgColor: "rgba(245, 158, 11, 0.1)" },
|
|
16816
|
+
failure: { label: "Failure", color: "#ef4444", bgColor: "rgba(239, 68, 68, 0.1)" }
|
|
16817
|
+
};
|
|
16818
|
+
|
|
16819
|
+
// src/components/premium-modals/power-limits/PowerLimitsModalView.ts
|
|
16820
|
+
var PowerLimitsModalView = class {
|
|
16821
|
+
container = null;
|
|
16822
|
+
overlayEl = null;
|
|
16823
|
+
config;
|
|
16824
|
+
formData;
|
|
16825
|
+
isLoading = false;
|
|
16826
|
+
isSaving = false;
|
|
16827
|
+
constructor(config) {
|
|
16828
|
+
this.config = config;
|
|
16829
|
+
this.formData = {
|
|
16830
|
+
deviceType: config.deviceType,
|
|
16831
|
+
telemetryType: config.telemetryType,
|
|
16832
|
+
standby: { baseValue: null, topValue: null },
|
|
16833
|
+
normal: { baseValue: null, topValue: null },
|
|
16834
|
+
alert: { baseValue: null, topValue: null },
|
|
16835
|
+
failure: { baseValue: null, topValue: null }
|
|
16836
|
+
};
|
|
16837
|
+
}
|
|
16838
|
+
render(targetContainer) {
|
|
16839
|
+
this.overlayEl = document.createElement("div");
|
|
16840
|
+
this.overlayEl.className = "myio-power-limits-overlay";
|
|
16841
|
+
this.overlayEl.innerHTML = `
|
|
16842
|
+
<style>${this.getStyles()}</style>
|
|
16843
|
+
<div class="myio-power-limits-card">
|
|
16844
|
+
${this.renderHeader()}
|
|
16845
|
+
${this.renderSelectors()}
|
|
16846
|
+
${this.renderStatusCards()}
|
|
16847
|
+
${this.renderLoadingState()}
|
|
16848
|
+
${this.renderErrorState()}
|
|
16849
|
+
${this.renderSuccessState()}
|
|
16850
|
+
</div>
|
|
16851
|
+
`;
|
|
16852
|
+
const target = targetContainer || document.body;
|
|
16853
|
+
target.appendChild(this.overlayEl);
|
|
16854
|
+
this.container = this.overlayEl.querySelector(".myio-power-limits-card");
|
|
16855
|
+
this.setupEventListeners();
|
|
16856
|
+
requestAnimationFrame(() => {
|
|
16857
|
+
this.overlayEl?.classList.add("active");
|
|
16858
|
+
});
|
|
16859
|
+
return this.overlayEl;
|
|
16860
|
+
}
|
|
16861
|
+
renderHeader() {
|
|
16862
|
+
return `
|
|
16863
|
+
<div class="myio-power-limits-header">
|
|
16864
|
+
<div class="myio-power-limits-title-section">
|
|
16865
|
+
<span class="myio-power-limits-icon">⚙</span>
|
|
16866
|
+
<h2 class="myio-power-limits-title">Power Limits Setup</h2>
|
|
16867
|
+
</div>
|
|
16868
|
+
<div class="myio-power-limits-actions">
|
|
16869
|
+
<button class="myio-btn myio-btn-primary" id="plm-save-btn" type="button">
|
|
16870
|
+
<span class="myio-btn-text">Save</span>
|
|
16871
|
+
<span class="myio-btn-spinner" style="display: none;"></span>
|
|
16872
|
+
</button>
|
|
16873
|
+
<button class="myio-btn myio-btn-secondary" id="plm-reset-btn" type="button">Reset</button>
|
|
16874
|
+
<button class="myio-btn myio-btn-close" id="plm-close-btn" type="button" aria-label="Close">×</button>
|
|
16875
|
+
</div>
|
|
16876
|
+
</div>
|
|
16877
|
+
`;
|
|
16878
|
+
}
|
|
16879
|
+
renderSelectors() {
|
|
16880
|
+
const deviceOptions = DEVICE_TYPES.map(
|
|
16881
|
+
(dt) => `<option value="${dt.value}" ${dt.value === this.config.deviceType ? "selected" : ""}>${dt.label}</option>`
|
|
16882
|
+
).join("");
|
|
16883
|
+
const telemetryOptions = TELEMETRY_TYPES2.map(
|
|
16884
|
+
(tt) => `<option value="${tt.value}" ${tt.value === this.config.telemetryType ? "selected" : ""}>${tt.label}</option>`
|
|
16885
|
+
).join("");
|
|
16886
|
+
return `
|
|
16887
|
+
<div class="myio-power-limits-selectors">
|
|
16888
|
+
<div class="myio-form-group">
|
|
16889
|
+
<label for="plm-device-type">Device Type</label>
|
|
16890
|
+
<select id="plm-device-type" class="myio-select">
|
|
16891
|
+
${deviceOptions}
|
|
16892
|
+
</select>
|
|
16893
|
+
</div>
|
|
16894
|
+
<div class="myio-form-group">
|
|
16895
|
+
<label for="plm-telemetry-type">Telemetry Type</label>
|
|
16896
|
+
<select id="plm-telemetry-type" class="myio-select">
|
|
16897
|
+
${telemetryOptions}
|
|
16898
|
+
</select>
|
|
16899
|
+
</div>
|
|
16900
|
+
</div>
|
|
16901
|
+
`;
|
|
16902
|
+
}
|
|
16903
|
+
renderStatusCards() {
|
|
16904
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
16905
|
+
const cards = statuses.map((status) => {
|
|
16906
|
+
const config = STATUS_CONFIG[status === "standby" ? "standBy" : status];
|
|
16907
|
+
const formValues = this.formData[status];
|
|
16908
|
+
return `
|
|
16909
|
+
<div class="myio-power-limits-card-item myio-status-${status}" style="--status-color: ${config.color}; --status-bg: ${config.bgColor};">
|
|
16910
|
+
<div class="myio-card-header">
|
|
16911
|
+
<span class="myio-status-indicator"></span>
|
|
16912
|
+
<span class="myio-status-label">${config.label}</span>
|
|
16913
|
+
</div>
|
|
16914
|
+
<div class="myio-card-inputs">
|
|
16915
|
+
<div class="myio-input-group">
|
|
16916
|
+
<label for="plm-${status}-base">Base Value</label>
|
|
16917
|
+
<input
|
|
16918
|
+
type="number"
|
|
16919
|
+
id="plm-${status}-base"
|
|
16920
|
+
class="myio-input"
|
|
16921
|
+
min="0"
|
|
16922
|
+
step="0.01"
|
|
16923
|
+
value="${formValues.baseValue ?? ""}"
|
|
16924
|
+
placeholder="0"
|
|
16925
|
+
>
|
|
16926
|
+
</div>
|
|
16927
|
+
<div class="myio-input-group">
|
|
16928
|
+
<label for="plm-${status}-top">Top Value</label>
|
|
16929
|
+
<input
|
|
16930
|
+
type="number"
|
|
16931
|
+
id="plm-${status}-top"
|
|
16932
|
+
class="myio-input"
|
|
16933
|
+
min="0"
|
|
16934
|
+
step="0.01"
|
|
16935
|
+
value="${formValues.topValue ?? ""}"
|
|
16936
|
+
placeholder="0"
|
|
16937
|
+
>
|
|
16938
|
+
</div>
|
|
16939
|
+
</div>
|
|
16940
|
+
</div>
|
|
16941
|
+
`;
|
|
16942
|
+
}).join("");
|
|
16943
|
+
return `
|
|
16944
|
+
<div class="myio-power-limits-grid" id="plm-grid">
|
|
16945
|
+
${cards}
|
|
16946
|
+
</div>
|
|
16947
|
+
`;
|
|
16948
|
+
}
|
|
16949
|
+
renderLoadingState() {
|
|
16950
|
+
return `
|
|
16951
|
+
<div class="myio-power-limits-loading" id="plm-loading" style="display: none;">
|
|
16952
|
+
<div class="myio-spinner"></div>
|
|
16953
|
+
<span>Loading configuration...</span>
|
|
16954
|
+
</div>
|
|
16955
|
+
`;
|
|
16956
|
+
}
|
|
16957
|
+
renderErrorState() {
|
|
16958
|
+
return `
|
|
16959
|
+
<div class="myio-power-limits-error" id="plm-error" style="display: none;">
|
|
16960
|
+
<span class="myio-error-icon">⚠</span>
|
|
16961
|
+
<span class="myio-error-message" id="plm-error-msg"></span>
|
|
16962
|
+
</div>
|
|
16963
|
+
`;
|
|
16964
|
+
}
|
|
16965
|
+
renderSuccessState() {
|
|
16966
|
+
return `
|
|
16967
|
+
<div class="myio-power-limits-success" id="plm-success" style="display: none;">
|
|
16968
|
+
<span class="myio-success-icon">✓</span>
|
|
16969
|
+
<span class="myio-success-message">Configuration saved successfully!</span>
|
|
16970
|
+
</div>
|
|
16971
|
+
`;
|
|
16972
|
+
}
|
|
16973
|
+
setupEventListeners() {
|
|
16974
|
+
if (!this.overlayEl) return;
|
|
16975
|
+
const closeBtn = this.overlayEl.querySelector("#plm-close-btn");
|
|
16976
|
+
closeBtn?.addEventListener("click", () => this.close());
|
|
16977
|
+
this.overlayEl.addEventListener("click", (e) => {
|
|
16978
|
+
if (e.target === this.overlayEl) {
|
|
16979
|
+
this.close();
|
|
16980
|
+
}
|
|
16981
|
+
});
|
|
16982
|
+
document.addEventListener("keydown", this.handleKeyDown);
|
|
16983
|
+
const saveBtn = this.overlayEl.querySelector("#plm-save-btn");
|
|
16984
|
+
saveBtn?.addEventListener("click", () => this.handleSave());
|
|
16985
|
+
const resetBtn = this.overlayEl.querySelector("#plm-reset-btn");
|
|
16986
|
+
resetBtn?.addEventListener("click", () => this.handleReset());
|
|
16987
|
+
const deviceSelect = this.overlayEl.querySelector("#plm-device-type");
|
|
16988
|
+
deviceSelect?.addEventListener("change", (e) => {
|
|
16989
|
+
const value = e.target.value;
|
|
16990
|
+
this.formData.deviceType = value;
|
|
16991
|
+
this.config.onDeviceTypeChange(value);
|
|
16992
|
+
});
|
|
16993
|
+
const telemetrySelect = this.overlayEl.querySelector("#plm-telemetry-type");
|
|
16994
|
+
telemetrySelect?.addEventListener("change", (e) => {
|
|
16995
|
+
const value = e.target.value;
|
|
16996
|
+
this.formData.telemetryType = value;
|
|
16997
|
+
this.config.onTelemetryTypeChange(value);
|
|
16998
|
+
});
|
|
16999
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
17000
|
+
statuses.forEach((status) => {
|
|
17001
|
+
const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
|
|
17002
|
+
const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
|
|
17003
|
+
baseInput?.addEventListener("input", (e) => {
|
|
17004
|
+
const value = e.target.value;
|
|
17005
|
+
this.formData[status].baseValue = value ? parseFloat(value) : null;
|
|
17006
|
+
});
|
|
17007
|
+
topInput?.addEventListener("input", (e) => {
|
|
17008
|
+
const value = e.target.value;
|
|
17009
|
+
this.formData[status].topValue = value ? parseFloat(value) : null;
|
|
17010
|
+
});
|
|
17011
|
+
});
|
|
17012
|
+
}
|
|
17013
|
+
handleKeyDown = (e) => {
|
|
17014
|
+
if (e.key === "Escape") {
|
|
17015
|
+
this.close();
|
|
17016
|
+
}
|
|
17017
|
+
};
|
|
17018
|
+
async handleSave() {
|
|
17019
|
+
if (this.isSaving) return;
|
|
17020
|
+
const validationError = this.validateForm();
|
|
17021
|
+
if (validationError) {
|
|
17022
|
+
this.showError(validationError);
|
|
17023
|
+
return;
|
|
17024
|
+
}
|
|
17025
|
+
this.isSaving = true;
|
|
17026
|
+
this.showSaveLoading(true);
|
|
17027
|
+
this.hideError();
|
|
17028
|
+
this.hideSuccess();
|
|
17029
|
+
try {
|
|
17030
|
+
await this.config.onSave();
|
|
17031
|
+
this.showSuccess();
|
|
17032
|
+
setTimeout(() => this.hideSuccess(), 3e3);
|
|
17033
|
+
} catch (error) {
|
|
17034
|
+
this.showError(error.message || "Failed to save configuration");
|
|
17035
|
+
} finally {
|
|
17036
|
+
this.isSaving = false;
|
|
17037
|
+
this.showSaveLoading(false);
|
|
17038
|
+
}
|
|
17039
|
+
}
|
|
17040
|
+
handleReset() {
|
|
17041
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
17042
|
+
statuses.forEach((status) => {
|
|
17043
|
+
const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
|
|
17044
|
+
const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
|
|
17045
|
+
if (baseInput) baseInput.value = "";
|
|
17046
|
+
if (topInput) topInput.value = "";
|
|
17047
|
+
this.formData[status] = { baseValue: null, topValue: null };
|
|
17048
|
+
});
|
|
17049
|
+
this.hideError();
|
|
17050
|
+
this.hideSuccess();
|
|
17051
|
+
}
|
|
17052
|
+
validateForm() {
|
|
17053
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
17054
|
+
for (const status of statuses) {
|
|
17055
|
+
const base = this.formData[status].baseValue;
|
|
17056
|
+
const top = this.formData[status].topValue;
|
|
17057
|
+
if (base !== null && base < 0) {
|
|
17058
|
+
return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value cannot be negative`;
|
|
17059
|
+
}
|
|
17060
|
+
if (top !== null && top < 0) {
|
|
17061
|
+
return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Top value cannot be negative`;
|
|
17062
|
+
}
|
|
17063
|
+
if (base !== null && top !== null && base > top) {
|
|
17064
|
+
return `${STATUS_CONFIG[status === "standby" ? "standBy" : status].label}: Base value should not exceed top value`;
|
|
17065
|
+
}
|
|
17066
|
+
}
|
|
17067
|
+
return null;
|
|
17068
|
+
}
|
|
17069
|
+
close() {
|
|
17070
|
+
document.removeEventListener("keydown", this.handleKeyDown);
|
|
17071
|
+
if (this.overlayEl) {
|
|
17072
|
+
this.overlayEl.classList.remove("active");
|
|
17073
|
+
setTimeout(() => {
|
|
17074
|
+
this.overlayEl?.remove();
|
|
17075
|
+
this.overlayEl = null;
|
|
17076
|
+
this.container = null;
|
|
17077
|
+
this.config.onClose();
|
|
17078
|
+
}, 300);
|
|
17079
|
+
}
|
|
17080
|
+
}
|
|
17081
|
+
destroy() {
|
|
17082
|
+
document.removeEventListener("keydown", this.handleKeyDown);
|
|
17083
|
+
this.overlayEl?.remove();
|
|
17084
|
+
this.overlayEl = null;
|
|
17085
|
+
this.container = null;
|
|
17086
|
+
}
|
|
17087
|
+
showLoading() {
|
|
17088
|
+
this.isLoading = true;
|
|
17089
|
+
const loadingEl = this.overlayEl?.querySelector("#plm-loading");
|
|
17090
|
+
const gridEl = this.overlayEl?.querySelector("#plm-grid");
|
|
17091
|
+
if (loadingEl) loadingEl.style.display = "flex";
|
|
17092
|
+
if (gridEl) gridEl.style.opacity = "0.5";
|
|
17093
|
+
}
|
|
17094
|
+
hideLoading() {
|
|
17095
|
+
this.isLoading = false;
|
|
17096
|
+
const loadingEl = this.overlayEl?.querySelector("#plm-loading");
|
|
17097
|
+
const gridEl = this.overlayEl?.querySelector("#plm-grid");
|
|
17098
|
+
if (loadingEl) loadingEl.style.display = "none";
|
|
17099
|
+
if (gridEl) gridEl.style.opacity = "1";
|
|
17100
|
+
}
|
|
17101
|
+
showSaveLoading(show) {
|
|
17102
|
+
const saveBtn = this.overlayEl?.querySelector("#plm-save-btn");
|
|
17103
|
+
const btnText = saveBtn?.querySelector(".myio-btn-text");
|
|
17104
|
+
const btnSpinner = saveBtn?.querySelector(".myio-btn-spinner");
|
|
17105
|
+
if (saveBtn) saveBtn.disabled = show;
|
|
17106
|
+
if (btnText) btnText.style.display = show ? "none" : "inline";
|
|
17107
|
+
if (btnSpinner) btnSpinner.style.display = show ? "inline-block" : "none";
|
|
17108
|
+
}
|
|
17109
|
+
showError(message) {
|
|
17110
|
+
const errorEl = this.overlayEl?.querySelector("#plm-error");
|
|
17111
|
+
const errorMsg = this.overlayEl?.querySelector("#plm-error-msg");
|
|
17112
|
+
if (errorEl) errorEl.style.display = "flex";
|
|
17113
|
+
if (errorMsg) errorMsg.textContent = message;
|
|
17114
|
+
}
|
|
17115
|
+
hideError() {
|
|
17116
|
+
const errorEl = this.overlayEl?.querySelector("#plm-error");
|
|
17117
|
+
if (errorEl) errorEl.style.display = "none";
|
|
17118
|
+
}
|
|
17119
|
+
showSuccess() {
|
|
17120
|
+
const successEl = this.overlayEl?.querySelector("#plm-success");
|
|
17121
|
+
if (successEl) successEl.style.display = "flex";
|
|
17122
|
+
}
|
|
17123
|
+
hideSuccess() {
|
|
17124
|
+
const successEl = this.overlayEl?.querySelector("#plm-success");
|
|
17125
|
+
if (successEl) successEl.style.display = "none";
|
|
17126
|
+
}
|
|
17127
|
+
getFormData() {
|
|
17128
|
+
return { ...this.formData };
|
|
17129
|
+
}
|
|
17130
|
+
setFormData(data) {
|
|
17131
|
+
if (data.deviceType) this.formData.deviceType = data.deviceType;
|
|
17132
|
+
if (data.telemetryType) this.formData.telemetryType = data.telemetryType;
|
|
17133
|
+
if (data.standby) this.formData.standby = { ...data.standby };
|
|
17134
|
+
if (data.normal) this.formData.normal = { ...data.normal };
|
|
17135
|
+
if (data.alert) this.formData.alert = { ...data.alert };
|
|
17136
|
+
if (data.failure) this.formData.failure = { ...data.failure };
|
|
17137
|
+
this.updateInputValues();
|
|
17138
|
+
}
|
|
17139
|
+
updateInputValues() {
|
|
17140
|
+
const statuses = ["standby", "normal", "alert", "failure"];
|
|
17141
|
+
statuses.forEach((status) => {
|
|
17142
|
+
const baseInput = this.overlayEl?.querySelector(`#plm-${status}-base`);
|
|
17143
|
+
const topInput = this.overlayEl?.querySelector(`#plm-${status}-top`);
|
|
17144
|
+
if (baseInput) {
|
|
17145
|
+
baseInput.value = this.formData[status].baseValue?.toString() ?? "";
|
|
17146
|
+
}
|
|
17147
|
+
if (topInput) {
|
|
17148
|
+
topInput.value = this.formData[status].topValue?.toString() ?? "";
|
|
17149
|
+
}
|
|
17150
|
+
});
|
|
17151
|
+
const deviceSelect = this.overlayEl?.querySelector("#plm-device-type");
|
|
17152
|
+
const telemetrySelect = this.overlayEl?.querySelector("#plm-telemetry-type");
|
|
17153
|
+
if (deviceSelect) deviceSelect.value = this.formData.deviceType;
|
|
17154
|
+
if (telemetrySelect) telemetrySelect.value = this.formData.telemetryType;
|
|
17155
|
+
}
|
|
17156
|
+
getStyles() {
|
|
17157
|
+
const styles = this.config.styles || {};
|
|
17158
|
+
const primaryColor = styles.primaryColor || "#4A148C";
|
|
17159
|
+
const successColor = styles.successColor || "#22c55e";
|
|
17160
|
+
const warningColor = styles.warningColor || "#f59e0b";
|
|
17161
|
+
const dangerColor = styles.dangerColor || "#ef4444";
|
|
17162
|
+
const infoColor = styles.infoColor || "#3b82f6";
|
|
17163
|
+
return `
|
|
17164
|
+
.myio-power-limits-overlay {
|
|
17165
|
+
position: fixed;
|
|
17166
|
+
top: 0;
|
|
17167
|
+
left: 0;
|
|
17168
|
+
right: 0;
|
|
17169
|
+
bottom: 0;
|
|
17170
|
+
background: rgba(0, 0, 0, 0.6);
|
|
17171
|
+
display: flex;
|
|
17172
|
+
align-items: center;
|
|
17173
|
+
justify-content: center;
|
|
17174
|
+
z-index: ${styles.zIndex || 1e4};
|
|
17175
|
+
opacity: 0;
|
|
17176
|
+
visibility: hidden;
|
|
17177
|
+
transition: all 0.3s ease;
|
|
17178
|
+
font-family: ${styles.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'};
|
|
17179
|
+
}
|
|
17180
|
+
|
|
17181
|
+
.myio-power-limits-overlay.active {
|
|
17182
|
+
opacity: 1;
|
|
17183
|
+
visibility: visible;
|
|
17184
|
+
}
|
|
17185
|
+
|
|
17186
|
+
.myio-power-limits-card {
|
|
17187
|
+
background: ${styles.backgroundColor || "#ffffff"};
|
|
17188
|
+
border-radius: ${styles.borderRadius || "12px"};
|
|
17189
|
+
width: 90%;
|
|
17190
|
+
max-width: 700px;
|
|
17191
|
+
max-height: 90vh;
|
|
17192
|
+
overflow-y: auto;
|
|
17193
|
+
transform: scale(0.9);
|
|
17194
|
+
transition: transform 0.3s ease;
|
|
17195
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
|
17196
|
+
}
|
|
17197
|
+
|
|
17198
|
+
.myio-power-limits-overlay.active .myio-power-limits-card {
|
|
17199
|
+
transform: scale(1);
|
|
17200
|
+
}
|
|
17201
|
+
|
|
17202
|
+
.myio-power-limits-header {
|
|
17203
|
+
display: flex;
|
|
17204
|
+
align-items: center;
|
|
17205
|
+
justify-content: space-between;
|
|
17206
|
+
padding: 20px 24px;
|
|
17207
|
+
background: linear-gradient(135deg, ${primaryColor}, ${this.lightenColor(primaryColor, 20)});
|
|
17208
|
+
color: white;
|
|
17209
|
+
border-radius: 12px 12px 0 0;
|
|
17210
|
+
}
|
|
17211
|
+
|
|
17212
|
+
.myio-power-limits-title-section {
|
|
17213
|
+
display: flex;
|
|
17214
|
+
align-items: center;
|
|
17215
|
+
gap: 12px;
|
|
17216
|
+
}
|
|
17217
|
+
|
|
17218
|
+
.myio-power-limits-icon {
|
|
17219
|
+
font-size: 24px;
|
|
17220
|
+
}
|
|
17221
|
+
|
|
17222
|
+
.myio-power-limits-title {
|
|
17223
|
+
font-size: 1.25rem;
|
|
17224
|
+
font-weight: 600;
|
|
17225
|
+
margin: 0;
|
|
17226
|
+
}
|
|
17227
|
+
|
|
17228
|
+
.myio-power-limits-actions {
|
|
17229
|
+
display: flex;
|
|
17230
|
+
align-items: center;
|
|
17231
|
+
gap: 8px;
|
|
17232
|
+
}
|
|
17233
|
+
|
|
17234
|
+
.myio-btn {
|
|
17235
|
+
padding: 8px 16px;
|
|
17236
|
+
border-radius: ${styles.buttonRadius || "6px"};
|
|
17237
|
+
font-size: 14px;
|
|
17238
|
+
font-weight: 500;
|
|
17239
|
+
cursor: pointer;
|
|
17240
|
+
border: none;
|
|
17241
|
+
transition: all 0.2s;
|
|
17242
|
+
display: inline-flex;
|
|
17243
|
+
align-items: center;
|
|
17244
|
+
gap: 6px;
|
|
17245
|
+
}
|
|
17246
|
+
|
|
17247
|
+
.myio-btn:disabled {
|
|
17248
|
+
opacity: 0.6;
|
|
17249
|
+
cursor: not-allowed;
|
|
17250
|
+
}
|
|
17251
|
+
|
|
17252
|
+
.myio-btn-primary {
|
|
17253
|
+
background: white;
|
|
17254
|
+
color: ${primaryColor};
|
|
17255
|
+
}
|
|
17256
|
+
|
|
17257
|
+
.myio-btn-primary:hover:not(:disabled) {
|
|
17258
|
+
background: #f3f4f6;
|
|
17259
|
+
}
|
|
17260
|
+
|
|
17261
|
+
.myio-btn-secondary {
|
|
17262
|
+
background: rgba(255, 255, 255, 0.2);
|
|
17263
|
+
color: white;
|
|
17264
|
+
}
|
|
17265
|
+
|
|
17266
|
+
.myio-btn-secondary:hover:not(:disabled) {
|
|
17267
|
+
background: rgba(255, 255, 255, 0.3);
|
|
17268
|
+
}
|
|
17269
|
+
|
|
17270
|
+
.myio-btn-close {
|
|
17271
|
+
background: transparent;
|
|
17272
|
+
color: white;
|
|
17273
|
+
font-size: 24px;
|
|
17274
|
+
padding: 4px 8px;
|
|
17275
|
+
line-height: 1;
|
|
17276
|
+
}
|
|
17277
|
+
|
|
17278
|
+
.myio-btn-close:hover {
|
|
17279
|
+
background: rgba(255, 255, 255, 0.1);
|
|
17280
|
+
}
|
|
17281
|
+
|
|
17282
|
+
.myio-btn-spinner {
|
|
17283
|
+
width: 16px;
|
|
17284
|
+
height: 16px;
|
|
17285
|
+
border: 2px solid ${primaryColor};
|
|
17286
|
+
border-top-color: transparent;
|
|
17287
|
+
border-radius: 50%;
|
|
17288
|
+
animation: spin 0.8s linear infinite;
|
|
17289
|
+
}
|
|
17290
|
+
|
|
17291
|
+
@keyframes spin {
|
|
17292
|
+
to { transform: rotate(360deg); }
|
|
17293
|
+
}
|
|
17294
|
+
|
|
17295
|
+
.myio-power-limits-selectors {
|
|
17296
|
+
display: grid;
|
|
17297
|
+
grid-template-columns: 1fr 1fr;
|
|
17298
|
+
gap: 16px;
|
|
17299
|
+
padding: 20px 24px;
|
|
17300
|
+
background: #f9fafb;
|
|
17301
|
+
border-bottom: 1px solid #e5e7eb;
|
|
17302
|
+
}
|
|
17303
|
+
|
|
17304
|
+
.myio-form-group {
|
|
17305
|
+
display: flex;
|
|
17306
|
+
flex-direction: column;
|
|
17307
|
+
gap: 6px;
|
|
17308
|
+
}
|
|
17309
|
+
|
|
17310
|
+
.myio-form-group label {
|
|
17311
|
+
font-size: 13px;
|
|
17312
|
+
font-weight: 500;
|
|
17313
|
+
color: #374151;
|
|
17314
|
+
}
|
|
17315
|
+
|
|
17316
|
+
.myio-select, .myio-input {
|
|
17317
|
+
padding: 10px 12px;
|
|
17318
|
+
border: 1px solid #d1d5db;
|
|
17319
|
+
border-radius: 6px;
|
|
17320
|
+
font-size: 14px;
|
|
17321
|
+
background: white;
|
|
17322
|
+
color: #1f2937;
|
|
17323
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
17324
|
+
}
|
|
17325
|
+
|
|
17326
|
+
.myio-select:focus, .myio-input:focus {
|
|
17327
|
+
outline: none;
|
|
17328
|
+
border-color: ${primaryColor};
|
|
17329
|
+
box-shadow: 0 0 0 3px ${this.hexToRgba(primaryColor, 0.1)};
|
|
17330
|
+
}
|
|
17331
|
+
|
|
17332
|
+
.myio-power-limits-grid {
|
|
17333
|
+
display: grid;
|
|
17334
|
+
grid-template-columns: repeat(2, 1fr);
|
|
17335
|
+
gap: 16px;
|
|
17336
|
+
padding: 24px;
|
|
17337
|
+
transition: opacity 0.3s;
|
|
17338
|
+
}
|
|
17339
|
+
|
|
17340
|
+
.myio-power-limits-card-item {
|
|
17341
|
+
background: var(--status-bg);
|
|
17342
|
+
border: 1px solid var(--status-color);
|
|
17343
|
+
border-radius: 8px;
|
|
17344
|
+
padding: 16px;
|
|
17345
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
17346
|
+
}
|
|
17347
|
+
|
|
17348
|
+
.myio-power-limits-card-item:hover {
|
|
17349
|
+
transform: translateY(-2px);
|
|
17350
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
17351
|
+
}
|
|
17352
|
+
|
|
17353
|
+
.myio-card-header {
|
|
17354
|
+
display: flex;
|
|
17355
|
+
align-items: center;
|
|
17356
|
+
gap: 8px;
|
|
17357
|
+
margin-bottom: 12px;
|
|
17358
|
+
}
|
|
17359
|
+
|
|
17360
|
+
.myio-status-indicator {
|
|
17361
|
+
width: 12px;
|
|
17362
|
+
height: 12px;
|
|
17363
|
+
border-radius: 50%;
|
|
17364
|
+
background: var(--status-color);
|
|
17365
|
+
}
|
|
17366
|
+
|
|
17367
|
+
.myio-status-label {
|
|
17368
|
+
font-weight: 600;
|
|
17369
|
+
font-size: 14px;
|
|
17370
|
+
color: #1f2937;
|
|
17371
|
+
}
|
|
17372
|
+
|
|
17373
|
+
.myio-card-inputs {
|
|
17374
|
+
display: grid;
|
|
17375
|
+
grid-template-columns: 1fr 1fr;
|
|
17376
|
+
gap: 12px;
|
|
17377
|
+
}
|
|
17378
|
+
|
|
17379
|
+
.myio-input-group {
|
|
17380
|
+
display: flex;
|
|
17381
|
+
flex-direction: column;
|
|
17382
|
+
gap: 4px;
|
|
17383
|
+
}
|
|
17384
|
+
|
|
17385
|
+
.myio-input-group label {
|
|
17386
|
+
font-size: 11px;
|
|
17387
|
+
font-weight: 500;
|
|
17388
|
+
color: #6b7280;
|
|
17389
|
+
text-transform: uppercase;
|
|
17390
|
+
}
|
|
17391
|
+
|
|
17392
|
+
.myio-power-limits-loading,
|
|
17393
|
+
.myio-power-limits-error,
|
|
17394
|
+
.myio-power-limits-success {
|
|
17395
|
+
display: flex;
|
|
17396
|
+
align-items: center;
|
|
17397
|
+
justify-content: center;
|
|
17398
|
+
gap: 12px;
|
|
17399
|
+
padding: 16px 24px;
|
|
17400
|
+
margin: 0 24px 24px;
|
|
17401
|
+
border-radius: 8px;
|
|
17402
|
+
}
|
|
17403
|
+
|
|
17404
|
+
.myio-power-limits-loading {
|
|
17405
|
+
background: #f3f4f6;
|
|
17406
|
+
color: #6b7280;
|
|
17407
|
+
}
|
|
17408
|
+
|
|
17409
|
+
.myio-power-limits-error {
|
|
17410
|
+
background: #fef2f2;
|
|
17411
|
+
color: ${dangerColor};
|
|
17412
|
+
border: 1px solid ${dangerColor};
|
|
17413
|
+
}
|
|
17414
|
+
|
|
17415
|
+
.myio-power-limits-success {
|
|
17416
|
+
background: #f0fdf4;
|
|
17417
|
+
color: ${successColor};
|
|
17418
|
+
border: 1px solid ${successColor};
|
|
17419
|
+
}
|
|
17420
|
+
|
|
17421
|
+
.myio-spinner {
|
|
17422
|
+
width: 24px;
|
|
17423
|
+
height: 24px;
|
|
17424
|
+
border: 3px solid #e5e7eb;
|
|
17425
|
+
border-top-color: ${primaryColor};
|
|
17426
|
+
border-radius: 50%;
|
|
17427
|
+
animation: spin 0.8s linear infinite;
|
|
17428
|
+
}
|
|
17429
|
+
|
|
17430
|
+
.myio-error-icon, .myio-success-icon {
|
|
17431
|
+
font-size: 20px;
|
|
17432
|
+
}
|
|
17433
|
+
|
|
17434
|
+
@media (max-width: 600px) {
|
|
17435
|
+
.myio-power-limits-selectors,
|
|
17436
|
+
.myio-power-limits-grid {
|
|
17437
|
+
grid-template-columns: 1fr;
|
|
17438
|
+
}
|
|
17439
|
+
|
|
17440
|
+
.myio-power-limits-header {
|
|
17441
|
+
flex-direction: column;
|
|
17442
|
+
gap: 12px;
|
|
17443
|
+
text-align: center;
|
|
17444
|
+
}
|
|
17445
|
+
|
|
17446
|
+
.myio-power-limits-actions {
|
|
17447
|
+
width: 100%;
|
|
17448
|
+
justify-content: center;
|
|
17449
|
+
}
|
|
17450
|
+
}
|
|
17451
|
+
`;
|
|
17452
|
+
}
|
|
17453
|
+
lightenColor(hex, percent) {
|
|
17454
|
+
const num = parseInt(hex.replace("#", ""), 16);
|
|
17455
|
+
const amt = Math.round(2.55 * percent);
|
|
17456
|
+
const R = (num >> 16) + amt;
|
|
17457
|
+
const G = (num >> 8 & 255) + amt;
|
|
17458
|
+
const B = (num & 255) + amt;
|
|
17459
|
+
return "#" + (16777216 + (R < 255 ? R < 1 ? 0 : R : 255) * 65536 + (G < 255 ? G < 1 ? 0 : G : 255) * 256 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
|
|
17460
|
+
}
|
|
17461
|
+
hexToRgba(hex, alpha) {
|
|
17462
|
+
const num = parseInt(hex.replace("#", ""), 16);
|
|
17463
|
+
const R = num >> 16;
|
|
17464
|
+
const G = num >> 8 & 255;
|
|
17465
|
+
const B = num & 255;
|
|
17466
|
+
return `rgba(${R}, ${G}, ${B}, ${alpha})`;
|
|
17467
|
+
}
|
|
17468
|
+
};
|
|
17469
|
+
|
|
17470
|
+
// src/components/premium-modals/power-limits/PowerLimitsPersister.ts
|
|
17471
|
+
var PowerLimitsPersister = class {
|
|
17472
|
+
jwtToken;
|
|
17473
|
+
tbBaseUrl;
|
|
17474
|
+
constructor(jwtToken, tbBaseUrl) {
|
|
17475
|
+
this.jwtToken = jwtToken;
|
|
17476
|
+
this.tbBaseUrl = tbBaseUrl || window.location.origin;
|
|
17477
|
+
}
|
|
17478
|
+
/**
|
|
17479
|
+
* Load existing mapInstantaneousPower from customer server_scope attributes
|
|
17480
|
+
*/
|
|
17481
|
+
async loadCustomerPowerLimits(customerId) {
|
|
17482
|
+
try {
|
|
17483
|
+
const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/values/attributes/SERVER_SCOPE?keys=mapInstantaneousPower`;
|
|
17484
|
+
const response = await fetch(url, {
|
|
17485
|
+
method: "GET",
|
|
17486
|
+
headers: {
|
|
17487
|
+
"X-Authorization": `Bearer ${this.jwtToken}`,
|
|
17488
|
+
"Content-Type": "application/json"
|
|
17489
|
+
}
|
|
17490
|
+
});
|
|
17491
|
+
if (!response.ok) {
|
|
17492
|
+
if (response.status === 404) {
|
|
17493
|
+
console.log("[PowerLimitsPersister] No existing mapInstantaneousPower found");
|
|
17494
|
+
return null;
|
|
17495
|
+
}
|
|
17496
|
+
throw this.createHttpError(response.status, await response.text().catch(() => ""));
|
|
17497
|
+
}
|
|
17498
|
+
const data = await response.json();
|
|
17499
|
+
if (!data || data.length === 0) {
|
|
17500
|
+
console.log("[PowerLimitsPersister] No mapInstantaneousPower attribute found");
|
|
17501
|
+
return null;
|
|
17502
|
+
}
|
|
17503
|
+
const attr = data.find((item) => item.key === "mapInstantaneousPower");
|
|
17504
|
+
if (!attr || !attr.value) {
|
|
17505
|
+
return null;
|
|
17506
|
+
}
|
|
17507
|
+
const parsedValue = typeof attr.value === "string" ? JSON.parse(attr.value) : attr.value;
|
|
17508
|
+
console.log("[PowerLimitsPersister] Loaded mapInstantaneousPower:", parsedValue);
|
|
17509
|
+
return parsedValue;
|
|
17510
|
+
} catch (error) {
|
|
17511
|
+
console.error("[PowerLimitsPersister] Error loading power limits:", error);
|
|
17512
|
+
throw this.mapError(error);
|
|
17513
|
+
}
|
|
17514
|
+
}
|
|
17515
|
+
/**
|
|
17516
|
+
* Save mapInstantaneousPower to customer server_scope attributes
|
|
17517
|
+
*/
|
|
17518
|
+
async saveCustomerPowerLimits(customerId, limits) {
|
|
17519
|
+
try {
|
|
17520
|
+
const url = `${this.tbBaseUrl}/api/plugins/telemetry/CUSTOMER/${customerId}/attributes/SERVER_SCOPE`;
|
|
17521
|
+
const payload = {
|
|
17522
|
+
mapInstantaneousPower: limits
|
|
17523
|
+
};
|
|
17524
|
+
console.log("[PowerLimitsPersister] Saving power limits:", payload);
|
|
17525
|
+
const response = await fetch(url, {
|
|
17526
|
+
method: "POST",
|
|
17527
|
+
headers: {
|
|
17528
|
+
"X-Authorization": `Bearer ${this.jwtToken}`,
|
|
17529
|
+
"Content-Type": "application/json"
|
|
17530
|
+
},
|
|
17531
|
+
body: JSON.stringify(payload)
|
|
17532
|
+
});
|
|
17533
|
+
if (!response.ok) {
|
|
17534
|
+
throw this.createHttpError(response.status, await response.text().catch(() => ""));
|
|
17535
|
+
}
|
|
17536
|
+
console.log("[PowerLimitsPersister] Successfully saved power limits");
|
|
17537
|
+
return { ok: true };
|
|
17538
|
+
} catch (error) {
|
|
17539
|
+
console.error("[PowerLimitsPersister] Error saving power limits:", error);
|
|
17540
|
+
return { ok: false, error: this.mapError(error) };
|
|
17541
|
+
}
|
|
17542
|
+
}
|
|
17543
|
+
/**
|
|
17544
|
+
* Extract form data for a specific device type and telemetry type
|
|
17545
|
+
*/
|
|
17546
|
+
extractFormData(limits, deviceType, telemetryType) {
|
|
17547
|
+
const defaultFormData = {
|
|
17548
|
+
deviceType,
|
|
17549
|
+
telemetryType,
|
|
17550
|
+
standby: { baseValue: null, topValue: null },
|
|
17551
|
+
normal: { baseValue: null, topValue: null },
|
|
17552
|
+
alert: { baseValue: null, topValue: null },
|
|
17553
|
+
failure: { baseValue: null, topValue: null }
|
|
17554
|
+
};
|
|
17555
|
+
if (!limits || !limits.limitsByInstantaneoustPowerType) {
|
|
17556
|
+
return defaultFormData;
|
|
17557
|
+
}
|
|
17558
|
+
const telemetryEntry = limits.limitsByInstantaneoustPowerType.find(
|
|
17559
|
+
(t) => t.telemetryType === telemetryType
|
|
17560
|
+
);
|
|
17561
|
+
if (!telemetryEntry || !telemetryEntry.itemsByDeviceType) {
|
|
17562
|
+
return defaultFormData;
|
|
17563
|
+
}
|
|
17564
|
+
const deviceEntry = telemetryEntry.itemsByDeviceType.find(
|
|
17565
|
+
(d) => d.deviceType === deviceType
|
|
17566
|
+
);
|
|
17567
|
+
if (!deviceEntry || !deviceEntry.limitsByDeviceStatus) {
|
|
17568
|
+
return defaultFormData;
|
|
17569
|
+
}
|
|
17570
|
+
const statusMap = {
|
|
17571
|
+
"standBy": "standby",
|
|
17572
|
+
"normal": "normal",
|
|
17573
|
+
"alert": "alert",
|
|
17574
|
+
"failure": "failure"
|
|
17575
|
+
};
|
|
17576
|
+
deviceEntry.limitsByDeviceStatus.forEach((status) => {
|
|
17577
|
+
const formKey = statusMap[status.deviceStatusName];
|
|
17578
|
+
if (formKey && defaultFormData[formKey]) {
|
|
17579
|
+
defaultFormData[formKey] = {
|
|
17580
|
+
baseValue: status.limitsValues.baseValue,
|
|
17581
|
+
topValue: status.limitsValues.topValue
|
|
17582
|
+
};
|
|
17583
|
+
}
|
|
17584
|
+
});
|
|
17585
|
+
return defaultFormData;
|
|
17586
|
+
}
|
|
17587
|
+
/**
|
|
17588
|
+
* Merge form data into existing limits JSON
|
|
17589
|
+
* Creates new entries if they don't exist
|
|
17590
|
+
*/
|
|
17591
|
+
mergeFormDataIntoLimits(existingLimits, formData) {
|
|
17592
|
+
const result = existingLimits ? JSON.parse(JSON.stringify(existingLimits)) : { version: "1.0.0", limitsByInstantaneoustPowerType: [] };
|
|
17593
|
+
const statusLimits = [
|
|
17594
|
+
{
|
|
17595
|
+
deviceStatusName: "standBy",
|
|
17596
|
+
limitsValues: {
|
|
17597
|
+
baseValue: formData.standby.baseValue ?? 0,
|
|
17598
|
+
topValue: formData.standby.topValue ?? 0
|
|
17599
|
+
}
|
|
17600
|
+
},
|
|
17601
|
+
{
|
|
17602
|
+
deviceStatusName: "normal",
|
|
17603
|
+
limitsValues: {
|
|
17604
|
+
baseValue: formData.normal.baseValue ?? 0,
|
|
17605
|
+
topValue: formData.normal.topValue ?? 0
|
|
17606
|
+
}
|
|
17607
|
+
},
|
|
17608
|
+
{
|
|
17609
|
+
deviceStatusName: "alert",
|
|
17610
|
+
limitsValues: {
|
|
17611
|
+
baseValue: formData.alert.baseValue ?? 0,
|
|
17612
|
+
topValue: formData.alert.topValue ?? 0
|
|
17613
|
+
}
|
|
17614
|
+
},
|
|
17615
|
+
{
|
|
17616
|
+
deviceStatusName: "failure",
|
|
17617
|
+
limitsValues: {
|
|
17618
|
+
baseValue: formData.failure.baseValue ?? 0,
|
|
17619
|
+
topValue: formData.failure.topValue ?? 0
|
|
17620
|
+
}
|
|
17621
|
+
}
|
|
17622
|
+
];
|
|
17623
|
+
let telemetryEntry = result.limitsByInstantaneoustPowerType.find(
|
|
17624
|
+
(t) => t.telemetryType === formData.telemetryType
|
|
17625
|
+
);
|
|
17626
|
+
if (!telemetryEntry) {
|
|
17627
|
+
telemetryEntry = {
|
|
17628
|
+
telemetryType: formData.telemetryType,
|
|
17629
|
+
itemsByDeviceType: []
|
|
17630
|
+
};
|
|
17631
|
+
result.limitsByInstantaneoustPowerType.push(telemetryEntry);
|
|
17632
|
+
}
|
|
17633
|
+
let deviceEntry = telemetryEntry.itemsByDeviceType.find(
|
|
17634
|
+
(d) => d.deviceType === formData.deviceType
|
|
17635
|
+
);
|
|
17636
|
+
if (!deviceEntry) {
|
|
17637
|
+
deviceEntry = {
|
|
17638
|
+
deviceType: formData.deviceType,
|
|
17639
|
+
name: `mapInstantaneousPower${this.formatDeviceTypeName(formData.deviceType)}`,
|
|
17640
|
+
description: `Power limits for ${formData.deviceType}`,
|
|
17641
|
+
limitsByDeviceStatus: []
|
|
17642
|
+
};
|
|
17643
|
+
telemetryEntry.itemsByDeviceType.push(deviceEntry);
|
|
17644
|
+
}
|
|
17645
|
+
deviceEntry.limitsByDeviceStatus = statusLimits;
|
|
17646
|
+
deviceEntry.name = `mapInstantaneousPower${this.formatDeviceTypeName(formData.deviceType)}`;
|
|
17647
|
+
deviceEntry.description = `Power limits for ${formData.deviceType} - ${formData.telemetryType}`;
|
|
17648
|
+
return result;
|
|
17649
|
+
}
|
|
17650
|
+
/**
|
|
17651
|
+
* Format device type name for the JSON name field
|
|
17652
|
+
*/
|
|
17653
|
+
formatDeviceTypeName(deviceType) {
|
|
17654
|
+
if (!deviceType) return "";
|
|
17655
|
+
return deviceType.toLowerCase().split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
17656
|
+
}
|
|
17657
|
+
createHttpError(status, body) {
|
|
17658
|
+
const error = new Error(`HTTP ${status}: ${body}`);
|
|
17659
|
+
error.status = status;
|
|
17660
|
+
error.body = body;
|
|
17661
|
+
return error;
|
|
17662
|
+
}
|
|
17663
|
+
mapError(error) {
|
|
17664
|
+
const status = error.status;
|
|
17665
|
+
if (status === 400) {
|
|
17666
|
+
return {
|
|
17667
|
+
code: "VALIDATION_ERROR",
|
|
17668
|
+
message: "Invalid input data",
|
|
17669
|
+
cause: error
|
|
17670
|
+
};
|
|
17671
|
+
}
|
|
17672
|
+
if (status === 401) {
|
|
17673
|
+
return {
|
|
17674
|
+
code: "TOKEN_EXPIRED",
|
|
17675
|
+
message: "Authentication token has expired",
|
|
17676
|
+
cause: error
|
|
17677
|
+
};
|
|
17678
|
+
}
|
|
17679
|
+
if (status === 403) {
|
|
17680
|
+
return {
|
|
17681
|
+
code: "AUTH_ERROR",
|
|
17682
|
+
message: "Insufficient permissions",
|
|
17683
|
+
cause: error
|
|
17684
|
+
};
|
|
17685
|
+
}
|
|
17686
|
+
if (status === 404) {
|
|
17687
|
+
return {
|
|
17688
|
+
code: "NETWORK_ERROR",
|
|
17689
|
+
message: "Customer not found",
|
|
17690
|
+
cause: error
|
|
17691
|
+
};
|
|
17692
|
+
}
|
|
17693
|
+
if (status >= 500) {
|
|
17694
|
+
return {
|
|
17695
|
+
code: "NETWORK_ERROR",
|
|
17696
|
+
message: "Server error occurred",
|
|
17697
|
+
cause: error
|
|
17698
|
+
};
|
|
17699
|
+
}
|
|
17700
|
+
return {
|
|
17701
|
+
code: "UNKNOWN_ERROR",
|
|
17702
|
+
message: error.message || "Unknown error occurred",
|
|
17703
|
+
cause: error
|
|
17704
|
+
};
|
|
17705
|
+
}
|
|
17706
|
+
};
|
|
17707
|
+
|
|
17708
|
+
// src/components/premium-modals/power-limits/openPowerLimitsSetupModal.ts
|
|
17709
|
+
async function openPowerLimitsSetupModal(params) {
|
|
17710
|
+
if (!params.token) {
|
|
17711
|
+
throw new Error("[PowerLimitsSetupModal] token is required");
|
|
17712
|
+
}
|
|
17713
|
+
if (!params.customerId) {
|
|
17714
|
+
throw new Error("[PowerLimitsSetupModal] customerId is required");
|
|
17715
|
+
}
|
|
17716
|
+
const persister = new PowerLimitsPersister(params.token, params.tbBaseUrl);
|
|
17717
|
+
let currentDeviceType = params.deviceType || "ELEVADOR";
|
|
17718
|
+
let currentTelemetryType = params.telemetryType || "consumption";
|
|
17719
|
+
let existingLimits = params.existingMapPower || null;
|
|
17720
|
+
const view = new PowerLimitsModalView({
|
|
17721
|
+
deviceType: currentDeviceType,
|
|
17722
|
+
telemetryType: currentTelemetryType,
|
|
17723
|
+
styles: params.styles,
|
|
17724
|
+
locale: params.locale,
|
|
17725
|
+
onDeviceTypeChange: async (deviceType) => {
|
|
17726
|
+
currentDeviceType = deviceType;
|
|
17727
|
+
await loadFormData();
|
|
17728
|
+
},
|
|
17729
|
+
onTelemetryTypeChange: async (telemetryType) => {
|
|
17730
|
+
currentTelemetryType = telemetryType;
|
|
17731
|
+
await loadFormData();
|
|
17732
|
+
},
|
|
17733
|
+
onSave: async () => {
|
|
17734
|
+
const formData = view.getFormData();
|
|
17735
|
+
const updatedLimits = persister.mergeFormDataIntoLimits(existingLimits, formData);
|
|
17736
|
+
const result = await persister.saveCustomerPowerLimits(params.customerId, updatedLimits);
|
|
17737
|
+
if (!result.ok) {
|
|
17738
|
+
throw new Error(result.error?.message || "Failed to save configuration");
|
|
17739
|
+
}
|
|
17740
|
+
existingLimits = updatedLimits;
|
|
17741
|
+
if (params.onSave) {
|
|
17742
|
+
params.onSave(updatedLimits);
|
|
17743
|
+
}
|
|
17744
|
+
},
|
|
17745
|
+
onClose: () => {
|
|
17746
|
+
if (params.onClose) {
|
|
17747
|
+
params.onClose();
|
|
17748
|
+
}
|
|
17749
|
+
}
|
|
17750
|
+
});
|
|
17751
|
+
async function loadFormData() {
|
|
17752
|
+
view.showLoading();
|
|
17753
|
+
try {
|
|
17754
|
+
if (!existingLimits) {
|
|
17755
|
+
existingLimits = await persister.loadCustomerPowerLimits(params.customerId);
|
|
17756
|
+
}
|
|
17757
|
+
const formData = persister.extractFormData(existingLimits, currentDeviceType, currentTelemetryType);
|
|
17758
|
+
view.setFormData(formData);
|
|
17759
|
+
} catch (error) {
|
|
17760
|
+
console.error("[PowerLimitsSetupModal] Error loading form data:", error);
|
|
17761
|
+
view.showError(error.message || "Failed to load configuration");
|
|
17762
|
+
} finally {
|
|
17763
|
+
view.hideLoading();
|
|
17764
|
+
}
|
|
17765
|
+
}
|
|
17766
|
+
let container;
|
|
17767
|
+
if (params.container) {
|
|
17768
|
+
if (typeof params.container === "string") {
|
|
17769
|
+
container = document.querySelector(params.container);
|
|
17770
|
+
} else {
|
|
17771
|
+
container = params.container;
|
|
17772
|
+
}
|
|
17773
|
+
}
|
|
17774
|
+
view.render(container);
|
|
17775
|
+
await loadFormData();
|
|
17776
|
+
return {
|
|
17777
|
+
destroy: () => view.destroy(),
|
|
17778
|
+
getFormData: () => view.getFormData(),
|
|
17779
|
+
setFormData: (data) => view.setFormData(data)
|
|
17780
|
+
};
|
|
17781
|
+
}
|
|
17782
|
+
|
|
16783
17783
|
// src/components/premium-modals/settings/SettingsModalView.ts
|
|
16784
17784
|
var SettingsModalView = class {
|
|
16785
17785
|
container;
|
|
@@ -27047,6 +28047,9 @@ function createDistributionChartWidget(config) {
|
|
|
27047
28047
|
MyIOSelectionStore,
|
|
27048
28048
|
MyIOSelectionStoreClass,
|
|
27049
28049
|
MyIOToast,
|
|
28050
|
+
POWER_LIMITS_DEVICE_TYPES,
|
|
28051
|
+
POWER_LIMITS_STATUS_CONFIG,
|
|
28052
|
+
POWER_LIMITS_TELEMETRY_TYPES,
|
|
27050
28053
|
addDetectionContext,
|
|
27051
28054
|
addNamespace,
|
|
27052
28055
|
aggregateByDay,
|
|
@@ -27144,6 +28147,7 @@ function createDistributionChartWidget(config) {
|
|
|
27144
28147
|
openDashboardPopupWaterTank,
|
|
27145
28148
|
openDemandModal,
|
|
27146
28149
|
openGoalsPanel,
|
|
28150
|
+
openPowerLimitsSetupModal,
|
|
27147
28151
|
openRealTimeTelemetryModal,
|
|
27148
28152
|
openTemperatureComparisonModal,
|
|
27149
28153
|
openTemperatureModal,
|