@fui-org/fui-cli 1.2.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fui-x7kph78r.js +420 -0
- package/dist/fui.js +1 -429
- package/package.json +3 -3
- package/skills/fui/SKILL.md +3 -3
- package/skills/fui-skill-cli/SKILL.md +139 -0
- package/skills/fui-skill-cli/references/INDEX.md +110 -0
- package/skills/fui-skill-cli/references/advanced-techniques.md +168 -0
- package/skills/fui-skill-cli/references/coding-standards.md +112 -0
- package/skills/fui-skill-cli/references/component-design.md +448 -0
- package/skills/fui-skill-cli/references/component-quickref.md +78 -0
- package/skills/fui-skill-cli/references/component-table.md +248 -0
- package/skills/fui-skill-cli/references/components-dialog.md +191 -0
- package/skills/fui-skill-cli/references/components-display.md +141 -0
- package/skills/fui-skill-cli/references/components-echart.md +316 -0
- package/skills/fui-skill-cli/references/components-input.md +335 -0
- package/skills/fui-skill-cli/references/controls-patterns.md +701 -0
- package/skills/fui-skill-cli/references/controls-styling-vocabulary.md +137 -0
- package/skills/fui-skill-cli/references/db-table-design.md +73 -0
- package/skills/fui-skill-cli/references/db-workflow.md +288 -0
- package/skills/fui-skill-cli/references/default-function.md +425 -0
- package/skills/fui-skill-cli/references/design-modes.md +57 -0
- package/skills/fui-skill-cli/references/echart-templates.md +489 -0
- package/skills/fui-skill-cli/references/fastproject.md +99 -0
- package/skills/fui-skill-cli/references/fsheet.md +203 -0
- package/skills/fui-skill-cli/references/fullstack-workflow.md +313 -0
- package/skills/fui-skill-cli/references/module-data-patterns.md +117 -0
- package/skills/fui-skill-cli/references/module-json-anatomy.md +132 -0
- package/skills/fui-skill-cli/references/module-structure.md +141 -0
- package/skills/fui-skill-cli/references/new-session.md +85 -0
- package/skills/fui-skill-cli/references/pdfmake.md +60 -0
- package/skills/fui-skill-cli/references/permission-system.md +150 -0
- package/skills/fui-skill-cli/references/platform-architecture.md +269 -0
- package/skills/fui-skill-cli/references/project-config.md +303 -0
- package/skills/fui-skill-cli/references/project-provisioning.md +278 -0
- package/skills/fui-skill-cli/references/script-map.md +262 -0
- package/skills/fui-skill-cli/references/sql-clr-functions.md +225 -0
- package/skills/fui-skill-cli/references/system-design.md +89 -0
- package/skills/fui-skill-cli/references/tapi-file-api.md +185 -0
- package/skills/fui-skill-cli/references/tapi-permission-patterns.md +156 -0
- package/skills/fui-skill-cli/references/tapi-reference.md +474 -0
- package/skills/fui-skill-cli/references/tools-registry.md +84 -0
- package/skills/fui-skill-cli/references/ui-crosswindow-patterns.md +321 -0
- package/skills/fui-skill-cli/references/ui-dialog-patterns.md +255 -0
- package/skills/fui-skill-cli/references/ui-layout-patterns.md +176 -0
- package/skills/fui-skill-cli/references/ui-patterns.md +303 -0
- package/skills/fui-skill-cli/references/ui-screenshot-review.md +95 -0
- package/skills/fui-skill-cli/references/ui-table-cell-patterns.md +318 -0
- package/skills/fui-skill-cli/references/ui-templates.md +22 -0
- package/skills/fui-skill-cli/references/verification.md +236 -0
- package/skills/fui-skill-cli/references/watcher-patterns.md +163 -0
- package/skills/fui-skill-cli/references/websocket-realtime.md +271 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# module.json Anatomy — data · watch · controls · set
|
|
2
|
+
|
|
3
|
+
> Owns: **the 4 `module.json` blocks (data/watch/controls/set) — roles, interaction, structure checklist**. Action/control syntax: [controls-patterns.md](controls-patterns.md).
|
|
4
|
+
|
|
5
|
+
`module.json` describes one FUI page with exactly **4 top-level blocks**. Runtime internals: [platform-architecture.md](platform-architecture.md). Battle-tested UI patterns (high priority): [ui-patterns.md](ui-patterns.md).
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"data": [/* state + action */],
|
|
10
|
+
"watch": {/* observer → action */},
|
|
11
|
+
"controls": [/* layout UI: container > rows > cols */],
|
|
12
|
+
"set": {/* override config trang (tùy chọn) */}
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Runtime order: `runAction(data)` → `buildModuleUI(controls)` → attach `watch` → merge `set` into page config. All state lives in `vueData`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. `data` — state init + action definitions
|
|
21
|
+
|
|
22
|
+
An **array**, processed top to bottom on page load. Three element kinds:
|
|
23
|
+
|
|
24
|
+
| Object kind | Recognized by | Effect |
|
|
25
|
+
| ------------ | ------------------------------------------------ | ----------------------------------- |
|
|
26
|
+
| State init | No action key (`API`/`CALL`/`IF`...) | Creates reactive var in `vueData` |
|
|
27
|
+
| Named action | Key = function name, value = action object | Reusable action (invoke via `CALL`) |
|
|
28
|
+
| Auto-startup | Standalone `{ "API": ... }` or `{ "CALL": ... }` | **Runs immediately** on load |
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
"data": [
|
|
32
|
+
{ "dsUser": [], "sGroup": null, "dlUserInfo": false },
|
|
33
|
+
{
|
|
34
|
+
"getUser": { "API": "SM_Users_SelectByDepGroup", "IN": { "GroupID": "sGroup" }, "OUT": "dsUser" }
|
|
35
|
+
},
|
|
36
|
+
{ "CALL": "getUser" }
|
|
37
|
+
]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Named actions are callable from `watch`, `controls` or other actions; trailing auto-startup = initial page data.
|
|
41
|
+
|
|
42
|
+
Details: `data[]` declaration + value resolution (string/var/backtick/`{{ }}`/deep key, auto-run, named action, `v_old`) → **[module-data-patterns.md](module-data-patterns.md)**; action engine → [controls-patterns.md](controls-patterns.md); real-world data layout → [ui-patterns.md](ui-patterns.md) §1–2.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 2. `watch` — state change → run action
|
|
47
|
+
|
|
48
|
+
An **object** `{ "varName": action }`; action runs when the var changes.
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
"watch": {
|
|
52
|
+
"sGroup": { "CALL": "getUser" },
|
|
53
|
+
"sDepartment": { "CALL": "getUser" },
|
|
54
|
+
"sModuleID": [ { "CALL": "getSysRight" }, { "CALL": "getFunctionRight" } ]
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- **Cascading filter**: one watch per filter dropdown → table reloads on change.
|
|
59
|
+
- Multiple actions for one var → use an **array**.
|
|
60
|
+
- **`deep-watch`**: tracks nested changes inside object/array (runtime supports the `deep-watch` key).
|
|
61
|
+
|
|
62
|
+
Details: [watcher-patterns.md](watcher-patterns.md) (v_old, deep-watch, cascading), [ui-patterns.md](ui-patterns.md) §3.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 3. `controls` — UI layout (mandatory grid container > rows > cols)
|
|
67
|
+
|
|
68
|
+
An **array** of containers. Runtime builds `container (v-container)` → `rows (v-layout)` → `cols` → each item is a **Control Object**.
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
"controls": [
|
|
72
|
+
{
|
|
73
|
+
"prop": "fluid grid-list-md",
|
|
74
|
+
"rows": [
|
|
75
|
+
{ "prop": "row", "cols": [ /* Control Objects */ ] }
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Control Object keys:
|
|
82
|
+
|
|
83
|
+
| Key | Role |
|
|
84
|
+
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
85
|
+
| `el` | Tag/component: `div`, `v-*` (Vuetify), `f-*`/`t-*` (FUI), `uc-*` (custom) |
|
|
86
|
+
| `attr` | Attributes/directives (`class`, `style`, `v-model`, `v-on:click`) — **use `v-on:click`, NOT `@click`** |
|
|
87
|
+
| `w` | Column width: `1–12` (grid) or `>= 25` (px, **requires `col: { "class": "shrink" }`**). Never 13–24. Required for every item in `cols` |
|
|
88
|
+
| `col` | Wrapping grid column config (`class`, `style`, `v-if`) |
|
|
89
|
+
| `innerHTML` | Content: string (supports `{{ }}`) or array of nested Control Objects |
|
|
90
|
+
|
|
91
|
+
Mandatory: always start with the grid wrapper; nest via `innerHTML` (array), never `children`; put dialogs in a container with `prop: "hidden-container"`.
|
|
92
|
+
|
|
93
|
+
Details: structure & grid → [controls-patterns.md](controls-patterns.md) §6; **allowed class/prop/style (don't invent styles)** → [controls-styling-vocabulary.md](controls-styling-vocabulary.md); picking components → [component-quickref.md](component-quickref.md); layout/table/dialog patterns → [ui-patterns.md](ui-patterns.md), [ui-table-cell-patterns.md](ui-table-cell-patterns.md), [ui-dialog-patterns.md](ui-dialog-patterns.md), [ui-layout-patterns.md](ui-layout-patterns.md).
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 4. `set` — per-page config override (optional)
|
|
98
|
+
|
|
99
|
+
An **object** overriding project config for this page. Runtime merges `project.json` then `set` (module wins) — see [platform-architecture.md](platform-architecture.md) §2.1.
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
"set": {
|
|
103
|
+
"title": "Quản lý sinh viên",
|
|
104
|
+
"menu": false
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Declare only fields differing from the project. Common: `title`, `menu: false` (hide header — sub-window/landing), `menuLeft` (own sidebar), `apiDomain` (different backend for this page). Normal pages **need no `set`**.
|
|
109
|
+
|
|
110
|
+
Full property list: [project-config.md](project-config.md).
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## How the 4 blocks interact
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
URL ?param ──► vueData[param] (inject trước khi data chạy)
|
|
118
|
+
data[] ──► tạo state + action, auto-startup fetch
|
|
119
|
+
controls ──► bind hai chiều vào state (v-model), gọi action (:action / v-on)
|
|
120
|
+
watch ──► state đổi → chạy action → cập nhật state khác → UI re-render
|
|
121
|
+
set ──► quyết định khung trang (title/menu/apiDomain) bao quanh controls
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Typical loop: user acts on `controls` → state changes → `watch` fires → `API` action in `data` → `OUT` updates state → `controls` re-render.
|
|
125
|
+
|
|
126
|
+
## Checklist
|
|
127
|
+
|
|
128
|
+
1. `data[]`: state first → named actions → `{ "CALL": ... }` auto-startup last
|
|
129
|
+
2. `watch`: every filter/dropdown has a watch → reload
|
|
130
|
+
3. `controls`: start with grid wrapper; `w` on every item; dialogs in `hidden-container`; `v-on:click` not `@click`
|
|
131
|
+
4. `set`: only when the page differs from project defaults
|
|
132
|
+
5. Reference state as `vueData.` in controls/attr; valid JSON (no trailing commas)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Module Structure
|
|
2
|
+
|
|
3
|
+
> Owns: project/module tree, per-file duties, `_moduleInfo.json`/`mTitle`, `HTMLOnly`, default meta tags. `uc-*.vue` rules: [component-design.md](component-design.md); `module.json` content: [controls-patterns.md](controls-patterns.md). _(Tier A — loaded with `fui skill get`.)_
|
|
4
|
+
|
|
5
|
+
Use when creating, refactoring or reviewing a module. With workspace access it is the real folder layout; in chat, use it to organize the response without assuming files exist.
|
|
6
|
+
|
|
7
|
+
## Local Structure
|
|
8
|
+
|
|
9
|
+
### Project-level
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
{projectId}/
|
|
13
|
+
|-- _projectInfo.json # Project metadata (ProjectID, ProjectName, Framework, etc.)
|
|
14
|
+
|-- project.json # Full project config (data/watch/controls/set at project scope)
|
|
15
|
+
|-- imports/ # Project-scope import files
|
|
16
|
+
| `-- _imports.json # Declared project-level JS/CSS imports
|
|
17
|
+
|-- components/ # Project-scope Vue components
|
|
18
|
+
| |-- _components.json # Component registry
|
|
19
|
+
| `-- uc-*.vue # Project-level custom components
|
|
20
|
+
|-- modules/ # All modules in this project
|
|
21
|
+
| |-- _modules.json # Module list metadata
|
|
22
|
+
| `-- {moduleId}/ # One folder per module (see module-level below)
|
|
23
|
+
`-- skills/ # FUI skill files (auto-copied on checkout)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Module-level (`modules/{moduleId}/`)
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
{moduleId}/
|
|
30
|
+
|-- _moduleInfo.json # Required: module metadata + mTitle (page title) + HTMLOnly
|
|
31
|
+
|-- module.json # Required: data/watch/controls/set (unused when HTMLOnly=true)
|
|
32
|
+
|-- script.js # Recommended: helper logic for FUN/EXE/chart/transform
|
|
33
|
+
|-- style.css # Optional: module-wide CSS (published via fui module publish css)
|
|
34
|
+
|-- header.html # Full <head> content: <link>, <style>, <script> tags
|
|
35
|
+
|-- body.html # HTMLOnly=false: supplementary body HTML
|
|
36
|
+
| # HTMLOnly=true: entire page content (custom HTML/Vue app)
|
|
37
|
+
|-- imports/ # Module-scope import files
|
|
38
|
+
| `-- _imports.json # Declared module-level JS/CSS imports
|
|
39
|
+
`-- components/ # Optional: custom Vue components
|
|
40
|
+
|-- _components.json # Required when using custom components
|
|
41
|
+
`-- uc-*.vue # Custom components (prefix uc-)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Required: `_moduleInfo.json`, `module.json`. Recommended: `script.js`, `imports/_imports.json`. Optional: `header.html`, `body.html`, `style.css`, `components/`.
|
|
45
|
+
|
|
46
|
+
## Chat Without Workspace
|
|
47
|
+
|
|
48
|
+
- Present the tree as canonical layout, not actual disk state; return each file in its own labeled code block.
|
|
49
|
+
- Ask the user to paste `_moduleInfo.json`, `module.json`, `script.js` or components when a review/patch depends on them. Scope advice to provided files; never invent unseen ones.
|
|
50
|
+
|
|
51
|
+
## File Duties
|
|
52
|
+
|
|
53
|
+
**module.json** — all runtime config in `data`, `watch`, `controls`, `set`; `controls` inside grid wrapper (`container > rows > cols`); business actions in `data`, triggered by `CALL`. Patterns: [`examples/module-patterns.json`](../examples/module-patterns.json); f-table props/header types: [`examples/f-table-patterns.json`](../examples/f-table-patterns.json).
|
|
54
|
+
|
|
55
|
+
**script.js** — complex transforms, chart builders, debounce, parsing; expose functions for `FUN`/`EXE` and template helpers. Prefer a reusable function over large inline `EXE`.
|
|
56
|
+
|
|
57
|
+
**style.css** — module-wide CSS not tied to one component. Publish with `fui module publish css`; an empty file is not auto-cleared by `fui module publish html`. Component-local CSS goes in the component's `<style scoped>`.
|
|
58
|
+
|
|
59
|
+
**\_moduleInfo.json** — keep `ProjectID`, `ModuleID`, `ModuleName`, `Framework` accurate. `mTitle` is the page title (edit it here; sent as `title` by `fui module publish html`). Read `HTMLOnly` before structuring anything.
|
|
60
|
+
|
|
61
|
+
**header.html** — inner `<head>` content only (`<link>`, `<style>`, `<script>`, `<meta>`); no wrapper, no `<title>` (use `mTitle`). `HTMLOnly=false`: usually CSS only; server injects framework and project scripts. `HTMLOnly=true`: bring your own runtime — read [HTMLOnly=true: no library is embedded](#htmlonlytrue-no-library-is-embedded) first. These meta tags are on every page — never repeat them:
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<meta charset="UTF-8" />
|
|
65
|
+
<meta
|
|
66
|
+
name="viewport"
|
|
67
|
+
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"
|
|
68
|
+
/>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- No pinch-zoom → fonts/buttons must be readable and tappable at natural size on mobile.
|
|
72
|
+
- Vuetify breakpoints follow real device CSS pixels.
|
|
73
|
+
- `viewport-fit=cover` → fullscreen/`HTMLOnly` layouts touching top/bottom need `env(safe-area-inset-*)` padding (iOS notch/home indicator).
|
|
74
|
+
|
|
75
|
+
**body.html** — inner `<body>` content only. `HTMLOnly=false`: supplementary HTML beside the Vue runtime, usually empty. `HTMLOnly=true`: the whole page (plain HTML or own Vue app with own `<div id="app">`/`<v-app>`); FUI's default mount point is hidden. Server and publish command strip `<head>`/`<body>` wrappers.
|
|
76
|
+
|
|
77
|
+
**imports/\_imports.json** — module-scope JS/CSS imports; entry `{ name, type, contentType, fileID, scope, sort }`. `sort` = load order: new imports use **>= 40** (40, 50, 60…); 1–39 is reserved for system/framework. Project-scope imports live in `{projectId}/imports/_imports.json`.
|
|
78
|
+
|
|
79
|
+
**components/\_components.json** — registers `uc-*`. Before publish an entry may hold only `comName`; `comID` is server-managed after publish/sync. Never invent `comID`.
|
|
80
|
+
|
|
81
|
+
**components/uc-\*.vue** — `uc-` prefix, kebab-case. Hold component UI complexity here, not in `module.json`. Contract: props in, emits out, slots to extend. No page-specific API/route logic unless the coupling is intentional and unavoidable. `scoped` does not really scope: prefix every selector with a unique class matching the component name ([component-design.md](component-design.md)). No backtick template strings in `<template>`.
|
|
82
|
+
|
|
83
|
+
**\_projectInfo.json** — written on checkout (`ProjectID`, `ProjectName`, `GroupName`, `Framework`, `pDomain`, `fetchedAt`). Read-only.
|
|
84
|
+
|
|
85
|
+
**project.json** — one `data` object of project defaults (`apiDomain`, `login`, `userInfo`, `menu`, `menuLeft`, `menuStyle`, `menuComponent`, `domainSetting`, …). Runtime merges it with `module.json` `set`; module wins, so declare only differences. Fields, menu items, `right` rules: [project-config.md](project-config.md).
|
|
86
|
+
|
|
87
|
+
## Naming
|
|
88
|
+
|
|
89
|
+
- Module folder: project's module ID convention.
|
|
90
|
+
- Use a component in `module.json` via `el: "uc-..."`, props in `attr` with kebab-case names.
|
|
91
|
+
|
|
92
|
+
## HTMLOnly Mode
|
|
93
|
+
|
|
94
|
+
Boolean in `_moduleInfo.json`. **Check it first.**
|
|
95
|
+
|
|
96
|
+
- **false (default)**: runtime reads `module.json` and bootstraps Vue; `uc-*.vue` and `script.js` helpers fully supported.
|
|
97
|
+
- **true**: `module.json` ignored — keep it `data:[], watch:{}, controls:[], set:{}`; FUI `controls`/`data`/`watch` have no effect. `body.html` is the entire page. Use for standalone tools, custom editors, pages needing their own runtime or a non-grid layout.
|
|
98
|
+
- **Full-height**: if the menu shows (not `set.menu: false`) it takes a fixed 48px — subtract 48px more from any root `height: 100vh` / `calc(100vh - Npx)`. See [project-config.md](project-config.md) §menu.
|
|
99
|
+
|
|
100
|
+
#### HTMLOnly=true: no library is embedded
|
|
101
|
+
|
|
102
|
+
Most common mistake; it shows **no error while writing**, only a blank page after deploy. The server emits just three things:
|
|
103
|
+
|
|
104
|
+
1. this module's imports (`{moduleId}/imports/_imports.json`),
|
|
105
|
+
2. module-level StyleCSS (`style.css` + `<style>` of module-level `uc-*.vue`),
|
|
106
|
+
3. the `moduledata` bundle (`$moduleUI` + `script.js` + module-level components).
|
|
107
|
+
|
|
108
|
+
Not embedded, even if the project declares them:
|
|
109
|
+
|
|
110
|
+
| Missing | Symptom |
|
|
111
|
+
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
112
|
+
| Framework V2/V3 — `vue.global.min.js`, `vuetify*.js/css`, `fastproject*.js`, `component*.js`, `defaultfunction*.js` | `Vue is not defined`, `<v-btn>` not rendered, no `f-*`/`t-*` |
|
|
113
|
+
| jQuery, lodash (`_`), `moment`/`dayjs`, `numeral`, `jquery-confirm` | `$ is not defined`, `_ is not defined` |
|
|
114
|
+
| Roboto, Material Design Icons (`mdi-*`) | wrong font, icons as empty boxes |
|
|
115
|
+
| `projectdata` bundle — `$projectData`, `$projectGroupSetting`, project-level components | `apiDomain`/`menu`/`login` undefined; project `uc-*` unknown |
|
|
116
|
+
| Project-level StyleCSS, `projectdefaultstyle.css` | shared project classes gone (incl. `.shrink`) |
|
|
117
|
+
| `<div id="fastProjectAPP">` | no mount point — build your own root in `body.html` |
|
|
118
|
+
|
|
119
|
+
**Declare every needed library in each HTMLOnly module**; project-level declarations do not help. Either:
|
|
120
|
+
|
|
121
|
+
- `fui import new` into the module's `imports/_imports.json` with `--sort` >= 40 (see `fui import new --help`) — preferred: visible in `fui import list` and the `fui module simulate --render` report; or
|
|
122
|
+
- raw `<link>`/`<script>` in `header.html` — flexible, but no command lists them.
|
|
123
|
+
|
|
124
|
+
**[script-map.md](script-map.md) does not apply here**: its "already bundled, no duplicate CDN" list is for `HTMLOnly=false` only. In HTMLOnly the CDN is required, not a duplicate.
|
|
125
|
+
|
|
126
|
+
`fui module simulate --render` renders HTMLOnly modules exactly like production (no framework, projectdata or `#fastProjectAPP`) and warns so; a missing library breaks the screenshot like the real page.
|
|
127
|
+
|
|
128
|
+
## Patterns
|
|
129
|
+
|
|
130
|
+
- **A — simple**: `_moduleInfo.json`, `module.json`, `script.js`, `imports/_imports.json`; no `components/` unless needed.
|
|
131
|
+
- **B — dashboard/report (recommended)**: `module.json` filters + action orchestration; `script.js` conversion/chart utils; `components/uc-*.vue` chart/table presentation; `header.html` module/component CSS. Keeps large `module.json` maintainable.
|
|
132
|
+
- **C — HTMLOnly page**: `_moduleInfo.json` (`HTMLOnly: true`), empty `module.json` skeleton, `header.html` all CSS + JS libraries, `body.html` whole page (plain HTML or self-contained Vue app); `components/`/`script.js` only if needed.
|
|
133
|
+
|
|
134
|
+
## Review Checklist
|
|
135
|
+
|
|
136
|
+
1. `HTMLOnly` checked first (decides which files matter).
|
|
137
|
+
2. false: valid `data/watch/controls/set`? true: `module.json` empty, all content in `body.html`?
|
|
138
|
+
3. Heavy logic in `script.js`, not oversized `EXE`?
|
|
139
|
+
4. Custom UI in `components/uc-*.vue`, registered in `_components.json`?
|
|
140
|
+
5. Imports in `imports/_imports.json`?
|
|
141
|
+
6. `header.html`/`body.html` inner content only (no `<head>`/`<body>`)?
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Open a New Claude Code CLI Session
|
|
2
|
+
|
|
3
|
+
> Owns: **opening another Claude Code CLI session in its own terminal window + resolving its workspace folder**. Talking to running sessions: §5. New project setup: [project-provisioning.md](project-provisioning.md).
|
|
4
|
+
|
|
5
|
+
User says **"new session" / "phiên mới" / "cửa sổ mới" / "mở thêm một session"** → open a new terminal window running Claude Code in the workspace folder.
|
|
6
|
+
|
|
7
|
+
**Do not ask or confirm.** Local, overwrites nothing; a wrong window is just closed.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. Folder — RESOLVE DYNAMICALLY, never hard-code
|
|
12
|
+
|
|
13
|
+
Workspace root differs per machine; **never hard-code an absolute path.** Sources, by priority:
|
|
14
|
+
|
|
15
|
+
1. **User names it** ("open a new session in project X") → use exactly that.
|
|
16
|
+
2. **The `Workspace root:` line** just printed by fui commands (`fui module get`, `fui skill sync`, `fui project sync`…). Most reliable: the workspace actually in use.
|
|
17
|
+
3. **Env var `FUI_MCP_WORKDIR`** — `$env:FUI_MCP_WORKDIR` (PowerShell) / `$FUI_MCP_WORKDIR` (bash). Unset → default `~/.fui-mcp/workspaces`.
|
|
18
|
+
|
|
19
|
+
None yields a folder → **ask the user**, don't guess.
|
|
20
|
+
|
|
21
|
+
Session for **one project** → `{workspaceRoot}/{projectId}`; general work → `{workspaceRoot}` itself.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 2. Command per OS
|
|
26
|
+
|
|
27
|
+
**Windows (PowerShell)** — most common:
|
|
28
|
+
|
|
29
|
+
```powershell
|
|
30
|
+
powershell -Command "Start-Process powershell -ArgumentList '-NoExit', '-Command', 'cd ''<THƯ-MỤC>''; claude --rc'"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**macOS:**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
osascript -e 'tell app "Terminal" to do script "cd \"<THƯ-MỤC>\" && claude --rc"'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Linux** (swap `gnome-terminal` for the terminal in use):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
gnome-terminal -- bash -c 'cd "<THƯ-MỤC>" && claude --rc; exec bash'
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Team default is **`claude --rc`**. If the user gives other flags (`-c`, `-r`, `--resume <id>`…) or an opening prompt, substitute them.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 3. Verify before reporting success
|
|
50
|
+
|
|
51
|
+
The open command **returns immediately** — "finished" does NOT mean the session opened. Check once more:
|
|
52
|
+
|
|
53
|
+
```powershell
|
|
54
|
+
Get-Process powershell -ErrorAction SilentlyContinue | Sort-Object StartTime -Descending |
|
|
55
|
+
Select-Object -First 3 Id, StartTime, MainWindowTitle | Format-Table -AutoSize
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
ps -eo pid,lstart,args | grep -i "[c]laude" | tail -3
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Report **PID + folder**. No new process ⇒ say it failed; **never report success** (the user would hunt for a nonexistent window).
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 4. Rules
|
|
67
|
+
|
|
68
|
+
**The user's flags are right; do NOT verify them.** No `claude --help` "check", no swapping in flags you prefer, no warnings.
|
|
69
|
+
|
|
70
|
+
> Precedent: `claude --rc --help` gave exit 255 + Usage — **not** proof `--rc` is wrong; `--help` was consumed as `--rc`'s value. A broken test rejecting a working setup is worse than none. Don't repeat it.
|
|
71
|
+
|
|
72
|
+
**Keep the quoting.** `''<path>''` is PowerShell single-quote escaping that survives `cmd → powershell → powershell` and makes paths **with spaces** work. Removing it breaks exactly that case.
|
|
73
|
+
|
|
74
|
+
**Keep `-NoExit`** (`exec bash` on Linux): otherwise the window closes when the Claude session ends, unreadable.
|
|
75
|
+
|
|
76
|
+
**Windows: go through `powershell`.** `claude` is usually `claude.ps1` (not `.exe`), so `cmd` can't run it.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 5. The new session is an INDEPENDENT process
|
|
81
|
+
|
|
82
|
+
- **Own session state**: active module target, skill-loaded flag, approvals… are separate (one session file per PID). The new session must run `fui skill get` and `fui use` itself.
|
|
83
|
+
- **Loads the newest build**: if fui code was just changed and the current session still runs the old build, the new session runs the new one — a way to **verify a newly added command** without restarting the in-progress session.
|
|
84
|
+
- **You cannot type into that window.** Communicate via `ListAgents` → `SendMessage` (it appears as a peer session).
|
|
85
|
+
- **Permissions are per session.** Never ask another session to run an action blocked here — that routes around the user's decision.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# PDF Generation with pdfmake
|
|
2
|
+
|
|
3
|
+
> Owns: **`f-pdfmake`: docDefinition, Vietnamese fonts, print/download PDF**.
|
|
4
|
+
|
|
5
|
+
Complex PDFs with `pdfmake` in FUI (via the `f-pdfmake` component).
|
|
6
|
+
|
|
7
|
+
## Dynamic Tables
|
|
8
|
+
|
|
9
|
+
Map a data array to table rows:
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
body: [
|
|
13
|
+
[
|
|
14
|
+
{ text: "STT", bold: true },
|
|
15
|
+
{ text: "Name", bold: true },
|
|
16
|
+
],
|
|
17
|
+
...data.items.map((item) => [item.index, item.name]),
|
|
18
|
+
];
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## SVG Checkboxes
|
|
22
|
+
|
|
23
|
+
Unicode (☑/☐) may not render in some PDF fonts. Use SVG paths:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
const checkedSvg = '<svg ...>...</svg>';
|
|
27
|
+
const uncheckedSvg = '<svg ...>...</svg>';
|
|
28
|
+
|
|
29
|
+
{
|
|
30
|
+
svg: item.isChecked ? checkedSvg : uncheckedSvg,
|
|
31
|
+
width: 14
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Complex Layouts
|
|
36
|
+
|
|
37
|
+
Use `columns` for layouts a table can't handle (e.g. checkbox beside text):
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
{
|
|
41
|
+
columns: [
|
|
42
|
+
{ svg: checkedSvg, width: 14 },
|
|
43
|
+
{ text: " Label text", width: "*" },
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Signature Section Table
|
|
49
|
+
|
|
50
|
+
Use a nested table for an aligned signature block:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
table: {
|
|
54
|
+
widths: ['16%', '16%', '16%', '16%', '16%', '16%'],
|
|
55
|
+
body: [
|
|
56
|
+
[{ text: 'Title', colSpan: 3 }, {}, {}, { text: 'Title', colSpan: 3 }, {}, {}],
|
|
57
|
+
['Sign 1', 'Sign 2', 'Sign 3', 'Sign 4', 'Sign 5', 'Sign 6']
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Permissions — SystemRight & FunctionRight
|
|
2
|
+
|
|
3
|
+
> Owns: **`SystemRight` vs `FunctionRight`, `rightTest`, `v-if`/menu guards, the 8 right-definition commands**. SP-body checks: [tapi-permission-patterns.md](tapi-permission-patterns.md).
|
|
4
|
+
|
|
5
|
+
FUI has **2 independent right types; neither replaces the other**. Mixing them up is a common bug in `v-if`, menu `right`, and SP checks.
|
|
6
|
+
|
|
7
|
+
## User asks about "permissions"/"rights" — mandatory
|
|
8
|
+
|
|
9
|
+
Never answer from guesses or previously read code/schema; fetch **live**:
|
|
10
|
+
|
|
11
|
+
1. `fui right system list` + `fui right function list` → **current** definitions (never infer from variable names/old comments).
|
|
12
|
+
2. `fui schema --search <kw>` (`right`/`quyen`/`role`/`permission`/`phanquyen`) → does the project have its **own permission tables**? These differ from `acc.tblSysRight`/`acc.tblFunction` (shared DEFINITION catalog, not per-user assignment). Many projects add assignment tables per module/screen/CRUD op — check before concluding "only SystemRight/FunctionRight".
|
|
13
|
+
3. Combine both sources before answering or designing permission logic.
|
|
14
|
+
|
|
15
|
+
## 🔴 A right code must EXIST before guarding with it
|
|
16
|
+
|
|
17
|
+
`"v-if": "vueData.user.FunctionRight.includes('42')"` or `"right": {"FunctionRight": ["42"]}` **does not create** 42. Not in the project's `tblFunction` → no user can hold it → `rightTest()` (`_.intersection`) always `false` → **button/menu vanishes, no JS error, no `[Vue warn]`**; only users report "button missing".
|
|
18
|
+
|
|
19
|
+
Why it survives verification:
|
|
20
|
+
|
|
21
|
+
1. **Preview lies.** `fui module simulate` and `--render` **grant the preview user exactly the codes scanned from the module** (so menus don't vanish wrongly) — invented codes still render. Both check the cache and print `🚨 FunctionRight CHƯA ĐƯỢC ĐỊNH NGHĨA…`; **read that line, not just the image**.
|
|
22
|
+
2. **SP can't help.** `@sys_FunctionRight` holds only codes **actually granted**; a missing code never matches.
|
|
23
|
+
3. **Never infer codes from names/old comments.** Only truth: `fui right function list` / `fui right system list`.
|
|
24
|
+
|
|
25
|
+
| When | Do |
|
|
26
|
+
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
27
|
+
| Start permission work on a project | `fui right function list` + `fui right system list` — also writes cache `{projectId}/_db/rights.json` **keyed by `apiName`**, the only thing no-live-call commands can check against. Multi-alias → **run per alias**; never check one alias's entries against another |
|
|
28
|
+
| Module/menu needs a missing right | `fui right function new` (or `fui right system new`) **first**, then guard — never "create later" |
|
|
29
|
+
| After editing a guarded module.json | `fui module validate` — codes missing from cache → **warning** with a ready-to-copy `fui right function new` command |
|
|
30
|
+
|
|
31
|
+
`fui module validate` reads local files only: **no `fui right * list` run yet → no cache, and it says it cannot check** instead of silently passing. `SystemRight 9` (Project Admin) is a platform constant — always valid, never warned.
|
|
32
|
+
|
|
33
|
+
## The 2 types
|
|
34
|
+
|
|
35
|
+
| | `SystemRight` | `FunctionRight` |
|
|
36
|
+
| ------------------ | ------------------------------------------------------------------ | -------------------------------------------------------- |
|
|
37
|
+
| **Nature** | User's **rank** in a project | **Per-function** permission |
|
|
38
|
+
| **Type** | One integer `0–9` | Code array (string[]) |
|
|
39
|
+
| **Answers** | "Who are you?" (Users, Managers, Administrators, Project Admin...) | "What may you do?" (view report, order, pay...) |
|
|
40
|
+
| **Defined in** | `tblSysRight` — project-set `Note` (rank name) per level | `tblFunction` — `FunctionCode` (number) + `FunctionName` |
|
|
41
|
+
| **Assigned** | Exactly 1 level per project | 0..N codes, independent of rank |
|
|
42
|
+
| **Client runtime** | `vueData.user.SystemRight` (number) | `vueData.user.FunctionRight` (string array) |
|
|
43
|
+
| **SP-side** | `@sys_SystemRight` | `@sys_FunctionRight` (string like `[10][20]`) |
|
|
44
|
+
|
|
45
|
+
`SystemRight` ≈ fixed job title (Staff = 1, Manager = 5, Project Admin = 9). `FunctionRight` ≈ per-person checklist regardless of title (Staff may get "Payment"; a Manager may lack "Delete data").
|
|
46
|
+
|
|
47
|
+
- Show/hide a whole UI area by rank (admin area) → `SystemRight`
|
|
48
|
+
- Toggle a specific button/flow ("Approve", "Export report") regardless of rank → `FunctionRight`
|
|
49
|
+
- Many screens use **both** (AND) — see the `right` example in `project-config.md`.
|
|
50
|
+
|
|
51
|
+
## Storage — central permission DB (alias `acc`)
|
|
52
|
+
|
|
53
|
+
Shared by all FUI projects:
|
|
54
|
+
|
|
55
|
+
- **`tblModules`** — one row per project, keyed by `APIName` (= project apiName/alias)
|
|
56
|
+
- **`tblSysRight`** — `SystemRight` levels (0–9) of **one project** + `Note`; `9` always **Project Admin**
|
|
57
|
+
- **`tblFunction`** — `FunctionRight` definitions (`FunctionCode` + `FunctionName`) of **one project** — catalog of assignable functions, not per-user assignment
|
|
58
|
+
|
|
59
|
+
> **Assigning** levels/codes to users is a separate admin operation, outside the 8 commands below (they manage **definitions** only).
|
|
60
|
+
|
|
61
|
+
### ⚠️ Not `UserRight` — right to EDIT a project in the FUI IDE
|
|
62
|
+
|
|
63
|
+
`UserRight` in `tblA_UserProject` is a **second**, similarly named system: right to **edit the project in the FUI IDE**.
|
|
64
|
+
|
|
65
|
+
| | `SystemRight` / `FunctionRight` | `UserRight` |
|
|
66
|
+
| ------------ | --------------------------------------------- | --------------------------------------------------------------------------- |
|
|
67
|
+
| Scope | **Whole app** — one level per user | **Per project** |
|
|
68
|
+
| Stored in | `acc.tblSysRight` / `acc.tblFunction` | `tblA_UserProject` (FUI platform DB, not `acc`) |
|
|
69
|
+
| Runtime read | `vueData.user.SystemRight` / `.FunctionRight` | none — FUI IDE only |
|
|
70
|
+
| Commands | 8 `fui right …` below | 5 `fui user …` → [project-provisioning.md](project-provisioning.md) §Step 6 |
|
|
71
|
+
|
|
72
|
+
The FUI IDE _is itself a FUI app_ (project `fp`), so `SystemRight` **on `fp`** is the developer's IDE right. Both axes **AND** (from real SP bodies):
|
|
73
|
+
|
|
74
|
+
| IDE operation | Condition |
|
|
75
|
+
| ----------------------------------------------------- | ------------------------------------------ |
|
|
76
|
+
| Create project (`fui project new`) | `SystemRight >= 3` on `fp` |
|
|
77
|
+
| Edit project metadata (`fui project update`) | `SystemRight >= 2` **and** `UserRight > 2` |
|
|
78
|
+
| Publish `project.json` (`fui project publish-config`) | `SystemRight >= 2` **and** `UserRight > 2` |
|
|
79
|
+
| Create/edit/publish modules (`fui module …`) | `SystemRight >= 2` **and** `UserRight > 1` |
|
|
80
|
+
|
|
81
|
+
`UserRight = 3` with `SystemRight = 1` edits nothing, and vice versa. Granting on the wrong axis → "granted but no effect".
|
|
82
|
+
|
|
83
|
+
## Client runtime
|
|
84
|
+
|
|
85
|
+
After declaring `userInfo` ([platform-architecture.md](platform-architecture.md)), FUI fetches and sets:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
vueData.user.SystemRight; // số, vd: 5
|
|
89
|
+
vueData.user.FunctionRight; // mảng chuỗi, vd: ["10", "20"]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**`v-if`:**
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{ "col": { "v-if": "vueData.user.SystemRight >= 5" } }
|
|
96
|
+
{ "col": { "v-if": "vueData.user.FunctionRight.includes('10')" } }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Menu `right`** ([project-config.md](project-config.md)):
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
"right": { "SystemRight": [1, 2, 5, 9], "FunctionRight": ["10", "20"] }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
- `SystemRight`: `user.SystemRight` must be **in** the array
|
|
106
|
+
- `FunctionRight`: `user.FunctionRight` must **share ≥1 code** with the array
|
|
107
|
+
- Both keys → **AND**
|
|
108
|
+
|
|
109
|
+
**`rightTest`** (menu/JS logic):
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
rightTest({ SystemRight: [5, 9], FunctionRight: ["10"] });
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## SP-side
|
|
116
|
+
|
|
117
|
+
tAPI injects `@sys_SystemRight` and `@sys_FunctionRight` into every SP; the client never sends them. **5 SP-body patterns** (access block, 2-tier module admin, `FunctionRight`...): [tapi-permission-patterns.md](tapi-permission-patterns.md).
|
|
118
|
+
|
|
119
|
+
## 8 commands — project right definitions
|
|
120
|
+
|
|
121
|
+
Operate on `acc` (APIs `SM_SystemRight_Select/Update`, `SM_FunctionRight_Select/Update`) with the dev's **userToken** (granted on `acc`) from the current project's `_db/_connections.json` — no extra connection setup. Multi-DB project: token comes from the **connection matching the target `apiName`** (else the default); missing `userToken` there → command fails even if other connections have one. `fui db list` shows which have tokens.
|
|
122
|
+
|
|
123
|
+
Create / edit / delete are **three separate commands**: delete is 🔴 irreversible and is never a boolean flag on a normal op. Flags: `fui right system --help`, `fui right function --help`.
|
|
124
|
+
|
|
125
|
+
| Command | Role | Main inputs | Safety |
|
|
126
|
+
| --------------------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
127
|
+
| `fui right system list` | List `SystemRight` definitions (0–9 + Note) | `apiName?`, `projectId?` | Read-only |
|
|
128
|
+
| `fui right system new` | Define a level that **doesn't exist yet** | `sysRight` (0–9), `note?` (≤50 chars, ignored if `sysRight=9`), `apiName?`, `projectId?` | User-chosen key (no auto ID) → checks `SM_SystemRight_Select` first; existing level = **hard error** pointing to `fui right system update` |
|
|
129
|
+
| `fui right system update` | **Only edit** an existing level | `sysRight` (**required**, from `list`), `note?`, `apiName?`, `projectId?` | ⚠️ Overwrites the note |
|
|
130
|
+
| `fui right system delete` | Delete a level definition | `sysRight` (**required**), `apiName?`, `projectId?` | 🔴 **Server blocks** while any user holds that level |
|
|
131
|
+
| `fui right function list` | List `FunctionRight` (FunctionID/Code/Name) | `apiName?`, `projectId?` | Read-only — only source of real `functionId` |
|
|
132
|
+
| `fui right function new` | Create a `FunctionRight` | `functionCode` (number, unique per project), `functionName?` (≤100 chars), `apiName?`, `projectId?` | Sends `FunctionID: 0` (SP INSERT); server rejects duplicate `functionCode` |
|
|
133
|
+
| `fui right function update` | **Only edit** an existing one | `functionId` (**required**, from `list`), `functionCode`, `functionName?`, `apiName?`, `projectId?` | ⚠️ No `?? 0` fallback — missing `functionId` errors, never silently creates |
|
|
134
|
+
| `fui right function delete` | Delete 1 `FunctionRight` | `functionId` (**required**), `apiName?`, `projectId?` | 🔴 Deletes the function **AND all user assignments** of that code — unrecoverable |
|
|
135
|
+
|
|
136
|
+
**Rules:**
|
|
137
|
+
|
|
138
|
+
1. Before any `delete` — state the consequences and wait for user confirmation.
|
|
139
|
+
2. Create with `new`; edit **requires** the identifier (`functionId` / `sysRight`) from `list` — nothing upserts silently.
|
|
140
|
+
3. `apiName`/`projectId` default to the session's active project — pass `apiName` for **another** project, or when the project has **several connections** and the right belongs to a non-default alias.
|
|
141
|
+
4. Server checks the caller: Select needs `SystemRight >= 2` on `acc`; Update needs higher, or admin (`9`) of the target project.
|
|
142
|
+
|
|
143
|
+
**Platform API** (reference; use the commands):
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
POST {apiDomain}/acc/SM_SystemRight_Select { ModuleID | APIName }
|
|
147
|
+
POST {apiDomain}/acc/SM_SystemRight_Update { ModuleID | APIName, SysRight, Note, Delete }
|
|
148
|
+
POST {apiDomain}/acc/SM_FunctionRight_Select { ModuleID | APIName }
|
|
149
|
+
POST {apiDomain}/acc/SM_FunctionRight_Update { FunctionID, ModuleID | APIName, FunctionCode, FunctionName, Delete }
|
|
150
|
+
```
|