iobroker.javascript 9.1.0 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -8
- package/admin/assets/AiChatPanel-sgt697A2.js +296 -0
- package/admin/assets/AiDatapointProvider-B0i3I5Fm.js +2 -0
- package/admin/assets/AiDiffView-RPozjjHf.js +1 -0
- package/admin/assets/AiInlineProvider-Dd7eKxk4.js +7 -0
- package/admin/assets/{Save-Cld9qv9i.js → Save-CkuNSiWL.js} +1 -1
- package/admin/assets/{ScriptEditor-BVaX7Hcs.js → ScriptEditor-CH4qJzqq.js} +2 -2
- package/admin/assets/ScriptEditorVanillaMonaco-cB_90T0P.js +1 -0
- package/admin/assets/{createSvgIcon-DPvF8xqu.js → createSvgIcon-DYs_tNrE.js} +1 -1
- package/admin/assets/docs-compact-CKNGiYh2.js +336 -0
- package/admin/assets/index-BI3JsAz_.js +1 -0
- package/admin/assets/{index-D8iYqogF.js → index-DAkyON1r.js} +5 -5
- package/admin/assets/index-DW5CwIma.js +1256 -0
- package/admin/assets/index-SHs7_wDh.js +1 -0
- package/admin/assets/{index-DlDUIfpA.js → index-dN73sbyQ.js} +1 -1
- package/admin/assets/index-hwplVCgv.js +986 -0
- package/admin/assets/index-wHNMOf-c.js +5 -0
- package/admin/assets/inheritsLoose-CIXm_zPk.js +29 -0
- package/admin/assets/{iobroker_javascript__loadShare___mf_0_mui_mf_1_material__loadShare__.mjs-QWG5Arqe.js → iobroker_javascript__loadShare___mf_0_mui_mf_1_material__loadShare__.mjs-CV1_X-Lf.js} +1 -1
- package/admin/assets/{localSharedImportMap-AxgBkrOR.js → localSharedImportMap-CqvxvyGG.js} +1 -1
- package/admin/assets/useTheme-DuTJsNQ-.js +1 -0
- package/admin/assets/{virtual_mf-REMOTE_ENTRY_ID_iobroker_javascript__remoteEntry_js-C9suQF96.js → virtual_mf-REMOTE_ENTRY_ID_iobroker_javascript__remoteEntry_js-BJ03G6Pu.js} +2 -2
- package/admin/custom/assets/{Components-FfVbavBM.js → Components-B9ZyjeRI.js} +1 -1
- package/admin/custom/assets/{index-Be7j5wvd.js → index-BVwMgafs.js} +1 -1
- package/admin/custom/assets/index-CVIpIckw.js +960 -0
- package/admin/custom/assets/{index-DNdWk-cT.js → index-DsIn9jH_.js} +1 -1
- package/admin/custom/assets/{localSharedImportMap-BRxFonIn.js → localSharedImportMap-C4qXtGUd.js} +1 -1
- package/admin/custom/assets/{virtualExposes-DyedJotb.js → virtualExposes-jSvr-kK3.js} +1 -1
- package/admin/custom/assets/{virtual_mf-REMOTE_ENTRY_ID_ConfigCustomJavascriptSet__customComponents_js-BtJxKB87.js → virtual_mf-REMOTE_ENTRY_ID_ConfigCustomJavascriptSet__customComponents_js-DFSXB0v2.js} +2 -2
- package/admin/custom/customComponents.js +1 -1
- package/admin/google-blockly/own/blocks_words.js +7 -0
- package/admin/google-blockly/own/field_oid.js +311 -37
- package/admin/i18n/de.json +8 -0
- package/admin/i18n/en.json +8 -0
- package/admin/i18n/es.json +8 -0
- package/admin/i18n/flat.txt +427 -0
- package/admin/i18n/fr.json +8 -0
- package/admin/i18n/it.json +8 -0
- package/admin/i18n/nl.json +8 -0
- package/admin/i18n/pl.json +8 -0
- package/admin/i18n/pt.json +8 -0
- package/admin/i18n/ru.json +8 -0
- package/admin/i18n/uk.json +8 -0
- package/admin/i18n/zh-cn.json +8 -0
- package/admin/img/anthropic.svg +1 -0
- package/admin/img/custom.svg +1 -0
- package/admin/img/deepseek.svg +1 -0
- package/admin/img/gemini.svg +1 -0
- package/admin/img/openai.svg +1 -0
- package/admin/jsonConfig.json +76 -14
- package/admin/mf-manifest.json +1 -1
- package/admin/remoteEntry.js +1 -1
- package/admin/tab.html +6 -6
- package/build/lib/debugger.js +2 -2
- package/build/lib/debugger.js.map +1 -1
- package/build/lib/inspect.js.map +1 -1
- package/build/lib/nodeModulesManagement.js +2 -2
- package/build/lib/nodeModulesManagement.js.map +1 -1
- package/build/lib/protectFs.js +5 -0
- package/build/lib/protectFs.js.map +1 -1
- package/build/lib/sandbox.js +2 -2
- package/build/lib/sandbox.js.map +1 -1
- package/build/main.js +72 -17
- package/build/main.js.map +1 -1
- package/build/types.d.ts +2 -0
- package/docs/de/README.md +21 -8
- package/docs/de/blockly.md +34 -0
- package/docs/en/README.md +21 -8
- package/docs/en/blockly.md +34 -0
- package/install/installTypings.js +1 -1
- package/io-package.json +27 -66
- package/package.json +7 -6
- package/admin/assets/OpenAiDialog-Dx-XNET0.js +0 -13
- package/admin/assets/ScriptEditorVanillaMonaco-yq11eIYC.js +0 -1
- package/admin/assets/docs-BrInh2Pn.js +0 -2036
- package/admin/assets/index-CLJ6-h9Q.js +0 -1
- package/admin/assets/index-COZhHfBn.js +0 -1230
- package/admin/assets/index-Cu-TydZj.js +0 -5
- package/admin/assets/index-Dnbw7_L3.js +0 -986
- package/admin/assets/index-gIA8x-8f.js +0 -1
- package/admin/assets/inheritsLoose-B0Ba5G9z.js +0 -29
- package/admin/assets/useTheme-hy6f3gra.js +0 -1
- package/admin/custom/assets/index-CYc31Gwg.js +0 -960
|
@@ -19,6 +19,7 @@ class FieldOID extends Blockly.Field {
|
|
|
19
19
|
this.CURSOR = 'pointer';
|
|
20
20
|
this.SERIALIZABLE = true;
|
|
21
21
|
this.spellcheck_ = false;
|
|
22
|
+
this.maxDisplayLength = 200;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
dispose() {
|
|
@@ -26,6 +27,235 @@ class FieldOID extends Blockly.Field {
|
|
|
26
27
|
super.dispose();
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
initView() {
|
|
31
|
+
super.initView();
|
|
32
|
+
const id = this.getValue();
|
|
33
|
+
if (id) {
|
|
34
|
+
this.updateIcon_(id);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static _resolveObjectName(id) {
|
|
39
|
+
const objects = window.main.objects;
|
|
40
|
+
if (!objects || !objects[id] || !objects[id].common || !objects[id].common.name) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
let name = objects[id].common.name;
|
|
44
|
+
if (typeof name === 'object') {
|
|
45
|
+
name = name[systemLang] || name.en;
|
|
46
|
+
}
|
|
47
|
+
return name || null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static computeDisplayText(id, maxLen) {
|
|
51
|
+
const mode = FieldOID.displayMode;
|
|
52
|
+
const objects = window.main.objects;
|
|
53
|
+
let text;
|
|
54
|
+
|
|
55
|
+
switch (mode) {
|
|
56
|
+
case 1: { // Path: all parent names joined with "."
|
|
57
|
+
const parts = id.split('.');
|
|
58
|
+
const names = [];
|
|
59
|
+
for (let i = 0; i < parts.length; i++) {
|
|
60
|
+
const ancestorId = parts.slice(0, i + 1).join('.');
|
|
61
|
+
const name = FieldOID._resolveObjectName(ancestorId);
|
|
62
|
+
names.push(name || parts[i]);
|
|
63
|
+
}
|
|
64
|
+
text = names.join('.');
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case 2: // State ID: last segment only
|
|
68
|
+
text = id.split('.').pop() || id;
|
|
69
|
+
break;
|
|
70
|
+
case 3: // Full ID
|
|
71
|
+
text = id;
|
|
72
|
+
break;
|
|
73
|
+
default: { // Mode 0: Name (current behavior)
|
|
74
|
+
text = FieldOID._resolveObjectName(id) || id;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Append type suffix for non-state objects
|
|
80
|
+
if (objects && objects[id]?.type && !['state', 'meta', 'script'].includes(objects[id].type)) {
|
|
81
|
+
text += ` (${objects[id].type})`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (maxLen && text.length > maxLen) {
|
|
85
|
+
text = text.substring(0, maxLen - 2) + '\u2026';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
|
|
89
|
+
text = text.replace(/\s/g, Blockly.Field.NBSP);
|
|
90
|
+
|
|
91
|
+
return text || Blockly.Field.NBSP;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
refreshDisplay() {
|
|
95
|
+
const id = this.getValue();
|
|
96
|
+
if (id) {
|
|
97
|
+
this._idName = FieldOID.computeDisplayText(id, this.maxDisplayLength);
|
|
98
|
+
this.updateIcon_(id);
|
|
99
|
+
this.forceRerender();
|
|
100
|
+
// For path mode, async-fetch parent objects to resolve names
|
|
101
|
+
if (FieldOID.displayMode === 1) {
|
|
102
|
+
this._resolvePathNamesAsync(id);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_resolvePathNamesAsync(id) {
|
|
108
|
+
if (typeof window.main.getObject !== 'function') return;
|
|
109
|
+
const objects = window.main.objects;
|
|
110
|
+
const parts = id.split('.');
|
|
111
|
+
let pending = 0;
|
|
112
|
+
let updated = false;
|
|
113
|
+
for (let i = 0; i < parts.length; i++) {
|
|
114
|
+
const ancestorId = parts.slice(0, i + 1).join('.');
|
|
115
|
+
if (objects[ancestorId]) continue; // already cached
|
|
116
|
+
pending++;
|
|
117
|
+
window.main.getObject(ancestorId, (err, obj) => {
|
|
118
|
+
if (obj) {
|
|
119
|
+
objects[obj._id] = objects[obj._id] || obj;
|
|
120
|
+
updated = true;
|
|
121
|
+
}
|
|
122
|
+
pending--;
|
|
123
|
+
if (pending === 0 && updated) {
|
|
124
|
+
this._idName = FieldOID.computeDisplayText(id, this.maxDisplayLength);
|
|
125
|
+
this.forceRerender();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
_getIconOffset() {
|
|
132
|
+
return (FieldOID.showIcon && this._iconElement) ? 20 : 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Override Blockly's size + position to account for icon
|
|
136
|
+
updateSize_(margin) {
|
|
137
|
+
const constants = this.getConstants();
|
|
138
|
+
const xPad = margin !== undefined ? margin :
|
|
139
|
+
(this.isFullBlockField() ? 0 : constants.FIELD_BORDER_RECT_X_PADDING);
|
|
140
|
+
const iconOffset = this._getIconOffset();
|
|
141
|
+
|
|
142
|
+
let textWidth = 0;
|
|
143
|
+
if (this.textElement_) {
|
|
144
|
+
textWidth = this.textElement_.getComputedTextLength();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let totalWidth = 2 * xPad + textWidth + iconOffset;
|
|
148
|
+
let totalHeight = constants.FIELD_TEXT_HEIGHT;
|
|
149
|
+
if (!this.isFullBlockField()) {
|
|
150
|
+
totalHeight = Math.max(totalHeight, constants.FIELD_BORDER_RECT_HEIGHT);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.size_.height = totalHeight;
|
|
154
|
+
this.size_.width = totalWidth;
|
|
155
|
+
|
|
156
|
+
this.positionTextElement_(xPad + iconOffset, textWidth);
|
|
157
|
+
this.positionBorderRect_();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
updateIcon_(id) {
|
|
161
|
+
if (!this.fieldGroup_) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (!FieldOID.showIcon) {
|
|
165
|
+
if (this._iconElement) {
|
|
166
|
+
this._iconElement.remove();
|
|
167
|
+
this._iconElement = null;
|
|
168
|
+
this._iconUrl = null;
|
|
169
|
+
}
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// First try synchronous resolve with cached objects
|
|
173
|
+
const iconUrl = FieldOID.resolveIcon(id);
|
|
174
|
+
if (iconUrl) {
|
|
175
|
+
this._applyIcon(iconUrl);
|
|
176
|
+
}
|
|
177
|
+
// Then async-fetch parent objects to find a closer (more specific) icon
|
|
178
|
+
this._resolveIconAsync(id);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
_applyIcon(iconUrl) {
|
|
182
|
+
if (!this.fieldGroup_) return;
|
|
183
|
+
if (this._iconUrl === iconUrl && this._iconElement) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
this._iconUrl = iconUrl;
|
|
187
|
+
const iconSize = 16;
|
|
188
|
+
if (!this._iconElement) {
|
|
189
|
+
this._iconElement = document.createElementNS('http://www.w3.org/2000/svg', 'image');
|
|
190
|
+
this._iconElement.setAttribute('width', String(iconSize));
|
|
191
|
+
this._iconElement.setAttribute('height', String(iconSize));
|
|
192
|
+
if (this.textElement_) {
|
|
193
|
+
this.fieldGroup_.insertBefore(this._iconElement, this.textElement_);
|
|
194
|
+
} else {
|
|
195
|
+
this.fieldGroup_.appendChild(this._iconElement);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
this._iconElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', iconUrl);
|
|
199
|
+
this._positionIcon();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
_positionIcon() {
|
|
203
|
+
if (!this._iconElement || !this.textElement_) return;
|
|
204
|
+
const iconSize = 16;
|
|
205
|
+
try {
|
|
206
|
+
// Position icon at the start of the field content area
|
|
207
|
+
const constants = this.getConstants();
|
|
208
|
+
const xPad = this.borderRect_ ? constants.FIELD_BORDER_RECT_X_PADDING : 0;
|
|
209
|
+
this._iconElement.setAttribute('x', String(xPad + 2));
|
|
210
|
+
|
|
211
|
+
// Vertically center icon with text
|
|
212
|
+
const textBBox = this.textElement_.getBBox();
|
|
213
|
+
if (textBBox.height > 0) {
|
|
214
|
+
const textMidY = textBBox.y + textBBox.height / 2;
|
|
215
|
+
this._iconElement.setAttribute('y', String(textMidY - iconSize / 2));
|
|
216
|
+
}
|
|
217
|
+
} catch (e) {
|
|
218
|
+
// getBBox can fail if element is not in DOM yet
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
_resolveIconAsync(id) {
|
|
223
|
+
if (!FieldOID.showIcon || typeof window.main.getObject !== 'function') {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const objects = window.main.objects;
|
|
227
|
+
const parts = id.split('.');
|
|
228
|
+
const adapterName = parts[0];
|
|
229
|
+
// Fetch ancestors from state level up to adapter instance level
|
|
230
|
+
// Start from the state itself, go up - first icon found wins
|
|
231
|
+
let remaining = parts.length;
|
|
232
|
+
const tryNext = (idx) => {
|
|
233
|
+
if (idx < 1) return;
|
|
234
|
+
const ancestorId = parts.slice(0, idx).join('.');
|
|
235
|
+
// Already in cache?
|
|
236
|
+
if (objects[ancestorId]) {
|
|
237
|
+
if (objects[ancestorId].common && objects[ancestorId].common.icon) {
|
|
238
|
+
this._applyIcon(FieldOID._buildIconUrl(objects[ancestorId].common.icon, adapterName));
|
|
239
|
+
return; // Found closest icon, stop
|
|
240
|
+
}
|
|
241
|
+
tryNext(idx - 1); // No icon here, try parent
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
// Fetch this ancestor
|
|
245
|
+
window.main.getObject(ancestorId, (err, obj) => {
|
|
246
|
+
if (obj) {
|
|
247
|
+
objects[obj._id] = objects[obj._id] || obj;
|
|
248
|
+
if (obj.common && obj.common.icon) {
|
|
249
|
+
this._applyIcon(FieldOID._buildIconUrl(obj.common.icon, adapterName));
|
|
250
|
+
return; // Found closest icon, stop
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
tryNext(idx - 1); // Try parent
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
tryNext(remaining);
|
|
257
|
+
}
|
|
258
|
+
|
|
29
259
|
setValue(id) {
|
|
30
260
|
if (id === null) {
|
|
31
261
|
return; // No change if null.
|
|
@@ -38,50 +268,26 @@ class FieldOID extends Blockly.Field {
|
|
|
38
268
|
window.main.getObject(id, (err, obj) => {
|
|
39
269
|
if (obj) {
|
|
40
270
|
objects[obj._id] = objects[obj._id] || obj;
|
|
41
|
-
|
|
271
|
+
const text = FieldOID.computeDisplayText(id, this.maxDisplayLength);
|
|
42
272
|
if (text) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
if (objects && objects[id] && objects[id]?.type && !['state', 'meta', 'script'].includes(objects[id].type)) {
|
|
51
|
-
text += ` (${objects[id].type})`;
|
|
52
|
-
}
|
|
53
|
-
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
|
|
54
|
-
text = text.replace(/\s/g, Blockly.Field.NBSP);
|
|
55
|
-
|
|
56
|
-
if (text) {
|
|
57
|
-
this._idName = text;
|
|
58
|
-
this.forceRerender();
|
|
59
|
-
}
|
|
273
|
+
this._idName = text;
|
|
274
|
+
this.forceRerender();
|
|
275
|
+
}
|
|
276
|
+
// Resolve parent names for path mode
|
|
277
|
+
if (FieldOID.displayMode === 1) {
|
|
278
|
+
this._resolvePathNamesAsync(id);
|
|
60
279
|
}
|
|
61
280
|
}
|
|
62
281
|
});
|
|
63
282
|
} else {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
283
|
+
this._idName = FieldOID.computeDisplayText(id, this.maxDisplayLength);
|
|
284
|
+
// Resolve parent names for path mode
|
|
285
|
+
if (FieldOID.displayMode === 1) {
|
|
286
|
+
this._resolvePathNamesAsync(id);
|
|
67
287
|
}
|
|
68
|
-
if (text.length > this.maxDisplayLength) {
|
|
69
|
-
// Truncate the displayed string and add an ellipsis ('...').
|
|
70
|
-
text = text.substring(0, this.maxDisplayLength - 2) + '\u2026';
|
|
71
|
-
}
|
|
72
|
-
if (objects && objects[id] && objects[id]?.type && !['state', 'meta', 'script'].includes(objects[id].type)) {
|
|
73
|
-
text += ` (${objects[id].type})`;
|
|
74
|
-
}
|
|
75
|
-
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
|
|
76
|
-
text = text.replace(/\s/g, Blockly.Field.NBSP);
|
|
77
|
-
|
|
78
|
-
if (!text) {
|
|
79
|
-
// Prevent the field from disappearing if empty.
|
|
80
|
-
text = Blockly.Field.NBSP;
|
|
81
|
-
}
|
|
82
|
-
this._idName = text;
|
|
83
288
|
}
|
|
84
289
|
|
|
290
|
+
this.updateIcon_(id);
|
|
85
291
|
super.setValue(id);
|
|
86
292
|
super.setTooltip(id);
|
|
87
293
|
}
|
|
@@ -98,7 +304,6 @@ class FieldOID extends Blockly.Field {
|
|
|
98
304
|
}
|
|
99
305
|
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
|
|
100
306
|
text = text.replace(/\s/g, Blockly.Field.NBSP);
|
|
101
|
-
|
|
102
307
|
if (this.sourceBlock_.RTL) {
|
|
103
308
|
// The SVG is LTR, force text to be RTL.
|
|
104
309
|
text += '\u200F';
|
|
@@ -214,6 +419,75 @@ class FieldOID extends Blockly.Field {
|
|
|
214
419
|
}
|
|
215
420
|
}
|
|
216
421
|
|
|
422
|
+
FieldOID.DISPLAY_MODE_KEYS = ['oid_display_name', 'oid_display_path', 'oid_display_id', 'oid_display_full_id'];
|
|
423
|
+
FieldOID.displayMode = parseInt(localStorage.getItem('Blockly.FieldOID.displayMode') || '0', 10) || 0;
|
|
424
|
+
FieldOID.showIcon = localStorage.getItem('Blockly.FieldOID.showIcon') === 'true';
|
|
425
|
+
|
|
426
|
+
FieldOID._buildIconUrl = function (icon, adapterName) {
|
|
427
|
+
if (!icon) return null;
|
|
428
|
+
// base64 data URIs and absolute URLs are used as-is
|
|
429
|
+
if (icon.startsWith('data:') || icon.startsWith('http://') || icon.startsWith('https://') || icon.startsWith('/')) {
|
|
430
|
+
return icon;
|
|
431
|
+
}
|
|
432
|
+
return '/adapter/' + adapterName + '/' + icon;
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
FieldOID.resolveIcon = function (id) {
|
|
436
|
+
const objects = window.main.objects;
|
|
437
|
+
if (!objects) return null;
|
|
438
|
+
const parts = id.split('.');
|
|
439
|
+
const adapterName = parts[0];
|
|
440
|
+
// Walk up the object hierarchy looking for common.icon
|
|
441
|
+
for (let i = parts.length; i >= 1; i--) {
|
|
442
|
+
const ancestorId = parts.slice(0, i).join('.');
|
|
443
|
+
const obj = objects[ancestorId];
|
|
444
|
+
if (obj && obj.common && obj.common.icon) {
|
|
445
|
+
return FieldOID._buildIconUrl(obj.common.icon, adapterName);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
// Fallback: check system.adapter.{adapterName}.{instance} (e.g. system.adapter.zigbee2mqtt.0)
|
|
449
|
+
if (parts.length >= 2) {
|
|
450
|
+
const instanceId = 'system.adapter.' + parts[0] + '.' + parts[1];
|
|
451
|
+
const sysInstance = objects[instanceId];
|
|
452
|
+
if (sysInstance && sysInstance.common && sysInstance.common.icon) {
|
|
453
|
+
return FieldOID._buildIconUrl(sysInstance.common.icon, adapterName);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return null;
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
FieldOID.setDisplayMode = function (mode, workspace) {
|
|
460
|
+
FieldOID.displayMode = mode;
|
|
461
|
+
localStorage.setItem('Blockly.FieldOID.displayMode', String(mode));
|
|
462
|
+
|
|
463
|
+
const blocks = workspace.getAllBlocks(false);
|
|
464
|
+
for (const block of blocks) {
|
|
465
|
+
for (const input of block.inputList) {
|
|
466
|
+
for (const field of input.fieldRow) {
|
|
467
|
+
if (field instanceof FieldOID) {
|
|
468
|
+
field.refreshDisplay();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
FieldOID.setShowIcon = function (show, workspace) {
|
|
476
|
+
FieldOID.showIcon = show;
|
|
477
|
+
localStorage.setItem('Blockly.FieldOID.showIcon', String(show));
|
|
478
|
+
|
|
479
|
+
const blocks = workspace.getAllBlocks(false);
|
|
480
|
+
for (const block of blocks) {
|
|
481
|
+
for (const input of block.inputList) {
|
|
482
|
+
for (const field of input.fieldRow) {
|
|
483
|
+
if (field instanceof FieldOID) {
|
|
484
|
+
field.refreshDisplay();
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
|
|
217
491
|
Blockly.FieldOID = FieldOID;
|
|
218
492
|
|
|
219
493
|
//Blockly.Field.register('field_oid', FieldOID);
|
package/admin/i18n/de.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"Maximum setState requests per Minute per Script": "Maximale setState-Anfragen pro Minute pro Skript",
|
|
22
22
|
"Maximum triggers per Script (until warning)": "Maximale Auslöser/Trigger pro Skript (bis zur Warnung)",
|
|
23
23
|
"Mirror scripts to file path": "Spiegeln von Skripten in den Dateipfad",
|
|
24
|
+
"Sort global scripts alphabetically": "Globale Skripte alphabetisch sortieren",
|
|
24
25
|
"Module names": "NPM-Modulnamen",
|
|
25
26
|
"Next sunrise": "Nächster Tagesbeginn:",
|
|
26
27
|
"Next sunset": "Nächstes Tagesende:",
|
|
@@ -61,6 +62,13 @@
|
|
|
61
62
|
"Custom API Base URL": "Eigene API Base-URL (z.B. für Ollama, LM Studio)",
|
|
62
63
|
"Custom API Base URL help": "Leer lassen für OpenAI. Für Ollama: http://localhost:11434/v1",
|
|
63
64
|
"Test API connection": "API-Verbindung testen",
|
|
65
|
+
"Test OpenAI": "OpenAI testen",
|
|
66
|
+
"Test Anthropic": "Anthropic testen",
|
|
67
|
+
"Test Gemini": "Gemini testen",
|
|
68
|
+
"Test DeepSeek": "DeepSeek testen",
|
|
69
|
+
"Test Custom API": "Eigene API testen",
|
|
70
|
+
"Custom API key": "API-Schlüssel (optional)",
|
|
71
|
+
"Custom API key help": "Nur nötig wenn der Anbieter Authentifizierung erfordert",
|
|
64
72
|
"AI settings": "KI-Einstellungen",
|
|
65
73
|
"AI settings description": "Wenn Sie die KI-Codegenerierung nutzen möchten, können Sie hier die API-Schlüssel für die entsprechenden Anbieter hinterlegen. Es wird nur der Schlüssel für den verwendeten Anbieter benötigt.",
|
|
66
74
|
"ChatGPT API key": "ChatGPT API-Schlüssel",
|
package/admin/i18n/en.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"Maximum setState requests per Minute per Script": "Maximum setState requests per Minute per Script",
|
|
22
22
|
"Maximum triggers per Script (until warning)": "Maximum triggers per Script (until warning)",
|
|
23
23
|
"Mirror scripts to file path": "Mirror scripts to file path",
|
|
24
|
+
"Sort global scripts alphabetically": "Sort global scripts alphabetically",
|
|
24
25
|
"Module names": "NPM module names",
|
|
25
26
|
"Next sunrise": "Next sunrise:",
|
|
26
27
|
"Next sunset": "Next sunset:",
|
|
@@ -61,6 +62,13 @@
|
|
|
61
62
|
"Custom API Base URL": "Custom API Base URL (e.g. for Ollama, LM Studio)",
|
|
62
63
|
"Custom API Base URL help": "Leave empty for OpenAI. For Ollama use http://localhost:11434/v1",
|
|
63
64
|
"Test API connection": "Test API connection",
|
|
65
|
+
"Test OpenAI": "Test OpenAI",
|
|
66
|
+
"Test Anthropic": "Test Anthropic",
|
|
67
|
+
"Test Gemini": "Test Gemini",
|
|
68
|
+
"Test DeepSeek": "Test DeepSeek",
|
|
69
|
+
"Test Custom API": "Test Custom API",
|
|
70
|
+
"Custom API key": "API key (optional)",
|
|
71
|
+
"Custom API key help": "Only needed if your provider requires authentication",
|
|
64
72
|
"AI settings": "AI settings",
|
|
65
73
|
"AI settings description": "If you want to use AI code generation, you can define API keys for the corresponding providers here. Only the key for the provider you use is required.",
|
|
66
74
|
"ChatGPT API key": "ChatGPT API key",
|
package/admin/i18n/es.json
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"Maximum setState requests per Minute per Script": "Máximas solicitudes de Estados por minuto por script",
|
|
22
22
|
"Maximum triggers per Script (until warning)": "Activadores máximos por script (hasta el aviso)",
|
|
23
23
|
"Mirror scripts to file path": "Guiones espejo a la ruta del archivo",
|
|
24
|
+
"Sort global scripts alphabetically": "Ordenar scripts globales alfabéticamente",
|
|
24
25
|
"Module names": "Nombres de módulos",
|
|
25
26
|
"Next sunrise": "Próximo amanecer:",
|
|
26
27
|
"Next sunset": "Próxima puesta de sol:",
|
|
@@ -61,6 +62,13 @@
|
|
|
61
62
|
"Custom API Base URL": "URL base de API personalizada (p. ej. para Ollama, LM Studio)",
|
|
62
63
|
"Custom API Base URL help": "Dejar vacío para OpenAI. Para Ollama usar http://localhost:11434/v1",
|
|
63
64
|
"Test API connection": "Probar conexión API",
|
|
65
|
+
"Test OpenAI": "Test OpenAI",
|
|
66
|
+
"Test Anthropic": "Test Anthropic",
|
|
67
|
+
"Test Gemini": "Test Gemini",
|
|
68
|
+
"Test DeepSeek": "Test DeepSeek",
|
|
69
|
+
"Test Custom API": "Test Custom API",
|
|
70
|
+
"Custom API key": "API key (optional)",
|
|
71
|
+
"Custom API key help": "Only needed if your provider requires authentication",
|
|
64
72
|
"AI settings": "Configuración de IA",
|
|
65
73
|
"AI settings description": "Si desea utilizar la generación de código con IA, puede definir aquí las claves API de los proveedores correspondientes. Solo se necesita la clave del proveedor que utilice.",
|
|
66
74
|
"ChatGPT API key": "Clave API de ChatGPT",
|