@record-evolution/widget-form 1.0.10 → 1.0.12

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,37 +1,55 @@
1
1
  {
2
2
  "title": "InputData",
3
+ "description": "A form widget for collecting user input and storing it in database tables. Use this widget to create data entry interfaces for manual input, configuration settings, user feedback, or any scenario requiring structured data collection. Supports various field types including text, numbers, dropdowns, checkboxes, textareas, and datetime pickers. Each field maps to a database column, enabling direct data persistence. Can display as a button-triggered modal or inline form.",
3
4
  "type": "object",
4
5
  "properties": {
5
6
  "title": {
6
7
  "title": "Title",
8
+ "description": "The main heading displayed at the top of the form. Use to describe the form's purpose (e.g., 'Add New Device', 'Submit Feedback', 'Configuration Settings').",
7
9
  "order": 1,
8
10
  "dataDrivenDisabled": true,
9
11
  "type": "string"
10
12
  },
11
13
  "subTitle": {
12
14
  "title": "Subtitle",
15
+ "description": "Secondary text displayed below the title. Use for instructions, context, or additional information about the form.",
13
16
  "order": 2,
14
17
  "dataDrivenDisabled": true,
15
18
  "type": "string"
16
19
  },
20
+ "deleteFlagColumn": {
21
+ "title": "Delete-Flag Column",
22
+ "description": "The target table column used to mark records as deleted when the delete button is clicked. This MUST be a boolean column. If the target table has such a deleted_flag column, it should be specified here regardless of the delete button setting.",
23
+ "dataDrivenDisabled": true,
24
+ "type": "targetColumn",
25
+ "order": 3
26
+ },
27
+ "deleteButton": {
28
+ "title": "Show Delete Button",
29
+ "description": "When enabled, shows a delete button that allows users to remove existing entries.",
30
+ "dataDrivenDisabled": true,
31
+ "type": "boolean",
32
+ "order": 4
33
+ },
17
34
  "formButton": {
18
35
  "title": "Form Open Button",
19
- "description": "If checked, a button will be shown to open the form. If unchecked, the form will be shown directly.",
36
+ "description": "When enabled, shows a button that opens the form in a modal dialog when clicked. When disabled, the form fields are displayed directly in the widget area. Use button mode for space-constrained layouts or optional data entry.",
20
37
  "dataDrivenDisabled": true,
21
38
  "type": "boolean",
22
- "order": 3
39
+ "order": 5
23
40
  },
24
41
  "formFields": {
25
42
  "title": "Form Fields",
26
- "description": "Add fields and define how they should be stored.",
43
+ "description": "Array of input fields that make up the form. Each field defines its type, validation rules, and target database column for storage. Fields are rendered in the order specified.",
27
44
  "type": "array",
28
- "order": 4,
45
+ "order": 6,
29
46
  "dataDrivenDisabled": true,
30
47
  "items": {
31
48
  "type": "object",
32
49
  "properties": {
33
50
  "label": {
34
51
  "title": "Label",
52
+ "description": "The text label displayed next to this form field. Should clearly describe what data the user should enter.",
35
53
  "type": "string",
36
54
  "dataDrivenDisabled": true,
37
55
  "required": true,
@@ -39,6 +57,7 @@
39
57
  },
40
58
  "type": {
41
59
  "title": "Field Type",
60
+ "description": "The input control type: 'dropdown' for selection from predefined options, 'textfield' for single-line text, 'numberfield' for numeric values, 'checkbox' for boolean yes/no, 'textarea' for multi-line text, 'datetime' for date and time selection.",
42
61
  "enum": ["dropdown", "textfield", "numberfield", "checkbox", "textarea", "datetime"],
43
62
  "type": "string",
44
63
  "dataDrivenDisabled": true,
@@ -48,76 +67,81 @@
48
67
  "hiddenField": {
49
68
  "title": "Hidden Field",
50
69
  "type": "boolean",
51
- "description": "If false, this field will be hidden in the form but still saved on submit.",
70
+ "description": "When enabled, this field is hidden from users but its value (typically a default or data-bound value) is still submitted with the form. Useful for including metadata, timestamps, or user IDs automatically.",
52
71
  "dataDrivenDisabled": true,
53
72
  "order": 3
54
73
  },
55
74
  "required": {
56
75
  "title": "Required",
57
76
  "type": "boolean",
58
- "description": "This field must be filled out before the form can be submitted. Ignored when a default value is provided.",
77
+ "description": "When enabled, users must fill out this field before the form can be submitted. The form will show a validation error if left empty. Ignored when a default value is provided.",
59
78
  "dataDrivenDisabled": true,
60
79
  "order": 4
61
80
  },
62
81
  "description": {
63
82
  "title": "Hint Text",
64
83
  "type": "string",
65
- "description": "This text will be shown as a description at the field.",
84
+ "description": "Helper text displayed below the field to guide users on what to enter. Use for format hints, examples, or clarifying instructions.",
66
85
  "dataDrivenDisabled": true,
67
86
  "order": 5
68
87
  },
69
88
  "targetColumn": {
70
89
  "title": "Target Column",
71
90
  "type": "targetColumn",
72
- "description": "The column in the target table where this field's data will be stored. This will be combined with all other fields in this form connected with the same target table.",
91
+ "description": "The database table and column where this field's value will be stored on form submission. Select from available tables and columns. All fields targeting the same table will be combined into a single row insert.",
73
92
  "dataDrivenDisabled": true,
74
93
  "required": true,
75
94
  "order": 6
76
95
  },
96
+ "preFilledValue": {
97
+ "title": "Pre-filled Value",
98
+ "description": "Pre-filled value for this field when the form loads. Can be a static value or bound to a data source.",
99
+ "type": "string",
100
+ "order": 7
101
+ },
77
102
  "defaultValue": {
78
103
  "title": "Default Value",
79
- "description": "This value will be used if the user does not provide a value.",
104
+ "description": "Default value for this field when the form loads. If the user does not provide a value, this default will be used. Can be a static value or bound to a data source.",
80
105
  "type": "string",
81
- "order": 7,
82
- "dataDrivenDisabled": true
106
+ "order": 8
83
107
  },
84
108
  "min": {
85
109
  "title": "Minimum Value",
86
110
  "type": "number",
87
- "description": "Minimum value for number fields.",
111
+ "description": "The minimum allowed numeric value for numberfield types. Values below this will fail validation.",
88
112
  "dataDrivenDisabled": true,
89
113
  "condition": {
90
114
  "relativePath": "../type",
91
115
  "showIfValueIn": ["numberfield"]
92
116
  },
93
- "order": 8
117
+ "order": 9
94
118
  },
95
119
  "max": {
96
120
  "title": "Maximum Value",
97
121
  "type": "number",
98
- "description": "Maximum value for number fields.",
122
+ "description": "The maximum allowed numeric value for numberfield types. Values above this will fail validation.",
99
123
  "dataDrivenDisabled": true,
100
124
  "condition": {
101
125
  "relativePath": "../type",
102
126
  "showIfValueIn": ["numberfield"]
103
127
  },
104
- "order": 9
128
+ "order": 10
105
129
  },
106
130
  "validation": {
107
131
  "title": "Validation Regex",
108
132
  "type": "string",
109
- "description": "Regular expression for validating text fields.",
133
+ "description": "A regular expression pattern to validate text input (e.g., '^[A-Z]{2}[0-9]{4}$' for format like 'AB1234'). Leave empty to accept any text.",
110
134
  "dataDrivenDisabled": true,
111
135
  "condition": {
112
136
  "relativePath": "../type",
113
137
  "showIfValueIn": ["textfield"]
114
138
  },
115
- "order": 10
139
+ "order": 11
116
140
  },
117
141
  "values": {
118
142
  "title": "Dropdown Values",
119
143
  "type": "array",
120
- "description": "List of values for the dropdown field.",
144
+ "description": "The list of selectable options for dropdown field types. Each option has a display label and a stored value.",
121
145
  "condition": {
122
146
  "relativePath": "../type",
123
147
  "showIfValueIn": ["dropdown"]
@@ -128,20 +152,20 @@
128
152
  "displayLabel": {
129
153
  "title": "Display Label",
130
154
  "type": "string",
131
- "description": "Label shown in the dropdown.",
155
+ "description": "The text shown to users in the dropdown list.",
132
156
  "required": true,
133
157
  "order": 1
134
158
  },
135
159
  "value": {
136
160
  "title": "Value",
137
161
  "type": "string",
138
- "description": "Value stored in the database.",
162
+ "description": "The actual value stored in the database when this option is selected. May differ from the display label.",
139
163
  "required": true,
140
164
  "order": 2
141
165
  }
142
166
  }
143
167
  },
144
- "order": 11
168
+ "order": 12
145
169
  }
146
170
  }
147
171
  }
@@ -67,6 +67,9 @@ export class WidgetForm extends LitElement {
67
67
 
68
68
  handleFormSubmit(event: Event) {
69
69
  event.preventDefault()
70
+ const submitter = (event as SubmitEvent).submitter as HTMLElement
71
+ const action = submitter?.getAttribute('value') ?? 'submit'
72
+
70
73
  const form = event.target as HTMLFormElement
71
74
  const formData = new FormData(form)
72
75
  const data = Object.fromEntries((formData as any).entries())
@@ -82,6 +85,15 @@ export class WidgetForm extends LitElement {
82
85
  )
83
86
  }
84
87
  })
88
+
89
+ if (this.inputData?.deleteFlagColumn)
90
+ submitData?.push({
91
+ swarm_app_databackend_key: this.inputData?.deleteFlagColumn?.swarm_app_databackend_key,
92
+ table_name: this.inputData?.deleteFlagColumn?.tablename,
93
+ column_name: this.inputData?.deleteFlagColumn?.column,
94
+ value: action === 'delete'
95
+ })
96
+
85
97
  this.dispatchEvent(
86
98
  new CustomEvent('data-submit', {
87
99
  detail: submitData,
@@ -110,6 +122,7 @@ export class WidgetForm extends LitElement {
110
122
  .name="column-${i}"
111
123
  .label="${field.label ?? ''}"
112
124
  .type="${field.type === 'numberfield' ? 'number' : 'text'}"
125
+ .value="${field.preFilledValue ?? ''}"
113
126
  .placeholder="${field.defaultValue ?? ''}"
114
127
  .pattern="${field.validation ?? ''}"
115
128
  supporting-text=${field.description ?? ''}
@@ -126,6 +139,7 @@ export class WidgetForm extends LitElement {
126
139
  .label="${field.label ?? ''}"
127
140
  style="width: 200px;"
128
141
  type="number"
142
+ .value="${field.preFilledValue ?? ''}"
129
143
  .placeholder="${field.defaultValue ?? ''}"
130
144
  step="any"
131
145
  min=${field.min ?? ''}
@@ -142,7 +156,7 @@ export class WidgetForm extends LitElement {
142
156
  <md-checkbox
143
157
  name="column-${i}"
144
158
  aria-label=${field.label ?? ''}
145
- ?checked=${field.defaultValue === 'true'}
159
+ ?checked=${(String(field.preFilledValue) ?? field.defaultValue) === 'true'}
146
160
  supporting-text=${field.description ?? ''}
147
161
  ?required=${field.required && !field.defaultValue}
148
162
  ></md-checkbox>
@@ -157,6 +171,7 @@ export class WidgetForm extends LitElement {
157
171
  .name="column-${i}"
158
172
  .label="${field.label ?? ''}"
159
173
  type="textarea"
174
+ .value="${field.preFilledValue ?? ''}"
160
175
  .placeholder="${field.defaultValue ?? ''}"
161
176
  rows="3"
162
177
  ?required=${field.required && !field.defaultValue}
@@ -181,7 +196,7 @@ export class WidgetForm extends LitElement {
181
196
  return html`
182
197
  <md-select-option
183
198
  .value="${val.value ?? ''}"
184
- ?selected="${val.value === field.defaultValue}"
199
+ ?selected="${val.value === (field.preFilledValue ?? field.defaultValue)}"
185
200
  >
186
201
  ${val.displayLabel}
187
202
  </md-select-option>
@@ -200,14 +215,33 @@ export class WidgetForm extends LitElement {
200
215
  style="width: 200px;"
201
216
  .label="${field.label ?? ''}"
202
217
  type="datetime-local"
203
- .value="${field.defaultValue ?? ''}"
218
+ .value="${field.preFilledValue ?? field.defaultValue ?? ''}"
204
219
  supporting-text=${field.description ?? ''}
205
220
  ?required=${field.required && !field.defaultValue}
206
221
  ></md-outlined-text-field>
207
222
  `
208
223
  }
209
224
 
225
+ resetForm() {
226
+ const form = this.shadowRoot?.querySelector('#form') as HTMLFormElement
227
+ if (!form) return
228
+ this.inputData?.formFields?.forEach((field, i) => {
229
+ const name = `column-${i}`
230
+ if (field.type === 'checkbox') {
231
+ const cb = form.querySelector(`md-checkbox[name="${name}"]`) as any
232
+ if (cb) cb.checked = field.preFilledValue === 'true'
233
+ } else if (field.type === 'dropdown') {
234
+ const select = form.querySelector(`md-outlined-select[name="${name}"]`) as any
235
+ if (select) select.value = field.preFilledValue ?? ''
236
+ } else {
237
+ const input = form.querySelector(`md-outlined-text-field[name="${name}"]`) as any
238
+ if (input) input.value = field.preFilledValue ?? ''
239
+ }
240
+ })
241
+ }
242
+
210
243
  cancelEdit(event: Event) {
244
+ this.resetForm()
211
245
  this.dialogOpen = false
212
246
  }
213
247
 
@@ -325,10 +359,37 @@ export class WidgetForm extends LitElement {
325
359
  --md-fab-container-color: #007bff;
326
360
  --md-fab-label-text-color: white;
327
361
  }
362
+
363
+ .delete-btn {
364
+ --md-filled-button-container-color: #d32f2f;
365
+ --md-filled-button-label-text-color: #fff;
366
+ --md-filled-button-hover-label-text-color: #fff;
367
+ --md-filled-button-focus-label-text-color: #fff;
368
+ --md-filled-button-pressed-label-text-color: #fff;
369
+ }
328
370
  `
329
371
 
330
372
  render() {
373
+ const fontColor = this.themeTitleColor
374
+ const bgColor = this.themeBgColor
375
+ const bgColorOpaque = bgColor?.startsWith('rgba')
376
+ ? bgColor.replace(/rgba\(([^)]+),\s*[\d.]+\)/, 'rgb($1)')
377
+ : bgColor?.startsWith('#') && bgColor.length === 9
378
+ ? bgColor.substring(0, 7)
379
+ : bgColor
331
380
  return html`
381
+ <style>
382
+ :host {
383
+ --md-sys-color-on-surface: ${fontColor};
384
+ --md-sys-color-on-surface-variant: ${fontColor};
385
+ --md-sys-color-outline: ${fontColor};
386
+ --md-sys-color-surface-container: ${bgColorOpaque};
387
+ --md-menu-container-color: ${bgColorOpaque};
388
+ --md-menu-item-selected-container-color: ${bgColorOpaque};
389
+ --md-menu-item-selected-label-text-color: ${fontColor};
390
+ color: ${fontColor};
391
+ }
392
+ </style>
332
393
  <div class="header">
333
394
  ${this.inputData?.formButton
334
395
  ? html`
@@ -352,9 +413,17 @@ export class WidgetForm extends LitElement {
352
413
  <div class="wrapper">
353
414
  ${this.renderForm()}
354
415
  <div class="form-actions">
355
- <md-outlined-button form="form" value="cancel" type="reset"
356
- >Reset</md-outlined-button
357
- >
416
+ ${this.inputData?.deleteButton
417
+ ? html`<md-filled-button
418
+ class="delete-btn"
419
+ form="form"
420
+ value="delete"
421
+ type="submit"
422
+ autofocus
423
+ >Delete</md-filled-button
424
+ >`
425
+ : nothing}
426
+ <md-outlined-button @click=${this.resetForm}>Reset</md-outlined-button>
358
427
  <md-filled-button form="form" value="submit" type="submit" autofocus
359
428
  >Submit</md-filled-button
360
429
  >
@@ -378,9 +447,17 @@ export class WidgetForm extends LitElement {
378
447
  <div slot="headline">${this.inputData?.title ?? 'Data Entry'}</div>
379
448
  ${this.renderForm()}
380
449
  <div slot="actions">
381
- <md-outlined-button form="form" value="cancel" type="reset"
382
- >Cancel</md-outlined-button
383
- >
450
+ ${this.inputData?.deleteButton
451
+ ? html`<md-filled-button
452
+ class="delete-btn"
453
+ form="form"
454
+ value="delete"
455
+ type="submit"
456
+ autofocus
457
+ >Delete</md-filled-button
458
+ >`
459
+ : nothing}
460
+ <md-outlined-button @click=${this.cancelEdit}>Cancel</md-outlined-button>
384
461
  <md-filled-button form="form" value="submit" type="submit" autofocus
385
462
  >Submit</md-filled-button
386
463
  >
@@ -398,7 +475,6 @@ export class WidgetForm extends LitElement {
398
475
  method="dialog"
399
476
  class="form-content"
400
477
  @submit=${this.handleFormSubmit}
401
- @reset=${this.cancelEdit}
402
478
  >
403
479
  ${repeat(
404
480
  this.inputData?.formFields?.filter((field) => !field.hiddenField) ?? [],