@akanjs/cli 0.0.135 → 0.0.137
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/cjs/index.js +1009 -1248
- package/esm/index.js +1009 -1248
- package/package.json +1 -1
- package/src/module/module.command.d.ts +1 -0
- package/src/module/module.prompt.d.ts +19 -2
- package/src/module/module.runner.d.ts +6 -0
- package/src/module/module.script.d.ts +1 -0
package/cjs/index.js
CHANGED
|
@@ -459,6 +459,11 @@ var Logger = class _Logger {
|
|
|
459
459
|
}
|
|
460
460
|
};
|
|
461
461
|
|
|
462
|
+
// pkgs/@akanjs/common/lowerlize.ts
|
|
463
|
+
var lowerlize = (str) => {
|
|
464
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
465
|
+
};
|
|
466
|
+
|
|
462
467
|
// pkgs/@akanjs/common/sleep.ts
|
|
463
468
|
var sleep = async (ms) => {
|
|
464
469
|
return new Promise((resolve) => {
|
|
@@ -1071,7 +1076,7 @@ var Executor = class {
|
|
|
1071
1076
|
`${dirname}/${filename}`
|
|
1072
1077
|
);
|
|
1073
1078
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
1074
|
-
this.writeFile(convertedTargetPath, content);
|
|
1079
|
+
this.writeFile(convertedTargetPath, content, { overwrite });
|
|
1075
1080
|
} else if (targetPath.endsWith(".template")) {
|
|
1076
1081
|
const content = await import_promises.default.readFile(templatePath, "utf8");
|
|
1077
1082
|
const convertedTargetPath = Object.entries(dict).reduce(
|
|
@@ -1083,7 +1088,7 @@ var Executor = class {
|
|
|
1083
1088
|
content
|
|
1084
1089
|
);
|
|
1085
1090
|
this.logger.verbose(`Apply template ${templatePath} to ${convertedTargetPath}`);
|
|
1086
|
-
this.writeFile(convertedTargetPath, convertedContent);
|
|
1091
|
+
this.writeFile(convertedTargetPath, convertedContent, { overwrite });
|
|
1087
1092
|
}
|
|
1088
1093
|
}
|
|
1089
1094
|
async applyTemplate({
|
|
@@ -2108,6 +2113,9 @@ var getArgumentValue = async (argMeta, value, workspace) => {
|
|
|
2108
2113
|
throw new Error(`Invalid system type: ${argMeta.type}`);
|
|
2109
2114
|
};
|
|
2110
2115
|
var runCommands = async (...commands) => {
|
|
2116
|
+
process.on("unhandledRejection", (error) => {
|
|
2117
|
+
console.error(import_chalk2.default.red("[fatal]"), error);
|
|
2118
|
+
});
|
|
2111
2119
|
const hasPackageJson = import_fs7.default.existsSync(`${__dirname}/../package.json`);
|
|
2112
2120
|
const version = hasPackageJson ? JSON.parse(import_fs7.default.readFileSync(`${__dirname}/../package.json`, "utf8")).version : "0.0.1";
|
|
2113
2121
|
import_commander.program.version(version).description("Akan CLI");
|
|
@@ -2166,6 +2174,7 @@ var runCommands = async (...commands) => {
|
|
|
2166
2174
|
|
|
2167
2175
|
// pkgs/@akanjs/devkit/src/aiEditor.ts
|
|
2168
2176
|
var import_prompts4 = require("@inquirer/prompts");
|
|
2177
|
+
var import_ora2 = __toESM(require("ora"));
|
|
2169
2178
|
var import_messages = require("@langchain/core/messages");
|
|
2170
2179
|
var import_openai2 = require("@langchain/openai");
|
|
2171
2180
|
var import_chalk3 = __toESM(require("chalk"));
|
|
@@ -2239,23 +2248,28 @@ var AiSession = class _AiSession {
|
|
|
2239
2248
|
await _AiSession.init();
|
|
2240
2249
|
if (!_AiSession.#chat)
|
|
2241
2250
|
throw new Error("Failed to initialize the AI session");
|
|
2251
|
+
const loader = (0, import_ora2.default)(`${_AiSession.#chat.model} is thinking...`).start();
|
|
2242
2252
|
try {
|
|
2243
2253
|
const humanMessage = new import_messages.HumanMessage(question);
|
|
2244
2254
|
this.messageHistory.push(humanMessage);
|
|
2245
2255
|
const stream = await _AiSession.#chat.stream(this.messageHistory);
|
|
2246
|
-
let fullResponse = "";
|
|
2256
|
+
let fullResponse = "", tokenIdx = 0;
|
|
2247
2257
|
for await (const chunk of stream) {
|
|
2258
|
+
if (loader.isSpinning)
|
|
2259
|
+
loader.succeed(`${_AiSession.#chat.model} responded`);
|
|
2248
2260
|
const content = chunk.content;
|
|
2249
2261
|
if (typeof content === "string") {
|
|
2250
2262
|
fullResponse += content;
|
|
2251
2263
|
onChunk(content);
|
|
2252
2264
|
}
|
|
2265
|
+
tokenIdx++;
|
|
2253
2266
|
}
|
|
2254
2267
|
fullResponse += "\n";
|
|
2255
2268
|
onChunk("\n");
|
|
2256
2269
|
this.messageHistory.push(new import_messages.AIMessage(fullResponse));
|
|
2257
2270
|
return { content: fullResponse, messageHistory: this.messageHistory };
|
|
2258
2271
|
} catch (error) {
|
|
2272
|
+
loader.fail(`${_AiSession.#chat.model} failed to respond`);
|
|
2259
2273
|
throw new Error("Failed to stream response");
|
|
2260
2274
|
}
|
|
2261
2275
|
}
|
|
@@ -2509,7 +2523,7 @@ var import_fs9 = __toESM(require("fs"));
|
|
|
2509
2523
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
2510
2524
|
var import_js_yaml2 = __toESM(require("js-yaml"));
|
|
2511
2525
|
var import_open = __toESM(require("open"));
|
|
2512
|
-
var
|
|
2526
|
+
var import_ora3 = __toESM(require("ora"));
|
|
2513
2527
|
var import_path4 = __toESM(require("path"));
|
|
2514
2528
|
var vite = __toESM(require("vite"));
|
|
2515
2529
|
var import_vite_plugin_commonjs = __toESM(require("vite-plugin-commonjs"));
|
|
@@ -2518,1031 +2532,6 @@ var import_vite_tsconfig_paths = __toESM(require("vite-tsconfig-paths"));
|
|
|
2518
2532
|
|
|
2519
2533
|
// pkgs/@akanjs/cli/src/module/module.prompt.ts
|
|
2520
2534
|
var frameworkDescription = `
|
|
2521
|
-
\uB098\uB294 \uC880 \uB354 \uD6A8\uC728\uC801\uC73C\uB85C \uCF54\uB529\uC744 \uD558\uAE30 \uC704\uD574\uC11C \uC790\uCCB4 \uD504\uB808\uC784\uC6CC\uD06C\uB97C \uC81C\uC791\uD588\uC5B4.
|
|
2522
|
-
|
|
2523
|
-
\uADF8\uB798\uC11C \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC124\uBA85\uC744 \uD574\uC904\uD14C\uB2C8\uAE4C \uC798 \uC774\uD574\uD558\uB3C4\uB85D \uD574. \uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uB294 next.js 13\uACFC nest.js, capacitor.js, nx, mongoDB \uAE30\uBC18\uC758 \uD504\uB860\uD2B8\uC5D4\uB4DC, \uC571, \uBC31\uC5D4\uB4DC \uD1B5\uD569 \uD504\uB808\uC784\uC6CC\uD06C\uC57C. \uADF8\uB798\uC11C \uBC31\uC5D4\uB4DC, \uD504\uB860\uD2B8\uC5D4\uB4DC, DB Schema\uC5D0 \uB300\uD55C \uCF54\uB4DC\uAC00 \uBAA8\uB450 \uD55C \uD3F4\uB354 \uC548\uC5D0 \uC788\uC5B4. \uADF8\uB798\uC11C \uC790\uBC14\uC2A4\uD06C\uB9BD\uD2B8, \uD0C0\uC785\uC2A4\uD06C\uB9BD\uD2B8, \uADF8\uB9AC\uACE0 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC774\uD574\uB9CC \uC788\uB2E4\uBA74 \uAD6C\uBD84\uC9D3\uC9C0 \uC54A\uACE0 \uC0AC\uC6A9\uD560 \uC218 \uC788\uB2E4\uB294 \uC7A5\uC810\uC774 \uC788\uC5B4.
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
\uAC00\uC7A5 \uC678\uBD80\uC758 \uAD6C\uC870\uB294
|
|
2528
|
-
|
|
2529
|
-
- app
|
|
2530
|
-
|
|
2531
|
-
- project1
|
|
2532
|
-
|
|
2533
|
-
- project2
|
|
2534
|
-
|
|
2535
|
-
- project3
|
|
2536
|
-
|
|
2537
|
-
- project4
|
|
2538
|
-
|
|
2539
|
-
- lib
|
|
2540
|
-
|
|
2541
|
-
- core
|
|
2542
|
-
|
|
2543
|
-
- external
|
|
2544
|
-
|
|
2545
|
-
- game
|
|
2546
|
-
|
|
2547
|
-
- mint
|
|
2548
|
-
|
|
2549
|
-
- platform
|
|
2550
|
-
|
|
2551
|
-
- shared
|
|
2552
|
-
|
|
2553
|
-
- social
|
|
2554
|
-
|
|
2555
|
-
- util
|
|
2556
|
-
|
|
2557
|
-
app\uC740 \uAC01 \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4DC\uB294 \uACF3\uC774\uC57C
|
|
2558
|
-
|
|
2559
|
-
lib \uD558\uC704 \uD3F4\uB354\uB4E4\uC740 \uC5EC\uB7EC \uD504\uB85C\uC81D\uD2B8\uC5D0\uC11C \uACF5\uC6A9\uC73C\uB85C \uC0AC\uC6A9\uD560 \uC218 \uC788\uACA0\uB2E4 \uB77C\uACE0 \uD310\uB2E8\uD574\uC11C \uBD84\uB9AC\uD574\uB193\uC740 \uACF3\uC774\uC57C.
|
|
2560
|
-
|
|
2561
|
-
\uB2E4\uC74C\uC740 app/project \uB0B4\uBD80\uC758 \uAD6C\uC870\uB97C \uC54C\uB824\uC904\uAC8C.
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
project
|
|
2566
|
-
|
|
2567
|
-
- app
|
|
2568
|
-
|
|
2569
|
-
- [lang]
|
|
2570
|
-
|
|
2571
|
-
- (projectName)
|
|
2572
|
-
|
|
2573
|
-
- (user)
|
|
2574
|
-
|
|
2575
|
-
- page.tsx
|
|
2576
|
-
|
|
2577
|
-
- layout.tsx
|
|
2578
|
-
|
|
2579
|
-
- (public)
|
|
2580
|
-
|
|
2581
|
-
- page.tsx
|
|
2582
|
-
|
|
2583
|
-
- layout.tsx
|
|
2584
|
-
|
|
2585
|
-
- (admin)
|
|
2586
|
-
|
|
2587
|
-
- page.tsx
|
|
2588
|
-
|
|
2589
|
-
- layout.tsx
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
- lib
|
|
2594
|
-
|
|
2595
|
-
- dataName1
|
|
2596
|
-
|
|
2597
|
-
- dataName2
|
|
2598
|
-
|
|
2599
|
-
- dataName3
|
|
2600
|
-
|
|
2601
|
-
- dataName4
|
|
2602
|
-
|
|
2603
|
-
- dataName5
|
|
2604
|
-
|
|
2605
|
-
- dataName6
|
|
2606
|
-
|
|
2607
|
-
- dataName7
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
app\uC740 \uC9C1\uC811\uC801\uC73C\uB85C \uC720\uC800\uAC00 \uBCF4\uB294 \uD398\uC774\uC9C0\uB97C \uC9DC\uB294 \uACF3\uC774\uC57C. \uD3F4\uB354 \uAD6C\uC870\uB294 next 13\uC758 app directory\uB97C \uB530\uB974\uACE0 \uC788\uC5B4.
|
|
2612
|
-
|
|
2613
|
-
public/page.tsx\uAC00 \uAC00\uC7A5 \uCD5C\uCD08\uB85C \uC811\uADFC\uB418\uB294 Index \uD398\uC774\uC9C0\uAC00 \uB420 \uAC70\uC57C.
|
|
2614
|
-
|
|
2615
|
-
\uC544\uB798\uB294 public/page.tsx\uC758 \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uC18C\uC2A4\uCF54\uB4DC\uC57C.
|
|
2616
|
-
|
|
2617
|
-
\`\`\`
|
|
2618
|
-
|
|
2619
|
-
import {{ Image, Link }} from "@util/ui";
|
|
2620
|
-
|
|
2621
|
-
import {{ getSelf }} from "@akanjs/client";
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
export default function Page() {{
|
|
2626
|
-
|
|
2627
|
-
const self = getSelf();
|
|
2628
|
-
|
|
2629
|
-
return (
|
|
2630
|
-
|
|
2631
|
-
<div className="relative w-full h-screen overflow-hidden flex items-center justify-center">
|
|
2632
|
-
|
|
2633
|
-
<Image
|
|
2634
|
-
|
|
2635
|
-
className="absolute left-0 right-0 top-0 bottom-0 w-full h-screen -z-50"
|
|
2636
|
-
|
|
2637
|
-
width={{1920}}
|
|
2638
|
-
|
|
2639
|
-
height={{1080}}
|
|
2640
|
-
|
|
2641
|
-
src="/back.jpg"
|
|
2642
|
-
|
|
2643
|
-
/>
|
|
2644
|
-
|
|
2645
|
-
<div className="max-w-md bg-base-100/50 shadow-lg rounded-xl backdrop-blur-xs w-full py-8 px-16 flex flex-col items-center justify-center gap-3">
|
|
2646
|
-
|
|
2647
|
-
<h1 className="text-4xl mt-2"><%= project %></h1>
|
|
2648
|
-
|
|
2649
|
-
<h2 className="text-lg"><%= project %> description</h2>
|
|
2650
|
-
|
|
2651
|
-
<Link className="w-full" href={{self ? "/home" : "/signin"}}>
|
|
2652
|
-
|
|
2653
|
-
<button className="btn w-full btn-primary">Go to dashboard</button>
|
|
2654
|
-
|
|
2655
|
-
</Link>
|
|
2656
|
-
|
|
2657
|
-
</div>
|
|
2658
|
-
|
|
2659
|
-
</div>
|
|
2660
|
-
|
|
2661
|
-
);
|
|
2662
|
-
|
|
2663
|
-
}}
|
|
2664
|
-
|
|
2665
|
-
\`\`\`
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
lib\uC740 \uC11C\uBE44\uC2A4\uB97C \uB9CC\uB4E4\uB2E4\uBCF4\uBA74 \uD544\uC694\uD55C \uB370\uC774\uD130\uB97C \uC815\uC758\uD558\uB294 \uACF3\uC774\uC57C.
|
|
2670
|
-
|
|
2671
|
-
\uB530\uB77C\uC11C dataName\uC740 DB\uC774\uB984. \uC989 \uB370\uC774\uD130\uBA85\uC744 \uB530\uB77C. \uB2E4\uB9CC \uD3F4\uB354 \uB0B4\uBD80\uC5D0\uB294 backend, frontend\uC5D0\uC11C \uD1B5\uD569\uC73C\uB85C \uC4F0\uB294 \uC18C\uC2A4\uCF54\uB4DC\uB4E4\uC774 \uC788\uC5B4.
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
\uC6B0\uB9AC \uD504\uB808\uC784\uC6CC\uD06C\uC758 \uD575\uC2EC\uC740 \uC815\uC758\uD55C \uBA54\uD0C0\uB370\uC774\uD130\uB4E4\uC744 \uC774\uC6A9\uD574\uC11C \uAC01 \uB370\uC774\uD130\uAC04\uC758 \uC5F0\uAD00\uC810\uC774\uB098, \uB370\uC774\uD130 \uD0C0\uC785\uC744 \uBCF4\uACE0 \uBBF8\uB9AC \uC815\uB9AC\uB41C \uACB0\uACFC\uB97C \uB9CC\uB4E4\uC5B4\uC8FC\uACE0 \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4E0\uB2E4\uBA74 \uAC70\uC758 \uBAA8\uB450 \uD544\uC694\uD55C \uC791\uC5C5\uB4E4\uC744 \uBBF8\uB9AC \uC815\uB9AC\uD574\uB1A8\uC5B4. \uC608\uB97C \uB4E4\uC5B4 \uB370\uC774\uD130 \uD0C0\uC785\uC5D0 \uC774\uBBF8\uC9C0 \uD30C\uC77C\uC774 \uC788\uB2E4\uACE0 \uD55C\uB2E4\uBA74 \uBC31\uC5D4\uB4DC\uB97C \uD1B5\uD574 \uADF8 \uC774\uBBF8\uC9C0\uB97C \uC11C\uBC84\uC758 \uC2A4\uD1A0\uB9AC\uC9C0\uC5D0 \uC800\uC7A5\uD558\uACE0 \uADF8 \uC800\uC7A5\uB41C \uD30C\uC77C\uC744 \uD2B9\uC815 db\uC5D0 id\uB97C \uCD94\uAC00\uD574\uC8FC\uB294 \uD568\uC218\uB4E4 \uAC19\uC740 \uAC83\uB4E4\uC740 \uC5B4\uB290 \uD504\uB85C\uC81D\uD2B8\uB358 \uAC04\uC5D0 \uBAA8\uB450 \uC0AC\uC6A9\uB418\uB294 \uBC29\uC2DD\uC774\uB77C\uACE0 \uD310\uB2E8\uD588\uC5B4. \uD558\uC9C0\uB9CC \uC6B0\uB9AC\uB294 \uD504\uB85C\uC81D\uD2B8\uB97C \uC791\uC5C5\uD560 \uB54C\uB9C8\uB2E4 \uC774 \uBD88\uD544\uC694\uD55C \uC791\uC5C5\uB4E4\uC744 \uD56D\uC0C1 \uB9CC\uB4E4\uACE0 \uD14C\uC2A4\uD2B8\uB97C \uD558\uB294 \uBD88\uD544\uC694\uD55C \uC77C\uB4E4\uC744 \uD558\uACE0\uC788\uC9C0. \uADF8\uB798\uC11C \uC6B0\uB9AC\uB294 \uAC01 \uD504\uB85C\uC81D\uD2B8\uAC00 \uB9CC\uB4E4 \uB54C\uB9C8\uB2E4 \uD544\uC218\uB85C \uC788\uC5B4\uC57C\uD560 \uC774\uBBF8\uC9C0 \uC5C5\uB85C\uB4DC \uD504\uB85C\uC138\uC2A4\uB97C \uD504\uB808\uC784\uC6CC\uD06C\uB97C \uD1B5\uD574 \uBBF8\uB9AC \uC815\uC758\uB41C \uC0C1\uD0DC\uB85C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC5B4.
|
|
2676
|
-
|
|
2677
|
-
\uACB0\uACFC\uC801\uC73C\uB85C \uC6B0\uB9B0 \uD544\uC694\uD558\uC9C0\uB9CC \uB9E4\uBC88 \uC791\uC5C5\uD558\uAE30\uC5D4 \uC190\uC774 \uB9CE\uC774\uAC00\uB294 \uC791\uC5C5\uB4E4\uC744 \uBBF8\uB9AC \uC815\uC758\uD574\uB1A8\uC5B4.
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
\uB610\uD55C \uC6B0\uB9B0 CLI\uB97C \uD1B5\uD574\uC11C \uD2B9\uC815 \uD504\uB85C\uC81D\uD2B8 \uD3F4\uB354 \uD15C\uD50C\uB9BF\uC744 \uB9CC\uB4E4\uC5B4\uC8FC\uAC70\uB098, \uD2B9\uC815 \uBAA8\uB378\uC758 \uD544\uB4DC\uB4E4\uC744 \uB9CC\uB4E4 \uC218 \uC788\uB3C4\uB85D \uD574\uB1A8\uC5B4. Model\uC774\uB77C\uB294 \uBCC0\uC218\uC758 \uACB0\uACFC\uAC12\uC744 \uBC1B\uACE0 \uC800 \uD15C\uD50C\uB9BF\uC5D0 \uB9DE\uAC8C\uB054 \uC774\uB984\uC744 \uB123\uC5B4\uC8FC\uB294 \uAC70\uC9C0. \uB9CC\uC57D \uB0B4\uAC00 phone\uC774\uB77C\uB294 \uBCC0\uC218\uB97C \uB123\uC5C8\uB2E4\uBA74 \uC800 \uBAA8\uB378\uC5D0 Phone\uACFC \uAC19\uC740 \uACB0\uACFC\uAC12\uC73C\uB85C \uAC12\uC774 \uB4E4\uC5B4\uAC00\uAC8C \uB428\uC73C\uB85C\uC11C \uD15C\uD50C\uB9BF\uC774 \uC0DD\uC131\uB3FC. \uC774\uB294 \uC6B0\uB9AC\uAC00 \uC774\uBBF8 \uB9CC\uB4E4\uC5B4\uB193\uC740 \uCEE4\uB9E8\uB4DC\uAC00 \uC788\uC5B4.
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
\uC608\uB97C \uB4E4\uC5B4 \uC5F0\uD544\uC774\uB77C\uB294 \uBAA8\uB378\uC744 \uCEE4\uB9E8\uB4DC\uB97C \uD1B5\uD574 \uC0DD\uC131\uD558\uBA74 \uC544\uB798\uC640 \uAC19\uC740 \uD30C\uC77C\uB4E4\uC774 \uC0DD\uC131\uB3FC.
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
pencil
|
|
2690
|
-
|
|
2691
|
-
- pencil.constant.ts ( pencil\uC5D0 \uB300\uD55C db schema, query, sort \uAD6C\uBB38\uC744 \uC815\uC758 )
|
|
2692
|
-
|
|
2693
|
-
- pencil.document.ts ( model\uC5D0\uC11C \uC790\uC8FC \uC0AC\uC6A9\uD558\uB294 method, static function, middleware\uB85C \uAC04\uB2E8\uD55C db \uAD00\uB9AC \uD568\uC218\uB4F1\uC744 \uAD00\uB9AC\uD568.)
|
|
2694
|
-
|
|
2695
|
-
- pencil.dictionary.ts (\uB2E4\uAD6D\uC5B4\uB97C \uC704\uD574\uC11C schema field, enum, service name\uC758 \uB2E4\uAD6D\uC5B4 \uC815\uBCF4 \uB4F1\uC744 \uBAA8\uB450 \uAD00\uB9AC. )
|
|
2696
|
-
|
|
2697
|
-
- pencil.signal.ts (frontend\uC758 fetch\uB97C \uC5F4\uC5B4\uC8FC\uB294 \uC77C\uC885\uC758 \uCC3D\uAD6C, \uAD8C\uD55C\uAD00\uB9AC\uB4F1\uC744 \uD568 nestjs\uC758 resolver\uC640 \uC720\uC0AC )
|
|
2698
|
-
|
|
2699
|
-
- pencil.service.ts (\uC2E4\uC9C8\uC801\uC778 \uC11C\uBE44\uC2A4 \uCF54\uB4DC\uB97C \uC791\uC131\uD558\uB294 \uACF3. \uAC01\uC885 \uBE44\uC988\uB2C8\uC2A4 \uB85C\uC9C1\uC744 \uCC98\uB9AC\uD568.)
|
|
2700
|
-
|
|
2701
|
-
- pencil.store.ts (pencil field\uC5D0 \uB300\uD55C \uC0C1\uD0DC\uAD00\uB9AC \uC800\uC7A5\uC18C.)
|
|
2702
|
-
|
|
2703
|
-
- pencil.Zone.tsx (\uC544\uB798 Templete, Unit, Util, View, Util\uB4F1\uC744 \uC870\uD569\uD574\uC11C \uB2E4\uC74C \uB808\uBCA8 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC791\uC131\uD558\uB294 \uACF3 client component\uB85C \uC815\uC758\uB428. )
|
|
2704
|
-
|
|
2705
|
-
- pencil.Templete.tsx (\uC8FC\uB85C edit\uC5D0 \uC5F0\uAD00\uB41C \uCEF4\uD3EC\uB10C\uD2B8 \uC815\uC758\uD558\uB294 \uACF3. client component\uB85C \uC815\uC758\uB428. )
|
|
2706
|
-
|
|
2707
|
-
- pencil.Unit.tsx (list \uCC98\uB7FC \uBCF5\uC218\uAC1C\uC758 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC815\uC758\uD558\uB294 \uACF3. server component\uB85C \uC815\uC758\uB428. )
|
|
2708
|
-
|
|
2709
|
-
- pencil.Util.tsx (Action \uBC84\uD2BC\uC744 \uC815\uC758\uD558\uB294 \uACF3. client component\uB85C \uC815\uC758\uB428. )
|
|
2710
|
-
|
|
2711
|
-
- pencil.View.tsx (\uB2E8\uC77C view \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uC815\uC758\uD558\uB294 \uACF3. server component\uB85C \uC815\uC758\uB428. )
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
\uC5EC\uAE30\uC11C constant\uC5D0 \uC815\uC758 \uB418\uC5B4\uC788\uB294 schema\uB97C \uAE30\uBCF8\uC73C\uB85C \uD574\uC11C \uAC01 document, dictionary, signal, service, store\uB97C \uC0DD\uC131\uD574.
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
document, signal, service\uB294 \uBC31\uC5D4\uB4DC\uC640 \uC5F0\uAD00\uB418\uC5B4\uC788\uB294 \uC18C\uC2A4\uCF54\uB4DC\uC57C.
|
|
2721
|
-
|
|
2722
|
-
\uC11C\uB85C\uAC04\uC758 \uAD00\uACC4\uB294 \uC8FC\uB85C signal\uC5D0\uC11C \uAC00\uC7A5 \uBA3C\uC800 \uC694\uCCAD\uC744 \uBC1B\uACE0 \uC774\uD6C4 \uB85C\uC9C1\uC758 \uBCF5\uC7A1\uB3C4\uC5D0 \uB530\uB77C\uC11C service\uB85C \uCC98\uB9AC\uD560 \uC9C0, docuemnt\uB85C \uCC98\uB9AC\uD560 \uC9C0\uB97C \uACB0\uC815\uD574.
|
|
2723
|
-
|
|
2724
|
-
signal - document
|
|
2725
|
-
|
|
2726
|
-
signal - service - document
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
store\uB294 \uD504\uB860\uD2B8\uC5D4\uB4DC\uC5D0\uC11C \uC0C1\uD0DC\uAD00\uB9AC\uB97C \uD560 \uB54C \uC0AC\uC6A9\uB3FC.
|
|
2731
|
-
|
|
2732
|
-
\uC6B0\uB9AC\uB294 signal\uC758 \uCF54\uB4DC\uB85C \uB098\uC628 \uBA54\uD0C0\uB370\uC774\uD130\uB97C \uC774\uC6A9\uD574\uC11C store\uC5D0\uC11C \uD754\uD788 \uC0AC\uC6A9\uB420\uB9CC\uD55C \uD568\uC218\uB4E4\uC744 \uBBF8\uB9AC \uC815\uC758\uD558\uAC8C\uB054 \uB9CC\uB4E4\uC5C8\uC5B4.
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
\uC774\uB807\uAC8C 11\uAC1C\uC758 \uD30C\uC77C\uB85C \uAD6C\uBD84\uD574\uC11C \uC815\uC758\uAC00 \uB3FC.
|
|
2737
|
-
|
|
2738
|
-
\uC9C0\uAE08\uBD80\uD134 \uD55C \uD30C\uC77C\uB4E4\uB9C8\uB2E4 \uC0C1\uC138\uD55C \uC124\uBA85\uC744 \uD574\uC904\uAC8C.
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
model.constant.ts
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
constant\uB294 \uAE30\uBCF8 \uC2A4\uD0A4\uB9C8\uAC00 \uAD6C\uC131\uB418\uB294 \uACF3\uC774\uC57C. \uADF8\uB798\uC11C \uC774 \uACF3\uC5D0\uC11C DB \uC2A4\uD0A4\uB9C8, \uCFFC\uB9AC, \uC815\uB82C \uAD6C\uBB38\uC744 \uC815\uC758\uD574.
|
|
2747
|
-
|
|
2748
|
-
\uC8FC\uC758\uD574\uC57C\uD560 \uAC74 decorator\uC5D0\uC11C \uC815\uC758\uD558\uB294 \uD0C0\uC785\uACFC \uC544\uB798\uC5D0 \uC815\uC758\uD558\uB294 \uD0C0\uC785\uC774 \uC57D\uAC04 \uB2E4\uB97C \uC218 \uC788\uC5B4
|
|
2749
|
-
|
|
2750
|
-
\uC608\uB97C \uB4E4\uC5B4 decorator\uC5D0\uC11C\uB294 Int\uB85C \uC815\uC758\uD558\uACE0 constant\uC5D0\uC11C\uB294 number\uB85C \uC815\uC758\uD574\uC57C\uD574.
|
|
2751
|
-
|
|
2752
|
-
\uCD94\uAC00\uB85C createdAt\uACFC updatedAt, status\uB294 \uAE30\uBCF8\uC801\uC73C\uB85C \uC0DD\uC131\uB418\uB294 \uD544\uB4DC\uC774\uB2C8\uAE4C \uB530\uB85C \uC815\uC758\uD558\uC9C0 \uC54A\uC544\uB3C4 \uB3FC.
|
|
2753
|
-
|
|
2754
|
-
\uC774\uB294 decorator\uC5D0\uC11C\uB294 GraphQL\uC5D0\uC11C \uC0AC\uC6A9\uD560 \uD0C0\uC785\uC744 \uC815\uC758\uD558\uACE0 constant\uC5D0\uC11C\uB294 \uC2E4\uC81C \uD0C0\uC785\uC744 \uC815\uC758\uD558\uB294 \uAC70\uC9C0.
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
\`\`\`
|
|
2759
|
-
|
|
2760
|
-
import { enumOf, Int } from "@akanjs/base";
|
|
2761
|
-
|
|
2762
|
-
import { Field, Filter, Model, sortOf, via } from "@akanjs/constant";
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
export const \${dict.Model}Statuses = ["active"] as const;
|
|
2767
|
-
|
|
2768
|
-
export type \${dict.Model}Status = (typeof \${dict.Model}Statuses)[number];
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
//\uB370\uC774\uD130\uB97C \uB9CC\uB4E4 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130 \uD0C0\uC785\uC744 \uC815\uC758\uD558\uB294 \uACF3
|
|
2773
|
-
|
|
2774
|
-
@Model.Input("\${dict.Model}Input")
|
|
2775
|
-
|
|
2776
|
-
export class \${dict.Model}Input {{
|
|
2777
|
-
|
|
2778
|
-
@Field.Prop(() => String)
|
|
2779
|
-
|
|
2780
|
-
field: string;
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
@Field.Prop(() => Int, {{ nullable: true }})
|
|
2785
|
-
|
|
2786
|
-
fieldInt: number | null;
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
@Field.Prop(() => Date, {{default: dayjs()}})
|
|
2791
|
-
|
|
2792
|
-
fieldInt: Dayjs;
|
|
2793
|
-
|
|
2794
|
-
}}
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
//\uB370\uC774\uD130\uAC00 \uB9CC\uB4E4\uC5B4\uC9C4 \uC774\uD6C4 \uC0DD\uC131\uB418\uAC70\uB098 \uC800\uC7A5\uC73C\uB85C \uCD94\uAC00\uD560 \uC218 \uC788\uB294 \uACF3
|
|
2799
|
-
|
|
2800
|
-
@Model.Object("\${dict.Model}Object")
|
|
2801
|
-
|
|
2802
|
-
export class \${dict.Model}Object extends via(\${dict.Model}Input) {
|
|
2803
|
-
|
|
2804
|
-
@Field.Prop(() => String, {{ enum: \${dict.Model}Statuses, default: "active" }})
|
|
2805
|
-
|
|
2806
|
-
status: \${dict.Model}Status;
|
|
2807
|
-
|
|
2808
|
-
}}
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
//\uB370\uC774\uD130\uB97C \uB9AC\uC2A4\uD2B8\uB85C \uBCF4\uC5EC\uC904 \uB54C \uD544\uC694\uD55C \uB370\uC774\uD130\uB9CC \uC81C\uACF5\uD558\uB294 \uACF3
|
|
2813
|
-
|
|
2814
|
-
@Model.Light("Light\${dict.Model}")
|
|
2815
|
-
|
|
2816
|
-
export class Light\${dict.Model} extends via(\${dict.Model}Object, [
|
|
2817
|
-
|
|
2818
|
-
"field",
|
|
2819
|
-
|
|
2820
|
-
"status",
|
|
2821
|
-
|
|
2822
|
-
] as const) {}
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
//\uCD5C\uC885 \uB370\uC774\uD130\uC758 Full \uD0C0\uC785\uC774 \uC815\uC758\uB418\uB294 \uACF3
|
|
2827
|
-
|
|
2828
|
-
@Model.Full("\${dict.Model}")
|
|
2829
|
-
|
|
2830
|
-
export class \${dict.Model} extends via(\${dict.Model}Object, Light\${dict.Model}) {}
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
//\uB370\uC774\uD130\uC758 \uC778\uC0AC\uC774\uD2B8\uB97C \uCE21\uC815\uD558\uAE30 \uC704\uD574\uC11C \uD544\uC694\uD55C \uB370\uC774\uD130\uB97C \uC815\uC758\uD558\uB294 \uACF3
|
|
2835
|
-
|
|
2836
|
-
@Model.Insight("\${dict.Model}Insight")
|
|
2837
|
-
|
|
2838
|
-
export class \${dict.Model}Insight {{
|
|
2839
|
-
|
|
2840
|
-
@Field.Prop(() => Int, {{ default: 0, accumulate: {{ $sum: 1 }} }})
|
|
2841
|
-
|
|
2842
|
-
count: number;
|
|
2843
|
-
|
|
2844
|
-
}}
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
//\uB370\uC774\uD130\uC758 \uD1B5\uACC4\uB97C \uACC4\uC0B0\uD558\uB294 \uACF3
|
|
2849
|
-
|
|
2850
|
-
@Model.Summary("\${dict.Model}Summary")
|
|
2851
|
-
|
|
2852
|
-
export class \${dict.Model}Summary {{
|
|
2853
|
-
|
|
2854
|
-
@Field.Prop(() => Int, {{ min: 0, default: 0, query: {{ status: {{}} }} }})
|
|
2855
|
-
|
|
2856
|
-
total\${dict.Model}: number;
|
|
2857
|
-
|
|
2858
|
-
}}
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
@Model.Filter("\${dict.Model}Filter")
|
|
2863
|
-
|
|
2864
|
-
export class \${dict.Model}Filter extends sortOf(\${dict.Model}, {}) {}
|
|
2865
|
-
|
|
2866
|
-
\`\`\`
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
model.dictonary.ts
|
|
2872
|
-
|
|
2873
|
-
\`\`\`
|
|
2874
|
-
|
|
2875
|
-
import {
|
|
2876
|
-
|
|
2877
|
-
baseTrans,
|
|
2878
|
-
|
|
2879
|
-
getBaseSignalTrans,
|
|
2880
|
-
|
|
2881
|
-
ModelDictionary,
|
|
2882
|
-
|
|
2883
|
-
SignalDictionary,
|
|
2884
|
-
|
|
2885
|
-
SummaryDictionary,
|
|
2886
|
-
|
|
2887
|
-
} from "@akanjs/dictionary";
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
import type { \${dict.Model}, \${dict.Model}Filter, \${dict.Model}Insight, \${dict.Model}Summary } from "./\${dict.model}.constant";
|
|
2892
|
-
|
|
2893
|
-
import type { \${dict.Model}Signal } from "./\${dict.model}.signal";
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
const modelDictionary = {{
|
|
2898
|
-
|
|
2899
|
-
...baseTrans,
|
|
2900
|
-
|
|
2901
|
-
modelName: ["\${dict.Model}", "\${dict.Model}"],
|
|
2902
|
-
|
|
2903
|
-
modelDesc: [
|
|
2904
|
-
|
|
2905
|
-
"\${dict.Model} description",
|
|
2906
|
-
|
|
2907
|
-
"\${dict.Model} \uC124\uBA85",
|
|
2908
|
-
|
|
2909
|
-
],
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
// * ==================== Model ==================== * //
|
|
2914
|
-
|
|
2915
|
-
field: ["Field", "\uD544\uB4DC"],
|
|
2916
|
-
|
|
2917
|
-
"desc-field": ["Field", "\uD544\uB4DC"],
|
|
2918
|
-
|
|
2919
|
-
// * ==================== Model ==================== * //
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
// * ==================== Insight ==================== * //
|
|
2924
|
-
|
|
2925
|
-
count: ["Count", "\uAC1C\uC218"],
|
|
2926
|
-
|
|
2927
|
-
"desc-count": ["\${dict.Model} count in current query settting", "\uD604\uC7AC \uCFFC\uB9AC \uC124\uC815\uC5D0 \uB9DE\uB294 \${dict.Model} \uC218"],
|
|
2928
|
-
|
|
2929
|
-
// * ==================== Insight ==================== * //
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
// * ==================== Filter ==================== * //
|
|
2934
|
-
|
|
2935
|
-
// * ==================== Filter ==================== * //
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
// * ==================== Etc ==================== * //
|
|
2940
|
-
|
|
2941
|
-
"enum-status-active": ["Active", "\uD65C\uC131"],
|
|
2942
|
-
|
|
2943
|
-
"enumdesc-status-active": ["Active status", "\uD65C\uC131 \uC0C1\uD0DC"],
|
|
2944
|
-
|
|
2945
|
-
// * ==================== Etc ==================== * //
|
|
2946
|
-
|
|
2947
|
-
}} satisfies ModelDictionary<\${dict.Model}, \${dict.Model}Insight, typeof \${dict.Model}Sort>;
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
export const \${dict.Model}SummaryDictionary = {{
|
|
2952
|
-
|
|
2953
|
-
// * ==================== Summary ==================== * //
|
|
2954
|
-
|
|
2955
|
-
total\${dict.Model}: ["Total \${dict.Model}", "\uCD1D \${dict.Model} \uC218"],
|
|
2956
|
-
|
|
2957
|
-
"desc-total\${dict.Model}": ["Total \${dict.Model} count in the database", "\uB370\uC774\uD130\uBCA0\uC774\uC2A4\uC5D0 \uC800\uC7A5\uB41C \uCD1D \${dict.Model} \uC218"],
|
|
2958
|
-
|
|
2959
|
-
// * ==================== Summary ==================== * //
|
|
2960
|
-
|
|
2961
|
-
}} satisfies SummaryDictionary<\${dict.Model}Summary>;
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
const signalDictionary = {{
|
|
2966
|
-
|
|
2967
|
-
...getBaseSignalTrans("\${dict.Model}" as const),
|
|
2968
|
-
|
|
2969
|
-
// * ==================== Endpoint ==================== * //
|
|
2970
|
-
|
|
2971
|
-
"api-\${dict.Model}ListInPublic": ["\${dict.Model} List In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uB9AC\uC2A4\uD2B8"],
|
|
2972
|
-
|
|
2973
|
-
"apidesc-\${dict.Model}ListInPublic": ["Get a list of public \${dict.Model}", "\uACF5\uAC1C\uB41C \${dict.Model}\uC758 \uB9AC\uC2A4\uD2B8\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4"],
|
|
2974
|
-
|
|
2975
|
-
"arg-\${dict.Model}ListInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
|
|
2976
|
-
|
|
2977
|
-
"argdesc-\${dict.Model}ListInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
|
|
2978
|
-
|
|
2979
|
-
"arg-\${dict.Model}ListInPublic-skip": ["Skip", "\uAC74\uB108\uB6F0\uAE30"],
|
|
2980
|
-
|
|
2981
|
-
"argdesc-\${dict.Model}ListInPublic-skip": ["Number of items to skip", "\uAC74\uB108\uB6F8 \uC544\uC774\uD15C \uC218"],
|
|
2982
|
-
|
|
2983
|
-
"arg-\${dict.Model}ListInPublic-limit": ["Limit", "\uC81C\uD55C"],
|
|
2984
|
-
|
|
2985
|
-
"argdesc-\${dict.Model}ListInPublic-limit": ["Maximum number of items to return", "\uBC18\uD658\uD560 \uCD5C\uB300 \uC544\uC774\uD15C \uC218"],
|
|
2986
|
-
|
|
2987
|
-
"arg-\${dict.Model}ListInPublic-sort": ["Sort", "\uC815\uB82C"],
|
|
2988
|
-
|
|
2989
|
-
"argdesc-\${dict.Model}ListInPublic-sort": ["Sort order of the items", "\uC544\uC774\uD15C\uC758 \uC815\uB82C \uC21C\uC11C"],
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
"api-\${dict.Model}InsightInPublic": ["\${dict.Model} Insight In Public", "\uACF5\uAC1C\uB41C \${dict.Model} \uC778\uC0AC\uC774\uD2B8"],
|
|
2994
|
-
|
|
2995
|
-
"apidesc-\${dict.Model}InsightInPublic": [
|
|
2996
|
-
|
|
2997
|
-
"Get insight data for public \${dict.Model}",
|
|
2998
|
-
|
|
2999
|
-
"\uACF5\uAC1C\uB41C \${dict.Model}\uC5D0 \uB300\uD55C \uC778\uC0AC\uC774\uD2B8 \uB370\uC774\uD130\uB97C \uAC00\uC838\uC635\uB2C8\uB2E4",
|
|
3000
|
-
|
|
3001
|
-
],
|
|
3002
|
-
|
|
3003
|
-
"arg-\${dict.Model}InsightInPublic-statuses": ["Statuses", "\uC0C1\uD0DC"],
|
|
3004
|
-
|
|
3005
|
-
"argdesc-\${dict.Model}InsightInPublic-statuses": ["Statuses to filter", "\uD544\uD130\uB9C1\uD560 \uC0C1\uD0DC"],
|
|
3006
|
-
|
|
3007
|
-
// * ==================== Endpoint ==================== * //
|
|
3008
|
-
|
|
3009
|
-
}} satisfies SignalDictionary<\${dict.Model}Signal, \${dict.Model}>;
|
|
3010
|
-
|
|
3011
|
-
\`\`\`
|
|
3012
|
-
|
|
3013
|
-
export const \${dict.model}Dictionary = {{ ...modelDictionary, ...signalDictionary }};
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
model.document.ts
|
|
3020
|
-
|
|
3021
|
-
\`\`\`
|
|
3022
|
-
|
|
3023
|
-
import { beyond, by, Database, into, type SchemaOf } from "@akanjs/document";
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
import { cnst } from "../cnst";
|
|
3028
|
-
|
|
3029
|
-
@Database.Input(() => cnst.\${dict.Model}Input)
|
|
3030
|
-
|
|
3031
|
-
export class \${dict.Model}Input extends by(cnst.\${dict.Model}Input) {}
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
@Database.Document(() => cnst.\${dict.Model})
|
|
3036
|
-
|
|
3037
|
-
export class \${dict.Model} extends by(cnst.\${dict.Model}) {}
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
@Database.Model(() => cnst.\${dict.Model})
|
|
3042
|
-
|
|
3043
|
-
export class \${dict.Model}Model extends into(\${dict.Model}, cnst.\${dict.Model}Cnst) {
|
|
3044
|
-
|
|
3045
|
-
async getSummary(): Promise<cnst.\${dict.Model}Summary> {
|
|
3046
|
-
|
|
3047
|
-
return {
|
|
3048
|
-
|
|
3049
|
-
...(await this.getDefaultSummary()),
|
|
3050
|
-
|
|
3051
|
-
};
|
|
3052
|
-
|
|
3053
|
-
}
|
|
3054
|
-
|
|
3055
|
-
}
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
@Database.Middleware(() => cnst.\${dict.Model})
|
|
3060
|
-
|
|
3061
|
-
export class \${dict.Model}Middleware extends beyond(\${dict.Model}Model, \${dict.Model}) {
|
|
3062
|
-
|
|
3063
|
-
onSchema(schema: SchemaOf<\${dict.Model}Model, \${dict.Model}>) {
|
|
3064
|
-
|
|
3065
|
-
// schema.index({ status: 1 })
|
|
3066
|
-
|
|
3067
|
-
}
|
|
3068
|
-
|
|
3069
|
-
}
|
|
3070
|
-
|
|
3071
|
-
\`\`\`
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
model.signal.ts
|
|
3077
|
-
|
|
3078
|
-
\`\`\`
|
|
3079
|
-
|
|
3080
|
-
import { Int } from "@akanjs/base";
|
|
3081
|
-
|
|
3082
|
-
import { SortOf } from "@akanjs/constant";
|
|
3083
|
-
|
|
3084
|
-
import { Arg, DbSignal, Mutation, Query, resolve, Signal } from "@akanjs/signal";
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
import { cnst, Srvs } from "../cnst";
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
@Signal(() => cnst.\${dict.Model})
|
|
3093
|
-
|
|
3094
|
-
export class \${dict.Model}Signal extends DbSignal(cnst.\${dict.model}Cnst, Srvs, {
|
|
3095
|
-
|
|
3096
|
-
guards: { get: Query.Public, cru: Mutation.Public },
|
|
3097
|
-
|
|
3098
|
-
}) {
|
|
3099
|
-
|
|
3100
|
-
// * /////////////////////////////////////
|
|
3101
|
-
|
|
3102
|
-
// * Public Slice
|
|
3103
|
-
|
|
3104
|
-
@Query.Public(() => [cnst.\${dict.Model}])
|
|
3105
|
-
|
|
3106
|
-
async \${dict.model}ListInPublic(
|
|
3107
|
-
|
|
3108
|
-
@Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null,
|
|
3109
|
-
|
|
3110
|
-
@Arg.Query("skip", () => Int, { nullable: true }) skip: number | null,
|
|
3111
|
-
|
|
3112
|
-
@Arg.Query("limit", () => Int, { nullable: true }) limit: number | null,
|
|
3113
|
-
|
|
3114
|
-
@Arg.Query("sort", () => String, { nullable: true }) sort: SortOf<cnst.\${dict.Model}Filter> | null
|
|
3115
|
-
|
|
3116
|
-
) {
|
|
3117
|
-
|
|
3118
|
-
const \${dict.models} = await this.\${dict.model}Service.listByStatuses(statuses, { skip, limit, sort });
|
|
3119
|
-
|
|
3120
|
-
return resolve<cnst.\${dict.Model}[]>(\${dict.models});
|
|
3121
|
-
|
|
3122
|
-
}
|
|
3123
|
-
|
|
3124
|
-
@Query.Public(() => cnst.\${dict.Model}Insight)
|
|
3125
|
-
|
|
3126
|
-
async \${dict.model}InsightInPublic(
|
|
3127
|
-
|
|
3128
|
-
@Arg.Query("statuses", () => [String], { nullable: true }) statuses: cnst.\${dict.Model}Status[] | null
|
|
3129
|
-
|
|
3130
|
-
) {
|
|
3131
|
-
|
|
3132
|
-
const \${dict.model}Insight = await this.\${dict.model}Service.insightByStatuses(statuses);
|
|
3133
|
-
|
|
3134
|
-
return resolve<cnst.\${dict.Model}Insight>(\${dict.model}Insight);
|
|
3135
|
-
|
|
3136
|
-
}
|
|
3137
|
-
|
|
3138
|
-
// * Public Slice
|
|
3139
|
-
|
|
3140
|
-
// * /////////////////////////////////////
|
|
3141
|
-
|
|
3142
|
-
}
|
|
3143
|
-
|
|
3144
|
-
\`\`\`
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
model.service.ts
|
|
3150
|
-
|
|
3151
|
-
\`\`\`
|
|
3152
|
-
|
|
3153
|
-
import { DbService, Service } from "@akanjs/service";
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
import { cnst } from "../cnst";
|
|
3158
|
-
|
|
3159
|
-
import * as db from "../db";
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
@Service("\${dict.Model}Service")
|
|
3164
|
-
|
|
3165
|
-
export class \${dict.Model}Service extends DbService(db.\${dict.Model}Db) {
|
|
3166
|
-
|
|
3167
|
-
async summarize(): Promise<cnst.\${dict.Model}Summary> {
|
|
3168
|
-
|
|
3169
|
-
return {
|
|
3170
|
-
|
|
3171
|
-
...(await this.\${dict.Model}Model.getSummary()),
|
|
3172
|
-
|
|
3173
|
-
};
|
|
3174
|
-
|
|
3175
|
-
}
|
|
3176
|
-
|
|
3177
|
-
}
|
|
3178
|
-
|
|
3179
|
-
\`\`\`
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
model.store.ts
|
|
3185
|
-
|
|
3186
|
-
\`\`\`
|
|
3187
|
-
|
|
3188
|
-
import { stateOf, Store } from "@akanjs/store";
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
import { cnst } from "../cnst";
|
|
3193
|
-
|
|
3194
|
-
import { fetch } from "../fetch";
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
@Store(() => cnst.\${dict.Model})
|
|
3199
|
-
|
|
3200
|
-
export class \${dict.Model}Store extends stateOf(fetch.\${dict.model}Gql, {
|
|
3201
|
-
|
|
3202
|
-
// state
|
|
3203
|
-
|
|
3204
|
-
}) {
|
|
3205
|
-
|
|
3206
|
-
// action
|
|
3207
|
-
|
|
3208
|
-
}
|
|
3209
|
-
|
|
3210
|
-
\`\`\`
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
model.Zone.tsx
|
|
3216
|
-
|
|
3217
|
-
\`\`\`
|
|
3218
|
-
|
|
3219
|
-
"use client";
|
|
3220
|
-
|
|
3221
|
-
import { Data, Load } from "@shared/ui";
|
|
3222
|
-
|
|
3223
|
-
import { ModelsProps } from "@akanjs/client";
|
|
3224
|
-
|
|
3225
|
-
import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
|
|
3226
|
-
|
|
3227
|
-
import { ClientInit, ClientView, DefaultOf } from "@akanjs/signal";
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
export const Admin = ({ sliceName = "\${dict.model}", init, query }: ModelsProps<cnst.\${dict.Model}>>) => {
|
|
3232
|
-
|
|
3233
|
-
return (
|
|
3234
|
-
|
|
3235
|
-
<Data.ListContainer
|
|
3236
|
-
|
|
3237
|
-
init={init}
|
|
3238
|
-
|
|
3239
|
-
query={query}
|
|
3240
|
-
|
|
3241
|
-
sliceName={sliceName}
|
|
3242
|
-
|
|
3243
|
-
renderItem={\${dict.Model}.Unit.Card}
|
|
3244
|
-
|
|
3245
|
-
renderDashboard={\${dict.Model}.Util.Stat}
|
|
3246
|
-
|
|
3247
|
-
renderInsight={\${dict.Model}.Util.Insight}
|
|
3248
|
-
|
|
3249
|
-
renderTemplate={\${dict.Model}.Template.General}
|
|
3250
|
-
|
|
3251
|
-
renderTitle={(\${dict.model}: DefaultOf<cnst.\${dict.Model}>>) => \`\${dict.Model} - \${\${dict.model}.id ? \${dict.model}.id : "New"}\`}
|
|
3252
|
-
|
|
3253
|
-
renderView={(\${dict.model}: cnst.\${dict.Model}>) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />}
|
|
3254
|
-
|
|
3255
|
-
columns={[
|
|
3256
|
-
|
|
3257
|
-
"id",
|
|
3258
|
-
|
|
3259
|
-
"status",
|
|
3260
|
-
|
|
3261
|
-
"createdAt",
|
|
3262
|
-
|
|
3263
|
-
"updatedAt",
|
|
3264
|
-
|
|
3265
|
-
]}
|
|
3266
|
-
|
|
3267
|
-
actions={(\${dict.model}: cnst.Light\${dict.Model}, idx) => ["remove", "edit", "view"]}
|
|
3268
|
-
|
|
3269
|
-
/>
|
|
3270
|
-
|
|
3271
|
-
);
|
|
3272
|
-
|
|
3273
|
-
};
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
interface CardProps {
|
|
3278
|
-
|
|
3279
|
-
className?: string;
|
|
3280
|
-
|
|
3281
|
-
init: ClientInit<"\${dict.model}", cnst.Light\${dict.Model}>;
|
|
3282
|
-
|
|
3283
|
-
}
|
|
3284
|
-
|
|
3285
|
-
export const Card = ({ className, init }: CardProps) => {
|
|
3286
|
-
|
|
3287
|
-
return (
|
|
3288
|
-
|
|
3289
|
-
<Load.Units
|
|
3290
|
-
|
|
3291
|
-
className={className}
|
|
3292
|
-
|
|
3293
|
-
init={init}
|
|
3294
|
-
|
|
3295
|
-
renderItem={(\${dict.model}: cnst.Light\${dict.Model}) => (
|
|
3296
|
-
|
|
3297
|
-
<\${dict.Model}.Unit.Card key={\${dict.model}.id} href={\`/\${dict.model}/\${\${dict.model}.id}\`} \${dict.model}={\${dict.model}} />
|
|
3298
|
-
|
|
3299
|
-
)}
|
|
3300
|
-
|
|
3301
|
-
/>
|
|
3302
|
-
|
|
3303
|
-
);
|
|
3304
|
-
|
|
3305
|
-
};
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
interface ViewProps {
|
|
3310
|
-
|
|
3311
|
-
className?: string;
|
|
3312
|
-
|
|
3313
|
-
view: ClientView<"\${dict.model}", cnst.\${dict.Model}>;
|
|
3314
|
-
|
|
3315
|
-
}
|
|
3316
|
-
|
|
3317
|
-
export const View = ({ view }: ViewProps) => {
|
|
3318
|
-
|
|
3319
|
-
return <Load.View view={view} renderView={(\${dict.model}) => <\${dict.Model}.View.General \${dict.model}={\${dict.model}} />} />;
|
|
3320
|
-
|
|
3321
|
-
};
|
|
3322
|
-
|
|
3323
|
-
\`\`\`
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
model.Templete.tsx
|
|
3328
|
-
|
|
3329
|
-
\`\`\`
|
|
3330
|
-
|
|
3331
|
-
"use client";
|
|
3332
|
-
|
|
3333
|
-
import { cnst, st, usePage } from "@\${dict.appName}/client";
|
|
3334
|
-
|
|
3335
|
-
import { Field } from "@shared/ui";
|
|
3336
|
-
|
|
3337
|
-
import { Layout } from "@util/ui";
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
interface \${dict.Model}EditProps {
|
|
3342
|
-
|
|
3343
|
-
\${dict.model}Id?: string | null;
|
|
3344
|
-
|
|
3345
|
-
}
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
export const General = ({ \${dict.model}Id = undefined }: \${dict.Model}EditProps) => {
|
|
3350
|
-
|
|
3351
|
-
const \${dict.model}Form = st.use.\${dict.model}Form();
|
|
3352
|
-
|
|
3353
|
-
const { l } = usePage();
|
|
3354
|
-
|
|
3355
|
-
return (
|
|
3356
|
-
|
|
3357
|
-
<Layout.Template>
|
|
3358
|
-
|
|
3359
|
-
<Field.Text
|
|
3360
|
-
|
|
3361
|
-
label={l.field("\${dict.model}", "id")}
|
|
3362
|
-
|
|
3363
|
-
desc={l.desc("\${dict.model}", "id")}
|
|
3364
|
-
|
|
3365
|
-
value={\${dict.model}Form.id}
|
|
3366
|
-
|
|
3367
|
-
onChange={st.do.setIdOn\${dict.Model}}
|
|
3368
|
-
|
|
3369
|
-
/>
|
|
3370
|
-
|
|
3371
|
-
</Layout.Template>
|
|
3372
|
-
|
|
3373
|
-
);
|
|
3374
|
-
|
|
3375
|
-
};
|
|
3376
|
-
|
|
3377
|
-
\`\`\`
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
model.Unit.tsx
|
|
3383
|
-
|
|
3384
|
-
\`\`\`
|
|
3385
|
-
|
|
3386
|
-
import { ModelProps } from "@akanjs/client";
|
|
3387
|
-
|
|
3388
|
-
import { cnst, \${dict.Model} } from "@\${dict.appName}/client";
|
|
3389
|
-
|
|
3390
|
-
import { Link } from "@util/ui";
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
export const Card = ({ \${dict.model}, href }: ModelProps<"\${dict.model}", cnst.Light\${dict.Model}>>) => {
|
|
3395
|
-
|
|
3396
|
-
return (
|
|
3397
|
-
|
|
3398
|
-
<Link href={href} className="animate-fadeIn w-full h-36 flex rounded-lg shadow-sm hover:shadow-lg duration-300">
|
|
3399
|
-
|
|
3400
|
-
<div>{\${dict.model}.id}</div>
|
|
3401
|
-
|
|
3402
|
-
</Link>
|
|
3403
|
-
|
|
3404
|
-
);
|
|
3405
|
-
|
|
3406
|
-
};
|
|
3407
|
-
|
|
3408
|
-
\`\`\`
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
model.Util.tsx
|
|
3414
|
-
|
|
3415
|
-
\`\`\`
|
|
3416
|
-
|
|
3417
|
-
"use client";
|
|
3418
|
-
|
|
3419
|
-
import { ModelDashboardProps, ModelInsightProps } from "@akanjs/client";
|
|
3420
|
-
|
|
3421
|
-
import { getQueryMap } from "@akanjs/constant";
|
|
3422
|
-
|
|
3423
|
-
import { cnst } from "@\${dict.appName}/client";
|
|
3424
|
-
|
|
3425
|
-
import { Data } from "@shared/ui";
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
export const Stat = ({
|
|
3430
|
-
|
|
3431
|
-
className,
|
|
3432
|
-
|
|
3433
|
-
summary,
|
|
3434
|
-
|
|
3435
|
-
sliceName = "\${dict.model}",
|
|
3436
|
-
|
|
3437
|
-
queryMap = getQueryMap(cnst.\${dict.Model}Summary),
|
|
3438
|
-
|
|
3439
|
-
hidePresents,
|
|
3440
|
-
|
|
3441
|
-
}: ModelDashboardProps<cnst.Summary>) => {
|
|
3442
|
-
|
|
3443
|
-
return (
|
|
3444
|
-
|
|
3445
|
-
<Data.Dashboard
|
|
3446
|
-
|
|
3447
|
-
className={className}
|
|
3448
|
-
|
|
3449
|
-
summary={summary}
|
|
3450
|
-
|
|
3451
|
-
sliceName={sliceName}
|
|
3452
|
-
|
|
3453
|
-
queryMap={queryMap}
|
|
3454
|
-
|
|
3455
|
-
columns={["total\${dict.Model}"]}
|
|
3456
|
-
|
|
3457
|
-
hidePresents={hidePresents}
|
|
3458
|
-
|
|
3459
|
-
/>
|
|
3460
|
-
|
|
3461
|
-
);
|
|
3462
|
-
|
|
3463
|
-
};
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
export const Insight = ({
|
|
3468
|
-
|
|
3469
|
-
className,
|
|
3470
|
-
|
|
3471
|
-
insight,
|
|
3472
|
-
|
|
3473
|
-
sliceName = "\${dict.model}",
|
|
3474
|
-
|
|
3475
|
-
}: ModelInsightProps<cnst.\${dict.Model}Insight>) => {
|
|
3476
|
-
|
|
3477
|
-
return (
|
|
3478
|
-
|
|
3479
|
-
<Data.Insight
|
|
3480
|
-
|
|
3481
|
-
className={className}
|
|
3482
|
-
|
|
3483
|
-
insight={insight}
|
|
3484
|
-
|
|
3485
|
-
sliceName={sliceName}
|
|
3486
|
-
|
|
3487
|
-
columns={["count"]}
|
|
3488
|
-
|
|
3489
|
-
/>
|
|
3490
|
-
|
|
3491
|
-
);
|
|
3492
|
-
|
|
3493
|
-
};
|
|
3494
|
-
|
|
3495
|
-
\`\`\`
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
model.View.tsx
|
|
3501
|
-
|
|
3502
|
-
\`\`\`
|
|
3503
|
-
|
|
3504
|
-
import { clsx } from "@akanjs/client";
|
|
3505
|
-
|
|
3506
|
-
import { cnst } from "@\${dict.appName}/client";
|
|
3507
|
-
|
|
3508
|
-
import { Image } from "@util/ui";
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
interface \${dict.Model}ViewProps {
|
|
3513
|
-
|
|
3514
|
-
className?: string;
|
|
3515
|
-
|
|
3516
|
-
\${dict.model}: cnst.\${dict.Model};
|
|
3517
|
-
|
|
3518
|
-
self?: { id?: string } | null;
|
|
3519
|
-
|
|
3520
|
-
}
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
export const General = ({ className, \${dict.model}, self }: \${dict.Model}ViewProps) => {
|
|
3525
|
-
|
|
3526
|
-
return (
|
|
3527
|
-
|
|
3528
|
-
<div className={clsx(className, "animate-fadeIn w-full")}>
|
|
3529
|
-
|
|
3530
|
-
<div>{\${dict.model}.id}</div>
|
|
3531
|
-
|
|
3532
|
-
</div>
|
|
3533
|
-
|
|
3534
|
-
);
|
|
3535
|
-
|
|
3536
|
-
};
|
|
3537
|
-
|
|
3538
|
-
\`\`\`
|
|
3539
|
-
|
|
3540
|
-
\uC774\uB7F0\uC2DD\uC73C\uB85C \uC6B0\uB9AC\uAC00 \uC9C1\uC811 \uB9CC\uB4E0 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uAE30\uBC18\uD574\uC11C db\uC640 \uC11C\uBE44\uC2A4 \uC2A4\uD1A0\uC5B4\uAE4C\uC9C0 \uBAA8\uB450 \uC5F0\uB3D9\uD574\uC11C \uD558\uB098\uC758 \uBAA8\uB378\uC5D0 \uB9DE\uAC8C\uB054 \uBAA8\uB4C8\uC744 \uD55C \uD3F4\uB354\uC5D0\uC11C \uC791\uC5C5\uD560 \uC218 \uC788\uAC8C\uB054 \uAD6C\uC870\uB97C \uB9CC\uB4E4\uC5C8\uC5B4.
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
\uC77C\uB2E8 \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uC124\uBA85\uC740 \uC774 \uC815\uB3C4\uB85C \uD558\uACE0 \uC774 \uC815\uBCF4\uB4E4\uC744 \uAE30\uBC18\uC73C\uB85C \uB0B4\uAC00 \uC6D0\uD558\uB294 \uC694\uAD6C\uB97C \uB4E4\uC5B4\uC918.
|
|
3545
|
-
|
|
3546
2535
|
`;
|
|
3547
2536
|
var moduleDesription = `
|
|
3548
2537
|
|
|
@@ -3978,6 +2967,767 @@ var utilUiDescription = `
|
|
|
3978
2967
|
- Modern React patterns (hooks, context, providers)
|
|
3979
2968
|
- Error handling and validation systems
|
|
3980
2969
|
`;
|
|
2970
|
+
var shardUiDescription = `
|
|
2971
|
+
Shared UI Library Analysis
|
|
2972
|
+
|
|
2973
|
+
Library Overview
|
|
2974
|
+
|
|
2975
|
+
The shared UI library in the akansoft project is a comprehensive React component collection designed for building data-driven
|
|
2976
|
+
applications. It provides a complete toolkit with consistent patterns, extensive customization options, and deep integration with the
|
|
2977
|
+
application's store system.
|
|
2978
|
+
|
|
2979
|
+
Key Characteristics
|
|
2980
|
+
|
|
2981
|
+
- Store-Centric Architecture: Deep integration with standardized store slices and naming conventions
|
|
2982
|
+
- Type-Safe Components: Extensive TypeScript generic usage for compile-time safety
|
|
2983
|
+
- Internationalization Ready: Built-in multi-language support throughout all components
|
|
2984
|
+
- Responsive Design: Mobile-first approach with adaptive breakpoints
|
|
2985
|
+
- Performance Optimized: Memoization, lazy loading, and efficient re-rendering
|
|
2986
|
+
- Accessibility Compliant: Proper ARIA attributes and keyboard navigation
|
|
2987
|
+
- Extensible Architecture: Plugin systems and customizable renderers
|
|
2988
|
+
- Unidirectional Data Flow: Predictable state management patterns
|
|
2989
|
+
|
|
2990
|
+
Component Categories
|
|
2991
|
+
|
|
2992
|
+
1. Field Components (Field.tsx)
|
|
2993
|
+
|
|
2994
|
+
Field.tsx is a core form component library for the akansoft project, providing more than 25 specialized input fields.
|
|
2995
|
+
|
|
2996
|
+
## Basic Structure and Common Features
|
|
2997
|
+
|
|
2998
|
+
### Label Component
|
|
2999
|
+
|
|
3000
|
+
\`\`\`typescript
|
|
3001
|
+
interface LabelProps {
|
|
3002
|
+
className?: string;
|
|
3003
|
+
label: string;
|
|
3004
|
+
desc?: string;
|
|
3005
|
+
unit?: string;
|
|
3006
|
+
nullable?: boolean;
|
|
3007
|
+
mode?: "view" | "edit";
|
|
3008
|
+
}
|
|
3009
|
+
\`\`\`
|
|
3010
|
+
- Purpose: Consistent label display for all fields
|
|
3011
|
+
- Features:
|
|
3012
|
+
- Help tooltip support (desc)
|
|
3013
|
+
- Unit display (unit)
|
|
3014
|
+
- Optional field display (nullable)
|
|
3015
|
+
- Required indicator is commented out (design decision)
|
|
3016
|
+
|
|
3017
|
+
## Text Input Components
|
|
3018
|
+
|
|
3019
|
+
### 1. Field.Text
|
|
3020
|
+
|
|
3021
|
+
\`\`\`typescript
|
|
3022
|
+
interface TextProps {
|
|
3023
|
+
label?: string;
|
|
3024
|
+
desc?: string;
|
|
3025
|
+
value: string | null;
|
|
3026
|
+
onChange: (value: string) => void;
|
|
3027
|
+
placeholder?: string;
|
|
3028
|
+
nullable?: boolean;
|
|
3029
|
+
disabled?: boolean;
|
|
3030
|
+
minlength?: number; // Default: nullable ? 0 : 2
|
|
3031
|
+
maxlength?: number; // Default: 200
|
|
3032
|
+
transform?: (value: string) => string;
|
|
3033
|
+
validate?: (text: string) => boolean | string;
|
|
3034
|
+
cache?: boolean; // Form caching support
|
|
3035
|
+
onPressEnter?: () => void;
|
|
3036
|
+
inputStyleType?: "bordered" | "borderless" | "underline";
|
|
3037
|
+
}
|
|
3038
|
+
\`\`\`
|
|
3039
|
+
Key features:
|
|
3040
|
+
- Real-time transformation (transform)
|
|
3041
|
+
- Automatic cache key generation: \${label}-\${desc}-text
|
|
3042
|
+
- Length validation and custom validation
|
|
3043
|
+
- Various input styles supported
|
|
3044
|
+
|
|
3045
|
+
### 2. Field.TextArea
|
|
3046
|
+
|
|
3047
|
+
\`\`\`typescript
|
|
3048
|
+
interface TextAreaProps {
|
|
3049
|
+
// Same basic props as Text +
|
|
3050
|
+
rows?: number; // Default: 3
|
|
3051
|
+
maxlength?: number; // Default: 1000
|
|
3052
|
+
}
|
|
3053
|
+
\`\`\`
|
|
3054
|
+
Key features:
|
|
3055
|
+
- Multi-line text input
|
|
3056
|
+
- Adjustable height (rows)
|
|
3057
|
+
- Longer maximum length than Text
|
|
3058
|
+
|
|
3059
|
+
### 3. Field.Price (to be deprecated)
|
|
3060
|
+
|
|
3061
|
+
\`\`\`typescript
|
|
3062
|
+
interface PriceProps {
|
|
3063
|
+
// Similar to Text but specialized for prices
|
|
3064
|
+
maxlength?: number; // Default: 80
|
|
3065
|
+
placeholder?: string; // Default: "~ \${l('shared.priceUnit')}"
|
|
3066
|
+
}
|
|
3067
|
+
\`\`\`
|
|
3068
|
+
Key features:
|
|
3069
|
+
- Automatic removal of commas and spaces
|
|
3070
|
+
- Automatic price unit placeholder
|
|
3071
|
+
- Marked as "delete" in comments - legacy component
|
|
3072
|
+
|
|
3073
|
+
## List Management Components
|
|
3074
|
+
|
|
3075
|
+
### 4. Field.List
|
|
3076
|
+
|
|
3077
|
+
\`\`\`typescript
|
|
3078
|
+
interface ListProps<Item> {
|
|
3079
|
+
label?: string;
|
|
3080
|
+
value: Item[];
|
|
3081
|
+
onChange: (value: Item[]) => void;
|
|
3082
|
+
onAdd: () => void;
|
|
3083
|
+
renderItem: (item: Item, idx: number) => ReactNode;
|
|
3084
|
+
}
|
|
3085
|
+
\`\`\`
|
|
3086
|
+
Key features:
|
|
3087
|
+
- Generic type supporting all item types
|
|
3088
|
+
- Custom rendering for each item
|
|
3089
|
+
- Automatic delete button addition
|
|
3090
|
+
- Automatic divider insertion
|
|
3091
|
+
|
|
3092
|
+
### 5. Field.TextList
|
|
3093
|
+
|
|
3094
|
+
\`\`\`typescript
|
|
3095
|
+
interface TextListProps {
|
|
3096
|
+
value: string[];
|
|
3097
|
+
onChange: (value: string[]) => void;
|
|
3098
|
+
minlength?: number; // Minimum array length, Default: 0
|
|
3099
|
+
maxlength?: number; // Maximum array length, Default: 50
|
|
3100
|
+
minTextlength?: number; // Minimum individual text length, Default: 2
|
|
3101
|
+
maxTextlength?: number; // Maximum individual text length, Default: 200
|
|
3102
|
+
transform?: (value: string) => string;
|
|
3103
|
+
validate?: (text: string) => boolean | string;
|
|
3104
|
+
cache?: boolean;
|
|
3105
|
+
}
|
|
3106
|
+
\`\`\`
|
|
3107
|
+
Key features:
|
|
3108
|
+
- Drag and drop for order changes
|
|
3109
|
+
- Individual text input validation
|
|
3110
|
+
- Cache key: \${label}-\${desc}-textList-[\${idx}]
|
|
3111
|
+
- Conditional "New" button display based on maximum length limit
|
|
3112
|
+
|
|
3113
|
+
### 6. Field.Tags
|
|
3114
|
+
|
|
3115
|
+
\`\`\`typescript
|
|
3116
|
+
interface TagsProps {
|
|
3117
|
+
value: string[];
|
|
3118
|
+
onChange: (value: string[]) => void;
|
|
3119
|
+
minlength?: number; // Default: 0
|
|
3120
|
+
maxlength?: number; // Default: 50
|
|
3121
|
+
minTextlength?: number; // Default: 2
|
|
3122
|
+
maxTextlength?: number; // Default: 10 (tags are shorter)
|
|
3123
|
+
transform?: (value: string) => string;
|
|
3124
|
+
validate?: (text: string) => boolean | string;
|
|
3125
|
+
}
|
|
3126
|
+
\`\`\`
|
|
3127
|
+
Key features:
|
|
3128
|
+
- Tag style UI (includes # prefix)
|
|
3129
|
+
- Inline editing mode
|
|
3130
|
+
- Creates additional input field when clicked
|
|
3131
|
+
- Cancel editing with ESC key
|
|
3132
|
+
- Complete tag addition with Enter/Blur
|
|
3133
|
+
|
|
3134
|
+
## Numeric Input Components
|
|
3135
|
+
|
|
3136
|
+
### 7. Field.Number
|
|
3137
|
+
|
|
3138
|
+
\`\`\`typescript
|
|
3139
|
+
interface NumberProps {
|
|
3140
|
+
value: number | null;
|
|
3141
|
+
onChange: (value: number) => void;
|
|
3142
|
+
min?: number;
|
|
3143
|
+
max?: number;
|
|
3144
|
+
unit?: string;
|
|
3145
|
+
transform?: (value: number) => number;
|
|
3146
|
+
validate?: (text: number) => boolean | string;
|
|
3147
|
+
formatter?: (value: string) => string; // Display format
|
|
3148
|
+
parser?: (value: string) => string; // Parsing format
|
|
3149
|
+
cache?: boolean;
|
|
3150
|
+
}
|
|
3151
|
+
\`\`\`
|
|
3152
|
+
Key features:
|
|
3153
|
+
- Automatic number validation and min/max checks
|
|
3154
|
+
- Customizable display format with formatter/parser
|
|
3155
|
+
- Unit display support
|
|
3156
|
+
- Cache key: \${label}-\${desc}-number
|
|
3157
|
+
|
|
3158
|
+
### 8. Field.DoubleNumber
|
|
3159
|
+
|
|
3160
|
+
\`\`\`typescript
|
|
3161
|
+
interface DoubleNumberProps {
|
|
3162
|
+
value: [number, number] | null;
|
|
3163
|
+
onChange: (value: [number, number]) => void;
|
|
3164
|
+
min?: [number, number] | null;
|
|
3165
|
+
max?: [number, number] | null;
|
|
3166
|
+
separator?: ReactNode | string; // Separator between inputs
|
|
3167
|
+
}
|
|
3168
|
+
\`\`\`
|
|
3169
|
+
Key features:
|
|
3170
|
+
- Range input (start-end values)
|
|
3171
|
+
- Independent min/max validation for each
|
|
3172
|
+
- Custom separator (e.g., "~", "-")
|
|
3173
|
+
- Cache keys: \${label}-\${desc}-number-[0], \${label}-\${desc}-number-[1]
|
|
3174
|
+
|
|
3175
|
+
## Selection Components
|
|
3176
|
+
|
|
3177
|
+
### 9. Field.Switch
|
|
3178
|
+
|
|
3179
|
+
\`\`\`typescript
|
|
3180
|
+
interface SwitchProps {
|
|
3181
|
+
value: boolean;
|
|
3182
|
+
onChange: (value: boolean) => void;
|
|
3183
|
+
onDesc?: string; // Description when true
|
|
3184
|
+
offDesc?: string; // Description when false
|
|
3185
|
+
disabled?: boolean;
|
|
3186
|
+
}
|
|
3187
|
+
\`\`\`
|
|
3188
|
+
Key features:
|
|
3189
|
+
- DaisyUI toggle style
|
|
3190
|
+
- State-specific description text
|
|
3191
|
+
- Uses toggle-accent class
|
|
3192
|
+
|
|
3193
|
+
### 10. Field.ToggleSelect
|
|
3194
|
+
|
|
3195
|
+
\`\`\`typescript
|
|
3196
|
+
interface ToggleSelectProps<I> {
|
|
3197
|
+
items: { label: string; value: I }[] | readonly I[] | I[] | Enum<I>;
|
|
3198
|
+
value: I | null;
|
|
3199
|
+
onChange: (value: I) => void;
|
|
3200
|
+
model?: string; // Model name for internationalization
|
|
3201
|
+
field?: string; // Field name for internationalization
|
|
3202
|
+
validate?: (value: I) => boolean | string;
|
|
3203
|
+
btnClassName?: string;
|
|
3204
|
+
}
|
|
3205
|
+
\`\`\`
|
|
3206
|
+
Key features:
|
|
3207
|
+
- Button-style single selection
|
|
3208
|
+
- Direct Enum type support
|
|
3209
|
+
- Automatic internationalization (l.enum(model, field, item))
|
|
3210
|
+
- Custom button styling
|
|
3211
|
+
|
|
3212
|
+
### 11. Field.MultiToggleSelect
|
|
3213
|
+
|
|
3214
|
+
\`\`\`typescript
|
|
3215
|
+
interface MultiToggleSelectProps<I> {
|
|
3216
|
+
items: Enum<I> | { label: string; value: I }[] | readonly I[] | I[];
|
|
3217
|
+
value: I[];
|
|
3218
|
+
onChange: (value: I[]) => void;
|
|
3219
|
+
minlength?: number;
|
|
3220
|
+
maxlength?: number;
|
|
3221
|
+
validate?: (value: I[]) => boolean | string;
|
|
3222
|
+
}
|
|
3223
|
+
\`\`\`
|
|
3224
|
+
Key features:
|
|
3225
|
+
- Multiple selection button UI
|
|
3226
|
+
- Minimum/maximum selection limit
|
|
3227
|
+
- Array length validation
|
|
3228
|
+
|
|
3229
|
+
## Relational Data Selection Components
|
|
3230
|
+
|
|
3231
|
+
### 12. Field.Parent & Field.ParentId
|
|
3232
|
+
|
|
3233
|
+
\`\`\`typescript
|
|
3234
|
+
interface ParentProps<T, State, Input, Full, Light, Sort, QueryArgs> {
|
|
3235
|
+
sliceName: string; // Target slice name
|
|
3236
|
+
value: Light | null; // Parent returns object
|
|
3237
|
+
onChange: (value?: Light | null) => void;
|
|
3238
|
+
initArgs?: any[]; // Initialization arguments
|
|
3239
|
+
sortOption?: (a: Light, b: Light) => number;
|
|
3240
|
+
renderOption: (model: Light) => ReactNode; // Option renderer
|
|
3241
|
+
renderSelected?: (value: Light) => ReactNode; // Selected item renderer
|
|
3242
|
+
onSearch?: (text: string) => void; // Search handler
|
|
3243
|
+
}
|
|
3244
|
+
|
|
3245
|
+
interface ParentIdProps extends ParentProps {
|
|
3246
|
+
value: string | null; // ParentId returns only ID
|
|
3247
|
+
onChange: (id?: string | null, model?: Light | null) => void;
|
|
3248
|
+
}
|
|
3249
|
+
\`\`\`
|
|
3250
|
+
Key features:
|
|
3251
|
+
- Dynamic store slice integration
|
|
3252
|
+
- Automatic naming convention: \${modelName}List, init\${ModelName}, etc.
|
|
3253
|
+
- Searchable dropdown
|
|
3254
|
+
- Lazy loading (data fetched on onOpen)
|
|
3255
|
+
- Parent: returns full object, ParentId: returns only ID
|
|
3256
|
+
|
|
3257
|
+
### 13. Field.Children & Field.ChildrenId
|
|
3258
|
+
|
|
3259
|
+
\`\`\`typescript
|
|
3260
|
+
interface ChildrenProps extends ParentProps {
|
|
3261
|
+
value: Light[]; // Multiple selection
|
|
3262
|
+
onChange: (value?: Light[] | null) => void;
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
interface ChildrenIdProps extends ChildrenProps {
|
|
3266
|
+
value: string[]; // ID array
|
|
3267
|
+
onChange: (value: string[]) => void;
|
|
3268
|
+
}
|
|
3269
|
+
\`\`\`
|
|
3270
|
+
Key features:
|
|
3271
|
+
- Multiple relationship selection
|
|
3272
|
+
- Same store integration logic as Parent
|
|
3273
|
+
- Automatic initialization (useEffect)
|
|
3274
|
+
|
|
3275
|
+
## Date/Time Components
|
|
3276
|
+
|
|
3277
|
+
### 14. Field.Date
|
|
3278
|
+
|
|
3279
|
+
\`\`\`typescript
|
|
3280
|
+
interface DateProps<Nullable extends boolean> {
|
|
3281
|
+
value: Nullable extends true ? Dayjs | null : Dayjs;
|
|
3282
|
+
onChange: (value: Dayjs) => void;
|
|
3283
|
+
min?: Dayjs;
|
|
3284
|
+
max?: Dayjs;
|
|
3285
|
+
showTime?: boolean; // datetime-local vs date
|
|
3286
|
+
nullable?: boolean;
|
|
3287
|
+
}
|
|
3288
|
+
\`\`\`
|
|
3289
|
+
Key features:
|
|
3290
|
+
- Uses Dayjs objects
|
|
3291
|
+
- Conditional nullable type (using TypeScript generics)
|
|
3292
|
+
- Automatic format change based on showTime
|
|
3293
|
+
- Uses HTML5 date/datetime-local inputs
|
|
3294
|
+
- Includes comment about DaisyUI max value bug
|
|
3295
|
+
|
|
3296
|
+
### 15. Field.DateRange
|
|
3297
|
+
|
|
3298
|
+
\`\`\`typescript
|
|
3299
|
+
interface DateRangeProps<Nullable extends boolean> {
|
|
3300
|
+
from: Nullable extends true ? Dayjs | null : Dayjs;
|
|
3301
|
+
to: Nullable extends true ? Dayjs | null : Dayjs;
|
|
3302
|
+
onChangeFrom: (value: Dayjs) => void;
|
|
3303
|
+
onChangeTo: (value: Dayjs) => void;
|
|
3304
|
+
onChange?: (from: Dayjs, to: Dayjs) => void; // Optional unified handler
|
|
3305
|
+
showTime?: boolean;
|
|
3306
|
+
}
|
|
3307
|
+
\`\`\`
|
|
3308
|
+
Key features:
|
|
3309
|
+
- Individual management of start/end dates
|
|
3310
|
+
- Optional unified change handler
|
|
3311
|
+
- Automatic "From"/"To" label display
|
|
3312
|
+
- Responsive layout (vertical on mobile)
|
|
3313
|
+
|
|
3314
|
+
## File Upload Components
|
|
3315
|
+
|
|
3316
|
+
### 16. Field.Img
|
|
3317
|
+
|
|
3318
|
+
\`\`\`typescript
|
|
3319
|
+
interface ImageProps {
|
|
3320
|
+
sliceName: string; // Determines file upload API
|
|
3321
|
+
value: cnst.File | null;
|
|
3322
|
+
onChange: (file: cnst.File | null) => void;
|
|
3323
|
+
styleType?: "circle" | "square"; // Default: "circle"
|
|
3324
|
+
aspectRatio?: number[]; // Aspect ratio restriction
|
|
3325
|
+
render?: (file: cnst.File) => ReactNode;
|
|
3326
|
+
disabled?: boolean;
|
|
3327
|
+
}
|
|
3328
|
+
\`\`\`
|
|
3329
|
+
Key features:
|
|
3330
|
+
- Dynamic upload API: add\${capitalize(sliceName)}Files
|
|
3331
|
+
- Upload status polling (1-second interval)
|
|
3332
|
+
- Aspect ratio restriction support
|
|
3333
|
+
- Circular/square preview
|
|
3334
|
+
|
|
3335
|
+
### 17. Field.Imgs
|
|
3336
|
+
|
|
3337
|
+
\`\`\`typescript
|
|
3338
|
+
interface ImagesProps {
|
|
3339
|
+
sliceName: string;
|
|
3340
|
+
value: cnst.File[];
|
|
3341
|
+
onChange: (files: cnst.File[]) => void;
|
|
3342
|
+
minlength?: number; // Default: 1
|
|
3343
|
+
maxlength?: number; // Default: 30
|
|
3344
|
+
render?: (file: cnst.File) => ReactNode;
|
|
3345
|
+
}
|
|
3346
|
+
\`\`\`
|
|
3347
|
+
Key features:
|
|
3348
|
+
- Multiple image upload
|
|
3349
|
+
- Batch polling of upload status
|
|
3350
|
+
- Minimum/maximum file count limit
|
|
3351
|
+
- Fixed square style
|
|
3352
|
+
|
|
3353
|
+
### 18. Field.File & Field.Files
|
|
3354
|
+
|
|
3355
|
+
\`\`\`typescript
|
|
3356
|
+
interface FileProps {
|
|
3357
|
+
sliceName: string;
|
|
3358
|
+
value: cnst.File | null; // File is single
|
|
3359
|
+
onChange: (file: cnst.File | null) => void;
|
|
3360
|
+
render?: (file: cnst.File) => ReactNode;
|
|
3361
|
+
}
|
|
3362
|
+
|
|
3363
|
+
interface FilesProps {
|
|
3364
|
+
sliceName: string;
|
|
3365
|
+
value: cnst.File[]; // Files is multiple
|
|
3366
|
+
onChange: (files: cnst.File[]) => void;
|
|
3367
|
+
minlength?: number; // Default: 1
|
|
3368
|
+
maxlength?: number; // Default: 30
|
|
3369
|
+
}
|
|
3370
|
+
\`\`\`
|
|
3371
|
+
Key features:
|
|
3372
|
+
- Support for all file types (beyond images)
|
|
3373
|
+
- Same upload logic as Img/Imgs
|
|
3374
|
+
- Custom file renderer support
|
|
3375
|
+
|
|
3376
|
+
## Rich Text Editor
|
|
3377
|
+
|
|
3378
|
+
### 19. Field.Slate
|
|
3379
|
+
|
|
3380
|
+
\`\`\`typescript
|
|
3381
|
+
interface SlateProps {
|
|
3382
|
+
sliceName: string; // Determines file upload API
|
|
3383
|
+
valuePath: string; // Store path
|
|
3384
|
+
onChange: (value: unknown) => void;
|
|
3385
|
+
addFile: (file: cnst.File | cnst.File[], options?) => void;
|
|
3386
|
+
placeholder?: string;
|
|
3387
|
+
disabled?: boolean;
|
|
3388
|
+
editorHeight?: string;
|
|
3389
|
+
}
|
|
3390
|
+
\`\`\`
|
|
3391
|
+
Key features:
|
|
3392
|
+
- Slate.js-based rich text editor
|
|
3393
|
+
- File drag and drop support
|
|
3394
|
+
- Dynamic store path access
|
|
3395
|
+
- Adjustable height
|
|
3396
|
+
|
|
3397
|
+
### 20. Field.Yoopta
|
|
3398
|
+
|
|
3399
|
+
\`\`\`typescript
|
|
3400
|
+
interface YooptaProps {
|
|
3401
|
+
value: JSON;
|
|
3402
|
+
onChange: (value: JSON) => void;
|
|
3403
|
+
readonly?: boolean;
|
|
3404
|
+
}
|
|
3405
|
+
\`\`\`
|
|
3406
|
+
Key features:
|
|
3407
|
+
- Yoopta editor integration
|
|
3408
|
+
- JSON data format
|
|
3409
|
+
- Read-only mode support
|
|
3410
|
+
|
|
3411
|
+
## Authentication and Contact Components
|
|
3412
|
+
|
|
3413
|
+
### 21. Field.Email
|
|
3414
|
+
|
|
3415
|
+
\`\`\`typescript
|
|
3416
|
+
interface EmailProps {
|
|
3417
|
+
value: string | null;
|
|
3418
|
+
onChange: (value: string) => void;
|
|
3419
|
+
placeholder?: string; // Default: "example@email.com"
|
|
3420
|
+
minlength?: number; // Default: nullable ? 0 : 2
|
|
3421
|
+
maxlength?: number; // Default: 80
|
|
3422
|
+
inputStyleType?: "bordered" | "borderless" | "underline";
|
|
3423
|
+
cache?: boolean;
|
|
3424
|
+
}
|
|
3425
|
+
\`\`\`
|
|
3426
|
+
Key features:
|
|
3427
|
+
- Automatic email format validation
|
|
3428
|
+
- Uses Input.Email component
|
|
3429
|
+
- Cache key: \${label}-\${desc}-email
|
|
3430
|
+
|
|
3431
|
+
### 22. Field.Phone
|
|
3432
|
+
|
|
3433
|
+
\`\`\`typescript
|
|
3434
|
+
interface PhoneProps {
|
|
3435
|
+
value: string | null;
|
|
3436
|
+
onChange: (value: string) => void;
|
|
3437
|
+
maxlength?: number; // Default: 13
|
|
3438
|
+
transform?: (value: string) => string; // Default: formatPhone
|
|
3439
|
+
cache?: boolean;
|
|
3440
|
+
}
|
|
3441
|
+
\`\`\`
|
|
3442
|
+
Key features:
|
|
3443
|
+
- Automatic phone number formatting (formatPhone)
|
|
3444
|
+
- isPhoneNumber validation
|
|
3445
|
+
- Cache key: \${label}-\${desc}-phone
|
|
3446
|
+
|
|
3447
|
+
### 23. Field.Password
|
|
3448
|
+
|
|
3449
|
+
\`\`\`typescript
|
|
3450
|
+
interface PasswordProps {
|
|
3451
|
+
value: string | null;
|
|
3452
|
+
onChange: (value: string) => void;
|
|
3453
|
+
confirmValue?: string | null; // Confirmation input
|
|
3454
|
+
onChangeConfirm?: (value: string) => void;
|
|
3455
|
+
showConfirm?: boolean; // Show confirmation input
|
|
3456
|
+
minlength?: number; // Default: nullable ? 0 : 8
|
|
3457
|
+
maxlength?: number; // Default: 20
|
|
3458
|
+
cache?: boolean;
|
|
3459
|
+
}
|
|
3460
|
+
\`\`\`
|
|
3461
|
+
Key features:
|
|
3462
|
+
- Optional password confirmation input
|
|
3463
|
+
- Automatic match validation
|
|
3464
|
+
- Secure input (masking)
|
|
3465
|
+
- Cache key: \${label}-\${desc}-password
|
|
3466
|
+
|
|
3467
|
+
## Geographic Location Components
|
|
3468
|
+
|
|
3469
|
+
### 24. Field.Coordinate
|
|
3470
|
+
|
|
3471
|
+
\`\`\`typescript
|
|
3472
|
+
interface CoordinateProps {
|
|
3473
|
+
coordinate: cnst.util.Coordinate | null;
|
|
3474
|
+
onChange: (coordinate: cnst.util.Coordinate) => void;
|
|
3475
|
+
mapKey: string; // Google Maps API key
|
|
3476
|
+
mapClassName?: string;
|
|
3477
|
+
disabled?: boolean;
|
|
3478
|
+
}
|
|
3479
|
+
\`\`\`
|
|
3480
|
+
Key features:
|
|
3481
|
+
- Google Maps integration
|
|
3482
|
+
- Coordinate selection by clicking
|
|
3483
|
+
- Automatic marker display (AiTwotoneEnvironment icon)
|
|
3484
|
+
- Default zoom level 3
|
|
3485
|
+
|
|
3486
|
+
### 25. Field.Postcode
|
|
3487
|
+
|
|
3488
|
+
\`\`\`typescript
|
|
3489
|
+
interface PostcodeProps {
|
|
3490
|
+
kakaoKey: string; // Kakao API key
|
|
3491
|
+
address: string | null;
|
|
3492
|
+
onChange: ({
|
|
3493
|
+
address: string;
|
|
3494
|
+
addressEn: string;
|
|
3495
|
+
zipcode: string;
|
|
3496
|
+
coordinate: cnst.util.Coordinate;
|
|
3497
|
+
}) => void;
|
|
3498
|
+
}
|
|
3499
|
+
\`\`\`
|
|
3500
|
+
Key features:
|
|
3501
|
+
- Daum postcode service (react-daum-postcode)
|
|
3502
|
+
- Coordinate conversion using Kakao Maps API
|
|
3503
|
+
- Simultaneous Korean/English address provision
|
|
3504
|
+
- Modal address search
|
|
3505
|
+
|
|
3506
|
+
### 26. Field.KoreanCityDistrict
|
|
3507
|
+
|
|
3508
|
+
\`\`\`typescript
|
|
3509
|
+
interface KoreanCityDistrictProps {
|
|
3510
|
+
city: string | null;
|
|
3511
|
+
onChangeCity: (city: string | null) => void;
|
|
3512
|
+
district: string | null;
|
|
3513
|
+
onChangeDistrict: (district: string | null) => void;
|
|
3514
|
+
disabled?: boolean;
|
|
3515
|
+
}
|
|
3516
|
+
\`\`\`
|
|
3517
|
+
Key features:
|
|
3518
|
+
- Hardcoded Korean region data
|
|
3519
|
+
- Two-level selection (city/province \u2192 district/county)
|
|
3520
|
+
- Includes detailed regions: 25 districts in Seoul, 16 in Busan, etc.
|
|
3521
|
+
- Linked selection (district activates after city selection)
|
|
3522
|
+
|
|
3523
|
+
## Common Patterns and Features
|
|
3524
|
+
|
|
3525
|
+
### 1. Caching System
|
|
3526
|
+
|
|
3527
|
+
Most input components support form data persistence with the cache prop:
|
|
3528
|
+
cacheKey={cache ? \`\${label}-\${desc}-\${componentType}\` : undefined}
|
|
3529
|
+
|
|
3530
|
+
### 2. Validation System
|
|
3531
|
+
|
|
3532
|
+
All components support multi-layer validation:
|
|
3533
|
+
- Basic validation (length, type, format)
|
|
3534
|
+
- Custom validation functions
|
|
3535
|
+
- Internationalized error messages
|
|
3536
|
+
|
|
3537
|
+
### 3. Internationalization
|
|
3538
|
+
|
|
3539
|
+
- Labels, placeholders, error messages all use l() function
|
|
3540
|
+
- Automatic translation for Enum types
|
|
3541
|
+
- Multi-language error message templates
|
|
3542
|
+
|
|
3543
|
+
### 4. Store Integration
|
|
3544
|
+
|
|
3545
|
+
Relational components automatically connect to the store through naming conventions:
|
|
3546
|
+
\`\`\`javascript
|
|
3547
|
+
const names = {
|
|
3548
|
+
model: modelName,
|
|
3549
|
+
modelList: \`\${modelName}List\`,
|
|
3550
|
+
initModel: \`init\${ModelName}\`,
|
|
3551
|
+
};
|
|
3552
|
+
\`\`\`
|
|
3553
|
+
|
|
3554
|
+
### 5. Type Safety
|
|
3555
|
+
|
|
3556
|
+
- Type safety ensured with TypeScript generics
|
|
3557
|
+
- Conditional types for handling nullable properties
|
|
3558
|
+
- Strict props interface definitions
|
|
3559
|
+
|
|
3560
|
+
This comprehensive field library provides a consistent user experience and developer convenience, designed to make complex form compositions simple and safe.
|
|
3561
|
+
2. Data Components (/Data/)
|
|
3562
|
+
|
|
3563
|
+
Purpose: Complete data visualization and management interfaces
|
|
3564
|
+
|
|
3565
|
+
ListContainer
|
|
3566
|
+
|
|
3567
|
+
- type?: "card" | "list" - Display mode selection
|
|
3568
|
+
- columns?: DataColumn<any>[] - Column configuration
|
|
3569
|
+
- tools?: DataTool[] - Toolbar actions
|
|
3570
|
+
- renderDashboard?: (props) => ReactNode - Dashboard customization
|
|
3571
|
+
- renderItem?: (props) => ReactNode - Item renderer
|
|
3572
|
+
|
|
3573
|
+
CardList
|
|
3574
|
+
|
|
3575
|
+
- sliceName: string - Store slice identifier
|
|
3576
|
+
- columns: DataColumn<any>[] - Data column definitions
|
|
3577
|
+
- actions?: DataAction<Light>[] - Item actions
|
|
3578
|
+
- renderItem: (args) => ReactNode - Card renderer
|
|
3579
|
+
- renderLoading?: () => ReactNode - Loading state
|
|
3580
|
+
|
|
3581
|
+
Dashboard
|
|
3582
|
+
|
|
3583
|
+
- summary: { [key: string]: any } - Statistics data
|
|
3584
|
+
- queryMap: { [key: string]: any } - Filter mappings
|
|
3585
|
+
- columns?: string[] - Clickable statistics
|
|
3586
|
+
- hidePresents?: boolean - Display control
|
|
3587
|
+
|
|
3588
|
+
3. Load Components (/Load/)
|
|
3589
|
+
|
|
3590
|
+
Purpose: Data loading and state management with SSR/CSR support
|
|
3591
|
+
|
|
3592
|
+
Page
|
|
3593
|
+
|
|
3594
|
+
- loader: () => Promise<Return> - Data fetching function
|
|
3595
|
+
- render: (data: Return) => ReactNode - Content renderer
|
|
3596
|
+
- loading?: () => ReactNode - Loading state
|
|
3597
|
+
|
|
3598
|
+
Edit
|
|
3599
|
+
|
|
3600
|
+
- edit: ClientEdit<T, Full> | Partial<Full> - Edit data
|
|
3601
|
+
- type?: "modal" | "form" | "empty" - Display mode
|
|
3602
|
+
- sliceName: string - Store slice
|
|
3603
|
+
- onSubmit?: string | ((model: Full) => void) - Submit handler
|
|
3604
|
+
|
|
3605
|
+
Units
|
|
3606
|
+
|
|
3607
|
+
- init: ClientInit<T, L> - Initial data
|
|
3608
|
+
- filter?: (item: L, idx: number) => boolean - Item filtering
|
|
3609
|
+
- sort?: (a: L, b: L) => number - Sorting function
|
|
3610
|
+
- renderItem?: (item: L, idx: number) => ReactNode - Item renderer
|
|
3611
|
+
- pagination?: boolean - Pagination control
|
|
3612
|
+
|
|
3613
|
+
4. Model Components (/Model/)
|
|
3614
|
+
|
|
3615
|
+
Purpose: CRUD operations with modal and inline editing
|
|
3616
|
+
|
|
3617
|
+
EditModal
|
|
3618
|
+
|
|
3619
|
+
- sliceName: string - Store slice identifier
|
|
3620
|
+
- id?: string - Model ID for editing
|
|
3621
|
+
- renderTitle?: ((model: Full) => ReactNode) | string - Title customization
|
|
3622
|
+
- onSubmit?: string | ((model: Full) => void) - Submit handler
|
|
3623
|
+
- onCancel?: string | ((form?: any) => any) - Cancel handler
|
|
3624
|
+
|
|
3625
|
+
ViewModal
|
|
3626
|
+
|
|
3627
|
+
- id: string - Model identifier
|
|
3628
|
+
- renderView: (model: any) => ReactNode - View content renderer
|
|
3629
|
+
- renderAction?: (model: any) => ReactNode - Action buttons
|
|
3630
|
+
|
|
3631
|
+
NewWrapper
|
|
3632
|
+
|
|
3633
|
+
- sliceName: string - Store slice
|
|
3634
|
+
- partial?: Partial<Full> - Default values
|
|
3635
|
+
- modal?: string | null - Modal type
|
|
3636
|
+
|
|
3637
|
+
5. System Components (/System/)
|
|
3638
|
+
|
|
3639
|
+
Purpose: Application-level providers and system utilities
|
|
3640
|
+
|
|
3641
|
+
Provider (CSR)
|
|
3642
|
+
|
|
3643
|
+
- fonts: ReactFont[] - Font configurations
|
|
3644
|
+
- gaTrackingId?: string - Analytics tracking
|
|
3645
|
+
- layoutStyle?: "mobile" | "web" - Layout mode
|
|
3646
|
+
|
|
3647
|
+
Provider (SSR)
|
|
3648
|
+
|
|
3649
|
+
- fonts?: NextFont[] - Next.js font configurations
|
|
3650
|
+
|
|
3651
|
+
SelectLanguage
|
|
3652
|
+
|
|
3653
|
+
- languages?: string[] - Available languages
|
|
3654
|
+
|
|
3655
|
+
6. Only Components (/Only/)
|
|
3656
|
+
|
|
3657
|
+
Purpose: Conditional rendering based on user state and device
|
|
3658
|
+
|
|
3659
|
+
Admin
|
|
3660
|
+
|
|
3661
|
+
- roles?: cnst.AdminRole[] - Required admin roles
|
|
3662
|
+
|
|
3663
|
+
User
|
|
3664
|
+
|
|
3665
|
+
- roles?: cnst.UserRole[] - Required user roles
|
|
3666
|
+
|
|
3667
|
+
Show
|
|
3668
|
+
|
|
3669
|
+
- show?: boolean | cnst.util.Responsive[] - Show conditions
|
|
3670
|
+
|
|
3671
|
+
Mobile/Web
|
|
3672
|
+
|
|
3673
|
+
- No props - Device-based rendering
|
|
3674
|
+
|
|
3675
|
+
7. Editor Components (/Editor/)
|
|
3676
|
+
|
|
3677
|
+
Purpose: Rich text editing capabilities
|
|
3678
|
+
|
|
3679
|
+
Slate
|
|
3680
|
+
|
|
3681
|
+
- addFilesGql: (fileList: FileList, id?: string) => Promise<File[]> - File upload
|
|
3682
|
+
- addFile: (file: cnst.File | cnst.File[], options?) => void - File management
|
|
3683
|
+
- onChange: (value: unknown) => void - Content change handler
|
|
3684
|
+
- defaultValue?: unknown - Initial content
|
|
3685
|
+
- placeholder?: string - Placeholder text
|
|
3686
|
+
- disabled?: boolean - Read-only mode
|
|
3687
|
+
|
|
3688
|
+
SlateContent
|
|
3689
|
+
|
|
3690
|
+
- content: unknown - Slate content to display
|
|
3691
|
+
|
|
3692
|
+
8. Property Component (Property.tsx)
|
|
3693
|
+
|
|
3694
|
+
Purpose: Metadata-driven property editing
|
|
3695
|
+
|
|
3696
|
+
- prop: string - Property name
|
|
3697
|
+
- slice: StoreOf<any, any> - Store slice
|
|
3698
|
+
- renderTemplate?: (form: any) => ReactNode - Custom edit renderer
|
|
3699
|
+
- renderView?: (model: any) => ReactNode - Custom view renderer
|
|
3700
|
+
- modelPath?: string - Model path in store
|
|
3701
|
+
|
|
3702
|
+
Integration Patterns
|
|
3703
|
+
|
|
3704
|
+
Store Integration
|
|
3705
|
+
|
|
3706
|
+
- Components use standardized naming conventions for store slices
|
|
3707
|
+
- Automatic state management through slice integration
|
|
3708
|
+
- Consistent error handling and loading states
|
|
3709
|
+
|
|
3710
|
+
Validation System
|
|
3711
|
+
|
|
3712
|
+
- Built-in validation for all field types
|
|
3713
|
+
- Custom validation function support
|
|
3714
|
+
- Internationalized error messages
|
|
3715
|
+
|
|
3716
|
+
File Management
|
|
3717
|
+
|
|
3718
|
+
- Integrated file upload system
|
|
3719
|
+
- Progress tracking and status management
|
|
3720
|
+
- Multiple file type support with preview
|
|
3721
|
+
|
|
3722
|
+
Responsive Behavior
|
|
3723
|
+
|
|
3724
|
+
- Mobile-first design approach
|
|
3725
|
+
- Adaptive layouts based on screen size
|
|
3726
|
+
- Touch-friendly interactions
|
|
3727
|
+
|
|
3728
|
+
This comprehensive UI library provides everything needed to build sophisticated data management interfaces with consistent user
|
|
3729
|
+
experience and maintainable code architecture.
|
|
3730
|
+
`;
|
|
3981
3731
|
var frameworkAbstract = `
|
|
3982
3732
|
Intro
|
|
3983
3733
|
- Build an all-stack application at once.
|
|
@@ -4057,6 +3807,87 @@ Core ESLint Extensions
|
|
|
4057
3807
|
This configuration creates a robust linting setup that enforces Next.js App Router best practices, maintains clean code
|
|
4058
3808
|
organization, and ensures proper server/client code separation.
|
|
4059
3809
|
`;
|
|
3810
|
+
var componentDefaultDescription = ({
|
|
3811
|
+
modelName,
|
|
3812
|
+
ModelName,
|
|
3813
|
+
exampleFiles,
|
|
3814
|
+
constant,
|
|
3815
|
+
properties
|
|
3816
|
+
}) => `
|
|
3817
|
+
|
|
3818
|
+
|
|
3819
|
+
1. Akan.js \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uAC1C\uC694
|
|
3820
|
+
${frameworkAbstract}
|
|
3821
|
+
|
|
3822
|
+
2. Akan.js\uD504\uB808\uC784\uC6CC\uD06C \uB370\uC774\uD130 \uAE30\uBC18 \uBAA8\uB4C8\uC5D0 \uB300\uD55C \uC124\uBA85
|
|
3823
|
+
${moduleDesription}
|
|
3824
|
+
|
|
3825
|
+
3. Akan.js eslint \uC124\uC815\uC5D0 \uB300\uD55C \uC124\uBA85
|
|
3826
|
+
${eslintDescription}
|
|
3827
|
+
|
|
3828
|
+
4. util/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uC124\uBA85
|
|
3829
|
+
${utilUiDescription}
|
|
3830
|
+
|
|
3831
|
+
5. shared/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uC124\uBA85
|
|
3832
|
+
${shardUiDescription}
|
|
3833
|
+
|
|
3834
|
+
6. ${ModelName}.constant.ts \uD30C\uC77C\uC5D0 \uB300\uD55C \uC815\uBCF4
|
|
3835
|
+
${constant}
|
|
3836
|
+
|
|
3837
|
+
7. ${modelName}\uC5D0\uC11C \uC885\uC18D\uB418\uB294 \uB2E4\uB978 \uBAA8\uB378\uB4E4\uC758 \uD0C0\uC785 \uC815\uC758
|
|
3838
|
+
${properties.map(
|
|
3839
|
+
(property) => `
|
|
3840
|
+
\`\`\`
|
|
3841
|
+
${property.key}.constant.ts
|
|
3842
|
+
|
|
3843
|
+
|
|
3844
|
+
${property.source}
|
|
3845
|
+
\`\`\`
|
|
3846
|
+
`
|
|
3847
|
+
).join("\n\n")}
|
|
3848
|
+
|
|
3849
|
+
|
|
3850
|
+
8. \uC608\uC2DC \uD30C\uC77C\uB4E4
|
|
3851
|
+
${exampleFiles.map(
|
|
3852
|
+
(example) => `
|
|
3853
|
+
Example filename: ${example.filepath}
|
|
3854
|
+
\`\`\`
|
|
3855
|
+
${example.content}
|
|
3856
|
+
\`\`\`
|
|
3857
|
+
`
|
|
3858
|
+
).join("\n\n")}
|
|
3859
|
+
|
|
3860
|
+
|
|
3861
|
+
|
|
3862
|
+
|
|
3863
|
+
|
|
3864
|
+
|
|
3865
|
+
\uC5ED\uD560\uBD80\uC5EC
|
|
3866
|
+
- Akan.js \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C \uAE30\uBC18 Typescript \uC2DC\uB2C8\uC5B4 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C\uC790.
|
|
3867
|
+
|
|
3868
|
+
\uCF54\uB529 \uADDC\uCE59
|
|
3869
|
+
- \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
|
|
3870
|
+
- \uC544\uC774\uCF58: react-icons \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
|
|
3871
|
+
- CSS: tailwind, DaisyUI(btn, input, badge \uAC19\uC740 \uAE30\uBCF8 \uC694\uC18C\uB9CC \uC0AC\uC6A9 \uAC00\uB2A5, card/hero \uAC19\uC740 \uBCF5\uC7A1\uD55C \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 X) \uC0AC\uC6A9
|
|
3872
|
+
- Ui Component: @util/ui \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
|
|
3873
|
+
- \uC870\uAC74\uBD80 \uD074\uB798\uC2A4: clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
|
|
3874
|
+
\uCF54\uB4DC \uC2A4\uD0C0\uC77C
|
|
3875
|
+
- \uC0C9\uC0C1: \uD558\uB4DC\uCF54\uB529(bg-red) \uB300\uC2E0 \uD14C\uB9C8 \uC0C9\uC0C1(bg-primary) \uC0AC\uC6A9
|
|
3876
|
+
- \uC870\uAC74\uBD80 \uB80C\uB354\uB9C1: field && <div>... \uB300\uC2E0 field ? <div>... : null \uC0AC\uC6A9
|
|
3877
|
+
- \uBAA8\uB378 \uC811\uADFC: \uAD6C\uC870\uBD84\uD574\uD560\uB2F9 \uB300\uC2E0 ${modelName}.field \uD615\uC2DD\uC73C\uB85C \uC811\uADFC
|
|
3878
|
+
- \uD0C0\uC785 \uC548\uC804: ${modelName}.constant.ts\uC758 \uC2A4\uD0A4\uB9C8 \uCC38\uC870\uD558\uC5EC \uC5D0\uB7EC \uBC29\uC9C0
|
|
3879
|
+
\uD544\uB4DC \uC811\uADFC \uC804: \uC2A4\uD0A4\uB9C8\uC758 \uC2E4\uC81C \uD544\uB4DC \uB9AC\uC2A4\uD2B8 \uC791\uC131 \uBC0F \uAC80\uD1A0 \uD544\uC218
|
|
3880
|
+
|
|
3881
|
+
\uC5C4\uACA9\uD55C \uC8FC\uC758\uC0AC\uD56D
|
|
3882
|
+
- UI \uD0B7\uC740 \uBB38\uC11C\uC5D0 \uBA85\uC2DC\uB41C \uCEF4\uD3EC\uB10C\uD2B8\uB9CC \uC0AC\uC6A9
|
|
3883
|
+
- \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uC804 \uBB38\uC11C \uD655\uC778 \uBC0F props \uC815\uD655\uD788 \uAC80\uC99D
|
|
3884
|
+
- \uBA85\uC2DC\uB41C \uB8F0 \uC678 \uC784\uC758 \uCD94\uC0C1\uD654 \uAE08\uC9C0
|
|
3885
|
+
- dayjs \uB77C\uC774\uBE0C\uB7EC\uB9AC\uB294 @akanjs/base\uC5D0\uC11C \uB798\uD551\uD558\uC5EC \uC81C\uACF5\uD558\uACE0 \uC788\uC74C.
|
|
3886
|
+
|
|
3887
|
+
|
|
3888
|
+
|
|
3889
|
+
|
|
3890
|
+
`;
|
|
4060
3891
|
var scalarConstantDescription = `
|
|
4061
3892
|
Purpose and Structure
|
|
4062
3893
|
|
|
@@ -4440,7 +4271,7 @@ Target filename: ${modelName}.constant.ts
|
|
|
4440
4271
|
${boilerplate}
|
|
4441
4272
|
\`\`\`
|
|
4442
4273
|
`;
|
|
4443
|
-
var
|
|
4274
|
+
var requestTemplate = ({
|
|
4444
4275
|
sysName,
|
|
4445
4276
|
modelName,
|
|
4446
4277
|
ModelName,
|
|
@@ -4449,78 +4280,56 @@ var requestView = ({
|
|
|
4449
4280
|
properties,
|
|
4450
4281
|
exampleFiles
|
|
4451
4282
|
}) => `
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
5. ${ModelName}.constant.ts \uD30C\uC77C\uC5D0 \uB300\uD55C \uC815\uBCF4
|
|
4469
|
-
${constant}
|
|
4283
|
+
${componentDefaultDescription({
|
|
4284
|
+
sysName,
|
|
4285
|
+
modelName,
|
|
4286
|
+
ModelName,
|
|
4287
|
+
exampleFiles,
|
|
4288
|
+
constant,
|
|
4289
|
+
properties
|
|
4290
|
+
})}
|
|
4291
|
+
\uC694\uCCAD\uC0AC\uD56D
|
|
4292
|
+
- \uC544\uB798 \uC81C\uACF5\uD560 \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uCF54\uB4DC\uC5D0 \uCD94\uAC00\uB85C \uCEF4\uD3EC\uB10C\uD2B8 \uAC1C\uBC1C
|
|
4293
|
+
- ${ModelName}.Template.tsx \uCF54\uB4DC \uC791\uC131
|
|
4294
|
+
- \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984\uC740 \uBAA8\uB378 \uC774\uB984\uC740 \uC2A4\uD0A4\uB9C8\uC5D0 \uAE30\uBC18\uD55C \uAE30\uB2A5\uC5D0 \uCD08\uC810\uC744 \uB450\uACE0 \uC791\uC131
|
|
4295
|
+
- \uC544\uB798 \uC81C\uACF5\uD560 \uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8\uC5D0 \uC788\uB294 General \uCEF4\uD3EC\uB10C\uD2B8 1\uAC1C\uB97C \uC81C\uC678\uD55C \uB514\uC790\uC778 \uCEF4\uD3EC\uB10C\uD2B8 4\uAC1C \uAC1C\uBC1C
|
|
4296
|
+
- \uCD94\uC0C1\uD654 \uD574\uC57C\uD558\uB294 \uACBD\uC6B0\uAC00 \uC788\uC744 \uACBD\uC6B0\uC5D4 \uBB38\uC11C\uB97C \uB2E4\uC2DC \uCC38\uACE0\uD558\uACE0 \uC124\uBA85\uB41C \uB0B4\uC5D0\uC11C \uD574\uACB0\uD574\uC57C\uD568.
|
|
4297
|
+
- \uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8\uC5D0 \uB9DE\uAC8C \uC815\uB9AC\uD574\uC11C \uC81C\uACF5
|
|
4298
|
+
-
|
|
4470
4299
|
|
|
4471
|
-
|
|
4472
|
-
${
|
|
4473
|
-
|
|
4300
|
+
Application name: ${sysName}
|
|
4301
|
+
Model name: ${modelName}
|
|
4302
|
+
Target filename: ${ModelName}.Template.tsx
|
|
4474
4303
|
\`\`\`
|
|
4475
|
-
${property.key}.constant.ts
|
|
4476
4304
|
|
|
4477
|
-
|
|
4478
|
-
${property.source}
|
|
4479
|
-
\`\`\`
|
|
4480
|
-
`
|
|
4481
|
-
).join("\n\n")}
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
7. \uC608\uC2DC \uD30C\uC77C\uB4E4
|
|
4485
|
-
${exampleFiles.map(
|
|
4486
|
-
(example) => `
|
|
4487
|
-
Example filename: ${example.filepath}
|
|
4488
|
-
\`\`\`
|
|
4489
|
-
${example.content}
|
|
4490
4305
|
\`\`\`
|
|
4491
|
-
`
|
|
4492
|
-
).join("\n\n")}
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
\uC5ED\uD560\uBD80\uC5EC
|
|
4500
|
-
- Akan.js \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C \uAE30\uBC18 Typescript \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C
|
|
4501
4306
|
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4307
|
+
|
|
4308
|
+
`;
|
|
4309
|
+
var requestView = ({
|
|
4310
|
+
sysName,
|
|
4311
|
+
modelName,
|
|
4312
|
+
ModelName,
|
|
4313
|
+
boilerplate,
|
|
4314
|
+
constant,
|
|
4315
|
+
properties,
|
|
4316
|
+
exampleFiles
|
|
4317
|
+
}) => `
|
|
4318
|
+
${componentDefaultDescription({
|
|
4319
|
+
sysName,
|
|
4320
|
+
modelName,
|
|
4321
|
+
ModelName,
|
|
4322
|
+
exampleFiles,
|
|
4323
|
+
constant,
|
|
4324
|
+
properties
|
|
4325
|
+
})}
|
|
4519
4326
|
\uC694\uCCAD\uC0AC\uD56D
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
\
|
|
4327
|
+
- \uC544\uB798 \uC81C\uACF5\uD560 \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uCF54\uB4DC\uC5D0 \uCD94\uAC00\uB85C \uCEF4\uD3EC\uB10C\uD2B8 \uAC1C\uBC1C
|
|
4328
|
+
- ${ModelName}.View.tsx \uCF54\uB4DC \uC791\uC131
|
|
4329
|
+
- \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984\uC5D0 ${ModelName}\uC740 \uC0DD\uB7B5\uD558\uBA70, \uB514\uC790\uC778 \uC911\uC810\uC758 \uC774\uB984\uC73C\uB85C \uC791\uC131
|
|
4330
|
+
- \uC544\uB798 \uC81C\uACF5\uD560 \uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8\uC5D0 \uC788\uB294 General \uCEF4\uD3EC\uB10C\uD2B8 1\uAC1C\uB97C \uC81C\uC678\uD55C \uB514\uC790\uC778 \uCEF4\uD3EC\uB10C\uD2B8 4\uAC1C \uAC1C\uBC1C
|
|
4331
|
+
- \uCD94\uC0C1\uD654 \uD574\uC57C\uD558\uB294 \uACBD\uC6B0\uAC00 \uC788\uC744 \uACBD\uC6B0\uC5D4 \uBB38\uC11C\uB97C \uB2E4\uC2DC \uCC38\uACE0\uD558\uACE0 \uC124\uBA85\uB41C \uB0B4\uC5D0\uC11C \uD574\uACB0\uD574\uC57C\uD568.
|
|
4332
|
+
- \uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8\uC5D0 \uB9DE\uAC8C \uC815\uB9AC\uD574\uC11C \uC81C\uACF5
|
|
4524
4333
|
|
|
4525
4334
|
|
|
4526
4335
|
Application name: ${sysName}
|
|
@@ -4528,7 +4337,7 @@ Model name: ${modelName}
|
|
|
4528
4337
|
|
|
4529
4338
|
Target filename: ${ModelName}.View.tsx
|
|
4530
4339
|
\`\`\`
|
|
4531
|
-
|
|
4340
|
+
${boilerplate}
|
|
4532
4341
|
\`\`\`
|
|
4533
4342
|
|
|
4534
4343
|
|
|
@@ -4539,78 +4348,25 @@ var requestUnit = ({
|
|
|
4539
4348
|
ModelName,
|
|
4540
4349
|
constant,
|
|
4541
4350
|
properties,
|
|
4351
|
+
boilerplate,
|
|
4542
4352
|
exampleFiles
|
|
4543
4353
|
}) => `
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
3. Akan.js eslint \uC124\uC815\uC5D0 \uB300\uD55C \uC124\uBA85
|
|
4553
|
-
${eslintDescription}
|
|
4554
|
-
|
|
4555
|
-
4. util/ui \uB0B4 ui\uD0B7\uC5D0 \uB300\uD55C \uC124\uBA85
|
|
4556
|
-
${utilUiDescription}
|
|
4557
|
-
|
|
4558
|
-
5. ${ModelName}.constant.ts \uD30C\uC77C\uC5D0 \uB300\uD55C \uC815\uBCF4
|
|
4559
|
-
${constant}
|
|
4560
|
-
|
|
4561
|
-
6. ${modelName}\uC5D0\uC11C \uC885\uC18D\uB418\uB294 \uB2E4\uB978 \uBAA8\uB378\uB4E4\uC758 \uD0C0\uC785 \uC815\uC758
|
|
4562
|
-
${properties.map(
|
|
4563
|
-
(property) => `
|
|
4564
|
-
\`\`\`
|
|
4565
|
-
${property.key}.constant.ts
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
${property.source}
|
|
4569
|
-
\`\`\`
|
|
4570
|
-
`
|
|
4571
|
-
).join("\n\n")}
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
7. \uC608\uC2DC \uD30C\uC77C\uB4E4
|
|
4575
|
-
${exampleFiles.map(
|
|
4576
|
-
(example) => `
|
|
4577
|
-
Example filename: ${example.filepath}
|
|
4578
|
-
\`\`\`
|
|
4579
|
-
${example.content}
|
|
4580
|
-
\`\`\`
|
|
4581
|
-
`
|
|
4582
|
-
).join("\n\n")}
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
\uC5ED\uD560\uBD80\uC5EC
|
|
4590
|
-
- Akan.js \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C \uAE30\uBC18 Typescript \uC2DC\uB2C8\uC5B4 \uD504\uB860\uD2B8\uC5D4\uB4DC \uAC1C\uBC1C\uC790.
|
|
4354
|
+
${componentDefaultDescription({
|
|
4355
|
+
sysName,
|
|
4356
|
+
modelName,
|
|
4357
|
+
ModelName,
|
|
4358
|
+
exampleFiles,
|
|
4359
|
+
constant,
|
|
4360
|
+
properties
|
|
4361
|
+
})}
|
|
4591
4362
|
|
|
4592
|
-
\uCF54\uB529 \uADDC\uCE59
|
|
4593
|
-
- \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
|
|
4594
|
-
- \uC544\uC774\uCF58: react-icons \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
|
|
4595
|
-
- CSS: DaisyUI (btn, input, badge \uAC19\uC740 \uAE30\uBCF8 \uC694\uC18C\uB9CC \uC0AC\uC6A9 \uAC00\uB2A5, card/hero \uAC19\uC740 \uBCF5\uC7A1\uD55C \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uBD88\uAC00)
|
|
4596
|
-
- \uC870\uAC74\uBD80 \uD074\uB798\uC2A4: clsx \uB77C\uC774\uBE0C\uB7EC\uB9AC \uC0AC\uC6A9
|
|
4597
|
-
\uCF54\uB4DC \uC2A4\uD0C0\uC77C
|
|
4598
|
-
- \uC0C9\uC0C1: \uD558\uB4DC\uCF54\uB529(bg-red) \uB300\uC2E0 \uD14C\uB9C8 \uC0C9\uC0C1(bg-primary) \uC0AC\uC6A9
|
|
4599
|
-
- \uC870\uAC74\uBD80 \uB80C\uB354\uB9C1: field && <div>... \uB300\uC2E0 field ? <div>... : null \uC0AC\uC6A9
|
|
4600
|
-
- \uBAA8\uB378 \uC811\uADFC: \uAD6C\uC870\uBD84\uD574\uD560\uB2F9 \uB300\uC2E0 ${modelName}.field \uD615\uC2DD\uC73C\uB85C \uC811\uADFC
|
|
4601
|
-
- \uD0C0\uC785 \uC548\uC804: ${modelName}.constant.ts\uC758 \uC2A4\uD0A4\uB9C8 \uCC38\uC870\uD558\uC5EC \uC5D0\uB7EC \uBC29\uC9C0
|
|
4602
|
-
\uD544\uB4DC \uC811\uADFC \uC804: \uC2A4\uD0A4\uB9C8\uC758 \uC2E4\uC81C \uD544\uB4DC \uB9AC\uC2A4\uD2B8 \uC791\uC131 \uBC0F \uAC80\uD1A0 \uD544\uC218
|
|
4603
|
-
|
|
4604
|
-
\uC5C4\uACA9\uD55C \uC8FC\uC758\uC0AC\uD56D
|
|
4605
|
-
- UI \uD0B7\uC740 \uBB38\uC11C\uC5D0 \uBA85\uC2DC\uB41C \uCEF4\uD3EC\uB10C\uD2B8\uB9CC \uC0AC\uC6A9
|
|
4606
|
-
- \uCEF4\uD3EC\uB10C\uD2B8 \uC0AC\uC6A9 \uC804 \uBB38\uC11C \uD655\uC778 \uBC0F props \uC815\uD655\uD788 \uAC80\uC99D
|
|
4607
|
-
- \uBA85\uC2DC\uB41C \uB8F0 \uC678 \uC784\uC758 \uCD94\uC0C1\uD654 \uAE08\uC9C0
|
|
4608
|
-
|
|
4609
4363
|
\uC694\uCCAD\uC0AC\uD56D
|
|
4364
|
+
- \uC544\uB798 \uC81C\uACF5\uD560 \uAE30\uBCF8 \uD15C\uD50C\uB9BF \uCF54\uB4DC\uC5D0 \uCD94\uAC00\uB85C \uCEF4\uD3EC\uB10C\uD2B8 \uAC1C\uBC1C
|
|
4610
4365
|
- ${ModelName}.Unit.tsx \uCF54\uB4DC \uC791\uC131
|
|
4611
|
-
- \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984\uC5D0 ModelName\uC740 \uC0DD\uB7B5\uD558\uBA70, \
|
|
4366
|
+
- \uCEF4\uD3EC\uB10C\uD2B8 \uC774\uB984\uC5D0 ${ModelName}\uC740 \uC0DD\uB7B5\uD558\uBA70, \uB514\uC790\uC778 \uC911\uC810\uC758 \uC774\uB984\uC73C\uB85C \uC791\uC131
|
|
4612
4367
|
- \uC608\uC2DC\uD30C\uC77C \uCEF4\uD3EC\uB10C\uD2B8\uC758 \uAE30\uBC18\uD558\uC5EC \uC77C\uBC18\uC801\uC73C\uB85C \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uCEF4\uD3EC\uB10C\uD2B8 1\uAC1C\uC640 \uB514\uC790\uC778\uC801 \uC694\uC18C\uAC00 \uD3EC\uD568\uB41C \uCEF4\uD3EC\uB10C\uD2B8 3\uAC1C \uAC1C\uBC1C
|
|
4613
4368
|
- \uCD94\uC0C1\uD654 \uD574\uC57C\uD558\uB294 \uACBD\uC6B0\uAC00 \uC788\uC744 \uACBD\uC6B0\uC5D4 \uBB38\uC11C\uB97C \uB2E4\uC2DC \uCC38\uACE0\uD558\uACE0 \uC124\uBA85\uB41C \uB0B4\uC5D0\uC11C \uD574\uACB0\uD574\uC57C\uD568.
|
|
4369
|
+
- \uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8\uC5D0 \uB9DE\uAC8C \uC815\uB9AC\uD574\uC11C \uC81C\uACF5
|
|
4614
4370
|
|
|
4615
4371
|
|
|
4616
4372
|
Application name: ${sysName}
|
|
@@ -4618,7 +4374,7 @@ Model name: ${modelName}
|
|
|
4618
4374
|
|
|
4619
4375
|
Target filename: ${ModelName}.Unit.tsx
|
|
4620
4376
|
\`\`\`
|
|
4621
|
-
|
|
4377
|
+
${boilerplate}
|
|
4622
4378
|
\`\`\`
|
|
4623
4379
|
|
|
4624
4380
|
|
|
@@ -5110,7 +4866,7 @@ var ApplicationRunner = class {
|
|
|
5110
4866
|
const chatModel = new import_openai3.ChatOpenAI({ modelName: "gpt-4o", openAIApiKey });
|
|
5111
4867
|
const projectName = await (0, import_prompts5.input)({ message: "please enter project name." });
|
|
5112
4868
|
const projectDesc = await (0, import_prompts5.input)({ message: "please enter project description. (40 ~ 60 characters)" });
|
|
5113
|
-
const spinner = (0,
|
|
4869
|
+
const spinner = (0, import_ora3.default)("Gerating project files...");
|
|
5114
4870
|
const mainPrompt = import_prompts6.PromptTemplate.fromTemplate(requestApplication());
|
|
5115
4871
|
const chain = import_runnables2.RunnableSequence.from([mainPrompt, chatModel, new import_output_parsers.StringOutputParser()]);
|
|
5116
4872
|
const resultOne = await chain.invoke({ projectName, projectDesc });
|
|
@@ -5286,7 +5042,7 @@ var ApplicationScript = class {
|
|
|
5286
5042
|
var ApplicationCommand = class {
|
|
5287
5043
|
applicationScript = new ApplicationScript();
|
|
5288
5044
|
async createApplication(name, start, workspace) {
|
|
5289
|
-
await this.applicationScript.createApplication(name, workspace, { start });
|
|
5045
|
+
await this.applicationScript.createApplication(name.toLowerCase().replace(/ /g, "-"), workspace, { start });
|
|
5290
5046
|
}
|
|
5291
5047
|
async removeApplication(app) {
|
|
5292
5048
|
await this.applicationScript.removeApplication(app);
|
|
@@ -5785,7 +5541,7 @@ CloudCommand = __decorateClass([
|
|
|
5785
5541
|
var LibraryCommand = class {
|
|
5786
5542
|
libraryScript = new LibraryScript();
|
|
5787
5543
|
async createLibrary(name, workspace) {
|
|
5788
|
-
await this.libraryScript.createLibrary(name, workspace);
|
|
5544
|
+
await this.libraryScript.createLibrary(name.toLowerCase().replace(/ /g, "-"), workspace);
|
|
5789
5545
|
}
|
|
5790
5546
|
async removeLibrary(lib) {
|
|
5791
5547
|
await this.libraryScript.removeLibrary(lib);
|
|
@@ -5854,19 +5610,11 @@ var ModuleRunner = class {
|
|
|
5854
5610
|
async createScalarTemplate(sys2, name) {
|
|
5855
5611
|
const akanConfig = await sys2.getConfig();
|
|
5856
5612
|
const scanResult = await sys2.scan({ akanConfig });
|
|
5857
|
-
const names = (0, import_pluralize.default)(name);
|
|
5858
5613
|
await sys2.applyTemplate({
|
|
5859
5614
|
basePath: "./lib/__scalar",
|
|
5860
5615
|
template: "__scalar",
|
|
5861
5616
|
scanResult,
|
|
5862
|
-
dict: {
|
|
5863
|
-
model: name,
|
|
5864
|
-
Model: capitalize(name),
|
|
5865
|
-
models: names,
|
|
5866
|
-
Models: capitalize(names),
|
|
5867
|
-
sysName: sys2.name,
|
|
5868
|
-
SysName: capitalize(sys2.name)
|
|
5869
|
-
}
|
|
5617
|
+
dict: { model: name, Model: capitalize(name), sysName: sys2.name, SysName: capitalize(sys2.name) }
|
|
5870
5618
|
});
|
|
5871
5619
|
await sys2.scan({ akanConfig });
|
|
5872
5620
|
return {
|
|
@@ -5877,22 +5625,39 @@ var ModuleRunner = class {
|
|
|
5877
5625
|
}
|
|
5878
5626
|
};
|
|
5879
5627
|
}
|
|
5628
|
+
async createComponentTemplate(sys2, name, type) {
|
|
5629
|
+
const akanConfig = await sys2.getConfig();
|
|
5630
|
+
const scanResult = await sys2.scan({ akanConfig });
|
|
5631
|
+
await sys2.applyTemplate({
|
|
5632
|
+
basePath: `./lib/${name}__`,
|
|
5633
|
+
template: `module/__Model__.${capitalize(type)}.ts`,
|
|
5634
|
+
scanResult,
|
|
5635
|
+
dict: { model: name, Model: capitalize(name), appName: sys2.name }
|
|
5636
|
+
});
|
|
5637
|
+
await sys2.scan({ akanConfig });
|
|
5638
|
+
return {
|
|
5639
|
+
component: {
|
|
5640
|
+
filename: `${name}.${capitalize(type)}.tsx`,
|
|
5641
|
+
content: sys2.readFile(`lib/${name}__/${capitalize(name)}.${capitalize(type)}.tsx`)
|
|
5642
|
+
}
|
|
5643
|
+
// constant: {
|
|
5644
|
+
// filename: `${name}.constant.ts`,
|
|
5645
|
+
// content: sys.readFile(`lib/__scalar/${name}/${name}.constant.ts`),
|
|
5646
|
+
// },
|
|
5647
|
+
// dictionary: {
|
|
5648
|
+
// filename: `${name}.dictionary.ts`,
|
|
5649
|
+
// content: sys.readFile(`lib/__scalar/${name}/${name}.dictionary.ts`),
|
|
5650
|
+
// },
|
|
5651
|
+
};
|
|
5652
|
+
}
|
|
5880
5653
|
async createModuleTemplate(sys2, name) {
|
|
5881
5654
|
const akanConfig = await sys2.getConfig();
|
|
5882
5655
|
const scanResult = await sys2.scan({ akanConfig });
|
|
5883
|
-
const names = (0, import_pluralize.default)(name);
|
|
5884
5656
|
await sys2.applyTemplate({
|
|
5885
5657
|
basePath: `./lib/${name}`,
|
|
5886
5658
|
template: "module",
|
|
5887
5659
|
scanResult,
|
|
5888
|
-
dict: {
|
|
5889
|
-
model: name,
|
|
5890
|
-
Model: capitalize(name),
|
|
5891
|
-
models: names,
|
|
5892
|
-
Models: capitalize(names),
|
|
5893
|
-
sysName: sys2.name,
|
|
5894
|
-
SysName: capitalize(sys2.name)
|
|
5895
|
-
}
|
|
5660
|
+
dict: { model: name, Model: capitalize(name), sysName: sys2.name, SysName: capitalize(sys2.name) }
|
|
5896
5661
|
});
|
|
5897
5662
|
await sys2.scan({ akanConfig });
|
|
5898
5663
|
return {
|
|
@@ -5939,64 +5704,6 @@ var ModuleRunner = class {
|
|
|
5939
5704
|
}
|
|
5940
5705
|
};
|
|
5941
5706
|
}
|
|
5942
|
-
// async createUnit(sys: App | Lib, modelName: string) {
|
|
5943
|
-
// const modelFileData = getModelFileData(sys.cwdPath, modelName);
|
|
5944
|
-
// const { paths } = getRelatedCnsts(modelFileData.constantFilePath);
|
|
5945
|
-
// const names = { model: modelName, Model: capitalize(modelName), LightModel: `Light${capitalize(modelName)}` };
|
|
5946
|
-
// const prompt = `
|
|
5947
|
-
// 너는 React, Typescript, TailwindCSS를 기반으로 코딩하는 프론트엔드 개발자야.
|
|
5948
|
-
// ${names.Model}이라는 도메인에 대해서 ${names.LightModel} 스키마를 대상으로 react component를 디자인하려고 해. 아래는 현재 보일러플레이트 형태의 컴포넌트야.
|
|
5949
|
-
// \`\`\`
|
|
5950
|
-
// ${modelFileData.unitFileStr}
|
|
5951
|
-
// \`\`\`
|
|
5952
|
-
// ${names.LightModel}은 다음과 같이 ${names.Model} 스키마에서 일부 필드를 추출해서 lightweight fetch된 형태로 설계되어있어.
|
|
5953
|
-
// \`\`\`
|
|
5954
|
-
// ${modelFileData.constantFileStr}
|
|
5955
|
-
// \`\`\`
|
|
5956
|
-
// 아래는 현재 스키마와 연관된 스키마 파일들이야. 스키마 파일들의 코드들을 보고 서로 어떻게 연계 되어있는지 이해하도록 해.
|
|
5957
|
-
// ${
|
|
5958
|
-
// paths
|
|
5959
|
-
// ? new Array(paths.size).fill(0).map((_, index) => {
|
|
5960
|
-
// //순서대로 paths key 추출
|
|
5961
|
-
// const key = Array.from(paths.keys())[index];
|
|
5962
|
-
// const filePath = paths.get(key)?.filePath;
|
|
5963
|
-
// if (!filePath) throw new Error("filePath is undefined");
|
|
5964
|
-
// return `${key}\n\`\`\`${fs.readFileSync(filePath, "utf8")}\`\`\`\`\n\n`;
|
|
5965
|
-
// })
|
|
5966
|
-
// : ""
|
|
5967
|
-
// }
|
|
5968
|
-
// 추가로, 만약에 아이콘 사용이 필요하면 react-icons/bi 라이브러리에서 사용해줘.
|
|
5969
|
-
// 또, 색상을 사용하려고 하면 하드코딩된 색상(bg-red)이 아닌 테마 색상(bg-primary)을 사용해서 작성해줘.
|
|
5970
|
-
// 그리고 optional한 필드는 field && <div>... 가 아닌, field ? <div>... : null 형태로 작성해줘.
|
|
5971
|
-
// css라이브러리는 DaisyUI를 기반으로 작성해주는데, btn, input, badge와 같은 단순한 기본 css는 사용해도 괜찮아. 그런데 card, hero같이 복잡한 컴포넌트는 사용하면 안돼.
|
|
5972
|
-
// 조건부 className이 필요한 경우에는 clsx 라이브러리를 사용해서 작성해야해.
|
|
5973
|
-
// 모델에 대해서 object destructuring은 하지말고 ${modelName}.field 형태로 접근하게 코드를 작성해야해.
|
|
5974
|
-
// ${names.Model}.Unit.Card의 리액트 컴포넌트를 디자인해서 작성해줘.
|
|
5975
|
-
// `;
|
|
5976
|
-
// try {
|
|
5977
|
-
// fs.writeFileSync("./local/prompt.txt", prompt);
|
|
5978
|
-
// const { content } = await streamAi(prompt, (chunk) => {
|
|
5979
|
-
// process.stdout.write(chunk);
|
|
5980
|
-
// });
|
|
5981
|
-
// fs.writeFileSync("./local/result.txt", content);
|
|
5982
|
-
// } catch (error) {
|
|
5983
|
-
// // console.error("Application error:", error);
|
|
5984
|
-
// }
|
|
5985
|
-
// }
|
|
5986
|
-
// async createView(sys: App | Lib, modelName: string) {
|
|
5987
|
-
// const modelFileData = getModelFileData(sys.cwdPath, modelName);
|
|
5988
|
-
// // const modelFileData = getModelFileData(sys.cwdPath, modelName);
|
|
5989
|
-
// // const { paths } = getRelatedCnsts(modelFileData.constantFilePath);
|
|
5990
|
-
// // const names = { model: modelName, Model: capitalize(modelName), LightModel: `Light${capitalize(modelName)}` };
|
|
5991
|
-
// // const prompt = prompt.requestView({
|
|
5992
|
-
// // sysName: sys.name,
|
|
5993
|
-
// // modelName,
|
|
5994
|
-
// // modelDesc: modelFileData.modelDesc,
|
|
5995
|
-
// // modelSchemaDesign: modelFileData.modelSchemaDesign,
|
|
5996
|
-
// // boilerplate: modelFileData.viewFileStr,
|
|
5997
|
-
// // paths,
|
|
5998
|
-
// // });
|
|
5999
|
-
// }
|
|
6000
5707
|
};
|
|
6001
5708
|
|
|
6002
5709
|
// pkgs/@akanjs/cli/src/module/module.script.ts
|
|
@@ -6026,6 +5733,7 @@ var ModuleScript = class {
|
|
|
6026
5733
|
async removeModule(workspace, name) {
|
|
6027
5734
|
}
|
|
6028
5735
|
async createScalar(sys2, name, description, schemaDescription) {
|
|
5736
|
+
await AiSession.init();
|
|
6029
5737
|
await AiSession.init();
|
|
6030
5738
|
const scalarConstantExampleFiles = await sys2.workspace.getScalarConstantFiles();
|
|
6031
5739
|
const { constant, dictionary } = await this.#runner.createScalarTemplate(sys2, name);
|
|
@@ -6046,7 +5754,45 @@ var ModuleScript = class {
|
|
|
6046
5754
|
}
|
|
6047
5755
|
async createTest(workspace, name) {
|
|
6048
5756
|
}
|
|
5757
|
+
async createTemplate(sys2) {
|
|
5758
|
+
await AiSession.init();
|
|
5759
|
+
const libs = await sys2.getModules();
|
|
5760
|
+
const lib = await (0, import_prompts8.select)({
|
|
5761
|
+
message: "Select the lib",
|
|
5762
|
+
choices: libs
|
|
5763
|
+
}).catch((e) => {
|
|
5764
|
+
Logger.error("canceled");
|
|
5765
|
+
return null;
|
|
5766
|
+
});
|
|
5767
|
+
if (!lib)
|
|
5768
|
+
return;
|
|
5769
|
+
const name = lib.split("/").pop();
|
|
5770
|
+
if (!name)
|
|
5771
|
+
return;
|
|
5772
|
+
const { component: template } = await this.#runner.createComponentTemplate(sys2, name, "template");
|
|
5773
|
+
const templateExampleFiles = (await sys2.getTemplatesSourceCode()).filter(
|
|
5774
|
+
(f) => !f.filepath.includes(`${name}.Template.tsx`)
|
|
5775
|
+
);
|
|
5776
|
+
const Name = capitalize(name);
|
|
5777
|
+
const relatedCnsts = getRelatedCnsts(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`);
|
|
5778
|
+
const constant = import_fs10.default.readFileSync(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`, "utf-8");
|
|
5779
|
+
const session = new AiSession();
|
|
5780
|
+
const promptRst = requestTemplate({
|
|
5781
|
+
sysName: sys2.name,
|
|
5782
|
+
modelName: name,
|
|
5783
|
+
ModelName: Name,
|
|
5784
|
+
constant,
|
|
5785
|
+
boilerplate: template.content,
|
|
5786
|
+
properties: relatedCnsts.map((r) => ({ key: r.key, source: r.source })),
|
|
5787
|
+
exampleFiles: randomPicks(templateExampleFiles, Math.min(20, templateExampleFiles.length))
|
|
5788
|
+
});
|
|
5789
|
+
const content = await session.editTypescript(promptRst);
|
|
5790
|
+
import_fs10.default.writeFileSync(`${sys2.cwdPath}/promptTemplate.txt`, promptRst);
|
|
5791
|
+
import_fs10.default.writeFileSync(`${sys2.cwdPath}/resultTemplate.txt`, content);
|
|
5792
|
+
sys2.writeFile(`lib/${name}__/${Name}.Template.tsx`, content);
|
|
5793
|
+
}
|
|
6049
5794
|
async createUnit(sys2) {
|
|
5795
|
+
await AiSession.init();
|
|
6050
5796
|
const libs = await sys2.getModules();
|
|
6051
5797
|
const lib = await (0, import_prompts8.select)({
|
|
6052
5798
|
message: "Select the lib",
|
|
@@ -6060,6 +5806,7 @@ var ModuleScript = class {
|
|
|
6060
5806
|
const name = lib.split("/").pop();
|
|
6061
5807
|
if (!name)
|
|
6062
5808
|
return;
|
|
5809
|
+
const { component: unit } = await this.#runner.createComponentTemplate(sys2, name, "unit");
|
|
6063
5810
|
const Name = capitalize(name);
|
|
6064
5811
|
const unitExampleFiles = (await sys2.getUnitsSourceCode()).filter((f) => !f.filepath.includes(`${name}.Unit.tsx`));
|
|
6065
5812
|
const relatedCnsts = getRelatedCnsts(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`);
|
|
@@ -6071,13 +5818,16 @@ var ModuleScript = class {
|
|
|
6071
5818
|
ModelName: Name,
|
|
6072
5819
|
constant,
|
|
6073
5820
|
properties: relatedCnsts.map((r) => ({ key: r.key, source: r.source })),
|
|
6074
|
-
exampleFiles: randomPicks(unitExampleFiles, Math.min(10, unitExampleFiles.length))
|
|
5821
|
+
exampleFiles: randomPicks(unitExampleFiles, Math.min(10, unitExampleFiles.length)),
|
|
5822
|
+
boilerplate: unit.content
|
|
6075
5823
|
});
|
|
6076
5824
|
const content = await session.editTypescript(promptRst);
|
|
6077
5825
|
import_fs10.default.writeFileSync(`${sys2.cwdPath}/promptUnit.txt`, promptRst);
|
|
6078
5826
|
import_fs10.default.writeFileSync(`${sys2.cwdPath}/resultUnit.txt`, content);
|
|
5827
|
+
sys2.writeFile(`lib/${name}__/${Name}.Unit.tsx`, content);
|
|
6079
5828
|
}
|
|
6080
5829
|
async createView(sys2) {
|
|
5830
|
+
await AiSession.init();
|
|
6081
5831
|
const libs = await sys2.getModules();
|
|
6082
5832
|
const lib = await (0, import_prompts8.select)({
|
|
6083
5833
|
message: "Select the lib",
|
|
@@ -6091,6 +5841,7 @@ var ModuleScript = class {
|
|
|
6091
5841
|
const name = lib.split("/").pop();
|
|
6092
5842
|
if (!name)
|
|
6093
5843
|
return;
|
|
5844
|
+
const { component: view } = await this.#runner.createComponentTemplate(sys2, name, "view");
|
|
6094
5845
|
const viewExampleFiles = (await sys2.getViewsSourceCode()).filter((f) => !f.filepath.includes(`${name}.View.tsx`));
|
|
6095
5846
|
const Name = capitalize(name);
|
|
6096
5847
|
const relatedCnsts = getRelatedCnsts(`${sys2.cwdPath}/lib/${name}/${name}.constant.ts`);
|
|
@@ -6101,12 +5852,14 @@ var ModuleScript = class {
|
|
|
6101
5852
|
modelName: name,
|
|
6102
5853
|
ModelName: Name,
|
|
6103
5854
|
constant,
|
|
5855
|
+
boilerplate: view.content,
|
|
6104
5856
|
properties: relatedCnsts.map((r) => ({ key: r.key, source: r.source })),
|
|
6105
5857
|
exampleFiles: randomPicks(viewExampleFiles, Math.min(20, viewExampleFiles.length))
|
|
6106
5858
|
});
|
|
6107
5859
|
const content = await session.editTypescript(promptRst);
|
|
6108
5860
|
import_fs10.default.writeFileSync(`${sys2.cwdPath}/prompt.txt`, promptRst);
|
|
6109
5861
|
import_fs10.default.writeFileSync(`${sys2.cwdPath}/result.txt`, content);
|
|
5862
|
+
sys2.writeFile(`lib/${name}__/${Name}.View.tsx`, content);
|
|
6110
5863
|
}
|
|
6111
5864
|
};
|
|
6112
5865
|
|
|
@@ -6114,14 +5867,14 @@ var ModuleScript = class {
|
|
|
6114
5867
|
var ModuleCommand = class {
|
|
6115
5868
|
moduleScript = new ModuleScript();
|
|
6116
5869
|
async createModule(sys2, name, workspace) {
|
|
6117
|
-
await this.moduleScript.createModuleTemplate(sys2, name);
|
|
5870
|
+
await this.moduleScript.createModuleTemplate(sys2, lowerlize(name));
|
|
6118
5871
|
}
|
|
6119
5872
|
async removeModule(name, workspace) {
|
|
6120
5873
|
}
|
|
6121
5874
|
async scanModule(name, workspace) {
|
|
6122
5875
|
}
|
|
6123
5876
|
async createScalar(sys2, name, description, schemaDescription, workspace) {
|
|
6124
|
-
await this.moduleScript.createScalar(sys2, name, description, schemaDescription);
|
|
5877
|
+
await this.moduleScript.createScalar(sys2, lowerlize(name), description, schemaDescription);
|
|
6125
5878
|
}
|
|
6126
5879
|
async createService(name, workspace) {
|
|
6127
5880
|
}
|
|
@@ -6133,6 +5886,9 @@ var ModuleCommand = class {
|
|
|
6133
5886
|
async createUnit(sys2, workspace) {
|
|
6134
5887
|
await this.moduleScript.createUnit(sys2);
|
|
6135
5888
|
}
|
|
5889
|
+
async createTemplate(sys2, workspace) {
|
|
5890
|
+
await this.moduleScript.createTemplate(sys2);
|
|
5891
|
+
}
|
|
6136
5892
|
};
|
|
6137
5893
|
__decorateClass([
|
|
6138
5894
|
Target.Public(),
|
|
@@ -6178,6 +5934,11 @@ __decorateClass([
|
|
|
6178
5934
|
__decorateParam(0, Sys()),
|
|
6179
5935
|
__decorateParam(1, Workspace())
|
|
6180
5936
|
], ModuleCommand.prototype, "createUnit", 1);
|
|
5937
|
+
__decorateClass([
|
|
5938
|
+
Target.Public(),
|
|
5939
|
+
__decorateParam(0, Sys()),
|
|
5940
|
+
__decorateParam(1, Workspace())
|
|
5941
|
+
], ModuleCommand.prototype, "createTemplate", 1);
|
|
6181
5942
|
ModuleCommand = __decorateClass([
|
|
6182
5943
|
Commands()
|
|
6183
5944
|
], ModuleCommand);
|
|
@@ -6189,7 +5950,7 @@ var PackageCommand = class {
|
|
|
6189
5950
|
await this.packageScript.version(workspace);
|
|
6190
5951
|
}
|
|
6191
5952
|
async createPackage(name, workspace) {
|
|
6192
|
-
await this.packageScript.createPackage(workspace, name);
|
|
5953
|
+
await this.packageScript.createPackage(workspace, name.toLowerCase().replace(/ /g, "-"));
|
|
6193
5954
|
}
|
|
6194
5955
|
async removePackage(pkg) {
|
|
6195
5956
|
await this.packageScript.removePackage(pkg);
|
|
@@ -6399,7 +6160,7 @@ var WorkspaceScript = class {
|
|
|
6399
6160
|
var WorkspaceCommand = class {
|
|
6400
6161
|
workspaceScript = new WorkspaceScript();
|
|
6401
6162
|
async createWorkspace(name, app, dir) {
|
|
6402
|
-
await this.workspaceScript.createWorkspace(name, app, dir);
|
|
6163
|
+
await this.workspaceScript.createWorkspace(name, app.toLowerCase().replace(/ /g, "-"), dir);
|
|
6403
6164
|
}
|
|
6404
6165
|
async generateMongo(workspace) {
|
|
6405
6166
|
await this.workspaceScript.generateMongo(workspace);
|
|
@@ -6454,5 +6215,5 @@ void runCommands(
|
|
|
6454
6215
|
//! 2. csr폴더를 현 위치로 복사 후 압축 후 삭제
|
|
6455
6216
|
//! execSync를 가져오기 싫으니 일단 2번 방법으로 해보자
|
|
6456
6217
|
//! add path in tsconfig.json
|
|
6457
|
-
//! 파일을 {name}.Unit.tsx에 저장.
|
|
6458
6218
|
//! 파일을 {name}.View.tsx에 저장.
|
|
6219
|
+
//! 파일을 {name}.Unit.tsx에 저장.
|