@sealcode/sealgen 0.19.4 → 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.
- package/@types/forms/fields/field.d.ts +1 -0
- package/@types/forms/fields/fields.d.ts +2 -1
- package/@types/forms/fields/get-field-for-sealious.d.ts +3 -1
- package/@types/forms/fields/hybrid.d.ts +11 -0
- package/@types/forms/fields/item-draft.d.ts +20 -0
- package/@types/forms/form.d.ts +1 -0
- package/@types/forms/multiform.d.ts +2 -2
- package/@types/page/list.d.ts +5 -4
- package/@types/page/mountable-with-fields.d.ts +9 -2
- package/@types/page/mountable.d.ts +1 -1
- package/@types/page/page.d.ts +1 -1
- package/@types/templates/form.d.ts +2 -2
- package/lib/forms/controls/checkboxed-list-input.test.js +16 -12
- package/lib/forms/controls/file.test.js +2 -2
- package/lib/forms/controls/image.test.js +4 -4
- package/lib/forms/controls/single-reference.test.js +2 -2
- package/lib/forms/fields/field.js +1 -1
- package/lib/forms/fields/field.test.js +9 -6
- package/lib/forms/fields/fields.js +2 -1
- package/lib/forms/fields/file.test.js +2 -2
- package/lib/forms/fields/get-field-for-sealious.js +14 -0
- package/lib/forms/fields/hybrid.js +37 -0
- package/lib/forms/fields/item-draft.js +34 -0
- package/lib/forms/form.js +11 -5
- package/lib/forms/form.test.js +9 -9
- package/lib/forms/multiform.js +7 -4
- package/lib/forms/multiform.test.js +7 -7
- package/lib/mount.js +4 -1
- package/lib/page/list.js +9 -6
- package/lib/page/mountable-with-fields.js +16 -1
- package/lib/page/mountable-with-fields.test.js +2 -2
- package/lib/page/mountable.js +1 -1
- package/lib/page/page.js +1 -1
- package/lib/templates/form.js +9 -18
- package/lib/templates/shared/collection-create-form.js +8 -8
- package/lib/templates/shared/collection-edit-form.js +9 -9
- package/lib/templates/shared/collection-list.js +2 -1
- package/lib/templates/shared/shared-crud-form-fields.js +4 -4
- package/lib/utils/extract-fields-from-collection.js +3 -0
- package/package.json +1 -1
- package/src/forms/controls/checkboxed-list-input.test.ts +16 -12
- package/src/forms/controls/file.test.ts +2 -2
- package/src/forms/controls/image.test.ts +4 -4
- package/src/forms/controls/single-reference.test.ts +2 -2
- package/src/forms/fields/field.test.ts +9 -6
- package/src/forms/fields/field.ts +6 -7
- package/src/forms/fields/fields.ts +2 -1
- package/src/forms/fields/file.test.ts +2 -2
- package/src/forms/fields/get-field-for-sealious.ts +66 -100
- package/src/forms/fields/hybrid.ts +47 -0
- package/src/forms/fields/item-draft.ts +44 -0
- package/src/forms/form.test.ts +15 -15
- package/src/forms/form.ts +34 -26
- package/src/forms/multiform.test.ts +7 -7
- package/src/forms/multiform.ts +10 -7
- package/src/mount.ts +11 -7
- package/src/page/list.ts +33 -28
- package/src/page/mountable-with-fields.test.ts +2 -2
- package/src/page/mountable-with-fields.ts +26 -5
- package/src/page/mountable.ts +1 -1
- package/src/page/page.ts +1 -1
- package/src/templates/form.ts +9 -18
- package/src/templates/shared/collection-create-form.ts +8 -8
- package/src/templates/shared/collection-edit-form.ts +9 -9
- package/src/templates/shared/collection-list.ts +5 -4
- package/src/templates/shared/shared-crud-form-fields.ts +5 -5
- package/src/utils/extract-fields-from-collection.ts +3 -0
|
@@ -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";
|
|
@@ -26,6 +26,8 @@ import { ExtractedFieldInfo } from "../../utils/extract-fields-from-collection.j
|
|
|
26
26
|
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
|
+
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>;
|
|
30
32
|
export declare function sealiousToFormField<SF extends SealiousField<any>>(sealious_field: SF): SealiousToFormField<SF>;
|
|
31
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
|
+
}
|
package/@types/forms/form.d.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/@types/page/list.d.ts
CHANGED
|
@@ -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
|
|
22
|
+
abstract getControls: (fields: F) => FormControl[];
|
|
23
|
+
controls: FormControl[];
|
|
20
24
|
constructor();
|
|
21
|
-
|
|
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;
|
package/@types/page/page.d.ts
CHANGED
|
@@ -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
|
-
|
|
9
|
+
getControls: () => never[];
|
|
10
10
|
mount(router: Router, path: string): void;
|
|
11
11
|
canAccess(_: Context): Promise<{
|
|
12
12
|
canAccess: boolean;
|
|
@@ -36,8 +36,8 @@ describe("checkboxed-list", () => {
|
|
|
36
36
|
new class extends Form {
|
|
37
37
|
constructor() {
|
|
38
38
|
super(...arguments);
|
|
39
|
-
this.
|
|
40
|
-
this.
|
|
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.
|
|
85
|
-
this.
|
|
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.
|
|
128
|
-
this.
|
|
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.
|
|
172
|
-
this.
|
|
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.
|
|
215
|
-
this.
|
|
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.
|
|
262
|
-
this.
|
|
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.
|
|
37
|
-
this.
|
|
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.
|
|
38
|
-
this.
|
|
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.
|
|
86
|
-
this.
|
|
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
|
-
|
|
36
|
-
|
|
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.
|
|
36
|
-
this.
|
|
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.
|
|
85
|
-
this.
|
|
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.
|
|
122
|
-
this.
|
|
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.
|
|
38
|
-
this.
|
|
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);
|
|
@@ -25,6 +25,8 @@ import extract_fields_from_collection from "../../utils/extract-fields-from-coll
|
|
|
25
25
|
import { EnumMultipleSealious } from "./enum-multiple-sealious.js";
|
|
26
26
|
import { URLField } from "./url.js";
|
|
27
27
|
import { Image } from "./image.js";
|
|
28
|
+
import { PhoneNumberWithCountryCode } from "./phone-number-with-country-code.js";
|
|
29
|
+
import { ItemDraft } from "./item-draft.js";
|
|
28
30
|
function sealiousToFormField(sealious_field) {
|
|
29
31
|
if (sealious_field instanceof SealiousFieldTypes.Boolean) {
|
|
30
32
|
return new BooleanField(
|
|
@@ -98,6 +100,9 @@ function sealiousToFormField(sealious_field) {
|
|
|
98
100
|
if (sealious_field instanceof SealiousFieldTypes.Int) {
|
|
99
101
|
return new Int(sealious_field.required);
|
|
100
102
|
}
|
|
103
|
+
if (sealious_field instanceof SealiousFieldTypes.ItemDraft) {
|
|
104
|
+
return new ItemDraft(sealious_field);
|
|
105
|
+
}
|
|
101
106
|
if (sealious_field instanceof SealiousFieldTypes.JsonObject) {
|
|
102
107
|
return new JSONField(
|
|
103
108
|
sealious_field.required
|
|
@@ -106,6 +111,11 @@ function sealiousToFormField(sealious_field) {
|
|
|
106
111
|
if (sealious_field instanceof SealiousFieldTypes.Password) {
|
|
107
112
|
return new Password(sealious_field.required);
|
|
108
113
|
}
|
|
114
|
+
if (sealious_field instanceof SealiousFieldTypes.PhoneNumber) {
|
|
115
|
+
return new PhoneNumberWithCountryCode(
|
|
116
|
+
sealious_field.required
|
|
117
|
+
);
|
|
118
|
+
}
|
|
109
119
|
if (sealious_field instanceof SealiousFieldTypes.SettableBy) {
|
|
110
120
|
return sealiousToFormField(
|
|
111
121
|
sealious_field.virtual_field
|
|
@@ -180,10 +190,14 @@ async function sealiousFieldInfoToFormField(field_info) {
|
|
|
180
190
|
return new Image(field_info.is_required);
|
|
181
191
|
case "int":
|
|
182
192
|
return new Int(field_info.is_required);
|
|
193
|
+
case "item-draft":
|
|
194
|
+
return new ItemDraft({ target_collection: { fields: {} } });
|
|
183
195
|
case "json-object":
|
|
184
196
|
return new JSONField(field_info.is_required);
|
|
185
197
|
case "password":
|
|
186
198
|
return new Password(field_info.is_required);
|
|
199
|
+
case "phone-number":
|
|
200
|
+
return new PhoneNumberWithCountryCode(field_info.is_required);
|
|
187
201
|
case "single-reference":
|
|
188
202
|
return new SingleReference(false, {});
|
|
189
203
|
case "text":
|
|
@@ -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(
|
package/lib/forms/form.test.js
CHANGED
|
@@ -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.
|
|
19
|
+
this.getFields = () => fields;
|
|
20
20
|
this.submitButtonText = "Submit";
|
|
21
|
-
this.
|
|
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 (
|
|
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.
|
|
216
|
+
this.getFields = () => fields;
|
|
217
217
|
this.submitButtonText = "Submit";
|
|
218
|
-
this.
|
|
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.
|
|
276
|
+
this.getFields = () => fields2;
|
|
277
277
|
this.submitButtonText = "Submit";
|
|
278
|
-
this.
|
|
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.
|
|
332
|
-
this.
|
|
331
|
+
this.getFields = () => fields2;
|
|
332
|
+
this.getControls = () => [new Controls.SimpleInput(fields2.title)];
|
|
333
333
|
}
|
|
334
334
|
async getInitialValues() {
|
|
335
335
|
return { title: "Hello" };
|
package/lib/forms/multiform.js
CHANGED
|
@@ -6,10 +6,13 @@ const FIELD_PREFIX_SEPARATOR = "___";
|
|
|
6
6
|
class Multiform extends MountableWithFields {
|
|
7
7
|
constructor() {
|
|
8
8
|
super(...arguments);
|
|
9
|
-
this.
|
|
9
|
+
this.getControls = () => [];
|
|
10
10
|
}
|
|
11
|
-
init() {
|
|
12
|
-
|
|
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 = () => (
|