@sealcode/sealgen 0.15.34 → 0.15.35
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/src/forms/controls/controls.d.ts +1 -0
- package/@types/src/forms/controls/table.d.ts +15 -0
- package/@types/src/forms/fields/fields.d.ts +1 -0
- package/@types/src/forms/fields/table.d.ts +12 -0
- package/@types/src/templates/shared/collection-create-form.d.ts +2 -0
- package/@types/src/templates/shared/collection-edit-form.d.ts +1 -0
- package/@types/src/templates/shared/collection-list.d.ts +1 -0
- package/@types/src/templates/shared/confirm-item-delete.d.ts +1 -0
- package/@types/src/templates/shared/item-delete.d.ts +1 -0
- package/@types/src/templates/shared/shared-crud-form-fields.d.ts +44 -0
- package/lib/add-crud.js +131 -0
- package/lib/forms/controls/controls.js +1 -0
- package/lib/forms/controls/table.js +62 -0
- package/lib/forms/fields/fields.js +1 -0
- package/lib/forms/fields/table.js +58 -0
- package/lib/templates/shared/collection-create-form.js +146 -0
- package/lib/templates/shared/collection-edit-form.js +200 -0
- package/lib/templates/shared/collection-list.js +211 -0
- package/lib/templates/shared/confirm-item-delete.js +72 -0
- package/lib/templates/shared/item-delete.js +41 -0
- package/lib/templates/shared/shared-crud-form-fields.js +118 -0
- package/lib/utils/write-file.js +11 -0
- package/package.json +1 -1
- package/src/forms/controls/controls.ts +1 -0
- package/src/forms/controls/table.ts +78 -0
- package/src/forms/fields/fields.ts +1 -0
- package/src/forms/fields/table.ts +72 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { FlatTemplatable } from "tempstream";
|
|
2
|
+
import { FormField } from "../fields/field.js";
|
|
3
|
+
import { Table as TableField } from "../fields/table.js";
|
|
4
|
+
import { FormControl, FormControlContext } from "./form-control.js";
|
|
5
|
+
|
|
6
|
+
export class Table<F extends Record<string, FormField>> extends FormControl {
|
|
7
|
+
role = <const>"input";
|
|
8
|
+
constructor(
|
|
9
|
+
public table_field: TableField<F>,
|
|
10
|
+
public render_fields: {
|
|
11
|
+
[field_name in keyof F]: (
|
|
12
|
+
fctx: FormControlContext,
|
|
13
|
+
name: string,
|
|
14
|
+
value: string
|
|
15
|
+
) => string;
|
|
16
|
+
}
|
|
17
|
+
) {
|
|
18
|
+
super();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
22
|
+
const { parsed: rows } = await this.table_field.getValue(
|
|
23
|
+
fctx.ctx,
|
|
24
|
+
fctx.data
|
|
25
|
+
);
|
|
26
|
+
if (!rows) {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
return /* HTML */ `<div
|
|
30
|
+
class="${[
|
|
31
|
+
"form-input__wrapper",
|
|
32
|
+
"form-input__wrapper--type--table",
|
|
33
|
+
"form-input__wrapper--options-count--" + rows.length.toString(),
|
|
34
|
+
...(rows.length >= 5
|
|
35
|
+
? ["form-input__wrapper--options-count--5-or-more"]
|
|
36
|
+
: []),
|
|
37
|
+
...(rows.length >= 10
|
|
38
|
+
? ["form-input__wrapper--options-count--10-or-more"]
|
|
39
|
+
: []),
|
|
40
|
+
...(rows.length >= 15
|
|
41
|
+
? ["form-input__wrapper--options-count--15-or-more"]
|
|
42
|
+
: []),
|
|
43
|
+
...(rows.length >= 20
|
|
44
|
+
? ["form-input__wrapper--options-count--20-or-more"]
|
|
45
|
+
: []),
|
|
46
|
+
].join(" ")}"
|
|
47
|
+
>
|
|
48
|
+
<div class="table__wrapper">
|
|
49
|
+
<table>
|
|
50
|
+
<tbody>
|
|
51
|
+
<tr>
|
|
52
|
+
${rows
|
|
53
|
+
?.map((row, row_index) => {
|
|
54
|
+
return /* HTML */ `<tr>
|
|
55
|
+
${Object.entries(
|
|
56
|
+
this.table_field.columns
|
|
57
|
+
)
|
|
58
|
+
.map(([key]) => {
|
|
59
|
+
return `<td>${this.render_fields[
|
|
60
|
+
key
|
|
61
|
+
](
|
|
62
|
+
fctx,
|
|
63
|
+
`${this.table_field.name}[${row_index}][${key}]`,
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
65
|
+
row[key] as string
|
|
66
|
+
)}</td>`;
|
|
67
|
+
})
|
|
68
|
+
.join("")}
|
|
69
|
+
</tr>`;
|
|
70
|
+
})
|
|
71
|
+
.join("")}
|
|
72
|
+
</tr>
|
|
73
|
+
</tbody>
|
|
74
|
+
</table>
|
|
75
|
+
</div>
|
|
76
|
+
</div>`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { is, predicates } from "@sealcode/ts-predicates";
|
|
2
|
+
import { Context } from "koa";
|
|
3
|
+
import { FormDataValue } from "../form-types.js";
|
|
4
|
+
import { FieldParseResult, FormField } from "./field.js";
|
|
5
|
+
|
|
6
|
+
export type TableFieldParsed<F extends Record<string, FormField>> = {
|
|
7
|
+
[field_name in keyof F]: unknown;
|
|
8
|
+
}[];
|
|
9
|
+
|
|
10
|
+
export class Table<F extends Record<string, FormField>> extends FormField<
|
|
11
|
+
true,
|
|
12
|
+
TableFieldParsed<F>
|
|
13
|
+
> {
|
|
14
|
+
constructor(public columns: F) {
|
|
15
|
+
super(true);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getEmptyValue() {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async parse(
|
|
23
|
+
ctx: Context,
|
|
24
|
+
raw_value: FormDataValue
|
|
25
|
+
): Promise<FieldParseResult<TableFieldParsed<F>>> {
|
|
26
|
+
// we expect an array-like object: {"0": {...}, ...etc}
|
|
27
|
+
if (!is(raw_value, predicates.object)) {
|
|
28
|
+
return {
|
|
29
|
+
parsable: false,
|
|
30
|
+
error: "Expected an object",
|
|
31
|
+
parsed_value: null,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const result: { [field_name in keyof F]: unknown }[] = [];
|
|
35
|
+
for (const row_number in raw_value) {
|
|
36
|
+
const row_data = raw_value[row_number];
|
|
37
|
+
const parsed_row: Record<string, unknown> = {};
|
|
38
|
+
if (!is(row_data, predicates.object)) {
|
|
39
|
+
throw new Error(`Expected object, got ${String(row_data)}`);
|
|
40
|
+
}
|
|
41
|
+
for (const key in row_data) {
|
|
42
|
+
const field = this.columns[key];
|
|
43
|
+
if (field == undefined) {
|
|
44
|
+
return {
|
|
45
|
+
parsable: false,
|
|
46
|
+
error: `Unknown column: ${key}`,
|
|
47
|
+
parsed_value: null,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// eslint-disable-next-line no-await-in-loop, @typescript-eslint/no-explicit-any, @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
51
|
+
const parse_result = await field.parse(
|
|
52
|
+
ctx,
|
|
53
|
+
(row_data as any)[key]
|
|
54
|
+
);
|
|
55
|
+
if (!parse_result.parsable) {
|
|
56
|
+
console.debug("table.ts:51");
|
|
57
|
+
return {
|
|
58
|
+
parsable: false,
|
|
59
|
+
error: `Invalid value for row ${row_number}.${key}: ${parse_result.error}`,
|
|
60
|
+
parsed_value: null,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
|
|
64
|
+
parsed_row[key] = parse_result.parsed_value as any;
|
|
65
|
+
}
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
67
|
+
result.push(parsed_row as { [field_name in keyof F]: unknown });
|
|
68
|
+
}
|
|
69
|
+
const ret = { parsed_value: result, parsable: true, error: null };
|
|
70
|
+
return ret as FieldParseResult<TableFieldParsed<F>>;
|
|
71
|
+
}
|
|
72
|
+
}
|