@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,15 @@
|
|
|
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
|
+
export declare class Table<F extends Record<string, FormField>> extends FormControl {
|
|
6
|
+
table_field: TableField<F>;
|
|
7
|
+
render_fields: {
|
|
8
|
+
[field_name in keyof F]: (fctx: FormControlContext, name: string, value: string) => string;
|
|
9
|
+
};
|
|
10
|
+
role: "input";
|
|
11
|
+
constructor(table_field: TableField<F>, render_fields: {
|
|
12
|
+
[field_name in keyof F]: (fctx: FormControlContext, name: string, value: string) => string;
|
|
13
|
+
});
|
|
14
|
+
render(fctx: FormControlContext): Promise<FlatTemplatable>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Context } from "koa";
|
|
2
|
+
import { FormDataValue } from "../form-types.js";
|
|
3
|
+
import { FieldParseResult, FormField } from "./field.js";
|
|
4
|
+
export type TableFieldParsed<F extends Record<string, FormField>> = {
|
|
5
|
+
[field_name in keyof F]: unknown;
|
|
6
|
+
}[];
|
|
7
|
+
export declare class Table<F extends Record<string, FormField>> extends FormField<true, TableFieldParsed<F>> {
|
|
8
|
+
columns: F;
|
|
9
|
+
constructor(columns: F);
|
|
10
|
+
getEmptyValue(): never[];
|
|
11
|
+
parse(ctx: Context, raw_value: FormDataValue): Promise<FieldParseResult<TableFieldParsed<F>>>;
|
|
12
|
+
}
|
|
@@ -1 +1,3 @@
|
|
|
1
|
+
import { ExtractedFieldInfo } from "../../utils/extract-fields-from-collection.js";
|
|
2
|
+
export declare function renderFieldForSealious({ name, type, is_required, is_readonly, }: ExtractedFieldInfo): string;
|
|
1
3
|
export declare function createItemFormTemplate(create_action_name: string, newfilefullpath: string, collection_name: string, list_action: string): Promise<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function editItemFormTemplate(edit_action_name: string, newfilefullpath: string, collection_name: string, list_action: string): Promise<string>;
|
|
@@ -10,6 +10,7 @@ declare const default_hooks: {
|
|
|
10
10
|
pre_header_html: string;
|
|
11
11
|
post_header_html: string;
|
|
12
12
|
post_import_js: string;
|
|
13
|
+
render_item: (collection_name: string) => string;
|
|
13
14
|
};
|
|
14
15
|
export declare function collectionListTemplate(collection_name: string, action_name: string, newfilefullpath: string, _hooks?: Partial<typeof default_hooks>): Promise<string>;
|
|
15
16
|
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function askItemDeleteTemplate(ask_delete_action_name: string, collection_name: string, newfilefullpath: string, list_action_name: string, delete_action_name: string): Promise<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function itemDeleteTemplate(delete_action_name: string, collection_name: string, newfilefullpath: string, list_action_name: string): Promise<string>;
|
|
@@ -1 +1,45 @@
|
|
|
1
|
+
import { ExtractedFieldInfo } from "../../utils/extract-fields-from-collection.js";
|
|
2
|
+
type FieldHandlerResult = {
|
|
3
|
+
imports: Partial<{
|
|
4
|
+
shared: string;
|
|
5
|
+
edit: string;
|
|
6
|
+
}>;
|
|
7
|
+
field: string;
|
|
8
|
+
controls: string;
|
|
9
|
+
is_required: boolean;
|
|
10
|
+
is_required_expr: string;
|
|
11
|
+
fields_var: string;
|
|
12
|
+
top_level_shared: string;
|
|
13
|
+
name: string;
|
|
14
|
+
initial_value: Partial<{
|
|
15
|
+
main_value: string;
|
|
16
|
+
parsed_value: string;
|
|
17
|
+
fallback_value: string;
|
|
18
|
+
}> | string;
|
|
19
|
+
post_edit: string;
|
|
20
|
+
};
|
|
21
|
+
type FieldHandler<Defaults extends Partial<FieldHandlerResult>, Result extends Partial<FieldHandlerResult>> = (collection_name: string, field: ExtractedFieldInfo, importPath: (path: string) => string, defaults: Defaults) => Promise<Result>;
|
|
22
|
+
export declare const field_handlers: Record<string, FieldHandler<FieldHandlerResult, Partial<FieldHandlerResult>> | undefined> & {
|
|
23
|
+
default: FieldHandler<Record<string, never>, FieldHandlerResult>;
|
|
24
|
+
};
|
|
25
|
+
export declare function getFieldHandler(collection_name: string, field: ExtractedFieldInfo, importPath: (path: string) => string): Promise<{
|
|
26
|
+
imports: Partial<{
|
|
27
|
+
shared: string;
|
|
28
|
+
edit: string;
|
|
29
|
+
}>;
|
|
30
|
+
field: string;
|
|
31
|
+
controls: string;
|
|
32
|
+
is_required: boolean;
|
|
33
|
+
is_required_expr: string;
|
|
34
|
+
fields_var: string;
|
|
35
|
+
top_level_shared: string;
|
|
36
|
+
name: string;
|
|
37
|
+
initial_value: string | Partial<{
|
|
38
|
+
main_value: string;
|
|
39
|
+
parsed_value: string;
|
|
40
|
+
fallback_value: string;
|
|
41
|
+
}>;
|
|
42
|
+
post_edit: string;
|
|
43
|
+
}>;
|
|
1
44
|
export declare function sharedCrudFormFields(collection_name: string, newfilefullpath: string): Promise<string>;
|
|
45
|
+
export {};
|
package/lib/add-crud.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import _locreq from "locreq";
|
|
2
|
+
import { escape_url_params } from "./utils/escape-url-params.js";
|
|
3
|
+
import prompts from "prompts";
|
|
4
|
+
import { toKebabCase, toPascalCase } from "js-convert-case";
|
|
5
|
+
import { listCollections } from "./utils/list-collections.js";
|
|
6
|
+
import { collectionListTemplate } from "./templates/shared/collection-list.js";
|
|
7
|
+
import { writeFile } from "./utils/write-file.js";
|
|
8
|
+
import { importPath } from "./utils/import-path.js";
|
|
9
|
+
import { sharedCrudFormFields } from "./templates/shared/shared-crud-form-fields.js";
|
|
10
|
+
import { generateRoutes } from "./generate-routes.js";
|
|
11
|
+
import { createItemFormTemplate } from "./templates/shared/collection-create-form.js";
|
|
12
|
+
import { editItemFormTemplate } from "./templates/shared/collection-edit-form.js";
|
|
13
|
+
import { askItemDeleteTemplate } from "./templates/shared/confirm-item-delete.js";
|
|
14
|
+
import { itemDeleteTemplate } from "./templates/shared/item-delete.js";
|
|
15
|
+
async function addCRUD(params, app_directory = process.cwd()) {
|
|
16
|
+
const target_locreq = _locreq(app_directory);
|
|
17
|
+
prompts.override(params);
|
|
18
|
+
const response = await prompts([
|
|
19
|
+
{
|
|
20
|
+
type: "autocomplete",
|
|
21
|
+
name: "collection",
|
|
22
|
+
message: "Which sealious collection do you like to add CRUD forms for?",
|
|
23
|
+
choices: (await listCollections()).map((collection) => ({
|
|
24
|
+
title: collection,
|
|
25
|
+
value: collection
|
|
26
|
+
}))
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
type: "text",
|
|
30
|
+
name: "url",
|
|
31
|
+
message: "Enter a full absolute path for the new route (for example: /admin/users/:id/edit): ",
|
|
32
|
+
validate: (s) => s.trim()[0] == "/" ? true : "Should start with a '/'",
|
|
33
|
+
initial: function(_, { collection }) {
|
|
34
|
+
return "/" + toKebabCase(collection);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
]);
|
|
38
|
+
const collection_name = response.collection;
|
|
39
|
+
const url = response.url;
|
|
40
|
+
const list_action_name = toPascalCase(collection_name) + "List";
|
|
41
|
+
const create_action_name = toPascalCase(collection_name) + "Create";
|
|
42
|
+
const edit_action_name = toPascalCase(collection_name) + "Edit";
|
|
43
|
+
const delete_ask_action_name = toPascalCase(collection_name) + "DeleteAsk";
|
|
44
|
+
const delete_action_name = toPascalCase(collection_name) + "Delete";
|
|
45
|
+
const list_path = target_locreq.resolve(
|
|
46
|
+
`src/back/routes/${escape_url_params(url)}.list.tsx`
|
|
47
|
+
);
|
|
48
|
+
const list_content = await collectionListTemplate(
|
|
49
|
+
collection_name,
|
|
50
|
+
list_action_name,
|
|
51
|
+
list_path,
|
|
52
|
+
{
|
|
53
|
+
post_import_js: `import { ${create_action_name}URL, ${edit_action_name}URL, ${delete_ask_action_name}URL } from "${importPath(
|
|
54
|
+
list_path,
|
|
55
|
+
"src/back/routes/urls.ts"
|
|
56
|
+
)}";`,
|
|
57
|
+
post_header_html: `<a href={${create_action_name}URL}> Create </a>`,
|
|
58
|
+
render_item: (collection_name2) => ` async renderItem(ctx: Context, item: CollectionItem<typeof ${toPascalCase(
|
|
59
|
+
collection_name2
|
|
60
|
+
)}>) {
|
|
61
|
+
return <tr>
|
|
62
|
+
{displayFields.map(({ field, format }) => {
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
|
|
64
|
+
const value = item.get(field as any);
|
|
65
|
+
return <td>{format ? format(value, item) : value}</td>;
|
|
66
|
+
})}
|
|
67
|
+
<td><div class="sealious-list__actions">
|
|
68
|
+
<a href={${edit_action_name}URL(item.id)}>Edit</a>
|
|
69
|
+
<a href={${delete_ask_action_name}URL(item.id)}>Delete</a>
|
|
70
|
+
</div>
|
|
71
|
+
</td>
|
|
72
|
+
</tr>;
|
|
73
|
+
}`
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
await writeFile(list_path, list_content);
|
|
77
|
+
const fields_path = target_locreq.resolve(
|
|
78
|
+
`src/back/routes/${escape_url_params(url)}/shared.ts`
|
|
79
|
+
);
|
|
80
|
+
const fields_content = await sharedCrudFormFields(
|
|
81
|
+
collection_name,
|
|
82
|
+
fields_path
|
|
83
|
+
);
|
|
84
|
+
await writeFile(fields_path, fields_content);
|
|
85
|
+
const create_path = target_locreq.resolve(
|
|
86
|
+
`src/back/routes/${escape_url_params(url)}/create.form.ts`
|
|
87
|
+
);
|
|
88
|
+
const create_content = await createItemFormTemplate(
|
|
89
|
+
create_action_name,
|
|
90
|
+
create_path,
|
|
91
|
+
collection_name,
|
|
92
|
+
list_action_name
|
|
93
|
+
);
|
|
94
|
+
await writeFile(create_path, create_content);
|
|
95
|
+
const edit_path = target_locreq.resolve(
|
|
96
|
+
`src/back/routes/${escape_url_params(url)}/[id]/edit.form.ts`
|
|
97
|
+
);
|
|
98
|
+
const edit_content = await editItemFormTemplate(
|
|
99
|
+
edit_action_name,
|
|
100
|
+
edit_path,
|
|
101
|
+
collection_name,
|
|
102
|
+
list_action_name
|
|
103
|
+
);
|
|
104
|
+
await writeFile(edit_path, edit_content);
|
|
105
|
+
const delete_ask_path = target_locreq.resolve(
|
|
106
|
+
`src/back/routes/${escape_url_params(url)}/[id]/delete-ask.page.tsx`
|
|
107
|
+
);
|
|
108
|
+
const delete_ask_content = await askItemDeleteTemplate(
|
|
109
|
+
delete_ask_action_name,
|
|
110
|
+
collection_name,
|
|
111
|
+
delete_ask_path,
|
|
112
|
+
list_action_name,
|
|
113
|
+
delete_action_name
|
|
114
|
+
);
|
|
115
|
+
await writeFile(delete_ask_path, delete_ask_content);
|
|
116
|
+
const delete_path = target_locreq.resolve(
|
|
117
|
+
`src/back/routes/${escape_url_params(url)}/[id]/delete.page.tsx`
|
|
118
|
+
);
|
|
119
|
+
const delete_content = await itemDeleteTemplate(
|
|
120
|
+
delete_action_name,
|
|
121
|
+
collection_name,
|
|
122
|
+
delete_ask_path,
|
|
123
|
+
list_action_name
|
|
124
|
+
);
|
|
125
|
+
await writeFile(delete_path, delete_content);
|
|
126
|
+
await generateRoutes();
|
|
127
|
+
}
|
|
128
|
+
export {
|
|
129
|
+
addCRUD
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=add-crud.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { FormControl } from "./form-control.js";
|
|
2
|
+
class Table extends FormControl {
|
|
3
|
+
constructor(table_field, render_fields) {
|
|
4
|
+
super();
|
|
5
|
+
this.table_field = table_field;
|
|
6
|
+
this.render_fields = render_fields;
|
|
7
|
+
this.role = "input";
|
|
8
|
+
}
|
|
9
|
+
async render(fctx) {
|
|
10
|
+
const { parsed: rows } = await this.table_field.getValue(
|
|
11
|
+
fctx.ctx,
|
|
12
|
+
fctx.data
|
|
13
|
+
);
|
|
14
|
+
if (!rows) {
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
return (
|
|
18
|
+
/* HTML */
|
|
19
|
+
`<div
|
|
20
|
+
class="${[
|
|
21
|
+
"form-input__wrapper",
|
|
22
|
+
"form-input__wrapper--type--table",
|
|
23
|
+
"form-input__wrapper--options-count--" + rows.length.toString(),
|
|
24
|
+
...rows.length >= 5 ? ["form-input__wrapper--options-count--5-or-more"] : [],
|
|
25
|
+
...rows.length >= 10 ? ["form-input__wrapper--options-count--10-or-more"] : [],
|
|
26
|
+
...rows.length >= 15 ? ["form-input__wrapper--options-count--15-or-more"] : [],
|
|
27
|
+
...rows.length >= 20 ? ["form-input__wrapper--options-count--20-or-more"] : []
|
|
28
|
+
].join(" ")}"
|
|
29
|
+
>
|
|
30
|
+
<div class="table__wrapper">
|
|
31
|
+
<table>
|
|
32
|
+
<tbody>
|
|
33
|
+
<tr>
|
|
34
|
+
${rows?.map((row, row_index) => {
|
|
35
|
+
return (
|
|
36
|
+
/* HTML */
|
|
37
|
+
`<tr>
|
|
38
|
+
${Object.entries(
|
|
39
|
+
this.table_field.columns
|
|
40
|
+
).map(([key]) => {
|
|
41
|
+
return `<td>${this.render_fields[key](
|
|
42
|
+
fctx,
|
|
43
|
+
`${this.table_field.name}[${row_index}][${key}]`,
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
45
|
+
row[key]
|
|
46
|
+
)}</td>`;
|
|
47
|
+
}).join("")}
|
|
48
|
+
</tr>`
|
|
49
|
+
);
|
|
50
|
+
}).join("")}
|
|
51
|
+
</tr>
|
|
52
|
+
</tbody>
|
|
53
|
+
</table>
|
|
54
|
+
</div>
|
|
55
|
+
</div>`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
Table
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=table.js.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { is, predicates } from "@sealcode/ts-predicates";
|
|
2
|
+
import { FormField } from "./field.js";
|
|
3
|
+
class Table extends FormField {
|
|
4
|
+
constructor(columns) {
|
|
5
|
+
super(true);
|
|
6
|
+
this.columns = columns;
|
|
7
|
+
}
|
|
8
|
+
getEmptyValue() {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
async parse(ctx, raw_value) {
|
|
12
|
+
if (!is(raw_value, predicates.object)) {
|
|
13
|
+
return {
|
|
14
|
+
parsable: false,
|
|
15
|
+
error: "Expected an object",
|
|
16
|
+
parsed_value: null
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const result = [];
|
|
20
|
+
for (const row_number in raw_value) {
|
|
21
|
+
const row_data = raw_value[row_number];
|
|
22
|
+
const parsed_row = {};
|
|
23
|
+
if (!is(row_data, predicates.object)) {
|
|
24
|
+
throw new Error(`Expected object, got ${String(row_data)}`);
|
|
25
|
+
}
|
|
26
|
+
for (const key in row_data) {
|
|
27
|
+
const field = this.columns[key];
|
|
28
|
+
if (field == void 0) {
|
|
29
|
+
return {
|
|
30
|
+
parsable: false,
|
|
31
|
+
error: `Unknown column: ${key}`,
|
|
32
|
+
parsed_value: null
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const parse_result = await field.parse(
|
|
36
|
+
ctx,
|
|
37
|
+
row_data[key]
|
|
38
|
+
);
|
|
39
|
+
if (!parse_result.parsable) {
|
|
40
|
+
console.debug("table.ts:51");
|
|
41
|
+
return {
|
|
42
|
+
parsable: false,
|
|
43
|
+
error: `Invalid value for row ${row_number}.${key}: ${parse_result.error}`,
|
|
44
|
+
parsed_value: null
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
parsed_row[key] = parse_result.parsed_value;
|
|
48
|
+
}
|
|
49
|
+
result.push(parsed_row);
|
|
50
|
+
}
|
|
51
|
+
const ret = { parsed_value: result, parsable: true, error: null };
|
|
52
|
+
return ret;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
Table
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=table.js.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { toCamelCase, toKebabCase, toPascalCase } from "js-convert-case";
|
|
2
|
+
import { formTemplate } from "../form.js";
|
|
3
|
+
import { curryImportPath } from "../../utils/import-path.js";
|
|
4
|
+
import extract_fields_from_collection from "../../utils/extract-fields-from-collection.js";
|
|
5
|
+
function renderFieldForSealious({
|
|
6
|
+
name,
|
|
7
|
+
type,
|
|
8
|
+
is_required,
|
|
9
|
+
is_readonly
|
|
10
|
+
}) {
|
|
11
|
+
if (type == "deep-reverse-single-reference" || type == "jdd" || is_readonly) {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
14
|
+
let fallback_value = `""`;
|
|
15
|
+
let main_value = `data.${name}`;
|
|
16
|
+
if (type == "image" || type == "file") {
|
|
17
|
+
fallback_value = `null`;
|
|
18
|
+
if (is_required) {
|
|
19
|
+
main_value = toCamelCase("prepared-" + name);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (type == "boolean") {
|
|
23
|
+
main_value = `!!data.${name}`;
|
|
24
|
+
fallback_value = "false";
|
|
25
|
+
}
|
|
26
|
+
if (type == "date") {
|
|
27
|
+
fallback_value == `undefined`;
|
|
28
|
+
}
|
|
29
|
+
if (is_required) {
|
|
30
|
+
return `${name}: ${main_value}`;
|
|
31
|
+
} else {
|
|
32
|
+
return `${name}: ${main_value} || ${fallback_value}`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function renderFieldPreCreateAction({ name, type }) {
|
|
36
|
+
if (type == "image" || type == "file") {
|
|
37
|
+
const tempname = toCamelCase("prepared-" + name);
|
|
38
|
+
return `const ${tempname} = data.${name}.new || data.${name}.old;
|
|
39
|
+
if(!${tempname}){
|
|
40
|
+
throw new Error("Missing field: ${name}")
|
|
41
|
+
}`;
|
|
42
|
+
}
|
|
43
|
+
return "";
|
|
44
|
+
}
|
|
45
|
+
function renderFieldPostCreateAction({
|
|
46
|
+
name,
|
|
47
|
+
type,
|
|
48
|
+
referencing_collection,
|
|
49
|
+
referencing_field,
|
|
50
|
+
intermediary_field_that_points_there
|
|
51
|
+
}) {
|
|
52
|
+
if (type == "deep-reverse-single-reference" && referencing_collection && referencing_field && intermediary_field_that_points_there) {
|
|
53
|
+
return ` await (async function(){
|
|
54
|
+
// We iterate over all selected values and insert appropriate entries for the ${name} relation
|
|
55
|
+
const ids = Object.entries(
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
57
|
+
data.${name} as unknown as Record<string, string>
|
|
58
|
+
)
|
|
59
|
+
.filter(([, value]) => value === "on")
|
|
60
|
+
.map(([key]) => key);
|
|
61
|
+
|
|
62
|
+
const promises = ids.map(async (id) => {
|
|
63
|
+
await ctx.$app.collections["${referencing_collection}"].create(
|
|
64
|
+
new ctx.$app.SuperContext(),
|
|
65
|
+
{
|
|
66
|
+
"${referencing_field}": created.id,
|
|
67
|
+
"${intermediary_field_that_points_there}": id,
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await Promise.all(promises);
|
|
73
|
+
})()`;
|
|
74
|
+
}
|
|
75
|
+
return "";
|
|
76
|
+
}
|
|
77
|
+
async function createItemFormTemplate(create_action_name, newfilefullpath, collection_name, list_action) {
|
|
78
|
+
const collection_fields = await extract_fields_from_collection(
|
|
79
|
+
collection_name
|
|
80
|
+
);
|
|
81
|
+
const importPath = curryImportPath(newfilefullpath);
|
|
82
|
+
return formTemplate(create_action_name, newfilefullpath, {
|
|
83
|
+
postimport: `import {${toPascalCase(
|
|
84
|
+
collection_name
|
|
85
|
+
)}FormFields, ${toPascalCase(
|
|
86
|
+
collection_name
|
|
87
|
+
)}FormControls }from "./shared.js";
|
|
88
|
+
|
|
89
|
+
import { ${toPascalCase(collection_name)} } from "${importPath(
|
|
90
|
+
"src/back/collections/collections.js"
|
|
91
|
+
)}";
|
|
92
|
+
|
|
93
|
+
import { ${list_action}URL } from "${importPath("src/back/routes/urls.js")}";
|
|
94
|
+
|
|
95
|
+
import {tempstream} from "tempstream";
|
|
96
|
+
`,
|
|
97
|
+
fields: `...${toPascalCase(collection_name)}FormFields`,
|
|
98
|
+
controls: `
|
|
99
|
+
new Controls.FormHeader("Create ${toPascalCase(
|
|
100
|
+
collection_name
|
|
101
|
+
)}"),
|
|
102
|
+
...${toPascalCase(collection_name)}FormControls`,
|
|
103
|
+
can_access: `canAccess = async (ctx: Context) => {
|
|
104
|
+
const policy = ${toPascalCase(collection_name)}.getPolicy("create");
|
|
105
|
+
const response = await policy.check(ctx.$context);
|
|
106
|
+
return { canAccess: response?.allowed || false, message: response?.reason || "" };
|
|
107
|
+
};`,
|
|
108
|
+
onsubmit: `
|
|
109
|
+
async onSubmit(ctx: Context) {
|
|
110
|
+
const data = await this.getParsedValues(ctx);
|
|
111
|
+
if (!data) {
|
|
112
|
+
throw new Error("Error when parsing the form values");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
${collection_fields.map((field) => renderFieldPreCreateAction(field)).filter((e) => e !== "").join("\n")}
|
|
116
|
+
|
|
117
|
+
const created = await ctx.$app.collections["${toKebabCase(
|
|
118
|
+
collection_name
|
|
119
|
+
)}"].create(
|
|
120
|
+
ctx.$context,
|
|
121
|
+
{
|
|
122
|
+
${collection_fields.map((field) => renderFieldForSealious(field)).filter((e) => e != "").join(",\n")}
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
${collection_fields.map((field) => renderFieldPostCreateAction(field)).filter((e) => e != "").join("\n")}
|
|
126
|
+
}
|
|
127
|
+
`,
|
|
128
|
+
render: ` async render(ctx: Context, data: FormData, show_field_errors: boolean) {
|
|
129
|
+
return html(
|
|
130
|
+
ctx,
|
|
131
|
+
"AddBlogArticle",
|
|
132
|
+
tempstream/* HTML */ \` <div class="add-opinion-form">
|
|
133
|
+
<a class="" href="\${${list_action}URL}"
|
|
134
|
+
>\u2190 Back to ${collection_name} list</a
|
|
135
|
+
>
|
|
136
|
+
\${await super.render(ctx, data, show_field_errors)}
|
|
137
|
+
</div>\`
|
|
138
|
+
);
|
|
139
|
+
}`
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
export {
|
|
143
|
+
createItemFormTemplate,
|
|
144
|
+
renderFieldForSealious
|
|
145
|
+
};
|
|
146
|
+
//# sourceMappingURL=collection-create-form.js.map
|