@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.
Files changed (214) hide show
  1. package/README.md +16 -7
  2. package/dist/fui-xg17j3f9.js +396 -0
  3. package/dist/fui.js +1 -1
  4. package/package.json +1 -1
  5. package/skills/fui/SKILL.md +152 -39
  6. package/skills/{fui-skill → fui}/assets/projectdefaultstyle.css +489 -489
  7. package/skills/{fui-skill → fui}/examples/component.vue +162 -162
  8. package/skills/{fui-skill → fui}/references/INDEX.md +4 -5
  9. package/skills/{fui-skill → fui}/references/advanced-techniques.md +170 -168
  10. package/skills/{fui-skill → fui}/references/component-design.md +2 -2
  11. package/skills/{fui-skill → fui}/references/component-quickref.md +78 -78
  12. package/skills/{fui-skill → fui}/references/component-table.md +287 -287
  13. package/skills/{fui-skill → fui}/references/components-dialog.md +191 -191
  14. package/skills/{fui-skill → fui}/references/components-display.md +141 -141
  15. package/skills/{fui-skill → fui}/references/components-echart.md +316 -316
  16. package/skills/{fui-skill → fui}/references/components-input.md +335 -335
  17. package/skills/{fui-skill → fui}/references/controls-patterns.md +2 -2
  18. package/skills/{fui-skill → fui}/references/controls-styling-vocabulary.md +173 -173
  19. package/skills/{fui-skill → fui}/references/db-workflow.md +9 -9
  20. package/skills/{fui-skill → fui}/references/default-function.md +456 -456
  21. package/skills/{fui-skill → fui}/references/design-modes.md +57 -57
  22. package/skills/{fui-skill → fui}/references/echart-templates.md +489 -489
  23. package/skills/{fui-skill → fui}/references/fastproject.md +99 -99
  24. package/skills/{fui-skill → fui}/references/fullstack-workflow.md +314 -313
  25. package/skills/{fui-skill → fui}/references/module-data-patterns.md +117 -117
  26. package/skills/{fui-skill → fui}/references/module-json-anatomy.md +132 -132
  27. package/skills/{fui-skill → fui}/references/module-structure.md +144 -144
  28. package/skills/{fui-skill → fui}/references/new-session.md +3 -20
  29. package/skills/{fui-skill → fui}/references/pdfmake.md +60 -60
  30. package/skills/{fui-skill → fui}/references/permission-system.md +1 -1
  31. package/skills/{fui-skill → fui}/references/platform-architecture.md +269 -269
  32. package/skills/{fui-skill → fui}/references/project-config.md +303 -303
  33. package/skills/{fui-skill → fui}/references/project-provisioning.md +4 -4
  34. package/skills/{fui-skill → fui}/references/script-map.md +262 -262
  35. package/skills/{fui-skill → fui}/references/sql-clr-functions.md +225 -225
  36. package/skills/{fui-skill → fui}/references/system-design.md +3 -3
  37. package/skills/{fui-skill → fui}/references/tapi-permission-patterns.md +156 -156
  38. package/skills/{fui-skill → fui}/references/tapi-reference.md +474 -474
  39. package/skills/fui/references/tools-registry.md +214 -0
  40. package/skills/{fui-skill → fui}/references/ui-crosswindow-patterns.md +321 -321
  41. package/skills/{fui-skill → fui}/references/ui-dialog-patterns.md +255 -255
  42. package/skills/{fui-skill → fui}/references/ui-layout-patterns.md +176 -176
  43. package/skills/{fui-skill → fui}/references/ui-patterns.md +303 -303
  44. package/skills/{fui-skill → fui}/references/ui-screenshot-review.md +95 -95
  45. package/skills/{fui-skill → fui}/references/ui-table-cell-patterns.md +318 -318
  46. package/skills/{fui-skill → fui}/references/verification.md +18 -18
  47. package/skills/{fui-skill → fui}/references/watcher-patterns.md +163 -163
  48. package/skills/{fui-skill → fui}/references/websocket-realtime.md +271 -271
  49. package/skills/{fui-skill → fui}/scripts/component-3.0.js +2715 -2715
  50. package/skills/{fui-skill → fui}/scripts/component.js +3147 -3147
  51. package/skills/{fui-skill → fui}/scripts/componentTable-3.0.js +1038 -1038
  52. package/skills/{fui-skill → fui}/scripts/componentTable.js +891 -891
  53. package/skills/{fui-skill → fui}/scripts/defaultfunction-3.0.js +866 -866
  54. package/skills/{fui-skill → fui}/scripts/defaultfunction.js +1051 -1051
  55. package/skills/{fui-skill → fui}/scripts/fastproject-3.0.js +870 -870
  56. package/skills/{fui-skill → fui}/scripts/fastproject.js +828 -828
  57. package/dist/fui-h4z7zhk2.js +0 -381
  58. package/skills/fui-skill/SKILL.md +0 -139
  59. package/skills/fui-skill/references/tools-registry.md +0 -84
  60. /package/skills/{fui-skill → fui}/assets/projectdefaultstyle-3.0.css +0 -0
  61. /package/skills/{fui-skill → fui}/design-md/airbnb/DESIGN.md +0 -0
  62. /package/skills/{fui-skill → fui}/design-md/airbnb/README.md +0 -0
  63. /package/skills/{fui-skill → fui}/design-md/airtable/DESIGN.md +0 -0
  64. /package/skills/{fui-skill → fui}/design-md/airtable/README.md +0 -0
  65. /package/skills/{fui-skill → fui}/design-md/apple/DESIGN.md +0 -0
  66. /package/skills/{fui-skill → fui}/design-md/apple/README.md +0 -0
  67. /package/skills/{fui-skill → fui}/design-md/asu/DESIGN.md +0 -0
  68. /package/skills/{fui-skill → fui}/design-md/asu/README.md +0 -0
  69. /package/skills/{fui-skill → fui}/design-md/binance/DESIGN.md +0 -0
  70. /package/skills/{fui-skill → fui}/design-md/binance/README.md +0 -0
  71. /package/skills/{fui-skill → fui}/design-md/bmw/DESIGN.md +0 -0
  72. /package/skills/{fui-skill → fui}/design-md/bmw/README.md +0 -0
  73. /package/skills/{fui-skill → fui}/design-md/bmw-m/DESIGN.md +0 -0
  74. /package/skills/{fui-skill → fui}/design-md/bmw-m/README.md +0 -0
  75. /package/skills/{fui-skill → fui}/design-md/bugatti/DESIGN.md +0 -0
  76. /package/skills/{fui-skill → fui}/design-md/bugatti/README.md +0 -0
  77. /package/skills/{fui-skill → fui}/design-md/cal/DESIGN.md +0 -0
  78. /package/skills/{fui-skill → fui}/design-md/cal/README.md +0 -0
  79. /package/skills/{fui-skill → fui}/design-md/claude/DESIGN.md +0 -0
  80. /package/skills/{fui-skill → fui}/design-md/claude/README.md +0 -0
  81. /package/skills/{fui-skill → fui}/design-md/clay/DESIGN.md +0 -0
  82. /package/skills/{fui-skill → fui}/design-md/clay/README.md +0 -0
  83. /package/skills/{fui-skill → fui}/design-md/clickhouse/DESIGN.md +0 -0
  84. /package/skills/{fui-skill → fui}/design-md/clickhouse/README.md +0 -0
  85. /package/skills/{fui-skill → fui}/design-md/cohere/DESIGN.md +0 -0
  86. /package/skills/{fui-skill → fui}/design-md/cohere/README.md +0 -0
  87. /package/skills/{fui-skill → fui}/design-md/coinbase/DESIGN.md +0 -0
  88. /package/skills/{fui-skill → fui}/design-md/coinbase/README.md +0 -0
  89. /package/skills/{fui-skill → fui}/design-md/composio/DESIGN.md +0 -0
  90. /package/skills/{fui-skill → fui}/design-md/composio/README.md +0 -0
  91. /package/skills/{fui-skill → fui}/design-md/cursor/DESIGN.md +0 -0
  92. /package/skills/{fui-skill → fui}/design-md/cursor/README.md +0 -0
  93. /package/skills/{fui-skill → fui}/design-md/elevenlabs/DESIGN.md +0 -0
  94. /package/skills/{fui-skill → fui}/design-md/elevenlabs/README.md +0 -0
  95. /package/skills/{fui-skill → fui}/design-md/expo/DESIGN.md +0 -0
  96. /package/skills/{fui-skill → fui}/design-md/expo/README.md +0 -0
  97. /package/skills/{fui-skill → fui}/design-md/ferrari/DESIGN.md +0 -0
  98. /package/skills/{fui-skill → fui}/design-md/ferrari/README.md +0 -0
  99. /package/skills/{fui-skill → fui}/design-md/figma/DESIGN.md +0 -0
  100. /package/skills/{fui-skill → fui}/design-md/figma/README.md +0 -0
  101. /package/skills/{fui-skill → fui}/design-md/framer/DESIGN.md +0 -0
  102. /package/skills/{fui-skill → fui}/design-md/framer/README.md +0 -0
  103. /package/skills/{fui-skill → fui}/design-md/fui/DESIGN.md +0 -0
  104. /package/skills/{fui-skill → fui}/design-md/hashicorp/DESIGN.md +0 -0
  105. /package/skills/{fui-skill → fui}/design-md/hashicorp/README.md +0 -0
  106. /package/skills/{fui-skill → fui}/design-md/ibm/DESIGN.md +0 -0
  107. /package/skills/{fui-skill → fui}/design-md/ibm/README.md +0 -0
  108. /package/skills/{fui-skill → fui}/design-md/intercom/DESIGN.md +0 -0
  109. /package/skills/{fui-skill → fui}/design-md/intercom/README.md +0 -0
  110. /package/skills/{fui-skill → fui}/design-md/kraken/DESIGN.md +0 -0
  111. /package/skills/{fui-skill → fui}/design-md/kraken/README.md +0 -0
  112. /package/skills/{fui-skill → fui}/design-md/lamborghini/DESIGN.md +0 -0
  113. /package/skills/{fui-skill → fui}/design-md/lamborghini/README.md +0 -0
  114. /package/skills/{fui-skill → fui}/design-md/linear.app/DESIGN.md +0 -0
  115. /package/skills/{fui-skill → fui}/design-md/linear.app/README.md +0 -0
  116. /package/skills/{fui-skill → fui}/design-md/lovable/DESIGN.md +0 -0
  117. /package/skills/{fui-skill → fui}/design-md/lovable/README.md +0 -0
  118. /package/skills/{fui-skill → fui}/design-md/mastercard/DESIGN.md +0 -0
  119. /package/skills/{fui-skill → fui}/design-md/mastercard/README.md +0 -0
  120. /package/skills/{fui-skill → fui}/design-md/meta/DESIGN.md +0 -0
  121. /package/skills/{fui-skill → fui}/design-md/meta/README.md +0 -0
  122. /package/skills/{fui-skill → fui}/design-md/minimax/DESIGN.md +0 -0
  123. /package/skills/{fui-skill → fui}/design-md/minimax/README.md +0 -0
  124. /package/skills/{fui-skill → fui}/design-md/mintlify/DESIGN.md +0 -0
  125. /package/skills/{fui-skill → fui}/design-md/mintlify/README.md +0 -0
  126. /package/skills/{fui-skill → fui}/design-md/miro/DESIGN.md +0 -0
  127. /package/skills/{fui-skill → fui}/design-md/miro/README.md +0 -0
  128. /package/skills/{fui-skill → fui}/design-md/mistral.ai/DESIGN.md +0 -0
  129. /package/skills/{fui-skill → fui}/design-md/mistral.ai/README.md +0 -0
  130. /package/skills/{fui-skill → fui}/design-md/mongodb/DESIGN.md +0 -0
  131. /package/skills/{fui-skill → fui}/design-md/mongodb/README.md +0 -0
  132. /package/skills/{fui-skill → fui}/design-md/nike/DESIGN.md +0 -0
  133. /package/skills/{fui-skill → fui}/design-md/nike/README.md +0 -0
  134. /package/skills/{fui-skill → fui}/design-md/notion/DESIGN.md +0 -0
  135. /package/skills/{fui-skill → fui}/design-md/notion/README.md +0 -0
  136. /package/skills/{fui-skill → fui}/design-md/nvidia/DESIGN.md +0 -0
  137. /package/skills/{fui-skill → fui}/design-md/nvidia/README.md +0 -0
  138. /package/skills/{fui-skill → fui}/design-md/ollama/DESIGN.md +0 -0
  139. /package/skills/{fui-skill → fui}/design-md/ollama/README.md +0 -0
  140. /package/skills/{fui-skill → fui}/design-md/opencode.ai/DESIGN.md +0 -0
  141. /package/skills/{fui-skill → fui}/design-md/opencode.ai/README.md +0 -0
  142. /package/skills/{fui-skill → fui}/design-md/pinterest/DESIGN.md +0 -0
  143. /package/skills/{fui-skill → fui}/design-md/pinterest/README.md +0 -0
  144. /package/skills/{fui-skill → fui}/design-md/playstation/DESIGN.md +0 -0
  145. /package/skills/{fui-skill → fui}/design-md/playstation/README.md +0 -0
  146. /package/skills/{fui-skill → fui}/design-md/posthog/DESIGN.md +0 -0
  147. /package/skills/{fui-skill → fui}/design-md/posthog/README.md +0 -0
  148. /package/skills/{fui-skill → fui}/design-md/raycast/DESIGN.md +0 -0
  149. /package/skills/{fui-skill → fui}/design-md/raycast/README.md +0 -0
  150. /package/skills/{fui-skill → fui}/design-md/renault/DESIGN.md +0 -0
  151. /package/skills/{fui-skill → fui}/design-md/renault/README.md +0 -0
  152. /package/skills/{fui-skill → fui}/design-md/replicate/DESIGN.md +0 -0
  153. /package/skills/{fui-skill → fui}/design-md/replicate/README.md +0 -0
  154. /package/skills/{fui-skill → fui}/design-md/resend/DESIGN.md +0 -0
  155. /package/skills/{fui-skill → fui}/design-md/resend/README.md +0 -0
  156. /package/skills/{fui-skill → fui}/design-md/revolut/DESIGN.md +0 -0
  157. /package/skills/{fui-skill → fui}/design-md/revolut/README.md +0 -0
  158. /package/skills/{fui-skill → fui}/design-md/runwayml/DESIGN.md +0 -0
  159. /package/skills/{fui-skill → fui}/design-md/runwayml/README.md +0 -0
  160. /package/skills/{fui-skill → fui}/design-md/sanity/DESIGN.md +0 -0
  161. /package/skills/{fui-skill → fui}/design-md/sanity/README.md +0 -0
  162. /package/skills/{fui-skill → fui}/design-md/sentry/DESIGN.md +0 -0
  163. /package/skills/{fui-skill → fui}/design-md/sentry/README.md +0 -0
  164. /package/skills/{fui-skill → fui}/design-md/shopify/DESIGN.md +0 -0
  165. /package/skills/{fui-skill → fui}/design-md/shopify/README.md +0 -0
  166. /package/skills/{fui-skill → fui}/design-md/slack/DESIGN.md +0 -0
  167. /package/skills/{fui-skill → fui}/design-md/spacex/DESIGN.md +0 -0
  168. /package/skills/{fui-skill → fui}/design-md/spacex/README.md +0 -0
  169. /package/skills/{fui-skill → fui}/design-md/spotify/DESIGN.md +0 -0
  170. /package/skills/{fui-skill → fui}/design-md/spotify/README.md +0 -0
  171. /package/skills/{fui-skill → fui}/design-md/starbucks/DESIGN.md +0 -0
  172. /package/skills/{fui-skill → fui}/design-md/starbucks/README.md +0 -0
  173. /package/skills/{fui-skill → fui}/design-md/stripe/DESIGN.md +0 -0
  174. /package/skills/{fui-skill → fui}/design-md/stripe/README.md +0 -0
  175. /package/skills/{fui-skill → fui}/design-md/supabase/DESIGN.md +0 -0
  176. /package/skills/{fui-skill → fui}/design-md/supabase/README.md +0 -0
  177. /package/skills/{fui-skill → fui}/design-md/superhuman/DESIGN.md +0 -0
  178. /package/skills/{fui-skill → fui}/design-md/superhuman/README.md +0 -0
  179. /package/skills/{fui-skill → fui}/design-md/tesla/DESIGN.md +0 -0
  180. /package/skills/{fui-skill → fui}/design-md/tesla/README.md +0 -0
  181. /package/skills/{fui-skill → fui}/design-md/theverge/DESIGN.md +0 -0
  182. /package/skills/{fui-skill → fui}/design-md/theverge/README.md +0 -0
  183. /package/skills/{fui-skill → fui}/design-md/together.ai/DESIGN.md +0 -0
  184. /package/skills/{fui-skill → fui}/design-md/together.ai/README.md +0 -0
  185. /package/skills/{fui-skill → fui}/design-md/uber/DESIGN.md +0 -0
  186. /package/skills/{fui-skill → fui}/design-md/uber/README.md +0 -0
  187. /package/skills/{fui-skill → fui}/design-md/vercel/DESIGN.md +0 -0
  188. /package/skills/{fui-skill → fui}/design-md/vercel/README.md +0 -0
  189. /package/skills/{fui-skill → fui}/design-md/vodafone/DESIGN.md +0 -0
  190. /package/skills/{fui-skill → fui}/design-md/vodafone/README.md +0 -0
  191. /package/skills/{fui-skill → fui}/design-md/voltagent/DESIGN.md +0 -0
  192. /package/skills/{fui-skill → fui}/design-md/voltagent/README.md +0 -0
  193. /package/skills/{fui-skill → fui}/design-md/warp/DESIGN.md +0 -0
  194. /package/skills/{fui-skill → fui}/design-md/warp/README.md +0 -0
  195. /package/skills/{fui-skill → fui}/design-md/webflow/DESIGN.md +0 -0
  196. /package/skills/{fui-skill → fui}/design-md/webflow/README.md +0 -0
  197. /package/skills/{fui-skill → fui}/design-md/wired/DESIGN.md +0 -0
  198. /package/skills/{fui-skill → fui}/design-md/wired/README.md +0 -0
  199. /package/skills/{fui-skill → fui}/design-md/wise/DESIGN.md +0 -0
  200. /package/skills/{fui-skill → fui}/design-md/wise/README.md +0 -0
  201. /package/skills/{fui-skill → fui}/design-md/x.ai/DESIGN.md +0 -0
  202. /package/skills/{fui-skill → fui}/design-md/x.ai/README.md +0 -0
  203. /package/skills/{fui-skill → fui}/design-md/zapier/DESIGN.md +0 -0
  204. /package/skills/{fui-skill → fui}/design-md/zapier/README.md +0 -0
  205. /package/skills/{fui-skill → fui}/examples/f-table-patterns.json +0 -0
  206. /package/skills/{fui-skill → fui}/examples/module-patterns.json +0 -0
  207. /package/skills/{fui-skill → fui}/examples/project-patterns.json +0 -0
  208. /package/skills/{fui-skill → fui}/references/coding-standards.md +0 -0
  209. /package/skills/{fui-skill → fui}/references/db-table-design.md +0 -0
  210. /package/skills/{fui-skill → fui}/references/fsheet.md +0 -0
  211. /package/skills/{fui-skill → fui}/references/tapi-file-api.md +0 -0
  212. /package/skills/{fui-skill → fui}/references/ui-templates.md +0 -0
  213. /package/skills/{fui-skill → fui}/scripts/fechart.js +0 -0
  214. /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