@sealcode/sealgen 0.8.2 → 0.8.5
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/@types/forms/controls/autocomplete.d.ts +3 -1
- package/@types/forms/controls/checkbox-group.d.ts +3 -2
- package/@types/forms/controls/collapsible-checkbox-group.d.ts +1 -1
- package/@types/forms/controls/collapsible-field-group.d.ts +1 -1
- package/@types/forms/controls/controls.d.ts +3 -0
- package/@types/forms/controls/dropdown.d.ts +6 -5
- package/@types/forms/controls/field-group.d.ts +3 -3
- package/@types/forms/controls/file.d.ts +14 -0
- package/@types/forms/controls/form-control.d.ts +4 -1
- package/@types/forms/controls/form-field-control.d.ts +1 -1
- package/@types/forms/controls/multiple-files.d.ts +31 -0
- package/@types/forms/controls/number.d.ts +17 -0
- package/@types/forms/controls/simple-input.d.ts +20 -27
- package/@types/forms/controls/textarea.d.ts +9 -7
- package/@types/forms/fields/field.d.ts +4 -1
- package/@types/forms/fields/file.d.ts +16 -0
- package/@types/forms/fields/files-multiple.d.ts +12 -0
- package/@types/forms/fields/multiple-files.d.ts +14 -0
- package/@types/forms/fields/number.d.ts +10 -1
- package/@types/forms/form.d.ts +7 -4
- package/@types/forms/multiform.d.ts +3 -3
- package/@types/page/list.d.ts +1 -1
- package/@types/page/mountable-with-fields.d.ts +3 -2
- package/@types/page/page.d.ts +1 -1
- package/@types/sanitize.d.ts +1 -1
- package/lib/forms/controls/autocomplete.js.map +1 -1
- package/lib/forms/controls/checkbox-group.js +11 -5
- package/lib/forms/controls/checkbox-group.js.map +1 -1
- package/lib/forms/controls/collapsible-checkbox-group.js +2 -2
- package/lib/forms/controls/collapsible-checkbox-group.js.map +1 -1
- package/lib/forms/controls/collapsible-field-group.js.map +1 -1
- package/lib/forms/controls/controls.js +3 -0
- package/lib/forms/controls/controls.js.map +1 -1
- package/lib/forms/controls/derived.js +12 -11
- package/lib/forms/controls/derived.js.map +1 -1
- package/lib/forms/controls/dropdown.js +25 -18
- package/lib/forms/controls/dropdown.js.map +1 -1
- package/lib/forms/controls/field-group.js +3 -3
- package/lib/forms/controls/field-group.js.map +1 -1
- package/lib/forms/controls/file.js +38 -0
- package/lib/forms/controls/file.js.map +1 -0
- package/lib/forms/controls/form-control.js +1 -0
- package/lib/forms/controls/form-control.js.map +1 -1
- package/lib/forms/controls/form-field-control.js.map +1 -1
- package/lib/forms/controls/multiple-files.js +137 -0
- package/lib/forms/controls/multiple-files.js.map +1 -0
- package/lib/forms/controls/number.js +34 -0
- package/lib/forms/controls/number.js.map +1 -0
- package/lib/forms/controls/simple-input.js +20 -10
- package/lib/forms/controls/simple-input.js.map +1 -1
- package/lib/forms/controls/textarea.js +13 -22
- package/lib/forms/controls/textarea.js.map +1 -1
- package/lib/forms/fields/enum-multiple.js +4 -1
- package/lib/forms/fields/enum-multiple.js.map +1 -1
- package/lib/forms/fields/field.js +8 -1
- package/lib/forms/fields/field.js.map +1 -1
- package/lib/forms/fields/file.js +58 -0
- package/lib/forms/fields/file.js.map +1 -0
- package/lib/forms/fields/files-multiple.js +18 -0
- package/lib/forms/fields/files-multiple.js.map +1 -0
- package/lib/forms/fields/multiple-files.js +19 -0
- package/lib/forms/fields/multiple-files.js.map +1 -0
- package/lib/forms/fields/number.js +6 -2
- package/lib/forms/fields/number.js.map +1 -1
- package/lib/forms/form.js +38 -21
- package/lib/forms/form.js.map +1 -1
- package/lib/forms/multiform.js +8 -8
- package/lib/forms/multiform.js.map +1 -1
- package/lib/page/list.js +9 -6
- package/lib/page/list.js.map +1 -1
- package/lib/page/mountable-with-fields.js +16 -3
- package/lib/page/mountable-with-fields.js.map +1 -1
- package/lib/page/page.js +1 -1
- package/lib/page/page.js.map +1 -1
- package/lib/sanitize.js +3 -0
- package/lib/sanitize.js.map +1 -1
- package/lib/tests/manual/multiform.js +13 -13
- package/lib/tests/manual/multiform.js.map +1 -1
- package/package.json +2 -2
- package/src/forms/controls/autocomplete.ts +2 -6
- package/src/forms/controls/checkbox-group.ts +17 -6
- package/src/forms/controls/collapsible-checkbox-group.ts +10 -2
- package/src/forms/controls/collapsible-field-group.ts +2 -4
- package/src/forms/controls/controls.ts +3 -0
- package/src/forms/controls/derived.ts +12 -11
- package/src/forms/controls/dropdown.ts +51 -34
- package/src/forms/controls/field-group.ts +6 -4
- package/src/forms/controls/file.ts +50 -0
- package/src/forms/controls/form-control.ts +5 -1
- package/src/forms/controls/form-field-control.ts +2 -1
- package/src/forms/controls/multiple-files.ts +213 -0
- package/src/forms/controls/number.ts +52 -0
- package/src/forms/controls/simple-input.ts +67 -37
- package/src/forms/controls/textarea.ts +23 -24
- package/src/forms/fields/enum-multiple.ts +3 -1
- package/src/forms/fields/field.ts +12 -2
- package/src/forms/fields/file.ts +86 -0
- package/src/forms/fields/multiple-files.ts +20 -0
- package/src/forms/fields/number.ts +17 -2
- package/src/forms/form.ts +84 -42
- package/src/forms/forms.scss +4 -1
- package/src/forms/multiform.ts +26 -13
- package/src/page/list.ts +10 -7
- package/src/page/mountable-with-fields.ts +26 -4
- package/src/page/page.ts +3 -1
- package/src/sanitize.ts +4 -1
- package/src/tests/manual/multiform.ts +19 -13
package/src/forms/multiform.ts
CHANGED
|
@@ -29,7 +29,7 @@ export class Multiform extends MountableWithFields {
|
|
|
29
29
|
form.form_id = this.name;
|
|
30
30
|
form.action = "./" + key;
|
|
31
31
|
form.init();
|
|
32
|
-
form.extractRawValues = (context) =>
|
|
32
|
+
form.extractRawValues = async (context) =>
|
|
33
33
|
this.getSubformRawValues(context, key);
|
|
34
34
|
const submit_button_id = this.name + "_" + key + "_submit";
|
|
35
35
|
|
|
@@ -52,7 +52,9 @@ export class Multiform extends MountableWithFields {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
extractRawValues(
|
|
55
|
+
async extractRawValues(
|
|
56
|
+
ctx: Context
|
|
57
|
+
): Promise<Record<string, FormDataValue>> {
|
|
56
58
|
return ctx.$body || {};
|
|
57
59
|
}
|
|
58
60
|
|
|
@@ -86,17 +88,22 @@ export class Multiform extends MountableWithFields {
|
|
|
86
88
|
|
|
87
89
|
async renderSubform(
|
|
88
90
|
ctx: Context,
|
|
89
|
-
sub_form_name: string
|
|
91
|
+
sub_form_name: string,
|
|
92
|
+
show_field_errors: boolean
|
|
90
93
|
): Promise<FlatTemplatable> {
|
|
91
94
|
const form = this.forms[sub_form_name];
|
|
92
95
|
const result = await form.canAccess(ctx);
|
|
93
96
|
if (!result.canAccess) {
|
|
94
97
|
return result.message;
|
|
95
98
|
}
|
|
96
|
-
return form.render(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
return form.render(
|
|
100
|
+
ctx,
|
|
101
|
+
{
|
|
102
|
+
raw_values: this.getSubformRawValues(ctx, sub_form_name),
|
|
103
|
+
messages: [],
|
|
104
|
+
},
|
|
105
|
+
show_field_errors
|
|
106
|
+
);
|
|
100
107
|
}
|
|
101
108
|
|
|
102
109
|
getSubformRawValues(
|
|
@@ -119,7 +126,8 @@ export class Multiform extends MountableWithFields {
|
|
|
119
126
|
async render(
|
|
120
127
|
ctx: Context,
|
|
121
128
|
messages: FormMessage[],
|
|
122
|
-
prerenderedForms: Record<string, FlatTemplatable | undefined> = {}
|
|
129
|
+
prerenderedForms: Record<string, FlatTemplatable | undefined> = {},
|
|
130
|
+
show_field_errors: boolean
|
|
123
131
|
): Promise<FlatTemplatable> {
|
|
124
132
|
return tempstream/* HTML */ `${this.renderMessages(ctx, {
|
|
125
133
|
raw_values: {},
|
|
@@ -143,7 +151,7 @@ export class Multiform extends MountableWithFields {
|
|
|
143
151
|
subform-id="${frame_form_id}"
|
|
144
152
|
>
|
|
145
153
|
${prerenderedForms[form_name] ||
|
|
146
|
-
this.renderSubform(ctx, form_name)}
|
|
154
|
+
this.renderSubform(ctx, form_name, show_field_errors)}
|
|
147
155
|
<form id="${frame_form_id}" method="POST"></form>
|
|
148
156
|
</turbo-frame>`;
|
|
149
157
|
})}
|
|
@@ -188,7 +196,7 @@ export class Multiform extends MountableWithFields {
|
|
|
188
196
|
mount(router: Router, path: string): void {
|
|
189
197
|
router.get(path, async (ctx) => {
|
|
190
198
|
ctx.type = "html";
|
|
191
|
-
ctx.body = await this.render(ctx, [], {});
|
|
199
|
+
ctx.body = await this.render(ctx, [], {}, false);
|
|
192
200
|
});
|
|
193
201
|
|
|
194
202
|
for (const [key, form] of Object.entries(this.forms)) {
|
|
@@ -199,9 +207,14 @@ export class Multiform extends MountableWithFields {
|
|
|
199
207
|
if (reaction.action == "stay") {
|
|
200
208
|
ctx.status = 422;
|
|
201
209
|
const form_content = reaction.content;
|
|
202
|
-
ctx.body = this.render(
|
|
203
|
-
|
|
204
|
-
|
|
210
|
+
ctx.body = this.render(
|
|
211
|
+
ctx,
|
|
212
|
+
[],
|
|
213
|
+
{
|
|
214
|
+
[key]: form_content,
|
|
215
|
+
},
|
|
216
|
+
true
|
|
217
|
+
);
|
|
205
218
|
} else if (reaction.action == "redirect") {
|
|
206
219
|
ctx.status = 303;
|
|
207
220
|
ctx.redirect(reaction.url);
|
package/src/page/list.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Templatable, tempstream, FlatTemplatable } from "tempstream";
|
|
|
5
5
|
import { peopleWhoCan } from "./access-control";
|
|
6
6
|
import { Page } from "./page";
|
|
7
7
|
import { ShapeToType } from "@sealcode/ts-predicates";
|
|
8
|
-
import { FormControl
|
|
8
|
+
import { FormControl } from "../forms/controls/controls";
|
|
9
9
|
import { FormField, NumberField } from "../forms/fields/field";
|
|
10
10
|
import { naturalNumbers, UrlWithNewParams } from "../utils/utils";
|
|
11
11
|
import { FormDataValue } from "..";
|
|
@@ -54,9 +54,12 @@ export abstract class ListPage<
|
|
|
54
54
|
|
|
55
55
|
async renderItems(
|
|
56
56
|
ctx: Context,
|
|
57
|
-
values
|
|
57
|
+
values?: Record<string, FormDataValue>,
|
|
58
58
|
items?: ItemType[]
|
|
59
59
|
): Promise<FlatTemplatable> {
|
|
60
|
+
if (!values) {
|
|
61
|
+
values = await this.extractRawValues(ctx);
|
|
62
|
+
}
|
|
60
63
|
const { parsed: page } = await this.fields.page.getValue(ctx, values);
|
|
61
64
|
const { parsed: itemsPerPage } =
|
|
62
65
|
await this.fields.itemsPerPage.getValue(ctx, values);
|
|
@@ -68,7 +71,7 @@ export abstract class ListPage<
|
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
async render(ctx: Context): Promise<FlatTemplatable> {
|
|
71
|
-
const values = this.extractRawValues(ctx);
|
|
74
|
+
const values = await this.extractRawValues(ctx);
|
|
72
75
|
|
|
73
76
|
return tempstream`${this.renderPagination(ctx, values)}
|
|
74
77
|
${this.renderFilters(ctx)}
|
|
@@ -130,7 +133,7 @@ ${this.renderListContainer(ctx, this.renderItems(ctx, values))}`;
|
|
|
130
133
|
|
|
131
134
|
async getFilterValues(ctx: Context): Promise<Record<string, unknown>> {
|
|
132
135
|
const filter = {} as Record<string, unknown>;
|
|
133
|
-
const raw_values = this.extractRawValues(ctx);
|
|
136
|
+
const raw_values = await this.extractRawValues(ctx);
|
|
134
137
|
for (const [fieldname, field] of Object.entries(this.filterFields)) {
|
|
135
138
|
// eslint-disable-next-line no-await-in-loop
|
|
136
139
|
const { parsed } = await field.getValue(ctx, raw_values);
|
|
@@ -139,8 +142,8 @@ ${this.renderListContainer(ctx, this.renderItems(ctx, values))}`;
|
|
|
139
142
|
return filter;
|
|
140
143
|
}
|
|
141
144
|
|
|
142
|
-
renderFilters(ctx: Context): FlatTemplatable {
|
|
143
|
-
const values = this.extractRawValues(ctx);
|
|
145
|
+
async renderFilters(ctx: Context): Promise<FlatTemplatable> {
|
|
146
|
+
const values = await this.extractRawValues(ctx);
|
|
144
147
|
return tempstream/* HTML */ `<form method="GET">
|
|
145
148
|
${makeHiddenInputs(ctx, this.fields, values, [
|
|
146
149
|
"page",
|
|
@@ -148,7 +151,7 @@ ${this.renderListContainer(ctx, this.renderItems(ctx, values))}`;
|
|
|
148
151
|
])}
|
|
149
152
|
${this.filterControls.map((control) => {
|
|
150
153
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
151
|
-
return control.render(ctx, values, [], "", "");
|
|
154
|
+
return control.render(ctx, values, [], "", "", false);
|
|
152
155
|
})}
|
|
153
156
|
</form>`;
|
|
154
157
|
}
|
|
@@ -77,15 +77,18 @@ export abstract class MountableWithFields<
|
|
|
77
77
|
|
|
78
78
|
public renderControls(
|
|
79
79
|
ctx: Context,
|
|
80
|
-
data: FormData<keyof Fields
|
|
80
|
+
data: FormData<keyof Fields>,
|
|
81
|
+
validate: boolean
|
|
81
82
|
): FlatTemplatable {
|
|
83
|
+
console.log("RENDER CONTROLS", data.raw_values);
|
|
82
84
|
return tempstream/* HTML */ `${this.controls.map((control) =>
|
|
83
85
|
control.render(
|
|
84
86
|
ctx,
|
|
85
87
|
data.raw_values,
|
|
86
88
|
data.messages,
|
|
87
89
|
this.field_names_prefix,
|
|
88
|
-
this.form_id
|
|
90
|
+
this.form_id,
|
|
91
|
+
validate
|
|
89
92
|
)
|
|
90
93
|
)}`;
|
|
91
94
|
}
|
|
@@ -109,12 +112,14 @@ export abstract class MountableWithFields<
|
|
|
109
112
|
</div>`;
|
|
110
113
|
}
|
|
111
114
|
|
|
112
|
-
abstract extractRawValues(
|
|
115
|
+
abstract extractRawValues(
|
|
116
|
+
ctx: Context
|
|
117
|
+
): Promise<Record<string, FormDataValue>>;
|
|
113
118
|
|
|
114
119
|
async getParsedValues(
|
|
115
120
|
ctx: Context
|
|
116
121
|
): Promise<ShapeToType<FieldsToShape<F>>> {
|
|
117
|
-
const raw_values = this.extractRawValues(ctx);
|
|
122
|
+
const raw_values = await this.extractRawValues(ctx);
|
|
118
123
|
const result: Record<string, unknown> = {};
|
|
119
124
|
const promises = Object.entries(this.fields).map(
|
|
120
125
|
async ([key, field]) => {
|
|
@@ -125,4 +130,21 @@ export abstract class MountableWithFields<
|
|
|
125
130
|
await Promise.all(promises);
|
|
126
131
|
return result as ShapeToType<FieldsToShape<F>>;
|
|
127
132
|
}
|
|
133
|
+
|
|
134
|
+
async getDatabaseValues(
|
|
135
|
+
ctx: Context
|
|
136
|
+
): Promise<ShapeToType<FieldsToShape<F>>> {
|
|
137
|
+
const raw_values = await this.extractRawValues(ctx);
|
|
138
|
+
const result: Record<string, unknown> = {};
|
|
139
|
+
const promises = Object.entries(this.fields).map(
|
|
140
|
+
async ([key, field]) => {
|
|
141
|
+
const db_value = await field.getDatabaseValue(ctx, raw_values);
|
|
142
|
+
if (db_value !== undefined) {
|
|
143
|
+
result[key] = db_value;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
await Promise.all(promises);
|
|
148
|
+
return result as ShapeToType<FieldsToShape<F>>;
|
|
149
|
+
}
|
|
128
150
|
}
|
package/src/page/page.ts
CHANGED
|
@@ -38,7 +38,9 @@ export abstract class Page<
|
|
|
38
38
|
|
|
39
39
|
public abstract render(ctx: Context): Promise<FlatTemplatable>;
|
|
40
40
|
|
|
41
|
-
extractRawValues(
|
|
41
|
+
async extractRawValues(
|
|
42
|
+
ctx: Context
|
|
43
|
+
): Promise<Record<string, FormDataValue>> {
|
|
42
44
|
return this.propsParser.decode(ctx);
|
|
43
45
|
}
|
|
44
46
|
}
|
package/src/sanitize.ts
CHANGED
|
@@ -49,20 +49,26 @@ const multiform = new (class extends Multiform {
|
|
|
49
49
|
async render(
|
|
50
50
|
ctx: Koa.Context,
|
|
51
51
|
messages: FormMessage[],
|
|
52
|
-
prerenderedForms?: Record<string, FlatTemplatable | undefined
|
|
52
|
+
prerenderedForms?: Record<string, FlatTemplatable | undefined>,
|
|
53
|
+
show_field_errors: boolean = true
|
|
53
54
|
): Promise<FlatTemplatable> {
|
|
54
|
-
return tempstream`<!DOCTYPE html>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
55
|
+
return tempstream/* HTML */ `<!DOCTYPE html>
|
|
56
|
+
<html>
|
|
57
|
+
<head>
|
|
58
|
+
<title>Multiform Test - Sealgen</title>
|
|
59
|
+
<script type="module">
|
|
60
|
+
import hotwiredTurbo from "https://cdn.skypack.dev/pin/@hotwired/turbo@v7.0.0-9XNv1By6uiqRlBzQLO2d/mode=imports,min/optimized/@hotwired/turbo.js";
|
|
61
|
+
</script>
|
|
62
|
+
</head>
|
|
63
|
+
<body>
|
|
64
|
+
${super.render(
|
|
65
|
+
ctx,
|
|
66
|
+
messages,
|
|
67
|
+
prerenderedForms,
|
|
68
|
+
show_field_errors
|
|
69
|
+
)}
|
|
70
|
+
</body>
|
|
71
|
+
</html>`;
|
|
66
72
|
}
|
|
67
73
|
})();
|
|
68
74
|
|