@aiderdesk/aiderdesk 0.61.0-dev → 0.61.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/out/renderer/assets/__vite-browser-external-2447137e-DYxpcVy9.js +4 -0
- package/out/renderer/assets/{_baseUniq-Z8t1Ab1g.js → _baseUniq-BPF2Herp.js} +21 -197
- package/out/renderer/assets/{arc-CwESpVYE.js → arc-DfPLteHF.js} +1 -1
- package/out/renderer/assets/{architectureDiagram-2XIMDMQ5-C490EQr5.js → architectureDiagram-Q4EWVU46-Bw0u-sSH.js} +34 -20
- package/out/renderer/assets/{blockDiagram-WCTKOSBZ-DbHssxrQ.js → blockDiagram-DXYQGD6D-CkfB9if8.js} +21 -8
- package/out/renderer/assets/{c4Diagram-IC4MRINW-BxE3GUKu.js → c4Diagram-AHTNJAMY-DweK9Liz.js} +31 -35
- package/out/renderer/assets/{channel-C9hJq_Xr.js → channel-C5wwrRof.js} +1 -1
- package/out/renderer/assets/{chunk-4BX2VUAB-ChcKNpL6.js → chunk-4BX2VUAB-0KM14cFd.js} +1 -1
- package/out/renderer/assets/{chunk-WL4C6EOR-vhby2fZi.js → chunk-4TB4RGXK-CmVtCVL4.js} +121 -82
- package/out/renderer/assets/{chunk-55IACEB6-oLT9lXTt.js → chunk-55IACEB6-BzVYZvBM.js} +1 -1
- package/out/renderer/assets/{chunk-KX2RTZJC-D32tV7H-.js → chunk-EDXVE4YY-BryQl5Kv.js} +1 -1
- package/out/renderer/assets/{chunk-FMBD7UC4-B5k8rETe.js → chunk-FMBD7UC4-CRiLea_e.js} +1 -1
- package/out/renderer/assets/{chunk-NQ4KR5QH-Bmqo2FpL.js → chunk-OYMX7WX6-Cpi4N3NO.js} +32 -15
- package/out/renderer/assets/{chunk-QZHKN3VN-8BpGifjS.js → chunk-QZHKN3VN-BT8kABWC.js} +1 -1
- package/out/renderer/assets/{chunk-JSJVCQXG-DtjSx6Cj.js → chunk-YZCP3GAM-OLZV_Sef.js} +1 -1
- package/out/renderer/assets/{classDiagram-VBA2DB6C-BxRSSb9e.js → classDiagram-6PBFFD2Q-VdE6G90i.js} +6 -6
- package/out/renderer/assets/{classDiagram-v2-RAHNMMFH-BxRSSb9e.js → classDiagram-v2-HSJHXN6E-VdE6G90i.js} +6 -6
- package/out/renderer/assets/{clone-D9a-uIZa.js → clone-DwQZ86nS.js} +1 -1
- package/out/renderer/assets/{cose-bilkent-S5V4N54A-CUqqQ-6R.js → cose-bilkent-S5V4N54A-BEcAKM9H.js} +1 -1
- package/out/renderer/assets/{dagre-KLK3FWXG-ORIwMMhq.js → dagre-KV5264BT-BcFQYL1M.js} +6 -6
- package/out/renderer/assets/diagram-5BDNPKRD-GrUNdC1u.js +171 -0
- package/out/renderer/assets/{diagram-E7M64L7V-bS9HcoDQ.js → diagram-G4DWMVQ6-CG4S-ov5.js} +15 -13
- package/out/renderer/assets/{diagram-IFDJBPK2-BRlTIR0J.js → diagram-MMDJMWI5-9ogY3MRC.js} +5 -6
- package/out/renderer/assets/{diagram-P4PSJMXO-jsjGwH-p.js → diagram-TYMM5635-Ck7mI1bS.js} +5 -6
- package/out/renderer/assets/{erDiagram-INFDFZHY-DGlgjHOQ.js → erDiagram-SMLLAGMA-Dvf_c-7M.js} +81 -35
- package/out/renderer/assets/{flowDiagram-PKNHOUZH-CzLC87bM.js → flowDiagram-DWJPFMVM-CPDjOXYp.js} +27 -45
- package/out/renderer/assets/{ganttDiagram-A5KZAMGK-BbDv36wT.js → ganttDiagram-T4ZO3ILL-B4dJrK-3.js} +17 -8
- package/out/renderer/assets/{gitGraphDiagram-K3NZZRJ6-CBQnBjEi.js → gitGraphDiagram-UUTBAWPF-De2eCfMN.js} +244 -67
- package/out/renderer/assets/{graph-Dl5N6maZ.js → graph-BFn23kR_.js} +175 -3
- package/out/renderer/assets/{index-MDHavDF9.js → index-BL-57WPa.js} +15877 -20787
- package/out/renderer/assets/{index-CDCy_DhA.css → index-BkntVzTm.css} +114 -301
- package/out/renderer/assets/{infoDiagram-LFFYTUFH-GtEDBEmz.js → infoDiagram-42DDH7IO-BIt9B6mQ.js} +5 -6
- package/out/renderer/assets/{ishikawaDiagram-PHBUUO56-Uj90gr3I.js → ishikawaDiagram-UXIWVN3A-CXZs0KGV.js} +3 -3
- package/out/renderer/assets/{journeyDiagram-4ABVD52K-DekFuOwS.js → journeyDiagram-VCZTEJTY-B-EXuj5b.js} +14 -13
- package/out/renderer/assets/{kanban-definition-K7BYSVSG-Hfz2L6NS.js → kanban-definition-6JOO6SKY-ByvN0qaD.js} +5 -2
- package/out/renderer/assets/{layout-B9K2VT39.js → layout-BpybWUv6.js} +117 -4
- package/out/renderer/assets/min-DB8ixvoT.js +41 -0
- package/out/renderer/assets/{mindmap-definition-YRQLILUH-DDcS7_GH.js → mindmap-definition-QFDTVHPH-Do-I-At8.js} +69 -13
- package/out/renderer/assets/{pieDiagram-SKSYHLDU-DwjEcJ0Q.js → pieDiagram-DEJITSTG-Cnpf6Gt6.js} +20 -13
- package/out/renderer/assets/{quadrantDiagram-337W2JSQ-CpGqN7vo.js → quadrantDiagram-34T5L4WZ-VcOb1qLd.js} +1 -1
- package/out/renderer/assets/{requirementDiagram-Z7DCOOCP-qDRUf1ip.js → requirementDiagram-MS252O5E-VJs9Hpaw.js} +42 -11
- package/out/renderer/assets/{sankeyDiagram-WA2Y5GQK-DRKS8C1H.js → sankeyDiagram-XADWPNL6-BoXxgLvi.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-2WXFIKYE-DhVN2ug2.js → sequenceDiagram-FGHM5R23-b69hQjSp.js} +446 -220
- package/out/renderer/assets/{stateDiagram-RAJIS63D-BpP4eSqu.js → stateDiagram-FHFEXIEX-BK7E-REm.js} +10 -9
- package/out/renderer/assets/{stateDiagram-v2-FVOUBMTO-B_qQJqra.js → stateDiagram-v2-QKLJ7IA2-Cd2wfCQu.js} +4 -4
- package/out/renderer/assets/{timeline-definition-YZTLITO2-UoWXE_76.js → timeline-definition-GMOUNBTQ-Bl-MTfK5.js} +445 -71
- package/out/renderer/assets/{vennDiagram-LZ73GAT5-Dp1FZ609.js → vennDiagram-DHZGUBPP-DNmr1k2L.js} +1 -1
- package/out/renderer/assets/{treemap-KZPCXAKY-W2a2L6ff.js → wardley-RL74JXVD-DTbxPMj9.js} +1474 -977
- package/out/renderer/assets/wardleyDiagram-NUSXRM2D-BWw08wtD.js +901 -0
- package/out/renderer/assets/{xychartDiagram-JWTSCODW-CTzYHTbD.js → xychartDiagram-5P7HB3ND-EEYPnLDT.js} +20 -4
- package/out/renderer/index.html +3 -3
- package/out/renderer/progress.html +212 -62
- package/out/resources/mcp-server/aider-desk-mcp-server.js +642 -402
- package/out/resources/skills/extension-creator/SKILL.md +320 -0
- package/out/resources/skills/extension-creator/assets/templates/Component.jsx.template +76 -0
- package/out/resources/skills/extension-creator/assets/templates/ConfigComponent.jsx.template +38 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension/config.ts.template +29 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension/index.ts.template +42 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension/package.json +12 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension/tsconfig.json +23 -0
- package/out/resources/skills/extension-creator/assets/templates/folder-extension-with-config/index.ts.template +80 -0
- package/out/resources/skills/extension-creator/assets/templates/single-file.ts.template +30 -0
- package/out/resources/skills/extension-creator/assets/templates/ui-component-external.ts.template +91 -0
- package/out/resources/skills/extension-creator/assets/templates/ui-component.ts.template +79 -0
- package/out/resources/skills/extension-creator/references/command-definition.md +170 -0
- package/out/resources/skills/extension-creator/references/config-components.md +427 -0
- package/out/resources/skills/extension-creator/references/event-types.md +156 -0
- package/out/resources/skills/extension-creator/references/examples-gallery.md +583 -0
- package/out/resources/skills/extension-creator/references/extension-interface.md +240 -0
- package/out/resources/skills/extension-creator/references/extension-types.md +186 -0
- package/out/resources/skills/extension-creator/references/in-repo-flow.md +132 -0
- package/out/resources/skills/extension-creator/references/install-targets.md +96 -0
- package/out/resources/skills/extension-creator/references/project-global-flow.md +76 -0
- package/out/resources/skills/extension-creator/references/ui-components.md +663 -0
- package/out/runner.js +976 -386
- package/package.json +2 -3
- package/out/renderer/assets/_basePickBy-BWoXHZ8Z.js +0 -161
- package/out/renderer/assets/apl-fqmucPXA.js +0 -140
- package/out/renderer/assets/asciiarmor-DucZyvP0.js +0 -56
- package/out/renderer/assets/asn1-BnOEsgAm.js +0 -144
- package/out/renderer/assets/asterisk-QAlztEwS.js +0 -345
- package/out/renderer/assets/brainfuck-DZVCuF_t.js +0 -53
- package/out/renderer/assets/clike-xqXYL6ge.js +0 -805
- package/out/renderer/assets/clojure-BhXMqnxz.js +0 -849
- package/out/renderer/assets/cmake-BGaNd9E7.js +0 -71
- package/out/renderer/assets/cobol-4yqQntpt.js +0 -120
- package/out/renderer/assets/coffeescript-D2dXvhEc.js +0 -308
- package/out/renderer/assets/commonlisp-CF_VNHQR.js +0 -130
- package/out/renderer/assets/crystal-DyuLTqLs.js +0 -398
- package/out/renderer/assets/css-c-jst79C.js +0 -1783
- package/out/renderer/assets/cypher-Dlu_3r4V.js +0 -121
- package/out/renderer/assets/d-UURgV0Ux.js +0 -179
- package/out/renderer/assets/diff-B_Bi2Crb.js +0 -25
- package/out/renderer/assets/dockerfile-Bvk733Ga.js +0 -201
- package/out/renderer/assets/dtd-Dy74G54E.js +0 -114
- package/out/renderer/assets/dylan-TSb-Nfix.js +0 -314
- package/out/renderer/assets/ebnf-4fKAGW3a.js +0 -140
- package/out/renderer/assets/ecl-B59qGGVg.js +0 -178
- package/out/renderer/assets/eiffel-Dze7nlu3.js +0 -134
- package/out/renderer/assets/elm-DG7jkhNZ.js +0 -176
- package/out/renderer/assets/erlang-BO6gOnGA.js +0 -674
- package/out/renderer/assets/factor-CMxFHDqz.js +0 -65
- package/out/renderer/assets/fcl-CDDUNjTj.js +0 -141
- package/out/renderer/assets/forth-B9D2JCeE.js +0 -116
- package/out/renderer/assets/fortran-CAG2BFbe.js +0 -467
- package/out/renderer/assets/gas-d3KEcW3x.js +0 -294
- package/out/renderer/assets/gherkin-DhZlEZiy.js +0 -115
- package/out/renderer/assets/groovy-CpwJiBl7.js +0 -223
- package/out/renderer/assets/haskell-ySd-OUo8.js +0 -459
- package/out/renderer/assets/haxe-7MlzfeYV.js +0 -514
- package/out/renderer/assets/http-BqypyemW.js +0 -79
- package/out/renderer/assets/idl-4HIGJlDI.js +0 -985
- package/out/renderer/assets/index-6qedlt0q.js +0 -689
- package/out/renderer/assets/index-86jDpUJn.js +0 -385
- package/out/renderer/assets/index-BRjO8ber.js +0 -332
- package/out/renderer/assets/index-BVgw7j0d.js +0 -312
- package/out/renderer/assets/index-BhkyI1q3.js +0 -642
- package/out/renderer/assets/index-BqrmLPkg.js +0 -82
- package/out/renderer/assets/index-BuPbw4xM.js +0 -178
- package/out/renderer/assets/index-CTO-LPBg.js +0 -311
- package/out/renderer/assets/index-CTO4SzlI.js +0 -97
- package/out/renderer/assets/index-CZ9IQK_0.js +0 -2488
- package/out/renderer/assets/index-CZxsVxBZ.js +0 -1765
- package/out/renderer/assets/index-DIXV-3Xn.js +0 -406
- package/out/renderer/assets/index-DNzOtZX5.js +0 -61
- package/out/renderer/assets/index-DZtJe7oC.js +0 -1019
- package/out/renderer/assets/index-DaWjZz_g.js +0 -291
- package/out/renderer/assets/index-De056HHR.js +0 -151
- package/out/renderer/assets/index-Dk3wSDSN.js +0 -117
- package/out/renderer/assets/index-Dy4VRsnA.js +0 -1041
- package/out/renderer/assets/index-FnnayPBc.js +0 -82
- package/out/renderer/assets/index-MZb_zy6R.js +0 -704
- package/out/renderer/assets/index-chzQl8rJ.js +0 -157
- package/out/renderer/assets/index-s-Owx3Pm.js +0 -327
- package/out/renderer/assets/javascript-C_OHM9hj.js +0 -994
- package/out/renderer/assets/julia-Bs6JJhYG.js +0 -407
- package/out/renderer/assets/livescript-DmzgM3Yt.js +0 -296
- package/out/renderer/assets/lua-8cJgIlqe.js +0 -256
- package/out/renderer/assets/mathematica-DNLOL9PQ.js +0 -110
- package/out/renderer/assets/mbox-Ga7d4MMN.js +0 -117
- package/out/renderer/assets/mirc-Dma3B8rS.js +0 -107
- package/out/renderer/assets/mllike-DHn7xckP.js +0 -334
- package/out/renderer/assets/modelica-0d55jYY0.js +0 -147
- package/out/renderer/assets/mscgen-DdqZYINH.js +0 -135
- package/out/renderer/assets/mumps-Btr8VblO.js +0 -93
- package/out/renderer/assets/nginx-DTDtBDVN.js +0 -141
- package/out/renderer/assets/nsis-3zG7tgur.js +0 -62
- package/out/renderer/assets/ntriples-CvgOYMpL.js +0 -153
- package/out/renderer/assets/octave-DYBj3-tl.js +0 -200
- package/out/renderer/assets/oz-R_e8WMIi.js +0 -231
- package/out/renderer/assets/pascal-GD8iposT.js +0 -105
- package/out/renderer/assets/perl-DL9mHpoi.js +0 -1105
- package/out/renderer/assets/pig-C_4T4YIV.js +0 -101
- package/out/renderer/assets/powershell-B0suO7Vd.js +0 -328
- package/out/renderer/assets/properties-BR-vP1aU.js +0 -58
- package/out/renderer/assets/protobuf-BxgpyhoW.js +0 -77
- package/out/renderer/assets/pug-CTXt1f8z.js +0 -405
- package/out/renderer/assets/puppet-Bdao66PW.js +0 -137
- package/out/renderer/assets/python-CvWbmiX4.js +0 -427
- package/out/renderer/assets/q-CrbCVq4a.js +0 -131
- package/out/renderer/assets/r-V7nswm59.js +0 -170
- package/out/renderer/assets/rpm-C-DLY-If.js +0 -109
- package/out/renderer/assets/ruby-JDKLJNK0.js +0 -330
- package/out/renderer/assets/sas-D2UG-yhZ.js +0 -207
- package/out/renderer/assets/scheme-BKzrkGJD.js +0 -222
- package/out/renderer/assets/shell-BlsXDxCn.js +0 -222
- package/out/renderer/assets/sieve-CjwBwOY5.js +0 -135
- package/out/renderer/assets/simple-mode-DMneyfDu.js +0 -130
- package/out/renderer/assets/smalltalk-BOIGQuhN.js +0 -121
- package/out/renderer/assets/solr-CwD7U71z.js +0 -69
- package/out/renderer/assets/sparql-DYskk2vE.js +0 -249
- package/out/renderer/assets/spreadsheet-Bgtt3oLP.js +0 -87
- package/out/renderer/assets/sql-BSrOzCRI.js +0 -354
- package/out/renderer/assets/stex-B6LNC55o.js +0 -231
- package/out/renderer/assets/stylus-BkS-boTH.js +0 -565
- package/out/renderer/assets/swift-FRZi1uvB.js +0 -291
- package/out/renderer/assets/tcl-CUcaCdmq.js +0 -114
- package/out/renderer/assets/textile-BnFpjsrl.js +0 -414
- package/out/renderer/assets/tiddlywiki-CjprD-Qp.js +0 -218
- package/out/renderer/assets/tiki-DK9DOeWn.js +0 -268
- package/out/renderer/assets/toml-BOuWGMcf.js +0 -76
- package/out/renderer/assets/troff-E1bJ0PPL.js +0 -61
- package/out/renderer/assets/ttcn-cfg-Dc39-fIP.js +0 -133
- package/out/renderer/assets/ttcn-tKd4HLu4.js +0 -192
- package/out/renderer/assets/turtle-Dq7-1WAf.js +0 -124
- package/out/renderer/assets/vb-Dp90gtsv.js +0 -196
- package/out/renderer/assets/vbscript-CI6_mxxU.js +0 -479
- package/out/renderer/assets/velocity-BwIZK1TH.js +0 -149
- package/out/renderer/assets/verilog-DDCYnHN8.js +0 -430
- package/out/renderer/assets/vhdl-DCkMIyT9.js +0 -158
- package/out/renderer/assets/webidl-BTLTThCm.js +0 -204
- package/out/renderer/assets/xquery-BrBUuxMR.js +0 -525
- package/out/renderer/assets/yacas-b5lAVEIl.js +0 -130
- package/out/renderer/assets/z80-BZV19vqv.js +0 -93
- package/scripts/download-uv.mjs +0 -147
- /package/patches/{ai+5.0.161.patch → ai+5.0.167.patch} +0 -0
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
# UI Components Reference
|
|
2
|
+
|
|
3
|
+
This document describes how to create UI extensions that add React components to the AiderDesk interface.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
UI extensions allow you to add custom React components to various locations in the AiderDesk interface. Components are defined as JSX/TSX strings and rendered using the `string-to-react-component` library.
|
|
8
|
+
|
|
9
|
+
## Registering UI Components
|
|
10
|
+
|
|
11
|
+
Implement the `getUIComponents()` method to return an array of UI component definitions:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
getUIComponents(context: ExtensionContext): UIComponentDefinition[] {
|
|
15
|
+
return [{
|
|
16
|
+
id: 'my-component',
|
|
17
|
+
placement: 'task-status-bar-right',
|
|
18
|
+
jsx: `({ data, task }) => {
|
|
19
|
+
return <div>Task: {task.name}</div>;
|
|
20
|
+
}`,
|
|
21
|
+
loadData: true,
|
|
22
|
+
noDataCache: false,
|
|
23
|
+
}];
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### UIComponentDefinition Properties
|
|
28
|
+
|
|
29
|
+
- **id** (string, required): Unique identifier for the component
|
|
30
|
+
- **placement** (UIComponentPlacement, required): Where to render the component
|
|
31
|
+
- **jsx** (string, required): JSX/TSX component code as a string
|
|
32
|
+
- **loadData** (boolean, optional): Whether to load data via `getUIExtensionData()` (default: false)
|
|
33
|
+
- **noDataCache** (boolean, optional): Always fetch fresh data on render (default: false)
|
|
34
|
+
|
|
35
|
+
## Available Placements
|
|
36
|
+
|
|
37
|
+
UI components can be placed in various locations throughout the AiderDesk interface. Each placement has specific characteristics and recommended use cases.
|
|
38
|
+
|
|
39
|
+
### Task Page - Top Section
|
|
40
|
+
|
|
41
|
+
- **task-status-bar-left**: Left side of the task status bar (very top of task page)
|
|
42
|
+
- *Use for*: Task-level status indicators, breadcrumbs
|
|
43
|
+
- *Layout*: Horizontal row, left-aligned
|
|
44
|
+
|
|
45
|
+
- **task-status-bar-right**: Right side of the task status bar
|
|
46
|
+
- *Use for*: Quick actions, global task settings
|
|
47
|
+
- *Layout*: Horizontal row, right-aligned
|
|
48
|
+
|
|
49
|
+
- **task-top-bar-left**: Left side of task top bar (just above chat messages)
|
|
50
|
+
- *Use for*: Context information, file indicators
|
|
51
|
+
- *Layout*: Horizontal row, left-aligned
|
|
52
|
+
|
|
53
|
+
- **task-top-bar-right**: Right side of task top bar
|
|
54
|
+
- *Use for*: View controls, filters
|
|
55
|
+
- *Layout*: Horizontal row, right-aligned
|
|
56
|
+
|
|
57
|
+
### Task Page - Messages Area
|
|
58
|
+
|
|
59
|
+
- **task-messages-top**: Above all messages in the chat
|
|
60
|
+
- *Use for*: Warnings, announcements, persistent information
|
|
61
|
+
- *Layout*: Full width, vertical stack
|
|
62
|
+
- *Note*: Appears once per task
|
|
63
|
+
|
|
64
|
+
- **task-messages-bottom**: Below all messages in the chat
|
|
65
|
+
- *Use for*: Summary information, pagination
|
|
66
|
+
- *Layout*: Full width, vertical stack
|
|
67
|
+
- *Note*: Appears once per task
|
|
68
|
+
|
|
69
|
+
- **task-message-above**: Above each individual message
|
|
70
|
+
- *Use for*: Message metadata, timestamps, labels
|
|
71
|
+
- *Layout*: Full message width, per-message
|
|
72
|
+
- *Props*: Includes `message` prop with current message data
|
|
73
|
+
|
|
74
|
+
- **task-message-below**: Below each individual message
|
|
75
|
+
- *Use for*: Message-specific actions, reactions, metrics
|
|
76
|
+
- *Layout*: Full message width, per-message
|
|
77
|
+
- *Props*: Includes `message` prop with current message data
|
|
78
|
+
|
|
79
|
+
- **task-message-bar**: In the message action bar (right side, appears on hover)
|
|
80
|
+
- *Use for*: Quick actions on specific messages (copy, edit, delete)
|
|
81
|
+
- *Layout*: Inline with other message actions
|
|
82
|
+
- *Props*: Includes `message` prop with current message data
|
|
83
|
+
|
|
84
|
+
### Task Page - Usage Info
|
|
85
|
+
|
|
86
|
+
- **task-usage-info-bottom**: Below the usage info section (tokens, costs display)
|
|
87
|
+
- *Use for*: Additional metrics, statistics, performance data
|
|
88
|
+
- *Layout*: Full width within usage info card
|
|
89
|
+
- *Note*: Only visible when usage info is shown
|
|
90
|
+
|
|
91
|
+
### Task Page - Input Area
|
|
92
|
+
|
|
93
|
+
- **task-input-above**: Above the input field
|
|
94
|
+
- *Use for*: Context selectors, mode switchers, warnings
|
|
95
|
+
- *Layout*: Full width above input
|
|
96
|
+
- *Example*: Multi-model selector, context warnings
|
|
97
|
+
|
|
98
|
+
- **task-input-toolbar-left**: Left side of input toolbar (below input field)
|
|
99
|
+
- *Use for*: Input-related actions, toggles
|
|
100
|
+
- *Layout*: Horizontal row, left side of toolbar
|
|
101
|
+
|
|
102
|
+
- **task-input-toolbar-right**: Right side of input toolbar
|
|
103
|
+
- *Use for*: Secondary actions, settings
|
|
104
|
+
- *Layout*: Horizontal row, right side of toolbar
|
|
105
|
+
|
|
106
|
+
### Task Page - State Actions
|
|
107
|
+
|
|
108
|
+
- **task-state-actions**: Task state action buttons (when task is stopped/waiting)
|
|
109
|
+
- *Use for*: Actions available when task is not running
|
|
110
|
+
- *Layout*: Horizontal row with other state actions
|
|
111
|
+
- *Note*: Only visible when task is stopped or waiting
|
|
112
|
+
|
|
113
|
+
- **task-state-actions-all**: Task state action buttons (visible in all states)
|
|
114
|
+
- *Use for*: Actions available regardless of task state
|
|
115
|
+
- *Layout*: Horizontal row with other state actions
|
|
116
|
+
- *Note*: Always visible
|
|
117
|
+
|
|
118
|
+
### Sidebar Placements
|
|
119
|
+
|
|
120
|
+
- **tasks-sidebar-header**: Header of the tasks sidebar (left panel)
|
|
121
|
+
- *Use for*: Sidebar controls, filters, project actions
|
|
122
|
+
- *Layout*: Full sidebar width at top
|
|
123
|
+
|
|
124
|
+
- **tasks-sidebar-bottom**: Bottom of the tasks sidebar
|
|
125
|
+
- *Use for*: Persistent sidebar actions, status
|
|
126
|
+
- *Layout*: Full sidebar width at bottom
|
|
127
|
+
|
|
128
|
+
### Global Placements
|
|
129
|
+
|
|
130
|
+
- **header-left**: Left side of the main application header
|
|
131
|
+
- *Use for*: Global navigation, branding
|
|
132
|
+
- *Layout*: Horizontal row, left side of header
|
|
133
|
+
|
|
134
|
+
- **header-right**: Right side of the main application header
|
|
135
|
+
- *Use for*: Global actions, user menu, settings
|
|
136
|
+
- *Layout*: Horizontal row, right side of header
|
|
137
|
+
|
|
138
|
+
- **welcome-page**: Full welcome page (when no task is open)
|
|
139
|
+
- *Use for*: Onboarding, workflow selection, project setup
|
|
140
|
+
- *Layout*: Full page layout
|
|
141
|
+
- *Note*: Replaces default welcome screen entirely
|
|
142
|
+
|
|
143
|
+
## Component Props
|
|
144
|
+
|
|
145
|
+
All UI components receive these props via the `data` prop passed by `string-to-react-component`.
|
|
146
|
+
|
|
147
|
+
**Note:** The `React` object is globally available within components (not passed as a prop). Access hooks via `React.useState`, `React.useEffect`, etc.
|
|
148
|
+
|
|
149
|
+
### Core Props
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
{
|
|
153
|
+
// Current task data (may be undefined)
|
|
154
|
+
task?: TaskData,
|
|
155
|
+
|
|
156
|
+
// Current project directory
|
|
157
|
+
projectDir?: string,
|
|
158
|
+
|
|
159
|
+
// Current agent profile
|
|
160
|
+
agentProfile?: AgentProfile,
|
|
161
|
+
|
|
162
|
+
// Available models
|
|
163
|
+
models: Model[],
|
|
164
|
+
|
|
165
|
+
// Available providers
|
|
166
|
+
providers: ProviderProfile[],
|
|
167
|
+
|
|
168
|
+
// Application API reference
|
|
169
|
+
api: ApplicationAPI,
|
|
170
|
+
|
|
171
|
+
// Current mode string
|
|
172
|
+
mode: string,
|
|
173
|
+
|
|
174
|
+
// UI component library
|
|
175
|
+
ui: UIComponents,
|
|
176
|
+
|
|
177
|
+
// React Icons library (organized by icon set)
|
|
178
|
+
icons: {
|
|
179
|
+
Ai: { ... }, // Ant Design Icons
|
|
180
|
+
Bi: { ... }, // BoxIcons
|
|
181
|
+
Bs: { ... }, // Bootstrap Icons
|
|
182
|
+
Cg: { ... }, // css.gg
|
|
183
|
+
Ci: { ... }, // Coolicons
|
|
184
|
+
Di: { ... }, // Devicons
|
|
185
|
+
Fa: { ... }, // Font Awesome 5
|
|
186
|
+
Fc: { ... }, // Flat Color Icons
|
|
187
|
+
Fi: { ... }, // Feather
|
|
188
|
+
Gi: { ... }, // Game Icons
|
|
189
|
+
Go: { ... }, // Github Octicons
|
|
190
|
+
Gr: { ... }, // Grommet Icons
|
|
191
|
+
Hi: { ... }, // Heroicons
|
|
192
|
+
Im: { ... }, // IcoMoon Free
|
|
193
|
+
Io5: { ... }, // Ionicons 5
|
|
194
|
+
Lu: { ... }, // Lucide
|
|
195
|
+
Md: { ... }, // Material Design Icons
|
|
196
|
+
Pi: { ... }, // Phosphor Icons
|
|
197
|
+
Ri: { ... }, // Remix Icon
|
|
198
|
+
Rx: { ... }, // Radix Icons
|
|
199
|
+
Si: { ... }, // Simple Icons
|
|
200
|
+
Sl: { ... }, // Simple Line Icons
|
|
201
|
+
Tb: { ... }, // Tabler Icons
|
|
202
|
+
Tfi: { ... }, // Themify Icons
|
|
203
|
+
Ti: { ... }, // Typicons
|
|
204
|
+
Vsc: { ... }, // VS Code Icons
|
|
205
|
+
Wi: { ... }, // Weather Icons
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
// Extension action executor
|
|
209
|
+
executeExtensionAction: (action: string, ...args: unknown[]) => Promise<unknown>,
|
|
210
|
+
|
|
211
|
+
// Data returned from getUIExtensionData() (if loadData: true)
|
|
212
|
+
data?: unknown,
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Message-Specific Props
|
|
217
|
+
|
|
218
|
+
For components placed in `task-message-above`, `task-message-below`, or `task-message-bar`:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
{
|
|
222
|
+
// All core props above, plus:
|
|
223
|
+
|
|
224
|
+
// The message being rendered
|
|
225
|
+
message: MessageData,
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Available UI Components
|
|
230
|
+
|
|
231
|
+
The `ui` prop provides pre-built AiderDesk components:
|
|
232
|
+
|
|
233
|
+
### Button
|
|
234
|
+
```jsx
|
|
235
|
+
<ui.Button
|
|
236
|
+
onClick={handleClick}
|
|
237
|
+
variant="solid" // or "outline"
|
|
238
|
+
color="primary" // or "secondary", "tertiary", "danger"
|
|
239
|
+
size="sm" // or "xs", "md", "lg"
|
|
240
|
+
disabled={false}
|
|
241
|
+
>
|
|
242
|
+
Click me
|
|
243
|
+
</ui.Button>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### IconButton
|
|
247
|
+
```jsx
|
|
248
|
+
<ui.IconButton
|
|
249
|
+
onClick={handleClick}
|
|
250
|
+
title="Click me"
|
|
251
|
+
size="sm"
|
|
252
|
+
disabled={false}
|
|
253
|
+
>
|
|
254
|
+
<FiSettings className="w-4 h-4" />
|
|
255
|
+
</ui.IconButton>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Checkbox
|
|
259
|
+
```jsx
|
|
260
|
+
<ui.Checkbox
|
|
261
|
+
label="Enable feature"
|
|
262
|
+
checked={isChecked}
|
|
263
|
+
onChange={handleChange}
|
|
264
|
+
size="sm" // or "xs", "md"
|
|
265
|
+
/>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### RadioButton
|
|
269
|
+
```jsx
|
|
270
|
+
<ui.RadioButton
|
|
271
|
+
name="option"
|
|
272
|
+
value="value1"
|
|
273
|
+
checked={selectedValue === 'value1'}
|
|
274
|
+
onChange={handleChange}
|
|
275
|
+
label="Option 1"
|
|
276
|
+
/>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Input
|
|
280
|
+
```jsx
|
|
281
|
+
<ui.Input
|
|
282
|
+
value={text}
|
|
283
|
+
onChange={handleChange}
|
|
284
|
+
placeholder="Enter text"
|
|
285
|
+
type="text" // or "password", "email", "number"
|
|
286
|
+
disabled={false}
|
|
287
|
+
/>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### TextArea
|
|
291
|
+
```jsx
|
|
292
|
+
<ui.TextArea
|
|
293
|
+
value={text}
|
|
294
|
+
onChange={handleChange}
|
|
295
|
+
placeholder="Enter text"
|
|
296
|
+
rows={4}
|
|
297
|
+
/>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Select
|
|
301
|
+
```jsx
|
|
302
|
+
<ui.Select
|
|
303
|
+
value={selectedValue}
|
|
304
|
+
onChange={handleChange}
|
|
305
|
+
options={[
|
|
306
|
+
{ value: 'opt1', label: 'Option 1' },
|
|
307
|
+
{ value: 'opt2', label: 'Option 2' },
|
|
308
|
+
]}
|
|
309
|
+
/>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### MultiSelect
|
|
313
|
+
```jsx
|
|
314
|
+
<ui.MultiSelect
|
|
315
|
+
value={selectedValues}
|
|
316
|
+
onChange={handleChange}
|
|
317
|
+
options={[
|
|
318
|
+
{ value: 'opt1', label: 'Option 1' },
|
|
319
|
+
{ value: 'opt2', label: 'Option 2' },
|
|
320
|
+
]}
|
|
321
|
+
/>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### ModelSelector
|
|
325
|
+
```jsx
|
|
326
|
+
<ui.ModelSelector
|
|
327
|
+
models={models}
|
|
328
|
+
providers={providers}
|
|
329
|
+
selectedModelId={modelId}
|
|
330
|
+
onChange={handleModelChange}
|
|
331
|
+
popupPlacement="top" // or "bottom"
|
|
332
|
+
/>
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Slider
|
|
336
|
+
```jsx
|
|
337
|
+
<ui.Slider
|
|
338
|
+
value={sliderValue}
|
|
339
|
+
onChange={handleChange}
|
|
340
|
+
min={0}
|
|
341
|
+
max={100}
|
|
342
|
+
step={1}
|
|
343
|
+
/>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### DatePicker
|
|
347
|
+
```jsx
|
|
348
|
+
<ui.DatePicker
|
|
349
|
+
value={dateValue}
|
|
350
|
+
onChange={handleChange}
|
|
351
|
+
/>
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Chip
|
|
355
|
+
```jsx
|
|
356
|
+
<ui.Chip
|
|
357
|
+
label="Feature"
|
|
358
|
+
color="primary" // or "secondary", "success", "warning", "error"
|
|
359
|
+
size="sm"
|
|
360
|
+
onDelete={handleDelete} // Optional
|
|
361
|
+
/>
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Tooltip
|
|
365
|
+
```jsx
|
|
366
|
+
<ui.Tooltip content="Helpful tooltip text">
|
|
367
|
+
<button>Hover me</button>
|
|
368
|
+
</ui.Tooltip>
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### LoadingOverlay
|
|
372
|
+
```jsx
|
|
373
|
+
<ui.LoadingOverlay message="Loading..." />
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### ConfirmDialog
|
|
377
|
+
```jsx
|
|
378
|
+
<ui.ConfirmDialog
|
|
379
|
+
title="Confirm Action"
|
|
380
|
+
onConfirm={handleConfirm}
|
|
381
|
+
onCancel={handleCancel}
|
|
382
|
+
confirmButtonText="Confirm"
|
|
383
|
+
confirmButtonColor="danger"
|
|
384
|
+
disabled={false}
|
|
385
|
+
>
|
|
386
|
+
<p>Are you sure you want to do this?</p>
|
|
387
|
+
</ui.ConfirmDialog>
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
## Using React
|
|
391
|
+
|
|
392
|
+
The `React` object is globally available in all components (provided by `string-to-react-component`):
|
|
393
|
+
|
|
394
|
+
```jsx
|
|
395
|
+
(props) => {
|
|
396
|
+
// Access React hooks directly from the React object
|
|
397
|
+
const { useState, useEffect, useCallback, useMemo } = React;
|
|
398
|
+
|
|
399
|
+
const [count, setCount] = useState(0);
|
|
400
|
+
|
|
401
|
+
const handleClick = useCallback(() => {
|
|
402
|
+
setCount(count + 1);
|
|
403
|
+
}, [count]);
|
|
404
|
+
|
|
405
|
+
return <button onClick={handleClick}>Count: {count}</button>;
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## Using React Icons
|
|
410
|
+
|
|
411
|
+
The `icons` prop provides access to all react-icons libraries:
|
|
412
|
+
|
|
413
|
+
```jsx
|
|
414
|
+
({ icons }) => {
|
|
415
|
+
// Import icons from different sets
|
|
416
|
+
const FiSettings = icons.Fi.FiSettings;
|
|
417
|
+
const HiCheck = icons.Hi.HiCheck;
|
|
418
|
+
const CgSpinner = icons.Cg.CgSpinner;
|
|
419
|
+
|
|
420
|
+
return (
|
|
421
|
+
<div>
|
|
422
|
+
<FiSettings className="w-4 h-4" />
|
|
423
|
+
<HiCheck className="w-5 h-5 text-success" />
|
|
424
|
+
<CgSpinner className="w-4 h-4 animate-spin" />
|
|
425
|
+
</div>
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Providing Data to Components
|
|
431
|
+
|
|
432
|
+
When `loadData: true`, implement `getUIExtensionData()`:
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
async getUIExtensionData(
|
|
436
|
+
componentId: string,
|
|
437
|
+
context: ExtensionContext
|
|
438
|
+
): Promise<unknown> {
|
|
439
|
+
if (componentId === 'my-component') {
|
|
440
|
+
return {
|
|
441
|
+
count: this.messageCount,
|
|
442
|
+
status: this.currentStatus,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
return undefined;
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
The data is passed to the component as the `data` prop.
|
|
450
|
+
|
|
451
|
+
### Data Caching
|
|
452
|
+
|
|
453
|
+
- **Default**: Data is cached and reused on subsequent renders
|
|
454
|
+
- **noDataCache: true**: Fresh data is fetched on every render
|
|
455
|
+
- Use `context.triggerUIDataRefresh(componentId)` to manually refresh data
|
|
456
|
+
|
|
457
|
+
## Handling Component Actions
|
|
458
|
+
|
|
459
|
+
Implement `executeUIExtensionAction()` to handle actions from components:
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
async executeUIExtensionAction(
|
|
463
|
+
componentId: string,
|
|
464
|
+
action: string,
|
|
465
|
+
args: unknown[],
|
|
466
|
+
context: ExtensionContext
|
|
467
|
+
): Promise<unknown> {
|
|
468
|
+
if (componentId === 'my-component') {
|
|
469
|
+
if (action === 'increment') {
|
|
470
|
+
this.count++;
|
|
471
|
+
context.triggerUIDataRefresh('my-component');
|
|
472
|
+
return { success: true };
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return undefined;
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Call from component via `executeExtensionAction`:
|
|
480
|
+
|
|
481
|
+
```jsx
|
|
482
|
+
({ executeExtensionAction }) => {
|
|
483
|
+
const handleClick = async () => {
|
|
484
|
+
const result = await executeExtensionAction('increment');
|
|
485
|
+
console.log(result);
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
return <button onClick={handleClick}>Increment</button>;
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
## Triggering UI Updates
|
|
493
|
+
|
|
494
|
+
### Refresh Component Data
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
// Refresh specific component
|
|
498
|
+
context.triggerUIDataRefresh('my-component');
|
|
499
|
+
|
|
500
|
+
// Refresh specific component for specific task
|
|
501
|
+
context.triggerUIDataRefresh('my-component', taskId);
|
|
502
|
+
|
|
503
|
+
// Refresh all components from this extension
|
|
504
|
+
context.triggerUIDataRefresh();
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Reload Component Definitions
|
|
508
|
+
|
|
509
|
+
```typescript
|
|
510
|
+
// Reload all components (e.g., when settings change)
|
|
511
|
+
context.triggerUIComponentsReload();
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
## Loading JSX from External Files
|
|
515
|
+
|
|
516
|
+
For larger components, separate JSX into .jsx files:
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
import { readFileSync } from 'fs';
|
|
520
|
+
import { join } from 'path';
|
|
521
|
+
|
|
522
|
+
getUIComponents(context: ExtensionContext): UIComponentDefinition[] {
|
|
523
|
+
const jsx = readFileSync(join(__dirname, './MyComponent.jsx'), 'utf-8');
|
|
524
|
+
|
|
525
|
+
return [{
|
|
526
|
+
id: 'my-component',
|
|
527
|
+
placement: 'task-status-bar-right',
|
|
528
|
+
jsx,
|
|
529
|
+
loadData: true,
|
|
530
|
+
}];
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**MyComponent.jsx:**
|
|
535
|
+
```jsx
|
|
536
|
+
({ data, task, ui }) => {
|
|
537
|
+
const { useState } = React;
|
|
538
|
+
const [count, setCount] = useState(0);
|
|
539
|
+
|
|
540
|
+
return (
|
|
541
|
+
<ui.Button onClick={() => setCount(count + 1)}>
|
|
542
|
+
Clicked {count} times
|
|
543
|
+
</ui.Button>
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
## Component Examples
|
|
549
|
+
|
|
550
|
+
### Simple Status Indicator
|
|
551
|
+
|
|
552
|
+
```jsx
|
|
553
|
+
(props) => {
|
|
554
|
+
const { data } = props;
|
|
555
|
+
|
|
556
|
+
if (!data?.active) return null;
|
|
557
|
+
|
|
558
|
+
return (
|
|
559
|
+
<div className="flex items-center gap-2 text-xs">
|
|
560
|
+
<span className="w-2 h-2 rounded-full bg-success animate-pulse" />
|
|
561
|
+
<span>Active</span>
|
|
562
|
+
</div>
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Interactive Counter
|
|
568
|
+
|
|
569
|
+
```jsx
|
|
570
|
+
(props) => {
|
|
571
|
+
const { data, executeExtensionAction, ui } = props;
|
|
572
|
+
const { Button } = ui;
|
|
573
|
+
const count = data?.count ?? 0;
|
|
574
|
+
|
|
575
|
+
const handleIncrement = async () => {
|
|
576
|
+
await executeExtensionAction('increment');
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
return (
|
|
580
|
+
<div className="flex items-center gap-2">
|
|
581
|
+
<span className="text-sm">Count: {count}</span>
|
|
582
|
+
<Button size="xs" onClick={handleIncrement}>+</Button>
|
|
583
|
+
</div>
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
### Model Selector
|
|
589
|
+
|
|
590
|
+
```jsx
|
|
591
|
+
(props) => {
|
|
592
|
+
const { models, providers, data, executeExtensionAction, ui } = props;
|
|
593
|
+
const { ModelSelector } = ui;
|
|
594
|
+
|
|
595
|
+
const handleModelChange = async (model) => {
|
|
596
|
+
const modelId = model ? `${model.providerId}/${model.id}` : '';
|
|
597
|
+
await executeExtensionAction('set-model', modelId);
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
return (
|
|
601
|
+
<ModelSelector
|
|
602
|
+
models={models}
|
|
603
|
+
providers={providers}
|
|
604
|
+
selectedModelId={data?.selectedModel}
|
|
605
|
+
onChange={handleModelChange}
|
|
606
|
+
/>
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### Message-Specific Component
|
|
612
|
+
|
|
613
|
+
```jsx
|
|
614
|
+
(props) => {
|
|
615
|
+
const { message, data } = props;
|
|
616
|
+
|
|
617
|
+
if (!message?.id || !data) return null;
|
|
618
|
+
|
|
619
|
+
const messageData = data[message.id];
|
|
620
|
+
if (!messageData) return null;
|
|
621
|
+
|
|
622
|
+
return (
|
|
623
|
+
<span className="text-xs text-text-muted">
|
|
624
|
+
{messageData.tokensPerSecond} TPS
|
|
625
|
+
</span>
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
## Best Practices
|
|
631
|
+
|
|
632
|
+
### Performance
|
|
633
|
+
|
|
634
|
+
- **Memoize callbacks**: Use `useCallback` for event handlers
|
|
635
|
+
- **Memoize values**: Use `useMemo` for expensive computations
|
|
636
|
+
- **Avoid unnecessary renders**: Return `null` early when possible
|
|
637
|
+
- **Use noDataCache sparingly**: Only when data must always be fresh
|
|
638
|
+
|
|
639
|
+
### Styling
|
|
640
|
+
|
|
641
|
+
- **Use Tailwind CSS**: All Tailwind classes are available
|
|
642
|
+
- **Follow design system**: Use color tokens (text-primary, bg-secondary, etc.)
|
|
643
|
+
- **Responsive design**: Use Tailwind responsive classes (sm:, md:, lg:)
|
|
644
|
+
- **Dark mode**: Colors automatically adapt to theme
|
|
645
|
+
|
|
646
|
+
### Error Handling
|
|
647
|
+
|
|
648
|
+
- **Null checks**: Always check for undefined props (task, data, message)
|
|
649
|
+
- **Try-catch**: Wrap risky operations in try-catch
|
|
650
|
+
- **Error boundaries**: Components are wrapped in error boundaries automatically
|
|
651
|
+
|
|
652
|
+
### Data Management
|
|
653
|
+
|
|
654
|
+
- **Refresh after mutations**: Call `triggerUIDataRefresh()` after changing state
|
|
655
|
+
- **Use loadData flag**: Set to `true` when component needs data
|
|
656
|
+
- **Cache intelligently**: Use `noDataCache: true` only when needed
|
|
657
|
+
|
|
658
|
+
### Code Organization
|
|
659
|
+
|
|
660
|
+
- **External files**: Use .jsx files for components > 20 lines
|
|
661
|
+
- **One component per file**: Keep components focused and reusable
|
|
662
|
+
- **Shared logic**: Extract common logic to extension methods
|
|
663
|
+
- **Type safety**: Use TypeScript in extension, JSX in components
|