@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.
- 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 +2 -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.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 +6 -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 +5 -6
- 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 +8 -0
- 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";
|
|
@@ -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
|
-
|
|
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
|
+
}
|
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
|
})
|
|
@@ -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);
|
|
@@ -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(
|
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 = () => (
|
|
@@ -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.
|
|
27
|
-
this.
|
|
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.
|
|
41
|
-
this.
|
|
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.
|
|
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.
|
|
445
|
+
this.getFields = () => fields;
|
|
446
446
|
this.submitButtonText = "Submit";
|
|
447
|
-
this.
|
|
447
|
+
this.getControls = () => [
|
|
448
448
|
new SimpleInput(fields.text, {
|
|
449
449
|
label: "This is a test:",
|
|
450
450
|
type: "text"
|
package/lib/mount.js
CHANGED
|
@@ -50,7 +50,10 @@ function mount(router, url, mountable, use_dummy_app = false, file_manager = use
|
|
|
50
50
|
handleHtmlPromise
|
|
51
51
|
];
|
|
52
52
|
router.use(raw_url, ...args);
|
|
53
|
-
|
|
53
|
+
router.use(raw_url, async (_ctx, next) => {
|
|
54
|
+
mountable.init(raw_url, router);
|
|
55
|
+
await next();
|
|
56
|
+
});
|
|
54
57
|
router.get(raw_url.slice(0, -1), async (ctx, next) => {
|
|
55
58
|
const url2 = ctx.URL;
|
|
56
59
|
if (!url2.pathname.endsWith("/")) {
|