@fui-org/fui-cli 2.1.3 → 2.2.0

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.
Files changed (219) hide show
  1. package/README.md +27 -7
  2. package/dist/fui-qrb1j9jz.js +397 -0
  3. package/dist/fui.js +1 -1
  4. package/package.json +1 -1
  5. package/skills/fui/SKILL.md +143 -38
  6. package/skills/fui/agents/fui-builder.md +62 -0
  7. package/skills/fui/agents/fui-tester.md +77 -0
  8. package/skills/{fui-skill → fui}/assets/projectdefaultstyle.css +489 -489
  9. package/skills/{fui-skill → fui}/examples/component.vue +162 -162
  10. package/skills/{fui-skill → fui}/references/INDEX.md +5 -4
  11. package/skills/{fui-skill → fui}/references/advanced-techniques.md +170 -168
  12. package/skills/{fui-skill → fui}/references/component-design.md +2 -2
  13. package/skills/{fui-skill → fui}/references/component-quickref.md +78 -78
  14. package/skills/{fui-skill → fui}/references/component-table.md +287 -287
  15. package/skills/{fui-skill → fui}/references/components-dialog.md +191 -191
  16. package/skills/{fui-skill → fui}/references/components-display.md +141 -141
  17. package/skills/{fui-skill → fui}/references/components-echart.md +316 -316
  18. package/skills/{fui-skill → fui}/references/components-input.md +335 -335
  19. package/skills/{fui-skill → fui}/references/controls-patterns.md +2 -2
  20. package/skills/{fui-skill → fui}/references/controls-styling-vocabulary.md +173 -173
  21. package/skills/{fui-skill → fui}/references/db-workflow.md +9 -9
  22. package/skills/{fui-skill → fui}/references/default-function.md +456 -456
  23. package/skills/{fui-skill → fui}/references/design-modes.md +57 -57
  24. package/skills/{fui-skill → fui}/references/echart-templates.md +489 -489
  25. package/skills/{fui-skill → fui}/references/fastproject.md +99 -99
  26. package/skills/{fui-skill → fui}/references/fullstack-workflow.md +314 -313
  27. package/skills/{fui-skill → fui}/references/module-data-patterns.md +117 -117
  28. package/skills/{fui-skill → fui}/references/module-json-anatomy.md +132 -132
  29. package/skills/{fui-skill → fui}/references/module-structure.md +144 -144
  30. package/skills/{fui-skill → fui}/references/new-session.md +1 -2
  31. package/skills/{fui-skill → fui}/references/pdfmake.md +60 -60
  32. package/skills/{fui-skill → fui}/references/permission-system.md +1 -1
  33. package/skills/{fui-skill → fui}/references/platform-architecture.md +269 -269
  34. package/skills/{fui-skill → fui}/references/project-config.md +303 -303
  35. package/skills/{fui-skill → fui}/references/project-provisioning.md +4 -4
  36. package/skills/{fui-skill → fui}/references/script-map.md +262 -262
  37. package/skills/{fui-skill → fui}/references/sql-clr-functions.md +225 -225
  38. package/skills/{fui-skill → fui}/references/system-design.md +2 -2
  39. package/skills/{fui-skill → fui}/references/tapi-permission-patterns.md +156 -156
  40. package/skills/{fui-skill → fui}/references/tapi-reference.md +474 -474
  41. package/skills/fui/references/team-run.md +141 -0
  42. package/skills/fui/references/tools-registry.md +211 -0
  43. package/skills/{fui-skill → fui}/references/ui-crosswindow-patterns.md +321 -321
  44. package/skills/{fui-skill → fui}/references/ui-dialog-patterns.md +255 -255
  45. package/skills/{fui-skill → fui}/references/ui-layout-patterns.md +176 -176
  46. package/skills/{fui-skill → fui}/references/ui-patterns.md +303 -303
  47. package/skills/{fui-skill → fui}/references/ui-screenshot-review.md +95 -95
  48. package/skills/{fui-skill → fui}/references/ui-table-cell-patterns.md +318 -318
  49. package/skills/{fui-skill → fui}/references/verification.md +11 -11
  50. package/skills/{fui-skill → fui}/references/watcher-patterns.md +163 -163
  51. package/skills/{fui-skill → fui}/references/websocket-realtime.md +271 -271
  52. package/skills/{fui-skill → fui}/scripts/component-3.0.js +2715 -2715
  53. package/skills/{fui-skill → fui}/scripts/component.js +3147 -3147
  54. package/skills/{fui-skill → fui}/scripts/componentTable-3.0.js +1038 -1038
  55. package/skills/{fui-skill → fui}/scripts/componentTable.js +891 -891
  56. package/skills/{fui-skill → fui}/scripts/defaultfunction-3.0.js +866 -866
  57. package/skills/{fui-skill → fui}/scripts/defaultfunction.js +1051 -1051
  58. package/skills/{fui-skill → fui}/scripts/fastproject-3.0.js +870 -870
  59. package/skills/{fui-skill → fui}/scripts/fastproject.js +828 -828
  60. package/skills/fui-target/hooks/register.tsx +2 -0
  61. package/skills/fui-target/types/index.d.ts +1 -0
  62. package/dist/fui-hk5frcn2.js +0 -381
  63. package/skills/fui-skill/SKILL.md +0 -139
  64. package/skills/fui-skill/references/tools-registry.md +0 -84
  65. /package/skills/{fui-skill → fui}/assets/projectdefaultstyle-3.0.css +0 -0
  66. /package/skills/{fui-skill → fui}/design-md/airbnb/DESIGN.md +0 -0
  67. /package/skills/{fui-skill → fui}/design-md/airbnb/README.md +0 -0
  68. /package/skills/{fui-skill → fui}/design-md/airtable/DESIGN.md +0 -0
  69. /package/skills/{fui-skill → fui}/design-md/airtable/README.md +0 -0
  70. /package/skills/{fui-skill → fui}/design-md/apple/DESIGN.md +0 -0
  71. /package/skills/{fui-skill → fui}/design-md/apple/README.md +0 -0
  72. /package/skills/{fui-skill → fui}/design-md/asu/DESIGN.md +0 -0
  73. /package/skills/{fui-skill → fui}/design-md/asu/README.md +0 -0
  74. /package/skills/{fui-skill → fui}/design-md/binance/DESIGN.md +0 -0
  75. /package/skills/{fui-skill → fui}/design-md/binance/README.md +0 -0
  76. /package/skills/{fui-skill → fui}/design-md/bmw/DESIGN.md +0 -0
  77. /package/skills/{fui-skill → fui}/design-md/bmw/README.md +0 -0
  78. /package/skills/{fui-skill → fui}/design-md/bmw-m/DESIGN.md +0 -0
  79. /package/skills/{fui-skill → fui}/design-md/bmw-m/README.md +0 -0
  80. /package/skills/{fui-skill → fui}/design-md/bugatti/DESIGN.md +0 -0
  81. /package/skills/{fui-skill → fui}/design-md/bugatti/README.md +0 -0
  82. /package/skills/{fui-skill → fui}/design-md/cal/DESIGN.md +0 -0
  83. /package/skills/{fui-skill → fui}/design-md/cal/README.md +0 -0
  84. /package/skills/{fui-skill → fui}/design-md/claude/DESIGN.md +0 -0
  85. /package/skills/{fui-skill → fui}/design-md/claude/README.md +0 -0
  86. /package/skills/{fui-skill → fui}/design-md/clay/DESIGN.md +0 -0
  87. /package/skills/{fui-skill → fui}/design-md/clay/README.md +0 -0
  88. /package/skills/{fui-skill → fui}/design-md/clickhouse/DESIGN.md +0 -0
  89. /package/skills/{fui-skill → fui}/design-md/clickhouse/README.md +0 -0
  90. /package/skills/{fui-skill → fui}/design-md/cohere/DESIGN.md +0 -0
  91. /package/skills/{fui-skill → fui}/design-md/cohere/README.md +0 -0
  92. /package/skills/{fui-skill → fui}/design-md/coinbase/DESIGN.md +0 -0
  93. /package/skills/{fui-skill → fui}/design-md/coinbase/README.md +0 -0
  94. /package/skills/{fui-skill → fui}/design-md/composio/DESIGN.md +0 -0
  95. /package/skills/{fui-skill → fui}/design-md/composio/README.md +0 -0
  96. /package/skills/{fui-skill → fui}/design-md/cursor/DESIGN.md +0 -0
  97. /package/skills/{fui-skill → fui}/design-md/cursor/README.md +0 -0
  98. /package/skills/{fui-skill → fui}/design-md/elevenlabs/DESIGN.md +0 -0
  99. /package/skills/{fui-skill → fui}/design-md/elevenlabs/README.md +0 -0
  100. /package/skills/{fui-skill → fui}/design-md/expo/DESIGN.md +0 -0
  101. /package/skills/{fui-skill → fui}/design-md/expo/README.md +0 -0
  102. /package/skills/{fui-skill → fui}/design-md/ferrari/DESIGN.md +0 -0
  103. /package/skills/{fui-skill → fui}/design-md/ferrari/README.md +0 -0
  104. /package/skills/{fui-skill → fui}/design-md/figma/DESIGN.md +0 -0
  105. /package/skills/{fui-skill → fui}/design-md/figma/README.md +0 -0
  106. /package/skills/{fui-skill → fui}/design-md/framer/DESIGN.md +0 -0
  107. /package/skills/{fui-skill → fui}/design-md/framer/README.md +0 -0
  108. /package/skills/{fui-skill → fui}/design-md/fui/DESIGN.md +0 -0
  109. /package/skills/{fui-skill → fui}/design-md/hashicorp/DESIGN.md +0 -0
  110. /package/skills/{fui-skill → fui}/design-md/hashicorp/README.md +0 -0
  111. /package/skills/{fui-skill → fui}/design-md/ibm/DESIGN.md +0 -0
  112. /package/skills/{fui-skill → fui}/design-md/ibm/README.md +0 -0
  113. /package/skills/{fui-skill → fui}/design-md/intercom/DESIGN.md +0 -0
  114. /package/skills/{fui-skill → fui}/design-md/intercom/README.md +0 -0
  115. /package/skills/{fui-skill → fui}/design-md/kraken/DESIGN.md +0 -0
  116. /package/skills/{fui-skill → fui}/design-md/kraken/README.md +0 -0
  117. /package/skills/{fui-skill → fui}/design-md/lamborghini/DESIGN.md +0 -0
  118. /package/skills/{fui-skill → fui}/design-md/lamborghini/README.md +0 -0
  119. /package/skills/{fui-skill → fui}/design-md/linear.app/DESIGN.md +0 -0
  120. /package/skills/{fui-skill → fui}/design-md/linear.app/README.md +0 -0
  121. /package/skills/{fui-skill → fui}/design-md/lovable/DESIGN.md +0 -0
  122. /package/skills/{fui-skill → fui}/design-md/lovable/README.md +0 -0
  123. /package/skills/{fui-skill → fui}/design-md/mastercard/DESIGN.md +0 -0
  124. /package/skills/{fui-skill → fui}/design-md/mastercard/README.md +0 -0
  125. /package/skills/{fui-skill → fui}/design-md/meta/DESIGN.md +0 -0
  126. /package/skills/{fui-skill → fui}/design-md/meta/README.md +0 -0
  127. /package/skills/{fui-skill → fui}/design-md/minimax/DESIGN.md +0 -0
  128. /package/skills/{fui-skill → fui}/design-md/minimax/README.md +0 -0
  129. /package/skills/{fui-skill → fui}/design-md/mintlify/DESIGN.md +0 -0
  130. /package/skills/{fui-skill → fui}/design-md/mintlify/README.md +0 -0
  131. /package/skills/{fui-skill → fui}/design-md/miro/DESIGN.md +0 -0
  132. /package/skills/{fui-skill → fui}/design-md/miro/README.md +0 -0
  133. /package/skills/{fui-skill → fui}/design-md/mistral.ai/DESIGN.md +0 -0
  134. /package/skills/{fui-skill → fui}/design-md/mistral.ai/README.md +0 -0
  135. /package/skills/{fui-skill → fui}/design-md/mongodb/DESIGN.md +0 -0
  136. /package/skills/{fui-skill → fui}/design-md/mongodb/README.md +0 -0
  137. /package/skills/{fui-skill → fui}/design-md/nike/DESIGN.md +0 -0
  138. /package/skills/{fui-skill → fui}/design-md/nike/README.md +0 -0
  139. /package/skills/{fui-skill → fui}/design-md/notion/DESIGN.md +0 -0
  140. /package/skills/{fui-skill → fui}/design-md/notion/README.md +0 -0
  141. /package/skills/{fui-skill → fui}/design-md/nvidia/DESIGN.md +0 -0
  142. /package/skills/{fui-skill → fui}/design-md/nvidia/README.md +0 -0
  143. /package/skills/{fui-skill → fui}/design-md/ollama/DESIGN.md +0 -0
  144. /package/skills/{fui-skill → fui}/design-md/ollama/README.md +0 -0
  145. /package/skills/{fui-skill → fui}/design-md/opencode.ai/DESIGN.md +0 -0
  146. /package/skills/{fui-skill → fui}/design-md/opencode.ai/README.md +0 -0
  147. /package/skills/{fui-skill → fui}/design-md/pinterest/DESIGN.md +0 -0
  148. /package/skills/{fui-skill → fui}/design-md/pinterest/README.md +0 -0
  149. /package/skills/{fui-skill → fui}/design-md/playstation/DESIGN.md +0 -0
  150. /package/skills/{fui-skill → fui}/design-md/playstation/README.md +0 -0
  151. /package/skills/{fui-skill → fui}/design-md/posthog/DESIGN.md +0 -0
  152. /package/skills/{fui-skill → fui}/design-md/posthog/README.md +0 -0
  153. /package/skills/{fui-skill → fui}/design-md/raycast/DESIGN.md +0 -0
  154. /package/skills/{fui-skill → fui}/design-md/raycast/README.md +0 -0
  155. /package/skills/{fui-skill → fui}/design-md/renault/DESIGN.md +0 -0
  156. /package/skills/{fui-skill → fui}/design-md/renault/README.md +0 -0
  157. /package/skills/{fui-skill → fui}/design-md/replicate/DESIGN.md +0 -0
  158. /package/skills/{fui-skill → fui}/design-md/replicate/README.md +0 -0
  159. /package/skills/{fui-skill → fui}/design-md/resend/DESIGN.md +0 -0
  160. /package/skills/{fui-skill → fui}/design-md/resend/README.md +0 -0
  161. /package/skills/{fui-skill → fui}/design-md/revolut/DESIGN.md +0 -0
  162. /package/skills/{fui-skill → fui}/design-md/revolut/README.md +0 -0
  163. /package/skills/{fui-skill → fui}/design-md/runwayml/DESIGN.md +0 -0
  164. /package/skills/{fui-skill → fui}/design-md/runwayml/README.md +0 -0
  165. /package/skills/{fui-skill → fui}/design-md/sanity/DESIGN.md +0 -0
  166. /package/skills/{fui-skill → fui}/design-md/sanity/README.md +0 -0
  167. /package/skills/{fui-skill → fui}/design-md/sentry/DESIGN.md +0 -0
  168. /package/skills/{fui-skill → fui}/design-md/sentry/README.md +0 -0
  169. /package/skills/{fui-skill → fui}/design-md/shopify/DESIGN.md +0 -0
  170. /package/skills/{fui-skill → fui}/design-md/shopify/README.md +0 -0
  171. /package/skills/{fui-skill → fui}/design-md/slack/DESIGN.md +0 -0
  172. /package/skills/{fui-skill → fui}/design-md/spacex/DESIGN.md +0 -0
  173. /package/skills/{fui-skill → fui}/design-md/spacex/README.md +0 -0
  174. /package/skills/{fui-skill → fui}/design-md/spotify/DESIGN.md +0 -0
  175. /package/skills/{fui-skill → fui}/design-md/spotify/README.md +0 -0
  176. /package/skills/{fui-skill → fui}/design-md/starbucks/DESIGN.md +0 -0
  177. /package/skills/{fui-skill → fui}/design-md/starbucks/README.md +0 -0
  178. /package/skills/{fui-skill → fui}/design-md/stripe/DESIGN.md +0 -0
  179. /package/skills/{fui-skill → fui}/design-md/stripe/README.md +0 -0
  180. /package/skills/{fui-skill → fui}/design-md/supabase/DESIGN.md +0 -0
  181. /package/skills/{fui-skill → fui}/design-md/supabase/README.md +0 -0
  182. /package/skills/{fui-skill → fui}/design-md/superhuman/DESIGN.md +0 -0
  183. /package/skills/{fui-skill → fui}/design-md/superhuman/README.md +0 -0
  184. /package/skills/{fui-skill → fui}/design-md/tesla/DESIGN.md +0 -0
  185. /package/skills/{fui-skill → fui}/design-md/tesla/README.md +0 -0
  186. /package/skills/{fui-skill → fui}/design-md/theverge/DESIGN.md +0 -0
  187. /package/skills/{fui-skill → fui}/design-md/theverge/README.md +0 -0
  188. /package/skills/{fui-skill → fui}/design-md/together.ai/DESIGN.md +0 -0
  189. /package/skills/{fui-skill → fui}/design-md/together.ai/README.md +0 -0
  190. /package/skills/{fui-skill → fui}/design-md/uber/DESIGN.md +0 -0
  191. /package/skills/{fui-skill → fui}/design-md/uber/README.md +0 -0
  192. /package/skills/{fui-skill → fui}/design-md/vercel/DESIGN.md +0 -0
  193. /package/skills/{fui-skill → fui}/design-md/vercel/README.md +0 -0
  194. /package/skills/{fui-skill → fui}/design-md/vodafone/DESIGN.md +0 -0
  195. /package/skills/{fui-skill → fui}/design-md/vodafone/README.md +0 -0
  196. /package/skills/{fui-skill → fui}/design-md/voltagent/DESIGN.md +0 -0
  197. /package/skills/{fui-skill → fui}/design-md/voltagent/README.md +0 -0
  198. /package/skills/{fui-skill → fui}/design-md/warp/DESIGN.md +0 -0
  199. /package/skills/{fui-skill → fui}/design-md/warp/README.md +0 -0
  200. /package/skills/{fui-skill → fui}/design-md/webflow/DESIGN.md +0 -0
  201. /package/skills/{fui-skill → fui}/design-md/webflow/README.md +0 -0
  202. /package/skills/{fui-skill → fui}/design-md/wired/DESIGN.md +0 -0
  203. /package/skills/{fui-skill → fui}/design-md/wired/README.md +0 -0
  204. /package/skills/{fui-skill → fui}/design-md/wise/DESIGN.md +0 -0
  205. /package/skills/{fui-skill → fui}/design-md/wise/README.md +0 -0
  206. /package/skills/{fui-skill → fui}/design-md/x.ai/DESIGN.md +0 -0
  207. /package/skills/{fui-skill → fui}/design-md/x.ai/README.md +0 -0
  208. /package/skills/{fui-skill → fui}/design-md/zapier/DESIGN.md +0 -0
  209. /package/skills/{fui-skill → fui}/design-md/zapier/README.md +0 -0
  210. /package/skills/{fui-skill → fui}/examples/f-table-patterns.json +0 -0
  211. /package/skills/{fui-skill → fui}/examples/module-patterns.json +0 -0
  212. /package/skills/{fui-skill → fui}/examples/project-patterns.json +0 -0
  213. /package/skills/{fui-skill → fui}/references/coding-standards.md +0 -0
  214. /package/skills/{fui-skill → fui}/references/db-table-design.md +0 -0
  215. /package/skills/{fui-skill → fui}/references/fsheet.md +0 -0
  216. /package/skills/{fui-skill → fui}/references/tapi-file-api.md +0 -0
  217. /package/skills/{fui-skill → fui}/references/ui-templates.md +0 -0
  218. /package/skills/{fui-skill → fui}/scripts/fechart.js +0 -0
  219. /package/skills/{fui-skill → fui}/scripts/fsheet.js +0 -0
@@ -1,303 +1,303 @@
1
- # FUI UI Patterns — Core
2
-
3
- > Owns: **core UI patterns: toolbar/filter, permission gate, UI design checklist**. Table/dialog/cross-window/layout live in separate `ui-*` files.
4
-
5
- Patterns taken from project **security-manager** — use as reference for new modules. Load specialised files as needed:
6
-
7
- | Need | File |
8
- | -------------------------------------------------------------------------------------- | -------------------------------------------------------- |
9
- | f-table + in-cell controls (t-check/t-button/t-select/t-menu, ctrl-update, chip-group) | [ui-table-cell-patterns.md](ui-table-cell-patterns.md) |
10
- | Dialog/popup form (hidden-container, open dialog with row, checkbox-list) | [ui-dialog-patterns.md](ui-dialog-patterns.md) |
11
- | Sub-window & data exchange (`openWindow`, `#PARENT`/`#Win`) | [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md) |
12
- | Layout (page-container, master-detail, v-switch, date init, dynamic label) | [ui-layout-patterns.md](ui-layout-patterns.md) |
13
-
14
- ---
15
-
16
- ## 1. `data[]` structure
17
-
18
- `data` initialises state + actions, processed top to bottom.
19
-
20
- - Object with **no action key** (no API, CALL, IF…) → state init
21
- - Object whose **key is a function name** → named (reusable) action
22
- - Trailing `{ "API": ..., "OUT": ... }` or `{ "CALL": ... }` → runs automatically on load
23
-
24
- ```json
25
- "data": [
26
- {
27
- "dsUser": [],
28
- "dsGroup": [],
29
- "sDepartment": null,
30
- "dlUserInfo": false
31
- },
32
- {
33
- "getDepartment": { "API": "SM_DepartmentSelectAll", "OUT": "dsDepartment" },
34
- "getGroup": { "API": "SM_Group_SelectAll", "OUT": "dsGroup" },
35
- "getUser": {
36
- "API": "SM_Users_SelectByDepGroup",
37
- "IN": { "GroupID": "sGroup", "DepartmentID": "sDepartment" },
38
- "OUT": "dsUser"
39
- }
40
- },
41
- { "CALL": "getDepartment" },
42
- { "CALL": "getGroup" }
43
- ]
44
- ```
45
-
46
- > **Auto-startup**: trailing CALLs in `data[]` run on module load — no event handler needed.
47
-
48
- ---
49
-
50
- ## 2. Cascading API init
51
-
52
- `CALLBACK` sets a value from the first API result; the next API runs via `watch`.
53
-
54
- ```json
55
- "data": [
56
- { "dsModule": [], "sModuleID": null },
57
- {
58
- "API": "/SM_Modules_SelectAll",
59
- "OUT": "dsModule",
60
- "CALLBACK": { "sModuleID": "dsModule[0].ModuleID" }
61
- }
62
- ],
63
- "watch": {
64
- "sModuleID": { "CALL": "getFunctionRight" }
65
- }
66
- ```
67
-
68
- > CALLBACK sets `sModuleID` → watch fires `getFunctionRight`. No manual call.
69
-
70
- ---
71
-
72
- ## 3. Watch — cascading filter
73
-
74
- Filter change → reload. Several actions → array of CALL.
75
-
76
- ```json
77
- "watch": {
78
- "sDepartment": { "CALL": "getUser" },
79
- "sGroup": { "CALL": "getUser" },
80
- "sModuleID": [
81
- { "CALL": "getUserModule" },
82
- { "CALL": "getSysRight" },
83
- { "CALL": "getFunctionRight" }
84
- ]
85
- }
86
- ```
87
-
88
- ---
89
-
90
- ## 4. Toolbar / filter row
91
-
92
- Row of filter fields + action buttons; `v-spacer` pushes the button group right.
93
-
94
- > **Rule: EVERY column is `"col": "shrink"` except `v-spacer`.** A non-`shrink` column takes a share of free space — including an empty-`w` column and buttons. Missing `shrink` → buttons stretch, gaps appear between buttons, and the trailing group doesn't reach the right edge even with `v-spacer`. Standard template + measurements: [controls-patterns.md](controls-patterns.md) §Toolbar row.
95
-
96
- ```json
97
- {
98
- "prop": "",
99
- "cols": [
100
- {
101
- "el": "v-autocomplete",
102
- "col": { "class": "shrink" },
103
- "attr": {
104
- "class": "flex-md-grow-0",
105
- "style": "width:200px",
106
- "v-model": "sGroup",
107
- "label": "Group",
108
- ":items": "dsGroup",
109
- "item-text": "GroupName",
110
- "item-value": "GroupID",
111
- ":required": false
112
- },
113
- "w": "200"
114
- },
115
- {
116
- "el": "v-text-field",
117
- "col": { "class": "shrink" },
118
- "attr": {
119
- "class": "flex-md-grow-0",
120
- "style": "width:200px",
121
- "v-model": "UserID",
122
- "label": "User ID",
123
- "clearable": ""
124
- },
125
- "w": "200"
126
- },
127
- {
128
- "el": "f-button",
129
- "col": { "class": "shrink" },
130
- "attr": {
131
- ":checkvalid": false,
132
- "color": "primary",
133
- "label": "Tìm",
134
- "icon-text": "mdi-magnify",
135
- ":action": { "CALL": "getUser" }
136
- }
137
- },
138
- { "el": "v-spacer", "attr": {} },
139
- {
140
- "el": "f-button",
141
- "col": { "v-if": "vueData.user.SystemRight==9", "class": "shrink" },
142
- "attr": {
143
- ":checkvalid": false,
144
- ":disabled": "!sGroup",
145
- "color": "primary",
146
- "label": "Add User",
147
- "icon-text": "mdi-account-multiple-plus",
148
- ":action": [{ "addNew": 1, "sUserID": "", "sUserName": "" }, { "dlUserInfo": true }]
149
- }
150
- }
151
- ]
152
- }
153
- ```
154
-
155
- - Filter fields: `w` in px (`>= 25`) + `col: "shrink"`. The `attr: { class: "flex-md-grow-0", style: "width:Xpx" }` pair above is **redundant** — `w` + `shrink` already gives that width (measured: `w:150` + `shrink` → exactly 150px on V2 and V3). It stays only because the example is copied from production; omit it in new code.
156
- - Search button right after the fields, also `col: "shrink"` (a non-shrink button stretches).
157
- - **Always `class: "shrink"` / `"col": "shrink"`, never `shrink: true`** — the bare attribute works only on V2; on V3 it's inert and the column goes full width.
158
- - `v-spacer` is the **only** non-`shrink` column — it must grow to push the following group right.
159
- - Admin Add/Delete buttons: after the spacer, permission `v-if` — `col: { "v-if": "…", "class": "shrink" }` (object form when extra keys are needed; keep `shrink`).
160
- - Right-align the whole row without `v-spacer`: `"prop": "row justify-end"`.
161
-
162
- ---
163
-
164
- ## 5. Permission gating
165
-
166
- Show/hide by the user's `SystemRight`.
167
-
168
- ```json
169
- "col": { "v-if": "vueData.user.SystemRight>1" }
170
- "col": { "v-if": "vueData.user.SystemRight==9" }
171
- ```
172
-
173
- - `>1` — any user with rights (not the lowest level)
174
- - `==9` — top admin only
175
-
176
- ---
177
-
178
- ## 6. IF/THEN/ELSE
179
-
180
- Branching inside an action or CALLBACK.
181
-
182
- ```json
183
- {
184
- "IF": "TypeLoad==1",
185
- "THEN": { "CALL": "getComputer" },
186
- "ELSE": {
187
- "IF": "TypeLoad==2",
188
- "THEN": { "CALL": "getComputerDinied" },
189
- "ELSE": { "CALL": "getComputerNotVisited" }
190
- }
191
- }
192
- ```
193
-
194
- - Condition: JS expression using vueData fields directly (no `vueData.` prefix).
195
- - Nest IF/ELSE for multi-branch switch.
196
-
197
- Real use: module with several view modes (`TypeLoad`) — after an update, refresh the list currently shown.
198
-
199
- ```json
200
- "data": [
201
- { "TypeLoad": 1 }
202
- ]
203
- ```
204
-
205
- ---
206
-
207
- ## 7. CALLBACK chaining
208
-
209
- Array CALLBACK → runs in order.
210
-
211
- > **Several commands MUST be an array, one `{}` per command.** Merging `CALL` + `MESS` + `EXE` into one object runs only **one** (priority `API` → `CALL` → `EXE` → `FUN` → `IF` → `MESS` → `MESSBOX`, each branch `return`s immediately); the rest are dropped silently — no error, no `[Vue warn]`. Full rule + runtime reason: [controls-patterns.md](controls-patterns.md) §CORE RULE.
212
-
213
- ```json
214
- "CALLBACK": [
215
- { "MESS": "Cập nhật thành công." },
216
- { "dlUserInfo": false },
217
- { "CALL": "getUser" }
218
- ]
219
- ```
220
-
221
- ```json
222
- "CALLBACK": [
223
- { "CALL": "getUserModule" },
224
- { "sUserDeptSelected": [], "dlAddUser": false },
225
- { "MESS": "Thêm user thành công." }
226
- ]
227
- ```
228
-
229
- Usual order: reload data → reset state → show message.
230
-
231
- ---
232
-
233
- ## 8. `set` — module-level config
234
-
235
- `set` at module.json root configures the whole module.
236
-
237
- ```json
238
- "set": {
239
- "menu": false
240
- }
241
- ```
242
-
243
- - `menu: false` — hide navigation menu (sub-windows, log viewers).
244
-
245
- > Module opened via `openWindow`: declare `"set": { "menu": false }` in the child module's module.json — **don't** pass `?menu=0` in the URL. Full pattern (incl. setting it dynamically from `data[]`): [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md).
246
-
247
- ---
248
-
249
- ## 9. CALLBACK with JS expression
250
-
251
- `{{ expression }}` in CALLBACK runs complex code after the API.
252
-
253
- ```json
254
- "CALLBACK": "{{ _.forEach(dsUsers, (x)=> x.FunctionName = JSON.parse(x.FunctionName)) }}"
255
- ```
256
-
257
- ```json
258
- "CALLBACK": "{{ _.forEach(dsUserFunction, (x)=> x.FunctionName = JSON.parse(x.FunctionName)), _.forEach(dsUserFunction, (x)=> x.UserSysItem = JSON.parse(x.UserSysItem)) }}"
259
- ```
260
-
261
- > Use when the API returns a JSON string that must be parsed to object/array before render.
262
-
263
- ---
264
-
265
- ## 10. script.js — helpers
266
-
267
- `script.js` holds helpers called from `v-on:click` or actions. They access `vueData` directly; use for logic plain action JSON can't express.
268
-
269
- ```javascript
270
- // script.js
271
- function setFunction(user, fc) {
272
- vueData.sFunctionSelected = [];
273
- vueData.sUserSelected = [];
274
- vueData.sUserSelected.push(user);
275
- if (!fc) return;
276
- vueData.dsFunctionRight.map((item) => {
277
- if (fc.some((fci) => fci.FunctionID == item.FunctionID)) {
278
- vueData.sFunctionSelected.push(item.FunctionID.toString());
279
- }
280
- });
281
- }
282
- ```
283
-
284
- Called from `v-on:click` in a header:
285
-
286
- ```json
287
- "v-on:click": "vueData.dlFunction = true; CALL(setFunction(item, item.FunctionName));"
288
- ```
289
-
290
- ---
291
-
292
- ## UI design checklist
293
-
294
- > `module.json` structure checklist (`data[]` order, grid wrapper, `w`, `v-on:`, `set`, valid JSON) is in [module-json-anatomy.md](module-json-anatomy.md). Below is UI-specific only.
295
-
296
- 1. **Toolbar row**: shrink filters + v-spacer + permission-gated buttons
297
- 2. **f-table**: fixed-header, item-class for row highlight, correct item-key — [ui-table-cell-patterns.md](ui-table-cell-patterns.md)
298
- 3. **Dialogs**: always in hidden-container, v-card[padding:0] + v-toolbar[dense flat] — [ui-dialog-patterns.md](ui-dialog-patterns.md)
299
- 4. **menuChucNang**: define in data[], reference via t-menu in headers — [ui-table-cell-patterns.md](ui-table-cell-patterns.md)
300
- 5. **ctrl-update**: simple CRUD; manual dialog for complex forms
301
- 6. **CALLBACK**: chaining array — reload → reset state → MESS
302
- 7. **#PARENT**: set at the top of data[] before startup CALLs — [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md)
303
- 8. **Permission**: `v-if: "vueData.user.SystemRight>1"` for admin-only sections
1
+ # FUI UI Patterns — Core
2
+
3
+ > Owns: **core UI patterns: toolbar/filter, permission gate, UI design checklist**. Table/dialog/cross-window/layout live in separate `ui-*` files.
4
+
5
+ Patterns taken from project **security-manager** — use as reference for new modules. Load specialised files as needed:
6
+
7
+ | Need | File |
8
+ | -------------------------------------------------------------------------------------- | -------------------------------------------------------- |
9
+ | f-table + in-cell controls (t-check/t-button/t-select/t-menu, ctrl-update, chip-group) | [ui-table-cell-patterns.md](ui-table-cell-patterns.md) |
10
+ | Dialog/popup form (hidden-container, open dialog with row, checkbox-list) | [ui-dialog-patterns.md](ui-dialog-patterns.md) |
11
+ | Sub-window & data exchange (`openWindow`, `#PARENT`/`#Win`) | [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md) |
12
+ | Layout (page-container, master-detail, v-switch, date init, dynamic label) | [ui-layout-patterns.md](ui-layout-patterns.md) |
13
+
14
+ ---
15
+
16
+ ## 1. `data[]` structure
17
+
18
+ `data` initialises state + actions, processed top to bottom.
19
+
20
+ - Object with **no action key** (no API, CALL, IF…) → state init
21
+ - Object whose **key is a function name** → named (reusable) action
22
+ - Trailing `{ "API": ..., "OUT": ... }` or `{ "CALL": ... }` → runs automatically on load
23
+
24
+ ```json
25
+ "data": [
26
+ {
27
+ "dsUser": [],
28
+ "dsGroup": [],
29
+ "sDepartment": null,
30
+ "dlUserInfo": false
31
+ },
32
+ {
33
+ "getDepartment": { "API": "SM_DepartmentSelectAll", "OUT": "dsDepartment" },
34
+ "getGroup": { "API": "SM_Group_SelectAll", "OUT": "dsGroup" },
35
+ "getUser": {
36
+ "API": "SM_Users_SelectByDepGroup",
37
+ "IN": { "GroupID": "sGroup", "DepartmentID": "sDepartment" },
38
+ "OUT": "dsUser"
39
+ }
40
+ },
41
+ { "CALL": "getDepartment" },
42
+ { "CALL": "getGroup" }
43
+ ]
44
+ ```
45
+
46
+ > **Auto-startup**: trailing CALLs in `data[]` run on module load — no event handler needed.
47
+
48
+ ---
49
+
50
+ ## 2. Cascading API init
51
+
52
+ `CALLBACK` sets a value from the first API result; the next API runs via `watch`.
53
+
54
+ ```json
55
+ "data": [
56
+ { "dsModule": [], "sModuleID": null },
57
+ {
58
+ "API": "/SM_Modules_SelectAll",
59
+ "OUT": "dsModule",
60
+ "CALLBACK": { "sModuleID": "dsModule[0].ModuleID" }
61
+ }
62
+ ],
63
+ "watch": {
64
+ "sModuleID": { "CALL": "getFunctionRight" }
65
+ }
66
+ ```
67
+
68
+ > CALLBACK sets `sModuleID` → watch fires `getFunctionRight`. No manual call.
69
+
70
+ ---
71
+
72
+ ## 3. Watch — cascading filter
73
+
74
+ Filter change → reload. Several actions → array of CALL.
75
+
76
+ ```json
77
+ "watch": {
78
+ "sDepartment": { "CALL": "getUser" },
79
+ "sGroup": { "CALL": "getUser" },
80
+ "sModuleID": [
81
+ { "CALL": "getUserModule" },
82
+ { "CALL": "getSysRight" },
83
+ { "CALL": "getFunctionRight" }
84
+ ]
85
+ }
86
+ ```
87
+
88
+ ---
89
+
90
+ ## 4. Toolbar / filter row
91
+
92
+ Row of filter fields + action buttons; `v-spacer` pushes the button group right.
93
+
94
+ > **Rule: EVERY column is `"col": "shrink"` except `v-spacer`.** A non-`shrink` column takes a share of free space — including an empty-`w` column and buttons. Missing `shrink` → buttons stretch, gaps appear between buttons, and the trailing group doesn't reach the right edge even with `v-spacer`. Standard template + measurements: [controls-patterns.md](controls-patterns.md) §Toolbar row.
95
+
96
+ ```json
97
+ {
98
+ "prop": "",
99
+ "cols": [
100
+ {
101
+ "el": "v-autocomplete",
102
+ "col": { "class": "shrink" },
103
+ "attr": {
104
+ "class": "flex-md-grow-0",
105
+ "style": "width:200px",
106
+ "v-model": "sGroup",
107
+ "label": "Group",
108
+ ":items": "dsGroup",
109
+ "item-text": "GroupName",
110
+ "item-value": "GroupID",
111
+ ":required": false
112
+ },
113
+ "w": "200"
114
+ },
115
+ {
116
+ "el": "v-text-field",
117
+ "col": { "class": "shrink" },
118
+ "attr": {
119
+ "class": "flex-md-grow-0",
120
+ "style": "width:200px",
121
+ "v-model": "UserID",
122
+ "label": "User ID",
123
+ "clearable": ""
124
+ },
125
+ "w": "200"
126
+ },
127
+ {
128
+ "el": "f-button",
129
+ "col": { "class": "shrink" },
130
+ "attr": {
131
+ ":checkvalid": false,
132
+ "color": "primary",
133
+ "label": "Tìm",
134
+ "icon-text": "mdi-magnify",
135
+ ":action": { "CALL": "getUser" }
136
+ }
137
+ },
138
+ { "el": "v-spacer", "attr": {} },
139
+ {
140
+ "el": "f-button",
141
+ "col": { "v-if": "vueData.user.SystemRight==9", "class": "shrink" },
142
+ "attr": {
143
+ ":checkvalid": false,
144
+ ":disabled": "!sGroup",
145
+ "color": "primary",
146
+ "label": "Add User",
147
+ "icon-text": "mdi-account-multiple-plus",
148
+ ":action": [{ "addNew": 1, "sUserID": "", "sUserName": "" }, { "dlUserInfo": true }]
149
+ }
150
+ }
151
+ ]
152
+ }
153
+ ```
154
+
155
+ - Filter fields: `w` in px (`>= 25`) + `col: "shrink"`. The `attr: { class: "flex-md-grow-0", style: "width:Xpx" }` pair above is **redundant** — `w` + `shrink` already gives that width (measured: `w:150` + `shrink` → exactly 150px on V2 and V3). It stays only because the example is copied from production; omit it in new code.
156
+ - Search button right after the fields, also `col: "shrink"` (a non-shrink button stretches).
157
+ - **Always `class: "shrink"` / `"col": "shrink"`, never `shrink: true`** — the bare attribute works only on V2; on V3 it's inert and the column goes full width.
158
+ - `v-spacer` is the **only** non-`shrink` column — it must grow to push the following group right.
159
+ - Admin Add/Delete buttons: after the spacer, permission `v-if` — `col: { "v-if": "…", "class": "shrink" }` (object form when extra keys are needed; keep `shrink`).
160
+ - Right-align the whole row without `v-spacer`: `"prop": "row justify-end"`.
161
+
162
+ ---
163
+
164
+ ## 5. Permission gating
165
+
166
+ Show/hide by the user's `SystemRight`.
167
+
168
+ ```json
169
+ "col": { "v-if": "vueData.user.SystemRight>1" }
170
+ "col": { "v-if": "vueData.user.SystemRight==9" }
171
+ ```
172
+
173
+ - `>1` — any user with rights (not the lowest level)
174
+ - `==9` — top admin only
175
+
176
+ ---
177
+
178
+ ## 6. IF/THEN/ELSE
179
+
180
+ Branching inside an action or CALLBACK.
181
+
182
+ ```json
183
+ {
184
+ "IF": "TypeLoad==1",
185
+ "THEN": { "CALL": "getComputer" },
186
+ "ELSE": {
187
+ "IF": "TypeLoad==2",
188
+ "THEN": { "CALL": "getComputerDinied" },
189
+ "ELSE": { "CALL": "getComputerNotVisited" }
190
+ }
191
+ }
192
+ ```
193
+
194
+ - Condition: JS expression using vueData fields directly (no `vueData.` prefix).
195
+ - Nest IF/ELSE for multi-branch switch.
196
+
197
+ Real use: module with several view modes (`TypeLoad`) — after an update, refresh the list currently shown.
198
+
199
+ ```json
200
+ "data": [
201
+ { "TypeLoad": 1 }
202
+ ]
203
+ ```
204
+
205
+ ---
206
+
207
+ ## 7. CALLBACK chaining
208
+
209
+ Array CALLBACK → runs in order.
210
+
211
+ > **Several commands MUST be an array, one `{}` per command.** Merging `CALL` + `MESS` + `EXE` into one object runs only **one** (priority `API` → `CALL` → `EXE` → `FUN` → `IF` → `MESS` → `MESSBOX`, each branch `return`s immediately); the rest are dropped silently — no error, no `[Vue warn]`. Full rule + runtime reason: [controls-patterns.md](controls-patterns.md) §CORE RULE.
212
+
213
+ ```json
214
+ "CALLBACK": [
215
+ { "MESS": "Cập nhật thành công." },
216
+ { "dlUserInfo": false },
217
+ { "CALL": "getUser" }
218
+ ]
219
+ ```
220
+
221
+ ```json
222
+ "CALLBACK": [
223
+ { "CALL": "getUserModule" },
224
+ { "sUserDeptSelected": [], "dlAddUser": false },
225
+ { "MESS": "Thêm user thành công." }
226
+ ]
227
+ ```
228
+
229
+ Usual order: reload data → reset state → show message.
230
+
231
+ ---
232
+
233
+ ## 8. `set` — module-level config
234
+
235
+ `set` at module.json root configures the whole module.
236
+
237
+ ```json
238
+ "set": {
239
+ "menu": false
240
+ }
241
+ ```
242
+
243
+ - `menu: false` — hide navigation menu (sub-windows, log viewers).
244
+
245
+ > Module opened via `openWindow`: declare `"set": { "menu": false }` in the child module's module.json — **don't** pass `?menu=0` in the URL. Full pattern (incl. setting it dynamically from `data[]`): [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md).
246
+
247
+ ---
248
+
249
+ ## 9. CALLBACK with JS expression
250
+
251
+ `{{ expression }}` in CALLBACK runs complex code after the API.
252
+
253
+ ```json
254
+ "CALLBACK": "{{ _.forEach(dsUsers, (x)=> x.FunctionName = JSON.parse(x.FunctionName)) }}"
255
+ ```
256
+
257
+ ```json
258
+ "CALLBACK": "{{ _.forEach(dsUserFunction, (x)=> x.FunctionName = JSON.parse(x.FunctionName)), _.forEach(dsUserFunction, (x)=> x.UserSysItem = JSON.parse(x.UserSysItem)) }}"
259
+ ```
260
+
261
+ > Use when the API returns a JSON string that must be parsed to object/array before render.
262
+
263
+ ---
264
+
265
+ ## 10. script.js — helpers
266
+
267
+ `script.js` holds helpers called from `v-on:click` or actions. They access `vueData` directly; use for logic plain action JSON can't express.
268
+
269
+ ```javascript
270
+ // script.js
271
+ function setFunction(user, fc) {
272
+ vueData.sFunctionSelected = [];
273
+ vueData.sUserSelected = [];
274
+ vueData.sUserSelected.push(user);
275
+ if (!fc) return;
276
+ vueData.dsFunctionRight.map((item) => {
277
+ if (fc.some((fci) => fci.FunctionID == item.FunctionID)) {
278
+ vueData.sFunctionSelected.push(item.FunctionID.toString());
279
+ }
280
+ });
281
+ }
282
+ ```
283
+
284
+ Called from `v-on:click` in a header:
285
+
286
+ ```json
287
+ "v-on:click": "vueData.dlFunction = true; CALL(setFunction(item, item.FunctionName));"
288
+ ```
289
+
290
+ ---
291
+
292
+ ## UI design checklist
293
+
294
+ > `module.json` structure checklist (`data[]` order, grid wrapper, `w`, `v-on:`, `set`, valid JSON) is in [module-json-anatomy.md](module-json-anatomy.md). Below is UI-specific only.
295
+
296
+ 1. **Toolbar row**: shrink filters + v-spacer + permission-gated buttons
297
+ 2. **f-table**: fixed-header, item-class for row highlight, correct item-key — [ui-table-cell-patterns.md](ui-table-cell-patterns.md)
298
+ 3. **Dialogs**: always in hidden-container, v-card[padding:0] + v-toolbar[dense flat] — [ui-dialog-patterns.md](ui-dialog-patterns.md)
299
+ 4. **menuChucNang**: define in data[], reference via t-menu in headers — [ui-table-cell-patterns.md](ui-table-cell-patterns.md)
300
+ 5. **ctrl-update**: simple CRUD; manual dialog for complex forms
301
+ 6. **CALLBACK**: chaining array — reload → reset state → MESS
302
+ 7. **#PARENT**: set at the top of data[] before startup CALLs — [ui-crosswindow-patterns.md](ui-crosswindow-patterns.md)
303
+ 8. **Permission**: `v-if: "vueData.user.SystemRight>1"` for admin-only sections