@bonsae/nrg 0.4.0 → 0.5.1
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/build/server/index.cjs +10 -17
- package/build/server/resources/nrg-client.js +3416 -3238
- package/build/vite/index.js +23 -9
- package/package.json +1 -1
- package/src/core/client/app.vue +2 -8
- package/src/core/client/components/node-red-config-input.vue +22 -0
- package/src/core/client/components/node-red-editor-input.vue +33 -9
- package/src/core/client/components/node-red-input-label.vue +53 -0
- package/src/core/client/components/node-red-input.vue +22 -0
- package/src/core/client/components/node-red-json-schema-form.vue +89 -44
- package/src/core/client/components/node-red-select-input.vue +22 -0
- package/src/core/client/components/node-red-typed-input.vue +22 -0
- package/src/core/client/index.ts +2 -0
- package/src/core/server/schemas/type.ts +5 -19
- package/src/core/server/schemas/types/index.ts +9 -1
- package/src/core/server/utils.ts +2 -2
- package/src/core/server/validator.ts +6 -2
- package/src/vite/client/build.ts +9 -7
- package/src/vite/client/plugins/node-definitions-inliner.ts +1 -1
- package/src/vite/plugins/build.ts +15 -3
package/build/vite/index.js
CHANGED
|
@@ -1211,7 +1211,7 @@ function getDefaultsFromSchema(schema) {
|
|
|
1211
1211
|
result[key] = {
|
|
1212
1212
|
required: false,
|
|
1213
1213
|
value: prop.default ?? void 0,
|
|
1214
|
-
type: prop["node-type"]
|
|
1214
|
+
type: prop["x-nrg-node-type"]
|
|
1215
1215
|
};
|
|
1216
1216
|
}
|
|
1217
1217
|
return result;
|
|
@@ -1443,11 +1443,13 @@ async function build2(clientBuildOptions, buildContext) {
|
|
|
1443
1443
|
if (fs10.existsSync(physicalEntryPath)) {
|
|
1444
1444
|
entryPath = physicalEntryPath;
|
|
1445
1445
|
} else {
|
|
1446
|
-
|
|
1447
|
-
|
|
1446
|
+
const cacheDir = path10.resolve("node_modules", ".nrg", "client");
|
|
1447
|
+
const cachedEntryPath = path10.resolve(cacheDir, entry);
|
|
1448
|
+
if (!fs10.existsSync(cacheDir)) {
|
|
1449
|
+
fs10.mkdirSync(cacheDir, { recursive: true });
|
|
1448
1450
|
}
|
|
1449
|
-
fs10.writeFileSync(
|
|
1450
|
-
entryPath =
|
|
1451
|
+
fs10.writeFileSync(cachedEntryPath, "// auto-generated entry\n");
|
|
1452
|
+
entryPath = cachedEntryPath;
|
|
1451
1453
|
generatedEntry = true;
|
|
1452
1454
|
}
|
|
1453
1455
|
const iconsDir = path10.resolve(
|
|
@@ -1592,7 +1594,7 @@ async function build2(clientBuildOptions, buildContext) {
|
|
|
1592
1594
|
throw new BuildError("client", error);
|
|
1593
1595
|
} finally {
|
|
1594
1596
|
if (generatedEntry) {
|
|
1595
|
-
fs10.unlinkSync(
|
|
1597
|
+
fs10.unlinkSync(entryPath);
|
|
1596
1598
|
}
|
|
1597
1599
|
}
|
|
1598
1600
|
}
|
|
@@ -1841,10 +1843,22 @@ function buildPlugin(options) {
|
|
|
1841
1843
|
const tsconfigsToCheck = [serverTsconfig, clientTsconfig].filter(
|
|
1842
1844
|
(p) => fs11.existsSync(p)
|
|
1843
1845
|
);
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
+
try {
|
|
1847
|
+
for (const tsconfig of tsconfigsToCheck) {
|
|
1848
|
+
execSync(`npx tsc -p ${tsconfig} --noEmit`, {
|
|
1849
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
1850
|
+
encoding: "utf-8"
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
logger.stopSpinner("Type checked");
|
|
1854
|
+
} catch (e) {
|
|
1855
|
+
logger.stopSpinner("Type check failed");
|
|
1856
|
+
const output = (e.stdout || "") + (e.stderr || "");
|
|
1857
|
+
if (output) {
|
|
1858
|
+
console.error(output);
|
|
1859
|
+
}
|
|
1860
|
+
throw new BuildError("type-check", e);
|
|
1846
1861
|
}
|
|
1847
|
-
logger.stopSpinner("Type checked");
|
|
1848
1862
|
logger.startSpinner("Cleaning");
|
|
1849
1863
|
cleanDir(buildContext.outDir);
|
|
1850
1864
|
logger.stopSpinner("Cleaned");
|
package/package.json
CHANGED
package/src/core/client/app.vue
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
localNode.validateInput = ($event.target as HTMLInputElement).checked
|
|
15
15
|
"
|
|
16
16
|
/>
|
|
17
|
-
<
|
|
17
|
+
<NodeRedInputLabel label="Validate Input" style="width: auto" />
|
|
18
18
|
</template>
|
|
19
19
|
<template v-if="features.hasOutputSchema">
|
|
20
20
|
<input
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
localNode.validateOutput = ($event.target as HTMLInputElement).checked
|
|
27
27
|
"
|
|
28
28
|
/>
|
|
29
|
-
<
|
|
29
|
+
<NodeRedInputLabel label="Validate Output" style="width: auto" />
|
|
30
30
|
</template>
|
|
31
31
|
</div>
|
|
32
32
|
<div style="width: 100%; padding-bottom: 12px">
|
|
@@ -185,12 +185,6 @@ export default defineComponent({
|
|
|
185
185
|
color: var(--red-ui-text-color-error);
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
:deep(.nrg-label) {
|
|
189
|
-
display: inline-block;
|
|
190
|
-
width: 100%;
|
|
191
|
-
cursor: default;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
188
|
:deep(.form-row input[type="text"]),
|
|
195
189
|
:deep(.form-row input[type="number"]),
|
|
196
190
|
:deep(.form-row input[type="password"]) {
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div style="display: flex; flex-direction: column; width: 100%">
|
|
3
|
+
<slot name="label">
|
|
4
|
+
<NodeRedInputLabel
|
|
5
|
+
v-if="label"
|
|
6
|
+
:label="label"
|
|
7
|
+
:icon="icon"
|
|
8
|
+
:required="required"
|
|
9
|
+
/>
|
|
10
|
+
</slot>
|
|
3
11
|
<input :id="inputId" type="text" style="width: 100%" />
|
|
4
12
|
<div v-if="error" class="node-red-vue-input-error-message">
|
|
5
13
|
{{ error }}
|
|
@@ -9,7 +17,9 @@
|
|
|
9
17
|
|
|
10
18
|
<script lang="ts">
|
|
11
19
|
import { defineComponent } from "vue";
|
|
20
|
+
import NodeRedInputLabel from "./node-red-input-label.vue";
|
|
12
21
|
export default defineComponent({
|
|
22
|
+
components: { NodeRedInputLabel },
|
|
13
23
|
props: {
|
|
14
24
|
value: {
|
|
15
25
|
type: String,
|
|
@@ -27,6 +37,18 @@ export default defineComponent({
|
|
|
27
37
|
type: String,
|
|
28
38
|
required: true,
|
|
29
39
|
},
|
|
40
|
+
label: {
|
|
41
|
+
type: String,
|
|
42
|
+
default: "",
|
|
43
|
+
},
|
|
44
|
+
icon: {
|
|
45
|
+
type: String,
|
|
46
|
+
default: "",
|
|
47
|
+
},
|
|
48
|
+
required: {
|
|
49
|
+
type: Boolean,
|
|
50
|
+
default: false,
|
|
51
|
+
},
|
|
30
52
|
error: {
|
|
31
53
|
type: String,
|
|
32
54
|
default: "",
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ref="container" class="container">
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
<slot name="label">
|
|
4
|
+
<NodeRedInputLabel
|
|
5
|
+
v-if="label"
|
|
6
|
+
:label="label"
|
|
7
|
+
:icon="icon"
|
|
8
|
+
:required="required"
|
|
9
|
+
/>
|
|
10
|
+
</slot>
|
|
11
|
+
<div class="editor-wrapper">
|
|
12
|
+
<button
|
|
13
|
+
ref="expand-button"
|
|
14
|
+
class="red-ui-button red-ui-button-small expand-button"
|
|
15
|
+
@click="onClickExpand"
|
|
16
|
+
>
|
|
17
|
+
<i class="fa fa-expand"></i>
|
|
18
|
+
</button>
|
|
19
|
+
<div :id="editorId" ref="editor"></div>
|
|
20
|
+
</div>
|
|
11
21
|
<div v-show="error" class="node-red-vue-input-error-message">
|
|
12
22
|
{{ error }}
|
|
13
23
|
</div>
|
|
@@ -17,7 +27,9 @@
|
|
|
17
27
|
<script lang="ts">
|
|
18
28
|
// TODO: expose editor apis
|
|
19
29
|
import { defineComponent } from "vue";
|
|
30
|
+
import NodeRedInputLabel from "./node-red-input-label.vue";
|
|
20
31
|
export default defineComponent({
|
|
32
|
+
components: { NodeRedInputLabel },
|
|
21
33
|
props: {
|
|
22
34
|
value: {
|
|
23
35
|
type: String,
|
|
@@ -121,6 +133,18 @@ export default defineComponent({
|
|
|
121
133
|
return isValid;
|
|
122
134
|
},
|
|
123
135
|
},
|
|
136
|
+
label: {
|
|
137
|
+
type: String,
|
|
138
|
+
default: "",
|
|
139
|
+
},
|
|
140
|
+
icon: {
|
|
141
|
+
type: String,
|
|
142
|
+
default: "",
|
|
143
|
+
},
|
|
144
|
+
required: {
|
|
145
|
+
type: Boolean,
|
|
146
|
+
default: false,
|
|
147
|
+
},
|
|
124
148
|
error: {
|
|
125
149
|
type: String,
|
|
126
150
|
default: "",
|
|
@@ -268,7 +292,7 @@ export default defineComponent({
|
|
|
268
292
|
});
|
|
269
293
|
</script>
|
|
270
294
|
<style scoped>
|
|
271
|
-
.
|
|
295
|
+
.editor-wrapper {
|
|
272
296
|
position: relative;
|
|
273
297
|
}
|
|
274
298
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span class="nrg-label">
|
|
3
|
+
<i v-if="icon" :class="iconClass"></i>
|
|
4
|
+
<slot>{{ label }}</slot>
|
|
5
|
+
<span v-if="required" class="nrg-required">*</span>
|
|
6
|
+
</span>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
import { defineComponent } from "vue";
|
|
11
|
+
|
|
12
|
+
export default defineComponent({
|
|
13
|
+
name: "NodeRedInputLabel",
|
|
14
|
+
props: {
|
|
15
|
+
label: {
|
|
16
|
+
type: String,
|
|
17
|
+
default: "",
|
|
18
|
+
},
|
|
19
|
+
icon: {
|
|
20
|
+
type: String,
|
|
21
|
+
default: "",
|
|
22
|
+
},
|
|
23
|
+
required: {
|
|
24
|
+
type: Boolean,
|
|
25
|
+
default: false,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
computed: {
|
|
29
|
+
iconClass(): string {
|
|
30
|
+
if (!this.icon) return "";
|
|
31
|
+
const name = this.icon.startsWith("fa-") ? this.icon : `fa-${this.icon}`;
|
|
32
|
+
return `fa ${name}`;
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<style scoped>
|
|
39
|
+
.nrg-label {
|
|
40
|
+
display: inline-block;
|
|
41
|
+
width: 100%;
|
|
42
|
+
cursor: default;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.nrg-label i {
|
|
46
|
+
margin-right: 5px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.nrg-required {
|
|
50
|
+
color: var(--red-ui-text-color-error);
|
|
51
|
+
margin-left: 2px;
|
|
52
|
+
}
|
|
53
|
+
</style>
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div style="display: flex; flex-direction: column; width: 100%">
|
|
3
|
+
<slot name="label">
|
|
4
|
+
<NodeRedInputLabel
|
|
5
|
+
v-if="label"
|
|
6
|
+
:label="label"
|
|
7
|
+
:icon="icon"
|
|
8
|
+
:required="required"
|
|
9
|
+
/>
|
|
10
|
+
</slot>
|
|
3
11
|
<input
|
|
4
12
|
ref="inputField"
|
|
5
13
|
:type="type"
|
|
@@ -18,10 +26,12 @@
|
|
|
18
26
|
|
|
19
27
|
<script lang="ts">
|
|
20
28
|
import { defineComponent } from "vue";
|
|
29
|
+
import NodeRedInputLabel from "./node-red-input-label.vue";
|
|
21
30
|
|
|
22
31
|
const SECRET_PATTERN = "*************";
|
|
23
32
|
|
|
24
33
|
export default defineComponent({
|
|
34
|
+
components: { NodeRedInputLabel },
|
|
25
35
|
props: {
|
|
26
36
|
value: {
|
|
27
37
|
type: String,
|
|
@@ -35,6 +45,18 @@ export default defineComponent({
|
|
|
35
45
|
type: String,
|
|
36
46
|
default: "",
|
|
37
47
|
},
|
|
48
|
+
label: {
|
|
49
|
+
type: String,
|
|
50
|
+
default: "",
|
|
51
|
+
},
|
|
52
|
+
icon: {
|
|
53
|
+
type: String,
|
|
54
|
+
default: "",
|
|
55
|
+
},
|
|
56
|
+
required: {
|
|
57
|
+
type: Boolean,
|
|
58
|
+
default: false,
|
|
59
|
+
},
|
|
38
60
|
error: {
|
|
39
61
|
type: String,
|
|
40
62
|
default: "",
|
|
@@ -1,36 +1,44 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
3
|
<div v-for="field in configFields" :key="field.key" class="form-row">
|
|
4
|
-
<span class="nrg-label">
|
|
5
|
-
{{ field.label }}
|
|
6
|
-
<span v-if="field.required" class="nrg-required">*</span>
|
|
7
|
-
</span>
|
|
8
|
-
|
|
9
4
|
<NodeRedInput
|
|
10
5
|
v-if="field.inputType === 'text' || field.inputType === 'number'"
|
|
11
6
|
:value="node[field.key]"
|
|
12
7
|
:type="field.htmlType"
|
|
8
|
+
:label="field.label"
|
|
9
|
+
:icon="field.icon"
|
|
10
|
+
:required="field.required"
|
|
13
11
|
:error="errors[`node.${field.key}`]"
|
|
14
12
|
@update:value="node[field.key] = $event"
|
|
15
13
|
/>
|
|
16
14
|
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
<div v-else-if="field.inputType === 'boolean'">
|
|
16
|
+
<NodeRedInputLabel
|
|
17
|
+
:label="field.label"
|
|
18
|
+
:icon="field.icon"
|
|
19
|
+
:required="field.required"
|
|
20
|
+
style="width: auto"
|
|
21
|
+
/>
|
|
22
|
+
<input
|
|
23
|
+
type="checkbox"
|
|
24
|
+
:checked="node[field.key]"
|
|
25
|
+
style="width: auto; margin: 0"
|
|
26
|
+
@change="
|
|
27
|
+
(e) => {
|
|
28
|
+
node[field.key] = (e.target as HTMLInputElement).checked;
|
|
29
|
+
}
|
|
30
|
+
"
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
28
33
|
|
|
29
34
|
<NodeRedSelectInput
|
|
30
35
|
v-else-if="field.inputType === 'select'"
|
|
31
36
|
:value="node[field.key]"
|
|
32
37
|
:options="field.options!"
|
|
33
38
|
:multiple="field.multiple"
|
|
39
|
+
:label="field.label"
|
|
40
|
+
:icon="field.icon"
|
|
41
|
+
:required="field.required"
|
|
34
42
|
:error="errors[`node.${field.key}`]"
|
|
35
43
|
@update:value="node[field.key] = $event"
|
|
36
44
|
/>
|
|
@@ -39,6 +47,9 @@
|
|
|
39
47
|
v-else-if="field.inputType === 'typed'"
|
|
40
48
|
:value="node[field.key]"
|
|
41
49
|
:types="field.types"
|
|
50
|
+
:label="field.label"
|
|
51
|
+
:icon="field.icon"
|
|
52
|
+
:required="field.required"
|
|
42
53
|
:error="errors[`node.${field.key}`]"
|
|
43
54
|
@update:value="node[field.key] = $event"
|
|
44
55
|
/>
|
|
@@ -49,11 +60,19 @@
|
|
|
49
60
|
:type="field.configType!"
|
|
50
61
|
:node="node"
|
|
51
62
|
:prop-name="field.key"
|
|
63
|
+
:label="field.label"
|
|
64
|
+
:icon="field.icon"
|
|
65
|
+
:required="field.required"
|
|
52
66
|
:error="errors[`node.${field.key}`]"
|
|
53
67
|
@update:value="node[field.key] = $event"
|
|
54
68
|
/>
|
|
55
69
|
|
|
56
70
|
<div v-else-if="field.inputType === 'array-text'">
|
|
71
|
+
<NodeRedInputLabel
|
|
72
|
+
:label="field.label"
|
|
73
|
+
:icon="field.icon"
|
|
74
|
+
:required="field.required"
|
|
75
|
+
/>
|
|
57
76
|
<span
|
|
58
77
|
style="
|
|
59
78
|
display: block;
|
|
@@ -95,6 +114,9 @@
|
|
|
95
114
|
v-else-if="field.inputType === 'editor'"
|
|
96
115
|
:value="node[field.key]"
|
|
97
116
|
:language="field.language"
|
|
117
|
+
:label="field.label"
|
|
118
|
+
:icon="field.icon"
|
|
119
|
+
:required="field.required"
|
|
98
120
|
:error="errors[`node.${field.key}`]"
|
|
99
121
|
@update:value="node[field.key] = $event"
|
|
100
122
|
/>
|
|
@@ -105,14 +127,12 @@
|
|
|
105
127
|
:key="`cred-${field.key}`"
|
|
106
128
|
class="form-row"
|
|
107
129
|
>
|
|
108
|
-
<span class="nrg-label">
|
|
109
|
-
{{ field.label }}
|
|
110
|
-
<span v-if="field.required" class="nrg-required">*</span>
|
|
111
|
-
</span>
|
|
112
|
-
|
|
113
130
|
<NodeRedInput
|
|
114
131
|
:value="node.credentials[field.key]"
|
|
115
132
|
:type="field.htmlType"
|
|
133
|
+
:label="field.label"
|
|
134
|
+
:icon="field.icon"
|
|
135
|
+
:required="field.required"
|
|
116
136
|
:error="errors[`node.credentials.${field.key}`]"
|
|
117
137
|
@update:value="node.credentials[field.key] = $event"
|
|
118
138
|
/>
|
|
@@ -123,6 +143,7 @@
|
|
|
123
143
|
<script lang="ts">
|
|
124
144
|
import type { PropType } from "vue";
|
|
125
145
|
import { defineComponent } from "vue";
|
|
146
|
+
import NodeRedInputLabel from "./node-red-input-label.vue";
|
|
126
147
|
import NodeRedInput from "./node-red-input.vue";
|
|
127
148
|
import NodeRedSelectInput from "./node-red-select-input.vue";
|
|
128
149
|
import NodeRedTypedInput from "./node-red-typed-input.vue";
|
|
@@ -144,6 +165,12 @@ const SKIP_FIELDS = new Set([
|
|
|
144
165
|
"validateOutput",
|
|
145
166
|
]);
|
|
146
167
|
|
|
168
|
+
interface NrgFormOptions {
|
|
169
|
+
icon?: string;
|
|
170
|
+
typedInputTypes?: string[];
|
|
171
|
+
editorLanguage?: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
147
174
|
interface FieldSchema {
|
|
148
175
|
type?: string | string[];
|
|
149
176
|
properties?: Record<string, FieldSchema>;
|
|
@@ -154,15 +181,15 @@ interface FieldSchema {
|
|
|
154
181
|
description?: string;
|
|
155
182
|
default?: any;
|
|
156
183
|
items?: FieldSchema;
|
|
157
|
-
"node-type"?: string;
|
|
158
|
-
"x-
|
|
159
|
-
"x-editor-language"?: string;
|
|
184
|
+
"x-nrg-node-type"?: string;
|
|
185
|
+
"x-nrg-form"?: NrgFormOptions;
|
|
160
186
|
[key: string]: any;
|
|
161
187
|
}
|
|
162
188
|
|
|
163
189
|
interface FormField {
|
|
164
190
|
key: string;
|
|
165
191
|
label: string;
|
|
192
|
+
icon: string;
|
|
166
193
|
inputType:
|
|
167
194
|
| "text"
|
|
168
195
|
| "number"
|
|
@@ -201,15 +228,18 @@ function buildField(
|
|
|
201
228
|
required: boolean,
|
|
202
229
|
): FormField {
|
|
203
230
|
const label = schema.title || formatLabel(key);
|
|
231
|
+
const form = schema["x-nrg-form"] ?? {};
|
|
232
|
+
const icon = form.icon || "";
|
|
204
233
|
|
|
205
234
|
// NodeRef → config input
|
|
206
|
-
if (schema["node-type"]) {
|
|
235
|
+
if (schema["x-nrg-node-type"]) {
|
|
207
236
|
return {
|
|
208
237
|
key,
|
|
209
238
|
label,
|
|
239
|
+
icon,
|
|
210
240
|
inputType: "config",
|
|
211
241
|
required,
|
|
212
|
-
configType: schema["node-type"],
|
|
242
|
+
configType: schema["x-nrg-node-type"],
|
|
213
243
|
};
|
|
214
244
|
}
|
|
215
245
|
|
|
@@ -218,9 +248,10 @@ function buildField(
|
|
|
218
248
|
return {
|
|
219
249
|
key,
|
|
220
250
|
label,
|
|
251
|
+
icon,
|
|
221
252
|
inputType: "typed",
|
|
222
253
|
required,
|
|
223
|
-
types:
|
|
254
|
+
types: form.typedInputTypes,
|
|
224
255
|
};
|
|
225
256
|
}
|
|
226
257
|
|
|
@@ -229,6 +260,7 @@ function buildField(
|
|
|
229
260
|
return {
|
|
230
261
|
key,
|
|
231
262
|
label,
|
|
263
|
+
icon,
|
|
232
264
|
inputType: "select",
|
|
233
265
|
required,
|
|
234
266
|
multiple: true,
|
|
@@ -244,6 +276,7 @@ function buildField(
|
|
|
244
276
|
return {
|
|
245
277
|
key,
|
|
246
278
|
label,
|
|
279
|
+
icon,
|
|
247
280
|
inputType: "select",
|
|
248
281
|
required,
|
|
249
282
|
multiple: false,
|
|
@@ -258,53 +291,71 @@ function buildField(
|
|
|
258
291
|
|
|
259
292
|
switch (rawType) {
|
|
260
293
|
case "boolean":
|
|
261
|
-
return { key, label, inputType: "boolean", required };
|
|
294
|
+
return { key, label, icon, inputType: "boolean", required };
|
|
262
295
|
|
|
263
296
|
case "number":
|
|
264
297
|
case "integer":
|
|
265
|
-
return {
|
|
298
|
+
return {
|
|
299
|
+
key,
|
|
300
|
+
label,
|
|
301
|
+
icon,
|
|
302
|
+
inputType: "number",
|
|
303
|
+
required,
|
|
304
|
+
htmlType: "number",
|
|
305
|
+
};
|
|
266
306
|
|
|
267
307
|
case "array":
|
|
268
|
-
if (
|
|
308
|
+
if (form.editorLanguage) {
|
|
269
309
|
return {
|
|
270
310
|
key,
|
|
271
311
|
label,
|
|
312
|
+
icon,
|
|
272
313
|
inputType: "editor",
|
|
273
314
|
required,
|
|
274
|
-
language:
|
|
315
|
+
language: form.editorLanguage,
|
|
275
316
|
};
|
|
276
317
|
}
|
|
277
318
|
// Plain array of strings → comma-separated text input
|
|
278
|
-
return { key, label, inputType: "array-text", required };
|
|
319
|
+
return { key, label, icon, inputType: "array-text", required };
|
|
279
320
|
|
|
280
321
|
case "object":
|
|
281
|
-
if (
|
|
322
|
+
if (form.editorLanguage) {
|
|
282
323
|
return {
|
|
283
324
|
key,
|
|
284
325
|
label,
|
|
326
|
+
icon,
|
|
285
327
|
inputType: "editor",
|
|
286
328
|
required,
|
|
287
|
-
language:
|
|
329
|
+
language: form.editorLanguage,
|
|
288
330
|
};
|
|
289
331
|
}
|
|
290
332
|
// Plain object → text input (stored as JSON string)
|
|
291
|
-
return {
|
|
333
|
+
return {
|
|
334
|
+
key,
|
|
335
|
+
label,
|
|
336
|
+
icon,
|
|
337
|
+
inputType: "text",
|
|
338
|
+
required,
|
|
339
|
+
htmlType: "text",
|
|
340
|
+
};
|
|
292
341
|
|
|
293
342
|
default:
|
|
294
343
|
// string with editor language → code editor
|
|
295
|
-
if (
|
|
344
|
+
if (form.editorLanguage) {
|
|
296
345
|
return {
|
|
297
346
|
key,
|
|
298
347
|
label,
|
|
348
|
+
icon,
|
|
299
349
|
inputType: "editor",
|
|
300
350
|
required,
|
|
301
|
-
language:
|
|
351
|
+
language: form.editorLanguage,
|
|
302
352
|
};
|
|
303
353
|
}
|
|
304
354
|
// string (or untyped)
|
|
305
355
|
return {
|
|
306
356
|
key,
|
|
307
357
|
label,
|
|
358
|
+
icon,
|
|
308
359
|
inputType: "text",
|
|
309
360
|
required,
|
|
310
361
|
htmlType: schema.format === "password" ? "password" : "text",
|
|
@@ -315,6 +366,7 @@ function buildField(
|
|
|
315
366
|
export default defineComponent({
|
|
316
367
|
name: "NodeRedJsonSchemaForm",
|
|
317
368
|
components: {
|
|
369
|
+
NodeRedInputLabel,
|
|
318
370
|
NodeRedInput,
|
|
319
371
|
NodeRedSelectInput,
|
|
320
372
|
NodeRedTypedInput,
|
|
@@ -370,10 +422,3 @@ export default defineComponent({
|
|
|
370
422
|
},
|
|
371
423
|
});
|
|
372
424
|
</script>
|
|
373
|
-
|
|
374
|
-
<style scoped>
|
|
375
|
-
.nrg-required {
|
|
376
|
-
color: var(--red-ui-text-color-error);
|
|
377
|
-
margin-left: 2px;
|
|
378
|
-
}
|
|
379
|
-
</style>
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div style="display: flex; flex-direction: column; width: 100%">
|
|
3
|
+
<slot name="label">
|
|
4
|
+
<NodeRedInputLabel
|
|
5
|
+
v-if="label"
|
|
6
|
+
:label="label"
|
|
7
|
+
:icon="icon"
|
|
8
|
+
:required="required"
|
|
9
|
+
/>
|
|
10
|
+
</slot>
|
|
3
11
|
<input
|
|
4
12
|
ref="selectInput"
|
|
5
13
|
type="text"
|
|
@@ -14,7 +22,9 @@
|
|
|
14
22
|
|
|
15
23
|
<script lang="ts">
|
|
16
24
|
import { defineComponent } from "vue";
|
|
25
|
+
import NodeRedInputLabel from "./node-red-input-label.vue";
|
|
17
26
|
export default defineComponent({
|
|
27
|
+
components: { NodeRedInputLabel },
|
|
18
28
|
props: {
|
|
19
29
|
value: {
|
|
20
30
|
type: [String, Array],
|
|
@@ -53,6 +63,18 @@ export default defineComponent({
|
|
|
53
63
|
type: Boolean,
|
|
54
64
|
default: false,
|
|
55
65
|
},
|
|
66
|
+
label: {
|
|
67
|
+
type: String,
|
|
68
|
+
default: "",
|
|
69
|
+
},
|
|
70
|
+
icon: {
|
|
71
|
+
type: String,
|
|
72
|
+
default: "",
|
|
73
|
+
},
|
|
74
|
+
required: {
|
|
75
|
+
type: Boolean,
|
|
76
|
+
default: false,
|
|
77
|
+
},
|
|
56
78
|
error: {
|
|
57
79
|
type: String,
|
|
58
80
|
default: "",
|