@vibe-forge/client 0.2.0-alpha.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 (184) hide show
  1. package/LICENSE +21 -0
  2. package/cli.cjs +6 -0
  3. package/index.html +27 -0
  4. package/package.json +42 -0
  5. package/src/App.tsx +174 -0
  6. package/src/api.ts +241 -0
  7. package/src/components/ArchiveView.scss +168 -0
  8. package/src/components/ArchiveView.tsx +299 -0
  9. package/src/components/AutomationView/AutomationView.scss +26 -0
  10. package/src/components/AutomationView/RuleFormPanel.scss +129 -0
  11. package/src/components/AutomationView/RuleFormPanel.tsx +257 -0
  12. package/src/components/AutomationView/RuleSidebar.scss +219 -0
  13. package/src/components/AutomationView/RuleSidebar.tsx +258 -0
  14. package/src/components/AutomationView/RunHistoryPanel.scss +286 -0
  15. package/src/components/AutomationView/RunHistoryPanel.tsx +320 -0
  16. package/src/components/AutomationView/TaskList.scss +128 -0
  17. package/src/components/AutomationView/TaskList.tsx +79 -0
  18. package/src/components/AutomationView/TriggerList.scss +153 -0
  19. package/src/components/AutomationView/TriggerList.tsx +217 -0
  20. package/src/components/AutomationView/index.tsx +228 -0
  21. package/src/components/AutomationView/types.ts +21 -0
  22. package/src/components/Chat.scss +89 -0
  23. package/src/components/Chat.tsx +92 -0
  24. package/src/components/ConfigView.scss +185 -0
  25. package/src/components/ConfigView.tsx +258 -0
  26. package/src/components/NavRail.scss +71 -0
  27. package/src/components/NavRail.tsx +188 -0
  28. package/src/components/Sidebar.scss +112 -0
  29. package/src/components/Sidebar.tsx +291 -0
  30. package/src/components/chat/ChatHeader.scss +401 -0
  31. package/src/components/chat/ChatHeader.tsx +342 -0
  32. package/src/components/chat/ChatHistoryView.tsx +122 -0
  33. package/src/components/chat/ChatSettingsView.tsx +22 -0
  34. package/src/components/chat/ChatTimelineView.scss +53 -0
  35. package/src/components/chat/ChatTimelineView.tsx +158 -0
  36. package/src/components/chat/CodeBlock.scss +87 -0
  37. package/src/components/chat/CodeBlock.tsx +179 -0
  38. package/src/components/chat/CompletionMenu.scss +70 -0
  39. package/src/components/chat/CompletionMenu.tsx +58 -0
  40. package/src/components/chat/CurrentTodoList.scss +217 -0
  41. package/src/components/chat/CurrentTodoList.tsx +103 -0
  42. package/src/components/chat/MarkdownContent.tsx +43 -0
  43. package/src/components/chat/MessageFooter.tsx +48 -0
  44. package/src/components/chat/MessageItem.scss +251 -0
  45. package/src/components/chat/MessageItem.tsx +78 -0
  46. package/src/components/chat/NewSessionGuide.scss +186 -0
  47. package/src/components/chat/NewSessionGuide.tsx +167 -0
  48. package/src/components/chat/Sender.scss +367 -0
  49. package/src/components/chat/Sender.tsx +541 -0
  50. package/src/components/chat/SessionTimelinePanel/EventList.scss +58 -0
  51. package/src/components/chat/SessionTimelinePanel/EventList.tsx +212 -0
  52. package/src/components/chat/SessionTimelinePanel/gantt.ts +177 -0
  53. package/src/components/chat/SessionTimelinePanel/git-graph.ts +518 -0
  54. package/src/components/chat/SessionTimelinePanel/index.scss +28 -0
  55. package/src/components/chat/SessionTimelinePanel/index.tsx +121 -0
  56. package/src/components/chat/SessionTimelinePanel/mermaid.ts +4 -0
  57. package/src/components/chat/SessionTimelinePanel/types.ts +64 -0
  58. package/src/components/chat/SessionTimelinePanel/utils.ts +20 -0
  59. package/src/components/chat/ThinkingStatus.scss +70 -0
  60. package/src/components/chat/ThinkingStatus.tsx +13 -0
  61. package/src/components/chat/ToolCallBox.scss +137 -0
  62. package/src/components/chat/ToolCallBox.tsx +55 -0
  63. package/src/components/chat/ToolGroup.scss +154 -0
  64. package/src/components/chat/ToolGroup.tsx +102 -0
  65. package/src/components/chat/ToolRenderer.tsx +45 -0
  66. package/src/components/chat/messageUtils.ts +171 -0
  67. package/src/components/chat/safeSerialize.ts +84 -0
  68. package/src/components/chat/tools/DefaultTool.tsx +63 -0
  69. package/src/components/chat/tools/adapter-claude/BashTool.scss +71 -0
  70. package/src/components/chat/tools/adapter-claude/BashTool.tsx +82 -0
  71. package/src/components/chat/tools/adapter-claude/GlobTool.scss +88 -0
  72. package/src/components/chat/tools/adapter-claude/GlobTool.tsx +85 -0
  73. package/src/components/chat/tools/adapter-claude/GrepTool.scss +96 -0
  74. package/src/components/chat/tools/adapter-claude/GrepTool.tsx +114 -0
  75. package/src/components/chat/tools/adapter-claude/LSTool.scss +85 -0
  76. package/src/components/chat/tools/adapter-claude/LSTool.tsx +94 -0
  77. package/src/components/chat/tools/adapter-claude/ReadTool.scss +57 -0
  78. package/src/components/chat/tools/adapter-claude/ReadTool.tsx +87 -0
  79. package/src/components/chat/tools/adapter-claude/TodoTool.scss +78 -0
  80. package/src/components/chat/tools/adapter-claude/TodoTool.tsx +60 -0
  81. package/src/components/chat/tools/adapter-claude/WriteTool.scss +92 -0
  82. package/src/components/chat/tools/adapter-claude/WriteTool.tsx +86 -0
  83. package/src/components/chat/tools/adapter-claude/components/FileList.scss +65 -0
  84. package/src/components/chat/tools/adapter-claude/components/FileList.tsx +185 -0
  85. package/src/components/chat/tools/adapter-claude/index.ts +28 -0
  86. package/src/components/chat/tools/defineToolRender.ts +28 -0
  87. package/src/components/chat/tools/task/GetTaskInfoTool.scss +50 -0
  88. package/src/components/chat/tools/task/GetTaskInfoTool.tsx +88 -0
  89. package/src/components/chat/tools/task/ListTasksTool.scss +56 -0
  90. package/src/components/chat/tools/task/ListTasksTool.tsx +83 -0
  91. package/src/components/chat/tools/task/StartTasksTool.scss +56 -0
  92. package/src/components/chat/tools/task/StartTasksTool.tsx +96 -0
  93. package/src/components/chat/tools/task/components/TaskToolCard.scss +127 -0
  94. package/src/components/chat/tools/task/components/TaskToolCard.tsx +177 -0
  95. package/src/components/chat/tools/task/index.ts +15 -0
  96. package/src/components/chat/useChatModels.tsx +206 -0
  97. package/src/components/chat/useChatSession.ts +370 -0
  98. package/src/components/config/ConfigAboutSection.scss +111 -0
  99. package/src/components/config/ConfigAboutSection.tsx +86 -0
  100. package/src/components/config/ConfigDisplayValue.scss +22 -0
  101. package/src/components/config/ConfigDisplayValue.tsx +62 -0
  102. package/src/components/config/ConfigEditors.scss +65 -0
  103. package/src/components/config/ConfigEditors.tsx +98 -0
  104. package/src/components/config/ConfigFieldRow.scss +97 -0
  105. package/src/components/config/ConfigFieldRow.tsx +36 -0
  106. package/src/components/config/ConfigSectionForm.scss +94 -0
  107. package/src/components/config/ConfigSectionForm.tsx +436 -0
  108. package/src/components/config/ConfigSectionPanel.tsx +67 -0
  109. package/src/components/config/ConfigShortcutInput.scss +11 -0
  110. package/src/components/config/ConfigShortcutInput.tsx +52 -0
  111. package/src/components/config/ConfigSourceSwitch.tsx +57 -0
  112. package/src/components/config/configSchema.ts +319 -0
  113. package/src/components/config/configUtils.ts +83 -0
  114. package/src/components/config/index.tsx +5 -0
  115. package/src/components/config/recordEditors/BooleanRecordEditor.scss +1 -0
  116. package/src/components/config/recordEditors/BooleanRecordEditor.tsx +75 -0
  117. package/src/components/config/recordEditors/KeyValueEditor.scss +1 -0
  118. package/src/components/config/recordEditors/KeyValueEditor.tsx +97 -0
  119. package/src/components/config/recordEditors/McpServersRecordEditor.scss +1 -0
  120. package/src/components/config/recordEditors/McpServersRecordEditor.tsx +258 -0
  121. package/src/components/config/recordEditors/ModelServicesRecordEditor.scss +1 -0
  122. package/src/components/config/recordEditors/ModelServicesRecordEditor.tsx +233 -0
  123. package/src/components/config/recordEditors/RecordEditors.scss +117 -0
  124. package/src/components/config/recordEditors/RecordJsonEditor.scss +1 -0
  125. package/src/components/config/recordEditors/RecordJsonEditor.tsx +113 -0
  126. package/src/components/config/recordEditors/index.tsx +5 -0
  127. package/src/components/knowledge-base/KnowledgeBaseView.scss +19 -0
  128. package/src/components/knowledge-base/KnowledgeBaseView.tsx +186 -0
  129. package/src/components/knowledge-base/components/ActionButton.scss +5 -0
  130. package/src/components/knowledge-base/components/ActionButton.tsx +9 -0
  131. package/src/components/knowledge-base/components/EmptyState.scss +19 -0
  132. package/src/components/knowledge-base/components/EmptyState.tsx +42 -0
  133. package/src/components/knowledge-base/components/EntitiesTab.scss +5 -0
  134. package/src/components/knowledge-base/components/EntitiesTab.tsx +80 -0
  135. package/src/components/knowledge-base/components/EntityItem.scss +82 -0
  136. package/src/components/knowledge-base/components/EntityItem.tsx +79 -0
  137. package/src/components/knowledge-base/components/EntityList.scss +5 -0
  138. package/src/components/knowledge-base/components/EntityList.tsx +70 -0
  139. package/src/components/knowledge-base/components/FilterBar.scss +21 -0
  140. package/src/components/knowledge-base/components/FilterBar.tsx +51 -0
  141. package/src/components/knowledge-base/components/FlowsTab.scss +5 -0
  142. package/src/components/knowledge-base/components/FlowsTab.tsx +80 -0
  143. package/src/components/knowledge-base/components/KnowledgeBaseHeader.scss +27 -0
  144. package/src/components/knowledge-base/components/KnowledgeBaseHeader.tsx +29 -0
  145. package/src/components/knowledge-base/components/KnowledgeList.scss +19 -0
  146. package/src/components/knowledge-base/components/KnowledgeList.tsx +19 -0
  147. package/src/components/knowledge-base/components/LoadingState.scss +5 -0
  148. package/src/components/knowledge-base/components/LoadingState.tsx +11 -0
  149. package/src/components/knowledge-base/components/MetaList.scss +19 -0
  150. package/src/components/knowledge-base/components/MetaList.tsx +18 -0
  151. package/src/components/knowledge-base/components/RulesTab.scss +5 -0
  152. package/src/components/knowledge-base/components/RulesTab.tsx +49 -0
  153. package/src/components/knowledge-base/components/SectionHeader.scss +22 -0
  154. package/src/components/knowledge-base/components/SectionHeader.tsx +21 -0
  155. package/src/components/knowledge-base/components/SkillsTab.scss +5 -0
  156. package/src/components/knowledge-base/components/SkillsTab.tsx +49 -0
  157. package/src/components/knowledge-base/components/SpecItem.scss +138 -0
  158. package/src/components/knowledge-base/components/SpecItem.tsx +131 -0
  159. package/src/components/knowledge-base/components/SpecList.scss +5 -0
  160. package/src/components/knowledge-base/components/SpecList.tsx +70 -0
  161. package/src/components/knowledge-base/components/TabContent.scss +8 -0
  162. package/src/components/knowledge-base/components/TabContent.tsx +17 -0
  163. package/src/components/knowledge-base/components/TabLabel.scss +10 -0
  164. package/src/components/knowledge-base/components/TabLabel.tsx +15 -0
  165. package/src/components/knowledge-base/index.tsx +1 -0
  166. package/src/components/sidebar/SessionItem.scss +256 -0
  167. package/src/components/sidebar/SessionItem.tsx +265 -0
  168. package/src/components/sidebar/SessionList.scss +92 -0
  169. package/src/components/sidebar/SessionList.tsx +166 -0
  170. package/src/components/sidebar/SidebarHeader.scss +79 -0
  171. package/src/components/sidebar/SidebarHeader.tsx +128 -0
  172. package/src/connectionManager.ts +172 -0
  173. package/src/hooks/useGlobalShortcut.ts +26 -0
  174. package/src/hooks/useQueryParams.ts +54 -0
  175. package/src/i18n.ts +22 -0
  176. package/src/main.tsx +41 -0
  177. package/src/resources/locales/en.json +765 -0
  178. package/src/resources/locales/zh.json +766 -0
  179. package/src/store/index.ts +23 -0
  180. package/src/styles/global.scss +100 -0
  181. package/src/utils/shortcutUtils.ts +88 -0
  182. package/src/vite-env.d.ts +12 -0
  183. package/src/ws.ts +33 -0
  184. package/vite.config.ts +26 -0
@@ -0,0 +1,257 @@
1
+ import './RuleFormPanel.scss'
2
+
3
+ import { Button, Form, Input, Switch, Tooltip } from 'antd'
4
+ import React, { useCallback, useEffect } from 'react'
5
+ import { useTranslation } from 'react-i18next'
6
+
7
+ import type { AutomationRule } from '#~/api.js'
8
+
9
+ import { TaskList } from './TaskList'
10
+ import { TriggerList } from './TriggerList'
11
+ import type { RuleFormValues } from './types'
12
+
13
+ interface RuleFormPanelProps {
14
+ mode: 'create' | 'edit'
15
+ rule: AutomationRule | null
16
+ submitting: boolean
17
+ onSubmit: (payload: Partial<AutomationRule>, immediateRun: boolean) => Promise<void>
18
+ onCancel: () => void
19
+ }
20
+
21
+ const serverHost = (import.meta.env.__VF_PROJECT_AI_SERVER_HOST__ as string | undefined) ?? window.location.hostname
22
+ const serverPort = (import.meta.env.__VF_PROJECT_AI_SERVER_PORT__ as string | undefined) ?? '8787'
23
+ const serverUrl = `http://${serverHost}:${serverPort}`
24
+
25
+ export function RuleFormPanel({ mode, rule, submitting, onSubmit, onCancel }: RuleFormPanelProps) {
26
+ const { t } = useTranslation()
27
+ const [form] = Form.useForm<RuleFormValues>()
28
+
29
+ const updateWeeklyCron = useCallback((index: number, nextDay?: string, nextTime?: string) => {
30
+ const triggers = form.getFieldValue('triggers') as RuleFormValues['triggers'] | undefined
31
+ const trigger = triggers?.[index]
32
+ if (!trigger) return
33
+ const day = nextDay ?? trigger.weeklyDay
34
+ const time = nextTime ?? trigger.weeklyTime
35
+ if (!day || !time) return
36
+ const [hour, minute] = time.split(':')
37
+ if (!hour || !minute) return
38
+ const h = Number.parseInt(hour, 10)
39
+ const m = Number.parseInt(minute, 10)
40
+ if (Number.isNaN(h) || Number.isNaN(m)) return
41
+ const expression = `${m} ${h} * * ${day}`
42
+ const currentExpression = trigger.cronExpression
43
+ const weeklyPattern = /^\d{1,2}\s+\d{1,2}\s+\*\s+\*\s+\d$/
44
+ if (!currentExpression || weeklyPattern.test(currentExpression)) {
45
+ form.setFieldValue(['triggers', index, 'cronExpression'], expression)
46
+ }
47
+ }, [form])
48
+
49
+ const getWebhookUrl = useCallback((triggerId?: string, webhookKey?: string) => {
50
+ if (!triggerId || !webhookKey) return ''
51
+ return `${serverUrl}/api/automation/webhook/${triggerId}?key=${webhookKey}`
52
+ }, [])
53
+
54
+ useEffect(() => {
55
+ if (mode === 'create') {
56
+ form.setFieldsValue({
57
+ name: '',
58
+ description: '',
59
+ enabled: true,
60
+ immediateRun: false,
61
+ triggers: [
62
+ {
63
+ type: 'interval',
64
+ intervalMinutes: 30,
65
+ cronExpression: '',
66
+ cronPreset: undefined,
67
+ weeklyDay: '1',
68
+ weeklyTime: '09:00'
69
+ }
70
+ ],
71
+ tasks: [
72
+ {
73
+ title: t('automation.taskDefaultTitle', { index: 1 }),
74
+ prompt: ''
75
+ }
76
+ ]
77
+ })
78
+ return
79
+ }
80
+ if (mode === 'edit' && rule) {
81
+ const triggers = (rule.triggers ?? []).map(trigger => {
82
+ const cronExpression = trigger.cronExpression ?? ''
83
+ const weeklyMatch = cronExpression.match(/^(\d{1,2})\s+(\d{1,2})\s+\*\s+\*\s+(\d)$/)
84
+ return {
85
+ id: trigger.id,
86
+ type: trigger.type,
87
+ intervalMinutes: trigger.intervalMs ? Math.max(1, Math.round(trigger.intervalMs / 60000)) : undefined,
88
+ webhookKey: trigger.webhookKey ?? undefined,
89
+ cronExpression,
90
+ cronPreset: undefined,
91
+ weeklyDay: weeklyMatch ? weeklyMatch[3] : '1',
92
+ weeklyTime: weeklyMatch ? `${weeklyMatch[2].padStart(2, '0')}:${weeklyMatch[1].padStart(2, '0')}` : '09:00'
93
+ }
94
+ })
95
+ const tasks = (rule.tasks ?? []).map((task, index) => ({
96
+ id: task.id,
97
+ title: task.title || t('automation.taskDefaultTitle', { index: index + 1 }),
98
+ prompt: task.prompt
99
+ }))
100
+ form.setFieldsValue({
101
+ name: rule.name,
102
+ description: rule.description ?? '',
103
+ enabled: rule.enabled,
104
+ immediateRun: false,
105
+ triggers: triggers.length > 0 ? triggers : [{
106
+ type: 'interval',
107
+ intervalMinutes: 30,
108
+ cronExpression: '',
109
+ cronPreset: undefined,
110
+ weeklyDay: '1',
111
+ weeklyTime: '09:00'
112
+ }],
113
+ tasks: tasks.length > 0 ? tasks : [{
114
+ title: t('automation.taskDefaultTitle', { index: 1 }),
115
+ prompt: ''
116
+ }]
117
+ })
118
+ }
119
+ }, [form, mode, rule, t])
120
+
121
+ const handleSubmit = useCallback(async () => {
122
+ const values = await form.validateFields()
123
+ const payload: Partial<AutomationRule> = {
124
+ name: values.name.trim(),
125
+ description: values.description?.trim() ?? '',
126
+ enabled: values.enabled,
127
+ triggers: values.triggers.map((trigger) => {
128
+ if (trigger.type === 'interval') {
129
+ return {
130
+ id: trigger.id,
131
+ type: 'interval',
132
+ intervalMs: Math.max(1, trigger.intervalMinutes ?? 1) * 60000
133
+ }
134
+ }
135
+ if (trigger.type === 'cron') {
136
+ return {
137
+ id: trigger.id,
138
+ type: 'cron',
139
+ cronExpression: trigger.cronExpression?.trim() ?? ''
140
+ }
141
+ }
142
+ return {
143
+ id: trigger.id,
144
+ type: 'webhook',
145
+ webhookKey: trigger.webhookKey?.trim() ?? ''
146
+ }
147
+ }) as AutomationRule['triggers'],
148
+ tasks: values.tasks.map((task) => ({
149
+ id: task.id,
150
+ title: task.title?.trim() ?? '',
151
+ prompt: task.prompt.trim()
152
+ })) as AutomationRule['tasks']
153
+ }
154
+ await onSubmit(payload, values.immediateRun)
155
+ }, [form, onSubmit])
156
+
157
+ return (
158
+ <div className='automation-view__form-panel'>
159
+ <div className='automation-view__form-header'>
160
+ <div className='automation-view__form-title'>
161
+ <span className='material-symbols-rounded automation-view__form-icon'>edit_square</span>
162
+ {mode === 'create' ? t('automation.newRule') : t('automation.editRule')}
163
+ </div>
164
+ <div className='automation-view__form-header-actions'>
165
+ <Tooltip title={t('common.cancel')}>
166
+ <Button
167
+ className='automation-view__square-button'
168
+ onClick={onCancel}
169
+ >
170
+ <span className='material-symbols-rounded automation-view__action-icon'>close</span>
171
+ </Button>
172
+ </Tooltip>
173
+ <Tooltip title={t('common.confirm')}>
174
+ <Button
175
+ className='automation-view__square-button automation-view__square-button--confirm'
176
+ type='primary'
177
+ loading={submitting}
178
+ onClick={() => void handleSubmit()}
179
+ >
180
+ <span className='material-symbols-rounded automation-view__action-icon'>check</span>
181
+ </Button>
182
+ </Tooltip>
183
+ </div>
184
+ </div>
185
+ <Form form={form} layout='vertical' initialValues={{ enabled: true, immediateRun: false }}>
186
+ <div className='automation-view__form-grid'>
187
+ <div className='automation-view__form-left'>
188
+ <div className='automation-view__form-section'>
189
+ <div className='automation-view__form-title'>
190
+ <span className='material-symbols-rounded automation-view__form-icon'>info</span>
191
+ {t('automation.sectionBasic')}
192
+ </div>
193
+ <Form.Item
194
+ name='name'
195
+ label={(
196
+ <span className='automation-view__label'>
197
+ <span className='material-symbols-rounded automation-view__label-icon'>badge</span>
198
+ {t('automation.ruleName')}
199
+ </span>
200
+ )}
201
+ rules={[{ required: true, message: t('automation.ruleNameRequired') }]}
202
+ >
203
+ <Input />
204
+ </Form.Item>
205
+ <Form.Item
206
+ name='description'
207
+ label={(
208
+ <span className='automation-view__label'>
209
+ <span className='material-symbols-rounded automation-view__label-icon'>description</span>
210
+ {t('automation.ruleDescription')}
211
+ </span>
212
+ )}
213
+ >
214
+ <Input.TextArea rows={2} />
215
+ </Form.Item>
216
+ <div className='automation-view__toggle-group'>
217
+ <div className='automation-view__toggle-row'>
218
+ <span className='automation-view__toggle-label'>
219
+ <span className='material-symbols-rounded automation-view__label-icon'>toggle_on</span>
220
+ {t('automation.enabled')}
221
+ </span>
222
+ <Form.Item name='enabled' valuePropName='checked' noStyle>
223
+ <Switch />
224
+ </Form.Item>
225
+ </div>
226
+ <div className='automation-view__toggle-row'>
227
+ <span className='automation-view__toggle-label automation-view__toggle-label--run'>
228
+ <span className='material-symbols-rounded automation-view__label-icon automation-view__label-icon--run'>play_circle</span>
229
+ {t('automation.immediateRun')}
230
+ </span>
231
+ <Form.Item name='immediateRun' valuePropName='checked' noStyle>
232
+ <Switch />
233
+ </Form.Item>
234
+ </div>
235
+ </div>
236
+ </div>
237
+ </div>
238
+ <div className='automation-view__form-right'>
239
+ <div className='automation-view__form-right-scroll'>
240
+ <div className='automation-view__form-section'>
241
+ <TriggerList
242
+ form={form}
243
+ updateWeeklyCron={updateWeeklyCron}
244
+ getWebhookUrl={getWebhookUrl}
245
+ />
246
+ </div>
247
+
248
+ <div className='automation-view__form-section'>
249
+ <TaskList />
250
+ </div>
251
+ </div>
252
+ </div>
253
+ </div>
254
+ </Form>
255
+ </div>
256
+ )
257
+ }
@@ -0,0 +1,219 @@
1
+ .automation-view {
2
+ &__sidebar {
3
+ display: flex;
4
+ flex-direction: column;
5
+ height: 100%;
6
+ }
7
+
8
+ &__sidebar-header {
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: space-between;
12
+ padding-bottom: 16px;
13
+ }
14
+
15
+ &__sidebar-search {
16
+ padding-bottom: 12px;
17
+ }
18
+
19
+ &__search-icon {
20
+ font-size: 16px;
21
+ color: var(--sub-text-color);
22
+ }
23
+
24
+ &__title {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: 8px;
28
+ }
29
+
30
+ &__title-icon {
31
+ font-size: 24px;
32
+ color: var(--sub-text-color);
33
+ }
34
+
35
+ &__title-text {
36
+ margin: 0;
37
+ font-size: 18px;
38
+ color: var(--text-color);
39
+ }
40
+
41
+ &__rule-list {
42
+ flex: 1;
43
+ overflow: auto;
44
+ }
45
+
46
+ &__rule-item {
47
+ padding: 0 !important;
48
+ margin-bottom: 10px;
49
+ cursor: pointer;
50
+ display: flex;
51
+ position: relative;
52
+ border-block-end: none !important;
53
+
54
+ &--active::before {
55
+ content: '';
56
+ position: absolute;
57
+ left: 0;
58
+ top: 0;
59
+ width: 100%;
60
+ height: 100%;
61
+ border: 2px solid var(--primary-color);
62
+ border-radius: 8px;
63
+ pointer-events: none;
64
+ }
65
+ }
66
+
67
+ &__rule-card {
68
+ display: flex;
69
+ align-items: flex-start;
70
+ justify-content: space-between;
71
+ width: 100%;
72
+ border: 1px solid var(--border-color);
73
+ border-radius: 12px;
74
+ padding: 12px 12px 12px 16px;
75
+ background: var(--bg-color);
76
+ }
77
+
78
+ &__rule-content {
79
+ display: flex;
80
+ flex-direction: column;
81
+ gap: 8px;
82
+ align-items: flex-start;
83
+ }
84
+
85
+ &__rule-name {
86
+ display: flex;
87
+ align-items: center;
88
+ gap: 8px;
89
+ }
90
+
91
+ &__rule-icon {
92
+ font-size: 20px;
93
+ color: var(--sub-text-color);
94
+
95
+ &--interval,
96
+ &--cron,
97
+ &--webhook {
98
+ color: var(--primary-color);
99
+ }
100
+ }
101
+
102
+ &__rule-title {
103
+ font-weight: 600;
104
+ color: var(--text-color);
105
+ }
106
+
107
+ &__rule-meta {
108
+ display: flex;
109
+ flex-direction: column;
110
+ gap: 4px;
111
+ color: var(--sub-text-color);
112
+ font-size: 12px;
113
+ }
114
+
115
+ &__rule-trigger-list {
116
+ display: flex;
117
+ align-items: center;
118
+ gap: 6px;
119
+ flex-wrap: wrap;
120
+ }
121
+
122
+ &__trigger-chip {
123
+ display: inline-flex;
124
+ align-items: center;
125
+ gap: 4px;
126
+ border-radius: 999px;
127
+ background: var(--tag-bg);
128
+ color: var(--sub-text-color);
129
+ }
130
+
131
+ &__trigger-icon {
132
+ font-size: 14px;
133
+ }
134
+
135
+ &__trigger-more {
136
+ font-size: 12px;
137
+ color: var(--sub-text-color);
138
+ }
139
+
140
+ &__rule-tasks {
141
+ display: inline-flex;
142
+ align-items: center;
143
+ gap: 6px;
144
+ }
145
+
146
+ &__rule-actions {
147
+ display: flex;
148
+ flex-direction: column;
149
+ align-items: flex-end;
150
+ gap: 12px;
151
+ padding-left: 12px;
152
+ flex-shrink: 0;
153
+
154
+ &-top {
155
+ display: inline-flex;
156
+ align-items: center;
157
+ justify-content: flex-end;
158
+ gap: 8px;
159
+ }
160
+
161
+ &-bottom {
162
+ display: inline-flex;
163
+ align-items: center;
164
+ gap: 8px;
165
+ }
166
+ }
167
+
168
+ &__rule-last {
169
+ display: inline-flex;
170
+ align-items: center;
171
+ gap: 6px;
172
+ color: var(--sub-text-color);
173
+ }
174
+
175
+ &__meta-icon {
176
+ font-size: 14px;
177
+ }
178
+
179
+ &__icon-button {
180
+ display: inline-flex;
181
+ align-items: center;
182
+ justify-content: center;
183
+ width: 32px;
184
+ height: 32px;
185
+ padding: 0;
186
+
187
+ &--run .automation-view__action-icon,
188
+ &--add .automation-view__action-icon {
189
+ color: var(--success-color);
190
+ }
191
+
192
+ &--delete .automation-view__action-icon {
193
+ color: var(--danger-color);
194
+ }
195
+
196
+ &--active .automation-view__action-icon {
197
+ color: var(--warning-color);
198
+ }
199
+
200
+ &--favorite .automation-view__action-icon {
201
+ color: var(--warning-color);
202
+ }
203
+ }
204
+
205
+ &__action-icon {
206
+ font-size: 18px;
207
+ }
208
+
209
+ &__action-icon--star {
210
+ color: var(--warning-color);
211
+ }
212
+
213
+ &__empty {
214
+ flex: 1;
215
+ display: flex;
216
+ align-items: center;
217
+ justify-content: center;
218
+ }
219
+ }