@formio/uag 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/UAGFormInterface.d.ts +5 -1
- package/lib/UAGFormInterface.js +61 -19
- package/lib/config.d.ts +0 -1
- package/lib/templates/allFieldsCollected.md +9 -11
- package/lib/templates/confirmFormSubmission.md +3 -6
- package/lib/templates/fieldCollectedNext.md +6 -3
- package/lib/templates/getFormFields.md +5 -13
- package/lib/templates/getFormFieldsEmpty.md +13 -3
- package/lib/templates/getFormFieldsInfo.md +6 -3
- package/lib/tools/SchemaBuilder.d.ts +3 -11
- package/lib/tools/SchemaBuilder.js +4 -19
- package/lib/tools/collectData.js +10 -15
- package/lib/tools/confirmSubmission.js +3 -5
- package/lib/tools/getFieldInfo.js +10 -2
- package/lib/tools/getFormFields.js +10 -45
- package/lib/tools/utils.d.ts +0 -3
- package/lib/tools/utils.js +0 -25
- package/package.json +1 -1
- package/lib/templates/getOptionalFields.md +0 -19
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ try {
|
|
|
60
60
|
There is also a way to extend the functionality of the UAG through the use of modules, which is documented in the [Modules Readme](./module/Readme.md)
|
|
61
61
|
|
|
62
62
|
### Docker
|
|
63
|
-
In addition to running the UAG in
|
|
63
|
+
In addition to running the UAG in Node.js, you can also run the UAG within the Docker environment. This enables a wide range of deployment options into common hosting environments such as AWS and Azure as well as allow for the use in common orchestration runtimes such as Kubernetes and Docker Compose. The container that you will use for running the UAG is as follows.
|
|
64
64
|
|
|
65
65
|
```
|
|
66
66
|
formio/uag
|
|
@@ -53,8 +53,12 @@ export declare class UAGFormInterface extends FormInterface {
|
|
|
53
53
|
getComponentFormat(component: Component): string;
|
|
54
54
|
getComponentInfo(component: Component, path: string): UAGComponentInfo;
|
|
55
55
|
isMultiple(component: Component | undefined): boolean;
|
|
56
|
+
getParentInfoFromComponent(parent: Component | undefined, parent_path?: string): ParentInfo | undefined;
|
|
57
|
+
getParentInfo(parent_path?: string): ParentInfo | undefined;
|
|
58
|
+
getParentLabel(parent?: ParentInfo): string;
|
|
59
|
+
getParentDataPath(parent: ParentInfo | undefined, rowIndex?: number): string;
|
|
56
60
|
getParentToolDescription(parent: ParentInfo | undefined): string;
|
|
57
|
-
getComponentValueRule(component: Component): string;
|
|
61
|
+
getComponentValueRule(component: Component, data_path?: string): string;
|
|
58
62
|
/**
|
|
59
63
|
* Determine if the component is a nested data components. For these components, the UAG treats them as
|
|
60
64
|
* separate data collection units where the agent will explicitely call out to collect data for these components.
|
package/lib/UAGFormInterface.js
CHANGED
|
@@ -66,33 +66,75 @@ class UAGFormInterface extends appserver_1.FormInterface {
|
|
|
66
66
|
return false;
|
|
67
67
|
return !!component.multiple || component.type === 'selectboxes' || component.type === 'tags';
|
|
68
68
|
}
|
|
69
|
+
getParentInfoFromComponent(parent, parent_path) {
|
|
70
|
+
if (!parent || !parent_path)
|
|
71
|
+
return undefined;
|
|
72
|
+
const parentInfo = {
|
|
73
|
+
type: parent.type,
|
|
74
|
+
label: parent.label || parent.key,
|
|
75
|
+
data_path: parent_path
|
|
76
|
+
};
|
|
77
|
+
if (parent.tree ||
|
|
78
|
+
parent.type === 'datagrid' ||
|
|
79
|
+
parent.type === 'editgrid') {
|
|
80
|
+
parentInfo.isTable = true;
|
|
81
|
+
return parentInfo;
|
|
82
|
+
}
|
|
83
|
+
if (parent.type === 'form') {
|
|
84
|
+
parentInfo.isForm = true;
|
|
85
|
+
return parentInfo;
|
|
86
|
+
}
|
|
87
|
+
if (parent.type === 'container') {
|
|
88
|
+
parentInfo.isContainer = true;
|
|
89
|
+
return parentInfo;
|
|
90
|
+
}
|
|
91
|
+
return parentInfo;
|
|
92
|
+
}
|
|
93
|
+
getParentInfo(parent_path) {
|
|
94
|
+
if (!parent_path)
|
|
95
|
+
return undefined;
|
|
96
|
+
const parent = this.getComponent(parent_path);
|
|
97
|
+
return this.getParentInfoFromComponent(parent, parent_path);
|
|
98
|
+
}
|
|
99
|
+
getParentLabel(parent) {
|
|
100
|
+
if (parent?.isTable) {
|
|
101
|
+
return `this row within the **${parent.label}** component`;
|
|
102
|
+
}
|
|
103
|
+
else if (parent?.isForm) {
|
|
104
|
+
return `the **${parent.label}** nested form`;
|
|
105
|
+
}
|
|
106
|
+
else if (parent?.isContainer) {
|
|
107
|
+
return `the **${parent.label}** container component`;
|
|
108
|
+
}
|
|
109
|
+
return `the **${this.form.title} (${this.form.name})** form`;
|
|
110
|
+
}
|
|
111
|
+
getParentDataPath(parent, rowIndex = -1) {
|
|
112
|
+
if (parent?.isTable) {
|
|
113
|
+
return (rowIndex >= 0) ? `${parent.data_path}[${rowIndex}]` : `${parent.data_path}[0]`;
|
|
114
|
+
}
|
|
115
|
+
if (parent?.isForm) {
|
|
116
|
+
return `${parent.data_path}.data`;
|
|
117
|
+
}
|
|
118
|
+
return parent?.data_path || '';
|
|
119
|
+
}
|
|
69
120
|
getParentToolDescription(parent) {
|
|
70
121
|
if (!parent)
|
|
71
122
|
return '';
|
|
72
|
-
return `To
|
|
123
|
+
return `To determine what fields are within this component, use the \`get_form_fields\` tool with \`parent_path\`="<data_path>" (e.g. \`parent_path\`="${parent.data_path}"). To collect data for this component, use the \`collect_field_data\` tool with the \`parent_path\` set for the parent's data_path.`;
|
|
73
124
|
}
|
|
74
|
-
getComponentValueRule(component) {
|
|
125
|
+
getComponentValueRule(component, data_path) {
|
|
75
126
|
let rule = '';
|
|
76
|
-
const parent =
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
data_path: '<data_path>'
|
|
80
|
-
};
|
|
81
|
-
if (component.tree ||
|
|
82
|
-
component.type === 'datagrid' ||
|
|
83
|
-
component.type === 'editgrid') {
|
|
84
|
-
parent.isTable = true;
|
|
85
|
-
rule += 'The value is a table of rows (array of objects). ' + this.getParentToolDescription(parent) + 'All `data_path`(s) for the components within this table should contain the current row index (e.g. `dataGrid[0].a`, `dataGrid[0].b`, `dataGrid[1].b`, etc.).';
|
|
127
|
+
const parent = this.getParentInfoFromComponent(component, data_path);
|
|
128
|
+
if (parent?.isTable) {
|
|
129
|
+
rule += 'The value is a table of rows (array of objects), where each row is a new instance of data values for the child components. ' + this.getParentToolDescription(parent) + ' All `data_path`(s) for the components within this table should contain the current row index (e.g. `dataGrid[0].a`, `dataGrid[0].b`, `dataGrid[1].b`, etc.).';
|
|
86
130
|
return rule;
|
|
87
131
|
}
|
|
88
|
-
if (
|
|
89
|
-
parent.
|
|
90
|
-
rule += 'The value is a nested form submission in the format `{data: {...}}` where `{...}` is the values for the child components. ' + this.getParentToolDescription(parent) + 'All `data_path`(s) for the components within this nested form should be prefixed with `data` (e.g. `nestedForm.data.exampleField`).';
|
|
132
|
+
if (parent?.isForm) {
|
|
133
|
+
rule += 'The value is a nested form submission in the format `{data: {...}}` where `{...}` is the values for the child components. ' + this.getParentToolDescription(parent) + ' All `data_path`(s) for the components within this nested form should be prefixed with `data` (e.g. `nestedForm.data.exampleField`).';
|
|
91
134
|
return rule;
|
|
92
135
|
}
|
|
93
|
-
if (
|
|
94
|
-
parent.
|
|
95
|
-
rule += 'The value is an object/map of nested component values in the format `{...}`. ' + this.getParentToolDescription(parent) + 'All `data_path`(s) for the components within this container should be prefixed with the container\'s `data_path` (e.g. `container.exampleField`).';
|
|
136
|
+
if (parent?.isContainer) {
|
|
137
|
+
rule += 'The value is an object/map of nested component values in the format `{...}`. ' + this.getParentToolDescription(parent) + ' All `data_path`(s) for the components within this container should be prefixed with the container\'s `data_path` (e.g. `container.exampleField`).';
|
|
96
138
|
return rule;
|
|
97
139
|
}
|
|
98
140
|
switch (component.type) {
|
|
@@ -268,7 +310,7 @@ class UAGFormInterface extends appserver_1.FormInterface {
|
|
|
268
310
|
}
|
|
269
311
|
// Add the component info to the appropriate list.
|
|
270
312
|
const criteria = component.validate?.required ? 'required' : 'optional';
|
|
271
|
-
fieldInfo[criteria].rules[component.type] = this.getComponentValueRule(component);
|
|
313
|
+
fieldInfo[criteria].rules[component.type] = this.getComponentValueRule(component, path);
|
|
272
314
|
fieldInfo[criteria].components.push(this.getComponentInfo(component, path));
|
|
273
315
|
}
|
|
274
316
|
}
|
package/lib/config.d.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
**All required fields have been collected for <%= parentLabel
|
|
2
|
-
<% if (parentDataPath) { %>
|
|
3
|
-
This data was collected within the data path of **<%= parentDataPath %>**.
|
|
4
|
-
<% } %>
|
|
5
|
-
<%= dataSummary %>
|
|
1
|
+
**All required fields have been collected for <%= parentLabel %>.**
|
|
6
2
|
|
|
3
|
+
<%= dataSummary %>
|
|
7
4
|
**Next Steps**:
|
|
8
5
|
<% if (parent && parent.isTable) { %>
|
|
9
|
-
1. Use the `get_form_fields` tool with
|
|
10
|
-
2. If
|
|
11
|
-
3. If
|
|
6
|
+
1. Use the `get_form_fields` tool with `parent_path`="<%= parent.data_path %>" and `criteria`="optional" to check if there are optional fields for this row. If so, ask the user if they wish to fill any of them out for this row.
|
|
7
|
+
2. If no other optional fields need to be provided, and another row of information is required for the **<%= parent.label %>** component, then use the `collect_field_data` tool to collect any additional required rows.
|
|
8
|
+
3. If no additionial required rows are needed, then ask the user if they wish to "Add Another" (add another row to the **<%= parent.label %>** component). If they affirm, then use the `collect_field_data` tool to collect the next row's data. Make sure to increment the row index for the fields within **<%= parent.data_path %>** data_path when collecting data for the next row (e.g. <%= parent.data_path %>[<%= rowIndex %>] => <%= parent.data_path %>[<%= (rowIndex + 1) %>]).
|
|
9
|
+
4. If they do not wish to "Add Another", then use the `get_form_fields` tool to determine if there are any more fields that need to be collected outside of the **<%= parent.label %>** component. If so, use the `collect_field_data` tool to collect that information (make sure to change the `parent_path` parameter to the level above the **<%= parent.label %>** field, or leave empty if we are at the root of the form).
|
|
12
10
|
<% } else if (parent && (parent.isForm || parent.isContainer)) { %>
|
|
13
|
-
1. Use the `get_form_fields` tool with
|
|
14
|
-
2. If there are no optional fields, or the user declines, then use the `get_form_fields` tool to determine if there are any more fields that need to be collected outside of the <%= parent.label %> component. If so, use the `collect_field_data` tool to collect that information (make sure to change the parent parameter to the level above the <%= parent.label %> field, or
|
|
11
|
+
1. Use the `get_form_fields` tool with `parent_path`="<%= parent.data_path %>" and `criteria`="optional" to check if there are any optional fields. If so, ask the user if they wish to fill any of them out.
|
|
12
|
+
2. If there are no optional fields, or the user declines, then use the `get_form_fields` tool to determine if there are any more fields that need to be collected outside of the <%= parent.label %> component. If so, use the `collect_field_data` tool to collect that information (make sure to change the parent parameter to the level above the <%= parent.label %> field, or leave empty if we are at the root of the form).
|
|
15
13
|
<% } else { %>
|
|
16
|
-
1. Use the `get_form_fields` tool with
|
|
14
|
+
1. Use the `get_form_fields` tool with `criteria`="optional" to check if there are optional fields. If so, ask the user if they wish to fill any of them out.
|
|
17
15
|
2. If there are no optional fields, or the user declines, then use the `confirm_form_submission` tool to show summary and get confirmation to submit the form.<% } %>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Confirm Form Submission
|
|
2
2
|
|
|
3
|
-
All the required information for
|
|
3
|
+
All the required information for <%= parentLabel %> has been collected.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Display the following information to the user for them to confirm if it looks accurate.
|
|
6
6
|
|
|
7
7
|
<%= dataSummary %>
|
|
8
8
|
|
|
@@ -12,7 +12,4 @@ Please review the following data before submission:
|
|
|
12
12
|
- Say or type "no" or "cancel" to make changes
|
|
13
13
|
- Tell me which field you'd like to modify if you need to make changes
|
|
14
14
|
|
|
15
|
-
Only use `submit_completed_form` if the user explicitly confirms (says "yes", "confirm", "submit", etc.).
|
|
16
|
-
|
|
17
|
-
**Current Data**:
|
|
18
|
-
<%= JSON.stringify(currentData, null, 2) %>
|
|
15
|
+
Only use `submit_completed_form` if the user explicitly confirms (says "yes", "confirm", "submit", etc.).
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
<%= message %>
|
|
2
2
|
<% if (parent) { %>
|
|
3
|
-
The following data is being collected for the nested component **<%= parent.label %> (<%= parent.type %>)**. The parent `data_path` is
|
|
3
|
+
The following data is being collected for the nested component **<%= parent.label %> (<%= parent.type %>)**. The parent `data_path` is **<%= parent.data_path %>**, and all of the child data is collected within the path of **<%= parentDataPath %>**.
|
|
4
4
|
<% } %>
|
|
5
|
-
## Progress: <%= progress.collected %>/<%= progress.total %>
|
|
5
|
+
## Progress: <%= progress.collected %>/<%= progress.total %> all fields (required and optional) collected for <%= parentLabel %>.
|
|
6
6
|
|
|
7
7
|
## Remaining required fields for <%= parentLabel %>:
|
|
8
8
|
<%= fields %>
|
|
9
|
+
<%= rules %>
|
|
10
|
+
|
|
9
11
|
Use the `collect_field_data` tool to provide values for the remaining required fields for <%= parentLabel %>. You can collect multiple fields at once by providing an array of field updates.
|
|
10
12
|
|
|
11
13
|
<%= dataSummary %>
|
|
12
14
|
|
|
13
15
|
**Next Steps**:
|
|
14
|
-
1. Ask the user for any remaining required fields for <%= parentLabel %>.
|
|
16
|
+
1. Ask the user for any remaining required fields for <%= parentLabel %>.
|
|
17
|
+
2. If all "required" fields have been collected, then use the `get_form_fields` with `criteria` set to "optional" to get any additional fields the user wishes to also provide.
|
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
<% if (parent) { %>
|
|
3
|
-
All values for these fields should be stored within the `data_path`="<%= parentDataPath %>" (e.g. "<%= parentDataPath %>.exampleField")
|
|
4
|
-
<% } %>
|
|
5
|
-
### Summary
|
|
6
|
-
- Total fields for <%= parentLabel %>: <%= totalFields %>
|
|
7
|
-
- Total fields collected for <%= parentLabel %>: <% totalCollected %>
|
|
8
|
-
- Number of <%= type %> fields for <%= parentLabel %>: <%= totalType %>
|
|
9
|
-
- Number of <%= type %> fields collected for <%= parentLabel %>: <%= totalTypeCollected %>
|
|
1
|
+
## <%= type %> fields for <%= parentLabel %><% if (parent) { %>
|
|
10
2
|
|
|
11
|
-
<%=
|
|
12
|
-
|
|
13
|
-
### <%= type %> fields for <%= parentLabel %>
|
|
3
|
+
All values for these fields should be stored within the `data_path`="<%= parentDataPath %>" (e.g. "<%= parentDataPath %>.exampleField")<% } %>
|
|
14
4
|
<%= fieldList %>
|
|
15
5
|
|
|
16
|
-
|
|
6
|
+
<%= rules %>
|
|
7
|
+
|
|
8
|
+
Once the user provides provides some context, use the `get_field_info` tool<% if (parent) { %> with the `parent_path`="<%= parent.data_path %>"<% } %> to understand how to validate and process the data that was collected. Make sure to set the `field_paths` to only the paths of the fields that the user has provided values for.
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
No fields were found matching
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
No fields were found matching `criteria`="<%= criteria %>" for <%= parentLabel %>.
|
|
2
|
+
|
|
3
|
+
**Next Steps**:
|
|
4
|
+
<% if (parent && parent.isTable) { %>
|
|
5
|
+
- Ask the user if they wish to "Add Another" (add another row to the **<%= parent.label %>** component). If they affirm, then use the `collect_field_data` tool to collect the next row's data. Make sure to increment the row index for the fields within **<%= parent.data_path %>** data_path when collecting data for the next row (e.g. <%= parent.data_path %>[<%= rowIndex %>] => <%= parent.data_path %>[<%= (rowIndex + 1) %>]).
|
|
6
|
+
<% } else if (parent) { %>
|
|
7
|
+
- Considering the search was made using a `parent_path` context, try the search again at a higher `parent_path` context.
|
|
8
|
+
<% } else if (criteria === "optional") { %>
|
|
9
|
+
- Since there are no more "optional" fields, use the `confirm_form_submission` tool to ensure all the collected information is correct.
|
|
10
|
+
<% } else if (criteria === "required") { %>
|
|
11
|
+
- Use the `get_form_fields` tool, with `criteria`="optional" to determine if there are any optional fields they wish to provide information for.
|
|
12
|
+
<% } else { %>
|
|
13
|
+
- Use the `confirm_form_submission` tool to ensure all the collected information is correct.
|
|
4
14
|
<% } %>
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
## Detailed field field information for <%= parentLabel %>
|
|
2
|
+
<% if (parent) { %>
|
|
3
|
+
All values for these fields should be stored within the parent path of "<%= parent.data_path %>" (e.g. "<%= parentDataPath %>.childField")
|
|
4
|
+
<% } %>
|
|
3
5
|
### Field Information
|
|
4
6
|
<%= fields %>
|
|
7
|
+
<%= rules %>
|
|
5
8
|
|
|
6
|
-
Use the `collect_field_data` tool to collect field information that the user has provided.
|
|
9
|
+
Use the `collect_field_data` tool<% if (parent) { %> with the `parent_path`="<%= parent.data_path %>"<% } %> to collect field information that the user has provided, or use the `submission_update` tool to update existing records with new or modified values.
|
|
@@ -103,18 +103,10 @@ export declare class SchemaBuilder {
|
|
|
103
103
|
*/
|
|
104
104
|
submission_id_partial(): this;
|
|
105
105
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* ```json
|
|
110
|
-
* {
|
|
111
|
-
* "type": "datagrid",
|
|
112
|
-
* "isTable": true,
|
|
113
|
-
* "data_path": "children"
|
|
114
|
-
* }
|
|
115
|
-
* ```
|
|
106
|
+
* The path of the parent component that contains nested components to collect spcific data for.
|
|
107
|
+
* @returns
|
|
116
108
|
*/
|
|
117
|
-
|
|
109
|
+
parent_path(): this;
|
|
118
110
|
/**
|
|
119
111
|
* An array of field updates to apply to the `form_data`.
|
|
120
112
|
* Each update specifies the `data_path` and the complete new value.
|
|
@@ -142,26 +142,11 @@ class SchemaBuilder {
|
|
|
142
142
|
return this;
|
|
143
143
|
}
|
|
144
144
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* ```json
|
|
149
|
-
* {
|
|
150
|
-
* "type": "datagrid",
|
|
151
|
-
* "isTable": true,
|
|
152
|
-
* "data_path": "children"
|
|
153
|
-
* }
|
|
154
|
-
* ```
|
|
145
|
+
* The path of the parent component that contains nested components to collect spcific data for.
|
|
146
|
+
* @returns
|
|
155
147
|
*/
|
|
156
|
-
|
|
157
|
-
this.schema.
|
|
158
|
-
type: zod_1.default.string().describe('The type of the parent component that contains nested components to collect data for. To find the type, you can use the `get_form_fields` tool for this path and look at the **Type** of that field.'),
|
|
159
|
-
label: zod_1.default.string().optional().describe('The label of the parent component that contains nested components to collect data for. This comes from the **Label** property of the field provided by the `get_form_fields` tool.'),
|
|
160
|
-
isTable: zod_1.default.boolean().optional().describe('Indicates if the parent component is a table-like component (datagrid or editgrid). This means that the value of this component is an array of objects, where each row is a new context of data for the fields within. Set this value to `true` if the `get_form_fields` tool says to use `parent.isTable=true`.'),
|
|
161
|
-
isForm: zod_1.default.boolean().optional().describe('Indicates if the parent component is a nested form-like component. This means that the value of this component is in the format of `{data: {...}}` where `{...}` is the context of data for the fields within. Set this value to `true` if the `get_form_fields` tool says to use `parent.isForm=true`.'),
|
|
162
|
-
isContainer: zod_1.default.boolean().optional().describe('Indicates if the parent component is a container-like component. This means that the value of this component is in the format of `{...}` where `{...}` is the context of data for the fields within. Set this value to `true` if the `get_form_fields` tool says to use `parent.isContainer=true`.'),
|
|
163
|
-
data_path: zod_1.default.string().describe('The `data_path` of the parent component that contains nested components to collect data for. To find the data_path, you can use the `get_form_fields` tool.')
|
|
164
|
-
}).optional().describe('Optional parent component information if collecting data for a specific nested component within a form. If not provided, the tool assumes data is being collected for the root form.');
|
|
148
|
+
parent_path() {
|
|
149
|
+
this.schema.parent_path = zod_1.default.string().optional().describe('The `data_path` of the parent component that contains nested components. Use this parameter if collecting data for fields within a specific nested component within a form. To find the `parent_path`, you can use the `get_field_info` tool, and use the `data_path` of any component that ****Has Nested Components**** = ✅ Yes. If not provided, the tool assumes data is being collected for the root form.');
|
|
165
150
|
return this;
|
|
166
151
|
}
|
|
167
152
|
/**
|
package/lib/tools/collectData.js
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.collectData = void 0;
|
|
4
4
|
const template_1 = require("../template");
|
|
5
|
-
const utils_1 = require("./utils");
|
|
6
5
|
const lodash_1 = require("lodash");
|
|
7
6
|
const SchemaBuilder_1 = require("./SchemaBuilder");
|
|
8
|
-
const lodash_2 = require("lodash");
|
|
9
7
|
const collectData = async (project) => {
|
|
10
8
|
return (0, lodash_1.defaultsDeep)(project.config?.toolOverrides?.collect_field_data || {}, {
|
|
11
9
|
name: 'collect_field_data',
|
|
@@ -14,17 +12,15 @@ const collectData = async (project) => {
|
|
|
14
12
|
inputSchema: (new SchemaBuilder_1.SchemaBuilder(project))
|
|
15
13
|
.form_name()
|
|
16
14
|
.form_data()
|
|
17
|
-
.
|
|
15
|
+
.parent_path()
|
|
18
16
|
.updates().schema,
|
|
19
|
-
execute: async ({ form_name, form_data,
|
|
17
|
+
execute: async ({ form_name, form_data, parent_path, updates }, extra) => {
|
|
20
18
|
const form = await project.getForm(form_name);
|
|
21
19
|
if (!form) {
|
|
22
20
|
return project.mcpResponse(template_1.ResponseTemplate.formNotFound, { formName: form_name }, true);
|
|
23
21
|
}
|
|
24
22
|
// Ensure the parent is undefined if the type or data_path is missing.
|
|
25
|
-
|
|
26
|
-
parent = undefined;
|
|
27
|
-
}
|
|
23
|
+
const parent = form.getParentInfo(parent_path);
|
|
28
24
|
// Merge the updates into the current data.
|
|
29
25
|
for (const { data_path, new_value } of updates) {
|
|
30
26
|
form_data[data_path] = new_value;
|
|
@@ -36,34 +32,33 @@ const collectData = async (project) => {
|
|
|
36
32
|
if (fields.errors.length > 0) {
|
|
37
33
|
return project.mcpResponse(template_1.ResponseTemplate.fieldValidationErrors, { invalidFields: fields.errors });
|
|
38
34
|
}
|
|
39
|
-
const collectedData = parent ? (0, lodash_2.get)(submission, parent.data_path || '') : submission.data;
|
|
40
35
|
// If no required fields remain, then we can move onto a new tool.
|
|
41
36
|
if (!fields.required.components.length) {
|
|
42
37
|
return project.mcpResponse(template_1.ResponseTemplate.allFieldsCollected, {
|
|
43
38
|
form: form.form,
|
|
44
39
|
parent,
|
|
45
|
-
parentDataPath:
|
|
46
|
-
parentLabel:
|
|
40
|
+
parentDataPath: form.getParentDataPath(parent, fields.rowIndex),
|
|
41
|
+
parentLabel: form.getParentLabel(parent),
|
|
47
42
|
rowIndex: fields.rowIndex,
|
|
48
43
|
dataSummary: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.collectedData, {
|
|
49
|
-
data: form.formatData(
|
|
44
|
+
data: form.formatData(submission.data)
|
|
50
45
|
})
|
|
51
46
|
});
|
|
52
47
|
}
|
|
53
48
|
// Collect more required fields.
|
|
54
49
|
return project.mcpResponse(template_1.ResponseTemplate.fieldCollectedNext, {
|
|
55
50
|
parent,
|
|
56
|
-
parentDataPath:
|
|
57
|
-
parentLabel:
|
|
51
|
+
parentDataPath: form.getParentDataPath(parent, fields.rowIndex),
|
|
52
|
+
parentLabel: form.getParentLabel(parent),
|
|
58
53
|
message: 'Form data collected successfully!',
|
|
59
54
|
rules: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.fieldRules, { rules: Object.entries(fields.required.rules) }),
|
|
60
55
|
fields: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.fields, { fields: fields.required.components }),
|
|
61
56
|
dataSummary: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.collectedData, {
|
|
62
|
-
data: form.formatData(
|
|
57
|
+
data: form.formatData(submission.data)
|
|
63
58
|
}),
|
|
64
59
|
progress: {
|
|
65
60
|
collected: Object.keys(form_data).length,
|
|
66
|
-
total: fields.
|
|
61
|
+
total: fields.total
|
|
67
62
|
}
|
|
68
63
|
});
|
|
69
64
|
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.confirmSubmission = void 0;
|
|
4
4
|
const template_1 = require("../template");
|
|
5
|
-
const utils_1 = require("./utils");
|
|
6
5
|
const lodash_1 = require("lodash");
|
|
7
6
|
const SchemaBuilder_1 = require("./SchemaBuilder");
|
|
8
7
|
const confirmSubmission = async (project) => {
|
|
@@ -29,7 +28,7 @@ const confirmSubmission = async (project) => {
|
|
|
29
28
|
if (fields.required.components.length) {
|
|
30
29
|
return project.mcpResponse(template_1.ResponseTemplate.fieldCollectedNext, {
|
|
31
30
|
parent: undefined,
|
|
32
|
-
parentLabel:
|
|
31
|
+
parentLabel: form.getParentLabel(),
|
|
33
32
|
message: 'There is additional data that needs to be collected before submission.',
|
|
34
33
|
rules: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.fieldRules, { rules: Object.entries(fields.required.rules) }),
|
|
35
34
|
fields: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.fields, { fields: fields.required.components }),
|
|
@@ -44,11 +43,10 @@ const confirmSubmission = async (project) => {
|
|
|
44
43
|
}
|
|
45
44
|
// Confirm the submission.
|
|
46
45
|
return project.mcpResponse(template_1.ResponseTemplate.confirmFormSubmission, {
|
|
47
|
-
form,
|
|
46
|
+
parentLabel: form.getParentLabel(),
|
|
48
47
|
dataSummary: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.collectedData, {
|
|
49
48
|
data: form.formatData(submission.data)
|
|
50
|
-
})
|
|
51
|
-
currentData: form_data
|
|
49
|
+
})
|
|
52
50
|
});
|
|
53
51
|
}
|
|
54
52
|
});
|
|
@@ -12,17 +12,25 @@ const getFieldInfo = async (project) => {
|
|
|
12
12
|
description: 'Get detailed information about a specific field(s) that have been provided from the user. It is used to understand the properties, validation rules, and options of the specific field(s) the user has provided values for. This purpose of this tool is to provide detailed information for any field(s) (provided using the `field_paths` parameter) to help understand the structure and requirements of a form. PREREQUISITE: This tool should be called after the `get_form_fields` tool has been called AND once the user has provided some values for the provided fields.',
|
|
13
13
|
inputSchema: (new SchemaBuilder_1.SchemaBuilder(project))
|
|
14
14
|
.form_name()
|
|
15
|
-
.field_paths()
|
|
16
|
-
|
|
15
|
+
.field_paths()
|
|
16
|
+
.parent_path().schema,
|
|
17
|
+
execute: async ({ form_name, field_paths, parent_path }, extra) => {
|
|
17
18
|
const form = await project.getForm(form_name);
|
|
18
19
|
if (!form) {
|
|
19
20
|
return project.mcpResponse(template_1.ResponseTemplate.formNotFound, { formName: form_name }, true);
|
|
20
21
|
}
|
|
21
22
|
try {
|
|
23
|
+
// Get the parent info if a parent_path was provided.
|
|
24
|
+
const parent = form.getParentInfo(parent_path);
|
|
22
25
|
// Get the fields at the specified data path (or root if not provided).
|
|
23
26
|
const fields = await form.getFields({ data: {} }, extra.authInfo, field_paths);
|
|
27
|
+
const allRules = { ...fields.required.rules, ...fields.optional.rules };
|
|
24
28
|
// Show the form fields based on the criteria.
|
|
25
29
|
return project.mcpResponse(template_1.ResponseTemplate.getFormFieldsInfo, {
|
|
30
|
+
parent,
|
|
31
|
+
parentLabel: form.getParentLabel(parent),
|
|
32
|
+
parentDataPath: form.getParentDataPath(parent, fields.rowIndex),
|
|
33
|
+
rules: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.fieldRules, { rules: Object.entries(allRules) }),
|
|
26
34
|
fields: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.fields, {
|
|
27
35
|
fields: fields.required.components.concat(fields.optional.components)
|
|
28
36
|
}),
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getFormFields = void 0;
|
|
4
4
|
const template_1 = require("../template");
|
|
5
|
-
const utils_1 = require("./utils");
|
|
6
5
|
const lodash_1 = require("lodash");
|
|
7
6
|
const SchemaBuilder_1 = require("./SchemaBuilder");
|
|
8
7
|
const error = require('debug')('formio:uag:getFormFields:error');
|
|
@@ -13,30 +12,18 @@ const getFormFields = async (project) => {
|
|
|
13
12
|
description: 'Get high level overview of the fields that are present in a form, and to understand the "rules" on how the data for each field type should be collected. The purpose of this tool is to determine what fields the user is requesting (and to understand how to format that values for that data), and use that to create a list of field data_path\'s that the user is providing context for. This list can then be provided to the `get_field_info` tool to determine the specific field level information for those fields (validation, required, collection rules, etc). PREREQUISITE: You must call the `get_forms` tool first to understand what forms are available to submit and the permissions associated with those forms.',
|
|
14
13
|
inputSchema: (new SchemaBuilder_1.SchemaBuilder(project))
|
|
15
14
|
.form_name()
|
|
16
|
-
.form_data()
|
|
17
15
|
.criteria()
|
|
18
|
-
.
|
|
19
|
-
execute: async ({ form_name,
|
|
16
|
+
.parent_path().schema,
|
|
17
|
+
execute: async ({ form_name, criteria, parent_path }, extra) => {
|
|
20
18
|
const form = await project.getForm(form_name);
|
|
21
19
|
if (!form) {
|
|
22
20
|
return project.mcpResponse(template_1.ResponseTemplate.formNotFound, { formName: form_name }, true);
|
|
23
21
|
}
|
|
24
22
|
try {
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
parent = undefined;
|
|
28
|
-
}
|
|
29
|
-
// Get the submission data.
|
|
30
|
-
const submission = form.convertToSubmission(form_data);
|
|
23
|
+
// Get the parent info if a path was provided.
|
|
24
|
+
const parent = form.getParentInfo(parent_path);
|
|
31
25
|
// Get the fields at the specified data path (or root if not provided).
|
|
32
|
-
const fields = await form.getFields(
|
|
33
|
-
// If the agent requests optional fields, but there are still requird fields to fill out, then force required
|
|
34
|
-
// and inform the agent of this change.
|
|
35
|
-
let message = '';
|
|
36
|
-
if (criteria == 'optional' && fields.required.components.length > 0) {
|
|
37
|
-
criteria = 'required';
|
|
38
|
-
message = 'You requested "optional" fields, but the user is not finished collecting required information. Please finish collecting the following required fields first.\n\n';
|
|
39
|
-
}
|
|
26
|
+
const fields = await form.getFields({ data: {} }, extra.authInfo, parent?.data_path);
|
|
40
27
|
// Determine which fields to show based on the criteria.
|
|
41
28
|
const criteriaFields = criteria === 'all' ?
|
|
42
29
|
[...fields.required.components, ...fields.optional.components] :
|
|
@@ -44,7 +31,8 @@ const getFormFields = async (project) => {
|
|
|
44
31
|
if (criteriaFields.length === 0) {
|
|
45
32
|
return project.mcpResponse(template_1.ResponseTemplate.getFormFieldsEmpty, {
|
|
46
33
|
parent,
|
|
47
|
-
parentLabel:
|
|
34
|
+
parentLabel: form.getParentLabel(parent),
|
|
35
|
+
criteria,
|
|
48
36
|
type: (0, lodash_1.upperFirst)(criteria),
|
|
49
37
|
form: form.form,
|
|
50
38
|
});
|
|
@@ -53,37 +41,14 @@ const getFormFields = async (project) => {
|
|
|
53
41
|
const criteriaRules = criteria === 'all' ?
|
|
54
42
|
{ ...fields.required.rules, ...fields.optional.rules } :
|
|
55
43
|
criteria === 'required' ? fields.required.rules : fields.optional.rules;
|
|
56
|
-
let totalType = fields.total;
|
|
57
|
-
if (criteria === 'required') {
|
|
58
|
-
totalType = fields.totalRequired;
|
|
59
|
-
}
|
|
60
|
-
else if (criteria === 'optional') {
|
|
61
|
-
totalType = fields.total - fields.totalRequired;
|
|
62
|
-
}
|
|
63
|
-
const totalCollected = Object.keys(form_data || {}).length;
|
|
64
|
-
let totalTypeCollected = 0;
|
|
65
|
-
if (criteria === 'required') {
|
|
66
|
-
totalTypeCollected = fields.totalRequiredCollected;
|
|
67
|
-
}
|
|
68
|
-
else if (criteria === 'optional') {
|
|
69
|
-
totalTypeCollected = totalCollected - fields.totalRequiredCollected;
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
totalTypeCollected = totalCollected;
|
|
73
|
-
}
|
|
74
44
|
// Show the form fields based on the criteria.
|
|
75
45
|
return project.mcpResponse(template_1.ResponseTemplate.getFormFields, {
|
|
76
|
-
message,
|
|
77
46
|
parent,
|
|
78
|
-
parentLabel:
|
|
79
|
-
parentDataPath:
|
|
47
|
+
parentLabel: form.getParentLabel(parent),
|
|
48
|
+
parentDataPath: form.getParentDataPath(parent, fields.rowIndex),
|
|
80
49
|
type: (0, lodash_1.upperFirst)(criteria),
|
|
81
50
|
rules: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.fieldRules, { rules: Object.entries(criteriaRules) }),
|
|
82
|
-
fieldList: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.fieldList, { fields: criteriaFields })
|
|
83
|
-
totalFields: fields.total,
|
|
84
|
-
totalType,
|
|
85
|
-
totalCollected,
|
|
86
|
-
totalTypeCollected
|
|
51
|
+
fieldList: project.uagTemplate?.renderTemplate(template_1.ResponseTemplate.fieldList, { fields: criteriaFields })
|
|
87
52
|
});
|
|
88
53
|
}
|
|
89
54
|
catch (err) {
|
package/lib/tools/utils.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ZodRawShape } from "zod";
|
|
2
|
-
import { Form } from '@formio/core';
|
|
3
2
|
export type ToolInfo = {
|
|
4
3
|
name?: string;
|
|
5
4
|
title?: string;
|
|
@@ -24,5 +23,3 @@ export type SearchQuery = {
|
|
|
24
23
|
search_value: string;
|
|
25
24
|
operator: string;
|
|
26
25
|
};
|
|
27
|
-
export declare function getParentLabel(parent?: ParentInfo, form?: Form): string;
|
|
28
|
-
export declare function getParentDataPath(parent?: ParentInfo, rowIndex?: number): string;
|
package/lib/tools/utils.js
CHANGED
|
@@ -1,27 +1,2 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getParentLabel = getParentLabel;
|
|
4
|
-
exports.getParentDataPath = getParentDataPath;
|
|
5
|
-
function getParentLabel(parent, form) {
|
|
6
|
-
let parentLabel = form ? `the **${form.title} (${form.name})** form` : 'this form';
|
|
7
|
-
if (parent?.isTable) {
|
|
8
|
-
parentLabel = `this row within the **${parent.label}** component`;
|
|
9
|
-
}
|
|
10
|
-
else if (parent?.isForm) {
|
|
11
|
-
parentLabel = `the **${parent.label}** nested form`;
|
|
12
|
-
}
|
|
13
|
-
else if (parent?.isContainer) {
|
|
14
|
-
parentLabel = `the **${parent.label}** container component`;
|
|
15
|
-
}
|
|
16
|
-
return parentLabel;
|
|
17
|
-
}
|
|
18
|
-
function getParentDataPath(parent, rowIndex = -1) {
|
|
19
|
-
let parentDataPath = parent?.data_path || '';
|
|
20
|
-
if (parentDataPath && (rowIndex >= 0)) {
|
|
21
|
-
parentDataPath += `[${rowIndex}]`;
|
|
22
|
-
}
|
|
23
|
-
if (parent?.isForm) {
|
|
24
|
-
parentDataPath += '.data';
|
|
25
|
-
}
|
|
26
|
-
return parentDataPath;
|
|
27
|
-
}
|
package/package.json
CHANGED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# Optional Fields Available
|
|
2
|
-
|
|
3
|
-
All required fields have been collected for your **<%= form.title %>** form.
|
|
4
|
-
|
|
5
|
-
**Would you like to fill out any optional fields?**
|
|
6
|
-
|
|
7
|
-
There are <%= totalOptionalFields %> optional fields available:
|
|
8
|
-
<%= optionalFields %>
|
|
9
|
-
|
|
10
|
-
If values for any of these fields are already provided, then skip to the `collect_field_data` tool to add those additional fields. Otherwise, use the following options.
|
|
11
|
-
|
|
12
|
-
**Options:**
|
|
13
|
-
- Say "yes" or "I'd like to fill optional fields" to add optional information
|
|
14
|
-
- Say "no" or "skip optional fields" to proceed with just the required information
|
|
15
|
-
- Say the name of a specific field you'd like to fill (e.g., "email")
|
|
16
|
-
|
|
17
|
-
Use the `collect_field_data` tool to collect any optional fields the user wants to fill.
|
|
18
|
-
|
|
19
|
-
If they wish to skip the collection of optional fields, then use the `submit_completed_form` to submit the required data to the form.
|