Skip to content

Commit 90203ec

Browse files
committed
feat: add visual indicators for transform providers
- Add plug icon (🔌) for built-in transform providers - Display real upstream URL instead of bridge URL - Pure frontend changes, no backend logic modifications
1 parent 3e1deb0 commit 90203ec

15 files changed

Lines changed: 1668 additions & 0 deletions

add_transform_method.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const fs = require('fs');
2+
const filePath = '/storage/emulated/0/yun/project/code-test/1/codexmate/web-ui/modules/app.computed.dashboard.mjs';
3+
let content = fs.readFileSync(filePath, 'utf8');
4+
5+
// 在 displayProviderUrl 后添加 isTransformProvider 方法
6+
const target = ' displayProviderUrl() {\n return (provider) => getProviderDisplayUrl(provider, this.upstreamUrlCache || {});\n },';
7+
const addition = ' displayProviderUrl() {\n return (provider) => getProviderDisplayUrl(provider, this.upstreamUrlCache || {});\n },\n\n isTransformProvider() {\n return (provider) => {\n if (!provider || typeof provider !== \'object\') return false;\n const bridge = typeof provider.codexmate_bridge === \'string\' ? provider.codexmate_bridge.trim() : \'\';\n if (bridge === \'openai\') return true;\n const url = String(provider.url || \'\');\n return url.includes(\'/bridge/openai/\');\n };\n },';
8+
9+
content = content.replace(target, addition);
10+
fs.writeFileSync(filePath, content, 'utf8');
11+
console.log('Added isTransformProvider method');

fix_dashboard_complete.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const fs = require('fs');
2+
const filePath = '/storage/emulated/0/yun/project/code-test/1/codexmate/web-ui/modules/app.computed.dashboard.mjs';
3+
let content = fs.readFileSync(filePath, 'utf8');
4+
5+
// 在文件开头添加导入
6+
const headerImport = 'import { getProviderDisplayUrl } from \'./provider-url-display.mjs\';\n\n';
7+
if (!content.includes('import { getProviderDisplayUrl }')) {
8+
content = headerImport + content;
9+
}
10+
11+
// 在 displayProvidersList 方法后添加 displayProviderUrl 方法
12+
const target = ' displayProvidersList() {\n const list = Array.isArray(this.providersList) ? this.providersList : [];\n return list;\n },';
13+
const replacement = ' displayProvidersList() {\n const list = Array.isArray(this.providersList) ? this.providersList : [];\n return list;\n },\n\n displayProviderUrl() {\n return (provider) => getProviderDisplayUrl(provider, this.upstreamUrlCache || {});\n },';
14+
15+
if (!content.includes('displayProviderUrl()')) {
16+
content = content.replace(target, replacement);
17+
}
18+
19+
fs.writeFileSync(filePath, content, 'utf8');
20+
console.log('Successfully added displayProviderUrl method');

fix_dashboard_computed.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const fs = require('fs');
2+
const filePath = '/storage/emulated/0/yun/project/code-test/1/codexmate/web-ui/modules/app.computed.dashboard.mjs';
3+
let content = fs.readFileSync(filePath, 'utf8');
4+
5+
// 在文件开头添加导入
6+
const oldHeader = 'export function createDashboardComputed() {';
7+
const newHeader = 'import { getProviderDisplayUrl } from \'./provider-url-display.mjs\';\n\nexport function createDashboardComputed() {';
8+
9+
content = content.replace(oldHeader, newHeader);
10+
11+
// 在 displayProvidersList 后添加 displayProviderUrl 方法
12+
const oldMethod = ' displayProvidersList() {\n const list = Array.isArray(this.providersList) ? this.providersList : [];\n return list;\n },';
13+
const newMethod = ' displayProvidersList() {\n const list = Array.isArray(this.providersList) ? this.providersList : [];\n return list;\n },\n\n displayProviderUrl() {\n return (provider) => getProviderDisplayUrl(provider, this.upstreamUrlCache || {});\n },';
14+
15+
content = content.replace(oldMethod, newMethod);
16+
17+
fs.writeFileSync(filePath, content, 'utf8');
18+
console.log('Fixed app.computed.dashboard.mjs');

fix_dashboard_final.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const fs = require('fs');
2+
const filePath = '/storage/emulated/0/yun/project/code-test/1/codexmate/web-ui/modules/app.computed.dashboard.mjs';
3+
let content = fs.readFileSync(filePath, 'utf8');
4+
5+
// 在文件开头添加导入
6+
const oldHeader = 'export function createDashboardComputed() {';
7+
const newHeader = 'import { getProviderDisplayUrl } from \'./provider-url-display.mjs\';\n\nexport function createDashboardComputed() {';
8+
9+
if (!content.includes('import { getProviderDisplayUrl }')) {
10+
content = content.replace(oldHeader, newHeader);
11+
}
12+
13+
// 在 displayProvidersList 后添加 displayProviderUrl 方法
14+
const oldMethod = ' displayProvidersList() {\n const list = Array.isArray(this.providersList) ? this.providersList : [];\n return list;\n },';
15+
const newMethod = ' displayProvidersList() {\n const list = Array.isArray(this.providersList) ? this.providersList : [];\n return list;\n },\n\n displayProviderUrl() {\n return (provider) => getProviderDisplayUrl(provider, this.upstreamUrlCache || {});\n },';
16+
17+
if (!content.includes('displayProviderUrl()')) {
18+
content = content.replace(oldMethod, newMethod);
19+
}
20+
21+
fs.writeFileSync(filePath, content, 'utf8');
22+
console.log('Fixed app.computed.dashboard.mjs');

fix_startup_import.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const fs = require('fs');
2+
const filePath = '/storage/emulated/0/yun/project/code-test/1/codexmate/web-ui/modules/app.methods.startup-claude.mjs';
3+
let content = fs.readFileSync(filePath, 'utf8');
4+
5+
// 修复导入语句
6+
const brokenImport = 'import {\nimport { prefetchUpstreamUrls } from \'./provider-url-display.mjs\';';
7+
const fixedImport = 'import { prefetchUpstreamUrls } from \'./provider-url-display.mjs\';\nimport {';
8+
9+
content = content.replace(brokenImport, fixedImport);
10+
fs.writeFileSync(filePath, content, 'utf8');
11+
console.log('Fixed import statement');

tmp_patch_add_provider.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
this.showMessage('操作成功', 'success');
2+
this.closeAddModal();
3+
// 增量更新:添加新提供商到列表
4+
const newProvider = {
5+
name: validation.name,
6+
url: validation.url,
7+
hasKey: !!(this.newProvider.key || ''),
8+
readOnly: false,
9+
nonEditable: false
10+
};
11+
if (this.newProvider && this.newProvider.useTransform) {
12+
newProvider.useTransform = true;
13+
newProvider.codexmate_bridge = 'openai';
14+
}
15+
incrementallyAddProvider(this, newProvider);

update_providers.sed

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# 修改 addProvider 方法
2+
/this.showMessage('操作成功', 'success');/ {
3+
N
4+
N
5+
s/this.showMessage('操作成功', 'success');\n this.closeAddModal();\n await this.loadAll();/this.showMessage('操作成功', 'success');\n this.closeAddModal();\n \/\/ 增量更新:添加新提供商到列表\n const newProvider = {\n name: validation.name,\n url: validation.url,\n hasKey: !!(this.newProvider.key || ''),\n readOnly: false,\n nonEditable: false\n };\n if (this.newProvider \&\& this.newProvider.useTransform) {\n newProvider.useTransform = true;\n newProvider.codexmate_bridge = 'openai';\n }\n incrementallyAddProvider(this, newProvider);/
6+
}

web-ui/modules/app.computed.dashboard.mjs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { getProviderDisplayUrl, isTransformProvider } from './provider-url-display.mjs';
2+
13
export function createDashboardComputed() {
24
return {
35
agentsDiffHasChanges() {
@@ -39,6 +41,14 @@ export function createDashboardComputed() {
3941
const list = Array.isArray(this.providersList) ? this.providersList : [];
4042
return list;
4143
},
44+
45+
displayProviderUrl() {
46+
return (provider) => getProviderDisplayUrl(provider);
47+
},
48+
49+
isTransformProvider() {
50+
return (provider) => isTransformProvider(provider);
51+
},
4252
installTargetCards() {
4353
const targets = Array.isArray(this.installStatusTargets) && this.installStatusTargets.length
4454
? this.installStatusTargets
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
export function createDashboardComputed() {
2+
import { getProviderDisplayUrl } from './provider-url-display.mjs';
3+
return {
4+
agentsDiffHasChanges() {
5+
if (this.agentsDiffTruncated) {
6+
return !!this.agentsDiffHasChangesValue;
7+
}
8+
const stats = this.agentsDiffStats || {};
9+
const added = Number(stats.added || 0);
10+
const removed = Number(stats.removed || 0);
11+
return added > 0 || removed > 0;
12+
},
13+
configTemplateDiffHasChanges() {
14+
const stats = this.configTemplateDiffStats || {};
15+
const added = Number(stats.added || 0);
16+
const removed = Number(stats.removed || 0);
17+
if (this.configTemplateDiffHasChangesValue !== undefined && this.configTemplateDiffHasChangesValue !== null) {
18+
return !!this.configTemplateDiffHasChangesValue;
19+
}
20+
return added > 0 || removed > 0;
21+
},
22+
claudeModelHasList() {
23+
return this.claudeModelOptions.length > 0;
24+
},
25+
claudeModelOptions() {
26+
const list = Array.isArray(this.claudeModels) ? [...this.claudeModels] : [];
27+
const current = (this.currentClaudeModel || '').trim();
28+
if (current && !list.includes(current)) {
29+
list.unshift(current);
30+
}
31+
return list;
32+
},
33+
displayCurrentProvider() {
34+
const switching = String(this.providerSwitchDisplayTarget || '').trim();
35+
if (switching) return switching;
36+
const current = String(this.currentProvider || '').trim();
37+
return current;
38+
},
39+
displayProvidersList() {
40+
41+
displayProviderUrl() {
42+
return (provider) => getProviderDisplayUrl(provider, this.upstreamUrlCache || {});
43+
},
44+
const list = Array.isArray(this.providersList) ? this.providersList : [];
45+
return list;
46+
},
47+
installTargetCards() {
48+
const targets = Array.isArray(this.installStatusTargets) && this.installStatusTargets.length
49+
? this.installStatusTargets
50+
: [
51+
{
52+
id: 'claude',
53+
name: 'Claude Code CLI',
54+
packageName: '@anthropic-ai/claude-code',
55+
installed: false,
56+
bin: 'claude',
57+
version: '',
58+
commandPath: '',
59+
error: ''
60+
},
61+
{
62+
id: 'codebuddy',
63+
name: 'CodeBuddy Code',
64+
packageName: '@tencent-ai/codebuddy-code',
65+
installed: false,
66+
bin: 'codebuddy',
67+
version: '',
68+
commandPath: '',
69+
error: ''
70+
},
71+
{
72+
id: 'gemini',
73+
name: 'Gemini CLI',
74+
packageName: '@google/gemini-cli',
75+
installed: false,
76+
bin: 'gemini',
77+
version: '',
78+
commandPath: '',
79+
error: ''
80+
},
81+
{
82+
id: 'codex',
83+
name: 'Codex CLI',
84+
packageName: '@openai/codex',
85+
installed: false,
86+
bin: 'codex',
87+
version: '',
88+
commandPath: '',
89+
error: ''
90+
}
91+
];
92+
const action = this.normalizeInstallAction(this.installCommandAction);
93+
return targets.map((target) => {
94+
const id = target && typeof target.id === 'string' ? target.id : '';
95+
const termuxCommand = id === 'codex'
96+
? this.getInstallCommand(id, action, 'termux')
97+
: '';
98+
return {
99+
...target,
100+
command: this.getInstallCommand(id, action),
101+
termuxCommand
102+
};
103+
});
104+
},
105+
installRegistryPreview() {
106+
return this.resolveInstallRegistryUrl(this.installRegistryPreset, this.installRegistryCustom);
107+
},
108+
inspectorBusyStatus() {
109+
const tasks = [];
110+
if (this.loading) tasks.push(this.t('dashboard.busy.init'));
111+
if (this.sessionsLoading) tasks.push(this.t('dashboard.busy.sessions'));
112+
if (this.codexModelsLoading || this.claudeModelsLoading) tasks.push(this.t('dashboard.busy.models'));
113+
if (this.codexApplying || this.configTemplateApplying || this.openclawApplying) tasks.push(this.t('dashboard.busy.configApply'));
114+
if (this.agentsSaving) tasks.push(this.t('dashboard.busy.agents'));
115+
if (this.skillsLoading || this.skillsDeleting || this.skillsScanningImports || this.skillsImporting || this.skillsZipImporting || this.skillsExporting) tasks.push(this.t('dashboard.busy.skills'));
116+
if (this.taskOrchestration && (this.taskOrchestration.loading || this.taskOrchestration.planning || this.taskOrchestration.running || this.taskOrchestration.queueAdding || this.taskOrchestration.queueStarting || this.taskOrchestration.retrying || this.taskOrchestration.selectedRunLoading)) {
117+
tasks.push(this.t('dashboard.busy.tasks'));
118+
}
119+
return tasks.length ? tasks.join(' / ') : this.t('dashboard.busy.idle');
120+
},
121+
inspectorMessageSummary() {
122+
const value = typeof this.message === 'string' ? this.message.trim() : '';
123+
return value || this.t('dashboard.message.none');
124+
},
125+
inspectorSessionSourceLabel() {
126+
if (this.sessionFilterSource === 'codex') return this.t('dashboard.sessionSource.codex');
127+
if (this.sessionFilterSource === 'claude') return this.t('dashboard.sessionSource.claude');
128+
if (this.sessionFilterSource === 'gemini') return this.t('dashboard.sessionSource.gemini');
129+
if (this.sessionFilterSource === 'codebuddy') return this.t('dashboard.sessionSource.codebuddy');
130+
return this.t('dashboard.sessionSource.all');
131+
},
132+
inspectorSessionPathLabel() {
133+
const value = typeof this.sessionPathFilter === 'string' ? this.sessionPathFilter.trim() : '';
134+
return value || this.t('dashboard.sessionPath.all');
135+
},
136+
inspectorSessionQueryLabel() {
137+
if (!this.isSessionQueryEnabled) return this.t('dashboard.sessionQuery.unsupported');
138+
const value = typeof this.sessionQuery === 'string' ? this.sessionQuery.trim() : '';
139+
return value || this.t('dashboard.sessionQuery.unset');
140+
},
141+
inspectorHealthStatus() {
142+
if (this.initError) return this.t('dashboard.healthStatus.failRead');
143+
if (this.loading) return this.t('dashboard.healthStatus.initializing');
144+
return this.t('dashboard.healthStatus.ok');
145+
},
146+
inspectorHealthTone() {
147+
if (this.initError) return 'error';
148+
if (this.loading) return 'warn';
149+
return 'ok';
150+
},
151+
inspectorModelLoadStatus() {
152+
if (this.codexModelsLoading || this.claudeModelsLoading) {
153+
return this.t('dashboard.modelStatus.loading');
154+
}
155+
if (this.modelsSource === 'error' || this.claudeModelsSource === 'error') {
156+
return this.t('dashboard.modelStatus.error');
157+
}
158+
return this.t('dashboard.modelStatus.ok');
159+
},
160+
installTroubleshootingTips() {
161+
const platform = this.resolveInstallPlatform();
162+
if (platform === 'win32') {
163+
return [
164+
this.t('docs.tip.win.1'),
165+
this.t('docs.tip.win.2'),
166+
this.t('docs.tip.win.3')
167+
];
168+
}
169+
return [
170+
this.t('docs.tip.unix.1'),
171+
this.t('docs.tip.unix.2'),
172+
this.t('docs.tip.unix.3')
173+
];
174+
}
175+
};
176+
}

0 commit comments

Comments
 (0)