@5minds/node-red-dashboard-2-processcube-dynamic-form 1.0.15 → 1.0.16

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.
@@ -1,192 +1,204 @@
1
1
  <script type="text/javascript">
2
- RED.nodes.registerType("ui-dynamic-form", {
3
- category: "ProcessCube UI",
4
- color: "#00aed7",
5
- defaults: {
6
- name: { value: "" },
7
- group: { type: "ui-group", required: true },
8
- order: { value: 0 },
9
- options: {
10
- value: [{ label: "" }],
11
- validate: function (v) {
12
- const unique = new Set(
13
- v.map(function (o) {
14
- return o.label;
15
- })
16
- );
17
- return v.length === unique.size;
2
+ RED.nodes.registerType('ui-dynamic-form', {
3
+ category: 'ProcessCube UI',
4
+ color: '#00aed7',
5
+ defaults: {
6
+ name: { value: '' },
7
+ group: { type: 'ui-group', required: true },
8
+ order: { value: 0 },
9
+ options: {
10
+ value: [{ label: '' }],
11
+ validate: function (v) {
12
+ const unique = new Set(
13
+ v.map(function (o) {
14
+ return o.label;
15
+ })
16
+ );
17
+ return v.length === unique.size;
18
+ },
19
+ },
20
+ waiting_title: { value: 'Waiting for Warten auf den Usertask...' },
21
+ waiting_info: {
22
+ value: 'Der Usertask wird automatisch angezeigt, wenn ein entsprechender Task vorhanden ist.',
23
+ },
24
+ width: {
25
+ value: 0,
26
+ validate: function (v) {
27
+ const width = v || 0;
28
+ const currentGroup = $('#node-input-group').val() || this.group;
29
+ const groupNode = RED.nodes.node(currentGroup);
30
+ const valid = !groupNode || +width <= +groupNode.width;
31
+ $('#node-input-size').toggleClass('input-error', !valid);
32
+ return valid;
33
+ },
34
+ },
35
+ height: { value: 0 },
36
+ outputs: { value: 1 },
18
37
  },
19
- },
20
- waiting_title: { value: "Waiting for Warten auf den Usertask..." },
21
- waiting_info: {
22
- value:
23
- "Der Usertask wird automatisch angezeigt, wenn ein entsprechender Task vorhanden ist.",
24
- },
25
- width: {
26
- value: 0,
27
- validate: function (v) {
28
- const width = v || 0;
29
- const currentGroup = $("#node-input-group").val() || this.group;
30
- const groupNode = RED.nodes.node(currentGroup);
31
- const valid = !groupNode || +width <= +groupNode.width;
32
- $("#node-input-size").toggleClass("input-error", !valid);
33
- return valid;
38
+ inputs: 1,
39
+ outputs: 1,
40
+ outputLabels: function (index) {
41
+ return this.options[index].label;
34
42
  },
35
- },
36
- height: { value: 0 },
37
- outputs: { value: 1 },
38
- },
39
- inputs: 1,
40
- outputs: 1,
41
- outputLabels: function (index) {
42
- return this.options[index].label;
43
- },
44
- icon: "file.svg",
45
- label: function () {
46
- return this.name || "dynamic-form";
47
- },
48
- oneditprepare: function () {
49
- $("#node-input-size").elementSizer({
50
- width: "#node-input-width",
51
- height: "#node-input-height",
52
- group: "#node-input-group",
53
- });
43
+ icon: 'file.svg',
44
+ label: function () {
45
+ return this.name || 'dynamic-form';
46
+ },
47
+ oneditprepare: function () {
48
+ $('#node-input-size').elementSizer({
49
+ width: '#node-input-width',
50
+ height: '#node-input-height',
51
+ group: '#node-input-group',
52
+ });
53
+
54
+ function generateOption(i, option) {
55
+ const container = $('<li/>', {
56
+ style: 'background: var(--red-ui-secondary-background, #fff); margin:0; padding:8px 0px 0px;',
57
+ });
54
58
 
55
- function generateOption(i, option) {
56
- const container = $("<li/>", {
57
- style:
58
- "background: var(--red-ui-secondary-background, #fff); margin:0; padding:8px 0px 0px;",
59
- });
59
+ // Create input fields for value and label
60
+ const row = $('<div/>').appendTo(container);
61
+ $('<input/>', {
62
+ class: 'node-input-option-label',
63
+ type: 'text',
64
+ style: 'margin-left:7px; width:calc(29%);',
65
+ placeholder: 'Label',
66
+ value: option.label,
67
+ })
68
+ .appendTo(row)
69
+ .typedInput({
70
+ type: 'str',
71
+ types: ['str'],
72
+ });
60
73
 
61
- // Create input fields for value and label
62
- const row = $("<div/>").appendTo(container);
63
- $("<input/>", {
64
- class: "node-input-option-label",
65
- type: "text",
66
- style: "margin-left:7px; width:calc(100% - 48px);",
67
- placeholder: "Label",
68
- value: option.label,
69
- })
70
- .appendTo(row)
71
- .typedInput({
72
- type: "str",
73
- types: ["str"],
74
- });
74
+ $('<input/>', {
75
+ class: 'node-input-option-condition',
76
+ type: 'text',
77
+ style: 'margin-left:7px; width:calc(29%);',
78
+ placeholder: 'Condition',
79
+ value: option.condition,
80
+ })
81
+ .appendTo(row)
82
+ .typedInput({
83
+ type: 'str',
84
+ types: ['str'],
85
+ });
75
86
 
76
- // $('<input/>', {
77
- // class: 'node-input-option-condition',
78
- // type: 'text',
79
- // style: 'margin-left:7px; width:calc(50% - 32px);',
80
- // placeholder: 'Condition',
81
- // value: option.condition
82
- // }).appendTo(row).typedInput({
83
- // type: 'str', types: ['str']
84
- // });
87
+ $('<input/>', {
88
+ class: 'node-input-option-error',
89
+ type: 'text',
90
+ style: 'margin-left:7px; width:calc(29%);',
91
+ placeholder: 'Error message',
92
+ value: option.errorMessage,
93
+ })
94
+ .appendTo(row)
95
+ .typedInput({
96
+ type: 'str',
97
+ types: ['str'],
98
+ });
85
99
 
86
- // Create delete button for the option
87
- const finalSpan = $("<span/>", {
88
- style: "float:right; margin-right:8px;",
89
- }).appendTo(row);
90
- const deleteButton = $("<a/>", {
91
- href: "#",
92
- class: "editor-button editor-button-small",
93
- style: "margin-top:7px; margin-left:5px;",
94
- }).appendTo(finalSpan);
95
- $("<i/>", { class: "fa fa-remove" }).appendTo(deleteButton);
100
+ // Create delete button for the option
101
+ const finalSpan = $('<span/>', {
102
+ style: 'float:right; margin-right:8px;',
103
+ }).appendTo(row);
104
+ const deleteButton = $('<a/>', {
105
+ href: '#',
106
+ class: 'editor-button editor-button-small',
107
+ style: 'margin-top:7px; margin-left:5px;',
108
+ }).appendTo(finalSpan);
109
+ $('<i/>', { class: 'fa fa-remove' }).appendTo(deleteButton);
96
110
 
97
- deleteButton.click(function () {
98
- container.css({
99
- background: "var(--red-ui-secondary-background-inactive, #fee)",
100
- });
101
- container.fadeOut(300, function () {
102
- $(this).remove();
103
- });
104
- });
111
+ deleteButton.click(function () {
112
+ container.css({
113
+ background: 'var(--red-ui-secondary-background-inactive, #fee)',
114
+ });
115
+ container.fadeOut(300, function () {
116
+ $(this).remove();
117
+ });
118
+ });
105
119
 
106
- $("#node-input-option-container").append(container);
107
- }
120
+ $('#node-input-option-container').append(container);
121
+ }
108
122
 
109
- $("#node-input-add-option").click(function () {
110
- generateOption(
111
- $("#node-input-option-container").children().length + 1,
112
- {}
113
- );
114
- $("#node-input-option-container-div").scrollTop(
115
- $("#node-input-option-container-div").get(0).scrollHeight
116
- );
117
- });
123
+ $('#node-input-add-option').click(function () {
124
+ generateOption($('#node-input-option-container').children().length + 1, {});
125
+ $('#node-input-option-container-div').scrollTop(
126
+ $('#node-input-option-container-div').get(0).scrollHeight
127
+ );
128
+ });
118
129
 
119
- for (let i = 0; i < this.options.length; i++) {
120
- const option = this.options[i];
121
- generateOption(i + 1, option);
122
- }
130
+ for (let i = 0; i < this.options.length; i++) {
131
+ const option = this.options[i];
132
+ generateOption(i + 1, option);
133
+ }
123
134
 
124
- $("#node-input-option-container").sortable({
125
- axis: "y",
126
- handle: ".node-input-option-handle",
127
- cursor: "move",
128
- });
129
- },
130
- oneditsave: function () {
131
- const options = $("#node-input-option-container").children();
132
- const node = this;
133
- node.options = [];
134
- options.each(function (i) {
135
- const option = $(this);
136
- const o = {
137
- label: option.find(".node-input-option-label").val(),
138
- // condition: option.find('.node-input-option-condition').val()
139
- };
135
+ $('#node-input-option-container').sortable({
136
+ axis: 'y',
137
+ handle: '.node-input-option-handle',
138
+ cursor: 'move',
139
+ });
140
+ },
141
+ oneditsave: function () {
142
+ const options = $('#node-input-option-container').children();
143
+ const node = this;
144
+ node.options = [];
145
+ options.each(function (i) {
146
+ const option = $(this);
147
+ const o = {
148
+ label: option.find('.node-input-option-label').val(),
149
+ condition: option.find('.node-input-option-condition').val(),
150
+ errorMessage: option.find('.node-input-option-error').val(),
151
+ };
140
152
 
141
- node.options.push(o);
142
- });
153
+ node.options.push(o);
154
+ });
143
155
 
144
- this.outputs = node.options.length || 1;
145
- },
146
- });
156
+ this.outputs = node.options.length || 1;
157
+ },
158
+ });
147
159
  </script>
148
160
 
149
161
  <script type="text/html" data-template-name="ui-dynamic-form">
150
- <div class="form-row">
151
- <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
152
- <input type="text" id="node-input-name" placeholder="Name">
153
- </div>
154
- <div class="form-row">
155
- <label for="node-input-group"><i class="fa fa-table"></i> Group</label>
156
- <input type="text" id="node-input-group">
157
- </div>
158
- <div class="form-row">
159
- <label><i class="fa fa-object-group"></i> <span data-i18n="ui-dynamic-form.label.size"></label>
160
- <input type="hidden" id="node-input-width">
161
- <input type="hidden" id="node-input-height">
162
- <button class="editor-button" id="node-input-size"></button>
163
- </div>
162
+ <div class="form-row">
163
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
164
+ <input type="text" id="node-input-name" placeholder="Name">
165
+ </div>
166
+ <div class="form-row">
167
+ <label for="node-input-group"><i class="fa fa-table"></i> Group</label>
168
+ <input type="text" id="node-input-group">
169
+ </div>
170
+ <div class="form-row">
171
+ <label><i class="fa fa-object-group"></i> <span data-i18n="ui-dynamic-form.label.size"></label>
172
+ <input type="hidden" id="node-input-width">
173
+ <input type="hidden" id="node-input-height">
174
+ <button class="editor-button" id="node-input-size"></button>
175
+ </div>
164
176
 
165
- <div class="form-row form-row-flex node-input-option-container-row" style="margin-bottom: 0px;width: 100%">
166
- <label for="node-input-width" style="vertical-align:top"><i class="fa fa-list-alt"></i> Actions</label>
167
- <div id="node-input-option-container-div" style="box-sizing:border-box; border-radius:5px; height:257px; padding:5px; border:1px solid var(--red-ui-form-input-border-color, #ccc); overflow-y:scroll; display:inline-block; width: 70%;">
168
- <span id="valWarning" style="color: var(--red-ui-text-color-error, #910000)"><b>All Values must be unique.</b></span>
169
- <ol id="node-input-option-container" style="list-style-type:none; margin:0;"></ol>
170
- </div>
171
- <a
172
- data-html="true"
173
- title="Dynamic Property: Send 'msg.options' in order to override this property."
174
- class="red-ui-button ui-node-popover-title"
175
- style="margin-left: 4px; cursor: help; font-size: 0.625rem; border-radius: 50%; width: 24px; height: 24px; display: inline-flex; justify-content: center; align-items: center;">
176
- <i style="font-family: ui-serif;">fx</i>
177
- </a>
178
- </div>
179
- <!-- Add Option Button -->
180
- <div class="form-row">
181
- <a href="#" class="editor-button editor-button-small" id="node-input-add-option" style="margin-top:4px; margin-left:103px;"><i class="fa fa-plus"></i> <span>action</span></a>
182
- </div>
177
+ <div class="form-row form-row-flex node-input-option-container-row" style="margin-bottom: 0px;width: 100%">
178
+ <label for="node-input-width" style="vertical-align:top"><i class="fa fa-list-alt"></i> Actions</label>
179
+ <div id="node-input-option-container-div" style="box-sizing:border-box; border-radius:5px; height:257px; padding:5px; border:1px solid var(--red-ui-form-input-border-color, #ccc); overflow-y:scroll; display:inline-block; width: 70%;">
180
+ <span id="valWarning" style="color: var(--red-ui-text-color-error, #910000)"><b>All Values must be unique.</b></span>
181
+ <ol id="node-input-option-container" style="list-style-type:none; margin:0;"></ol>
182
+ </div>
183
+ <!-- <a
184
+ data-html="true"
185
+ title="Dynamic Property: Send 'msg.options' in order to override this property."
186
+ class="red-ui-button ui-node-popover-title"
187
+ style="margin-left: 4px; cursor: help; font-size: 0.625rem; border-radius: 50%; width: 24px; height: 24px; display: inline-flex; justify-content: center; align-items: center;">
188
+ <i style="font-family: ui-serif;">fx</i>
189
+ </a> -->
190
+ </div>
191
+ <!-- Add Option Button -->
192
+ <div class="form-row">
193
+ <a href="#" class="editor-button editor-button-small" id="node-input-add-option" style="margin-top:4px; margin-left:103px;"><i class="fa fa-plus"></i> <span>action</span></a>
194
+ </div>
183
195
 
184
- <div class="form-row">
185
- <label for="node-input-waiting_title"><i class="fa fa-hand"></i>Title for waiting text.</label>
186
- <input type="text" id="node-input-waiting_title">
187
- </div>
188
- <div class="form-row">
189
- <label for="node-input-waiting_info"><i class="fa fa-hand"></i>Text for waiting text.</label>
190
- <input type="text" id="node-input-waiting_info">
191
- </div>
196
+ <div class="form-row">
197
+ <label for="node-input-waiting_title"><i class="fa fa-hand"></i>Title for waiting text.</label>
198
+ <input type="text" id="node-input-waiting_title">
199
+ </div>
200
+ <div class="form-row">
201
+ <label for="node-input-waiting_info"><i class="fa fa-hand"></i>Text for waiting text.</label>
202
+ <input type="text" id="node-input-waiting_info">
203
+ </div>
192
204
  </script>
package/package.json CHANGED
@@ -1,85 +1,85 @@
1
1
  {
2
- "name": "@5minds/node-red-dashboard-2-processcube-dynamic-form",
3
- "version": "1.0.15",
4
- "description": "The ui component for the ProcessCube dynamic-form",
5
- "keywords": [
6
- "processcube",
7
- "dynamic-form",
8
- "node-red",
9
- "node-red-dashboard-2"
10
- ],
11
- "repository": {
12
- "type": "git",
13
- "url": "https://github.com/5minds/.gitnode-red-dashboard-2-processcube-dynamic-form"
14
- },
15
- "license": "Apache-2.0",
16
- "author": {
17
- "name": "Martin Moellenbeck",
18
- "url": "https://github.com/moellenbeck"
19
- },
20
- "contributors": [
21
- {
22
- "name": "Robin Lenz",
23
- "url": "https://github.com/roblen45"
2
+ "name": "@5minds/node-red-dashboard-2-processcube-dynamic-form",
3
+ "version": "1.0.16",
4
+ "description": "The ui component for the ProcessCube dynamic-form",
5
+ "keywords": [
6
+ "processcube",
7
+ "dynamic-form",
8
+ "node-red",
9
+ "node-red-dashboard-2"
10
+ ],
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/5minds/.gitnode-red-dashboard-2-processcube-dynamic-form"
24
14
  },
25
- {
26
- "name": "Luis Thieme",
27
- "url": "https://github.com/luisthieme"
28
- }
29
- ],
30
- "exports": {
31
- "import": "./resources/dynamic-form.esm.js",
32
- "require": "./resources/dynamic-form.umd.js"
33
- },
34
- "files": [
35
- "dist/*",
36
- "nodes/*",
37
- "ui/*",
38
- "resources/*"
39
- ],
40
- "scripts": {
41
- "build": "vite build",
42
- "build:dev": "NODE_ENV=development vite build",
43
- "dev": "NODE_ENV=development vite build --watch",
44
- "dev:prod": "vite build --watch",
45
- "lint": "npm run lint:js && npm run lint:package",
46
- "lint:fix": "npm run lint:js:fix && npm run lint:package:fix",
47
- "lint:js": "eslint --ext .js,.vue,.cjs,.mjs .",
48
- "lint:js:fix": "yarn lint:js --fix",
49
- "lint:package": "sort-package-json --check 'package.json'",
50
- "lint:package:fix": "sort-package-json 'package.json'"
51
- },
52
- "dependencies": {
53
- "to-title-case": "^1.0.0",
54
- "vue": "^3.3.8",
55
- "vuex": "^4.1.0"
56
- },
57
- "devDependencies": {
58
- "@vitejs/plugin-vue": "^4.5.0",
59
- "eslint": "^8.53.0",
60
- "eslint-config-standard": "^17.1.0",
61
- "eslint-plugin-import": "^2.29.0",
62
- "eslint-plugin-n": "^16.3.1",
63
- "eslint-plugin-vue": "^9.18.1",
64
- "vite": "^5.0.13",
65
- "vite-plugin-css-injected-by-js": "^3.3.0"
66
- },
67
- "engines": {
68
- "node": ">=14"
69
- },
70
- "node-red": {
71
- "version": ">=3.0.0",
72
- "nodes": {
73
- "ui-dynamic-form": "nodes/dynamic-form.js"
74
- }
75
- },
76
- "node-red-dashboard-2": {
77
- "version": "1.0.0",
78
- "widgets": {
79
- "ui-dynamic-form": {
80
- "output": "ui-dynamic-form.umd.js",
81
- "component": "DynamicForm"
82
- }
15
+ "license": "Apache-2.0",
16
+ "author": {
17
+ "name": "Martin Moellenbeck",
18
+ "url": "https://github.com/moellenbeck"
19
+ },
20
+ "contributors": [
21
+ {
22
+ "name": "Robin Lenz",
23
+ "url": "https://github.com/roblen45"
24
+ },
25
+ {
26
+ "name": "Luis Thieme",
27
+ "url": "https://github.com/luisthieme"
28
+ }
29
+ ],
30
+ "exports": {
31
+ "import": "./resources/dynamic-form.esm.js",
32
+ "require": "./resources/dynamic-form.umd.js"
33
+ },
34
+ "files": [
35
+ "dist/*",
36
+ "nodes/*",
37
+ "ui/*",
38
+ "resources/*"
39
+ ],
40
+ "scripts": {
41
+ "build": "vite build",
42
+ "build:dev": "NODE_ENV=development vite build",
43
+ "dev": "NODE_ENV=development vite build --watch",
44
+ "dev:prod": "vite build --watch",
45
+ "lint": "npm run lint:js && npm run lint:package",
46
+ "lint:fix": "npm run lint:js:fix && npm run lint:package:fix",
47
+ "lint:js": "eslint --ext .js,.vue,.cjs,.mjs .",
48
+ "lint:js:fix": "yarn lint:js --fix",
49
+ "lint:package": "sort-package-json --check 'package.json'",
50
+ "lint:package:fix": "sort-package-json 'package.json'"
51
+ },
52
+ "dependencies": {
53
+ "to-title-case": "^1.0.0",
54
+ "vue": "^3.3.8",
55
+ "vuex": "^4.1.0"
56
+ },
57
+ "devDependencies": {
58
+ "@vitejs/plugin-vue": "^4.5.0",
59
+ "eslint": "^8.53.0",
60
+ "eslint-config-standard": "^17.1.0",
61
+ "eslint-plugin-import": "^2.29.0",
62
+ "eslint-plugin-n": "^16.3.1",
63
+ "eslint-plugin-vue": "^9.18.1",
64
+ "vite": "^5.0.13",
65
+ "vite-plugin-css-injected-by-js": "^3.3.0"
66
+ },
67
+ "engines": {
68
+ "node": ">=14"
69
+ },
70
+ "node-red": {
71
+ "version": ">=3.0.0",
72
+ "nodes": {
73
+ "ui-dynamic-form": "nodes/dynamic-form.js"
74
+ }
75
+ },
76
+ "node-red-dashboard-2": {
77
+ "version": "1.0.0",
78
+ "widgets": {
79
+ "ui-dynamic-form": {
80
+ "output": "ui-dynamic-form.umd.js",
81
+ "component": "DynamicForm"
82
+ }
83
+ }
83
84
  }
84
- }
85
85
  }
@@ -1,2 +1,2 @@
1
- (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode(".dynamic-form-wrapper[data-v-37f46fd0]{padding:10px;margin:10px;border:1px solid black}.dynamic-form-class[data-v-37f46fd0]{color:green;font-weight:700}h1[data-v-37f46fd0]{margin-bottom:10px}h2[data-v-37f46fd0]{margin-top:1.5rem;margin-bottom:.75rem}h3[data-v-37f46fd0]{margin-top:1rem}p[data-v-37f46fd0]{margin-bottom:5px}ul li[data-v-37f46fd0]{list-style-type:circle;list-style-position:inside;margin-left:15px}pre[data-v-37f46fd0]{padding:12px;margin:12px;background-color:#eee}code[data-v-37f46fd0]{font-size:.825rem;color:#ae0000}")),document.head.appendChild(e)}}catch(a){console.error("vite-plugin-css-injected-by-js",a)}})();
2
- (function(n,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue"),require("vuex")):typeof define=="function"&&define.amd?define(["exports","vue","vuex"],e):(n=typeof globalThis<"u"?globalThis:n||self,e(n["ui-dynamic-form"]={},n.Vue,n.vuex))})(this,function(n,e,p){"use strict";const u=(t,o)=>{const s=t.__vccOpts||t;for(const[l,r]of o)s[l]=r;return s},f={name:"DynamicForm",inject:["$socket"],props:{id:{type:String,required:!0},props:{type:Object,default:()=>({})},state:{type:Object,default:()=>({enabled:!1,visible:!1})}},setup(t){console.info("DynamicForm setup with:",t),console.debug("Vue function loaded correctly",e.markRaw)},data(){return{actions:[],form:{},formData:{}}},computed:{...p.mapState("data",["messages"]),waiting_title(){return this.props.waiting_title||"Warten auf den Usertask..."},waiting_info(){return this.props.waiting_info||"Der Usertask wird automatisch angezeigt, wenn ein entsprechender Task vorhanden ist."}},mounted(){this.$socket.on("widget-load:"+this.id,t=>{this.init(),this.$store.commit("data/bind",{widgetId:this.id,msg:t})}),this.$socket.on("msg-input:"+this.id,t=>{this.init(),t.payload&&t.payload.userTask&&t.payload.userTask.startToken&&(this.formData={...t.payload.userTask.startToken},console.info(this.formData)),this.$store.commit("data/bind",{widgetId:this.id,msg:t})}),this.$socket.emit("widget-load",this.id)},unmounted(){var t,o;(t=this.$socket)==null||t.off("widget-load"+this.id),(o=this.$socket)==null||o.off("msg-input:"+this.id)},methods:{hasUserTask(){return this.messages&&this.messages[this.id]&&this.messages[this.id].payload.userTask},userTask(){return this.hasUserTask()?this.messages[this.id].payload.userTask:{}},fields(){return(this.hasUserTask()?this.userTask().userTaskConfig.formFields:[]).map(s=>({...s,component:k(s.type),items:h(s.type,s)}))},hasFields(){return this.messages&&this.messages[this.id]&&this.messages[this.id].payload.userTask!==void 0},send(t,o){const s=[];s[o]=t,console.info(s),this.$socket.emit("widget-action",this.id,s)},init(){this.actions=this.props.options},actionFn(t){this.send({payload:{formData:this.formData,userTask:this.userTask()}},this.actions.findIndex(o=>o.label===t))}}};function h(t,o){return t==="enum"?o.enumValues.map(s=>({title:s.name,value:s.id})):null}function k(t){switch(t){case"string":return"v-text-field";case"long":case"date":return"v-text-field";case"enum":return"v-select";case"boolean":return"v-checkbox";case"text":return"v-text-field";case"select":return"v-select";case"checkbox":return"v-checkbox";case"radio":return"v-radio";case"switch":return"v-switch";case"slider":return"v-slider";case"time":return"v-time-picker";case"datetime":return"v-datetime-picker";case"color":return"v-color-picker";case"file":return"v-file-input";case"textarea":return"v-textarea";case"password":return"v-text-field";case"number":return"v-text-field";case"email":return"v-text-field";case"tel":return"v-text-field";case"url":return"v-text-field";default:return"v-text-field"}}const _={className:"dynamic-form-wrapper"},y={key:0},x={key:1};function g(t,o,s,l,r,a){const T=e.resolveComponent("v-col"),d=e.resolveComponent("v-row"),b=e.resolveComponent("v-btn"),B=e.resolveComponent("v-form"),C=e.resolveComponent("v-alert");return e.openBlock(),e.createElementBlock("div",_,[a.hasFields()?(e.openBlock(),e.createElementBlock("p",y,[e.createVNode(B,{ref:"form",modelValue:r.form,"onUpdate:modelValue":o[0]||(o[0]=i=>r.form=i)},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(a.fields(),(i,c)=>(e.openBlock(),e.createBlock(d,{key:c},{default:e.withCtx(()=>[e.createVNode(T,{cols:"12"},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(i.component),{id:i.id,modelValue:r.formData[i.id],"onUpdate:modelValue":m=>r.formData[i.id]=m,required:i.required,items:i.items,label:i.label},null,8,["id","modelValue","onUpdate:modelValue","required","items","label"]))]),_:2},1024)]),_:2},1024))),128)),e.createVNode(d,{style:{display:"flex",gap:"8px",padding:"12px"}},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(r.actions,(i,c)=>(e.openBlock(),e.createElementBlock("div",{key:c,style:{"flex-grow":"1"}},[(e.openBlock(),e.createBlock(b,{key:c,style:{width:"100%"},onClick:m=>a.actionFn(i.label)},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(i.label),1)]),_:2},1032,["onClick"]))]))),128))]),_:1})]),_:1},8,["modelValue"])])):(e.openBlock(),e.createElementBlock("p",x,[e.createVNode(C,{text:a.waiting_info,title:a.waiting_title},null,8,["text","title"])]))])}const w=u(f,[["render",g],["__scopeId","data-v-37f46fd0"]]);n.DynamicForm=w,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})});
1
+ (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode(".dynamic-form-wrapper[data-v-9cd04719]{padding:10px;margin:10px;border:1px solid black}.dynamic-form-class[data-v-9cd04719]{color:green;font-weight:700}h1[data-v-9cd04719]{margin-bottom:10px}h2[data-v-9cd04719]{margin-top:1.5rem;margin-bottom:.75rem}h3[data-v-9cd04719]{margin-top:1rem}p[data-v-9cd04719]{margin-bottom:5px}ul li[data-v-9cd04719]{list-style-type:circle;list-style-position:inside;margin-left:15px}pre[data-v-9cd04719]{padding:12px;margin:12px;background-color:#eee}code[data-v-9cd04719]{font-size:.825rem;color:#ae0000}")),document.head.appendChild(e)}}catch(a){console.error("vite-plugin-css-injected-by-js",a)}})();
2
+ (function(n,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue"),require("vuex")):typeof define=="function"&&define.amd?define(["exports","vue","vuex"],e):(n=typeof globalThis<"u"?globalThis:n||self,e(n["ui-dynamic-form"]={},n.Vue,n.vuex))})(this,function(n,e,h){"use strict";const u=(t,s)=>{const r=t.__vccOpts||t;for(const[d,i]of s)r[d]=i;return r},f={name:"DynamicForm",inject:["$socket"],props:{id:{type:String,required:!0},props:{type:Object,default:()=>({})},state:{type:Object,default:()=>({enabled:!1,visible:!1})}},setup(t){console.info("DynamicForm setup with:",t),console.debug("Vue function loaded correctly",e.markRaw)},data(){return{actions:[],form:{},formData:{},msg:{},taskInput:{},error:!1,errorMsg:""}},computed:{...h.mapState("data",["messages"]),waiting_title(){return this.props.waiting_title||"Warten auf den Usertask..."},waiting_info(){return this.props.waiting_info||"Der Usertask wird automatisch angezeigt, wenn ein entsprechender Task vorhanden ist."}},mounted(){this.$socket.on("widget-load:"+this.id,t=>{this.init(),this.$store.commit("data/bind",{widgetId:this.id,msg:t})}),this.$socket.on("msg-input:"+this.id,t=>{this.init(),this.msg=t,t.payload&&t.payload.userTask&&(this.taskInput=t.payload.userTask),t.payload&&t.payload.userTask&&t.payload.userTask.startToken&&(this.formData={...t.payload.userTask.startToken},console.info(this.formData)),this.$store.commit("data/bind",{widgetId:this.id,msg:t})}),this.$socket.emit("widget-load",this.id)},unmounted(){var t,s;(t=this.$socket)==null||t.off("widget-load"+this.id),(s=this.$socket)==null||s.off("msg-input:"+this.id)},methods:{hasUserTask(){return this.messages&&this.messages[this.id]&&this.messages[this.id].payload.userTask},userTask(){return this.hasUserTask()?this.messages[this.id].payload.userTask:{}},fields(){return(this.hasUserTask()?this.userTask().userTaskConfig.formFields:[]).map(r=>({...r,component:y(r.type),items:k(r.type,r)}))},hasFields(){return this.messages&&this.messages[this.id]&&this.messages[this.id].payload.userTask!==void 0},send(t,s){const r=[];r[s]=t,this.$socket.emit("widget-action",this.id,r)},init(){this.actions=this.props.options},actionFn(t){this.checkCondition(t.condition)?(this.showError(!1,""),this.send({payload:{formData:this.formData,userTask:this.userTask()}},this.actions.findIndex(s=>s.label===t.label))):this.showError(!0,t.errorMessage)},checkCondition(t){try{return!!Function("fields","userTask","msg",'"use strict"; return ('+t+")")(this.formData,this.taskInput,this.msg)}catch(s){return console.error("Error while evaluating condition: "+s),!1}},showError(t,s){this.error=t,this.errorMsg=s}}};function k(t,s){return t==="enum"?s.enumValues.map(r=>({title:r.name,value:r.id})):null}function y(t){switch(t){case"string":return"v-text-field";case"long":case"date":return"v-text-field";case"enum":return"v-select";case"boolean":return"v-checkbox";case"text":return"v-text-field";case"select":return"v-select";case"checkbox":return"v-checkbox";case"radio":return"v-radio";case"switch":return"v-switch";case"slider":return"v-slider";case"time":return"v-time-picker";case"datetime":return"v-datetime-picker";case"color":return"v-color-picker";case"file":return"v-file-input";case"textarea":return"v-textarea";case"password":return"v-text-field";case"number":return"v-text-field";case"email":return"v-text-field";case"tel":return"v-text-field";case"url":return"v-text-field";default:return"v-text-field"}}const _={className:"dynamic-form-wrapper"},g={key:0},x={key:1};function w(t,s,r,d,i,a){const b=e.resolveComponent("v-col"),l=e.resolveComponent("v-row"),m=e.resolveComponent("v-alert"),B=e.resolveComponent("v-btn"),C=e.resolveComponent("v-form");return e.openBlock(),e.createElementBlock("div",_,[a.hasFields()?(e.openBlock(),e.createElementBlock("p",g,[e.createVNode(C,{ref:"form",modelValue:i.form,"onUpdate:modelValue":s[0]||(s[0]=o=>i.form=o)},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(a.fields(),(o,c)=>(e.openBlock(),e.createBlock(l,{key:c},{default:e.withCtx(()=>[e.createVNode(b,{cols:"12"},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(o.component),{id:o.id,modelValue:i.formData[o.id],"onUpdate:modelValue":p=>i.formData[o.id]=p,required:o.required,items:o.items,label:o.label},null,8,["id","modelValue","onUpdate:modelValue","required","items","label"]))]),_:2},1024)]),_:2},1024))),128)),e.createVNode(l,{style:{padding:"12px"}},{default:e.withCtx(()=>[i.error?(e.openBlock(),e.createBlock(m,{key:0,type:"error"},{default:e.withCtx(()=>[e.createTextVNode("Error: "+e.toDisplayString(i.errorMsg),1)]),_:1})):e.createCommentVNode("",!0)]),_:1}),e.createVNode(l,{style:{display:"flex",gap:"8px",padding:"12px"}},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(i.actions,(o,c)=>(e.openBlock(),e.createElementBlock("div",{key:c,style:{"flex-grow":"1"}},[(e.openBlock(),e.createBlock(B,{key:c,style:{width:"100%"},onClick:p=>a.actionFn(o)},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(o.label),1)]),_:2},1032,["onClick"]))]))),128))]),_:1})]),_:1},8,["modelValue"])])):(e.openBlock(),e.createElementBlock("p",x,[e.createVNode(m,{text:a.waiting_info,title:a.waiting_title},null,8,["text","title"])]))])}const T=u(f,[["render",w],["__scopeId","data-v-9cd04719"]]);n.DynamicForm=T,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})});
@@ -1,226 +1,241 @@
1
1
  <template>
2
- <!-- Component must be wrapped in a block so props such as className and style can be passed in from parent -->
3
- <div className="dynamic-form-wrapper">
4
- <p v-if="hasFields()">
5
- <v-form ref="form" v-model="form">
6
- <v-row v-for="(field, index) in fields()" :key="index">
7
- <v-col cols="12">
8
- <component
9
- :is="field.component"
10
- :id="field.id"
11
- v-model="formData[field.id]"
12
- :required="field.required"
13
- :items="field.items"
14
- :label="field.label" />
15
- </v-col>
16
- </v-row>
17
-
18
- <v-row style="display: flex; gap: 8px; padding: 12px">
19
- <div
20
- v-for="(action, index) in actions"
21
- :key="index"
22
- style="flex-grow: 1">
23
- <v-btn
24
- :key="index"
25
- style="width: 100%"
26
- @click="actionFn(action.label)">
27
- {{ action.label }}
28
- </v-btn>
29
- </div>
30
- </v-row>
31
- </v-form>
32
- </p>
33
- <p v-else>
34
- <v-alert :text="waiting_info" :title="waiting_title" />
35
- </p>
36
- </div>
2
+ <!-- Component must be wrapped in a block so props such as className and style can be passed in from parent -->
3
+ <div className="dynamic-form-wrapper">
4
+ <p v-if="hasFields()">
5
+ <v-form ref="form" v-model="form">
6
+ <v-row v-for="(field, index) in fields()" :key="index">
7
+ <v-col cols="12">
8
+ <component
9
+ :is="field.component"
10
+ :id="field.id"
11
+ v-model="formData[field.id]"
12
+ :required="field.required"
13
+ :items="field.items"
14
+ :label="field.label"
15
+ />
16
+ </v-col>
17
+ </v-row>
18
+ <v-row style="padding: 12px">
19
+ <v-alert v-if="error" type="error">Error: {{ errorMsg }}</v-alert>
20
+ </v-row>
21
+ <v-row style="display: flex; gap: 8px; padding: 12px">
22
+ <div v-for="(action, index) in actions" :key="index" style="flex-grow: 1">
23
+ <v-btn :key="index" style="width: 100%" @click="actionFn(action)">
24
+ {{ action.label }}
25
+ </v-btn>
26
+ </div>
27
+ </v-row>
28
+ </v-form>
29
+ </p>
30
+ <p v-else>
31
+ <v-alert :text="waiting_info" :title="waiting_title" />
32
+ </p>
33
+ </div>
37
34
  </template>
38
35
 
39
36
  <script>
40
- import { markRaw } from "vue";
41
- import { mapState } from "vuex";
37
+ import { markRaw } from 'vue';
38
+ import { mapState } from 'vuex';
42
39
 
43
40
  export default {
44
- name: "DynamicForm",
45
- inject: ["$socket"],
46
- props: {
47
- /* do not remove entries from this - Dashboard's Layout Manager's will pass this data to your component */
48
- id: { type: String, required: true },
49
- props: { type: Object, default: () => ({}) },
50
- state: {
51
- type: Object,
52
- default: () => ({ enabled: false, visible: false }),
41
+ name: 'DynamicForm',
42
+ inject: ['$socket'],
43
+ props: {
44
+ /* do not remove entries from this - Dashboard's Layout Manager's will pass this data to your component */
45
+ id: { type: String, required: true },
46
+ props: { type: Object, default: () => ({}) },
47
+ state: {
48
+ type: Object,
49
+ default: () => ({ enabled: false, visible: false }),
50
+ },
51
+ },
52
+ setup(props) {
53
+ console.info('DynamicForm setup with:', props);
54
+ console.debug('Vue function loaded correctly', markRaw);
53
55
  },
54
- },
55
- setup(props) {
56
- console.info("DynamicForm setup with:", props);
57
- console.debug("Vue function loaded correctly", markRaw);
58
- },
59
- data() {
60
- return {
61
- actions: [],
62
- form: {},
63
- formData: {},
64
- };
65
- },
66
- computed: {
67
- ...mapState("data", ["messages"]),
68
- waiting_title() {
69
- return this.props.waiting_title || "Warten auf den Usertask..."
56
+ data() {
57
+ return {
58
+ actions: [],
59
+ form: {},
60
+ formData: {},
61
+ msg: {},
62
+ taskInput: {},
63
+ error: false,
64
+ errorMsg: '',
65
+ };
70
66
  },
71
- waiting_info() {
72
- return (
73
- this.props.waiting_info ||
74
- "Der Usertask wird automatisch angezeigt, wenn ein entsprechender Task vorhanden ist."
75
- );
67
+ computed: {
68
+ ...mapState('data', ['messages']),
69
+ waiting_title() {
70
+ return this.props.waiting_title || 'Warten auf den Usertask...';
71
+ },
72
+ waiting_info() {
73
+ return (
74
+ this.props.waiting_info ||
75
+ 'Der Usertask wird automatisch angezeigt, wenn ein entsprechender Task vorhanden ist.'
76
+ );
77
+ },
76
78
  },
77
- },
78
- mounted() {
79
- this.$socket.on("widget-load:" + this.id, (msg) => {
80
- this.init()
79
+ mounted() {
80
+ this.$socket.on('widget-load:' + this.id, (msg) => {
81
+ this.init();
81
82
 
82
- this.$store.commit("data/bind", {
83
- widgetId: this.id,
84
- msg,
85
- });
86
- });
87
- this.$socket.on("msg-input:" + this.id, (msg) => {
88
- // store the latest message in our client-side vuex store when we receive a new message
89
- this.init()
83
+ this.$store.commit('data/bind', {
84
+ widgetId: this.id,
85
+ msg,
86
+ });
87
+ });
88
+ this.$socket.on('msg-input:' + this.id, (msg) => {
89
+ // store the latest message in our client-side vuex store when we receive a new message
90
+ this.init();
90
91
 
91
- if (msg.payload && msg.payload.userTask && msg.payload.userTask.startToken) {
92
- //this.formData = { ...msg.payload.userTask.startToken.formData };
93
- this.formData = { ...msg.payload.userTask.startToken }
94
- console.info(this.formData)
95
- }
92
+ this.msg = msg;
96
93
 
97
- this.$store.commit("data/bind", {
98
- widgetId: this.id,
99
- msg,
100
- });
101
- });
102
- // tell Node-RED that we're loading a new instance of this widget
103
- this.$socket.emit("widget-load", this.id);
104
- },
105
- unmounted() {
106
- /* Make sure, any events you subscribe to on SocketIO are unsubscribed to here */
107
- this.$socket?.off("widget-load" + this.id);
108
- this.$socket?.off("msg-input:" + this.id);
109
- },
110
- methods: {
111
- hasUserTask() {
112
- return (
113
- this.messages &&
114
- this.messages[this.id] &&
115
- this.messages[this.id].payload.userTask
116
- );
117
- },
118
- userTask() {
119
- return this.hasUserTask() ? this.messages[this.id].payload.userTask : {};
120
- },
121
- fields() {
122
- const aFields = this.hasUserTask()
123
- ? this.userTask().userTaskConfig.formFields
124
- : [];
94
+ if (msg.payload && msg.payload.userTask) {
95
+ this.taskInput = msg.payload.userTask;
96
+ }
125
97
 
126
- const fieldMap = aFields.map((field) => ({
127
- ...field,
128
- component: mapFieldTypes(field.type),
129
- items: mapItems(field.type, field),
130
- }));
98
+ if (msg.payload && msg.payload.userTask && msg.payload.userTask.startToken) {
99
+ //this.formData = { ...msg.payload.userTask.startToken.formData };
100
+ this.formData = { ...msg.payload.userTask.startToken };
101
+ console.info(this.formData);
102
+ }
131
103
 
132
- return fieldMap;
104
+ this.$store.commit('data/bind', {
105
+ widgetId: this.id,
106
+ msg,
107
+ });
108
+ });
109
+ // tell Node-RED that we're loading a new instance of this widget
110
+ this.$socket.emit('widget-load', this.id);
133
111
  },
134
- hasFields() {
135
- return (
136
- this.messages &&
137
- this.messages[this.id] &&
138
- this.messages[this.id].payload.userTask !== undefined
139
- );
112
+ unmounted() {
113
+ /* Make sure, any events you subscribe to on SocketIO are unsubscribed to here */
114
+ this.$socket?.off('widget-load' + this.id);
115
+ this.$socket?.off('msg-input:' + this.id);
140
116
  },
141
- /*
117
+ methods: {
118
+ hasUserTask() {
119
+ return this.messages && this.messages[this.id] && this.messages[this.id].payload.userTask;
120
+ },
121
+ userTask() {
122
+ return this.hasUserTask() ? this.messages[this.id].payload.userTask : {};
123
+ },
124
+ fields() {
125
+ const aFields = this.hasUserTask() ? this.userTask().userTaskConfig.formFields : [];
126
+
127
+ const fieldMap = aFields.map((field) => ({
128
+ ...field,
129
+ component: mapFieldTypes(field.type),
130
+ items: mapItems(field.type, field),
131
+ }));
132
+
133
+ return fieldMap;
134
+ },
135
+ hasFields() {
136
+ return this.messages && this.messages[this.id] && this.messages[this.id].payload.userTask !== undefined;
137
+ },
138
+ /*
142
139
  widget-action just sends a msg to Node-RED, it does not store the msg state server-side
143
140
  alternatively, you can use widget-change, which will also store the msg in the Node's datastore
144
141
  */
145
- send(msg, index) {
146
- const msgArr = [];
147
- msgArr[index] = msg;
148
- console.info(msgArr);
149
- this.$socket.emit("widget-action", this.id, msgArr);
150
- },
151
- init() {
152
- this.actions = this.props.options;
153
- },
154
- actionFn(action) {
155
- this.send(
156
- { payload: { formData: this.formData, userTask: this.userTask() } },
157
- this.actions.findIndex((element) => element.label === action)
158
- );
142
+ send(msg, index) {
143
+ const msgArr = [];
144
+ msgArr[index] = msg;
145
+ this.$socket.emit('widget-action', this.id, msgArr);
146
+ },
147
+ init() {
148
+ this.actions = this.props.options;
149
+ },
150
+ actionFn(action) {
151
+ if (this.checkCondition(action.condition)) {
152
+ this.showError(false, '');
153
+ this.send(
154
+ { payload: { formData: this.formData, userTask: this.userTask() } },
155
+ this.actions.findIndex((element) => element.label === action.label)
156
+ );
157
+ } else {
158
+ this.showError(true, action.errorMessage);
159
+ }
160
+ },
161
+ checkCondition(condition) {
162
+ try {
163
+ const func = Function('fields', 'userTask', 'msg', '"use strict"; return (' + condition + ')');
164
+ const result = func(this.formData, this.taskInput, this.msg);
165
+ return Boolean(result);
166
+ } catch (err) {
167
+ console.error('Error while evaluating condition: ' + err);
168
+ return false;
169
+ }
170
+ },
171
+ showError(bool, errMsg) {
172
+ this.error = bool;
173
+ this.errorMsg = errMsg;
174
+ },
159
175
  },
160
- },
161
176
  };
162
177
 
163
178
  function mapItems(type, field) {
164
- if (type === "enum") {
165
- return field.enumValues.map((enumValue) => ({
166
- title: enumValue.name,
167
- value: enumValue.id,
168
- }));
169
- } else {
170
- return null;
171
- }
179
+ if (type === 'enum') {
180
+ return field.enumValues.map((enumValue) => ({
181
+ title: enumValue.name,
182
+ value: enumValue.id,
183
+ }));
184
+ } else {
185
+ return null;
186
+ }
172
187
  }
173
188
 
174
189
  function mapFieldTypes(fieldType) {
175
- switch (fieldType) {
176
- case "string":
177
- return "v-text-field";
178
- case "long":
179
- case "date":
180
- return "v-text-field";
181
- case "enum":
182
- return "v-select";
183
- case "boolean":
184
- return "v-checkbox";
185
- case "text":
186
- return "v-text-field";
187
- case "select":
188
- return "v-select";
189
- case "checkbox":
190
- return "v-checkbox";
191
- case "radio":
192
- return "v-radio";
193
- case "switch":
194
- return "v-switch";
195
- case "slider":
196
- return "v-slider";
197
- case "time":
198
- return "v-time-picker";
199
- case "datetime":
200
- return "v-datetime-picker";
201
- case "color":
202
- return "v-color-picker";
203
- case "file":
204
- return "v-file-input";
205
- case "textarea":
206
- return "v-textarea";
207
- case "password":
208
- return "v-text-field";
209
- case "number":
210
- return "v-text-field";
211
- case "email":
212
- return "v-text-field";
213
- case "tel":
214
- return "v-text-field";
215
- case "url":
216
- return "v-text-field";
217
- default:
218
- return "v-text-field";
219
- }
190
+ switch (fieldType) {
191
+ case 'string':
192
+ return 'v-text-field';
193
+ case 'long':
194
+ case 'date':
195
+ return 'v-text-field';
196
+ case 'enum':
197
+ return 'v-select';
198
+ case 'boolean':
199
+ return 'v-checkbox';
200
+ case 'text':
201
+ return 'v-text-field';
202
+ case 'select':
203
+ return 'v-select';
204
+ case 'checkbox':
205
+ return 'v-checkbox';
206
+ case 'radio':
207
+ return 'v-radio';
208
+ case 'switch':
209
+ return 'v-switch';
210
+ case 'slider':
211
+ return 'v-slider';
212
+ case 'time':
213
+ return 'v-time-picker';
214
+ case 'datetime':
215
+ return 'v-datetime-picker';
216
+ case 'color':
217
+ return 'v-color-picker';
218
+ case 'file':
219
+ return 'v-file-input';
220
+ case 'textarea':
221
+ return 'v-textarea';
222
+ case 'password':
223
+ return 'v-text-field';
224
+ case 'number':
225
+ return 'v-text-field';
226
+ case 'email':
227
+ return 'v-text-field';
228
+ case 'tel':
229
+ return 'v-text-field';
230
+ case 'url':
231
+ return 'v-text-field';
232
+ default:
233
+ return 'v-text-field';
234
+ }
220
235
  }
221
236
  </script>
222
237
 
223
238
  <style scoped>
224
239
  /* CSS is auto scoped, but using named classes is still recommended */
225
- @import "../stylesheets/dynamic-form.css";
240
+ @import '../stylesheets/dynamic-form.css';
226
241
  </style>