@openmfp/webcomponents 0.6.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/.github/workflows/pipeline.yaml +41 -0
- package/.storybook/main.ts +34 -0
- package/.storybook/preview.ts +29 -0
- package/.storybook/tsconfig.json +11 -0
- package/AGENTS.md +153 -0
- package/CODEOWNERS +6 -0
- package/CONTRIBUTING.md +95 -0
- package/LICENSE +201 -0
- package/LICENSES/Apache-2.0.txt +73 -0
- package/README.md +91 -0
- package/REUSE.toml +9 -0
- package/angular.json +157 -0
- package/docs/dashboard.md +358 -0
- package/docs/declarative-form.md +178 -0
- package/docs/declarative-table-card.md +235 -0
- package/docs/declarative-table.md +315 -0
- package/eslint.config.js +41 -0
- package/package.json +73 -0
- package/projects/ngx/cards/favorites/favorites.component.html +12 -0
- package/projects/ngx/cards/favorites/favorites.component.scss +50 -0
- package/projects/ngx/cards/favorites/favorites.component.ts +19 -0
- package/projects/ngx/cards/public-api.ts +4 -0
- package/projects/ngx/cards/service-status/service-status-card.component.html +15 -0
- package/projects/ngx/cards/service-status/service-status-card.component.scss +87 -0
- package/projects/ngx/cards/service-status/service-status-card.component.ts +36 -0
- package/projects/ngx/cards/stories/visited-service-card.stories.ts +149 -0
- package/projects/ngx/cards/visited-service-card/visited-service-card.component.html +17 -0
- package/projects/ngx/cards/visited-service-card/visited-service-card.component.scss +34 -0
- package/projects/ngx/cards/visited-service-card/visited-service-card.component.ts +22 -0
- package/projects/ngx/cards/whats-new/whats-new.component.html +10 -0
- package/projects/ngx/cards/whats-new/whats-new.component.scss +25 -0
- package/projects/ngx/cards/whats-new/whats-new.component.ts +46 -0
- package/projects/ngx/declarative-ui/dashboard/add-card-dialog/add-card-dialog.component.html +28 -0
- package/projects/ngx/declarative-ui/dashboard/add-card-dialog/add-card-dialog.component.scss +44 -0
- package/projects/ngx/declarative-ui/dashboard/add-card-dialog/add-card-dialog.component.spec.ts +85 -0
- package/projects/ngx/declarative-ui/dashboard/add-card-dialog/add-card-dialog.component.ts +58 -0
- package/projects/ngx/declarative-ui/dashboard/card/dashboard-card.component.html +29 -0
- package/projects/ngx/declarative-ui/dashboard/card/dashboard-card.component.scss +63 -0
- package/projects/ngx/declarative-ui/dashboard/card/dashboard-card.component.spec.ts +255 -0
- package/projects/ngx/declarative-ui/dashboard/card/dashboard-card.component.ts +75 -0
- package/projects/ngx/declarative-ui/dashboard/card/utils/dashboard-card-registry.spec.ts +76 -0
- package/projects/ngx/declarative-ui/dashboard/card/utils/dashboard-card-registry.ts +109 -0
- package/projects/ngx/declarative-ui/dashboard/card/utils/index.ts +4 -0
- package/projects/ngx/declarative-ui/dashboard/card/utils/mount-angular-card.spec.ts +141 -0
- package/projects/ngx/declarative-ui/dashboard/card/utils/mount-angular-card.ts +44 -0
- package/projects/ngx/declarative-ui/dashboard/card/utils/mount-sap-card.spec.ts +142 -0
- package/projects/ngx/declarative-ui/dashboard/card/utils/mount-sap-card.ts +52 -0
- package/projects/ngx/declarative-ui/dashboard/card/utils/mount-wc-card.spec.ts +107 -0
- package/projects/ngx/declarative-ui/dashboard/card/utils/mount-wc-card.ts +22 -0
- package/projects/ngx/declarative-ui/dashboard/dashboard/dashboard.component.html +134 -0
- package/projects/ngx/declarative-ui/dashboard/dashboard/dashboard.component.scss +88 -0
- package/projects/ngx/declarative-ui/dashboard/dashboard/dashboard.component.spec.ts +354 -0
- package/projects/ngx/declarative-ui/dashboard/dashboard/dashboard.component.ts +238 -0
- package/projects/ngx/declarative-ui/dashboard/dashboard/index.ts +1 -0
- package/projects/ngx/declarative-ui/dashboard/index.ts +5 -0
- package/projects/ngx/declarative-ui/dashboard/models/constants.ts +2 -0
- package/projects/ngx/declarative-ui/dashboard/models/dashboard.model.ts +50 -0
- package/projects/ngx/declarative-ui/dashboard/models/index.ts +1 -0
- package/projects/ngx/declarative-ui/dashboard/section/dashboard-section.component.html +28 -0
- package/projects/ngx/declarative-ui/dashboard/section/dashboard-section.component.scss +85 -0
- package/projects/ngx/declarative-ui/dashboard/section/dashboard-section.component.spec.ts +104 -0
- package/projects/ngx/declarative-ui/dashboard/section/dashboard-section.component.ts +23 -0
- package/projects/ngx/declarative-ui/form/declarative-form/declarative-form.component.html +62 -0
- package/projects/ngx/declarative-ui/form/declarative-form/declarative-form.component.scss +12 -0
- package/projects/ngx/declarative-ui/form/declarative-form/declarative-form.component.spec.ts +301 -0
- package/projects/ngx/declarative-ui/form/declarative-form/declarative-form.component.ts +166 -0
- package/projects/ngx/declarative-ui/form/declarative-form/index.ts +1 -0
- package/projects/ngx/declarative-ui/form/index.ts +2 -0
- package/projects/ngx/declarative-ui/form/models/form-field-definition.ts +15 -0
- package/projects/ngx/declarative-ui/form/models/index.ts +1 -0
- package/projects/ngx/declarative-ui/form/utils/set-property-by-path.ts +30 -0
- package/projects/ngx/declarative-ui/models/index.ts +2 -0
- package/projects/ngx/declarative-ui/models/resource.ts +5 -0
- package/projects/ngx/declarative-ui/models/ui-definition.ts +95 -0
- package/projects/ngx/declarative-ui/public-api.ts +4 -0
- package/projects/ngx/declarative-ui/stories/add-card-dialog.stories.ts +91 -0
- package/projects/ngx/declarative-ui/stories/background-lightblue.png +0 -0
- package/projects/ngx/declarative-ui/stories/dashboard.cards.ts +107 -0
- package/projects/ngx/declarative-ui/stories/dashboard.stories.ts +296 -0
- package/projects/ngx/declarative-ui/stories/declarative-form.stories.ts +149 -0
- package/projects/ngx/declarative-ui/stories/declarative-table-card.stories.ts +358 -0
- package/projects/ngx/declarative-ui/stories/declarative-table.stories.ts +363 -0
- package/projects/ngx/declarative-ui/stories/pods-table.config.ts +188 -0
- package/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.html +138 -0
- package/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.scss +21 -0
- package/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.spec.ts +345 -0
- package/projects/ngx/declarative-ui/table/declarative-table/declarative-table.component.ts +61 -0
- package/projects/ngx/declarative-ui/table/declarative-table/index.ts +1 -0
- package/projects/ngx/declarative-ui/table/index.ts +2 -0
- package/projects/ngx/declarative-ui/table/models/index.ts +14 -0
- package/projects/ngx/declarative-ui/table/models/table.model.ts +17 -0
- package/projects/ngx/declarative-ui/table/utils/cssRules.engine.spec.ts +146 -0
- package/projects/ngx/declarative-ui/table/utils/cssRules.engine.ts +69 -0
- package/projects/ngx/declarative-ui/table/utils/field-definition.utils.spec.ts +70 -0
- package/projects/ngx/declarative-ui/table/utils/field-definition.utils.ts +13 -0
- package/projects/ngx/declarative-ui/table/utils/proccess-fields.spec.ts +511 -0
- package/projects/ngx/declarative-ui/table/utils/proccess-fields.ts +71 -0
- package/projects/ngx/declarative-ui/table/utils/resource-field-by-path.spec.ts +372 -0
- package/projects/ngx/declarative-ui/table/utils/resource-field-by-path.ts +98 -0
- package/projects/ngx/declarative-ui/table/value-cell/boolean-value/boolean-cell.constants.ts +5 -0
- package/projects/ngx/declarative-ui/table/value-cell/boolean-value/boolean-value.component.html +1 -0
- package/projects/ngx/declarative-ui/table/value-cell/boolean-value/boolean-value.component.scss +0 -0
- package/projects/ngx/declarative-ui/table/value-cell/boolean-value/boolean-value.component.spec.ts +119 -0
- package/projects/ngx/declarative-ui/table/value-cell/boolean-value/boolean-value.component.ts +35 -0
- package/projects/ngx/declarative-ui/table/value-cell/link-value/link-value.component.html +7 -0
- package/projects/ngx/declarative-ui/table/value-cell/link-value/link-value.component.scss +0 -0
- package/projects/ngx/declarative-ui/table/value-cell/link-value/link-value.component.spec.ts +114 -0
- package/projects/ngx/declarative-ui/table/value-cell/link-value/link-value.component.ts +19 -0
- package/projects/ngx/declarative-ui/table/value-cell/secret-value/secret-value.component.html +7 -0
- package/projects/ngx/declarative-ui/table/value-cell/secret-value/secret-value.component.scss +10 -0
- package/projects/ngx/declarative-ui/table/value-cell/secret-value/secret-value.component.spec.ts +188 -0
- package/projects/ngx/declarative-ui/table/value-cell/secret-value/secret-value.component.ts +16 -0
- package/projects/ngx/declarative-ui/table/value-cell/value-cell.component.html +59 -0
- package/projects/ngx/declarative-ui/table/value-cell/value-cell.component.scss +33 -0
- package/projects/ngx/declarative-ui/table/value-cell/value-cell.component.spec.ts +316 -0
- package/projects/ngx/declarative-ui/table/value-cell/value-cell.component.ts +115 -0
- package/projects/ngx/declarative-ui/table-card/declarative-table-card.component.html +156 -0
- package/projects/ngx/declarative-ui/table-card/declarative-table-card.component.scss +123 -0
- package/projects/ngx/declarative-ui/table-card/declarative-table-card.component.spec.ts +786 -0
- package/projects/ngx/declarative-ui/table-card/declarative-table-card.component.ts +286 -0
- package/projects/ngx/declarative-ui/table-card/index.ts +2 -0
- package/projects/ngx/declarative-ui/table-card/models/configs.ts +46 -0
- package/projects/ngx/declarative-ui/tsconfig.lib.json +11 -0
- package/projects/ngx/declarative-ui/tsconfig.lib.prod.json +9 -0
- package/projects/ngx/declarative-ui/tsconfig.spec.json +9 -0
- package/projects/ngx/ng-package.json +8 -0
- package/projects/ngx/package.json +22 -0
- package/projects/ngx/public-api.ts +2 -0
- package/projects/ngx/tsconfig.lib.json +11 -0
- package/projects/ngx/tsconfig.lib.prod.json +9 -0
- package/projects/webcomponents/main.ts +92 -0
- package/projects/webcomponents/tsconfig.app.json +9 -0
- package/projects/webcomponents-dashboard/main.ts +15 -0
- package/projects/webcomponents-dashboard/tsconfig.app.json +9 -0
- package/renovate.json +6 -0
- package/scripts/bundle-wc.mjs +79 -0
- package/tsconfig.json +37 -0
- package/tsconfig.spec.json +8 -0
- package/tsconfig.storybook.json +16 -0
- package/vitest.config.ts +26 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# DeclarativeForm
|
|
2
|
+
|
|
3
|
+
A dynamic form web component that renders fields from a declarative field definition. The component does not execute validation logic. It emits per-field change events based on each field's `validation` strategy, accepts host-owned field errors, and emits a nested value only when the host triggers submit.
|
|
4
|
+
|
|
5
|
+
## Tags
|
|
6
|
+
|
|
7
|
+
| Usage | Tag |
|
|
8
|
+
| ---------------------------------- | --------------------------- |
|
|
9
|
+
| Angular component | `<mfp-declarative-form>` |
|
|
10
|
+
| Web Component (framework-agnostic) | `<mfp-wc-declarative-form>` |
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Usage as a web component
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<mfp-wc-declarative-form id="form"></mfp-wc-declarative-form>
|
|
18
|
+
|
|
19
|
+
<script type="module">
|
|
20
|
+
const form = document.getElementById('form');
|
|
21
|
+
|
|
22
|
+
form.fields = [
|
|
23
|
+
{ name: 'metadata.name', label: 'Name', required: true, validation: 'onChange' },
|
|
24
|
+
{ name: 'metadata.namespace', label: 'Namespace', validation: 'onBlur' },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
form.addEventListener('fieldChange', (event) => {
|
|
28
|
+
const { fieldProperty, value } = event.detail;
|
|
29
|
+
const fieldErrors = { ...form.fieldErrors };
|
|
30
|
+
|
|
31
|
+
if (fieldProperty === 'metadata.name' && !value) {
|
|
32
|
+
fieldErrors[fieldProperty] = 'Name is required';
|
|
33
|
+
} else {
|
|
34
|
+
fieldErrors[fieldProperty] = null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
form.fieldErrors = fieldErrors;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
form.addEventListener('formSubmit', (event) => {
|
|
41
|
+
console.log(event.detail);
|
|
42
|
+
// { metadata: { name: 'my-app', namespace: 'default' } }
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Trigger when the surrounding page decides the form should submit.
|
|
46
|
+
form.submit();
|
|
47
|
+
</script>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> `fields`, `initialValues`, and `fieldErrors` are JavaScript properties, not HTML attributes.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Usage as an Angular component
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import {
|
|
58
|
+
DeclarativeForm,
|
|
59
|
+
FormFieldChangeEvent,
|
|
60
|
+
FormFieldDefinition,
|
|
61
|
+
FormFieldErrors,
|
|
62
|
+
} from '@openmfp/webcomponents';
|
|
63
|
+
|
|
64
|
+
@Component({
|
|
65
|
+
imports: [DeclarativeForm],
|
|
66
|
+
template: `
|
|
67
|
+
<mfp-declarative-form
|
|
68
|
+
#form
|
|
69
|
+
[fields]="fields"
|
|
70
|
+
[initialValues]="initialValues"
|
|
71
|
+
[fieldErrors]="fieldErrors"
|
|
72
|
+
(fieldChange)="onFieldChange($event)"
|
|
73
|
+
(formSubmit)="onSubmit($event)"
|
|
74
|
+
/>
|
|
75
|
+
|
|
76
|
+
<button type="button" (click)="form.submit()">Save</button>
|
|
77
|
+
`,
|
|
78
|
+
})
|
|
79
|
+
export class MyComponent {
|
|
80
|
+
fields: FormFieldDefinition[] = [
|
|
81
|
+
{ name: 'metadata.name', label: 'Name', required: true, validation: 'onChange' },
|
|
82
|
+
{ name: 'metadata.namespace', label: 'Namespace', validation: 'onBlur' },
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
initialValues = {
|
|
86
|
+
'metadata.name': 'my-app',
|
|
87
|
+
'metadata.namespace': 'default',
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
fieldErrors: FormFieldErrors = {};
|
|
91
|
+
|
|
92
|
+
onFieldChange(event: FormFieldChangeEvent): void {
|
|
93
|
+
const { fieldProperty, value } = event;
|
|
94
|
+
this.fieldErrors = {
|
|
95
|
+
...this.fieldErrors,
|
|
96
|
+
[fieldProperty]: !value ? 'Field is required' : null,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
onSubmit(value: Record<string, unknown>): void {
|
|
101
|
+
// value is nested: { metadata: { name: 'my-app', namespace: 'default' } }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## API
|
|
109
|
+
|
|
110
|
+
### Inputs
|
|
111
|
+
|
|
112
|
+
| Input | Type | Required | Default | Description |
|
|
113
|
+
| --------------- | ------------------------- | -------- | ------- | ----------------------------------------------------------------------------- |
|
|
114
|
+
| `fields` | `FormFieldDefinition[]` | yes | - | Field definitions to render |
|
|
115
|
+
| `initialValues` | `Record<string, unknown>` | no | `{}` | Initial values keyed by exact `field.name` |
|
|
116
|
+
| `fieldErrors` | `FormFieldErrors` | no | `{}` | Host-owned errors keyed by exact `field.name` |
|
|
117
|
+
| `editMode` | `boolean` | no | `false` | Signals edit mode to consumers; does not change component behavior on its own |
|
|
118
|
+
|
|
119
|
+
### Outputs / Events
|
|
120
|
+
|
|
121
|
+
| Event | Detail payload | Description |
|
|
122
|
+
| ------------ | --------------------------- | ------------------------------------------------------------------ |
|
|
123
|
+
| `fieldChange` | `FormFieldChangeEvent` | Fires per-field based on the field's `validation` strategy |
|
|
124
|
+
| `formSubmit` | `Record<string, unknown>` | Fires when `submit()` is called; value is nested |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Types
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
interface FormFieldDefinition {
|
|
132
|
+
name: string; // Field key; dots create nested submit output paths
|
|
133
|
+
label?: string; // Display label shown above the field
|
|
134
|
+
required?: boolean; // Visual required marker only
|
|
135
|
+
values?: string[]; // Static select options
|
|
136
|
+
disabled?: boolean; // Disables the field
|
|
137
|
+
validation?: 'onBlur' | 'onChange'; // When to emit fieldChange for this field
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
interface FormFieldChangeEvent {
|
|
141
|
+
fieldProperty: string; // The field property name (matches field.name)
|
|
142
|
+
value: unknown; // Current value of the control
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
type FormFieldErrors = Record<string, string | null>;
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`fieldChange` emits a single field at a time:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
{ fieldProperty: 'metadata.name', value: 'my-app' }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`formSubmit` emits a nested object:
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
{
|
|
158
|
+
metadata: {
|
|
159
|
+
name: 'my-app',
|
|
160
|
+
namespace: 'default',
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Validation
|
|
168
|
+
|
|
169
|
+
- The component never executes validators.
|
|
170
|
+
- `required` only renders the required marker on the label/input.
|
|
171
|
+
- The `validation` property on each field controls when `fieldChange` fires:
|
|
172
|
+
- `'onChange'` — fires on every value change.
|
|
173
|
+
- `'onBlur'` — fires when the field loses focus.
|
|
174
|
+
- Not set — no `fieldChange` event is emitted for that field.
|
|
175
|
+
- On initialization (and when `initialValues` changes), the component emits `fieldChange` for every field that has a `validation` strategy. This lets the host run validation immediately and disable the submit button before the user interacts.
|
|
176
|
+
- The host validates the received `FormFieldChangeEvent` and updates `fieldErrors`.
|
|
177
|
+
- A field shows `Negative` value state and the error message only when it is dirty or touched and `fieldErrors[field.name]` is a non-empty string.
|
|
178
|
+
- Empty, missing, or `null` errors render as no error.
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# DeclarativeTableCard
|
|
2
|
+
|
|
3
|
+
A card component that wraps `mfp-declarative-table` and adds a header, search, and optional create/edit/delete dialogs. Form validation and async submit state are owned by the host application.
|
|
4
|
+
|
|
5
|
+
## Tags
|
|
6
|
+
|
|
7
|
+
| Usage | Tag |
|
|
8
|
+
| ---------------------------------- | --------------------------------- |
|
|
9
|
+
| Angular component | `<mfp-declarative-table-card>` |
|
|
10
|
+
| Web Component (framework-agnostic) | `<mfp-wc-declarative-table-card>` |
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Usage as a web component
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<mfp-wc-declarative-table-card id="card"></mfp-wc-declarative-table-card>
|
|
18
|
+
|
|
19
|
+
<script type="module">
|
|
20
|
+
const card = document.getElementById('card');
|
|
21
|
+
|
|
22
|
+
card.resources = [
|
|
23
|
+
{
|
|
24
|
+
id: '1',
|
|
25
|
+
metadata: { name: 'api-server', namespace: 'default' },
|
|
26
|
+
status: { phase: 'Running' },
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
card.config = {
|
|
31
|
+
header: 'Pods',
|
|
32
|
+
tableConfig: {
|
|
33
|
+
fields: [
|
|
34
|
+
{ label: 'Name', property: 'metadata.name' },
|
|
35
|
+
{ label: 'Namespace', property: 'metadata.namespace' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
createResourceFormConfig: {
|
|
39
|
+
fields: [
|
|
40
|
+
{ name: 'metadata.name', label: 'Name', required: true },
|
|
41
|
+
{ name: 'metadata.namespace', label: 'Namespace' },
|
|
42
|
+
],
|
|
43
|
+
title: 'Create Pod',
|
|
44
|
+
confirmLabel: 'Create',
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
card.addEventListener('createFieldChange', (event) => {
|
|
49
|
+
const { fieldProperty, value } = event.detail;
|
|
50
|
+
|
|
51
|
+
card.createFormState = {
|
|
52
|
+
fieldErrors: {
|
|
53
|
+
...card.createFormState?.fieldErrors,
|
|
54
|
+
[fieldProperty]: !value ? 'Field is required' : null,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
card.addEventListener('createSubmit', async (event) => {
|
|
60
|
+
await createPod(event.detail);
|
|
61
|
+
card.createFormState = {};
|
|
62
|
+
card.closeCreateDialog();
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Usage as an Angular component
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import {
|
|
73
|
+
DeclarativeTableCard,
|
|
74
|
+
FormFieldChangeEvent,
|
|
75
|
+
TableCardConfig,
|
|
76
|
+
TableCardFormState,
|
|
77
|
+
} from '@openmfp/webcomponents';
|
|
78
|
+
|
|
79
|
+
@Component({
|
|
80
|
+
imports: [DeclarativeTableCard],
|
|
81
|
+
template: `
|
|
82
|
+
<mfp-declarative-table-card
|
|
83
|
+
#tableCard
|
|
84
|
+
[config]="config"
|
|
85
|
+
[resources]="pods"
|
|
86
|
+
[createFormState]="createFormState"
|
|
87
|
+
[editFormState]="editFormState"
|
|
88
|
+
(createFieldChange)="onCreateFieldChange($event)"
|
|
89
|
+
(editFieldChange)="onEditFieldChange($event)"
|
|
90
|
+
(createSubmit)="onCreateSubmit($event, tableCard)"
|
|
91
|
+
(editSubmit)="onEditSubmit($event, tableCard)"
|
|
92
|
+
(deleteSubmit)="onDeleteSubmit($event, tableCard)"
|
|
93
|
+
(searchChanged)="onSearch($event)"
|
|
94
|
+
/>
|
|
95
|
+
`,
|
|
96
|
+
})
|
|
97
|
+
export class MyComponent {
|
|
98
|
+
pods = [];
|
|
99
|
+
createFormState: TableCardFormState = {};
|
|
100
|
+
editFormState: TableCardFormState = {};
|
|
101
|
+
|
|
102
|
+
config: TableCardConfig = {
|
|
103
|
+
header: 'Pods',
|
|
104
|
+
tableConfig: {
|
|
105
|
+
fields: [
|
|
106
|
+
{ label: 'Name', property: 'metadata.name' },
|
|
107
|
+
{ label: 'Namespace', property: 'metadata.namespace' },
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
createResourceFormConfig: {
|
|
111
|
+
fields: [
|
|
112
|
+
{ name: 'metadata.name', label: 'Name', required: true },
|
|
113
|
+
{ name: 'metadata.namespace', label: 'Namespace' },
|
|
114
|
+
],
|
|
115
|
+
title: 'Create Pod',
|
|
116
|
+
confirmLabel: 'Create',
|
|
117
|
+
},
|
|
118
|
+
deleteResourceConfirmationConfig: {
|
|
119
|
+
title: 'Delete Pod?',
|
|
120
|
+
message: 'This action cannot be undone.',
|
|
121
|
+
confirmLabel: 'Delete',
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
onCreateFieldChange(event: FormFieldChangeEvent): void {
|
|
126
|
+
const { fieldProperty, value } = event;
|
|
127
|
+
this.createFormState = {
|
|
128
|
+
fieldErrors: {
|
|
129
|
+
...this.createFormState.fieldErrors,
|
|
130
|
+
[fieldProperty]: !value ? 'Field is required' : null,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
onEditFieldChange(event: {
|
|
136
|
+
resource: Pod;
|
|
137
|
+
formChangeEvent: FormFieldChangeEvent;
|
|
138
|
+
}): void {
|
|
139
|
+
// Validate event.formChangeEvent and update editFormState.
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async onCreateSubmit(
|
|
143
|
+
value: Record<string, unknown>,
|
|
144
|
+
tableCard: DeclarativeTableCard<Pod>,
|
|
145
|
+
): Promise<void> {
|
|
146
|
+
await this.createPod(value);
|
|
147
|
+
this.createFormState = {};
|
|
148
|
+
tableCard.closeCreateDialog();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async onEditSubmit(
|
|
152
|
+
event: { resource: Pod; value: Record<string, unknown> },
|
|
153
|
+
tableCard: DeclarativeTableCard<Pod>,
|
|
154
|
+
): Promise<void> {
|
|
155
|
+
await this.updatePod(event.resource, event.value);
|
|
156
|
+
this.editFormState = {};
|
|
157
|
+
tableCard.closeEditDialog();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async onDeleteSubmit(
|
|
161
|
+
pod: Pod,
|
|
162
|
+
tableCard: DeclarativeTableCard<Pod>,
|
|
163
|
+
): Promise<void> {
|
|
164
|
+
await this.deletePod(pod);
|
|
165
|
+
tableCard.closeDeleteDialog();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## API
|
|
173
|
+
|
|
174
|
+
### Inputs
|
|
175
|
+
|
|
176
|
+
| Input | Type | Required | Default | Description |
|
|
177
|
+
| ----------------- | -------------------- | -------- | ------- | --------------------------------------------------------- |
|
|
178
|
+
| `resources` | `T[]` | yes | - | Data rows passed to the inner table |
|
|
179
|
+
| `config` | `TableCardConfig` | yes | - | Static table, button, and dialog configuration |
|
|
180
|
+
| `createFormState` | `TableCardFormState` | no | `{}` | Runtime validation and submit state for the create dialog |
|
|
181
|
+
| `editFormState` | `TableCardFormState` | no | `{}` | Runtime validation and submit state for the edit dialog |
|
|
182
|
+
|
|
183
|
+
### Outputs / Events
|
|
184
|
+
|
|
185
|
+
| Event | Payload | Description |
|
|
186
|
+
| ------------------------ | ------------------------------------------------- | ------------------------------------------------------------ |
|
|
187
|
+
| `createFieldChange` | `FormFieldChangeEvent` | Re-emits per-field change from the create form |
|
|
188
|
+
| `editFieldChange` | `{ resource: T; formChangeEvent: FormFieldChangeEvent }` | Re-emits per-field change from the edit form with resource |
|
|
189
|
+
| `createSubmit` | `Record<string, unknown>` | Fires when the create dialog Save button is clicked |
|
|
190
|
+
| `editSubmit` | `{ resource: T; value: Record<string, unknown> }` | Fires when the edit dialog Save button is clicked |
|
|
191
|
+
| `deleteSubmit` | `T` | Fires when the delete dialog Delete button is clicked |
|
|
192
|
+
| `searchChanged` | `string` | Emits 300 ms after the search input changes |
|
|
193
|
+
| `tableRowClicked` | `T` | Emits when a table row is clicked |
|
|
194
|
+
| `loadMoreResources` | - | Emits when the user triggers load more |
|
|
195
|
+
| `paginationLimitChanged` | `number` | Emits when the user changes page size |
|
|
196
|
+
| `actionButtonClick` | `ValueCellButtonClickEvent<T>` | Emits for row-action buttons other than built-in edit/delete |
|
|
197
|
+
|
|
198
|
+
### Methods
|
|
199
|
+
|
|
200
|
+
| Method | Description |
|
|
201
|
+
| --------------------- | ------------------------ |
|
|
202
|
+
| `closeCreateDialog()` | Closes the create dialog |
|
|
203
|
+
| `closeEditDialog()` | Closes the edit dialog |
|
|
204
|
+
| `closeDeleteDialog()` | Closes the delete dialog |
|
|
205
|
+
|
|
206
|
+
Submit events do not close dialogs automatically. Close the dialog after successful validation, save, or delete.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Configuration types
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
interface TableCardConfig {
|
|
214
|
+
header: string;
|
|
215
|
+
headerTooltip?: string;
|
|
216
|
+
tableConfig: TableConfig;
|
|
217
|
+
buttonSettings?: TableCardButtonSettings;
|
|
218
|
+
createResourceFormConfig?: ResourceFormConfig;
|
|
219
|
+
editResourceFormConfig?: ResourceFormConfig;
|
|
220
|
+
deleteResourceConfirmationConfig?: DeleteResourceConfirmationConfig;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
interface ResourceFormConfig {
|
|
224
|
+
fields: FormFieldDefinition[];
|
|
225
|
+
title?: string;
|
|
226
|
+
confirmLabel?: string;
|
|
227
|
+
cancelLabel?: string;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
interface TableCardFormState {
|
|
231
|
+
fieldErrors?: FormFieldErrors;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`ResourceFormConfig` is static. Keep runtime errors in `createFormState` / `editFormState`. The submit button is disabled when any entry in `fieldErrors` is truthy.
|