@sealcode/sealgen 0.10.6 → 0.11.1
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/add-jdd-component.d.ts +1 -0
- package/@types/forms/controls/array.d.ts +1 -1
- package/@types/forms/multiform.d.ts +1 -1
- package/@types/generate-components.d.ts +1 -0
- package/@types/templates/jdd-component.d.ts +1 -0
- package/@types/templates/templates.d.ts +2 -0
- package/lib/add-jdd-component.js +34 -0
- package/lib/add-route.js +4 -1
- package/lib/add-route.test.js +5 -2
- package/lib/build.js +15 -5
- package/lib/cli.js +4 -0
- package/lib/forms/multiform.test.js +2 -2
- package/lib/generate-components.js +63 -0
- package/lib/generate-routes.js +1 -1
- package/lib/templates/jdd-component.js +43 -0
- package/lib/templates/list.js +18 -20
- package/lib/templates/long-running-process.js +30 -26
- package/lib/templates/page.js +2 -2
- package/lib/templates/route-test.js +3 -2
- package/lib/templates/stateful-page.js +21 -17
- package/lib/templates/templates.js +2 -0
- package/lib/utils/import-path.js +1 -1
- package/package.json +5 -2
- package/src/add-jdd-component.ts +43 -0
- package/src/add-route.test.ts +6 -2
- package/src/add-route.ts +4 -1
- package/src/build.ts +15 -5
- package/src/cli.ts +4 -0
- package/src/forms/multiform.test.ts +2 -2
- package/src/generate-components.ts +46 -0
- package/src/generate-routes.ts +4 -1
- package/src/templates/jdd-component.ts +41 -0
- package/src/templates/list.ts +18 -20
- package/src/templates/long-running-process.ts +30 -26
- package/src/templates/page.ts +2 -2
- package/src/templates/route-test.ts +3 -2
- package/src/templates/stateful-page.ts +21 -17
- package/src/templates/templates.ts +2 -0
- package/src/utils/import-path.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sealcode/sealgen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Module to automate adding routes and collections to a sealious application",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"@types/node": "^18.11.4",
|
|
27
27
|
"@types/prettier": "^2.7.0",
|
|
28
28
|
"@types/prompts": "^2.0.14",
|
|
29
|
+
"@types/recursive-readdir": "^2.2.4",
|
|
29
30
|
"@typescript-eslint/eslint-plugin": "^4.29.3",
|
|
30
31
|
"@typescript-eslint/parser": "^4.29.3",
|
|
31
32
|
"eslint": "^7.32.0",
|
|
@@ -50,12 +51,14 @@
|
|
|
50
51
|
"deepmerge": "^4.3.1",
|
|
51
52
|
"esbuild": "^0.15.5",
|
|
52
53
|
"esbuild-sass-plugin": "^2.3.1",
|
|
54
|
+
"js-convert-case": "^4.2.0",
|
|
53
55
|
"koa": "^2.13.0",
|
|
54
56
|
"locreq": "^2.0.2",
|
|
55
57
|
"merge": "^2.1.1",
|
|
56
58
|
"prettier": "^2.7.1",
|
|
57
59
|
"prompts": "^2.4.2",
|
|
58
|
-
"
|
|
60
|
+
"recursive-readdir": "^2.2.3",
|
|
61
|
+
"tempstream": "^0.3.0",
|
|
59
62
|
"tiny-glob": "^0.2.9",
|
|
60
63
|
"yargs": "^17.6.2"
|
|
61
64
|
},
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
2
|
+
import _locreq from "locreq";
|
|
3
|
+
import { promises as fs, existsSync } from "fs";
|
|
4
|
+
import { question } from "./utils/question";
|
|
5
|
+
const target_locreq = _locreq(process.cwd());
|
|
6
|
+
import { jddComponentTemplate } from "./templates/jdd-component";
|
|
7
|
+
import { generateComponents } from "./generate-components";
|
|
8
|
+
import { toKebabCase } from "js-convert-case";
|
|
9
|
+
|
|
10
|
+
export async function addJDDComponent(): Promise<void> {
|
|
11
|
+
const component_name = await question(
|
|
12
|
+
"What's the name of the component? > ",
|
|
13
|
+
(s: string) => s.length > 3
|
|
14
|
+
);
|
|
15
|
+
const file_path = target_locreq.resolve(
|
|
16
|
+
`src/back/jdd-components/${toKebabCase(component_name)}/${toKebabCase(
|
|
17
|
+
component_name
|
|
18
|
+
)}.jdd.tsx`
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
if (existsSync(file_path)) {
|
|
22
|
+
// eslint-disable-next-line no-console
|
|
23
|
+
console.error(`ERROR: File ${file_path} already exists.`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
await fs.mkdir(resolve(file_path, "../"), { recursive: true });
|
|
27
|
+
await fs.writeFile(file_path, jddComponentTemplate(component_name));
|
|
28
|
+
|
|
29
|
+
const css_file_path = target_locreq.resolve(
|
|
30
|
+
`src/back/jdd-components/${toKebabCase(component_name)}/${toKebabCase(
|
|
31
|
+
component_name
|
|
32
|
+
)}.scss`
|
|
33
|
+
);
|
|
34
|
+
await fs.writeFile(
|
|
35
|
+
css_file_path,
|
|
36
|
+
`.${toKebabCase(component_name)} {
|
|
37
|
+
}`
|
|
38
|
+
);
|
|
39
|
+
// eslint-disable-next-line no-console
|
|
40
|
+
console.log(`Created ${file_path}`);
|
|
41
|
+
console.log(`Created ${css_file_path}`);
|
|
42
|
+
await generateComponents();
|
|
43
|
+
}
|
package/src/add-route.test.ts
CHANGED
|
@@ -4,9 +4,13 @@ import { promisify } from "util";
|
|
|
4
4
|
import axios from "axios";
|
|
5
5
|
import waitPort from "wait-port";
|
|
6
6
|
import getPort from "get-port";
|
|
7
|
+
import _locreq from "locreq";
|
|
8
|
+
const target_locreq = _locreq(__dirname);
|
|
7
9
|
|
|
8
10
|
const execAsync = promisify(exec);
|
|
9
11
|
|
|
12
|
+
const callSealgenBin = () => `node ${target_locreq.resolve("lib/cli.js")}`;
|
|
13
|
+
|
|
10
14
|
describe("add route test", () => {
|
|
11
15
|
let node_pid = 0;
|
|
12
16
|
const app_path = "/tmp/sealious-minimal";
|
|
@@ -27,7 +31,7 @@ describe("add route test", () => {
|
|
|
27
31
|
this.timeout(250000);
|
|
28
32
|
console.log("\tcloning sealious-minimal...");
|
|
29
33
|
await execAsync(
|
|
30
|
-
`git clone https://hub.sealcode.org/source/sealious-minimal.git ${app_path} && cd ${app_path} && git checkout
|
|
34
|
+
`git clone https://hub.sealcode.org/source/sealious-minimal.git ${app_path} && cd ${app_path} && git checkout d5abeb9514359dde4`
|
|
31
35
|
);
|
|
32
36
|
console.log("\tinstalling dependencies and sealgen...");
|
|
33
37
|
await execAsync(
|
|
@@ -35,7 +39,7 @@ describe("add route test", () => {
|
|
|
35
39
|
);
|
|
36
40
|
console.log("\trunning add-route and building app...");
|
|
37
41
|
await execAsync(
|
|
38
|
-
`cd ${app_path} &&
|
|
42
|
+
`cd ${app_path} && ${callSealgenBin()} add-route --url=/sample --action=Sample --mode=page && ${callSealgenBin()} build`
|
|
39
43
|
);
|
|
40
44
|
console.log(
|
|
41
45
|
"\tstarting the database...(if timeouts here, run 'docker pull mongo:4.4-bionic' to solve)"
|
package/src/add-route.ts
CHANGED
|
@@ -47,9 +47,12 @@ export async function addRoute(
|
|
|
47
47
|
]);
|
|
48
48
|
|
|
49
49
|
const { action, url, mode } = response as Record<string, string>;
|
|
50
|
+
const extension = ["list", "lpr", "page", "sreact"].includes(mode)
|
|
51
|
+
? "tsx"
|
|
52
|
+
: "ts";
|
|
50
53
|
|
|
51
54
|
const file_path = target_locreq.resolve(
|
|
52
|
-
`src/back/routes/${escape_url_params(url)}.${mode}
|
|
55
|
+
`src/back/routes/${escape_url_params(url)}.${mode}.${extension}`
|
|
53
56
|
);
|
|
54
57
|
const test_file_path = target_locreq.resolve(
|
|
55
58
|
`src/back/routes/${escape_url_params(url)}.test.ts`
|
package/src/build.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { build, BuildResult } from "esbuild";
|
|
2
2
|
import { promises as fs } from "fs";
|
|
3
|
+
import { extname } from "path";
|
|
3
4
|
import { sassPlugin } from "esbuild-sass-plugin";
|
|
4
5
|
import * as chokidar from "chokidar";
|
|
5
6
|
import { default as glob } from "tiny-glob";
|
|
@@ -9,23 +10,25 @@ import { generateCollections } from "./generate-collections";
|
|
|
9
10
|
import { generateRoutes } from "./generate-routes";
|
|
10
11
|
|
|
11
12
|
const generate_names = (function* generate_names() {
|
|
12
|
-
|
|
13
|
+
const base_name = "____unique_import_";
|
|
13
14
|
let count = 0;
|
|
14
15
|
while (true) {
|
|
15
|
-
yield base_name
|
|
16
|
+
yield `${base_name}${count}`;
|
|
16
17
|
count++;
|
|
17
18
|
}
|
|
18
19
|
})();
|
|
19
20
|
|
|
20
21
|
async function build_ts() {
|
|
21
22
|
await Promise.all([generateCollections(), generateRoutes()]);
|
|
22
|
-
const entryPoints = (await glob("./src/back/**/*.ts")).filter(
|
|
23
|
+
const entryPoints = (await glob("./src/back/**/*.{ts,tsx}")).filter(
|
|
23
24
|
(path) => !path.includes(".#")
|
|
24
25
|
);
|
|
25
26
|
try {
|
|
26
27
|
await build({
|
|
27
28
|
entryPoints,
|
|
28
29
|
sourcemap: true,
|
|
30
|
+
bundle: false,
|
|
31
|
+
jsxFactory: "TempstreamJSX.createElement",
|
|
29
32
|
outdir: "./dist/back",
|
|
30
33
|
logLevel: "info",
|
|
31
34
|
platform: "node",
|
|
@@ -52,6 +55,7 @@ async function build_ts() {
|
|
|
52
55
|
all_named,
|
|
53
56
|
module_path
|
|
54
57
|
) => {
|
|
58
|
+
/* eslint-disable */
|
|
55
59
|
const new_name =
|
|
56
60
|
generate_names.next().value;
|
|
57
61
|
const result =
|
|
@@ -92,15 +96,20 @@ async function build_ts() {
|
|
|
92
96
|
})
|
|
93
97
|
.join(" ");
|
|
94
98
|
return result;
|
|
99
|
+
/* eslint-enable */
|
|
95
100
|
}
|
|
96
101
|
);
|
|
97
|
-
return {
|
|
102
|
+
return {
|
|
103
|
+
contents,
|
|
104
|
+
loader: extname(path) === ".tsx" ? "tsx" : "ts",
|
|
105
|
+
};
|
|
98
106
|
});
|
|
99
107
|
},
|
|
100
108
|
},
|
|
101
109
|
],
|
|
102
110
|
});
|
|
103
111
|
} catch (e) {
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
104
113
|
console.error(e.message);
|
|
105
114
|
}
|
|
106
115
|
}
|
|
@@ -119,6 +128,7 @@ async function complex_build(watch: boolean): Promise<void> {
|
|
|
119
128
|
await scss_build?.rebuild?.();
|
|
120
129
|
console.log(`Built main.scss [on ${path}]`);
|
|
121
130
|
} catch (e) {
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
122
132
|
console.error(e.message);
|
|
123
133
|
await sleep(200);
|
|
124
134
|
scss_build
|
|
@@ -128,7 +138,7 @@ async function complex_build(watch: boolean): Promise<void> {
|
|
|
128
138
|
}
|
|
129
139
|
}
|
|
130
140
|
if (
|
|
131
|
-
path.endsWith(".ts") &&
|
|
141
|
+
(path.endsWith(".ts") || path.endsWith(".tsx")) &&
|
|
132
142
|
!path.endsWith("src/back/collections/collections.ts") &&
|
|
133
143
|
!path.endsWith("src/back/routes/routes.ts") &&
|
|
134
144
|
!path.endsWith("src/back/routes/urls.ts")
|
package/src/cli.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { addCollection } from "./add-collection";
|
|
3
|
+
import { addJDDComponent } from "./add-jdd-component";
|
|
3
4
|
import { addRoute } from "./add-route";
|
|
4
5
|
import { buildProject } from "./build";
|
|
5
6
|
import { generateScssIncludes } from "./find-scss-includes";
|
|
6
7
|
import { generateCollections } from "./generate-collections";
|
|
8
|
+
import { generateComponents } from "./generate-components";
|
|
7
9
|
import { generateRoutes } from "./generate-routes";
|
|
8
10
|
import { makeEnv } from "./make-env";
|
|
9
11
|
|
|
@@ -14,6 +16,7 @@ const actions: Record<
|
|
|
14
16
|
"add-collection": addCollection,
|
|
15
17
|
"add-route": addRoute,
|
|
16
18
|
"generate-collections": generateCollections,
|
|
19
|
+
"generate-components": generateComponents,
|
|
17
20
|
"generate-routes": generateRoutes,
|
|
18
21
|
"generate-scss-includes": generateScssIncludes,
|
|
19
22
|
build: buildProject,
|
|
@@ -26,6 +29,7 @@ const actions: Record<
|
|
|
26
29
|
);
|
|
27
30
|
},
|
|
28
31
|
"make-env": makeEnv,
|
|
32
|
+
"add-component": addJDDComponent
|
|
29
33
|
};
|
|
30
34
|
|
|
31
35
|
void (async function () {
|
|
@@ -109,8 +109,8 @@ async function general_form_validation_e2e_tests(js_enabled: boolean) {
|
|
|
109
109
|
await page.getByPlaceholder("password").click();
|
|
110
110
|
await page.getByPlaceholder("password").fill("test");
|
|
111
111
|
await page.locator("#multiform_test_form2_submit").click();
|
|
112
|
-
assertThrowsAsync(async () => {
|
|
113
|
-
page.getByText("Incorrect input").click({ timeout: 500 });
|
|
112
|
+
await assertThrowsAsync(async () => {
|
|
113
|
+
await page.getByText("Incorrect input").click({ timeout: 500 });
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import _locreq from "locreq";
|
|
2
|
+
import * as prettier from "prettier";
|
|
3
|
+
import { promises as fs } from "fs";
|
|
4
|
+
import { assertType, predicates } from "@sealcode/ts-predicates";
|
|
5
|
+
import { getPrettierConfig } from "./utils/prettier";
|
|
6
|
+
import recursive from "recursive-readdir";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { toKebabCase, toPascalCase } from "js-convert-case";
|
|
9
|
+
|
|
10
|
+
const target_locreq = _locreq(process.cwd());
|
|
11
|
+
|
|
12
|
+
export async function generateComponents(): Promise<void> {
|
|
13
|
+
const components_dir = target_locreq.resolve("src/back/jdd-components");
|
|
14
|
+
const component_names = (await recursive(components_dir)).filter((c) =>
|
|
15
|
+
c.endsWith(".jdd.tsx")
|
|
16
|
+
);
|
|
17
|
+
const component_data = component_names
|
|
18
|
+
.map(
|
|
19
|
+
(p) =>
|
|
20
|
+
"./" +
|
|
21
|
+
path.relative(components_dir, p).replace(/\.[tj]sx?$/, ".js")
|
|
22
|
+
)
|
|
23
|
+
.map((relative_path) => {
|
|
24
|
+
const name = relative_path.match(/\/([^\/]+).jdd/)?.[1];
|
|
25
|
+
return { name, relative_path };
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const content = `// DO NOT EDIT! This file is generated automaticaly with 'npm run generate-components'
|
|
29
|
+
import { Registry } from "@sealcode/jdd";
|
|
30
|
+
|
|
31
|
+
export const registry = new Registry();
|
|
32
|
+
${component_data
|
|
33
|
+
.map(
|
|
34
|
+
(c) => `
|
|
35
|
+
import { ${toPascalCase(c.name)} } from "${c.relative_path}";
|
|
36
|
+
registry.add("${toKebabCase(c.name)}", ${toPascalCase(c.name)});`
|
|
37
|
+
)
|
|
38
|
+
.join("\n")}`;
|
|
39
|
+
const target = "src/back/jdd-components/components.ts";
|
|
40
|
+
await fs.writeFile(
|
|
41
|
+
target_locreq.resolve(target),
|
|
42
|
+
prettier.format(content, await getPrettierConfig())
|
|
43
|
+
);
|
|
44
|
+
// eslint-disable-next-line no-console
|
|
45
|
+
console.log(`Successfuly generated new ${target} file`);
|
|
46
|
+
}
|
package/src/generate-routes.ts
CHANGED
|
@@ -51,7 +51,10 @@ export async function generateRoutes(): Promise<void> {
|
|
|
51
51
|
await walkDir(target_locreq.resolve("src/back/routes"))
|
|
52
52
|
)
|
|
53
53
|
.filter((f) =>
|
|
54
|
-
Object.keys(Templates).some(
|
|
54
|
+
Object.keys(Templates).some(
|
|
55
|
+
(key) =>
|
|
56
|
+
f.endsWith(`.${key}.ts`) || f.endsWith(`.${key}.tsx`)
|
|
57
|
+
)
|
|
55
58
|
)
|
|
56
59
|
.map(async (fullpath) => ({
|
|
57
60
|
fullpath,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { toKebabCase, toPascalCase } from "js-convert-case";
|
|
2
|
+
|
|
3
|
+
export function jddComponentTemplate(component_name: string) {
|
|
4
|
+
return `import { FlatTemplatable, TempstreamJSX } from "tempstream";
|
|
5
|
+
import {
|
|
6
|
+
Component,
|
|
7
|
+
ComponentArguments,
|
|
8
|
+
ExtractStructuredComponentArgumentsValues,
|
|
9
|
+
JDDContext,
|
|
10
|
+
} from "@sealcode/jdd";
|
|
11
|
+
|
|
12
|
+
const component_arguments = {
|
|
13
|
+
title: new ComponentArguments.ShortText(),
|
|
14
|
+
content: new ComponentArguments.Markdown(),
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
export class ${toPascalCase(
|
|
18
|
+
component_name
|
|
19
|
+
)} extends Component<typeof component_arguments> {
|
|
20
|
+
getArguments() {
|
|
21
|
+
return component_arguments;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
toHTML(
|
|
25
|
+
{
|
|
26
|
+
title,
|
|
27
|
+
content,
|
|
28
|
+
}: ExtractStructuredComponentArgumentsValues<typeof component_arguments>,
|
|
29
|
+
{ render_markdown }: JDDContext
|
|
30
|
+
): FlatTemplatable {
|
|
31
|
+
return (
|
|
32
|
+
<div class="${toKebabCase(component_name)}">
|
|
33
|
+
<h2>{title} • ${toPascalCase(component_name)} </h2>
|
|
34
|
+
<div>{render_markdown(content)}</div>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
`;
|
|
41
|
+
}
|
package/src/templates/list.ts
CHANGED
|
@@ -33,8 +33,8 @@ export const listTemplate = async (
|
|
|
33
33
|
]);
|
|
34
34
|
const rel = curryImportPath(newfilefullpath);
|
|
35
35
|
return `import { Context } from "koa";
|
|
36
|
-
import { CollectionItem
|
|
37
|
-
import { FlatTemplatable,
|
|
36
|
+
import { CollectionItem } from "sealious";
|
|
37
|
+
import { FlatTemplatable, TempstreamJSX } from "tempstream";
|
|
38
38
|
import { ${uppercase_collection} } from "${rel(
|
|
39
39
|
"src/back/collections/collections.js"
|
|
40
40
|
)}";
|
|
@@ -62,7 +62,7 @@ ${collection_fields
|
|
|
62
62
|
)
|
|
63
63
|
.join(",\n")}
|
|
64
64
|
] as {
|
|
65
|
-
field: keyof (typeof
|
|
65
|
+
field: keyof (typeof ${uppercase_collection})["fields"];
|
|
66
66
|
render?: ListFilterRender;
|
|
67
67
|
}[];
|
|
68
68
|
|
|
@@ -102,18 +102,18 @@ export default new (class ${action_name}Page extends SealiousItemListPage<
|
|
|
102
102
|
const query_params = qs.parse(ctx.search.slice(1));
|
|
103
103
|
query_params.page = "1";
|
|
104
104
|
const filter_values = await this.getFilterValues(ctx);
|
|
105
|
-
return
|
|
106
|
-
|
|
105
|
+
return <form>
|
|
106
|
+
{Object.entries(query_params).map(([key, value]) => {
|
|
107
107
|
if (key == "filter") {
|
|
108
108
|
return "";
|
|
109
109
|
}
|
|
110
|
-
return
|
|
110
|
+
return <input
|
|
111
111
|
type="hidden"
|
|
112
112
|
name="\${key}"
|
|
113
113
|
value="\${value}"
|
|
114
|
-
|
|
114
|
+
/>;
|
|
115
115
|
})}
|
|
116
|
-
|
|
116
|
+
{filterFields.map(({ field, render }) => {
|
|
117
117
|
if (!render) {
|
|
118
118
|
render = DefaultListFilters.fallback;
|
|
119
119
|
}
|
|
@@ -124,31 +124,29 @@ export default new (class ${action_name}Page extends SealiousItemListPage<
|
|
|
124
124
|
);
|
|
125
125
|
})}
|
|
126
126
|
<input type="submit" />
|
|
127
|
-
</form
|
|
127
|
+
</form>;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
async renderItem(_: Context, item: CollectionItem<typeof ${uppercase_collection}>) {
|
|
131
|
-
return
|
|
132
|
-
|
|
131
|
+
return <tr>
|
|
132
|
+
{displayFields.map(({ field, format }) => {
|
|
133
133
|
const value = item.get(field as any);
|
|
134
|
-
return
|
|
134
|
+
return <td>{format ? format(value) : value}</td>;
|
|
135
135
|
})}
|
|
136
|
-
</tr
|
|
136
|
+
</tr>;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
async render(ctx: Context) {
|
|
140
140
|
return html(
|
|
141
141
|
ctx,
|
|
142
142
|
"${action_name}",
|
|
143
|
-
|
|
144
|
-
<h2>${action_name}</h2>
|
|
143
|
+
<div>
|
|
144
|
+
<h2>${action_name} List</h2>
|
|
145
145
|
<table class="sealious-list">
|
|
146
|
-
|
|
147
|
-
<tbody>
|
|
148
|
-
\${super.render(ctx)}
|
|
149
|
-
</tbody>
|
|
146
|
+
{this.renderTableHead(ctx, displayFields)}
|
|
147
|
+
<tbody>{super.render(ctx)}</tbody>
|
|
150
148
|
</table>
|
|
151
|
-
</div
|
|
149
|
+
</div>
|
|
152
150
|
);
|
|
153
151
|
}
|
|
154
152
|
|
|
@@ -6,7 +6,7 @@ export async function LongRunningProcessTemplate(
|
|
|
6
6
|
): Promise<string> {
|
|
7
7
|
const rel = curryImportPath(newfilefullpath);
|
|
8
8
|
return `import { Context } from "koa";
|
|
9
|
-
import {
|
|
9
|
+
import { TempstreamJSX } from "tempstream";
|
|
10
10
|
import { Page } from "@sealcode/sealgen";
|
|
11
11
|
import html from "${rel("src/back/html.js")}";
|
|
12
12
|
import { LongRunningProcess } from "sealious";
|
|
@@ -24,34 +24,38 @@ export default new (class PatroniteAutoImportStatusPage extends Page {
|
|
|
24
24
|
async render(ctx: Context) {
|
|
25
25
|
const lpr_id = ctx.params.id;
|
|
26
26
|
const lpr_data = LongRunningProcess.getByID(ctx.$context, lpr_id);
|
|
27
|
+
const render_script = lpr_data.state !== "error" && lpr_data.state !== "finished";
|
|
28
|
+
const script = /* HTML */ \`<script>
|
|
29
|
+
setTimeout(() => {
|
|
30
|
+
document.location = document.location;
|
|
31
|
+
}, \${this.interval});
|
|
32
|
+
</script>\`;
|
|
33
|
+
|
|
27
34
|
return html(
|
|
28
35
|
ctx,
|
|
29
36
|
"PatroniteAutoImportStatus",
|
|
30
|
-
|
|
31
|
-
(lpr_data) =>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
style="height:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
: ""}
|
|
53
|
-
\`
|
|
54
|
-
)}\`
|
|
37
|
+
<div>
|
|
38
|
+
{lpr_data.then((lpr_data) => {
|
|
39
|
+
return (
|
|
40
|
+
<div>
|
|
41
|
+
<div>status: {lpr_data.state}</div>
|
|
42
|
+
<div style="height: 20px; width: 100%">
|
|
43
|
+
<div
|
|
44
|
+
style="height: 100%; background-color: green; width: {Math.round(
|
|
45
|
+
lpr_data.progress * 100
|
|
46
|
+
)}%"
|
|
47
|
+
></div>
|
|
48
|
+
</div>
|
|
49
|
+
<div>
|
|
50
|
+
{lpr_data.events.map((e) => (
|
|
51
|
+
<div>{e.message}</div>
|
|
52
|
+
))}
|
|
53
|
+
</div>
|
|
54
|
+
{render_script ? { script } : ""}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
})}
|
|
58
|
+
</div>
|
|
55
59
|
);
|
|
56
60
|
}
|
|
57
61
|
})();
|
package/src/templates/page.ts
CHANGED
|
@@ -5,7 +5,7 @@ export async function pageTemplate(
|
|
|
5
5
|
): Promise<string> {
|
|
6
6
|
const rel = curryImportPath(newfilefullpath);
|
|
7
7
|
return `import { Context } from "koa";
|
|
8
|
-
import {
|
|
8
|
+
import { TempstreamJSX } from "tempstream";
|
|
9
9
|
import { Page } from "@sealcode/sealgen";
|
|
10
10
|
import html from "${rel("src/back/html.js")}";
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ export default new (class ${action_name}Page extends Page {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
async render(ctx: Context) {
|
|
21
|
-
return html(ctx, "${action_name}",
|
|
21
|
+
return html(ctx, "${action_name}", <div></div>);
|
|
22
22
|
}
|
|
23
23
|
})();
|
|
24
24
|
`;
|
|
@@ -5,11 +5,12 @@ export function testTemplate(action_name: string, new_file_fullpath: string) {
|
|
|
5
5
|
return `import { withProdApp } from "${rel(
|
|
6
6
|
"src/back/test_utils/with-prod-app.js"
|
|
7
7
|
)}";
|
|
8
|
-
import {
|
|
8
|
+
import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "${rel(
|
|
9
9
|
"src/back/test_utils/webhint.js"
|
|
10
10
|
)}";
|
|
11
11
|
import { ${action_name}URL } from "${rel("src/back/routes/urls.js")}";
|
|
12
|
-
import { getBrowser } from "${rel("src/test_utils/browser-creator.js")}";
|
|
12
|
+
import { getBrowser } from "${rel("src/back/test_utils/browser-creator.js")}";
|
|
13
|
+
import { Browser, BrowserContext, Page } from "@playwright/test";
|
|
13
14
|
|
|
14
15
|
describe("${action_name} webhint", () => {
|
|
15
16
|
it(
|
|
@@ -5,14 +5,14 @@ export async function statefulPageTemplate(
|
|
|
5
5
|
newfilefullpath: string
|
|
6
6
|
): Promise<string> {
|
|
7
7
|
const rel = curryImportPath(newfilefullpath);
|
|
8
|
-
return `import {
|
|
9
|
-
import {
|
|
8
|
+
return `import { TempstreamJSX, Templatable } from "tempstream";
|
|
9
|
+
import { BaseContext } from "koa";
|
|
10
10
|
import { StatefulPage } from "@sealcode/sealgen";
|
|
11
11
|
import html from "${rel("src/back/html.js")}";
|
|
12
12
|
|
|
13
13
|
export const actionName = "${action_name}";
|
|
14
14
|
|
|
15
|
-
const actions =
|
|
15
|
+
const actions = {
|
|
16
16
|
add: (state: State, inputs: Record<string, string>) => {
|
|
17
17
|
console.log({ inputs });
|
|
18
18
|
return {
|
|
@@ -26,39 +26,43 @@ const actions = <const>{
|
|
|
26
26
|
elements: state.elements.filter((_, index) => index != index_to_remove),
|
|
27
27
|
};
|
|
28
28
|
},
|
|
29
|
-
};
|
|
29
|
+
} as const;
|
|
30
30
|
|
|
31
31
|
type State = {
|
|
32
32
|
elements: string[];
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
export default new (class ${action_name}Page extends StatefulPage<State, typeof actions> {
|
|
36
36
|
actions = actions;
|
|
37
37
|
|
|
38
38
|
getInitialState() {
|
|
39
39
|
return { elements: ["one", "two", "three"] };
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
wrapInLayout(ctx: BaseContext, content: Templatable): Templatable {
|
|
43
43
|
return html(ctx, "${action_name}", content);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
render(ctx: BaseContext, state: State, inputs: Record<string, string>) {
|
|
47
|
-
return
|
|
48
|
-
\${state.elements.map(
|
|
49
|
-
(e, index) => /* HTML */ \`<li>
|
|
50
|
-
\${e} \${this.makeActionButton(state, "remove", index)}
|
|
51
|
-
</li>\`
|
|
52
|
-
)}
|
|
53
|
-
</ul>
|
|
47
|
+
return (
|
|
54
48
|
<div>
|
|
55
|
-
<
|
|
49
|
+
<ul>
|
|
50
|
+
{state.elements.map((e, index) => (
|
|
51
|
+
<li>
|
|
52
|
+
{e} {this.makeActionButton(state, "remove", index)}
|
|
53
|
+
</li>
|
|
54
|
+
))}
|
|
55
|
+
</ul>
|
|
56
|
+
<div>
|
|
57
|
+
<input
|
|
56
58
|
name="element_to_add"
|
|
57
59
|
type="text"
|
|
58
|
-
value=
|
|
60
|
+
value={inputs.element_to_add || ""}
|
|
59
61
|
/>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
{this.makeActionButton(state, "add")}
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
62
66
|
}
|
|
63
67
|
})();
|
|
64
68
|
`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formTemplate } from "./form";
|
|
2
|
+
import { jddComponentTemplate } from "./jdd-component";
|
|
2
3
|
import { listTemplate } from "./list";
|
|
3
4
|
import { LongRunningProcessTemplate } from "./long-running-process";
|
|
4
5
|
import { multiformTemplate } from "./multiform";
|
|
@@ -16,4 +17,5 @@ export const Templates = {
|
|
|
16
17
|
post: postTemplate,
|
|
17
18
|
sreact: statefulPageTemplate,
|
|
18
19
|
lpr: LongRunningProcessTemplate,
|
|
20
|
+
jdd: jddComponentTemplate,
|
|
19
21
|
};
|
package/src/utils/import-path.ts
CHANGED
|
@@ -8,7 +8,7 @@ export function importPath(
|
|
|
8
8
|
): string {
|
|
9
9
|
let result = relative(
|
|
10
10
|
dirname(target_locreq.resolve(project_module_path)),
|
|
11
|
-
target_locreq.resolve(project_target_path).replace(/.
|
|
11
|
+
target_locreq.resolve(project_target_path).replace(/.tsx?$/, ".js")
|
|
12
12
|
);
|
|
13
13
|
if (result[0] != ".") {
|
|
14
14
|
result = "./" + result;
|