@vibe-forge/client 0.11.3 → 1.0.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 (200) hide show
  1. package/cli.cjs +6 -11
  2. package/dist/assets/{arc-h39NrT24.js → arc-CbOXL0l9.js} +1 -1
  3. package/dist/assets/{blockDiagram-c4efeb88-CaDg46I6.js → blockDiagram-c4efeb88-CqxINvsS.js} +1 -1
  4. package/dist/assets/{c4Diagram-c83219d4-CDqjcF9U.js → c4Diagram-c83219d4-BKazU0hb.js} +1 -1
  5. package/dist/assets/channel-Dnopc5A6.js +1 -0
  6. package/dist/assets/{classDiagram-beda092f-BDnZm8nO.js → classDiagram-beda092f-fAFX5BpB.js} +1 -1
  7. package/dist/assets/{classDiagram-v2-2358418a-BUi85KJW.js → classDiagram-v2-2358418a-w1VkNGJj.js} +1 -1
  8. package/dist/assets/clone-sQthahUA.js +1 -0
  9. package/dist/assets/{createText-1719965b-Ca5dEwfo.js → createText-1719965b-CEinakVP.js} +1 -1
  10. package/dist/assets/{cssMode-Ysz7NfYo.js → cssMode-DPqRki4y.js} +1 -1
  11. package/dist/assets/{edges-96097737-CdSKqxZt.js → edges-96097737-Cb0F1_3K.js} +1 -1
  12. package/dist/assets/{erDiagram-0228fc6a-B-veAUv_.js → erDiagram-0228fc6a-C-N2fx-J.js} +1 -1
  13. package/dist/assets/{flowDb-c6c81e3f-DD8Cx7_9.js → flowDb-c6c81e3f-D1Xz_8Gf.js} +1 -1
  14. package/dist/assets/{flowDiagram-50d868cf-9f-_x1ET.js → flowDiagram-50d868cf-DyPSZyAj.js} +1 -1
  15. package/dist/assets/flowDiagram-v2-4f6560a1-OazrdWQO.js +1 -0
  16. package/dist/assets/{flowchart-elk-definition-6af322e1-5RhpQM4M.js → flowchart-elk-definition-6af322e1-Dr1DDXwE.js} +1 -1
  17. package/dist/assets/{freemarker2-SgMdIXw4.js → freemarker2-C3DvPFaK.js} +1 -1
  18. package/dist/assets/{ganttDiagram-a2739b55-DnxNghZA.js → ganttDiagram-a2739b55-DmvY1GRj.js} +1 -1
  19. package/dist/assets/{gitGraphDiagram-82fe8481-CBvS3Tf9.js → gitGraphDiagram-82fe8481-CoXfPYYi.js} +1 -1
  20. package/dist/assets/{graph-CkHF299-.js → graph-BkDQy7Qt.js} +1 -1
  21. package/dist/assets/{handlebars-C57IyLUe.js → handlebars-BcTFdqjl.js} +1 -1
  22. package/dist/assets/{html-YsDy5wvW.js → html-Dg-O6XFr.js} +1 -1
  23. package/dist/assets/{htmlMode-7o_VDODD.js → htmlMode-B_wqYWvn.js} +1 -1
  24. package/dist/assets/{index-5325376f-BzOVQPu-.js → index-5325376f-kxPTR3_e.js} +1 -1
  25. package/dist/assets/index-o93dlo92.css +32 -0
  26. package/dist/assets/{index-BHFpctk6.js → index-wkhI4dr6.js} +357 -337
  27. package/dist/assets/{infoDiagram-8eee0895-DJ-UI1h4.js → infoDiagram-8eee0895-BEvqkwPI.js} +1 -1
  28. package/dist/assets/{javascript-BHQ9NEZr.js → javascript-DhlOH8_z.js} +1 -1
  29. package/dist/assets/{journeyDiagram-c64418c1-DwfykcG9.js → journeyDiagram-c64418c1-gKtLYmmp.js} +1 -1
  30. package/dist/assets/{jsonMode-3QjftkMM.js → jsonMode-DxTbF9OD.js} +1 -1
  31. package/dist/assets/{layout-CbViRb_b.js → layout-CDaZEk6E.js} +1 -1
  32. package/dist/assets/{line-DBdBvv9D.js → line-DNRQu8iq.js} +1 -1
  33. package/dist/assets/{linear-BDAfhcjn.js → linear-Cph9Z6_j.js} +1 -1
  34. package/dist/assets/{liquid-B0cPPzIR.js → liquid-ByZ6JgRG.js} +1 -1
  35. package/dist/assets/{lspLanguageFeatures-IOxbobOz.js → lspLanguageFeatures-DzvhkgnM.js} +1 -1
  36. package/dist/assets/{mdx-Dma_RA8P.js → mdx-D8RGHTl6.js} +1 -1
  37. package/dist/assets/{mermaid.core-Cvn8Go4x.js → mermaid.core-BgcryF__.js} +4 -4
  38. package/dist/assets/{mindmap-definition-8da855dc-DEnYq0Lc.js → mindmap-definition-8da855dc-WrxK0FcB.js} +1 -1
  39. package/dist/assets/{pieDiagram-a8764435-ZC4j8sHU.js → pieDiagram-a8764435-VsZBsiQy.js} +1 -1
  40. package/dist/assets/{python-Be0WX4q5.js → python-CXVtk_cg.js} +1 -1
  41. package/dist/assets/{quadrantDiagram-1e28029f-DUaqHlIB.js → quadrantDiagram-1e28029f-BVlgwOvU.js} +1 -1
  42. package/dist/assets/{razor-Tjhny-uT.js → razor-0tind7h2.js} +1 -1
  43. package/dist/assets/{requirementDiagram-08caed73-DjSal3es.js → requirementDiagram-08caed73-CpPMPoYp.js} +1 -1
  44. package/dist/assets/{sankeyDiagram-a04cb91d-BMDXMrMz.js → sankeyDiagram-a04cb91d-Cm5nnRmc.js} +1 -1
  45. package/dist/assets/{sequenceDiagram-c5b8d532-CQl9YUlH.js → sequenceDiagram-c5b8d532-DpMlJvJB.js} +1 -1
  46. package/dist/assets/{stateDiagram-1ecb1508-DG7mU9jD.js → stateDiagram-1ecb1508-DU1zc7vq.js} +1 -1
  47. package/dist/assets/{stateDiagram-v2-c2b004d7-DTbR_azy.js → stateDiagram-v2-c2b004d7-D-0RgmAp.js} +1 -1
  48. package/dist/assets/{styles-b4e223ce-C9aS3zb8.js → styles-b4e223ce-BSO-yNWV.js} +1 -1
  49. package/dist/assets/{styles-ca3715f6-Bh3keVTZ.js → styles-ca3715f6-CHnsn2Ro.js} +1 -1
  50. package/dist/assets/{styles-d45a18b0-BDcLLa65.js → styles-d45a18b0-B-rVGjEq.js} +1 -1
  51. package/dist/assets/{svgDrawCommon-b86b1483-B9H5ZS_9.js → svgDrawCommon-b86b1483-CA3Pl89f.js} +1 -1
  52. package/dist/assets/{timeline-definition-faaaa080-DCMYCBhK.js → timeline-definition-faaaa080-BcihLR6s.js} +1 -1
  53. package/dist/assets/{tsMode-DVqLsn98.js → tsMode-D9GGa5Ur.js} +1 -1
  54. package/dist/assets/{typescript-wMVyXw7G.js → typescript-BT9CK_EL.js} +1 -1
  55. package/dist/assets/{xml-w0gzmn0c.js → xml-DNO75J-T.js} +1 -1
  56. package/dist/assets/{xychartDiagram-f5964ef8-CdxyD3K5.js → xychartDiagram-f5964ef8-DJTwe32X.js} +1 -1
  57. package/dist/assets/{yaml-C29TL1ed.js → yaml-7CVzhiP2.js} +1 -1
  58. package/dist/index.html +2 -2
  59. package/package.json +13 -10
  60. package/src/api/git.ts +12 -0
  61. package/src/api/sessions.ts +61 -3
  62. package/src/api.ts +8 -0
  63. package/src/components/ArchiveView.scss +143 -54
  64. package/src/components/ArchiveView.tsx +181 -167
  65. package/src/components/CodeBlock.scss +5 -0
  66. package/src/components/ConfigView.scss +142 -31
  67. package/src/components/ConfigView.tsx +161 -86
  68. package/src/components/MarkdownContent.tsx +7 -0
  69. package/src/components/NavRail.scss +248 -0
  70. package/src/components/NavRail.tsx +80 -107
  71. package/src/components/NavRailCompact.tsx +107 -0
  72. package/src/components/NavRailCompactMoreSheet.tsx +141 -0
  73. package/src/components/ShortcutTooltip.tsx +4 -2
  74. package/src/components/Sidebar.scss +51 -0
  75. package/src/components/Sidebar.tsx +43 -16
  76. package/src/components/automation-view/RuleFormPanel.scss +40 -13
  77. package/src/components/automation-view/RuleSidebar.scss +73 -47
  78. package/src/components/automation-view/RuleSidebar.tsx +9 -13
  79. package/src/components/automation-view/RunHistoryPanel.scss +141 -13
  80. package/src/components/automation-view/RunHistoryPanel.tsx +203 -161
  81. package/src/components/automation-view/TaskList.scss +44 -13
  82. package/src/components/automation-view/TriggerList.scss +46 -14
  83. package/src/components/automation-view/index.scss +82 -10
  84. package/src/components/automation-view/index.tsx +108 -55
  85. package/src/components/benchmark-view/BenchmarkCasePanel.scss +36 -16
  86. package/src/components/benchmark-view/BenchmarkSidebar.scss +44 -22
  87. package/src/components/benchmark-view/BenchmarkSidebar.tsx +0 -6
  88. package/src/components/benchmark-view/BenchmarkView.scss +63 -20
  89. package/src/components/benchmark-view/index.tsx +71 -34
  90. package/src/components/chat/ChatComposerCard.scss +4 -0
  91. package/src/components/chat/ChatHeader.scss +187 -0
  92. package/src/components/chat/ChatHeader.tsx +206 -56
  93. package/src/components/chat/ChatHistoryView.tsx +63 -2
  94. package/src/components/chat/ChatTimelineView.scss +94 -1
  95. package/src/components/chat/ChatTimelineView.tsx +42 -0
  96. package/src/components/chat/NewSessionGuide.scss +139 -1
  97. package/src/components/chat/NewSessionGuide.tsx +57 -100
  98. package/src/components/chat/NewSessionGuideCompactPanel.tsx +130 -0
  99. package/src/components/chat/NewSessionGuideGrid.tsx +141 -0
  100. package/src/components/chat/git-controls/BranchSwitcherDropdown.tsx +61 -56
  101. package/src/components/chat/git-controls/BranchSwitcherResults.tsx +167 -0
  102. package/src/components/chat/git-controls/BranchTreeEntries.tsx +99 -0
  103. package/src/components/chat/git-controls/ChatGitControls.scss +437 -5
  104. package/src/components/chat/git-controls/ChatGitControls.tsx +136 -109
  105. package/src/components/chat/git-controls/DraftGitControls.tsx +91 -0
  106. package/src/components/chat/git-controls/GitOperationsDropdown.tsx +10 -2
  107. package/src/components/chat/git-controls/GitWorktreeDropdown.tsx +301 -28
  108. package/src/components/chat/git-controls/git-branch-tree.ts +148 -0
  109. package/src/components/chat/git-controls/use-chat-draft-git-controls.ts +168 -0
  110. package/src/components/chat/git-controls/use-chat-git-controls.ts +76 -3
  111. package/src/components/chat/messages/MessageContextMenu.tsx +3 -1
  112. package/src/components/chat/messages/MessageItem.scss +78 -4
  113. package/src/components/chat/messages/MessageItem.tsx +47 -3
  114. package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.scss +15 -0
  115. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.scss +17 -0
  116. package/src/components/chat/sender/@components/reference-actions/ReferencePermissionActionsPopover.tsx +4 -1
  117. package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.scss +15 -2
  118. package/src/components/chat/sender/@components/sender-body/SenderBody.tsx +3 -0
  119. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-theme.ts +52 -3
  120. package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.scss +12 -0
  121. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectBase.scss +21 -0
  122. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectShared.scss +21 -0
  123. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.scss +63 -0
  124. package/src/components/chat/sender/@core/get-sender-runtime-state.ts +1 -1
  125. package/src/components/chat/sender/@hooks/use-model-select-browser.tsx +4 -2
  126. package/src/components/chat/sender/@types/sender-props.ts +1 -0
  127. package/src/components/chat/sender/Sender.scss +1 -1
  128. package/src/components/chat/sender/Sender.tsx +1 -0
  129. package/src/components/chat/session-timeline-panel/EventList.scss +88 -0
  130. package/src/components/chat/session-timeline-panel/EventList.tsx +99 -47
  131. package/src/components/chat/session-timeline-panel/gantt.ts +23 -7
  132. package/src/components/chat/session-timeline-panel/git-graph.ts +6 -1
  133. package/src/components/chat/session-timeline-panel/index.scss +14 -1
  134. package/src/components/chat/session-timeline-panel/index.tsx +86 -10
  135. package/src/components/chat/session-timeline-panel/types.ts +4 -0
  136. package/src/components/chat/status-bar/ChatStatusBar.scss +27 -0
  137. package/src/components/chat/status-bar/ChatStatusBar.tsx +39 -0
  138. package/src/components/chat/terminal/ChatTerminalView.tsx +6 -0
  139. package/src/components/chat/tools/core/ToolCallBox.scss +19 -0
  140. package/src/components/chat/tools/core/ToolGroup.scss +32 -0
  141. package/src/components/chat/tools/task/components/TaskToolCard.scss +59 -1
  142. package/src/components/config/ConfigEditors.scss +20 -6
  143. package/src/components/config/ConfigFieldRow.scss +57 -17
  144. package/src/components/config/ConfigSectionForm.scss +10 -4
  145. package/src/components/config/ConfigSectionPanel.tsx +18 -11
  146. package/src/components/config/configSchema.ts +1 -0
  147. package/src/components/config/record-editors/RecordEditors.scss +42 -9
  148. package/src/components/dock-panel/DockPanel.scss +6 -2
  149. package/src/components/dock-panel/DockPanel.tsx +12 -16
  150. package/src/components/knowledge-base/KnowledgeBaseView.scss +180 -6
  151. package/src/components/knowledge-base/KnowledgeBaseView.tsx +98 -26
  152. package/src/components/knowledge-base/components/ActionButton.scss +4 -0
  153. package/src/components/knowledge-base/components/EmptyState.scss +5 -8
  154. package/src/components/knowledge-base/components/EntitiesTab.tsx +8 -2
  155. package/src/components/knowledge-base/components/EntityItem.scss +10 -3
  156. package/src/components/knowledge-base/components/FilterBar.scss +13 -2
  157. package/src/components/knowledge-base/components/FlowsTab.tsx +8 -2
  158. package/src/components/knowledge-base/components/KnowledgeBaseHeader.scss +2 -23
  159. package/src/components/knowledge-base/components/KnowledgeBaseHeader.tsx +0 -5
  160. package/src/components/knowledge-base/components/KnowledgeList.scss +15 -6
  161. package/src/components/knowledge-base/components/LoadingState.scss +4 -0
  162. package/src/components/knowledge-base/components/RuleItem.scss +86 -0
  163. package/src/components/knowledge-base/components/RuleItem.tsx +2 -0
  164. package/src/components/knowledge-base/components/RulesTab.tsx +8 -2
  165. package/src/components/knowledge-base/components/SectionHeader.scss +3 -18
  166. package/src/components/knowledge-base/components/SectionHeader.tsx +3 -7
  167. package/src/components/knowledge-base/components/SkillsTab.tsx +8 -3
  168. package/src/components/knowledge-base/components/SpecItem.scss +16 -7
  169. package/src/components/layout/@hooks/use-mobile-sidebar-modal.ts +190 -0
  170. package/src/components/layout/AppShell.scss +106 -6
  171. package/src/components/layout/AppShell.tsx +118 -10
  172. package/src/components/layout/PageShell.scss +41 -0
  173. package/src/components/layout/PageShell.tsx +32 -0
  174. package/src/components/layout/mobile-sidebar-constants.ts +1 -0
  175. package/src/components/nav-rail-compact-config.ts +114 -0
  176. package/src/components/nav-rail-items.tsx +181 -0
  177. package/src/components/sidebar/SessionContextMenu.tsx +3 -1
  178. package/src/components/sidebar/SessionItem.scss +62 -0
  179. package/src/components/sidebar/SessionItem.tsx +97 -52
  180. package/src/components/sidebar/SessionList.tsx +6 -0
  181. package/src/components/sidebar/SidebarHeader.scss +49 -0
  182. package/src/components/sidebar/SidebarHeader.tsx +27 -5
  183. package/src/components/sidebar/SidebarHeaderBatchActions.tsx +8 -4
  184. package/src/components/sidebar/SidebarHeaderSearchActions.tsx +6 -3
  185. package/src/components/sidebar/SidebarUtilityFooter.tsx +69 -0
  186. package/src/components/workspace/ContextFilePicker.tsx +12 -4
  187. package/src/hooks/chat/chat-session-workspace-draft.ts +25 -0
  188. package/src/hooks/chat/use-chat-scroll.ts +24 -7
  189. package/src/hooks/chat/use-chat-session-actions.ts +19 -2
  190. package/src/hooks/use-responsive-layout.ts +115 -0
  191. package/src/resources/adapters.ts +15 -0
  192. package/src/resources/locales/en.json +52 -0
  193. package/src/resources/locales/zh.json +52 -0
  194. package/src/routes/ChatRoute.scss +113 -14
  195. package/src/routes/ChatRoute.tsx +29 -35
  196. package/src/store/index.ts +2 -0
  197. package/dist/assets/channel-CBULQbJz.js +0 -1
  198. package/dist/assets/clone-dkS7LczW.js +0 -1
  199. package/dist/assets/flowDiagram-v2-4f6560a1-1miffU4x.js +0 -1
  200. package/dist/assets/index-D_XqxIvp.css +0 -32
@@ -21,7 +21,7 @@ export function ConfigSectionPanel({
21
21
  className
22
22
  }: {
23
23
  sectionKey: string
24
- title: ReactNode
24
+ title?: ReactNode
25
25
  icon?: ReactNode
26
26
  fields?: FieldSpec[]
27
27
  value: unknown
@@ -34,19 +34,26 @@ export function ConfigSectionPanel({
34
34
  className?: string
35
35
  }) {
36
36
  const wrapClassName = ['config-view__editor-wrap', className].filter(Boolean).join(' ')
37
- const hasHeader = title != null || icon != null || headerExtra != null
37
+ const hasHeading = title != null || icon != null
38
+ const hasHeader = hasHeading || headerExtra != null
39
+ const headerClassName = [
40
+ 'config-view__section-header',
41
+ !hasHeading ? 'config-view__section-header--actions-only' : ''
42
+ ].filter(Boolean).join(' ')
38
43
  return (
39
44
  <div className={wrapClassName}>
40
45
  {hasHeader && (
41
- <div className='config-view__section-header'>
42
- <div className='config-view__section-title'>
43
- {icon != null && (
44
- <span className='material-symbols-rounded config-view__section-icon'>
45
- {icon}
46
- </span>
47
- )}
48
- <span>{title}</span>
49
- </div>
46
+ <div className={headerClassName}>
47
+ {hasHeading && (
48
+ <div className='config-view__section-title'>
49
+ {icon != null && (
50
+ <span className='material-symbols-rounded config-view__section-icon'>
51
+ {icon}
52
+ </span>
53
+ )}
54
+ <span>{title}</span>
55
+ </div>
56
+ )}
50
57
  {headerExtra}
51
58
  </div>
52
59
  )}
@@ -269,6 +269,7 @@ export const configSchema: Record<string, FieldSpec[]> = {
269
269
  { value: 'programmatic', label: 'config.options.conversation.programmatic' }
270
270
  ]
271
271
  },
272
+ { path: ['createSessionWorktree'], type: 'boolean', defaultValue: true, icon: 'account_tree' },
272
273
  { path: ['customInstructions'], type: 'multiline', defaultValue: '', icon: 'description' }
273
274
  ],
274
275
  models: [
@@ -1,14 +1,23 @@
1
1
  .config-view__record-list {
2
2
  display: flex;
3
3
  flex-direction: column;
4
- gap: 10px;
4
+ gap: 8px;
5
5
  }
6
6
 
7
7
  .config-view__record-card {
8
- border-radius: 12px;
8
+ padding: var(--subpage-tertiary-padding);
9
+ border: var(--subpage-tertiary-border);
10
+ border-radius: var(--subpage-tertiary-radius);
11
+ background: var(--subpage-tertiary-bg);
9
12
  display: flex;
10
13
  flex-direction: column;
11
14
  gap: 10px;
15
+ transition: border-color .2s ease, background-color .2s ease;
16
+ }
17
+
18
+ .config-view__record-card:hover {
19
+ border-color: var(--subpage-tertiary-hover-border);
20
+ background: var(--subpage-tertiary-hover-bg);
12
21
  }
13
22
 
14
23
  .config-view__record-title {
@@ -62,19 +71,27 @@
62
71
  .config-view__record-fields {
63
72
  display: flex;
64
73
  flex-direction: column;
65
- border-radius: 10px;
74
+ gap: 10px;
66
75
  }
67
76
 
68
77
  .config-view__record-row {
69
78
  display: flex;
70
- align-items: center;
79
+ align-items: flex-start;
71
80
  gap: 8px;
81
+ padding: 0;
82
+ border: none;
83
+ border-radius: 0;
84
+ background: transparent;
72
85
  }
73
86
 
74
87
  .config-view__record-key {
75
88
  font-size: 12px;
76
89
  color: var(--sub-text-color);
77
- min-width: 140px;
90
+ min-width: 132px;
91
+ padding-top: 6px;
92
+ overflow: hidden;
93
+ text-overflow: ellipsis;
94
+ white-space: nowrap;
78
95
  }
79
96
 
80
97
  .config-view__record-add {
@@ -88,21 +105,37 @@
88
105
  align-items: center;
89
106
  gap: 8px;
90
107
  flex: 1;
108
+ padding: 10px 12px;
109
+ border: 1px dashed var(--border-color);
110
+ border-radius: 8px;
111
+ background: var(--sub-bg-color);
91
112
  }
92
113
 
93
114
  .config-view__record-add-inputs .ant-input,
94
- .config-view__record-add-inputs .ant-input-affix-wrapper {
115
+ .config-view__record-add-inputs .ant-input-affix-wrapper,
116
+ .config-view__record-add-inputs .ant-select {
95
117
  flex: 1;
96
118
  }
97
119
 
120
+ .config-view__record-add-inputs .ant-input,
121
+ .config-view__record-add-inputs .ant-input-affix-wrapper,
122
+ .config-view__record-add-inputs .ant-select-selector,
123
+ .config-view__record-row .ant-input,
124
+ .config-view__record-row .ant-input-affix-wrapper,
125
+ .config-view__record-row .ant-select-selector {
126
+ border-radius: 6px !important;
127
+ min-height: 30px;
128
+ }
129
+
98
130
  .config-view__icon-button {
99
- width: 32px;
100
- height: 32px;
101
- min-width: 32px;
131
+ width: 28px;
132
+ height: 28px;
133
+ min-width: 28px;
102
134
  padding: 0;
103
135
  display: inline-flex;
104
136
  align-items: center;
105
137
  justify-content: center;
138
+ border-radius: 6px;
106
139
  }
107
140
 
108
141
  .config-view__icon-button--compact {
@@ -47,11 +47,15 @@
47
47
  min-height: 24px;
48
48
  margin: -12px -12px 0;
49
49
  padding: 12px 12px 0;
50
- cursor: row-resize;
50
+ cursor: default;
51
51
  flex-shrink: 0;
52
52
  transition: opacity .18s ease;
53
53
 
54
- &:hover {
54
+ &.is-resizable {
55
+ cursor: row-resize;
56
+ }
57
+
58
+ &.is-resizable:hover {
55
59
  opacity: .92;
56
60
  }
57
61
  }
@@ -6,22 +6,17 @@ import { useEffect, useMemo, useRef, useState } from 'react'
6
6
 
7
7
  const DEFAULT_PANEL_HEIGHT = 240
8
8
 
9
- const clampPanelHeight = (height: number, minHeight: number, maxHeight: number) => {
10
- return Math.min(Math.max(height, minHeight), Math.max(minHeight, maxHeight))
11
- }
12
-
13
- const shouldIgnoreResizePointerDown = (target: HTMLElement | null) => {
14
- if (target == null) {
15
- return false
16
- }
9
+ const clampPanelHeight = (height: number, minHeight: number, maxHeight: number) =>
10
+ Math.min(Math.max(height, minHeight), Math.max(minHeight, maxHeight))
17
11
 
18
- return target.closest(
12
+ const shouldIgnoreResizePointerDown = (target: HTMLElement | null) =>
13
+ target?.closest(
19
14
  'button, a, input, textarea, select, option, [role="button"], [data-dock-panel-no-resize="true"]'
20
15
  ) != null
21
- }
22
16
 
23
17
  export function DockPanel({
24
18
  enterMotion = 'slide-up',
19
+ allowResize = true,
25
20
  children,
26
21
  className,
27
22
  closeLabel,
@@ -38,6 +33,7 @@ export function DockPanel({
38
33
  actions
39
34
  }: {
40
35
  enterMotion?: 'none' | 'slide-up'
36
+ allowResize?: boolean
41
37
  actions?: ReactNode
42
38
  children: ReactNode
43
39
  className?: string
@@ -75,7 +71,7 @@ export function DockPanel({
75
71
  }, [])
76
72
 
77
73
  useEffect(() => {
78
- if (!isResizing) {
74
+ if (!allowResize || !isResizing) {
79
75
  return
80
76
  }
81
77
 
@@ -110,7 +106,7 @@ export function DockPanel({
110
106
  window.removeEventListener('pointerup', stopResizing)
111
107
  window.removeEventListener('pointercancel', stopResizing)
112
108
  }
113
- }, [isResizing, minHeight])
109
+ }, [allowResize, isResizing, minHeight])
114
110
 
115
111
  const handleResizePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {
116
112
  if (shouldIgnoreResizePointerDown(event.target as HTMLElement | null)) {
@@ -148,13 +144,13 @@ export function DockPanel({
148
144
  ref={panelRef}
149
145
  className={`dock-panel ${isOpen && enterMotion === 'slide-up' ? 'is-entering-slide-up' : ''} ${
150
146
  isOpen ? 'is-open' : 'is-closing'
151
- } ${className ?? ''} ${isResizing ? 'is-resizing' : ''}`}
147
+ } ${className ?? ''} ${isResizing ? 'is-resizing' : ''} ${allowResize ? 'is-resizable' : 'is-static'}`}
152
148
  style={panelStyle as CSSProperties}
153
149
  >
154
150
  <div
155
- className='dock-panel__resize-handle'
156
- title={resizeLabel}
157
- onPointerDown={handleResizePointerDown}
151
+ className={`dock-panel__resize-handle ${allowResize ? 'is-resizable' : 'is-static'}`}
152
+ title={allowResize ? resizeLabel : undefined}
153
+ onPointerDown={allowResize ? handleResizePointerDown : undefined}
158
154
  >
159
155
  <div className='dock-panel__header-main'>
160
156
  <span className='dock-panel__title'>{title}</span>
@@ -1,19 +1,193 @@
1
1
  .knowledge-base-view {
2
- height: 100%;
2
+ color: var(--text-color);
3
+ }
4
+
5
+ .knowledge-base-view__mobile-switcher-shell {
6
+ display: none;
7
+ }
8
+
9
+ .knowledge-base-view__body {
10
+ display: flex;
11
+ flex: 1;
12
+ min-height: 0;
13
+ flex-direction: row;
14
+ overflow: hidden;
15
+ }
16
+
17
+ .knowledge-base-view__left {
18
+ width: var(--subpage-secondary-panel-width);
19
+ min-width: var(--subpage-secondary-panel-width);
20
+ max-width: var(--subpage-secondary-panel-width);
21
+ display: flex;
22
+ flex-direction: column;
23
+ background: var(--sub-bg-color);
24
+ }
25
+
26
+ .knowledge-base-view__sidebar {
27
+ display: flex;
28
+ flex-direction: column;
29
+ flex: 1;
30
+ min-height: 0;
31
+ }
32
+
33
+ .knowledge-base-view__nav-list {
3
34
  display: flex;
4
35
  flex-direction: column;
5
- padding: 24px;
36
+ gap: 6px;
37
+ padding: 10px 12px 12px;
38
+ overflow: auto;
39
+ }
40
+
41
+ .knowledge-base-view__nav-item {
42
+ width: 100%;
43
+ display: flex;
44
+ align-items: flex-start;
45
+ gap: 8px;
46
+ padding: 8px;
47
+ border: 1px solid var(--border-color);
48
+ border-radius: 8px;
6
49
  background: var(--bg-color);
7
50
  color: var(--text-color);
51
+ text-align: left;
52
+ cursor: pointer;
53
+ transition: border-color .2s ease, background-color .2s ease, color .2s ease;
54
+ }
55
+
56
+ .knowledge-base-view__nav-item:hover {
57
+ border-color: var(--sidebar-hover-bg, #e5e5e5);
58
+ background: var(--sidebar-hover-bg, #e5e5e5);
59
+ }
60
+
61
+ .knowledge-base-view__nav-item.is-active {
62
+ border-color: var(--primary-color);
63
+ background: var(--primary-soft-bg);
64
+ color: var(--sidebar-active-text, var(--primary-color));
65
+ }
66
+
67
+ .knowledge-base-view__nav-icon {
68
+ font-size: 18px;
69
+ color: var(--sub-text-color);
70
+ flex-shrink: 0;
71
+ }
72
+
73
+ .knowledge-base-view__nav-item.is-active .knowledge-base-view__nav-icon {
74
+ color: inherit;
75
+ font-variation-settings: 'FILL' 1;
76
+ }
77
+
78
+ .knowledge-base-view__nav-main {
79
+ display: flex;
80
+ flex-direction: column;
81
+ gap: 4px;
82
+ min-width: 0;
83
+ flex: 1;
84
+ }
85
+
86
+ .knowledge-base-view__nav-row {
87
+ display: flex;
88
+ align-items: center;
89
+ gap: 8px;
90
+ min-width: 0;
91
+ }
92
+
93
+ .knowledge-base-view__nav-label {
94
+ flex: 1;
95
+ min-width: 0;
96
+ font-size: 12px;
97
+ line-height: 1.35;
98
+ font-weight: 500;
99
+ }
100
+
101
+ .knowledge-base-view__nav-count {
102
+ flex-shrink: 0;
103
+ font-size: 10px;
104
+ line-height: 1;
105
+ color: var(--sub-text-color);
106
+ }
107
+
108
+ .knowledge-base-view__nav-item.is-active .knowledge-base-view__nav-count {
109
+ color: inherit;
110
+ }
111
+
112
+ .knowledge-base-view__nav-desc {
113
+ font-size: 11px;
114
+ line-height: 1.4;
115
+ color: var(--sub-text-color);
116
+ }
117
+
118
+ .knowledge-base-view__nav-item.is-active .knowledge-base-view__nav-desc {
119
+ color: inherit;
120
+ opacity: .88;
121
+ }
122
+
123
+ .knowledge-base-view__right {
124
+ flex: 1;
125
+ min-width: 0;
126
+ min-height: 0;
8
127
  overflow: hidden;
128
+ margin: var(--subpage-content-card-gap);
129
+ margin-left: 0;
130
+ border-radius: var(--subpage-content-card-radius);
131
+ background: var(--subpage-content-card-bg);
132
+ display: flex;
133
+ flex-direction: column;
9
134
  }
10
135
 
11
- .knowledge-base-view__tabs {
136
+ .knowledge-base-view__right-body {
12
137
  flex: 1;
13
138
  min-height: 0;
139
+ overflow: hidden;
14
140
  }
15
141
 
16
- .knowledge-base-view__tabs > .ant-tabs-nav {
17
- padding: 0 24px;
18
- margin: 0;
142
+ @media (max-width: 1100px) {
143
+ .knowledge-base-view__body {
144
+ flex-direction: column;
145
+ }
146
+
147
+ .knowledge-base-view__left {
148
+ width: 100%;
149
+ min-width: 0;
150
+ max-width: none;
151
+ }
152
+
153
+ .knowledge-base-view__right {
154
+ margin-top: 0;
155
+ margin-left: var(--subpage-content-card-gap);
156
+ }
157
+
158
+ .knowledge-base-view__nav-list {
159
+ padding-bottom: 10px;
160
+ }
161
+ }
162
+
163
+ @media (max-width: 960px) {
164
+ .knowledge-base-view--compact {
165
+ .knowledge-base-view__mobile-switcher-shell {
166
+ display: block;
167
+ padding: 12px;
168
+ padding-bottom: 0;
169
+ }
170
+
171
+ .knowledge-base-view__mobile-switcher {
172
+ width: 100%;
173
+
174
+ .ant-segmented-group {
175
+ gap: 4px;
176
+ }
177
+
178
+ .ant-segmented-item {
179
+ min-height: 32px;
180
+ font-size: 12px;
181
+ }
182
+ }
183
+
184
+ .knowledge-base-view__right {
185
+ margin: 12px;
186
+ margin-top: 12px;
187
+ }
188
+ }
189
+
190
+ .knowledge-base-view__nav-item {
191
+ padding: 8px 10px;
192
+ }
19
193
  }
@@ -1,18 +1,18 @@
1
1
  import './KnowledgeBaseView.scss'
2
2
 
3
- import { App, Tabs } from 'antd'
3
+ import { App, Segmented } from 'antd'
4
4
  import React from 'react'
5
5
  import { useTranslation } from 'react-i18next'
6
6
  import useSWR from 'swr'
7
7
 
8
8
  import type { EntitySummary, RuleSummary, SpecSummary } from '#~/api.js'
9
+ import { PageShell } from '#~/components/layout/PageShell.js'
10
+ import { useResponsiveLayout } from '#~/hooks/use-responsive-layout'
9
11
  import { useQueryParams } from '#~/hooks/useQueryParams.js'
10
12
  import { EntitiesTab } from './components/EntitiesTab.js'
11
13
  import { FlowsTab } from './components/FlowsTab.js'
12
- import { KnowledgeBaseHeader } from './components/KnowledgeBaseHeader.js'
13
14
  import { RulesTab } from './components/RulesTab.js'
14
15
  import { SkillsTab } from './components/SkillsTab.js'
15
- import { TabLabel } from './components/TabLabel.js'
16
16
 
17
17
  interface KnowledgeQueryParams extends Record<string, string> {
18
18
  kbTab: string
@@ -21,6 +21,7 @@ interface KnowledgeQueryParams extends Record<string, string> {
21
21
  export function KnowledgeBaseView() {
22
22
  const { t } = useTranslation()
23
23
  const { message } = App.useApp()
24
+ const { isCompactLayout, isTouchInteraction } = useResponsiveLayout()
24
25
  const {
25
26
  data: specsRes,
26
27
  isLoading: isSpecsLoading,
@@ -147,12 +148,27 @@ export function KnowledgeBaseView() {
147
148
  message.info(t('knowledge.rules.importHint'))
148
149
  }
149
150
 
150
- const tabs = [
151
+ const skillCount = React.useMemo(() => {
152
+ const names = new Set<string>()
153
+ specs.forEach(spec => {
154
+ spec.skills?.forEach(skill => names.add(skill))
155
+ })
156
+ entities.forEach(entity => {
157
+ entity.skills?.forEach(skill => names.add(skill))
158
+ })
159
+ return names.size
160
+ }, [entities, specs])
161
+
162
+ const sections = [
151
163
  {
152
164
  key: 'skills',
153
- label: <TabLabel icon='psychology' label={t('knowledge.tabs.skills')} />,
154
- children: (
165
+ icon: 'psychology',
166
+ label: t('knowledge.tabs.skills'),
167
+ description: t('knowledge.skills.desc'),
168
+ count: skillCount,
169
+ content: (
155
170
  <SkillsTab
171
+ onRefresh={handleRefresh}
156
172
  onCreate={handleCreateSkill}
157
173
  onImport={handleImportSkill}
158
174
  />
@@ -160,8 +176,11 @@ export function KnowledgeBaseView() {
160
176
  },
161
177
  {
162
178
  key: 'entities',
163
- label: <TabLabel icon='group_work' label={t('knowledge.tabs.entities')} />,
164
- children: (
179
+ icon: 'group_work',
180
+ label: t('knowledge.tabs.entities'),
181
+ description: t('knowledge.entities.desc'),
182
+ count: entities.length,
183
+ content: (
165
184
  <EntitiesTab
166
185
  entities={entities}
167
186
  filteredEntities={filteredEntities}
@@ -169,6 +188,7 @@ export function KnowledgeBaseView() {
169
188
  query={entityQuery}
170
189
  tagOptions={entityTagOptions}
171
190
  tagFilter={entityTagFilter}
191
+ onRefresh={handleRefresh}
172
192
  onQueryChange={setEntityQuery}
173
193
  onTagFilterChange={setEntityTagFilter}
174
194
  onCreate={handleCreateEntity}
@@ -178,8 +198,11 @@ export function KnowledgeBaseView() {
178
198
  },
179
199
  {
180
200
  key: 'flows',
181
- label: <TabLabel icon='account_tree' label={t('knowledge.tabs.flows')} />,
182
- children: (
201
+ icon: 'account_tree',
202
+ label: t('knowledge.tabs.flows'),
203
+ description: t('knowledge.flows.desc'),
204
+ count: specs.length,
205
+ content: (
183
206
  <FlowsTab
184
207
  specs={specs}
185
208
  filteredSpecs={filteredSpecs}
@@ -187,6 +210,7 @@ export function KnowledgeBaseView() {
187
210
  query={specQuery}
188
211
  tagOptions={specTagOptions}
189
212
  tagFilter={specTagFilter}
213
+ onRefresh={handleRefresh}
190
214
  onQueryChange={setSpecQuery}
191
215
  onTagFilterChange={setSpecTagFilter}
192
216
  onCreate={handleCreateSpec}
@@ -196,13 +220,17 @@ export function KnowledgeBaseView() {
196
220
  },
197
221
  {
198
222
  key: 'rules',
199
- label: <TabLabel icon='gavel' label={t('knowledge.tabs.rules')} />,
200
- children: (
223
+ icon: 'gavel',
224
+ label: t('knowledge.tabs.rules'),
225
+ description: t('knowledge.rules.desc'),
226
+ count: rules.length,
227
+ content: (
201
228
  <RulesTab
202
229
  rules={rules}
203
230
  filteredRules={filteredRules}
204
231
  isLoading={isRulesLoading}
205
232
  query={ruleQuery}
233
+ onRefresh={handleRefresh}
206
234
  onQueryChange={setRuleQuery}
207
235
  onCreate={handleCreateRule}
208
236
  onImport={handleImportRule}
@@ -211,24 +239,68 @@ export function KnowledgeBaseView() {
211
239
  }
212
240
  ]
213
241
 
214
- const tabKeys = React.useMemo(() => tabs.map(tab => tab.key), [tabs])
215
- const activeTab = tabKeys.includes(values.kbTab) ? values.kbTab : tabKeys[0]
242
+ const sectionKeys = React.useMemo(() => sections.map(section => section.key), [sections])
243
+ const activeSectionKey = sectionKeys.includes(values.kbTab) ? values.kbTab : sectionKeys[0]
244
+ const activeSection = React.useMemo(
245
+ () => sections.find(section => section.key === activeSectionKey) ?? sections[0],
246
+ [activeSectionKey, sections]
247
+ )
248
+ const isCompactView = isCompactLayout || isTouchInteraction
216
249
 
217
250
  React.useEffect(() => {
218
- if (values.kbTab !== activeTab) {
219
- update({ kbTab: activeTab })
251
+ if (values.kbTab !== activeSectionKey) {
252
+ update({ kbTab: activeSectionKey })
220
253
  }
221
- }, [activeTab, update, values.kbTab])
254
+ }, [activeSectionKey, update, values.kbTab])
222
255
 
223
256
  return (
224
- <div className='knowledge-base-view'>
225
- <KnowledgeBaseHeader onRefresh={handleRefresh} />
226
- <Tabs
227
- className='knowledge-base-view__tabs'
228
- items={tabs}
229
- activeKey={activeTab}
230
- onChange={(key) => update({ kbTab: key })}
231
- />
232
- </div>
257
+ <PageShell
258
+ className={`knowledge-base-view ${isCompactView ? 'knowledge-base-view--compact' : ''}`}
259
+ bodyClassName='knowledge-base-view__body'
260
+ >
261
+ {isCompactView
262
+ ? (
263
+ <div className='knowledge-base-view__mobile-switcher-shell'>
264
+ <Segmented
265
+ block
266
+ className='knowledge-base-view__mobile-switcher'
267
+ value={activeSectionKey}
268
+ onChange={(value) => update({ kbTab: value as string })}
269
+ options={sections.map((section) => ({
270
+ label: `${section.label} ${section.count}`,
271
+ value: section.key
272
+ }))}
273
+ />
274
+ </div>
275
+ )
276
+ : (
277
+ <div className='knowledge-base-view__left'>
278
+ <div className='knowledge-base-view__sidebar'>
279
+ <div className='knowledge-base-view__nav-list'>
280
+ {sections.map((section) => (
281
+ <button
282
+ key={section.key}
283
+ type='button'
284
+ className={`knowledge-base-view__nav-item ${section.key === activeSectionKey ? 'is-active' : ''}`}
285
+ onClick={() => update({ kbTab: section.key })}
286
+ >
287
+ <span className='material-symbols-rounded knowledge-base-view__nav-icon'>{section.icon}</span>
288
+ <span className='knowledge-base-view__nav-main'>
289
+ <span className='knowledge-base-view__nav-row'>
290
+ <span className='knowledge-base-view__nav-label'>{section.label}</span>
291
+ <span className='knowledge-base-view__nav-count'>{section.count}</span>
292
+ </span>
293
+ <span className='knowledge-base-view__nav-desc'>{section.description}</span>
294
+ </span>
295
+ </button>
296
+ ))}
297
+ </div>
298
+ </div>
299
+ </div>
300
+ )}
301
+ <div className='knowledge-base-view__right'>
302
+ <div className='knowledge-base-view__right-body'>{activeSection?.content}</div>
303
+ </div>
304
+ </PageShell>
233
305
  )
234
306
  }
@@ -2,4 +2,8 @@
2
2
  display: inline-flex;
3
3
  align-items: center;
4
4
  gap: 6px;
5
+ height: 28px;
6
+ padding: 0 10px;
7
+ border-radius: 6px;
8
+ font-size: 12px;
5
9
  }
@@ -1,19 +1,16 @@
1
1
  .knowledge-base-view__empty {
2
- padding: 24px;
2
+ min-height: 240px;
3
+ padding: 32px 24px;
3
4
  display: flex;
4
5
  flex-direction: column;
5
6
  align-items: center;
7
+ justify-content: center;
6
8
  gap: 12px;
7
- border-radius: 12px;
8
- border: 1px dashed var(--border-color);
9
- background: var(--code-bg);
10
9
  }
11
10
 
12
11
  .knowledge-base-view__empty-simple {
13
- padding: 24px;
12
+ min-height: 180px;
13
+ padding: 32px 24px;
14
14
  display: grid;
15
15
  place-items: center;
16
- border-radius: 12px;
17
- border: 1px dashed var(--border-color);
18
- background: var(--code-bg);
19
16
  }