@sealcode/sealgen 0.19.5 → 0.19.7

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.
Files changed (66) hide show
  1. package/@types/forms/fields/field.d.ts +1 -0
  2. package/@types/forms/fields/fields.d.ts +2 -1
  3. package/@types/forms/fields/get-field-for-sealious.d.ts +2 -1
  4. package/@types/forms/fields/hybrid.d.ts +11 -0
  5. package/@types/forms/fields/item-draft.d.ts +20 -0
  6. package/@types/forms/form.d.ts +1 -0
  7. package/@types/forms/multiform.d.ts +2 -2
  8. package/@types/page/list.d.ts +5 -4
  9. package/@types/page/mountable-with-fields.d.ts +9 -2
  10. package/@types/page/mountable.d.ts +1 -1
  11. package/@types/page/page.d.ts +1 -1
  12. package/@types/templates/form.d.ts +2 -2
  13. package/lib/forms/controls/checkboxed-list-input.test.js +16 -12
  14. package/lib/forms/controls/file.test.js +2 -2
  15. package/lib/forms/controls/image.test.js +4 -4
  16. package/lib/forms/controls/single-reference.test.js +2 -2
  17. package/lib/forms/fields/field.test.js +9 -6
  18. package/lib/forms/fields/fields.js +2 -1
  19. package/lib/forms/fields/file.test.js +2 -2
  20. package/lib/forms/fields/get-field-for-sealious.js +6 -0
  21. package/lib/forms/fields/hybrid.js +37 -0
  22. package/lib/forms/fields/item-draft.js +34 -0
  23. package/lib/forms/form.js +11 -5
  24. package/lib/forms/form.test.js +9 -9
  25. package/lib/forms/multiform.js +7 -4
  26. package/lib/forms/multiform.test.js +7 -7
  27. package/lib/mount.js +4 -1
  28. package/lib/page/list.js +9 -6
  29. package/lib/page/mountable-with-fields.js +16 -1
  30. package/lib/page/mountable-with-fields.test.js +2 -2
  31. package/lib/page/mountable.js +1 -1
  32. package/lib/page/page.js +1 -1
  33. package/lib/templates/form.js +9 -18
  34. package/lib/templates/shared/collection-create-form.js +8 -8
  35. package/lib/templates/shared/collection-edit-form.js +9 -9
  36. package/lib/templates/shared/collection-list.js +2 -1
  37. package/lib/templates/shared/shared-crud-form-fields.js +4 -4
  38. package/lib/utils/extract-fields-from-collection.js +3 -0
  39. package/package.json +1 -1
  40. package/src/forms/controls/checkboxed-list-input.test.ts +16 -12
  41. package/src/forms/controls/file.test.ts +2 -2
  42. package/src/forms/controls/image.test.ts +4 -4
  43. package/src/forms/controls/single-reference.test.ts +2 -2
  44. package/src/forms/fields/field.test.ts +9 -6
  45. package/src/forms/fields/field.ts +5 -6
  46. package/src/forms/fields/fields.ts +2 -1
  47. package/src/forms/fields/file.test.ts +2 -2
  48. package/src/forms/fields/get-field-for-sealious.ts +8 -0
  49. package/src/forms/fields/hybrid.ts +47 -0
  50. package/src/forms/fields/item-draft.ts +44 -0
  51. package/src/forms/form.test.ts +15 -15
  52. package/src/forms/form.ts +34 -26
  53. package/src/forms/multiform.test.ts +7 -7
  54. package/src/forms/multiform.ts +10 -7
  55. package/src/mount.ts +11 -7
  56. package/src/page/list.ts +33 -28
  57. package/src/page/mountable-with-fields.test.ts +2 -2
  58. package/src/page/mountable-with-fields.ts +26 -5
  59. package/src/page/mountable.ts +1 -1
  60. package/src/page/page.ts +1 -1
  61. package/src/templates/form.ts +9 -18
  62. package/src/templates/shared/collection-create-form.ts +8 -8
  63. package/src/templates/shared/collection-edit-form.ts +9 -9
  64. package/src/templates/shared/collection-list.ts +5 -4
  65. package/src/templates/shared/shared-crud-form-fields.ts +5 -5
  66. package/src/utils/extract-fields-from-collection.ts +3 -0
@@ -18,9 +18,9 @@ const fields = {
18
18
 
19
19
  export function form_factory(canAccessFun?: Mountable["canAccess"]): Form<typeof fields, void> {
20
20
  const result = new (class extends Form<typeof fields, void> {
21
- fields = fields;
21
+ getFields = () => fields;
22
22
  submitButtonText = "Submit";
23
- controls = [
23
+ getControls = () => [
24
24
  new Controls.SimpleInput(fields.text, {
25
25
  label: "This is a test:",
26
26
  type: "password",
@@ -112,7 +112,7 @@ describe("form test", () => {
112
112
  router,
113
113
  "/",
114
114
  form_factory(
115
- async (ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
115
+ async (_ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
116
116
  return { canAccess: true, message: "" };
117
117
  }
118
118
  ),
@@ -184,9 +184,9 @@ describe("form test", () => {
184
184
  "/",
185
185
  form_factory(
186
186
  async (ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
187
- return ctx.$context && ctx.$context.user_id
188
- ? { canAccess: true, message: "" }
189
- : { canAccess: false, message: "" };
187
+ return ctx.$context && ctx.$context.user_id ?
188
+ { canAccess: true, message: "" }
189
+ : { canAccess: false, message: "" };
190
190
  }
191
191
  ),
192
192
  true
@@ -214,9 +214,9 @@ describe("form test", () => {
214
214
  "/",
215
215
  form_factory(
216
216
  async (ctx: Koa.Context): Promise<{ canAccess: boolean; message: string }> => {
217
- return ctx.$context && ctx.$context.user_id
218
- ? { canAccess: true, message: "" }
219
- : { canAccess: false, message: "" };
217
+ return ctx.$context && ctx.$context.user_id ?
218
+ { canAccess: true, message: "" }
219
+ : { canAccess: false, message: "" };
220
220
  }
221
221
  ),
222
222
  true
@@ -242,9 +242,9 @@ describe("form test", () => {
242
242
  router,
243
243
  "/",
244
244
  new (class extends Form<typeof fields, void> {
245
- fields = fields;
245
+ getFields = () => fields;
246
246
  submitButtonText = "Submit";
247
- controls = [
247
+ getControls = () => [
248
248
  new Controls.SimpleInput(fields.text, {
249
249
  label: "This is a test:",
250
250
  type: "password",
@@ -311,9 +311,9 @@ describe("form test", () => {
311
311
  router,
312
312
  "/",
313
313
  new (class extends Form<typeof fields, void> {
314
- fields = fields;
314
+ getFields = () => fields;
315
315
  submitButtonText = "Submit";
316
- controls = [
316
+ getControls = () => [
317
317
  new Controls.SimpleInput(fields.text, {
318
318
  label: "This is a test:",
319
319
  type: "text",
@@ -375,8 +375,8 @@ describe("form test", () => {
375
375
  router,
376
376
  "/",
377
377
  new (class extends Form<typeof fields, null> {
378
- fields = fields;
379
- controls = [new Controls.SimpleInput(fields.title)];
378
+ getFields = () => fields;
379
+ getControls = () => [new Controls.SimpleInput(fields.title)];
380
380
 
381
381
  async getInitialValues() {
382
382
  return { title: "Hello" };
package/src/forms/form.ts CHANGED
@@ -66,15 +66,15 @@ export abstract class Form<
66
66
  ): Promise<JSX.Element | Readable> {
67
67
  return tempstream /* HTML */ `<div class="form-container">
68
68
  ${this.makeOpenFormTag(ctx)}
69
- ${!this.controls.some((control) => control.role == "messages")
70
- ? this.renderMessages(ctx, data)
71
- : ""}
69
+ ${!this.controls.some((control) => control.role == "messages") ?
70
+ this.renderMessages(ctx, data)
71
+ : ""}
72
72
  ${this.renderControls(
73
73
  this.makeFormControlContext(ctx, data, show_field_errors)
74
74
  )}
75
- ${this.controls.some((control) => control.role == "submit")
76
- ? ""
77
- : this.makeSubmitButton()}
75
+ ${this.controls.some((control) => control.role == "submit") ?
76
+ ""
77
+ : this.makeSubmitButton()}
78
78
  ${this.makeCloseFormTag()}
79
79
  </div>`;
80
80
  }
@@ -102,9 +102,10 @@ export abstract class Form<
102
102
  form_messages: FormMessage[],
103
103
  field_errors: FieldMessages<keyof Fields>
104
104
  ): Promise<FormReaction> {
105
- const messages = form_messages.length
106
- ? form_messages
107
- : [<const>{ type: "error", text: "Some fields are invalid" }];
105
+ const messages =
106
+ form_messages.length ? form_messages : (
107
+ [<const>{ type: "error", text: "Some fields are invalid" }]
108
+ );
108
109
  return {
109
110
  action: "stay",
110
111
  content: await this.render(
@@ -217,12 +218,13 @@ export abstract class Form<
217
218
  // eslint-disable-next-line no-console
218
219
  console.dir(e, { depth: 5 });
219
220
  const message =
220
- is(e, predicates.object) &&
221
- hasFieldOfType(e, "message", predicates.string)
222
- ? e?.message
223
- : is(e, predicates.string)
224
- ? e
225
- : "Wystąpił błąd";
221
+ (
222
+ is(e, predicates.object) &&
223
+ hasFieldOfType(e, "message", predicates.string)
224
+ ) ?
225
+ e?.message
226
+ : is(e, predicates.string) ? e
227
+ : "Wystąpił błąd";
226
228
 
227
229
  return this.onError(
228
230
  ctx,
@@ -241,6 +243,20 @@ export abstract class Form<
241
243
  }
242
244
  }
243
245
 
246
+ init(path: string, router: Router) {
247
+ super.init(path, router);
248
+ if (this.initialized) {
249
+ return;
250
+ }
251
+ // for use with other subroutes or middlewares that individual controls
252
+ // might register
253
+ const subrouter = new Router();
254
+ for (const control of this.controls) {
255
+ control.mount(subrouter, this);
256
+ }
257
+ router.use(path, subrouter.routes(), subrouter.allowedMethods());
258
+ }
259
+
244
260
  public mount(router: Router, path: string): void {
245
261
  router.use(path, async (ctx, next) => {
246
262
  const result = await this.canAccess(ctx);
@@ -255,14 +271,6 @@ export abstract class Form<
255
271
  await next();
256
272
  });
257
273
 
258
- // for use with other subroutes or middlewares that individual controls
259
- // might register
260
- const subrouter = new Router();
261
- for (const control of this.controls) {
262
- control.mount(subrouter, this);
263
- }
264
- router.use(path, subrouter.routes(), subrouter.allowedMethods());
265
-
266
274
  router.get(path, async (ctx) => {
267
275
  ctx.type = "html";
268
276
  ctx.body = await this.render(
@@ -292,9 +300,9 @@ export abstract class Form<
292
300
  async extractRawValues(
293
301
  ctx: Context
294
302
  ): Promise<Record<string, FormDataValue>> {
295
- return Object.keys(ctx.$body).length
296
- ? ctx.$body
297
- : this.getInitialValues(ctx);
303
+ return Object.keys(ctx.$body).length ?
304
+ ctx.$body
305
+ : this.getInitialValues(ctx);
298
306
  }
299
307
 
300
308
  static initFieldNames(fields: Record<string, FormField>): void {
@@ -27,8 +27,8 @@ const fields1 = {
27
27
 
28
28
  const form1 = new (class extends Form<typeof fields1, void> {
29
29
  defaultSuccessMessage = "Form1 done!";
30
- controls = [new FormHeader("form1"), new SimpleInput(fields1.email)];
31
- fields = fields1;
30
+ getControls = () => [new FormHeader("form1"), new SimpleInput(fields1.email)];
31
+ getFields = () => fields1;
32
32
  onSubmit() {
33
33
  return;
34
34
  }
@@ -40,8 +40,8 @@ const fields2 = {
40
40
 
41
41
  const form2 = new (class extends Form<Record<never, unknown>, void> {
42
42
  defaultSuccessMessage = "Form2 done!";
43
- controls = [new FormHeader("form2"), new SimpleInput(fields2.name)];
44
- fields = fields2;
43
+ getControls = () => [new FormHeader("form2"), new SimpleInput(fields2.name)];
44
+ getFields = () => fields2;
45
45
  onSubmit() {
46
46
  return;
47
47
  }
@@ -427,7 +427,7 @@ describe("multiform test", () => {
427
427
  form1: new (class extends Form<typeof fields1, void> {
428
428
  fields = fields1;
429
429
  submitButtonText = "Submit";
430
- controls = [
430
+ getControls = () => [
431
431
  new SimpleInput(fields1.email, {
432
432
  label: "This is a test:",
433
433
  type: "text",
@@ -500,9 +500,9 @@ describe("multiform test", () => {
500
500
  name = "multiform_test";
501
501
  forms = {
502
502
  form1: new (class extends Form<typeof fields, void> {
503
- fields = fields;
503
+ getFields = () => fields;
504
504
  submitButtonText = "Submit";
505
- controls = [
505
+ getControls = () => [
506
506
  new SimpleInput(fields.text, {
507
507
  label: "This is a test:",
508
508
  type: "text",
@@ -11,12 +11,15 @@ import { Form } from "./form.js";
11
11
  const FIELD_PREFIX_SEPARATOR = "___";
12
12
 
13
13
  export class Multiform extends MountableWithFields {
14
- controls = [];
14
+ getControls = () => [];
15
15
  public name: string;
16
16
  public forms: Record<string, Form<Fields, unknown>>;
17
17
 
18
- init(): void {
19
- super.init();
18
+ init(path: string, router: Router): void {
19
+ if (this.initialized) {
20
+ return;
21
+ }
22
+ super.init(path, router);
20
23
  for (const [key, form] of Object.entries(this.forms)) {
21
24
  if (key !== attribute(key)) {
22
25
  throw new Error(
@@ -30,7 +33,7 @@ export class Multiform extends MountableWithFields {
30
33
  form.field_names_prefix = key + FIELD_PREFIX_SEPARATOR;
31
34
  form.form_id = this.name;
32
35
  form.action = "./" + key;
33
- form.init();
36
+ form.init(path, router);
34
37
  form.extractRawValues = async (context) =>
35
38
  this.getSubformRawValues(context, key);
36
39
  const submit_button_id = this.name + "_" + key + "_submit";
@@ -82,9 +85,9 @@ export class Multiform extends MountableWithFields {
82
85
  throw new Error("Wrong turbo-frame header value type");
83
86
  }
84
87
  const forms_to_render =
85
- requested_frame && this.forms[requested_frame]
86
- ? [<const>[requested_frame, this.forms[requested_frame]]]
87
- : Object.entries(this.forms);
88
+ requested_frame && this.forms[requested_frame] ?
89
+ [<const>[requested_frame, this.forms[requested_frame]]]
90
+ : Object.entries(this.forms);
88
91
  return forms_to_render;
89
92
  }
90
93
 
package/src/mount.ts CHANGED
@@ -19,9 +19,9 @@ export function mount(
19
19
  url: string | { rawURL: string },
20
20
  mountable: Mountable,
21
21
  use_dummy_app = false,
22
- file_manager: FileManager | undefined = use_dummy_app
23
- ? new FileManager("/tmp", "/uploaded_files")
24
- : undefined
22
+ file_manager: FileManager | undefined = use_dummy_app ?
23
+ new FileManager("/tmp", "/uploaded_files")
24
+ : undefined
25
25
  ): void {
26
26
  const raw_url = typeof url === "string" ? url : url.rawURL;
27
27
 
@@ -35,8 +35,9 @@ export function mount(
35
35
 
36
36
  const fileManager = new FileManager("/tmp", "/uploaded_files");
37
37
 
38
- const args = use_dummy_app
39
- ? [
38
+ const args =
39
+ use_dummy_app ?
40
+ [
40
41
  async (ctx: Context, next: any) => {
41
42
  // this dummy is a temporary solution it's ilustrating the ways that
42
43
  // sealgen is coupled with sealious. Definitely room for improvement in this
@@ -66,14 +67,17 @@ export function mount(
66
67
  SealiousMiddlewares.parseBody(file_manager),
67
68
  handleHtmlPromise,
68
69
  ]
69
- : [
70
+ : [
70
71
  SealiousMiddlewares.extractContext(),
71
72
  SealiousMiddlewares.parseBody(file_manager),
72
73
  handleHtmlPromise,
73
74
  ];
74
75
 
75
76
  router.use(raw_url, ...args);
76
- mountable.init();
77
+ router.use(raw_url, async (_ctx, next) => {
78
+ mountable.init(raw_url, router);
79
+ await next();
80
+ });
77
81
 
78
82
  // to automatically add trailing slashes:
79
83
  router.get(raw_url.slice(0, -1), async (ctx, next) => {
package/src/page/list.ts CHANGED
@@ -1,15 +1,16 @@
1
- import { Context } from "koa";
2
- import { Templatable, tempstream, FlatTemplatable } from "tempstream";
3
- import { Page } from "./page.js";
4
1
  import { ShapeToType } from "@sealcode/ts-predicates";
2
+ import { Context } from "koa";
3
+ import qs from "qs";
4
+ import { FlatTemplatable, Templatable, tempstream } from "tempstream";
5
5
  import { FormControl } from "../forms/controls/controls.js";
6
6
  import { FormField } from "../forms/fields/field.js";
7
- import { naturalNumbers, UrlWithNewParams } from "../utils/utils.js";
8
- import { makeHiddenInputs } from "../make-hidden-inputs.js";
9
- import qs from "qs";
10
7
  import { NumberField } from "../forms/fields/number.js";
11
8
  import { TextBasedSimpleField } from "../forms/fields/simple-form-field.js";
12
9
  import { FormDataValue } from "../forms/form-types.js";
10
+ import { makeHiddenInputs } from "../make-hidden-inputs.js";
11
+ import { naturalNumbers, UrlWithNewParams } from "../utils/utils.js";
12
+ import { Page } from "./page.js";
13
+ import Router from "@koa/router";
13
14
 
14
15
  export const BasePagePropsShape = <const>{};
15
16
  export type BasePageProps = ShapeToType<typeof BasePagePropsShape>;
@@ -72,8 +73,11 @@ export abstract class ListPage<
72
73
  filterFields: Record<string, FormField> = {};
73
74
  filterControls: FormControl[] = [];
74
75
 
75
- init(): void {
76
- super.init();
76
+ init(path: string, router: Router): void {
77
+ if (this.initialized) {
78
+ return;
79
+ }
80
+ super.init(path, router);
77
81
  for (const [, field] of Object.entries(this.filterFields)) {
78
82
  void field.init();
79
83
  }
@@ -107,9 +111,9 @@ export abstract class ListPage<
107
111
  }
108
112
  const { itemsPerPage, page } = await this.getPaginationConfig(ctx);
109
113
  const items_promise = this.getItems(ctx, page, itemsPerPage, values);
110
- return tempstream`${(items
111
- ? Promise.resolve(items)
112
- : items_promise
114
+ return tempstream`${(items ?
115
+ Promise.resolve(items)
116
+ : items_promise
113
117
  ).then((items) =>
114
118
  items.map((item, index) => this.renderItem(ctx, item, index))
115
119
  )}`;
@@ -128,12 +132,12 @@ export abstract class ListPage<
128
132
 
129
133
  return tempstream /* HTML */ `<div class="list-pagination">
130
134
  <div class="list-pagination__left">
131
- ${page > 1
132
- ? this.renderPageButton(ctx, 1, "Pierwsza strona")
133
- : ""}
134
- ${page > 1
135
- ? this.renderPageButton(ctx, page - 1, "Poprzednia strona")
136
- : ""}
135
+ ${page > 1 ?
136
+ this.renderPageButton(ctx, 1, "Pierwsza strona")
137
+ : ""}
138
+ ${page > 1 ?
139
+ this.renderPageButton(ctx, page - 1, "Poprzednia strona")
140
+ : ""}
137
141
  </div>
138
142
  <div class="list-pagination__center">
139
143
  <select
@@ -157,12 +161,12 @@ export abstract class ListPage<
157
161
  </select>
158
162
  </div>
159
163
  <div class="list-pagination__right">
160
- ${page < totalIems
161
- ? this.renderPageButton(ctx, page + 1, "Następna strona")
162
- : ""}
163
- ${page < totalIems
164
- ? this.renderPageButton(ctx, totalIems, "Ostatnia strona")
165
- : ""}
164
+ ${page < totalIems ?
165
+ this.renderPageButton(ctx, page + 1, "Następna strona")
166
+ : ""}
167
+ ${page < totalIems ?
168
+ this.renderPageButton(ctx, totalIems, "Ostatnia strona")
169
+ : ""}
166
170
  </div>
167
171
  </div>`;
168
172
  }
@@ -248,11 +252,12 @@ export abstract class ListPage<
248
252
  const current_order =
249
253
  current_sort?.field == field ? current_sort.order : null;
250
254
  const order =
251
- current_order === "asc" // cycles the sort order: null → "asc" → "desc" → null → ...
252
- ? "desc"
253
- : current_order === null
254
- ? "asc"
255
- : null;
255
+ (
256
+ current_order === "asc" // cycles the sort order: null → "asc" → "desc" → null → ...
257
+ ) ?
258
+ "desc"
259
+ : current_order === null ? "asc"
260
+ : null;
256
261
  return /* HTML */ `<th data-field="${field}">
257
262
  <a href="${this.makeSortLink(ctx, field, order)}"
258
263
  >${label}
@@ -11,8 +11,8 @@ describe("mountable-with-fields", () => {
11
11
  required: new CollectionField(true, new FieldTypes.Text()),
12
12
  };
13
13
  new (class extends Form<typeof fields, void> {
14
- fields = fields;
15
- controls = [];
14
+ getFields = () => fields;
15
+ getControls = () => [];
16
16
  async onSubmit(ctx: Context, form_values: FormData) {
17
17
  const data = await this.getParsedValues(ctx);
18
18
  // this should not throw a Typescript error
@@ -13,6 +13,7 @@ import type {
13
13
  FormData,
14
14
  } from "../forms/form-types.js";
15
15
  import { Mountable } from "./mountable.js";
16
+ import Router from "@koa/router";
16
17
 
17
18
  export type PageErrorMessage = { type: "access" | "internal"; message: string };
18
19
 
@@ -27,21 +28,41 @@ type ParsedValue<T extends FormField> = Resolved<
27
28
  export abstract class MountableWithFields<
28
29
  F extends Fields = Fields,
29
30
  > extends Mountable {
31
+ getFields: () => F;
30
32
  fields: F;
33
+ initialized = false;
31
34
  field_names_prefix = ""; // useful for multiform, where many forms are merged into one and field assignment is made using the prefix
32
35
  form_id = ""; // all fields within this mountable will be tied to form of this id
33
- abstract controls: FormControl[];
36
+ abstract getControls: (fields: F) => FormControl[];
37
+ controls: FormControl[];
34
38
 
35
39
  constructor() {
36
40
  super();
37
41
  if (!this.fields) this.fields = {} as F;
38
42
  }
39
43
 
40
- init(): void {
44
+ /** most routes should be setup using .mount(), but mount runs before
45
+ initialization so we don't yet have controls, app, etc ready for dynamic
46
+ routes **/
47
+ init(path: string, router: Router): void {
48
+ // we setup fields not on construction, but sometime after the app is
49
+ // initialized, as some field constructors require app data to fulle
50
+ // construct themselves
51
+ super.init(path, router);
52
+ if (this.initialized) {
53
+ return;
54
+ }
55
+ if (this.getFields) {
56
+ this.fields = this.getFields();
57
+ } else if (!this.fields) {
58
+ throw new Error("Fields not defined and getter not provided");
59
+ }
60
+ this.controls = this.getControls(this.fields);
41
61
  for (const [field_name, field] of Object.entries(this.fields)) {
42
62
  void field.init();
43
63
  field.setName(field_name);
44
64
  }
65
+ this.initialized = true;
45
66
  }
46
67
 
47
68
  makeFormControlContext(
@@ -145,9 +166,9 @@ export abstract class MountableWithFields<
145
166
  ): Promise<Record<string, FormDataValue>>;
146
167
 
147
168
  async getParsedValues(ctx: Context): Promise<{
148
- [field in keyof F]: F[field] extends FormField<true>
149
- ? Exclude<ParsedValue<F[field]>, null>
150
- : ParsedValue<F[field]>;
169
+ [field in keyof F]: F[field] extends FormField<true> ?
170
+ Exclude<ParsedValue<F[field]>, null>
171
+ : ParsedValue<F[field]>;
151
172
  }> {
152
173
  const raw_values = await this.extractRawValues(ctx);
153
174
  const result: Record<string, unknown> = {};
@@ -3,7 +3,7 @@ import Router from "@koa/router";
3
3
  import { Context } from "koa";
4
4
 
5
5
  export abstract class Mountable {
6
- init(): void {}
6
+ init(_path: string, _router: Router): void {}
7
7
  abstract mount(router: Router, path: string): void;
8
8
 
9
9
  abstract canAccess(
package/src/page/page.ts CHANGED
@@ -15,7 +15,7 @@ export abstract class Page<
15
15
  > extends MountableWithFields<F> {
16
16
  propsParser: PagePropsParser<Record<keyof Fields, unknown>> =
17
17
  new AllQueryParams();
18
- controls = [];
18
+ getControls = () => [];
19
19
 
20
20
  mount(router: Router, path: string): void {
21
21
  router.get(path, async (ctx) => {
@@ -4,13 +4,12 @@ const defaults = {
4
4
  postimport: `
5
5
  import { Fields } from "@sealcode/sealgen";
6
6
  import type {FormDataValue} from "@sealcode/sealgen";`,
7
- fields: `
8
- password: new Fields.Password(true),`,
9
- controls: `
10
- new Controls.SimpleInput(fields.password, {
7
+ get_fields: `()=>(<const>{ password: new Fields.Password(true) })`,
8
+ get_controls: `
9
+ ()=><const>[new Controls.SimpleInput(fields.password, {
11
10
  label: "Password:",
12
11
  type: "password",
13
- }),`,
12
+ })],`,
14
13
  validate_method: `async validateValues(
15
14
  ctx: Context,
16
15
  data: Record<string, FormDataValue>
@@ -48,28 +47,20 @@ export async function formTemplate(
48
47
  const params = { ...defaults, ..._params };
49
48
  const content = `import type { Context } from "koa";
50
49
  import type { FormData } from "@sealcode/sealgen";
51
- import { Form, Controls, fieldsToShape } from "@sealcode/sealgen";
50
+ import { Form, Controls } from "@sealcode/sealgen";
52
51
  import html from "src/back/html.js";
53
52
 
54
53
  ${params.postimport}
55
54
 
56
55
  export const actionName = "${action_name}";
57
56
 
58
- const fields = {
59
- ${params.fields}
60
- };
61
-
62
- Form.initFieldNames(fields);
63
-
64
- export const ${action_name}Shape = fieldsToShape(fields);
57
+ const getFields = ${params.get_fields};
65
58
 
66
- export default new (class ${action_name}Form extends Form<typeof fields, void> {
59
+ export default new (class ${action_name}Form extends Form<ReturnType<typeof getFields>, void> {
67
60
  defaultSuccessMessage = "Formularz wypełniony poprawnie";
68
- fields = fields;
61
+ getFields = getFields;
69
62
 
70
- controls = [
71
- ${params.controls}
72
- ];
63
+ getControls = ${params.get_controls};
73
64
 
74
65
  ${params.other_methods}
75
66
 
@@ -12,11 +12,11 @@ export async function createItemFormTemplate(
12
12
  ): Promise<string> {
13
13
  const collection_fields =
14
14
  await extract_fields_from_collection(collection_name);
15
- const formFieldsVar = `${toPascalCase(collection_name)}FormFields`;
15
+ const formFieldsGetterVar = `get${toPascalCase(collection_name)}FormFields`;
16
16
 
17
17
  return formTemplate(create_action_name, {
18
18
  success_message: "Created!",
19
- postimport: `import {${formFieldsVar}, get${toPascalCase(
19
+ postimport: `import {${formFieldsGetterVar}, get${toPascalCase(
20
20
  collection_name
21
21
  )}FormControls }from "./shared.js";
22
22
 
@@ -28,12 +28,12 @@ export async function createItemFormTemplate(
28
28
  import {tempstream} from "tempstream";
29
29
  `,
30
30
 
31
- fields: `...${toPascalCase(collection_name)}FormFields`,
32
- controls: `
31
+ get_fields: `get${toPascalCase(collection_name)}FormFields`,
32
+ get_controls: `(fields: ReturnType<typeof getFields>)=>[
33
33
  new Controls.FormHeader("Create ${toPascalCase(
34
34
  collection_name
35
35
  )}"),
36
- ...get${toPascalCase(collection_name)}FormControls()`,
36
+ ...get${toPascalCase(collection_name)}FormControls(fields)]`,
37
37
 
38
38
  can_access: `canAccess = async (ctx: Context) => {
39
39
  const policy = ${toPascalCase(collection_name)}.getPolicy("create");
@@ -55,15 +55,15 @@ export async function createItemFormTemplate(
55
55
  ${collection_fields
56
56
  .map((field_info) =>
57
57
  field_info.form_field.generateCreateValueGetter(field_info, {
58
- form_field_types: formFieldsVar,
58
+ form_field_types: "FormFieldTypes",
59
59
  sealious_field: `fields${wrapAttribute(field_info.name)}`,
60
- form_fields: "fields",
60
+ form_fields: "this.fields",
61
61
  })
62
62
  )
63
63
  .join(",\n")}
64
64
  });
65
65
 
66
- for(const field of Object.values(${formFieldsVar})){
66
+ for(const field of Object.values(this.fields)){
67
67
  // eslint-disable-next-line no-await-in-loop
68
68
  await field.postSealiousCreate(ctx, created, formData)
69
69
  }