vue-agent-start 0.1.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 (169) hide show
  1. package/package.json +30 -0
  2. package/pnpm-workspace.yaml +3 -0
  3. package/src/agent-flow/adapter/backend.ts +99 -0
  4. package/src/agent-flow/components/ChatIframePanel.vue +773 -0
  5. package/src/agent-flow/components/DatasetItemCard.vue +313 -0
  6. package/src/agent-flow/components/MemoryWindow.vue +104 -0
  7. package/src/agent-flow/components/PromptEditor.vue +804 -0
  8. package/src/agent-flow/components/PromptEditorTagPanel.vue +460 -0
  9. package/src/agent-flow/components/SvgIcon.vue +32 -0
  10. package/src/agent-flow/components/ToolItemCard.vue +169 -0
  11. package/src/agent-flow/components/VariableCard.vue +161 -0
  12. package/src/agent-flow/components/VariableSelector.vue +162 -0
  13. package/src/agent-flow/components/chat-iframe-types.ts +35 -0
  14. package/src/agent-flow/components/stubs/DatasetChooser.vue +70 -0
  15. package/src/agent-flow/components/stubs/Embedding.vue +22 -0
  16. package/src/agent-flow/components/stubs/ModelSelect.vue +24 -0
  17. package/src/agent-flow/components/stubs/RestfulSelectCard.vue +24 -0
  18. package/src/agent-flow/components/stubs/ToolChooser.vue +96 -0
  19. package/src/agent-flow/components/stubs/TriggersItemCard.vue +126 -0
  20. package/src/agent-flow/components/stubs/VariableModal.vue +115 -0
  21. package/src/agent-flow/index.ts +73 -0
  22. package/src/agent-flow/stores/workflow.ts +72 -0
  23. package/src/agent-flow/utils/langUtils.ts +173 -0
  24. package/src/agent-flow/workflow/Ability.vue +65 -0
  25. package/src/agent-flow/workflow/AuthorizationItem.vue +101 -0
  26. package/src/agent-flow/workflow/ConversationVar.vue +42 -0
  27. package/src/agent-flow/workflow/CustomEdge.vue +94 -0
  28. package/src/agent-flow/workflow/EnvironmentVar.vue +40 -0
  29. package/src/agent-flow/workflow/FlowDesigner.vue +2802 -0
  30. package/src/agent-flow/workflow/Icon.vue +179 -0
  31. package/src/agent-flow/workflow/NodeConfig.vue +509 -0
  32. package/src/agent-flow/workflow/NodeConfigCard.vue +460 -0
  33. package/src/agent-flow/workflow/NodeHandle.vue +147 -0
  34. package/src/agent-flow/workflow/NodeHeaderToolbar.vue +77 -0
  35. package/src/agent-flow/workflow/NodeHoverToolbar.vue +176 -0
  36. package/src/agent-flow/workflow/OutputItemCard.vue +668 -0
  37. package/src/agent-flow/workflow/ParamTableItem.vue +200 -0
  38. package/src/agent-flow/workflow/StructTable.vue +202 -0
  39. package/src/agent-flow/workflow/VarInsertField.vue +517 -0
  40. package/src/agent-flow/workflow/VarSelectField.vue +223 -0
  41. package/src/agent-flow/workflow/VariableSelectorItem.vue +48 -0
  42. package/src/agent-flow/workflow/WfField.vue +206 -0
  43. package/src/agent-flow/workflow/_config-base.css +470 -0
  44. package/src/agent-flow/workflow/composables/useNode.js +55 -0
  45. package/src/agent-flow/workflow/index.vue +53 -0
  46. package/src/agent-flow/workflow/nodeCard/AgentNodeCard.vue +180 -0
  47. package/src/agent-flow/workflow/nodeCard/AnswerNodeCard.vue +65 -0
  48. package/src/agent-flow/workflow/nodeCard/ClassifierCard.vue +152 -0
  49. package/src/agent-flow/workflow/nodeCard/CodeNodeCard.vue +139 -0
  50. package/src/agent-flow/workflow/nodeCard/ConditionNodeCard.vue +323 -0
  51. package/src/agent-flow/workflow/nodeCard/DocumentExtractorCard.vue +83 -0
  52. package/src/agent-flow/workflow/nodeCard/EndNodeCard.vue +123 -0
  53. package/src/agent-flow/workflow/nodeCard/HttpNodeCard.vue +451 -0
  54. package/src/agent-flow/workflow/nodeCard/HumanInputCard.vue +152 -0
  55. package/src/agent-flow/workflow/nodeCard/IterationCard.vue +66 -0
  56. package/src/agent-flow/workflow/nodeCard/KnowledgeRetrievalCard.vue +48 -0
  57. package/src/agent-flow/workflow/nodeCard/LLMNodeCard.vue +206 -0
  58. package/src/agent-flow/workflow/nodeCard/ListOperatorCard.vue +188 -0
  59. package/src/agent-flow/workflow/nodeCard/ParameterExtractorCard.vue +352 -0
  60. package/src/agent-flow/workflow/nodeCard/ServiceApiNodeCard.vue +188 -0
  61. package/src/agent-flow/workflow/nodeCard/StartNodeCard.vue +216 -0
  62. package/src/agent-flow/workflow/nodeCard/VariableAssignerCard.vue +125 -0
  63. package/src/agent-flow/workflow/nodeCard/VariableNodeCard.vue +121 -0
  64. package/src/agent-flow/workflow/nodes/AgentNode.vue +122 -0
  65. package/src/agent-flow/workflow/nodes/AnswerNode.vue +99 -0
  66. package/src/agent-flow/workflow/nodes/ClassifierNode.vue +199 -0
  67. package/src/agent-flow/workflow/nodes/CodeNode.vue +152 -0
  68. package/src/agent-flow/workflow/nodes/ConditionNode.vue +232 -0
  69. package/src/agent-flow/workflow/nodes/DocumentExtractorNode.vue +96 -0
  70. package/src/agent-flow/workflow/nodes/EndNode.vue +119 -0
  71. package/src/agent-flow/workflow/nodes/FileUploadNode.vue +97 -0
  72. package/src/agent-flow/workflow/nodes/HttpNode.vue +204 -0
  73. package/src/agent-flow/workflow/nodes/HumanInputNode.vue +110 -0
  74. package/src/agent-flow/workflow/nodes/IterationNode.vue +98 -0
  75. package/src/agent-flow/workflow/nodes/KnowledgeRetrievalNode.vue +253 -0
  76. package/src/agent-flow/workflow/nodes/LLMNode.vue +134 -0
  77. package/src/agent-flow/workflow/nodes/ListOperatorNode.vue +111 -0
  78. package/src/agent-flow/workflow/nodes/LoopNode.vue +94 -0
  79. package/src/agent-flow/workflow/nodes/ParameterExtractorNode.vue +147 -0
  80. package/src/agent-flow/workflow/nodes/ServiceApiNode.vue +161 -0
  81. package/src/agent-flow/workflow/nodes/StartNode.vue +199 -0
  82. package/src/agent-flow/workflow/nodes/TemplateNode.vue +103 -0
  83. package/src/agent-flow/workflow/nodes/UserInputNode.vue +92 -0
  84. package/src/agent-flow/workflow/nodes/VariableAssignerNode.vue +145 -0
  85. package/src/agent-flow/workflow/nodes/VariableNode.vue +130 -0
  86. package/src/agent-flow/workflow/nodes/_node-base.css +338 -0
  87. package/src/agent-flow/workflow/utils/node_card_form.ts +335 -0
  88. package/src/agent-flow/workflow/utils/node_config.ts +63 -0
  89. package/src/agent-flow/workflow/utils/workflow_utils.ts +151 -0
  90. package/src/agent-studio/adapters/springAgentStart.ts +390 -0
  91. package/src/agent-studio/api/index.ts +1 -0
  92. package/src/agent-studio/api/types.ts +173 -0
  93. package/src/agent-studio/components/AgentApiDocs.vue +500 -0
  94. package/src/agent-studio/components/AgentAppsPage.vue +1601 -0
  95. package/src/agent-studio/components/AgentCardGrid.vue +259 -0
  96. package/src/agent-studio/components/AgentChatPage.vue +553 -0
  97. package/src/agent-studio/components/AgentDebugPanel.vue +350 -0
  98. package/src/agent-studio/components/AgentLogsPanel.vue +391 -0
  99. package/src/agent-studio/components/AgentMonitorPanel.vue +204 -0
  100. package/src/agent-studio/components/AgentOrchestrate.vue +505 -0
  101. package/src/agent-studio/components/AgentPromptEditor.vue +237 -0
  102. package/src/agent-studio/components/AgentStudioShell.vue +227 -0
  103. package/src/agent-studio/components/AgentToolsPanel.vue +394 -0
  104. package/src/agent-studio/components/AgentVariablesPanel.vue +205 -0
  105. package/src/agent-studio/components/ApiKeyManager.vue +251 -0
  106. package/src/agent-studio/components/AppDesignDrawer.vue +3391 -0
  107. package/src/agent-studio/components/CreateAppModal.vue +737 -0
  108. package/src/agent-studio/components/SparkChart.vue +200 -0
  109. package/src/agent-studio/components/VariableEditorModal.vue +499 -0
  110. package/src/agent-studio/composables/useAgentStudio.ts +347 -0
  111. package/src/agent-studio/index.ts +60 -0
  112. package/src/agent-studio/panels/DrawerFlowDesigner.vue +203 -0
  113. package/src/agent-studio/panels/LogAnnotationPanel.vue +490 -0
  114. package/src/agent-studio/panels/MonitorPanel.vue +535 -0
  115. package/src/agent-studio/types.ts +242 -0
  116. package/src/index.ts +155 -0
  117. package/src/knowledge-hub/adapters/springAgentStart.ts +472 -0
  118. package/src/knowledge-hub/components/AddDocumentsWizard.vue +1452 -0
  119. package/src/knowledge-hub/components/CreateDatasetWizard.vue +1723 -0
  120. package/src/knowledge-hub/components/DatasetCardGrid.vue +467 -0
  121. package/src/knowledge-hub/components/DatasetDetailDrawer.vue +888 -0
  122. package/src/knowledge-hub/components/DatasetPicker.vue +65 -0
  123. package/src/knowledge-hub/components/DatasetPickerModal.vue +526 -0
  124. package/src/knowledge-hub/components/DatasetSettingsPanel.vue +908 -0
  125. package/src/knowledge-hub/components/DatasetSidebar.vue +781 -0
  126. package/src/knowledge-hub/components/DocumentChunksView.vue +802 -0
  127. package/src/knowledge-hub/components/DocumentTable.vue +552 -0
  128. package/src/knowledge-hub/components/HitTestingPanel.vue +74 -0
  129. package/src/knowledge-hub/components/KnowledgeApp.vue +66 -0
  130. package/src/knowledge-hub/components/KnowledgeHubApp.vue +504 -0
  131. package/src/knowledge-hub/components/RecallTestingPanelV2.vue +515 -0
  132. package/src/knowledge-hub/components/RetrievalConfigPopover.vue +270 -0
  133. package/src/knowledge-hub/components/RetrievalMethodPicker.vue +547 -0
  134. package/src/knowledge-hub/components/RetrievedList.vue +24 -0
  135. package/src/knowledge-hub/components/internal/KhDialog.vue +195 -0
  136. package/src/knowledge-hub/composables/useKnowledge.ts +89 -0
  137. package/src/knowledge-hub/i18n/index.ts +2 -0
  138. package/src/knowledge-hub/i18n/messages.ts +422 -0
  139. package/src/knowledge-hub/i18n/useKhI18n.ts +107 -0
  140. package/src/knowledge-hub/index.ts +46 -0
  141. package/src/knowledge-hub/styles/index.css +4 -0
  142. package/src/knowledge-hub/styles/tokens.css +138 -0
  143. package/src/knowledge-hub/types/api.ts +213 -0
  144. package/src/knowledge-hub/types/dataset.ts +88 -0
  145. package/src/knowledge-hub/types/document.ts +45 -0
  146. package/src/knowledge-hub/types/index.ts +9 -0
  147. package/src/knowledge-hub/types/retrieval.ts +46 -0
  148. package/src/provider-hub/components/CredentialForm.vue +103 -0
  149. package/src/provider-hub/components/DefaultModelsPanel.vue +270 -0
  150. package/src/provider-hub/components/GroupedModelSelect.vue +445 -0
  151. package/src/provider-hub/components/ModelCardGrid.vue +332 -0
  152. package/src/provider-hub/components/ModelParameterDrawer.vue +739 -0
  153. package/src/provider-hub/components/ModelPickerPopover.vue +1282 -0
  154. package/src/provider-hub/components/ProviderApp.vue +159 -0
  155. package/src/provider-hub/components/ProviderCredentialModal.vue +321 -0
  156. package/src/provider-hub/components/ProviderGallery.vue +131 -0
  157. package/src/provider-hub/components/ProviderHubShell.vue +1992 -0
  158. package/src/provider-hub/components/ProviderIcon.vue +130 -0
  159. package/src/provider-hub/composables/useProviderHub.ts +358 -0
  160. package/src/provider-hub/index.ts +43 -0
  161. package/src/provider-hub/svg/MiniMax.svg +1 -0
  162. package/src/provider-hub/svg/Volcengine.svg +1 -0
  163. package/src/provider-hub/svg/Zhipu.svg +1 -0
  164. package/src/provider-hub/svg/deepseek.svg +1 -0
  165. package/src/provider-hub/svg/moonshot.svg +1 -0
  166. package/src/provider-hub/svg/openai.svg +1 -0
  167. package/src/provider-hub/svg/qwen.svg +1 -0
  168. package/src/provider-hub/svg/siliconflow.svg +1 -0
  169. package/src/provider-hub/types.ts +256 -0
@@ -0,0 +1,103 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * CredentialForm — schema-driven form for provider credentials.
4
+ *
5
+ * Consumes a provider's `credentialSchema` and renders each field as either a
6
+ * password input (when secret) or plain text. Uses v-model on a caller-owned
7
+ * record so the parent can decide validation + submission.
8
+ */
9
+ import type { CredentialField } from '../types';
10
+
11
+ interface Props {
12
+ /** The provider's field schema, from GET /model-providers. */
13
+ fields: CredentialField[];
14
+ /** The credential values (parent-owned). */
15
+ modelValue: Record<string, unknown>;
16
+ /** Show "leave empty to keep current" placeholder — used in the edit flow. */
17
+ editMode?: boolean;
18
+ }
19
+
20
+ const props = withDefaults(defineProps<Props>(), {
21
+ editMode: false,
22
+ });
23
+
24
+ const emit = defineEmits<{
25
+ (e: 'update:modelValue', v: Record<string, unknown>): void;
26
+ }>();
27
+
28
+ function set(name: string, value: unknown) {
29
+ const next = { ...props.modelValue, [name]: value };
30
+ emit('update:modelValue', next);
31
+ }
32
+ </script>
33
+
34
+ <template>
35
+ <div class="ph-form">
36
+ <div v-for="f in fields" :key="f.name" class="ph-field">
37
+ <label class="ph-label">
38
+ <span>{{ f.label }}</span>
39
+ <span v-if="f.required" class="ph-req">*</span>
40
+ <span v-if="f.secret" class="ph-secret">密文</span>
41
+ </label>
42
+ <input
43
+ v-if="f.secret"
44
+ type="password"
45
+ class="ph-input"
46
+ autocomplete="off"
47
+ :value="modelValue[f.name] as string ?? ''"
48
+ :placeholder="editMode ? '留空 = 保持不变' : (f.placeholder ?? '')"
49
+ @input="(e) => set(f.name, (e.target as HTMLInputElement).value)"
50
+ />
51
+ <input
52
+ v-else
53
+ type="text"
54
+ class="ph-input"
55
+ :value="modelValue[f.name] as string ?? ''"
56
+ :placeholder="editMode ? '留空 = 保持不变' : (f.placeholder ?? '')"
57
+ @input="(e) => set(f.name, (e.target as HTMLInputElement).value)"
58
+ />
59
+ </div>
60
+ </div>
61
+ </template>
62
+
63
+ <style scoped>
64
+ .ph-form {
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: 12px;
68
+ }
69
+ .ph-field {
70
+ display: flex;
71
+ flex-direction: column;
72
+ gap: 4px;
73
+ }
74
+ .ph-label {
75
+ display: flex;
76
+ align-items: center;
77
+ gap: 6px;
78
+ font-size: 13px;
79
+ font-weight: 500;
80
+ color: #374151;
81
+ }
82
+ .ph-req {
83
+ color: #dc2626;
84
+ }
85
+ .ph-secret {
86
+ padding: 0 6px;
87
+ font-size: 10px;
88
+ border-radius: 4px;
89
+ background: #fef3c7;
90
+ color: #b45309;
91
+ }
92
+ .ph-input {
93
+ padding: 6px 10px;
94
+ font-size: 13px;
95
+ border: 1px solid #d1d5db;
96
+ border-radius: 6px;
97
+ transition: border-color 0.15s ease;
98
+ }
99
+ .ph-input:focus {
100
+ outline: none;
101
+ border-color: #6366f1;
102
+ }
103
+ </style>
@@ -0,0 +1,270 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * DefaultModelsPanel — Dify/reference-parity "system default models" strip.
4
+ *
5
+ * Layout is a row per model type (LLM / TEXT_EMBEDDING / RERANK / SPEECH2TEXT /
6
+ * TTS). Each row is a single a-select whose options are grouped per provider,
7
+ * mirroring the reference project's DefaultModel.vue: opt-group header shows
8
+ * "{provider} - {description}", options list each enabled model with an icon
9
+ * badge + a modelType tag.
10
+ *
11
+ * Auto-save on selection — no modal, no OK button. Sends
12
+ * PUT /model-providers/{provider}/models/{model}/default?modelType=... which
13
+ * writes to agent_tenant_default_model.
14
+ */
15
+ import { computed, onMounted, ref, watch } from 'vue';
16
+
17
+ import {
18
+ modelTypeColor,
19
+ modelTypeLabel,
20
+ useProviderHub,
21
+ } from '../composables/useProviderHub';
22
+ import type {
23
+ GroupedProviderView,
24
+ ModelEntity,
25
+ ModelType,
26
+ } from '../types';
27
+ import GroupedModelSelect, {
28
+ type GroupedModelSelectOption,
29
+ } from './GroupedModelSelect.vue';
30
+
31
+ interface Props {
32
+ tenantId?: string;
33
+ /**
34
+ * Rows to render, in order. Each row maps to one a-select. Defaults follow
35
+ * the reference project (adds SPEECH2TEXT alongside LLM/EMBED/RERANK/TTS).
36
+ */
37
+ types?: Array<{ desc: string; modelType: ModelType }>;
38
+ }
39
+
40
+ const props = withDefaults(defineProps<Props>(), {
41
+ types: () => [
42
+ { modelType: 'LLM', desc: '系统推理模型' },
43
+ { modelType: 'TEXT_EMBEDDING', desc: 'Embedding 模型' },
44
+ { modelType: 'RERANK', desc: 'Rerank 模型' },
45
+ { modelType: 'SPEECH2TEXT', desc: '语音转文本模型' },
46
+ { modelType: 'TTS', desc: '文本转语音模型' },
47
+ ],
48
+ });
49
+
50
+ const emit = defineEmits<{
51
+ (e: 'change'): void;
52
+ }>();
53
+
54
+ const {
55
+ listDefaults,
56
+ listModelsGroupedByType,
57
+ setModelDefaultByName,
58
+ } = useProviderHub();
59
+
60
+ /** provider list per model type — feeds each row's a-select opt-groups. */
61
+ const providerModelMap = ref<Record<string, GroupedProviderView[]>>({});
62
+ /** Currently-selected model.id per type. Composite `${provider}::${model}::${type}`. */
63
+ const selected = ref<Record<string, string | undefined>>({});
64
+ const loading = ref(false);
65
+ const savingType = ref<null | string>(null);
66
+
67
+ async function refresh() {
68
+ loading.value = true;
69
+ try {
70
+ const [groups, defaults] = await Promise.all([
71
+ listModelsGroupedByType(props.tenantId),
72
+ listDefaults(props.tenantId),
73
+ ]);
74
+ providerModelMap.value = groups;
75
+
76
+ // Seed the Select value from the tenant's saved defaults. The grouped
77
+ // response uses composite ids; recompute the same shape from ModelEntity
78
+ // so v-model matches an option exactly.
79
+ const next: Record<string, string | undefined> = {};
80
+ for (const row of props.types) {
81
+ const t = row.modelType;
82
+ const def = defaults[t] as ModelEntity | undefined;
83
+ next[t] = def
84
+ ? `${def.providerName}::${def.modelName}::${t}`
85
+ : undefined;
86
+ }
87
+ selected.value = next;
88
+ } finally {
89
+ loading.value = false;
90
+ }
91
+ }
92
+
93
+ onMounted(refresh);
94
+ watch(() => props.tenantId, refresh);
95
+
96
+ defineExpose({ refresh });
97
+
98
+ async function onChange(t: ModelType, value: string | undefined) {
99
+ selected.value = { ...selected.value, [t]: value };
100
+ if (!value) return;
101
+ const [providerName, modelName, modelType] = value.split('::');
102
+ if (!providerName || !modelName || !modelType) return;
103
+ savingType.value = t;
104
+ try {
105
+ await setModelDefaultByName(
106
+ providerName,
107
+ modelName,
108
+ modelType as ModelType,
109
+ props.tenantId,
110
+ );
111
+ emit('change');
112
+ } finally {
113
+ savingType.value = null;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Flatten each type's grouped-by-provider view into the flat option list
119
+ * {@link GroupedModelSelect} expects. We keep `providerLabel` verbose (name +
120
+ * description) since it doubles as the group header for these dropdowns.
121
+ */
122
+ function toOptions(
123
+ providers: GroupedProviderView[],
124
+ ): GroupedModelSelectOption[] {
125
+ return providers.flatMap((p) =>
126
+ p.modelList.map<GroupedModelSelectOption>((m) => ({
127
+ id: m.id,
128
+ label: m.modelName,
129
+ providerName: p.provider,
130
+ providerLabel:
131
+ p.description && p.label
132
+ ? `${p.label} — ${p.description}`
133
+ : p.label || p.provider,
134
+ })),
135
+ );
136
+ }
137
+
138
+ const rows = computed(() =>
139
+ props.types.map((r) => ({
140
+ ...r,
141
+ providers: providerModelMap.value[r.modelType] ?? [],
142
+ options: toOptions(providerModelMap.value[r.modelType] ?? []),
143
+ value: selected.value[r.modelType],
144
+ })),
145
+ );
146
+ </script>
147
+
148
+ <template>
149
+ <section class="dmp-root">
150
+ <div class="dmp-title">
151
+ <span>系统默认模型</span>
152
+ <span class="dmp-title-hint">
153
+ · 智能体 / 知识库 / 工作流 在未指定模型时使用
154
+ </span>
155
+ </div>
156
+
157
+ <div class="dmp-grid">
158
+ <div v-for="r in rows" :key="r.modelType" class="dmp-row">
159
+ <div class="dmp-row-head">
160
+ <span class="dmp-cap" :data-color="modelTypeColor(r.modelType)">
161
+ {{ modelTypeLabel(r.modelType) }}
162
+ </span>
163
+ <span class="dmp-desc">{{ r.desc }}</span>
164
+ <span v-if="savingType === r.modelType" class="dmp-saving">保存中…</span>
165
+ </div>
166
+
167
+ <GroupedModelSelect
168
+ :model-value="r.value ?? null"
169
+ :options="r.options"
170
+ :disabled="savingType === r.modelType"
171
+ :placeholder="
172
+ r.providers.length === 0
173
+ ? '暂无可用模型 — 请先启用该类型的模型'
174
+ : '请选择模型'
175
+ "
176
+ :empty-text="`暂无可用的${modelTypeLabel(r.modelType)}模型`"
177
+ empty-hint="请先在「模型供应商」里配置并启用"
178
+ @update:model-value="(v) => onChange(r.modelType, v ?? undefined)"
179
+ />
180
+ </div>
181
+ </div>
182
+ </section>
183
+ </template>
184
+
185
+ <style scoped>
186
+ .dmp-root {
187
+ display: flex;
188
+ flex-direction: column;
189
+ gap: 10px;
190
+ }
191
+ .dmp-title {
192
+ font-size: 14px;
193
+ font-weight: 600;
194
+ color: #374151;
195
+ display: flex;
196
+ align-items: baseline;
197
+ gap: 4px;
198
+ }
199
+ :global(.dark) .dmp-title {
200
+ color: #d1d5db;
201
+ }
202
+ .dmp-title-hint {
203
+ font-weight: 400;
204
+ color: #9ca3af;
205
+ font-size: 12px;
206
+ }
207
+ .dmp-grid {
208
+ display: grid;
209
+ /* Evenly split the row across the configured types. minmax(180px, 1fr) keeps
210
+ * all 5 cards on one row at ~960px+ viewports; below that they wrap gracefully
211
+ * instead of stretching the last card. */
212
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
213
+ gap: 12px;
214
+ }
215
+ .dmp-row {
216
+ padding: 12px 14px;
217
+ background: #fff;
218
+ border: 1px solid #e5e7eb;
219
+ border-radius: 10px;
220
+ display: flex;
221
+ flex-direction: column;
222
+ gap: 8px;
223
+ }
224
+ :global(.dark) .dmp-row {
225
+ background: #1f1f1f;
226
+ border-color: #2d2d2d;
227
+ }
228
+ .dmp-row-head {
229
+ display: flex;
230
+ align-items: center;
231
+ gap: 8px;
232
+ }
233
+ .dmp-cap {
234
+ padding: 1px 8px;
235
+ font-size: 10px;
236
+ font-weight: 500;
237
+ border-radius: 4px;
238
+ background: #eef2ff;
239
+ color: #4338ca;
240
+ letter-spacing: 0.5px;
241
+ }
242
+ .dmp-cap[data-color='green'] {
243
+ background: #ecfdf5;
244
+ color: #059669;
245
+ }
246
+ .dmp-cap[data-color='orange'] {
247
+ background: #fff7ed;
248
+ color: #c2410c;
249
+ }
250
+ .dmp-cap[data-color='purple'] {
251
+ background: #faf5ff;
252
+ color: #7c3aed;
253
+ }
254
+ .dmp-desc {
255
+ font-size: 12px;
256
+ color: #6b7280;
257
+ flex: 1;
258
+ min-width: 0;
259
+ overflow: hidden;
260
+ text-overflow: ellipsis;
261
+ white-space: nowrap;
262
+ }
263
+ :global(.dark) .dmp-desc {
264
+ color: #9ca3af;
265
+ }
266
+ .dmp-saving {
267
+ font-size: 11px;
268
+ color: #6366f1;
269
+ }
270
+ </style>