mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
feat: 添加高可用性模型池支持,优化路径解析功能
This commit is contained in:
@@ -1122,6 +1122,55 @@ select.cli-input {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* ===========================
|
||||
Model Pools (High Availability)
|
||||
=========================== */
|
||||
|
||||
.model-pools-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.pool-type-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.pool-type-header {
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: hsl(var(--muted-foreground));
|
||||
background: hsl(var(--muted) / 0.3);
|
||||
border-bottom: 1px solid hsl(var(--border));
|
||||
}
|
||||
|
||||
.pool-item {
|
||||
padding: 0.75rem;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid hsl(var(--border));
|
||||
transition: background-color 0.15s;
|
||||
}
|
||||
|
||||
.pool-item:hover {
|
||||
background: hsl(var(--muted) / 0.3);
|
||||
}
|
||||
|
||||
.pool-item.selected {
|
||||
background: hsl(var(--primary) / 0.1);
|
||||
border-left: 3px solid hsl(var(--primary));
|
||||
}
|
||||
|
||||
.pool-item .pool-name {
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.pool-item .pool-target {
|
||||
font-size: 0.75rem;
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
/* Responsive adjustments for tabs */
|
||||
@media (max-width: 768px) {
|
||||
.sidebar-tab {
|
||||
|
||||
@@ -2396,7 +2396,7 @@ function deleteModel(providerId, modelId, modelType) {
|
||||
});
|
||||
})
|
||||
.then(function() {
|
||||
return loadApiSettings();
|
||||
return loadApiSettings(true); // Force refresh to get updated data
|
||||
})
|
||||
.then(function() {
|
||||
if (selectedProviderId === providerId) {
|
||||
@@ -4091,23 +4091,21 @@ function renderModelPoolsList() {
|
||||
type === 'llm' ? t('apiSettings.llmPools') :
|
||||
t('apiSettings.rerankerPools');
|
||||
|
||||
html += '<div class="pool-type-group" style="margin-bottom: 1.5rem;">' +
|
||||
'<div class="pool-type-header" style="padding: 0.5rem; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; color: var(--text-secondary); border-bottom: 1px solid var(--border);">' +
|
||||
typeLabel +
|
||||
'</div>';
|
||||
html += '<div class="pool-type-group">' +
|
||||
'<div class="pool-type-header">' + typeLabel + '</div>';
|
||||
|
||||
pools.forEach(function(pool) {
|
||||
var isSelected = selectedPoolId === pool.id;
|
||||
var statusClass = pool.enabled ? 'status-enabled' : 'status-disabled';
|
||||
var statusText = pool.enabled ? t('common.enabled') : t('common.disabled');
|
||||
|
||||
html += '<div class="pool-item' + (isSelected ? ' selected' : '') + '" onclick="selectModelPool(\'' + pool.id + '\')" style="padding: 0.75rem; cursor: pointer; border-bottom: 1px solid var(--border);">' +
|
||||
html += '<div class="pool-item' + (isSelected ? ' selected' : '') + '" onclick="selectModelPool(\'' + pool.id + '\')">' +
|
||||
'<div style="display: flex; justify-content: space-between; align-items: center;">' +
|
||||
'<div style="flex: 1; min-width: 0;">' +
|
||||
'<div style="font-weight: 500; margin-bottom: 0.25rem;">' + escapeHtml(pool.name || pool.targetModel) + '</div>' +
|
||||
'<div style="font-size: 0.75rem; color: var(--text-secondary);">' + escapeHtml(pool.targetModel) + '</div>' +
|
||||
'<div class="pool-name">' + escapeHtml(pool.name || pool.targetModel) + '</div>' +
|
||||
'<div class="pool-target">' + escapeHtml(pool.targetModel) + '</div>' +
|
||||
'</div>' +
|
||||
'<span class="status-badge ' + statusClass + '" style="font-size: 0.7rem; padding: 0.25rem 0.5rem; border-radius: 4px;">' + statusText + '</span>' +
|
||||
'<span class="status-badge ' + statusClass + '">' + statusText + '</span>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
});
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface ValidatePathOptions {
|
||||
|
||||
/**
|
||||
* Resolve a path, handling ~ for home directory
|
||||
* Also handles Windows drive-relative paths (e.g., "D:path" -> "D:\path")
|
||||
* @param inputPath - Path to resolve
|
||||
* @returns Absolute path
|
||||
*/
|
||||
@@ -34,6 +35,17 @@ export function resolvePath(inputPath: string): string {
|
||||
return join(homedir(), inputPath.slice(1));
|
||||
}
|
||||
|
||||
// Handle Windows drive-relative paths (e.g., "D:path" without backslash)
|
||||
// Pattern: single letter followed by colon, then immediately a non-slash character
|
||||
// This converts "D:path" to "D:\path" to make it absolute
|
||||
if (process.platform === 'win32' || /^[a-zA-Z]:/.test(inputPath)) {
|
||||
const driveRelativeMatch = inputPath.match(/^([a-zA-Z]:)([^/\\].*)$/);
|
||||
if (driveRelativeMatch) {
|
||||
// Insert backslash after drive letter
|
||||
inputPath = driveRelativeMatch[1] + '\\' + driveRelativeMatch[2];
|
||||
}
|
||||
}
|
||||
|
||||
return resolve(inputPath);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user