@fui-org/fui-cli 2.1.4 → 2.2.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/README.md +16 -7
- package/dist/fui-xg17j3f9.js +396 -0
- package/dist/fui.js +1 -1
- package/package.json +1 -1
- package/skills/fui/SKILL.md +152 -39
- package/skills/{fui-skill → fui}/assets/projectdefaultstyle.css +489 -489
- package/skills/{fui-skill → fui}/examples/component.vue +162 -162
- package/skills/{fui-skill → fui}/references/INDEX.md +4 -5
- package/skills/{fui-skill → fui}/references/advanced-techniques.md +170 -168
- package/skills/{fui-skill → fui}/references/component-design.md +2 -2
- package/skills/{fui-skill → fui}/references/component-quickref.md +78 -78
- package/skills/{fui-skill → fui}/references/component-table.md +287 -287
- package/skills/{fui-skill → fui}/references/components-dialog.md +191 -191
- package/skills/{fui-skill → fui}/references/components-display.md +141 -141
- package/skills/{fui-skill → fui}/references/components-echart.md +316 -316
- package/skills/{fui-skill → fui}/references/components-input.md +335 -335
- package/skills/{fui-skill → fui}/references/controls-patterns.md +2 -2
- package/skills/{fui-skill → fui}/references/controls-styling-vocabulary.md +173 -173
- package/skills/{fui-skill → fui}/references/db-workflow.md +9 -9
- package/skills/{fui-skill → fui}/references/default-function.md +456 -456
- package/skills/{fui-skill → fui}/references/design-modes.md +57 -57
- package/skills/{fui-skill → fui}/references/echart-templates.md +489 -489
- package/skills/{fui-skill → fui}/references/fastproject.md +99 -99
- package/skills/{fui-skill → fui}/references/fullstack-workflow.md +314 -313
- package/skills/{fui-skill → fui}/references/module-data-patterns.md +117 -117
- package/skills/{fui-skill → fui}/references/module-json-anatomy.md +132 -132
- package/skills/{fui-skill → fui}/references/module-structure.md +144 -144
- package/skills/{fui-skill → fui}/references/new-session.md +3 -20
- package/skills/{fui-skill → fui}/references/pdfmake.md +60 -60
- package/skills/{fui-skill → fui}/references/permission-system.md +1 -1
- package/skills/{fui-skill → fui}/references/platform-architecture.md +269 -269
- package/skills/{fui-skill → fui}/references/project-config.md +303 -303
- package/skills/{fui-skill → fui}/references/project-provisioning.md +4 -4
- package/skills/{fui-skill → fui}/references/script-map.md +262 -262
- package/skills/{fui-skill → fui}/references/sql-clr-functions.md +225 -225
- package/skills/{fui-skill → fui}/references/system-design.md +3 -3
- package/skills/{fui-skill → fui}/references/tapi-permission-patterns.md +156 -156
- package/skills/{fui-skill → fui}/references/tapi-reference.md +474 -474
- package/skills/fui/references/tools-registry.md +214 -0
- package/skills/{fui-skill → fui}/references/ui-crosswindow-patterns.md +321 -321
- package/skills/{fui-skill → fui}/references/ui-dialog-patterns.md +255 -255
- package/skills/{fui-skill → fui}/references/ui-layout-patterns.md +176 -176
- package/skills/{fui-skill → fui}/references/ui-patterns.md +303 -303
- package/skills/{fui-skill → fui}/references/ui-screenshot-review.md +95 -95
- package/skills/{fui-skill → fui}/references/ui-table-cell-patterns.md +318 -318
- package/skills/{fui-skill → fui}/references/verification.md +18 -18
- package/skills/{fui-skill → fui}/references/watcher-patterns.md +163 -163
- package/skills/{fui-skill → fui}/references/websocket-realtime.md +271 -271
- package/skills/{fui-skill → fui}/scripts/component-3.0.js +2715 -2715
- package/skills/{fui-skill → fui}/scripts/component.js +3147 -3147
- package/skills/{fui-skill → fui}/scripts/componentTable-3.0.js +1038 -1038
- package/skills/{fui-skill → fui}/scripts/componentTable.js +891 -891
- package/skills/{fui-skill → fui}/scripts/defaultfunction-3.0.js +866 -866
- package/skills/{fui-skill → fui}/scripts/defaultfunction.js +1051 -1051
- package/skills/{fui-skill → fui}/scripts/fastproject-3.0.js +870 -870
- package/skills/{fui-skill → fui}/scripts/fastproject.js +828 -828
- package/dist/fui-h4z7zhk2.js +0 -381
- package/skills/fui-skill/SKILL.md +0 -139
- package/skills/fui-skill/references/tools-registry.md +0 -84
- /package/skills/{fui-skill → fui}/assets/projectdefaultstyle-3.0.css +0 -0
- /package/skills/{fui-skill → fui}/design-md/airbnb/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/airbnb/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/airtable/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/airtable/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/apple/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/apple/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/asu/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/asu/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/binance/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/binance/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw-m/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw-m/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bugatti/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bugatti/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cal/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cal/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/claude/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/claude/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clay/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clay/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clickhouse/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clickhouse/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cohere/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cohere/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/coinbase/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/coinbase/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/composio/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/composio/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cursor/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cursor/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/elevenlabs/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/elevenlabs/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/expo/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/expo/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ferrari/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ferrari/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/figma/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/figma/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/framer/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/framer/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/fui/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/hashicorp/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/hashicorp/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ibm/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ibm/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/intercom/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/intercom/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/kraken/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/kraken/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lamborghini/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lamborghini/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/linear.app/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/linear.app/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lovable/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lovable/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mastercard/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mastercard/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/meta/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/meta/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/minimax/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/minimax/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mintlify/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mintlify/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/miro/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/miro/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mistral.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mistral.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mongodb/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mongodb/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nike/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nike/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/notion/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/notion/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nvidia/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nvidia/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ollama/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ollama/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/opencode.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/opencode.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/pinterest/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/pinterest/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/playstation/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/playstation/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/posthog/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/posthog/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/raycast/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/raycast/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/renault/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/renault/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/replicate/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/replicate/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/resend/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/resend/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/revolut/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/revolut/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/runwayml/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/runwayml/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sanity/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sanity/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sentry/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sentry/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/shopify/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/shopify/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/slack/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spacex/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spacex/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spotify/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spotify/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/starbucks/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/starbucks/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/stripe/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/stripe/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/supabase/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/supabase/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/superhuman/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/superhuman/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/tesla/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/tesla/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/theverge/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/theverge/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/together.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/together.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/uber/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/uber/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vercel/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vercel/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vodafone/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vodafone/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/voltagent/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/voltagent/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/warp/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/warp/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/webflow/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/webflow/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wired/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wired/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wise/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wise/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/x.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/x.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/zapier/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/zapier/README.md +0 -0
- /package/skills/{fui-skill → fui}/examples/f-table-patterns.json +0 -0
- /package/skills/{fui-skill → fui}/examples/module-patterns.json +0 -0
- /package/skills/{fui-skill → fui}/examples/project-patterns.json +0 -0
- /package/skills/{fui-skill → fui}/references/coding-standards.md +0 -0
- /package/skills/{fui-skill → fui}/references/db-table-design.md +0 -0
- /package/skills/{fui-skill → fui}/references/fsheet.md +0 -0
- /package/skills/{fui-skill → fui}/references/tapi-file-api.md +0 -0
- /package/skills/{fui-skill → fui}/references/ui-templates.md +0 -0
- /package/skills/{fui-skill → fui}/scripts/fechart.js +0 -0
- /package/skills/{fui-skill → fui}/scripts/fsheet.js +0 -0
|
@@ -30,21 +30,21 @@ Tiers differ ~100× in cost per run:
|
|
|
30
30
|
| `Unknown custom element: <f-…>` / empty component | **1** | wrong name or missing required import |
|
|
31
31
|
| Chart draws nothing | **1** (missing `echarts.min.js`/`fechart.js`, most cases) → **5** (0-size canvas) | |
|
|
32
32
|
| Misaligned columns, cramped row | **2** (Σw > 12) | |
|
|
33
|
-
| Dialog won't open | **2** (`⚠
|
|
33
|
+
| Dialog won't open | **2** (`⚠ no opener`) → **3** | |
|
|
34
34
|
| Wrong action order · infinite watch loop · CONFIRM/MESS wrong branch | **3** | |
|
|
35
35
|
| Wrong numbers · `undefined`/`NaN` on page | **3** | almost always `OUT`/mapData on the wrong key, not display |
|
|
36
36
|
| API returns unexpected shape | `fui sp verify` (static, **calls no endpoint**) | infers from the real SP body + generates `--mocks` for tier 3. Only metadata reads: `OBJECT_DEFINITION` when no local `.sql`, `sys.database_permissions` with `--check-grant`; never runs the SP |
|
|
37
37
|
| One `uc-*.vue` wrong | **4** | once proven, remaining bugs are assembly |
|
|
38
38
|
| Horizontal overflow · wrong height · leaking style · bad spacing · broken on mobile | **5** | only tier seeing geometry |
|
|
39
|
-
| Import/asset not loaded | **5**, section `⛔
|
|
40
|
-
| Suspected "platform library bug" | **5**, check `⛔
|
|
39
|
+
| Import/asset not loaded | **5**, section `⛔ MISSING ENV FILES` | environment error — **don't** edit the module for it |
|
|
40
|
+
| Suspected "platform library bug" | **5**, check `⛔ STALE, UNVERIFIED ASSETS` FIRST | stale asset ⇒ on-disk copy ran; CDN conclusions worthless |
|
|
41
41
|
| **Permission-gated** button/menu hidden for real users but shown in preview | **1** after `fui right function list` | undefined code ⇒ `rightTest()` always false, no JS error. Tiers 3/5 **pre-grant** scanned codes so they always show — [permission-system.md](permission-system.md) |
|
|
42
42
|
|
|
43
|
-
**Stale assets:** `--render` revalidates every asset per run (conditional GET; trace shows `N revalidate 304`). `⛔
|
|
43
|
+
**Stale assets:** `--render` revalidates every asset per run (conditional GET; trace shows `N revalidate 304`). `⛔ STALE, UNVERIFIED ASSETS` = network failed, on-disk copy ran ⇒ "library X has a bug" from that run is **unusable**; reconnect and re-render, or `--refresh-assets`. `ℹ️ PLATFORM ASSETS CHANGED` = platform file changed between runs — behavior changed without a `module.json` edit ⇒ look there first.
|
|
44
44
|
|
|
45
|
-
**Read the `--render` report top-down:** `═══
|
|
45
|
+
**Read the `--render` report top-down:** `═══ DIAGNOSIS ═══` groups failures by **where to fix** — `[ENV]` (fix first; the others may be consequences) · `[MODULE]` (module.json/script.js/component) · `[VIEW]` (DOM audit + image). `↪` = cheaper tier that should have caught it.
|
|
46
46
|
|
|
47
|
-
**STOP re-rendering** when `Δ
|
|
47
|
+
**STOP re-rendering** when `Δ vs previous run` shows _no metric changed_, or the report carries a `🛑 STUCK` block: the fix missed the bug. Drop to tiers 1–3 to learn why, then return.
|
|
48
48
|
|
|
49
49
|
---
|
|
50
50
|
|
|
@@ -115,21 +115,21 @@ Tiers differ ~100× in cost per run:
|
|
|
115
115
|
- [ ] Read each warning — may be intentional (unlisted component, optional param...), never skip unread
|
|
116
116
|
- [ ] **`[design]`** warnings (colored dialog toolbar, red delete button, odd dialog width, no floating label, delete without CONFIRM, redundant Close button, hand-built v-snackbar/v-alert instead of MESS/MESSBOX, main f-table/f-sheet without `":height": -16` so the page scrolls instead of the table...) — **must fix** unless the user explicitly asked otherwise this session
|
|
117
117
|
- [ ] Strict mode (`FUI_STRICT=1`): errors BLOCK publish
|
|
118
|
-
- [ ] `fui module outline`, READ the tree: row Σw ≤12? `⚠
|
|
118
|
+
- [ ] `fui module outline`, READ the tree: row Σw ≤12? `⚠ no opener`? `⚠ never called`? `⚠ unused in controls/watch/actions`?
|
|
119
119
|
- [ ] Complex runtime logic (action chain, watch cascade, dialog flow): `fui module simulate` with main-flow `--scenario` + `--mocks` (shape from `fui sp verify` snippet) + asserts — fix every `⚠` and ✘ first. Your `--mocks` always win; a static API with NO mock whose SP is confirmed read-only (`fui sp verify`/local `.sql`) is called for real (max 8 calls/run, cached in `_testdata/`) instead of `{data:[]}` — see the "Live/Cache data" line. SPs with writes are never called
|
|
120
|
-
- [ ] **`--mocks` for existing SPs come from `fui sp verify`, never guessed** — on `🚨
|
|
121
|
-
- [ ] **Final visual QA (Playwright available)**: `fui module simulate --render --vue-data '{..demo data..}' --mocks '{...}'`. READ the
|
|
120
|
+
- [ ] **`--mocks` for existing SPs come from `fui sp verify`, never guessed** — on `🚨 UNVERIFIED MOCK SHAPE`, stop, run `fui sp verify`, copy its `--mocks snippet` verbatim (no hand edits). Invented shapes only for SPs not yet deployed
|
|
121
|
+
- [ ] **Final visual QA (Playwright available)**: `fui module simulate --render --vue-data '{..demo data..}' --mocks '{...}'`. OPEN and READ the image files the report lists (`Screenshot:`, `Full-page:`; nothing is attached to the output) + DOM audit (empty app, overflow, "undefined"/"NaN", broken image, 0-size chart canvas) + JS errors/`[Vue warn]` + final vueData; fix and re-render until clean. **`⛔ MISSING ENV FILES` first**: environment error — run its suggested command (`fui project sync`/`fui module get`); errors below may be consequences, don't edit module.json for them. How to read screenshots: `ui-screenshot-review.md`. Chart/animation missing → raise `--settle-ms` (e.g. 1500). Open dialog captured as `render-dialog.jpg`. Mobile use → extra run `--device mobile`. No Playwright → skip (command returns install steps)
|
|
122
122
|
- [ ] **Changed project level + module level** (project component/import, `project.json`/menu): publish **project level FIRST**, then render — `--render` loads `$projectData`, project components and project CSS from the server (`_aset`); module-level parts render locally (iterate freely, publish later). **Project components are hard-blocked** (no bypass flag) if a local `uc-*.vue` differs from the server bundle: `fui component preview` → `fui component new`/`update` → render. Blocked because server is newer (web IDE edit) → `fui project sync`, never push over
|
|
123
123
|
|
|
124
124
|
### Publish — only what changed
|
|
125
125
|
|
|
126
126
|
- [ ] Only `module.json` → `fui module publish json` (no preview/approval)
|
|
127
|
-
- [ ] `header.html` / `body.html` / title → `fui module preview` →
|
|
127
|
+
- [ ] `header.html` / `body.html` / title → `fui module preview` → self-review the diff → `fui module publish html --approval <token>` (includes module.json); wait only when the developer previously said not to upload or requested review first
|
|
128
128
|
- [ ] `script.js` (even emptied) → `fui module publish script` — **⚠️ `publish html` does not clear an empty script on the server**
|
|
129
129
|
- [ ] `uc-*.vue` → `fui component new` (first) / `fui component update` (later), per file — `update` hard-errors if absent on server, never creates
|
|
130
130
|
- [ ] Several parts → one command each, in turn
|
|
131
131
|
|
|
132
|
-
For `fui module publish html`: preview ran and diff reviewed ·
|
|
132
|
+
For `fui module publish html`: preview ran and diff reviewed · upload is authorized by the module request · approval token in hand. If the developer requested local-only or review-first work, explicit later confirmation replaces the standing authorization.
|
|
133
133
|
|
|
134
134
|
---
|
|
135
135
|
|
|
@@ -151,7 +151,7 @@ For `fui module publish html`: preview ran and diff reviewed · user explicitly
|
|
|
151
151
|
- [ ] Permission check at top: `IF @sys_SystemRight < N BEGIN RAISERROR(N'[Unauthorized]Bạn không có quyền...', 16, 1) RETURN END` — severity always `16`; `[Unauthorized]` prefix required so tAPI returns HTTP 401 ([tapi-reference.md](tapi-reference.md) §5)
|
|
152
152
|
- [ ] No SQL string concatenation (parameterize)
|
|
153
153
|
- [ ] `.sql` has **NO `GRANT EXECUTE`** — tAPI sends one batch, no `GO`, so a GRANT after `END` is **swallowed into the SP body** and runs on every call, silently. `fui sp deploy` grants new procedures and **re-queries `sys.database_permissions` to confirm**
|
|
154
|
-
- [ ] `fui sp deploy` shows
|
|
154
|
+
- [ ] `fui sp deploy` shows `GRANT EXECUTE ... TO [public]: applied` (new SP) or `[public] has EXECUTE on "<sp>"`; on `grant FAILED` or `[public] lacks EXECUTE` run exactly the printed `fui exec "GRANT ..."` (**don't redeploy**). `fui exec` deploys have no auto-grant (fui warns with the command). Later doubts: `fui sp verify <name> --check-grant`
|
|
155
155
|
|
|
156
156
|
### Logic
|
|
157
157
|
|
|
@@ -165,7 +165,7 @@ For `fui module publish html`: preview ran and diff reviewed · user explicitly
|
|
|
165
165
|
- [ ] `fui sp save` first (local only)
|
|
166
166
|
- [ ] Full body reviewed in the local file
|
|
167
167
|
- [ ] Summary to user: SP name, CREATE/ALTER, affected tables
|
|
168
|
-
- [ ]
|
|
168
|
+
- [ ] The SP belongs to the requested module work and all static checks passed, or the developer explicitly approved a previously paused/local-only deployment
|
|
169
169
|
- [ ] Any API (read or write) about to be wired into module.json → `fui sp verify` once: static shape/error contract + param check, **no endpoint call** (metadata reads only, as above)
|
|
170
170
|
- [ ] **Write** APIs: verify by reading the body (`fui sp get`/`fui sp verify`) — WHERE, transaction, RAISERROR; test the UI flow with `fui module simulate --mocks '{...}'` (snippet from `fui sp verify`), never the real API
|
|
171
171
|
|
|
@@ -216,7 +216,7 @@ For `fui module publish html`: preview ran and diff reviewed · user explicitly
|
|
|
216
216
|
|
|
217
217
|
1. **Re-read every file changed in that publish first**; don't jump elsewhere
|
|
218
218
|
2. Looks right ⇒ `fui module preview` for server vs local diff
|
|
219
|
-
3. Preview shows `
|
|
219
|
+
3. Preview shows `controls 0, data keys 0` ⇒ server holds a broken old version — push again
|
|
220
220
|
4. Only when local is confirmed correct: check other files (header.html, script.js, imports)
|
|
221
221
|
|
|
222
222
|
---
|
|
@@ -227,10 +227,10 @@ Before any mutating command:
|
|
|
227
227
|
|
|
228
228
|
| Question | If NO → |
|
|
229
229
|
| ------------------------------------------ | ------------------------------ |
|
|
230
|
-
| Read-only
|
|
231
|
-
|
|
|
232
|
-
| 🔴 Destructive?
|
|
230
|
+
| Read-only or in current module scope? | Continue after checks |
|
|
231
|
+
| Unrelated server mutation? | Confirm intent with user |
|
|
232
|
+
| 🔴 Destructive or real-data write? | Require explicit confirmation |
|
|
233
233
|
| `fui module publish html`: approval token? | Run `fui module preview` first |
|
|
234
|
-
| `fui sp deploy`:
|
|
234
|
+
| `fui sp deploy`: in current module scope? | Deploy after static checks |
|
|
235
235
|
|
|
236
236
|
Per-command classification: [tools-registry.md](tools-registry.md).
|
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
# Watcher Patterns
|
|
2
|
-
|
|
3
|
-
> Owns: **`watch`: `v_old`, deep-watch, cascading, race control**. Action syntax: [controls-patterns.md](controls-patterns.md).
|
|
4
|
-
|
|
5
|
-
Use for multi-level dependent forms (Province → District → Ward) and attribute filters (status, type, date, keyword...). Goals: correct FUI structure (`data`, `watch`, `controls`, `set`), no watcher loops, fewer redundant API calls, maintainable large modules.
|
|
6
|
-
|
|
7
|
-
## 1. Rules
|
|
8
|
-
|
|
9
|
-
1. **Watch the smallest input key** — an ID or filter field (`provinceID`, `districtID`, `filter.status`), not a large object unless needed.
|
|
10
|
-
2. **Split actions by level** — `handleProvinceChange` only resets dependents and calls `apiLoadDistricts`; `handleDistrictChange` only resets the level below and calls `apiLoadWards`; `applyFilters` holds the final list-loading logic.
|
|
11
|
-
3. **`deep-watch` selectively** — only small filter objects (e.g. `filter`). Never deep-watch large arrays like `items`, `tableData`.
|
|
12
|
-
4. **No self-made loops** — never watch the action's own output var; never watch `items` and write `items` in the callback.
|
|
13
|
-
5. **Guard before API calls** — `IF/THEN/ELSE` to validate input (e.g. no province selected → don't load districts).
|
|
14
|
-
6. **Debounce/race control in `script.js`** — watchers only orchestrate; debounce and stale-response-overwrite protection live in JS helpers.
|
|
15
|
-
7. **Force literal strings only via `IN`** — in an action with `IN`, a string without spaces may be read as an expression → use `` `value`` or `"'value'"`. Full rules: [controls-patterns.md §0](controls-patterns.md#0-value-resolution-rules-fundamental).
|
|
16
|
-
|
|
17
|
-
## 2. Pattern A: administrative-area cascade
|
|
18
|
-
|
|
19
|
-
```json
|
|
20
|
-
{
|
|
21
|
-
"data": [
|
|
22
|
-
{
|
|
23
|
-
"formData": {
|
|
24
|
-
"provinceID": null,
|
|
25
|
-
"districtID": null,
|
|
26
|
-
"wardID": null
|
|
27
|
-
},
|
|
28
|
-
"provinceList": [],
|
|
29
|
-
"districtList": [],
|
|
30
|
-
"wardList": []
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"apiLoadProvinces": {
|
|
34
|
-
"API": "/api/location/provinces",
|
|
35
|
-
"OUT": "provinceList"
|
|
36
|
-
},
|
|
37
|
-
"apiLoadDistricts": {
|
|
38
|
-
"API": "/api/location/districts",
|
|
39
|
-
"IN": { "ProvinceID": "formData.provinceID" },
|
|
40
|
-
"OUT": "districtList"
|
|
41
|
-
},
|
|
42
|
-
"apiLoadWards": {
|
|
43
|
-
"API": "/api/location/wards",
|
|
44
|
-
"IN": { "DistrictID": "formData.districtID" },
|
|
45
|
-
"OUT": "wardList"
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"handleProvinceChange": [
|
|
50
|
-
{
|
|
51
|
-
"districtList": [],
|
|
52
|
-
"wardList": [],
|
|
53
|
-
"formData.districtID": null,
|
|
54
|
-
"formData.wardID": null
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
"IF": "formData.provinceID",
|
|
58
|
-
"THEN": { "CALL": "apiLoadDistricts" }
|
|
59
|
-
}
|
|
60
|
-
],
|
|
61
|
-
"handleDistrictChange": [
|
|
62
|
-
{
|
|
63
|
-
"wardList": [],
|
|
64
|
-
"formData.wardID": null
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"IF": "formData.districtID",
|
|
68
|
-
"THEN": { "CALL": "apiLoadWards" }
|
|
69
|
-
}
|
|
70
|
-
]
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
"CALL": "apiLoadProvinces"
|
|
74
|
-
}
|
|
75
|
-
],
|
|
76
|
-
"watch": {
|
|
77
|
-
"formData.provinceID": { "CALL": "handleProvinceChange" },
|
|
78
|
-
"formData.districtID": { "CALL": "handleDistrictChange" }
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Key points: watch specific keys; reset lower levels before calling their API; guard against calling with null.
|
|
84
|
-
|
|
85
|
-
## 3. Pattern B: filter object + deep-watch
|
|
86
|
-
|
|
87
|
-
```json
|
|
88
|
-
{
|
|
89
|
-
"data": [
|
|
90
|
-
{
|
|
91
|
-
"filter": {
|
|
92
|
-
"keyword": "",
|
|
93
|
-
"status": null,
|
|
94
|
-
"fromDate": null,
|
|
95
|
-
"toDate": null
|
|
96
|
-
},
|
|
97
|
-
"items": []
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
"apiLoadItems": {
|
|
101
|
-
"API": "/api/items/search",
|
|
102
|
-
"IN": {
|
|
103
|
-
"Keyword": "filter.keyword",
|
|
104
|
-
"Status": "filter.status",
|
|
105
|
-
"FromDate": "filter.fromDate",
|
|
106
|
-
"ToDate": "filter.toDate"
|
|
107
|
-
},
|
|
108
|
-
"OUT": "items"
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
"handleFilterChanged": {
|
|
113
|
-
"CALL": "apiLoadItems"
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
],
|
|
117
|
-
"watch": {
|
|
118
|
-
"deep-watch": {
|
|
119
|
-
"filter": { "CALL": "handleFilterChanged" }
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Keep `filter` small and stable. Continuous text-search input → debounce in `script.js`.
|
|
126
|
-
|
|
127
|
-
## 4. Recommended debounce (script.js)
|
|
128
|
-
|
|
129
|
-
```javascript
|
|
130
|
-
var filterTimer = null;
|
|
131
|
-
|
|
132
|
-
function debounceFilter(input) {
|
|
133
|
-
var callActionName = input && input.callActionName;
|
|
134
|
-
var waitMs = input && input.waitMs;
|
|
135
|
-
clearTimeout(filterTimer);
|
|
136
|
-
filterTimer = setTimeout(function () {
|
|
137
|
-
CALL(vueData[callActionName]);
|
|
138
|
-
}, waitMs || 350);
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Action in `module.json`:
|
|
143
|
-
|
|
144
|
-
```json
|
|
145
|
-
{
|
|
146
|
-
"handleFilterChanged": {
|
|
147
|
-
"FUN": "debounceFilter",
|
|
148
|
-
"IN": {
|
|
149
|
-
"callActionName": "'apiLoadItems'",
|
|
150
|
-
"waitMs": 350
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
## 5. Watcher QA checklist
|
|
157
|
-
|
|
158
|
-
1. Watch key small enough (ID/field, not a large object)?
|
|
159
|
-
2. Dependents reset before calling the API?
|
|
160
|
-
3. `IF` guard before API when input is null/empty?
|
|
161
|
-
4. Any watcher loop risk?
|
|
162
|
-
5. Text input needs debounce?
|
|
163
|
-
6. Action with `IN`: literal string rule applied to space-free text values?
|
|
1
|
+
# Watcher Patterns
|
|
2
|
+
|
|
3
|
+
> Owns: **`watch`: `v_old`, deep-watch, cascading, race control**. Action syntax: [controls-patterns.md](controls-patterns.md).
|
|
4
|
+
|
|
5
|
+
Use for multi-level dependent forms (Province → District → Ward) and attribute filters (status, type, date, keyword...). Goals: correct FUI structure (`data`, `watch`, `controls`, `set`), no watcher loops, fewer redundant API calls, maintainable large modules.
|
|
6
|
+
|
|
7
|
+
## 1. Rules
|
|
8
|
+
|
|
9
|
+
1. **Watch the smallest input key** — an ID or filter field (`provinceID`, `districtID`, `filter.status`), not a large object unless needed.
|
|
10
|
+
2. **Split actions by level** — `handleProvinceChange` only resets dependents and calls `apiLoadDistricts`; `handleDistrictChange` only resets the level below and calls `apiLoadWards`; `applyFilters` holds the final list-loading logic.
|
|
11
|
+
3. **`deep-watch` selectively** — only small filter objects (e.g. `filter`). Never deep-watch large arrays like `items`, `tableData`.
|
|
12
|
+
4. **No self-made loops** — never watch the action's own output var; never watch `items` and write `items` in the callback.
|
|
13
|
+
5. **Guard before API calls** — `IF/THEN/ELSE` to validate input (e.g. no province selected → don't load districts).
|
|
14
|
+
6. **Debounce/race control in `script.js`** — watchers only orchestrate; debounce and stale-response-overwrite protection live in JS helpers.
|
|
15
|
+
7. **Force literal strings only via `IN`** — in an action with `IN`, a string without spaces may be read as an expression → use `` `value`` or `"'value'"`. Full rules: [controls-patterns.md §0](controls-patterns.md#0-value-resolution-rules-fundamental).
|
|
16
|
+
|
|
17
|
+
## 2. Pattern A: administrative-area cascade
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"data": [
|
|
22
|
+
{
|
|
23
|
+
"formData": {
|
|
24
|
+
"provinceID": null,
|
|
25
|
+
"districtID": null,
|
|
26
|
+
"wardID": null
|
|
27
|
+
},
|
|
28
|
+
"provinceList": [],
|
|
29
|
+
"districtList": [],
|
|
30
|
+
"wardList": []
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"apiLoadProvinces": {
|
|
34
|
+
"API": "/api/location/provinces",
|
|
35
|
+
"OUT": "provinceList"
|
|
36
|
+
},
|
|
37
|
+
"apiLoadDistricts": {
|
|
38
|
+
"API": "/api/location/districts",
|
|
39
|
+
"IN": { "ProvinceID": "formData.provinceID" },
|
|
40
|
+
"OUT": "districtList"
|
|
41
|
+
},
|
|
42
|
+
"apiLoadWards": {
|
|
43
|
+
"API": "/api/location/wards",
|
|
44
|
+
"IN": { "DistrictID": "formData.districtID" },
|
|
45
|
+
"OUT": "wardList"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"handleProvinceChange": [
|
|
50
|
+
{
|
|
51
|
+
"districtList": [],
|
|
52
|
+
"wardList": [],
|
|
53
|
+
"formData.districtID": null,
|
|
54
|
+
"formData.wardID": null
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"IF": "formData.provinceID",
|
|
58
|
+
"THEN": { "CALL": "apiLoadDistricts" }
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"handleDistrictChange": [
|
|
62
|
+
{
|
|
63
|
+
"wardList": [],
|
|
64
|
+
"formData.wardID": null
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"IF": "formData.districtID",
|
|
68
|
+
"THEN": { "CALL": "apiLoadWards" }
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"CALL": "apiLoadProvinces"
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"watch": {
|
|
77
|
+
"formData.provinceID": { "CALL": "handleProvinceChange" },
|
|
78
|
+
"formData.districtID": { "CALL": "handleDistrictChange" }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Key points: watch specific keys; reset lower levels before calling their API; guard against calling with null.
|
|
84
|
+
|
|
85
|
+
## 3. Pattern B: filter object + deep-watch
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"data": [
|
|
90
|
+
{
|
|
91
|
+
"filter": {
|
|
92
|
+
"keyword": "",
|
|
93
|
+
"status": null,
|
|
94
|
+
"fromDate": null,
|
|
95
|
+
"toDate": null
|
|
96
|
+
},
|
|
97
|
+
"items": []
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"apiLoadItems": {
|
|
101
|
+
"API": "/api/items/search",
|
|
102
|
+
"IN": {
|
|
103
|
+
"Keyword": "filter.keyword",
|
|
104
|
+
"Status": "filter.status",
|
|
105
|
+
"FromDate": "filter.fromDate",
|
|
106
|
+
"ToDate": "filter.toDate"
|
|
107
|
+
},
|
|
108
|
+
"OUT": "items"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"handleFilterChanged": {
|
|
113
|
+
"CALL": "apiLoadItems"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"watch": {
|
|
118
|
+
"deep-watch": {
|
|
119
|
+
"filter": { "CALL": "handleFilterChanged" }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Keep `filter` small and stable. Continuous text-search input → debounce in `script.js`.
|
|
126
|
+
|
|
127
|
+
## 4. Recommended debounce (script.js)
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
var filterTimer = null;
|
|
131
|
+
|
|
132
|
+
function debounceFilter(input) {
|
|
133
|
+
var callActionName = input && input.callActionName;
|
|
134
|
+
var waitMs = input && input.waitMs;
|
|
135
|
+
clearTimeout(filterTimer);
|
|
136
|
+
filterTimer = setTimeout(function () {
|
|
137
|
+
CALL(vueData[callActionName]);
|
|
138
|
+
}, waitMs || 350);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Action in `module.json`:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"handleFilterChanged": {
|
|
147
|
+
"FUN": "debounceFilter",
|
|
148
|
+
"IN": {
|
|
149
|
+
"callActionName": "'apiLoadItems'",
|
|
150
|
+
"waitMs": 350
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 5. Watcher QA checklist
|
|
157
|
+
|
|
158
|
+
1. Watch key small enough (ID/field, not a large object)?
|
|
159
|
+
2. Dependents reset before calling the API?
|
|
160
|
+
3. `IF` guard before API when input is null/empty?
|
|
161
|
+
4. Any watcher loop risk?
|
|
162
|
+
5. Text input needs debounce?
|
|
163
|
+
6. Action with `IN`: literal string rule applied to space-free text values?
|