@sealcode/sealgen 0.19.5 → 0.19.6

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 (67) 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.js +1 -1
  18. package/lib/forms/fields/field.test.js +9 -6
  19. package/lib/forms/fields/fields.js +2 -1
  20. package/lib/forms/fields/file.test.js +2 -2
  21. package/lib/forms/fields/get-field-for-sealious.js +6 -0
  22. package/lib/forms/fields/hybrid.js +37 -0
  23. package/lib/forms/fields/item-draft.js +34 -0
  24. package/lib/forms/form.js +11 -5
  25. package/lib/forms/form.test.js +9 -9
  26. package/lib/forms/multiform.js +7 -4
  27. package/lib/forms/multiform.test.js +7 -7
  28. package/lib/mount.js +4 -1
  29. package/lib/page/list.js +9 -6
  30. package/lib/page/mountable-with-fields.js +16 -1
  31. package/lib/page/mountable-with-fields.test.js +2 -2
  32. package/lib/page/mountable.js +1 -1
  33. package/lib/page/page.js +1 -1
  34. package/lib/templates/form.js +9 -18
  35. package/lib/templates/shared/collection-create-form.js +8 -8
  36. package/lib/templates/shared/collection-edit-form.js +9 -9
  37. package/lib/templates/shared/collection-list.js +2 -1
  38. package/lib/templates/shared/shared-crud-form-fields.js +4 -4
  39. package/lib/utils/extract-fields-from-collection.js +3 -0
  40. package/package.json +1 -1
  41. package/src/forms/controls/checkboxed-list-input.test.ts +16 -12
  42. package/src/forms/controls/file.test.ts +2 -2
  43. package/src/forms/controls/image.test.ts +4 -4
  44. package/src/forms/controls/single-reference.test.ts +2 -2
  45. package/src/forms/fields/field.test.ts +9 -6
  46. package/src/forms/fields/field.ts +6 -7
  47. package/src/forms/fields/fields.ts +2 -1
  48. package/src/forms/fields/file.test.ts +2 -2
  49. package/src/forms/fields/get-field-for-sealious.ts +8 -0
  50. package/src/forms/fields/hybrid.ts +47 -0
  51. package/src/forms/fields/item-draft.ts +44 -0
  52. package/src/forms/form.test.ts +15 -15
  53. package/src/forms/form.ts +34 -26
  54. package/src/forms/multiform.test.ts +7 -7
  55. package/src/forms/multiform.ts +10 -7
  56. package/src/mount.ts +11 -7
  57. package/src/page/list.ts +33 -28
  58. package/src/page/mountable-with-fields.test.ts +2 -2
  59. package/src/page/mountable-with-fields.ts +26 -5
  60. package/src/page/mountable.ts +1 -1
  61. package/src/page/page.ts +1 -1
  62. package/src/templates/form.ts +9 -18
  63. package/src/templates/shared/collection-create-form.ts +8 -8
  64. package/src/templates/shared/collection-edit-form.ts +9 -9
  65. package/src/templates/shared/collection-list.ts +5 -4
  66. package/src/templates/shared/shared-crud-form-fields.ts +5 -5
  67. package/src/utils/extract-fields-from-collection.ts +3 -0
@@ -78,5 +78,6 @@ export declare abstract class FormField<Required extends boolean = boolean, Pars
78
78
  what: string;
79
79
  from: string;
80
80
  as?: string;
81
+ type?: boolean;
81
82
  }[];
82
83
  }
@@ -15,13 +15,14 @@ export * from "./float.js";
15
15
  export * from "./html.js";
16
16
  export * from "./image.js";
17
17
  export * from "./int.js";
18
+ export * from "./item-draft.js";
18
19
  export * from "./json.js";
19
20
  export * from "./markdown.js";
20
21
  export * from "./multiple-files.js";
21
22
  export * from "./number.js";
22
23
  export * from "./password.js";
23
- export * from "./phone-number.js";
24
24
  export * from "./phone-number-with-country-code.js";
25
+ export * from "./phone-number.js";
25
26
  export * from "./pick-from-list-sealious.js";
26
27
  export * from "./pick-from-list.js";
27
28
  export * from "./regexp.js";
@@ -27,6 +27,7 @@ import { EnumMultipleSealious } from "./enum-multiple-sealious.js";
27
27
  import { URLField } from "./url.js";
28
28
  import { Image } from "./image.js";
29
29
  import { PhoneNumberWithCountryCode } from "./phone-number-with-country-code.js";
30
- export type SealiousToFormField<T> = T extends SealiousFieldTypes.Boolean ? BooleanField<false> : T extends SealiousFieldTypes.Color ? Color<false> : T extends SealiousFieldTypes.ControlAccess<infer R> ? SealiousToFormField<R> : T extends SealiousFieldTypes.Date ? DateField<false> : T extends SealiousFieldTypes.DateTime ? DateTime<false> : T extends SealiousFieldTypes.DeepReverseSingleReference ? DeepReverseSingleReferenceList | DeepReverseSingleReferenceTable : T extends SealiousFieldTypes.DisallowUpdate<any, any, any, infer R> ? SealiousToFormField<R> : T extends SealiousFieldTypes.Email ? EmailField<false> : T extends SealiousFieldTypes.Enum<any> ? PickFromListSealious<false> : T extends SealiousFieldTypes.EnumMultiple<infer R> ? R extends string[] ? EnumMultipleSealious<R> : TextBasedSimpleField<false> : T extends SealiousFieldTypes.File ? File<false> : T extends SealiousFieldTypes.Float ? Float<false> : T extends SealiousFieldTypes.HTML ? HTML<false> : T extends SealiousFieldTypes.Image ? Image<false> : T extends SealiousFieldTypes.Int ? Int<false> : T extends SealiousFieldTypes.JsonObject ? JSONField<false> : T extends SealiousFieldTypes.JDD ? TextBasedSimpleField<false, SimpleInput> : T extends SealiousFieldTypes.Password ? Password<false> : T extends SealiousFieldTypes.PhoneNumber ? PhoneNumberWithCountryCode<false> : T extends SealiousFieldTypes.ReverseSingleReference ? TextBasedSimpleField<false, SimpleInput> : T extends SealiousFieldTypes.SecretToken ? TextBasedSimpleField<false, SimpleInput> : T extends SealiousFieldTypes.SettableBy<infer R> ? SealiousToFormField<R> : T extends SealiousFieldTypes.SingleReference ? SingleReference<Collection, boolean, T> : T extends SealiousFieldTypes.Text ? Text<false> : T extends SealiousFieldTypes.Username ? CollectionField<SealiousFieldTypes.Username, false> : T extends SealiousFieldTypes.ValueExistingInCollection ? SimpleFormField<false> : T extends SealiousFieldTypes.ValueNotExistingInCollection ? SimpleFormField<false> : T extends SealiousRequiredField<any, any, any> ? SimpleFormField<false> : T extends SealiousFieldTypes.Url ? URLField<false> : T extends SealiousFieldTypes.Money ? SimpleFormField<false> : T extends SealiousFieldTypes.Markdown ? Markdown<false> : T extends SealiousFieldTypes.Coordinates ? Coordinates<false> : T extends SealiousFieldTypes.StructuredArray<infer R> ? StructuredArrayField<R> : TextBasedSimpleField<any>;
30
+ import { ItemDraft } from "./item-draft.js";
31
+ export type SealiousToFormField<T> = T extends SealiousFieldTypes.Boolean ? BooleanField<false> : T extends SealiousFieldTypes.Color ? Color<false> : T extends SealiousFieldTypes.ControlAccess<infer R> ? SealiousToFormField<R> : T extends SealiousFieldTypes.Date ? DateField<false> : T extends SealiousFieldTypes.DateTime ? DateTime<false> : T extends SealiousFieldTypes.DeepReverseSingleReference ? DeepReverseSingleReferenceList | DeepReverseSingleReferenceTable : T extends SealiousFieldTypes.DisallowUpdate<any, any, any, infer R> ? SealiousToFormField<R> : T extends SealiousFieldTypes.Email ? EmailField<false> : T extends SealiousFieldTypes.Enum<any> ? PickFromListSealious<false> : T extends SealiousFieldTypes.EnumMultiple<infer R> ? R extends string[] ? EnumMultipleSealious<R> : TextBasedSimpleField<false> : T extends SealiousFieldTypes.File ? File<false> : T extends SealiousFieldTypes.Float ? Float<false> : T extends SealiousFieldTypes.HTML ? HTML<false> : T extends SealiousFieldTypes.Image ? Image<false> : T extends SealiousFieldTypes.Int ? Int<false> : T extends SealiousFieldTypes.ItemDraft<infer C extends Collection> ? ItemDraft<C> : T extends SealiousFieldTypes.JsonObject ? JSONField<false> : T extends SealiousFieldTypes.JDD ? TextBasedSimpleField<false, SimpleInput> : T extends SealiousFieldTypes.Password ? Password<false> : T extends SealiousFieldTypes.PhoneNumber ? PhoneNumberWithCountryCode<false> : T extends SealiousFieldTypes.ReverseSingleReference ? TextBasedSimpleField<false, SimpleInput> : T extends SealiousFieldTypes.SecretToken ? TextBasedSimpleField<false, SimpleInput> : T extends SealiousFieldTypes.SettableBy<infer R> ? SealiousToFormField<R> : T extends SealiousFieldTypes.SingleReference ? SingleReference<Collection, boolean, T> : T extends SealiousFieldTypes.Text ? Text<false> : T extends SealiousFieldTypes.Username ? CollectionField<SealiousFieldTypes.Username, false> : T extends SealiousFieldTypes.ValueExistingInCollection ? SimpleFormField<false> : T extends SealiousFieldTypes.ValueNotExistingInCollection ? SimpleFormField<false> : T extends SealiousRequiredField<any, any, any> ? SimpleFormField<false> : T extends SealiousFieldTypes.Url ? URLField<false> : T extends SealiousFieldTypes.Money ? SimpleFormField<false> : T extends SealiousFieldTypes.Markdown ? Markdown<false> : T extends SealiousFieldTypes.Coordinates ? Coordinates<false> : T extends SealiousFieldTypes.StructuredArray<infer R> ? StructuredArrayField<R> : TextBasedSimpleField<any>;
31
32
  export declare function sealiousToFormField<SF extends SealiousField<any>>(sealious_field: SF): SealiousToFormField<SF>;
32
33
  export declare function sealiousFieldInfoToFormField(field_info: ExtractedFieldInfo): Promise<FormField>;
@@ -0,0 +1,11 @@
1
+ import { Context } from "koa";
2
+ import { Hybrid as HybridControl } from "../controls/hybrid.js";
3
+ import { FormDataValue } from "../form-types.js";
4
+ import { FieldParseResult, FormField } from "./field.js";
5
+ export declare class Hybrid<Fields extends Record<string, FormField>> extends FormField<true, Record<string, unknown>> {
6
+ subfields: Fields;
7
+ constructor(subfields: Fields);
8
+ getEmptyValue(): Record<string, unknown>;
9
+ parse(ctx: Context, raw_value: FormDataValue): Promise<FieldParseResult<Record<string, unknown>>>;
10
+ getControl(): HybridControl;
11
+ }
@@ -0,0 +1,20 @@
1
+ import { Collection, FieldTypes as SealiousFieldTypes } from "sealious";
2
+ import { Hybrid } from "./hybrid.js";
3
+ import { FormField } from "./field.js";
4
+ import { ExtractedFieldInfo } from "../../utils/extract-fields-from-collection.js";
5
+ export declare class ItemDraft<C extends Collection> extends Hybrid<{
6
+ [name in keyof C["fields"]]: FormField;
7
+ }> {
8
+ sealious_field: SealiousFieldTypes.ItemDraft<C>;
9
+ constructor(sealious_field: SealiousFieldTypes.ItemDraft<C>);
10
+ generateFieldDeclaration(field_info: ExtractedFieldInfo, vars: {
11
+ form_field_types: string;
12
+ sealious_field: string;
13
+ }): string;
14
+ generateImportsForFieldList(field_info: ExtractedFieldInfo): {
15
+ what: string;
16
+ from: string;
17
+ as?: string;
18
+ type?: boolean;
19
+ }[];
20
+ }
@@ -27,6 +27,7 @@ export declare abstract class Form<F extends Fields, SubmitResult> extends Mount
27
27
  onSuccess(ctx: Context, _data: FormData, _submitResult: SubmitResult): Promise<FormReaction>;
28
28
  getRawValuesOnSuccess(ctx: Context): Promise<Record<string, FormDataValue>>;
29
29
  handlePost(ctx: Context): Promise<FormReaction>;
30
+ init(path: string, router: Router): void;
30
31
  mount(router: Router, path: string): void;
31
32
  extractRawValues(ctx: Context): Promise<Record<string, FormDataValue>>;
32
33
  static initFieldNames(fields: Record<string, FormField>): void;
@@ -5,10 +5,10 @@ import { Fields, MountableWithFields } from "../page/mountable-with-fields.js";
5
5
  import type { FormDataValue, FormMessage } from "./form-types.js";
6
6
  import { Form } from "./form.js";
7
7
  export declare class Multiform extends MountableWithFields {
8
- controls: never[];
8
+ getControls: () => never[];
9
9
  name: string;
10
10
  forms: Record<string, Form<Fields, unknown>>;
11
- init(): void;
11
+ init(path: string, router: Router): void;
12
12
  extractRawValues(ctx: Context): Promise<Record<string, FormDataValue>>;
13
13
  canAccess(): Promise<{
14
14
  canAccess: boolean;
@@ -1,12 +1,13 @@
1
- import { Context } from "koa";
2
- import { Templatable, FlatTemplatable } from "tempstream";
3
- import { Page } from "./page.js";
4
1
  import { ShapeToType } from "@sealcode/ts-predicates";
2
+ import { Context } from "koa";
3
+ import { FlatTemplatable, Templatable } from "tempstream";
5
4
  import { FormControl } from "../forms/controls/controls.js";
6
5
  import { FormField } from "../forms/fields/field.js";
7
6
  import { NumberField } from "../forms/fields/number.js";
8
7
  import { TextBasedSimpleField } from "../forms/fields/simple-form-field.js";
9
8
  import { FormDataValue } from "../forms/form-types.js";
9
+ import { Page } from "./page.js";
10
+ import Router from "@koa/router";
10
11
  export declare const BasePagePropsShape: {};
11
12
  export type BasePageProps = ShapeToType<typeof BasePagePropsShape>;
12
13
  export declare const DEFAULT_ITEMS_PER_PAGE = 12;
@@ -25,7 +26,7 @@ export declare abstract class ListPage<ItemType, F extends typeof BaseListPageFi
25
26
  abstract renderItem(ctx: Context, item: ItemType, index: number): Promise<FlatTemplatable>;
26
27
  filterFields: Record<string, FormField>;
27
28
  filterControls: FormControl[];
28
- init(): void;
29
+ init(path: string, router: Router): void;
29
30
  renderListContainer(_: Context, content: Templatable): FlatTemplatable;
30
31
  getPaginationConfig(ctx: Context): Promise<{
31
32
  page: number;
@@ -5,6 +5,7 @@ import { FieldMessages, FormControl, FormControlContext } from "../forms/control
5
5
  import type { FieldsToShape, FormField } from "../forms/fields/field.js";
6
6
  import type { FormDataValue, FormMessage, FormData } from "../forms/form-types.js";
7
7
  import { Mountable } from "./mountable.js";
8
+ import Router from "@koa/router";
8
9
  export type PageErrorMessage = {
9
10
  type: "access" | "internal";
10
11
  message: string;
@@ -13,12 +14,18 @@ export type Fields = Record<string, FormField<boolean, any>>;
13
14
  type Resolved<T> = T extends Promise<infer X> ? X : never;
14
15
  type ParsedValue<T extends FormField> = Resolved<ReturnType<T["getParsedValue"]>>["parsed"];
15
16
  export declare abstract class MountableWithFields<F extends Fields = Fields> extends Mountable {
17
+ getFields: () => F;
16
18
  fields: F;
19
+ initialized: boolean;
17
20
  field_names_prefix: string;
18
21
  form_id: string;
19
- abstract controls: FormControl[];
22
+ abstract getControls: (fields: F) => FormControl[];
23
+ controls: FormControl[];
20
24
  constructor();
21
- init(): void;
25
+ /** most routes should be setup using .mount(), but mount runs before
26
+ initialization so we don't yet have controls, app, etc ready for dynamic
27
+ routes **/
28
+ init(path: string, router: Router): void;
22
29
  makeFormControlContext(ctx: Context, data: FormData, validate: boolean, field_name_prefix?: string, form_id?: string): FormControlContext;
23
30
  validateValues(_ctx: Context, _data: Record<string, FormDataValue>): Promise<{
24
31
  valid: boolean;
@@ -1,7 +1,7 @@
1
1
  import Router from "@koa/router";
2
2
  import { Context } from "koa";
3
3
  export declare abstract class Mountable {
4
- init(): void;
4
+ init(_path: string, _router: Router): void;
5
5
  abstract mount(router: Router, path: string): void;
6
6
  abstract canAccess(ctx: Context): Promise<{
7
7
  canAccess: boolean;
@@ -6,7 +6,7 @@ import { Fields, MountableWithFields, PageErrorMessage } from "./mountable-with-
6
6
  import { PagePropsParser } from "./props-parser.js";
7
7
  export declare abstract class Page<F extends Fields = Record<string, never>> extends MountableWithFields<F> {
8
8
  propsParser: PagePropsParser<Record<keyof Fields, unknown>>;
9
- controls: never[];
9
+ getControls: () => never[];
10
10
  mount(router: Router, path: string): void;
11
11
  canAccess(_: Context): Promise<{
12
12
  canAccess: boolean;
@@ -1,7 +1,7 @@
1
1
  declare const defaults: {
2
2
  postimport: string;
3
- fields: string;
4
- controls: string;
3
+ get_fields: string;
4
+ get_controls: string;
5
5
  validate_method: string;
6
6
  onsubmit: string;
7
7
  can_access: string;
@@ -36,8 +36,8 @@ describe("checkboxed-list", () => {
36
36
  new class extends Form {
37
37
  constructor() {
38
38
  super(...arguments);
39
- this.fields = fields;
40
- this.controls = [new CheckboxedListInput(fields.syllables)];
39
+ this.getFields = () => fields;
40
+ this.getControls = () => [new CheckboxedListInput(fields.syllables)];
41
41
  }
42
42
  async onSubmit(ctx) {
43
43
  received_values = await this.getParsedValues(ctx);
@@ -81,8 +81,8 @@ describe("checkboxed-list", () => {
81
81
  new class extends Form {
82
82
  constructor() {
83
83
  super(...arguments);
84
- this.fields = fields;
85
- this.controls = [new CheckboxedListInput(fields.syllables)];
84
+ this.getFields = () => fields;
85
+ this.getControls = () => [new CheckboxedListInput(fields.syllables)];
86
86
  }
87
87
  async onSubmit(ctx) {
88
88
  submit_called = true;
@@ -124,8 +124,8 @@ describe("checkboxed-list", () => {
124
124
  new class extends Form {
125
125
  constructor() {
126
126
  super(...arguments);
127
- this.fields = fields;
128
- this.controls = [new CheckboxedListInput(fields.syllables)];
127
+ this.getFields = () => fields;
128
+ this.getControls = () => [new CheckboxedListInput(fields.syllables)];
129
129
  }
130
130
  async onSubmit(ctx) {
131
131
  submit_called = true;
@@ -168,8 +168,8 @@ describe("checkboxed-list", () => {
168
168
  new class extends Form {
169
169
  constructor() {
170
170
  super(...arguments);
171
- this.fields = fields;
172
- this.controls = [new CheckboxedListInput(fields.syllables)];
171
+ this.getFields = () => fields;
172
+ this.getControls = () => [new CheckboxedListInput(fields.syllables)];
173
173
  }
174
174
  async onSubmit(ctx) {
175
175
  submit_called = true;
@@ -211,8 +211,10 @@ describe("checkboxed-list", () => {
211
211
  new class extends Form {
212
212
  constructor() {
213
213
  super(...arguments);
214
- this.fields = fields;
215
- this.controls = [new CheckboxedListInput(fields.syllables, { label: "ABC" })];
214
+ this.getFields = () => fields;
215
+ this.getControls = () => [
216
+ new CheckboxedListInput(fields.syllables, { label: "ABC" })
217
+ ];
216
218
  }
217
219
  async onSubmit(ctx) {
218
220
  }
@@ -258,8 +260,10 @@ describe("checkboxed-list", () => {
258
260
  new class extends Form {
259
261
  constructor() {
260
262
  super(...arguments);
261
- this.fields = fields;
262
- this.controls = [new CheckboxedListInput(fields.syllables, { label: "Letters" })];
263
+ this.getFields = () => fields;
264
+ this.getControls = () => [
265
+ new CheckboxedListInput(fields.syllables, { label: "Letters" })
266
+ ];
263
267
  }
264
268
  async onSubmit(ctx) {
265
269
  }
@@ -33,8 +33,8 @@ describe("file-control", () => {
33
33
  new class extends Form {
34
34
  constructor() {
35
35
  super(...arguments);
36
- this.fields = fields;
37
- this.controls = [new Controls.File(fields.file)];
36
+ this.getFields = () => fields;
37
+ this.getControls = () => [new Controls.File(fields.file)];
38
38
  }
39
39
  async onSubmit(_ctx) {
40
40
  submit_called = true;
@@ -34,8 +34,8 @@ describe("photo-control", () => {
34
34
  new class extends Form {
35
35
  constructor() {
36
36
  super(...arguments);
37
- this.fields = fields;
38
- this.controls = [new Image(fields.photo)];
37
+ this.getFields = () => fields;
38
+ this.getControls = () => [new Image(fields.photo)];
39
39
  }
40
40
  async onSubmit(ctx) {
41
41
  const data = await this.getParsedValues(ctx);
@@ -82,8 +82,8 @@ describe("photo-control", () => {
82
82
  new class extends Form {
83
83
  constructor() {
84
84
  super(...arguments);
85
- this.fields = fields;
86
- this.controls = [new Image(fields.photo)];
85
+ this.getFields = () => fields;
86
+ this.getControls = () => [new Image(fields.photo)];
87
87
  }
88
88
  async onSubmit(ctx) {
89
89
  submit_called = true;
@@ -32,8 +32,8 @@ describe("single-reference.test", () => {
32
32
  form_file_path,
33
33
  await formTemplate("SomeForm", {
34
34
  postimport: `import {Comments} from "../collections/collections.js"; import {Fields} from "@sealcode/sealgen";`,
35
- fields: `article: new Fields.CollectionField(true, Comments.fields.article),`,
36
- controls: `new Controls.SingleReferenceDropdown(fields.article, {getLabel: item=>item.get("title")}),`,
35
+ get_fields: `()=>(<const>{article: new Fields.CollectionField(true, Comments.fields.article)})`,
36
+ get_controls: `(fields)=>[new Controls.SingleReferenceDropdown(fields.article, {getLabel: item=>item.get("title")})]`,
37
37
  validate_method: "",
38
38
  success_message: "Submit OK"
39
39
  })
@@ -109,7 +109,7 @@ class FormField {
109
109
  return `${wrapKeyName(field_info.name)}: await ${vars.form_fields}${wrapAttribute(field_info.name)}.getSealiousCreateValue(fctx)`;
110
110
  }
111
111
  generateInitialValue(field_info, vars) {
112
- return `${wrapKeyName(field_info.name)}: await ${vars.form_fields}${wrapAttribute(field_info.name)}.sealiousValueToForm(ctx, item.get("${field_info.name}"))`;
112
+ return `${wrapKeyName(field_info.name)}: await ${vars.form_fields}${wrapAttribute(field_info.name)}.sealiousValueToForm(ctx, item.get("${field_info.name}"), item)`;
113
113
  }
114
114
  generateImportsForFieldList(field_info) {
115
115
  return [];
@@ -32,8 +32,8 @@ describe("basic field", () => {
32
32
  new class extends Form {
33
33
  constructor() {
34
34
  super(...arguments);
35
- this.fields = fields;
36
- this.controls = [new SimpleInput(fields.text)];
35
+ this.getFields = () => fields;
36
+ this.getControls = () => [new SimpleInput(fields.text)];
37
37
  }
38
38
  async onSubmit(ctx, data) {
39
39
  received_values = await this.getParsedValues(ctx);
@@ -81,8 +81,8 @@ describe("basic field", () => {
81
81
  new class extends Form {
82
82
  constructor() {
83
83
  super(...arguments);
84
- this.fields = fields;
85
- this.controls = [new SimpleInput(fields.text)];
84
+ this.getFields = () => fields;
85
+ this.getControls = () => [new SimpleInput(fields.text)];
86
86
  }
87
87
  async onSubmit() {
88
88
  }
@@ -118,8 +118,11 @@ describe("basic field", () => {
118
118
  new class extends Form {
119
119
  constructor() {
120
120
  super(...arguments);
121
- this.fields = fields;
122
- this.controls = [new SimpleInput(fields.text), new Checkbox(fields.checkbox)];
121
+ this.getFields = () => fields;
122
+ this.getControls = () => [
123
+ new SimpleInput(fields.text),
124
+ new Checkbox(fields.checkbox)
125
+ ];
123
126
  }
124
127
  async onSubmit() {
125
128
  submit_called = true;
@@ -15,13 +15,14 @@ export * from "./float.js";
15
15
  export * from "./html.js";
16
16
  export * from "./image.js";
17
17
  export * from "./int.js";
18
+ export * from "./item-draft.js";
18
19
  export * from "./json.js";
19
20
  export * from "./markdown.js";
20
21
  export * from "./multiple-files.js";
21
22
  export * from "./number.js";
22
23
  export * from "./password.js";
23
- export * from "./phone-number.js";
24
24
  export * from "./phone-number-with-country-code.js";
25
+ export * from "./phone-number.js";
25
26
  export * from "./pick-from-list-sealious.js";
26
27
  export * from "./pick-from-list.js";
27
28
  export * from "./regexp.js";
@@ -34,8 +34,8 @@ describe("file field", () => {
34
34
  new class extends Form {
35
35
  constructor() {
36
36
  super(...arguments);
37
- this.fields = fields;
38
- this.controls = [new Image(fields.file)];
37
+ this.getFields = () => fields;
38
+ this.getControls = () => [new Image(fields.file)];
39
39
  }
40
40
  async onSubmit(ctx) {
41
41
  received_values = await this.getParsedValues(ctx);
@@ -26,6 +26,7 @@ import { EnumMultipleSealious } from "./enum-multiple-sealious.js";
26
26
  import { URLField } from "./url.js";
27
27
  import { Image } from "./image.js";
28
28
  import { PhoneNumberWithCountryCode } from "./phone-number-with-country-code.js";
29
+ import { ItemDraft } from "./item-draft.js";
29
30
  function sealiousToFormField(sealious_field) {
30
31
  if (sealious_field instanceof SealiousFieldTypes.Boolean) {
31
32
  return new BooleanField(
@@ -99,6 +100,9 @@ function sealiousToFormField(sealious_field) {
99
100
  if (sealious_field instanceof SealiousFieldTypes.Int) {
100
101
  return new Int(sealious_field.required);
101
102
  }
103
+ if (sealious_field instanceof SealiousFieldTypes.ItemDraft) {
104
+ return new ItemDraft(sealious_field);
105
+ }
102
106
  if (sealious_field instanceof SealiousFieldTypes.JsonObject) {
103
107
  return new JSONField(
104
108
  sealious_field.required
@@ -186,6 +190,8 @@ async function sealiousFieldInfoToFormField(field_info) {
186
190
  return new Image(field_info.is_required);
187
191
  case "int":
188
192
  return new Int(field_info.is_required);
193
+ case "item-draft":
194
+ return new ItemDraft({ target_collection: { fields: {} } });
189
195
  case "json-object":
190
196
  return new JSONField(field_info.is_required);
191
197
  case "password":
@@ -0,0 +1,37 @@
1
+ import { Hybrid as HybridControl } from "../controls/hybrid.js";
2
+ import { FormField } from "./field.js";
3
+ class Hybrid extends FormField {
4
+ constructor(subfields) {
5
+ super(true);
6
+ this.subfields = subfields;
7
+ }
8
+ getEmptyValue() {
9
+ return {};
10
+ }
11
+ async parse(ctx, raw_value) {
12
+ return {
13
+ parsable: true,
14
+ error: null,
15
+ parsed_value: Object.fromEntries(
16
+ await Promise.all(
17
+ Object.entries(this.subfields).map(
18
+ async ([key, subfield]) => [
19
+ key,
20
+ (await subfield.getParsedValue(
21
+ ctx,
22
+ raw_value[key]
23
+ )).parsed
24
+ ]
25
+ )
26
+ )
27
+ )
28
+ };
29
+ }
30
+ getControl() {
31
+ return new HybridControl(this, this.subfields);
32
+ }
33
+ }
34
+ export {
35
+ Hybrid
36
+ };
37
+ //# sourceMappingURL=hybrid.js.map
@@ -0,0 +1,34 @@
1
+ import { sealiousToFormField } from "./get-field-for-sealious.js";
2
+ import { Hybrid } from "./hybrid.js";
3
+ import { toPascalCase } from "js-convert-case";
4
+ class ItemDraft extends Hybrid {
5
+ constructor(sealious_field) {
6
+ super(
7
+ Object.fromEntries(
8
+ Object.entries(sealious_field.target_collection.fields).map(
9
+ ([field_name, sealious_field2]) => [
10
+ field_name,
11
+ sealiousToFormField(sealious_field2)
12
+ ]
13
+ )
14
+ )
15
+ );
16
+ this.sealious_field = sealious_field;
17
+ }
18
+ generateFieldDeclaration(field_info, vars) {
19
+ return `new ${vars.form_field_types}.${this.constructor.name}<typeof ${toPascalCase(field_info.target)}>(${vars.sealious_field})`;
20
+ }
21
+ generateImportsForFieldList(field_info) {
22
+ return [
23
+ {
24
+ what: toPascalCase(field_info.target),
25
+ from: "src/back/collections/collections.js",
26
+ type: true
27
+ }
28
+ ];
29
+ }
30
+ }
31
+ export {
32
+ ItemDraft
33
+ };
34
+ //# sourceMappingURL=item-draft.js.map
package/lib/forms/form.js CHANGED
@@ -168,6 +168,17 @@ class Form extends MountableWithFields {
168
168
  );
169
169
  }
170
170
  }
171
+ init(path, router) {
172
+ super.init(path, router);
173
+ if (this.initialized) {
174
+ return;
175
+ }
176
+ const subrouter = new Router();
177
+ for (const control of this.controls) {
178
+ control.mount(subrouter, this);
179
+ }
180
+ router.use(path, subrouter.routes(), subrouter.allowedMethods());
181
+ }
171
182
  mount(router, path) {
172
183
  router.use(path, async (ctx, next) => {
173
184
  const result = await this.canAccess(ctx);
@@ -181,11 +192,6 @@ class Form extends MountableWithFields {
181
192
  }
182
193
  await next();
183
194
  });
184
- const subrouter = new Router();
185
- for (const control of this.controls) {
186
- control.mount(subrouter, this);
187
- }
188
- router.use(path, subrouter.routes(), subrouter.allowedMethods());
189
195
  router.get(path, async (ctx) => {
190
196
  ctx.type = "html";
191
197
  ctx.body = await this.render(
@@ -16,9 +16,9 @@ function form_factory(canAccessFun) {
16
16
  const result = new class extends Form {
17
17
  constructor() {
18
18
  super(...arguments);
19
- this.fields = fields;
19
+ this.getFields = () => fields;
20
20
  this.submitButtonText = "Submit";
21
- this.controls = [
21
+ this.getControls = () => [
22
22
  new Controls.SimpleInput(fields.text, {
23
23
  label: "This is a test:",
24
24
  type: "password"
@@ -98,7 +98,7 @@ describe("form test", () => {
98
98
  router,
99
99
  "/",
100
100
  form_factory(
101
- async (ctx) => {
101
+ async (_ctx) => {
102
102
  return { canAccess: true, message: "" };
103
103
  }
104
104
  ),
@@ -213,9 +213,9 @@ describe("form test", () => {
213
213
  new class extends Form {
214
214
  constructor() {
215
215
  super(...arguments);
216
- this.fields = fields;
216
+ this.getFields = () => fields;
217
217
  this.submitButtonText = "Submit";
218
- this.controls = [
218
+ this.getControls = () => [
219
219
  new Controls.SimpleInput(fields.text, {
220
220
  label: "This is a test:",
221
221
  type: "password"
@@ -273,9 +273,9 @@ describe("form test", () => {
273
273
  new class extends Form {
274
274
  constructor() {
275
275
  super(...arguments);
276
- this.fields = fields2;
276
+ this.getFields = () => fields2;
277
277
  this.submitButtonText = "Submit";
278
- this.controls = [
278
+ this.getControls = () => [
279
279
  new Controls.SimpleInput(fields2.text, {
280
280
  label: "This is a test:",
281
281
  type: "text"
@@ -328,8 +328,8 @@ describe("form test", () => {
328
328
  new class extends Form {
329
329
  constructor() {
330
330
  super(...arguments);
331
- this.fields = fields2;
332
- this.controls = [new Controls.SimpleInput(fields2.title)];
331
+ this.getFields = () => fields2;
332
+ this.getControls = () => [new Controls.SimpleInput(fields2.title)];
333
333
  }
334
334
  async getInitialValues() {
335
335
  return { title: "Hello" };
@@ -6,10 +6,13 @@ const FIELD_PREFIX_SEPARATOR = "___";
6
6
  class Multiform extends MountableWithFields {
7
7
  constructor() {
8
8
  super(...arguments);
9
- this.controls = [];
9
+ this.getControls = () => [];
10
10
  }
11
- init() {
12
- super.init();
11
+ init(path, router) {
12
+ if (this.initialized) {
13
+ return;
14
+ }
15
+ super.init(path, router);
13
16
  for (const [key, form] of Object.entries(this.forms)) {
14
17
  if (key !== attribute(key)) {
15
18
  throw new Error(
@@ -23,7 +26,7 @@ class Multiform extends MountableWithFields {
23
26
  form.field_names_prefix = key + FIELD_PREFIX_SEPARATOR;
24
27
  form.form_id = this.name;
25
28
  form.action = "./" + key;
26
- form.init();
29
+ form.init(path, router);
27
30
  form.extractRawValues = async (context) => this.getSubformRawValues(context, key);
28
31
  const submit_button_id = this.name + "_" + key + "_submit";
29
32
  form.makeSubmitButton = () => (
@@ -23,8 +23,8 @@ const form1 = new class extends Form {
23
23
  constructor() {
24
24
  super(...arguments);
25
25
  this.defaultSuccessMessage = "Form1 done!";
26
- this.controls = [new FormHeader("form1"), new SimpleInput(fields1.email)];
27
- this.fields = fields1;
26
+ this.getControls = () => [new FormHeader("form1"), new SimpleInput(fields1.email)];
27
+ this.getFields = () => fields1;
28
28
  }
29
29
  onSubmit() {
30
30
  return;
@@ -37,8 +37,8 @@ const form2 = new class extends Form {
37
37
  constructor() {
38
38
  super(...arguments);
39
39
  this.defaultSuccessMessage = "Form2 done!";
40
- this.controls = [new FormHeader("form2"), new SimpleInput(fields2.name)];
41
- this.fields = fields2;
40
+ this.getControls = () => [new FormHeader("form2"), new SimpleInput(fields2.name)];
41
+ this.getFields = () => fields2;
42
42
  }
43
43
  onSubmit() {
44
44
  return;
@@ -375,7 +375,7 @@ describe("multiform test", () => {
375
375
  super(...arguments);
376
376
  this.fields = fields1;
377
377
  this.submitButtonText = "Submit";
378
- this.controls = [
378
+ this.getControls = () => [
379
379
  new SimpleInput(fields1.email, {
380
380
  label: "This is a test:",
381
381
  type: "text"
@@ -442,9 +442,9 @@ describe("multiform test", () => {
442
442
  form1: new class extends Form {
443
443
  constructor() {
444
444
  super(...arguments);
445
- this.fields = fields;
445
+ this.getFields = () => fields;
446
446
  this.submitButtonText = "Submit";
447
- this.controls = [
447
+ this.getControls = () => [
448
448
  new SimpleInput(fields.text, {
449
449
  label: "This is a test:",
450
450
  type: "text"