@sealcode/sealgen 0.15.1 → 0.15.3
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/.eslintrc.cjs +38 -0
- package/.xunit +53 -0
- package/@types/src/page/stateful-page.d.ts +4 -2
- package/build.js +1 -1
- package/{dist → lib}/add-route.test.js +2 -2
- package/{dist → lib}/build.js +3 -3
- package/{dist → lib}/builder.js +3 -0
- package/lib/cli.js +39 -0
- package/{dist → lib}/esbuild-plugins/load-assets.js +2 -2
- package/{dist → lib}/forms/controls/array.js +1 -2
- package/{dist → lib}/forms/controls/autocomplete.js +8 -10
- package/{dist → lib}/forms/controls/checkboxed-list-input.test.js +3 -2
- package/{dist → lib}/forms/controls/collapsible-field-group.js +2 -1
- package/{dist → lib}/forms/controls/editable-collection-subset.js +6 -4
- package/{dist → lib}/forms/controls/field-group.js +1 -1
- package/{dist → lib}/forms/controls/file.js +2 -5
- package/{dist → lib}/forms/controls/form-control.js +2 -1
- package/{dist → lib}/forms/controls/photo.js +1 -1
- package/{dist → lib}/forms/controls/photo.test.js +5 -7
- package/{dist → lib}/forms/controls/textarea.js +1 -1
- package/{dist → lib}/forms/fields/boolean.test.js +0 -1
- package/{dist → lib}/forms/fields/field.js +2 -5
- package/{dist → lib}/forms/fields/file.js +8 -2
- package/{dist → lib}/forms/fields/structured-array.js +1 -1
- package/{dist → lib}/forms/form.test.js +8 -9
- package/{dist → lib}/forms/multiform.test.js +14 -14
- package/{dist → lib}/generate-components.js +1 -1
- package/{dist → lib}/generate-routes.test.js +1 -0
- package/{dist → lib}/generate-stimulus.js +1 -1
- package/lib/index.js +25 -0
- package/{dist → lib}/mount.js +4 -3
- package/{dist → lib}/notifier.js +3 -1
- package/{dist → lib}/page/list.js +1 -1
- package/{dist → lib}/page/mountable-with-fields.js +1 -1
- package/{dist → lib}/page/sealious-list.js +2 -2
- package/{dist → lib}/page/stateful-page.js +37 -19
- package/{dist → lib}/templates/jdd-component.js +2 -2
- package/{dist → lib}/utils/extract-fields-from-collection.js +16 -1
- package/package.json +19 -14
- package/src/add-route.test.ts +2 -2
- package/src/add-route.ts +2 -2
- package/src/build.ts +3 -3
- package/src/builder.ts +3 -2
- package/src/esbuild-plugins/load-assets.ts +5 -4
- package/src/esbuild-plugins/rewrite-asset-imports.ts +4 -3
- package/src/forms/controls/array.ts +5 -3
- package/src/forms/controls/autocomplete.ts +2 -2
- package/src/forms/controls/checkbox-group.ts +1 -5
- package/src/forms/controls/checkboxed-list-input.test.ts +3 -2
- package/src/forms/controls/checkboxed-list-input.ts +0 -1
- package/src/forms/controls/collapsible-field-group.ts +4 -2
- package/src/forms/controls/derived.ts +1 -1
- package/src/forms/controls/dropdown.ts +3 -3
- package/src/forms/controls/editable-collection-subset.ts +10 -4
- package/src/forms/controls/field-group.ts +1 -1
- package/src/forms/controls/file.ts +1 -1
- package/src/forms/controls/form-control.ts +2 -1
- package/src/forms/controls/hidden-input.ts +0 -2
- package/src/forms/controls/multiple-files.ts +8 -5
- package/src/forms/controls/number.ts +1 -1
- package/src/forms/controls/photo.test.ts +6 -7
- package/src/forms/controls/photo.ts +3 -6
- package/src/forms/controls/simple-input.ts +3 -5
- package/src/forms/controls/textarea.ts +3 -8
- package/src/forms/controls/tickable.ts +2 -4
- package/src/forms/fields/boolean.test.ts +0 -1
- package/src/forms/fields/existing-sealious-value.ts +1 -0
- package/src/forms/fields/field.ts +5 -8
- package/src/forms/fields/file.ts +13 -6
- package/src/forms/fields/structured-array.ts +2 -2
- package/src/forms/form.test.ts +9 -10
- package/src/forms/form.ts +1 -1
- package/src/forms/multiform.test.ts +14 -14
- package/src/forms/multiform.ts +2 -1
- package/src/generate-components.ts +1 -2
- package/src/generate-routes.test.ts +1 -0
- package/src/generate-stimulus.ts +1 -1
- package/src/get-fonts.ts +2 -0
- package/src/mount.ts +8 -3
- package/src/notifier.ts +3 -1
- package/src/page/list.ts +1 -1
- package/src/page/mountable-with-fields.ts +3 -1
- package/src/page/sealious-list.ts +3 -2
- package/src/page/stateful-page.ts +53 -24
- package/src/templates/jdd-component.ts +2 -2
- package/src/utils/extract-fields-from-collection.ts +19 -1
- package/src/utils/translate.ts +1 -1
- package/src/utils/utils.ts +2 -0
- package/test.cjs +54 -0
- package/tsconfig.json +3 -4
- package/dist/back/routes/sample.page.js +0 -17
- package/dist/back/routes/sample.test.js +0 -39
- package/dist/hehe.test.js +0 -7
- package/dist/sample-index.js +0 -3
- package/dist/sample-lib.js +0 -9
- package/dist/vitest.config.js +0 -23
- package/src/vitest.config.ts +0 -21
- /package/{dist → lib}/add-collection.js +0 -0
- /package/{dist → lib}/add-jdd-component.js +0 -0
- /package/{dist → lib}/add-route.js +0 -0
- /package/{dist → lib}/components/components.js +0 -0
- /package/{dist → lib}/components/tabs.js +0 -0
- /package/{dist → lib}/components/toggle-modal.js +0 -0
- /package/{dist → lib}/embeddable-file-extensions.js +0 -0
- /package/{dist → lib}/esbuild-plugins/rewrite-asset-imports.js +0 -0
- /package/{dist → lib}/example.test.js +0 -0
- /package/{dist → lib}/find-css-includes.js +0 -0
- /package/{dist → lib}/forms/controls/big-radio-group.js +0 -0
- /package/{dist → lib}/forms/controls/checkbox-group.js +0 -0
- /package/{dist → lib}/forms/controls/checkbox.js +0 -0
- /package/{dist → lib}/forms/controls/checkboxed-list-input.js +0 -0
- /package/{dist → lib}/forms/controls/collapsible-checkbox-group.js +0 -0
- /package/{dist → lib}/forms/controls/controls.js +0 -0
- /package/{dist → lib}/forms/controls/derived-frame.js +0 -0
- /package/{dist → lib}/forms/controls/derived.js +0 -0
- /package/{dist → lib}/forms/controls/dropdown.js +0 -0
- /package/{dist → lib}/forms/controls/form-field-control.js +0 -0
- /package/{dist → lib}/forms/controls/form-header.js +0 -0
- /package/{dist → lib}/forms/controls/form-paragraph.js +0 -0
- /package/{dist → lib}/forms/controls/frame.js +0 -0
- /package/{dist → lib}/forms/controls/hidden-input.js +0 -0
- /package/{dist → lib}/forms/controls/html.js +0 -0
- /package/{dist → lib}/forms/controls/multiple-files.js +0 -0
- /package/{dist → lib}/forms/controls/multiple-photos.js +0 -0
- /package/{dist → lib}/forms/controls/number.js +0 -0
- /package/{dist → lib}/forms/controls/radio.js +0 -0
- /package/{dist → lib}/forms/controls/reverse-single-reference.js +0 -0
- /package/{dist → lib}/forms/controls/simple-input.js +0 -0
- /package/{dist → lib}/forms/controls/tickable.js +0 -0
- /package/{dist → lib}/forms/fields/boolean.js +0 -0
- /package/{dist → lib}/forms/fields/checkboxed-list.js +0 -0
- /package/{dist → lib}/forms/fields/collection-field.js +0 -0
- /package/{dist → lib}/forms/fields/email.js +0 -0
- /package/{dist → lib}/forms/fields/email.test.js +0 -0
- /package/{dist → lib}/forms/fields/enum-multiple.js +0 -0
- /package/{dist → lib}/forms/fields/enum-multiple.test.js +0 -0
- /package/{dist → lib}/forms/fields/enum.js +0 -0
- /package/{dist → lib}/forms/fields/enum.test.js +0 -0
- /package/{dist → lib}/forms/fields/existing-sealious-value.js +0 -0
- /package/{dist → lib}/forms/fields/fields.js +0 -0
- /package/{dist → lib}/forms/fields/multiple-files.js +0 -0
- /package/{dist → lib}/forms/fields/number.js +0 -0
- /package/{dist → lib}/forms/fields/number.test.js +0 -0
- /package/{dist → lib}/forms/fields/pick-from-list.js +0 -0
- /package/{dist → lib}/forms/fields/pick-from-list.test.js +0 -0
- /package/{dist → lib}/forms/fields/proxy-field.js +0 -0
- /package/{dist → lib}/forms/fields/regexp.js +0 -0
- /package/{dist → lib}/forms/fields/regexp.test.js +0 -0
- /package/{dist → lib}/forms/fields/reverse-single-reference.js +0 -0
- /package/{dist → lib}/forms/fields/simple-form-field.js +0 -0
- /package/{dist → lib}/forms/form-types.js +0 -0
- /package/{dist → lib}/forms/form.js +0 -0
- /package/{dist → lib}/forms/multiform.js +0 -0
- /package/{dist → lib}/generate-collections.js +0 -0
- /package/{dist → lib}/generate-routes.js +0 -0
- /package/{dist → lib}/get-fonts.js +0 -0
- /package/{dist → lib}/koa.d.js +0 -0
- /package/{dist → lib}/make-env.js +0 -0
- /package/{dist → lib}/make-hidden-inputs.js +0 -0
- /package/{dist → lib}/page/access-control.js +0 -0
- /package/{dist → lib}/page/default-list-filters.js +0 -0
- /package/{dist → lib}/page/mountable.js +0 -0
- /package/{dist → lib}/page/page.js +0 -0
- /package/{dist → lib}/page/props-parser.js +0 -0
- /package/{dist → lib}/run.js +0 -0
- /package/{dist → lib}/sanitize.js +0 -0
- /package/{dist → lib}/target-locreq.js +0 -0
- /package/{dist → lib}/templates/collection.js +0 -0
- /package/{dist → lib}/templates/form.js +0 -0
- /package/{dist → lib}/templates/list.js +0 -0
- /package/{dist → lib}/templates/long-running-process.js +0 -0
- /package/{dist → lib}/templates/multiform.js +0 -0
- /package/{dist → lib}/templates/page.js +0 -0
- /package/{dist → lib}/templates/post.js +0 -0
- /package/{dist → lib}/templates/redirect.js +0 -0
- /package/{dist → lib}/templates/route-test.js +0 -0
- /package/{dist → lib}/templates/stateful-page.js +0 -0
- /package/{dist → lib}/templates/stimulus-controller.js +0 -0
- /package/{dist → lib}/templates/templates.js +0 -0
- /package/{dist → lib}/test_utils/locator_is_visible.js +0 -0
- /package/{dist → lib}/utils/assert-throws.js +0 -0
- /package/{dist → lib}/utils/base64.js +0 -0
- /package/{dist → lib}/utils/browser-creator.js +0 -0
- /package/{dist → lib}/utils/escape-url-params.js +0 -0
- /package/{dist → lib}/utils/exec.js +0 -0
- /package/{dist → lib}/utils/format-external-url.js +0 -0
- /package/{dist → lib}/utils/import-path.js +0 -0
- /package/{dist → lib}/utils/input-wrapper.js +0 -0
- /package/{dist → lib}/utils/list-collections.js +0 -0
- /package/{dist → lib}/utils/make-slug.js +0 -0
- /package/{dist → lib}/utils/module-dirname.js +0 -0
- /package/{dist → lib}/utils/natural-numbers.js +0 -0
- /package/{dist → lib}/utils/prettier.js +0 -0
- /package/{dist → lib}/utils/question.js +0 -0
- /package/{dist → lib}/utils/render-attributes.js +0 -0
- /package/{dist → lib}/utils/sleep.js +0 -0
- /package/{dist → lib}/utils/translate.js +0 -0
- /package/{dist → lib}/utils/url-with-new-params.js +0 -0
- /package/{dist → lib}/utils/utils.js +0 -0
- /package/{dist → lib}/utils/walk.js +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
1
2
|
import Router from "@koa/router";
|
|
2
3
|
import { hasShape, predicates } from "@sealcode/ts-predicates";
|
|
3
4
|
import { Context } from "koa";
|
|
@@ -57,7 +58,6 @@ export class StructuredArray<
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
makeSubfield(_field_name: string): FormField {
|
|
60
|
-
const fields = this;
|
|
61
61
|
return new SimpleFormField(false);
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -77,6 +77,7 @@ export class StructuredArray<
|
|
|
77
77
|
validate: false,
|
|
78
78
|
};
|
|
79
79
|
if (Array.isArray(control)) {
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
80
81
|
const [constructor, field_name, params] = control;
|
|
81
82
|
const field = this.makeSubfield(field_name);
|
|
82
83
|
if (!field) {
|
|
@@ -173,13 +174,14 @@ export class StructuredArray<
|
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
async getTargetItemID(ctx: Context): Promise<string> {
|
|
176
|
-
|
|
177
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
178
|
+
return ctx.params.id as string;
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
mount(router: Router) {
|
|
180
182
|
console.log("mounting!", this.getActionURL());
|
|
181
183
|
router.post(this.getActionURL(), async (ctx) => {
|
|
182
|
-
|
|
184
|
+
const form_id = ctx.query.form_id;
|
|
183
185
|
if (typeof form_id != "string") {
|
|
184
186
|
throw new Error("Missing form_id query param");
|
|
185
187
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Context } from "koa";
|
|
2
|
+
import { tempstream } from "tempstream";
|
|
2
3
|
import { PickFromListField } from "../fields/pick-from-list.js";
|
|
3
|
-
import { FormDataValue } from "../form-types.js";
|
|
4
4
|
import { FormControlContext } from "./form-control.js";
|
|
5
5
|
import { SimpleInput } from "./simple-input.js";
|
|
6
6
|
|
|
@@ -24,7 +24,7 @@ export class Autocomplete extends SimpleInput<string | null> {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async postInput(ctx: Context) {
|
|
27
|
-
return /* HTML */ `<datalist id="${this.getListID()}">
|
|
27
|
+
return tempstream/* HTML */ `<datalist id="${this.getListID()}">
|
|
28
28
|
${(await this.field.generateOptions(ctx)).map(
|
|
29
29
|
({ value }) => /* HTML */ `<option>${value}</option>`
|
|
30
30
|
)}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { Context } from "koa";
|
|
2
1
|
import { FlatTemplatable } from "tempstream";
|
|
3
2
|
import { EnumMultipleField } from "../fields/enum-multiple.js";
|
|
4
|
-
import { FormField } from "../fields/field.js";
|
|
5
3
|
import { ProxyFormField } from "../fields/proxy-field.js";
|
|
6
4
|
import { CheckboxWithValue } from "./checkbox.js";
|
|
7
5
|
import { FieldGroup } from "./field-group.js";
|
|
@@ -41,9 +39,7 @@ export class CheckboxGroup<
|
|
|
41
39
|
}).render(fctx);
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
async render
|
|
45
|
-
fctx: FormControlContext
|
|
46
|
-
): Promise<FlatTemplatable> {
|
|
42
|
+
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
47
43
|
const { parsed: values } = await this.field.getValue(
|
|
48
44
|
fctx.ctx,
|
|
49
45
|
fctx.data
|
|
@@ -8,14 +8,15 @@ import { CheckboxedListField } from "../fields/checkboxed-list.js";
|
|
|
8
8
|
import { Form } from "../form.js";
|
|
9
9
|
import { CheckboxedListInput } from "./checkboxed-list-input.js";
|
|
10
10
|
import { getBrowser } from "../../utils/browser-creator.js";
|
|
11
|
+
import assert from "assert";
|
|
11
12
|
|
|
12
|
-
describe
|
|
13
|
+
describe("checkboxed-list", () => {
|
|
13
14
|
describe("basic tests", async () => {
|
|
14
15
|
let server: ReturnType<Koa["listen"]>;
|
|
15
16
|
let browser: Browser;
|
|
16
17
|
let page: Page;
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
afterEach(() => {
|
|
19
20
|
server.close();
|
|
20
21
|
});
|
|
21
22
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FlatTemplatable } from "tempstream";
|
|
1
|
+
import { FlatTemplatable, tempstream } from "tempstream";
|
|
2
2
|
import { FieldGroup } from "./field-group.js";
|
|
3
3
|
import { randomUUID } from "crypto";
|
|
4
4
|
import { FormControl } from "./form-control.js";
|
|
@@ -26,7 +26,9 @@ export class CollapsibleFieldGroup extends FieldGroup {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
getGroupLabelProps() {
|
|
29
|
-
return super.getGroupLabelProps()
|
|
29
|
+
return tempstream`${super.getGroupLabelProps()} for="${
|
|
30
|
+
this.collapseID
|
|
31
|
+
}"`;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
preLabelContainer(): FlatTemplatable {
|
|
@@ -43,13 +43,13 @@ export class FreeformDropdown extends SimpleInput<string | null> {
|
|
|
43
43
|
? [
|
|
44
44
|
[
|
|
45
45
|
"onchange",
|
|
46
|
-
(original.onchange
|
|
47
|
-
";this.form.submit();",
|
|
46
|
+
((original.onchange as string | undefined) ||
|
|
47
|
+
"") + ";this.form.submit();",
|
|
48
48
|
],
|
|
49
49
|
]
|
|
50
50
|
: []),
|
|
51
51
|
]),
|
|
52
|
-
}
|
|
52
|
+
} as Record<string, string>;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
async renderInput(
|
|
@@ -42,7 +42,12 @@ export class EditableCollectionSubset extends FormFieldControl {
|
|
|
42
42
|
method="POST"
|
|
43
43
|
action="${fctx.ctx.path}"
|
|
44
44
|
>
|
|
45
|
-
<span
|
|
45
|
+
<span
|
|
46
|
+
>${
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
48
|
+
text
|
|
49
|
+
}</span
|
|
50
|
+
>
|
|
46
51
|
<input
|
|
47
52
|
type="hidden"
|
|
48
53
|
name="${this.field.name}"
|
|
@@ -79,9 +84,10 @@ export class EditableCollectionSubset extends FormFieldControl {
|
|
|
79
84
|
)
|
|
80
85
|
.map(
|
|
81
86
|
([value, text]) =>
|
|
82
|
-
`<option value="${attribute(
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
`<option value="${attribute(value)}">${
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
89
|
+
text
|
|
90
|
+
}</option>`
|
|
85
91
|
)
|
|
86
92
|
)}
|
|
87
93
|
</select>
|
|
@@ -52,7 +52,7 @@ export class FieldGroup extends FormFieldControl {
|
|
|
52
52
|
<div class="field-group__label-container">
|
|
53
53
|
${this.preLabel()}
|
|
54
54
|
${label
|
|
55
|
-
? `<label ${this.getGroupLabelProps()}>${label}</label>`
|
|
55
|
+
? tempstream`<label ${this.getGroupLabelProps()}>${label}</label>`
|
|
56
56
|
: ""}
|
|
57
57
|
${this.postLabel()}
|
|
58
58
|
</div>
|
|
@@ -21,7 +21,7 @@ export class File extends SimpleInput<FileContainer> {
|
|
|
21
21
|
if (!file) {
|
|
22
22
|
return empty_container;
|
|
23
23
|
}
|
|
24
|
-
return /* HTML */ `<div class="${class_name}">
|
|
24
|
+
return tempstream/* HTML */ `<div class="${class_name}">
|
|
25
25
|
${file.getOriginalFilename()}
|
|
26
26
|
</div>`;
|
|
27
27
|
}
|
|
@@ -20,5 +20,6 @@ export abstract class FormControl {
|
|
|
20
20
|
): FlatTemplatable | Promise<FlatTemplatable>;
|
|
21
21
|
abstract role: "input" | "decoration" | "messages" | "submit";
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
24
|
+
mount(_router: Router) {}
|
|
24
25
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { Context } from "koa";
|
|
2
1
|
import { FlatTemplatable, tempstream } from "tempstream";
|
|
3
2
|
import { attribute } from "../../sanitize.js";
|
|
4
3
|
import { FormField } from "../fields/field.js";
|
|
5
|
-
import { FormDataValue } from "../form-types.js";
|
|
6
4
|
import { FormControlContext } from "./form-control.js";
|
|
7
5
|
import { FormFieldControl } from "./form-field-control.js";
|
|
8
6
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Router from "@koa/router";
|
|
2
|
-
import { CollectionItem, Field as SealiousField } from "sealious";
|
|
2
|
+
import { Collection, CollectionItem, Field as SealiousField } from "sealious";
|
|
3
3
|
import { Context } from "koa";
|
|
4
4
|
import { inputWrapper } from "../../utils/input-wrapper.js";
|
|
5
5
|
import { FlatTemplatable, tempstream } from "tempstream";
|
|
@@ -140,14 +140,14 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
async extractFileFromItem(
|
|
143
|
-
item: CollectionItem
|
|
143
|
+
item: CollectionItem<Collection>
|
|
144
144
|
): Promise<FilePointer | null> {
|
|
145
145
|
const sealious_field = this.getFileField();
|
|
146
146
|
if (!sealious_field) {
|
|
147
147
|
return null;
|
|
148
148
|
}
|
|
149
149
|
return await item.collection.app.FileManager.fromToken(
|
|
150
|
-
item.get(sealious_field.name).token
|
|
150
|
+
(item.get(sealious_field.name) as FilePointer).token
|
|
151
151
|
);
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -216,12 +216,15 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
216
216
|
await this.getFileItems(ctx)
|
|
217
217
|
)
|
|
218
218
|
.filter((item) => item) // filter out undefineds
|
|
219
|
-
.map(async (item) => [
|
|
219
|
+
.map(async (item: CollectionItem<Collection>) => [
|
|
220
220
|
item,
|
|
221
221
|
await this.extractFileFromItem(item),
|
|
222
222
|
])
|
|
223
223
|
)
|
|
224
|
-
).filter(([_, f]) => f !== null) as [
|
|
224
|
+
).filter(([_, f]) => f !== null) as [
|
|
225
|
+
CollectionItem<Collection>,
|
|
226
|
+
FilePointer
|
|
227
|
+
][];
|
|
225
228
|
|
|
226
229
|
return inputWrapper(
|
|
227
230
|
["multiple-files", this.field.name, ...this.getClassModifiers()],
|
|
@@ -13,15 +13,16 @@ import { KoaResponsiveImageRouter } from "koa-responsive-image-router";
|
|
|
13
13
|
import _locreq from "locreq";
|
|
14
14
|
import { module_dirname } from "../../utils/module-dirname.js";
|
|
15
15
|
import { FileManager, PathFilePointer } from "@sealcode/file-manager";
|
|
16
|
+
import assert from "node:assert";
|
|
16
17
|
const locreq = _locreq(module_dirname(import.meta.url));
|
|
17
18
|
|
|
18
|
-
describe("photo-
|
|
19
|
+
describe("photo-control", () => {
|
|
19
20
|
describe("basic tests", async () => {
|
|
20
21
|
let server: ReturnType<Koa["listen"]>;
|
|
21
22
|
let browser: Browser;
|
|
22
23
|
let page: Page;
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
after(() => {
|
|
25
26
|
server.close();
|
|
26
27
|
});
|
|
27
28
|
|
|
@@ -53,13 +54,11 @@ describe("photo-controll", () => {
|
|
|
53
54
|
controls = [new Photo(fields.photo, imageRouter)];
|
|
54
55
|
|
|
55
56
|
async onSubmit(ctx: Context) {
|
|
56
|
-
console.log("OnSubmit!");
|
|
57
57
|
const data = await this.getParsedValues(ctx);
|
|
58
|
-
console.log({ data });
|
|
59
58
|
received_photo = data.photo;
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
async getInitialValues(
|
|
61
|
+
async getInitialValues(_ctx: Context) {
|
|
63
62
|
const file = new PathFilePointer(
|
|
64
63
|
new FileManager("/tmp", "/uploaded_files"),
|
|
65
64
|
locreq.resolve("assets/important.png")
|
|
@@ -77,14 +76,14 @@ describe("photo-controll", () => {
|
|
|
77
76
|
);
|
|
78
77
|
app.use(router.routes()).use(router.allowedMethods());
|
|
79
78
|
server = app.listen(port);
|
|
79
|
+
// await sleep(99999999);
|
|
80
80
|
|
|
81
81
|
browser = await getBrowser();
|
|
82
82
|
const context = await browser.newContext();
|
|
83
83
|
page = await context.newPage();
|
|
84
84
|
await page.goto(`http://localhost:${port}`);
|
|
85
85
|
await page.getByRole("button", { name: "Wyślij" }).click();
|
|
86
|
-
console.log({ received_photo });
|
|
87
86
|
assert(received_photo !== undefined && (received_photo as any).old !== null);
|
|
88
87
|
});
|
|
89
|
-
});
|
|
88
|
+
}).timeout(99999999999);
|
|
90
89
|
});
|
|
@@ -22,7 +22,7 @@ export class Photo extends File {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
async renderFilePreview(
|
|
25
|
-
|
|
25
|
+
_ctx: Context,
|
|
26
26
|
file: FilePointer | null
|
|
27
27
|
): Promise<FlatTemplatable> {
|
|
28
28
|
const class_name = "file_preview";
|
|
@@ -48,15 +48,12 @@ export class Photo extends File {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
async getInputAttributes(fctx: FormControlContext) {
|
|
51
|
-
const original =
|
|
52
|
-
string,
|
|
53
|
-
string | boolean
|
|
54
|
-
>;
|
|
51
|
+
const original = await super.getInputAttributes(fctx);
|
|
55
52
|
return {
|
|
56
53
|
...original,
|
|
57
54
|
accept: "image/*",
|
|
58
55
|
onchange:
|
|
59
|
-
(original.onchange || "") +
|
|
56
|
+
((original.onchange as string) || "") +
|
|
60
57
|
";" +
|
|
61
58
|
`
|
|
62
59
|
const file = this.files[0];
|
|
@@ -91,7 +91,7 @@ export class SimpleInput<
|
|
|
91
91
|
!valid && raw
|
|
92
92
|
? raw.toString()
|
|
93
93
|
: parsed !== undefined && parsed !== null
|
|
94
|
-
? (
|
|
94
|
+
? (parsed as string)?.toString() || ""
|
|
95
95
|
: "",
|
|
96
96
|
],
|
|
97
97
|
...(fctx.form_id ? [["form", fctx.form_id]] : []),
|
|
@@ -100,7 +100,7 @@ export class SimpleInput<
|
|
|
100
100
|
...(required ? [["required", true]] : []),
|
|
101
101
|
...(!this.options.autocomplete ? [["autocomplete", "off"]] : []),
|
|
102
102
|
...(this.options.step ? [["step", this.options.step]] : []),
|
|
103
|
-
])
|
|
103
|
+
]) as Record<string, string>;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
async postInput(_: Context): Promise<FlatTemplatable> {
|
|
@@ -126,9 +126,7 @@ export class SimpleInput<
|
|
|
126
126
|
];
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
async render
|
|
130
|
-
fctx: FormControlContext
|
|
131
|
-
): Promise<FlatTemplatable> {
|
|
129
|
+
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
132
130
|
const id = this.getID();
|
|
133
131
|
const label = this.getLabel();
|
|
134
132
|
|
|
@@ -4,9 +4,7 @@ import { FormDataValue } from "../form-types.js";
|
|
|
4
4
|
import { FormControlContext } from "./form-control.js";
|
|
5
5
|
import { SimpleInput, SimpleInputOptions } from "./simple-input.js";
|
|
6
6
|
|
|
7
|
-
export class Textarea
|
|
8
|
-
string | null
|
|
9
|
-
> {
|
|
7
|
+
export class Textarea extends SimpleInput<string | null> {
|
|
10
8
|
constructor(
|
|
11
9
|
public field: FormField<boolean, string | null>,
|
|
12
10
|
public options: SimpleInputOptions & {
|
|
@@ -31,10 +29,7 @@ export class Textarea<Required extends boolean> extends SimpleInput<
|
|
|
31
29
|
async getInputAttributes(
|
|
32
30
|
fctx: FormControlContext
|
|
33
31
|
): Promise<Record<string, string | boolean>> {
|
|
34
|
-
const original =
|
|
35
|
-
string,
|
|
36
|
-
string | boolean
|
|
37
|
-
>;
|
|
32
|
+
const original = await super.getInputAttributes(fctx);
|
|
38
33
|
let onkeydown = original.onkeydown || "";
|
|
39
34
|
if (this.options.autogrow) {
|
|
40
35
|
onkeydown += `;this.style.height = '5px';this.style.height = Math.max((this.scrollHeight)+32, ${
|
|
@@ -55,6 +50,6 @@ export class Textarea<Required extends boolean> extends SimpleInput<
|
|
|
55
50
|
data: Record<string, FormDataValue>
|
|
56
51
|
) {
|
|
57
52
|
const { parsed: value } = await this.field.getValue(ctx, data);
|
|
58
|
-
return /* HTML */ `<textarea ${attributes}>${value}</textarea>`;
|
|
53
|
+
return /* HTML */ `<textarea ${attributes}>${value || ""}</textarea>`;
|
|
59
54
|
}
|
|
60
55
|
}
|
|
@@ -15,7 +15,7 @@ export type TickableOptions = {
|
|
|
15
15
|
readonly?: boolean;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
export abstract class Tickable<T
|
|
18
|
+
export abstract class Tickable<T> extends FormFieldControl {
|
|
19
19
|
constructor(
|
|
20
20
|
public field: FormField<boolean, T>,
|
|
21
21
|
public options: TickableOptions = {}
|
|
@@ -63,9 +63,7 @@ export abstract class Tickable<T extends unknown> extends FormFieldControl {
|
|
|
63
63
|
];
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
async render
|
|
67
|
-
fctx: FormControlContext
|
|
68
|
-
): Promise<FlatTemplatable> {
|
|
66
|
+
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
69
67
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
70
68
|
const { parsed, valid, message } = await this.field.getValue(
|
|
71
69
|
fctx.ctx,
|
|
@@ -7,6 +7,7 @@ export class ExistingSealiousValue<
|
|
|
7
7
|
constructor(required: Required, field: Field) {
|
|
8
8
|
super(required, async (ctx) => {
|
|
9
9
|
const { items } = await field.collection.list(ctx.$context).fetch();
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
10
11
|
return Object.fromEntries(
|
|
11
12
|
items.map((item) => {
|
|
12
13
|
const value = item.get(field.name);
|
|
@@ -49,7 +49,7 @@ export type FieldParseResult<T> =
|
|
|
49
49
|
|
|
50
50
|
export abstract class FormField<
|
|
51
51
|
Required extends boolean = boolean,
|
|
52
|
-
ParsedValue
|
|
52
|
+
ParsedValue = unknown
|
|
53
53
|
> {
|
|
54
54
|
name: string;
|
|
55
55
|
constructor(public readonly required: Required) {}
|
|
@@ -85,8 +85,8 @@ export abstract class FormField<
|
|
|
85
85
|
public abstract getEmptyValue(): ParsedValue;
|
|
86
86
|
|
|
87
87
|
public async isValueValid(
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
_ctx: Context,
|
|
89
|
+
_value: ParsedValue
|
|
90
90
|
): Promise<FormFieldValidationResponse> {
|
|
91
91
|
return { valid: true, message: "" };
|
|
92
92
|
}
|
|
@@ -128,12 +128,9 @@ export abstract class FormField<
|
|
|
128
128
|
message: parse_error || "Error",
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
|
-
const { valid, message } = await this._validate(
|
|
132
|
-
ctx,
|
|
133
|
-
parsed_value as ParsedValue
|
|
134
|
-
);
|
|
131
|
+
const { valid, message } = await this._validate(ctx, parsed_value);
|
|
135
132
|
return {
|
|
136
|
-
parsed: parsed_value
|
|
133
|
+
parsed: parsed_value,
|
|
137
134
|
valid,
|
|
138
135
|
message,
|
|
139
136
|
raw: all_form_values[this.name],
|
package/src/forms/fields/file.ts
CHANGED
|
@@ -21,7 +21,7 @@ export class File<Required extends boolean> extends FormField<
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
async parse(
|
|
24
|
-
|
|
24
|
+
_ctx: Context,
|
|
25
25
|
raw_value: FormDataValue
|
|
26
26
|
): Promise<FieldParseResult<FileContainer>> {
|
|
27
27
|
let result;
|
|
@@ -30,17 +30,23 @@ export class File<Required extends boolean> extends FormField<
|
|
|
30
30
|
result = {
|
|
31
31
|
parsed_value: { old: file, new: null },
|
|
32
32
|
error: null,
|
|
33
|
-
parsable: true as
|
|
33
|
+
parsable: true as const,
|
|
34
34
|
};
|
|
35
35
|
} else if (!is(raw_value, predicates.object)) {
|
|
36
36
|
result = {
|
|
37
37
|
parsed_value: null,
|
|
38
38
|
error: "Expected a field with old.id:string, old.filename:string and new?:File",
|
|
39
|
-
parsable: false as
|
|
39
|
+
parsable: false as const,
|
|
40
40
|
};
|
|
41
41
|
} else {
|
|
42
|
-
const old_file = hasFieldOfType(
|
|
43
|
-
|
|
42
|
+
const old_file = hasFieldOfType(
|
|
43
|
+
raw_value,
|
|
44
|
+
"old",
|
|
45
|
+
predicates.or(predicates.string, predicates.object)
|
|
46
|
+
)
|
|
47
|
+
? await this.file_manager.toPointer(
|
|
48
|
+
raw_value.old as string | FilePointer
|
|
49
|
+
)
|
|
44
50
|
: null;
|
|
45
51
|
const new_file =
|
|
46
52
|
hasFieldOfType(
|
|
@@ -51,11 +57,12 @@ export class File<Required extends boolean> extends FormField<
|
|
|
51
57
|
? raw_value.new[0]
|
|
52
58
|
: null;
|
|
53
59
|
result = {
|
|
54
|
-
parsable: true as
|
|
60
|
+
parsable: true as const,
|
|
55
61
|
error: null,
|
|
56
62
|
parsed_value: { old: old_file, new: new_file },
|
|
57
63
|
};
|
|
58
64
|
}
|
|
65
|
+
|
|
59
66
|
return result;
|
|
60
67
|
}
|
|
61
68
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Context } from "koa";
|
|
2
|
-
import { Field,
|
|
2
|
+
import { Field, FieldsetOutput, FieldTypes } from "sealious";
|
|
3
3
|
import { FormDataValue } from "../form-types.js";
|
|
4
4
|
import { FormField } from "./field.js";
|
|
5
5
|
|
|
@@ -13,7 +13,7 @@ export class StructuredArrayField<
|
|
|
13
13
|
super(true);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
async parse(
|
|
16
|
+
async parse(_context: Context, value: FormDataValue) {
|
|
17
17
|
return {
|
|
18
18
|
parsable: <const>true,
|
|
19
19
|
error: null,
|
package/src/forms/form.test.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import Router from "@koa/router";
|
|
2
|
-
import { describe, it, beforeAll, afterAll, afterEach, beforeEach } from "vitest";
|
|
3
2
|
import axios from "axios";
|
|
4
3
|
import Koa, { BaseContext } from "koa";
|
|
5
4
|
import { Page } from "playwright";
|
|
@@ -7,7 +6,7 @@ import { Controls, Fields, Form, Mountable } from "../index.js";
|
|
|
7
6
|
import { mount } from "../mount.js";
|
|
8
7
|
import { locator_is_visible } from "../test_utils/locator_is_visible.js";
|
|
9
8
|
import { getBrowser } from "../utils/browser-creator.js";
|
|
10
|
-
import { assertThrowsAsync
|
|
9
|
+
import { assertThrowsAsync } from "../utils/utils.js";
|
|
11
10
|
import { FormDataValue } from "./form-types.js";
|
|
12
11
|
import getPort from "get-port";
|
|
13
12
|
import { SimpleFormField } from "./fields/simple-form-field.js";
|
|
@@ -42,7 +41,7 @@ console.log("Using port " + port + " for form.test.ts");
|
|
|
42
41
|
describe("form test", () => {
|
|
43
42
|
let page: Page;
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
before(async () => {
|
|
46
45
|
const browser = await getBrowser();
|
|
47
46
|
const context = await browser.newContext();
|
|
48
47
|
page = await context.newPage();
|
|
@@ -51,7 +50,7 @@ describe("form test", () => {
|
|
|
51
50
|
describe("basic tests", async () => {
|
|
52
51
|
let server: ReturnType<Koa["listen"]>;
|
|
53
52
|
|
|
54
|
-
|
|
53
|
+
before(async () => {
|
|
55
54
|
const app = new Koa();
|
|
56
55
|
const router = new Router();
|
|
57
56
|
|
|
@@ -61,7 +60,7 @@ describe("form test", () => {
|
|
|
61
60
|
await page.goto(`http://localhost:${port}`);
|
|
62
61
|
});
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
after(async () => {
|
|
65
64
|
server.close();
|
|
66
65
|
});
|
|
67
66
|
|
|
@@ -131,7 +130,7 @@ describe("form test", () => {
|
|
|
131
130
|
const app = new Koa();
|
|
132
131
|
const router = new Router();
|
|
133
132
|
|
|
134
|
-
|
|
133
|
+
before(async () => {
|
|
135
134
|
mount(
|
|
136
135
|
router,
|
|
137
136
|
"/",
|
|
@@ -236,7 +235,7 @@ describe("form test", () => {
|
|
|
236
235
|
describe("validation message", async () => {
|
|
237
236
|
let server: ReturnType<Koa["listen"]>;
|
|
238
237
|
|
|
239
|
-
|
|
238
|
+
before(async () => {
|
|
240
239
|
const app = new Koa();
|
|
241
240
|
const router = new Router();
|
|
242
241
|
|
|
@@ -277,7 +276,7 @@ describe("form test", () => {
|
|
|
277
276
|
await page.goto(`http://localhost:${port}`);
|
|
278
277
|
});
|
|
279
278
|
|
|
280
|
-
|
|
279
|
+
after(async () => {
|
|
281
280
|
server.close();
|
|
282
281
|
});
|
|
283
282
|
|
|
@@ -302,7 +301,7 @@ describe("form test", () => {
|
|
|
302
301
|
describe("field specific validation message", async () => {
|
|
303
302
|
let server: ReturnType<Koa["listen"]>;
|
|
304
303
|
|
|
305
|
-
|
|
304
|
+
before(async () => {
|
|
306
305
|
const app = new Koa();
|
|
307
306
|
const router = new Router();
|
|
308
307
|
const fields = {
|
|
@@ -334,7 +333,7 @@ describe("form test", () => {
|
|
|
334
333
|
await page.goto(`http://localhost:${port}`);
|
|
335
334
|
});
|
|
336
335
|
|
|
337
|
-
|
|
336
|
+
after(async () => {
|
|
338
337
|
server.close();
|
|
339
338
|
});
|
|
340
339
|
|