@mengruo/dsh-vision-toolkit 0.0.1 → 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.
- package/README.i18n.yaml +2 -2
- package/README.md +17 -42
- package/README.zh.md +16 -41
- package/assets/logo_eapi_dark.png +0 -0
- package/docs/aihubmix-gemini-vision.i18n.yaml +2 -2
- package/docs/aihubmix-gemini-vision.md +2 -2
- package/docs/aihubmix-gemini-vision.zh.md +2 -2
- package/lib/client.js +246 -68
- package/lib/client.js.map +1 -1
- package/lib/config.js +143 -24
- package/lib/config.js.map +1 -1
- package/lib/evidence-cache.js +14 -0
- package/lib/evidence-cache.js.map +1 -1
- package/lib/image-input-variants.js +39 -27
- package/lib/image-input-variants.js.map +1 -1
- package/lib/runtime-install.js +204 -19
- package/lib/runtime-install.js.map +1 -1
- package/lib/runtime.js +310 -154
- package/lib/runtime.js.map +1 -1
- package/lib/tools.js +1 -0
- package/lib/tools.js.map +1 -1
- package/lib/types/client/index.d.ts +45 -3
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/config.d.ts +53 -0
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/evidence-cache.d.ts.map +1 -1
- package/lib/types/image-input-variants.d.ts +1 -6
- package/lib/types/image-input-variants.d.ts.map +1 -1
- package/lib/types/runtime-install.d.ts +21 -0
- package/lib/types/runtime-install.d.ts.map +1 -1
- package/lib/types/runtime.d.ts +45 -10
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/tools.d.ts.map +1 -1
- package/lib/types/upstream.d.ts +3 -0
- package/lib/types/upstream.d.ts.map +1 -1
- package/lib/types/web.d.ts +8 -0
- package/lib/types/web.d.ts.map +1 -1
- package/lib/upstream.js +11 -6
- package/lib/upstream.js.map +1 -1
- package/lib/web.js +50 -7
- package/lib/web.js.map +1 -1
- package/package.json +1 -1
- package/src/client/index.tsx +331 -88
- package/src/config.ts +210 -28
- package/src/evidence-cache.ts +14 -0
- package/src/image-input-variants.ts +39 -27
- package/src/runtime-install.ts +231 -20
- package/src/runtime.ts +333 -180
- package/src/tools.ts +1 -0
- package/src/upstream.ts +15 -8
- package/src/web.ts +67 -8
package/lib/client.js
CHANGED
|
@@ -87,15 +87,28 @@ const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKi
|
|
|
87
87
|
const BUILT_IN_FREE_VISION_BASE_URL = 'https://vision.anionex.me/v1';
|
|
88
88
|
const BUILT_IN_FREE_VISION_CREDENTIAL = 'ANIONEX_FREE_VISION';
|
|
89
89
|
const BUILT_IN_FREE_VISION_MODEL = 'gemini-3.7-flash';
|
|
90
|
-
const AIHUBMIX_TUTORIAL_URL_EN = 'https://github.com/Anionex/dsh-vision-toolkit/blob/main/docs/aihubmix-gemini-vision.md';
|
|
91
|
-
const AIHUBMIX_TUTORIAL_URL_ZH = 'https://github.com/Anionex/dsh-vision-toolkit/blob/main/docs/aihubmix-gemini-vision.zh.md';
|
|
92
90
|
const en = {
|
|
93
91
|
nav: 'Vision',
|
|
94
92
|
settingsTitle: 'Vision Toolkit',
|
|
95
93
|
settingsIntro: 'Configure the pinned visual engineering runtime, its external vision endpoint, and local safety limits.',
|
|
96
94
|
externalNotice: 'Remote tools send the selected image bytes to the configured external vision API. Local crop, trace, pixel diff, palette, foreground extraction, and HTML rendering do not upload images.',
|
|
97
95
|
provider: 'Vision service',
|
|
98
|
-
providerHint: '
|
|
96
|
+
providerHint: 'Add multiple API endpoints and order them by failover priority. A failed or rate-limited request automatically moves to the next provider; when every provider fails, the request reports an error.',
|
|
97
|
+
providers: 'Vision providers',
|
|
98
|
+
name: 'Label',
|
|
99
|
+
enabled: 'Enabled',
|
|
100
|
+
priority: 'Priority {index}',
|
|
101
|
+
attempts: 'Attempts',
|
|
102
|
+
attemptsHint: 'Total attempts against this provider before failing over to the next one.',
|
|
103
|
+
addProvider: 'Add provider',
|
|
104
|
+
moveUp: 'Move up',
|
|
105
|
+
moveDown: 'Move down',
|
|
106
|
+
removeProvider: 'Remove',
|
|
107
|
+
prioritySort: 'Provider priority',
|
|
108
|
+
prioritySortHint: 'Order the providers by failover priority. The top one is tried first; request order here is the priority order.',
|
|
109
|
+
runtimeCheck: 'Runtime check',
|
|
110
|
+
runtimeCheckHint: 'Checks the local Python environment (with its libraries) and the browser used for HTML screenshots.',
|
|
111
|
+
apiKeyBuiltInFree: 'The built-in free provider needs no user key.',
|
|
99
112
|
aihubmixTutorial: 'Need an AIHubMix key for free Gemini 3.7 Flash vision? Follow the signup guide →',
|
|
100
113
|
baseUrl: 'Base URL',
|
|
101
114
|
apiKey: 'API key',
|
|
@@ -280,7 +293,22 @@ const zh = {
|
|
|
280
293
|
settingsIntro: '在这里设置视觉模型服务、工具运行环境,以及图片和文件的本地访问范围。',
|
|
281
294
|
externalNotice: '使用图像理解、目标定位、界面检测或文字识别等在线功能时,所选图片会发送到下方配置的视觉服务。图片裁剪、轮廓描摹、像素对比、主色提取、前景提取和网页截图均在本机完成,不会上传图片。',
|
|
282
295
|
provider: '在线视觉服务',
|
|
283
|
-
providerHint: '
|
|
296
|
+
providerHint: '添加多个 API 并按故障转移优先级排序;某个 API 失败或限流后自动切换到下一个,全部失败才返回错误。',
|
|
297
|
+
providers: '视觉服务列表',
|
|
298
|
+
name: '名称',
|
|
299
|
+
enabled: '启用',
|
|
300
|
+
priority: '优先级 {index}',
|
|
301
|
+
attempts: '尝试次数',
|
|
302
|
+
attemptsHint: '该服务在故障转移到下一个之前最多尝试的次数。',
|
|
303
|
+
addProvider: '添加服务',
|
|
304
|
+
moveUp: '上移',
|
|
305
|
+
moveDown: '下移',
|
|
306
|
+
removeProvider: '移除',
|
|
307
|
+
prioritySort: '服务优先级',
|
|
308
|
+
prioritySortHint: '按故障转移优先级排列服务;排在最上面的最先尝试,这里的顺序就是优先级顺序。',
|
|
309
|
+
runtimeCheck: '运行检查',
|
|
310
|
+
runtimeCheckHint: '检查本地 Python 环境(含依赖库)和用于网页截图的浏览器。',
|
|
311
|
+
apiKeyBuiltInFree: '内置免费服务无需填写密钥。',
|
|
284
312
|
aihubmixTutorial: '想申请 AIHubMix Key,并用免费 Gemini 3.7 Flash 识图?看这篇图文教程 →',
|
|
285
313
|
baseUrl: 'API 地址',
|
|
286
314
|
apiKey: 'API 密钥',
|
|
@@ -730,7 +758,7 @@ class VisionSettingsController {
|
|
|
730
758
|
return;
|
|
731
759
|
void this.load();
|
|
732
760
|
}
|
|
733
|
-
async save(value, expectedRevision,
|
|
761
|
+
async save(value, expectedRevision, credentials, writeSettings) {
|
|
734
762
|
this.set({ ...this.state, action: 'save', error: undefined, message: undefined });
|
|
735
763
|
let snapshot = this.state.snapshot;
|
|
736
764
|
try {
|
|
@@ -743,7 +771,7 @@ class VisionSettingsController {
|
|
|
743
771
|
}
|
|
744
772
|
if (snapshot === undefined)
|
|
745
773
|
throw new Error('Vision Toolkit Settings are unavailable');
|
|
746
|
-
|
|
774
|
+
for (const credential of credentials) {
|
|
747
775
|
try {
|
|
748
776
|
snapshot = await apiRequest({
|
|
749
777
|
method: 'POST',
|
|
@@ -751,8 +779,8 @@ class VisionSettingsController {
|
|
|
751
779
|
body: JSON.stringify({
|
|
752
780
|
action: 'credential',
|
|
753
781
|
expectedRevision: snapshot.settings.revision,
|
|
754
|
-
ref:
|
|
755
|
-
value:
|
|
782
|
+
ref: credential.ref,
|
|
783
|
+
value: credential.value,
|
|
756
784
|
}),
|
|
757
785
|
});
|
|
758
786
|
}
|
|
@@ -761,6 +789,7 @@ class VisionSettingsController {
|
|
|
761
789
|
status: 'ready',
|
|
762
790
|
snapshot,
|
|
763
791
|
health: this.state.health,
|
|
792
|
+
providerHealth: this.state.providerHealth,
|
|
764
793
|
update: this.state.update,
|
|
765
794
|
restart: this.state.restart,
|
|
766
795
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -772,6 +801,7 @@ class VisionSettingsController {
|
|
|
772
801
|
status: 'ready',
|
|
773
802
|
snapshot,
|
|
774
803
|
health: this.state.health,
|
|
804
|
+
providerHealth: this.state.providerHealth,
|
|
775
805
|
update: this.state.update,
|
|
776
806
|
restart: this.state.restart,
|
|
777
807
|
message: 'saved',
|
|
@@ -788,7 +818,7 @@ class VisionSettingsController {
|
|
|
788
818
|
(0, display_config_ts_1.resetDisplayConfigCache)();
|
|
789
819
|
}
|
|
790
820
|
}
|
|
791
|
-
async runHealth(mode) {
|
|
821
|
+
async runHealth(mode, providerIndex) {
|
|
792
822
|
const testConnection = mode !== 'health';
|
|
793
823
|
const testModel = mode === 'model';
|
|
794
824
|
this.set({ ...this.state, action: mode, error: undefined, message: undefined });
|
|
@@ -796,9 +826,20 @@ class VisionSettingsController {
|
|
|
796
826
|
const health = await apiRequest({
|
|
797
827
|
method: 'POST',
|
|
798
828
|
headers: { 'Content-Type': 'application/json' },
|
|
799
|
-
body: JSON.stringify({
|
|
829
|
+
body: JSON.stringify({
|
|
830
|
+
action: 'health',
|
|
831
|
+
testConnection,
|
|
832
|
+
testModel,
|
|
833
|
+
...(providerIndex === undefined ? {} : { providerIndex }),
|
|
834
|
+
}),
|
|
800
835
|
});
|
|
801
|
-
|
|
836
|
+
if (providerIndex === undefined) {
|
|
837
|
+
this.set({ ...this.state, action: undefined, health });
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
const providerHealth = { ...(this.state.providerHealth ?? {}), [providerIndex]: health };
|
|
841
|
+
this.set({ ...this.state, action: undefined, providerHealth });
|
|
842
|
+
}
|
|
802
843
|
}
|
|
803
844
|
catch (error) {
|
|
804
845
|
this.set({ ...this.state, action: undefined, error: error instanceof Error ? error.message : String(error) });
|
|
@@ -842,19 +883,77 @@ class VisionSettingsController {
|
|
|
842
883
|
}
|
|
843
884
|
}
|
|
844
885
|
exports.VisionSettingsController = VisionSettingsController;
|
|
886
|
+
function randomProviderId() {
|
|
887
|
+
const bytes = new Uint8Array(6);
|
|
888
|
+
if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
|
|
889
|
+
crypto.getRandomValues(bytes);
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
for (let i = 0; i < bytes.length; i++)
|
|
893
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
894
|
+
}
|
|
895
|
+
return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('').toUpperCase();
|
|
896
|
+
}
|
|
897
|
+
function autoCredentialName(id) {
|
|
898
|
+
return `VISION_PROVIDER_${id}`;
|
|
899
|
+
}
|
|
900
|
+
function emptyProviderDraft(defaults) {
|
|
901
|
+
const id = randomProviderId();
|
|
902
|
+
return {
|
|
903
|
+
id,
|
|
904
|
+
name: '',
|
|
905
|
+
enabled: true,
|
|
906
|
+
baseUrl: '',
|
|
907
|
+
credential: autoCredentialName(id),
|
|
908
|
+
model: '',
|
|
909
|
+
protocol: 'openai',
|
|
910
|
+
anthropicThinking: 'omit',
|
|
911
|
+
userAgent: DEFAULT_USER_AGENT,
|
|
912
|
+
timeoutMs: String(defaults.timeoutMs),
|
|
913
|
+
maxImageBytes: String(defaults.maxImageBytes),
|
|
914
|
+
maxImagePixels: String(defaults.maxImagePixels),
|
|
915
|
+
concurrency: String(defaults.concurrency),
|
|
916
|
+
attempts: '3',
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
function providerDraftOf(value, fallback, defaults) {
|
|
920
|
+
const source = value ?? fallback;
|
|
921
|
+
const id = source?.id ?? '';
|
|
922
|
+
return {
|
|
923
|
+
id,
|
|
924
|
+
name: source?.name ?? '',
|
|
925
|
+
enabled: source?.enabled !== false,
|
|
926
|
+
baseUrl: source?.baseUrl ?? '',
|
|
927
|
+
credential: source?.credential ?? autoCredentialName(id),
|
|
928
|
+
model: source?.model ?? '',
|
|
929
|
+
protocol: source?.protocol ?? 'openai',
|
|
930
|
+
anthropicThinking: source?.anthropicThinking ?? 'omit',
|
|
931
|
+
userAgent: source?.userAgent ?? DEFAULT_USER_AGENT,
|
|
932
|
+
timeoutMs: String(source?.timeoutMs ?? defaults.timeoutMs),
|
|
933
|
+
maxImageBytes: String(source?.maxImageBytes ?? defaults.maxImageBytes),
|
|
934
|
+
maxImagePixels: String(source?.maxImagePixels ?? defaults.maxImagePixels),
|
|
935
|
+
concurrency: String(source?.concurrency ?? defaults.concurrency),
|
|
936
|
+
attempts: String(source?.attempts ?? 3),
|
|
937
|
+
};
|
|
938
|
+
}
|
|
845
939
|
function draftOf(value) {
|
|
940
|
+
const globalDefaults = {
|
|
941
|
+
timeoutMs: value.timeoutMs ?? 30000,
|
|
942
|
+
maxImageBytes: value.maxImageBytes ?? 4194304,
|
|
943
|
+
maxImagePixels: value.maxImagePixels ?? 20000000,
|
|
944
|
+
concurrency: value.concurrency ?? 4,
|
|
945
|
+
};
|
|
946
|
+
const configured = value.providers ?? [];
|
|
947
|
+
const providers = configured.length > 0
|
|
948
|
+
? configured.map(entry => providerDraftOf(entry, undefined, globalDefaults))
|
|
949
|
+
: [providerDraftOf(undefined, value.provider, globalDefaults)];
|
|
846
950
|
return {
|
|
847
|
-
|
|
848
|
-
credential: value.provider?.credential ?? BUILT_IN_FREE_VISION_CREDENTIAL,
|
|
849
|
-
model: value.provider?.model ?? BUILT_IN_FREE_VISION_MODEL,
|
|
850
|
-
protocol: value.provider?.protocol ?? 'openai',
|
|
851
|
-
anthropicThinking: value.provider?.anthropicThinking ?? 'omit',
|
|
852
|
-
userAgent: value.provider?.userAgent ?? DEFAULT_USER_AGENT,
|
|
951
|
+
providers,
|
|
853
952
|
language: value.language ?? 'zh',
|
|
854
|
-
timeoutMs: String(
|
|
855
|
-
maxImageBytes: String(
|
|
856
|
-
maxImagePixels: String(
|
|
857
|
-
concurrency: String(
|
|
953
|
+
timeoutMs: String(globalDefaults.timeoutMs),
|
|
954
|
+
maxImageBytes: String(globalDefaults.maxImageBytes),
|
|
955
|
+
maxImagePixels: String(globalDefaults.maxImagePixels),
|
|
956
|
+
concurrency: String(globalDefaults.concurrency),
|
|
858
957
|
runtimeMode: value.runtime?.mode ?? 'managed',
|
|
859
958
|
toolkitPath: value.runtime?.agentVisionToolkitPath ?? '',
|
|
860
959
|
python: value.runtime?.python ?? '',
|
|
@@ -884,15 +983,33 @@ function apiKeyFailure(value, t) {
|
|
|
884
983
|
return undefined;
|
|
885
984
|
}
|
|
886
985
|
function valueOf(draft, t) {
|
|
986
|
+
const providers = draft.providers.map(provider => ({
|
|
987
|
+
...(provider.id.length === 0 ? {} : { id: provider.id }),
|
|
988
|
+
...(provider.name.trim().length === 0 ? {} : { name: provider.name.trim() }),
|
|
989
|
+
...(provider.enabled ? {} : { enabled: false }),
|
|
990
|
+
...(provider.baseUrl.trim().length === 0 ? {} : { baseUrl: provider.baseUrl.trim() }),
|
|
991
|
+
...(provider.credential.trim().length === 0 ? {} : { credential: provider.credential.trim() }),
|
|
992
|
+
...(provider.model.trim().length === 0 ? {} : { model: provider.model.trim() }),
|
|
993
|
+
protocol: provider.protocol,
|
|
994
|
+
anthropicThinking: provider.anthropicThinking,
|
|
995
|
+
...(provider.userAgent.trim() === DEFAULT_USER_AGENT ? {} : { userAgent: provider.userAgent.trim() }),
|
|
996
|
+
...(provider.timeoutMs.trim().length === 0 ? {} : { timeoutMs: positiveInteger(provider.timeoutMs, t('timeout'), t) }),
|
|
997
|
+
...(provider.maxImageBytes.trim().length === 0 ? {} : { maxImageBytes: positiveInteger(provider.maxImageBytes, t('maxBytes'), t) }),
|
|
998
|
+
...(provider.maxImagePixels.trim().length === 0 ? {} : { maxImagePixels: positiveInteger(provider.maxImagePixels, t('maxPixels'), t) }),
|
|
999
|
+
...(provider.concurrency.trim().length === 0 ? {} : { concurrency: positiveInteger(provider.concurrency, t('concurrency'), t) }),
|
|
1000
|
+
...(provider.attempts.trim().length === 0 ? {} : { attempts: positiveInteger(provider.attempts, t('attempts'), t) }),
|
|
1001
|
+
}));
|
|
1002
|
+
const primary = draft.providers[0];
|
|
887
1003
|
return {
|
|
888
1004
|
provider: {
|
|
889
|
-
baseUrl:
|
|
890
|
-
credential:
|
|
891
|
-
model:
|
|
892
|
-
protocol:
|
|
893
|
-
anthropicThinking:
|
|
894
|
-
userAgent:
|
|
1005
|
+
baseUrl: primary?.baseUrl.trim() || BUILT_IN_FREE_VISION_BASE_URL,
|
|
1006
|
+
credential: primary?.credential.trim() || BUILT_IN_FREE_VISION_CREDENTIAL,
|
|
1007
|
+
model: primary?.model.trim() || BUILT_IN_FREE_VISION_MODEL,
|
|
1008
|
+
protocol: primary?.protocol ?? 'openai',
|
|
1009
|
+
anthropicThinking: primary?.anthropicThinking ?? 'omit',
|
|
1010
|
+
userAgent: primary?.userAgent.trim() || DEFAULT_USER_AGENT,
|
|
895
1011
|
},
|
|
1012
|
+
providers,
|
|
896
1013
|
language: draft.language,
|
|
897
1014
|
timeoutMs: positiveInteger(draft.timeoutMs, t('timeout'), t),
|
|
898
1015
|
maxImageBytes: positiveInteger(draft.maxImageBytes, t('maxBytes'), t),
|
|
@@ -922,12 +1039,6 @@ function settingsDraftChanged(draft, saved, t) {
|
|
|
922
1039
|
return true;
|
|
923
1040
|
}
|
|
924
1041
|
}
|
|
925
|
-
function isBuiltInFreeVisionDraft(draft) {
|
|
926
|
-
return draft.baseUrl.trim().replace(/\/+$/, '') === BUILT_IN_FREE_VISION_BASE_URL
|
|
927
|
-
&& draft.credential.trim() === BUILT_IN_FREE_VISION_CREDENTIAL
|
|
928
|
-
&& draft.model.trim() === BUILT_IN_FREE_VISION_MODEL
|
|
929
|
-
&& draft.protocol === 'openai';
|
|
930
|
-
}
|
|
931
1042
|
function Field({ label, children, hint }) {
|
|
932
1043
|
return (0, jsx_runtime_1.jsxs)("label", { className: "dvt-field", children: [(0, jsx_runtime_1.jsx)("span", { children: label }), children, hint === undefined ? null : (0, jsx_runtime_1.jsx)("small", { children: hint })] });
|
|
933
1044
|
}
|
|
@@ -1021,20 +1132,6 @@ function healthDetail(name, detail, t) {
|
|
|
1021
1132
|
return t('healthModelFailed', { detail: match[1] });
|
|
1022
1133
|
return detail;
|
|
1023
1134
|
}
|
|
1024
|
-
function modelTestTag(health, check) {
|
|
1025
|
-
if (!health.modelTested)
|
|
1026
|
-
return { status: 'warning', label: 'modelTestNotRunTag' };
|
|
1027
|
-
if (check.status === 'ok')
|
|
1028
|
-
return { status: 'ok', label: 'modelTestVerifiedTag' };
|
|
1029
|
-
return { status: 'error', label: 'modelTestFailedTag' };
|
|
1030
|
-
}
|
|
1031
|
-
function credentialSource(source, t) {
|
|
1032
|
-
if (source === 'env')
|
|
1033
|
-
return t('sourceEnv');
|
|
1034
|
-
if (source === 'file')
|
|
1035
|
-
return t('sourceFile');
|
|
1036
|
-
return source;
|
|
1037
|
-
}
|
|
1038
1135
|
const UPDATE_REASON_KEYS = {
|
|
1039
1136
|
'profile-not-found': 'updateReasonProfileNotFound',
|
|
1040
1137
|
'not-direct-dependency': 'updateReasonNotDependency',
|
|
@@ -1052,7 +1149,8 @@ function LoadedSettings({ controller, t }) {
|
|
|
1052
1149
|
const state = (0, react_1.useSyncExternalStore)(controller.subscribe, controller.snapshot, controller.snapshot);
|
|
1053
1150
|
const snapshot = state.snapshot;
|
|
1054
1151
|
const [draft, setDraft] = (0, react_1.useState)(undefined);
|
|
1055
|
-
const [
|
|
1152
|
+
const [selectedIndex, setSelectedIndex] = (0, react_1.useState)(0);
|
|
1153
|
+
const [keys, setKeys] = (0, react_1.useState)({});
|
|
1056
1154
|
const [draftError, setDraftError] = (0, react_1.useState)(undefined);
|
|
1057
1155
|
const [copiedCommand, setCopiedCommand] = (0, react_1.useState)(false);
|
|
1058
1156
|
(0, react_1.useEffect)(() => { if (state.status === 'idle')
|
|
@@ -1100,40 +1198,111 @@ function LoadedSettings({ controller, t }) {
|
|
|
1100
1198
|
return (0, jsx_runtime_1.jsxs)("div", { className: "dvt-settings", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: state.error ?? t('runtimeUnavailable') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "outline", onClick: () => { void controller.load(); }, children: t('retry') })] });
|
|
1101
1199
|
}
|
|
1102
1200
|
const update = (key, value) => setDraft(current => current === undefined ? current : { ...current, [key]: value });
|
|
1201
|
+
const updateProvider = (index, key, value) => {
|
|
1202
|
+
setDraft(current => {
|
|
1203
|
+
if (current === undefined)
|
|
1204
|
+
return current;
|
|
1205
|
+
const providers = current.providers.map((provider, i) => i === index ? { ...provider, [key]: value } : provider);
|
|
1206
|
+
return { ...current, providers };
|
|
1207
|
+
});
|
|
1208
|
+
};
|
|
1209
|
+
const addProvider = () => {
|
|
1210
|
+
setDraft(current => current === undefined ? current : {
|
|
1211
|
+
...current,
|
|
1212
|
+
providers: [...current.providers, emptyProviderDraft({
|
|
1213
|
+
timeoutMs: Number(current.timeoutMs) || 30000,
|
|
1214
|
+
maxImageBytes: Number(current.maxImageBytes) || 4194304,
|
|
1215
|
+
maxImagePixels: Number(current.maxImagePixels) || 20000000,
|
|
1216
|
+
concurrency: Number(current.concurrency) || 4,
|
|
1217
|
+
})],
|
|
1218
|
+
});
|
|
1219
|
+
setSelectedIndex(draft.providers.length);
|
|
1220
|
+
};
|
|
1221
|
+
const removeProvider = (index) => {
|
|
1222
|
+
const removed = draft.providers[index];
|
|
1223
|
+
if (removed !== undefined) {
|
|
1224
|
+
// Deleting a provider also deletes its stored credential.
|
|
1225
|
+
void apiRequest({
|
|
1226
|
+
method: 'POST',
|
|
1227
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1228
|
+
body: JSON.stringify({ action: 'delete-credential', ref: removed.credential }),
|
|
1229
|
+
}).catch(() => { });
|
|
1230
|
+
}
|
|
1231
|
+
setDraft(current => current === undefined ? current : { ...current, providers: current.providers.filter((_, i) => i !== index) });
|
|
1232
|
+
setSelectedIndex(prev => {
|
|
1233
|
+
if (index < prev)
|
|
1234
|
+
return prev - 1;
|
|
1235
|
+
if (prev >= draft.providers.length - 1)
|
|
1236
|
+
return Math.max(0, draft.providers.length - 2);
|
|
1237
|
+
return prev;
|
|
1238
|
+
});
|
|
1239
|
+
};
|
|
1240
|
+
const moveProvider = (index, delta) => {
|
|
1241
|
+
setDraft(current => {
|
|
1242
|
+
if (current === undefined)
|
|
1243
|
+
return current;
|
|
1244
|
+
const target = index + delta;
|
|
1245
|
+
if (target < 0 || target >= current.providers.length)
|
|
1246
|
+
return current;
|
|
1247
|
+
const providers = [...current.providers];
|
|
1248
|
+
const [entry] = providers.splice(index, 1);
|
|
1249
|
+
if (entry === undefined)
|
|
1250
|
+
return current;
|
|
1251
|
+
providers.splice(target, 0, entry);
|
|
1252
|
+
return { ...current, providers };
|
|
1253
|
+
});
|
|
1254
|
+
setSelectedIndex(prev => {
|
|
1255
|
+
const target = index + delta;
|
|
1256
|
+
if (prev === index)
|
|
1257
|
+
return target;
|
|
1258
|
+
if (target < index && prev >= target && prev < index)
|
|
1259
|
+
return prev + 1;
|
|
1260
|
+
if (target > index && prev > index && prev <= target)
|
|
1261
|
+
return prev - 1;
|
|
1262
|
+
return prev;
|
|
1263
|
+
});
|
|
1264
|
+
};
|
|
1103
1265
|
const save = () => {
|
|
1104
1266
|
try {
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1267
|
+
for (const value of Object.values(keys)) {
|
|
1268
|
+
const failure = apiKeyFailure(value, t);
|
|
1269
|
+
if (failure !== undefined) {
|
|
1270
|
+
setDraftError(failure);
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1109
1273
|
}
|
|
1110
|
-
const
|
|
1274
|
+
const credentials = Object.entries(keys)
|
|
1275
|
+
.filter(([, value]) => value.trim().length > 0)
|
|
1276
|
+
.map(([ref, value]) => ({ ref, value: value.trim() }));
|
|
1277
|
+
const savedRefs = new Set(credentials.map(credential => credential.ref));
|
|
1111
1278
|
setDraftError(undefined);
|
|
1112
|
-
void controller.save(valueOf(draft, t), snapshot.settings.revision,
|
|
1113
|
-
|
|
1279
|
+
void controller.save(valueOf(draft, t), snapshot.settings.revision, credentials, snapshot.writable).then(saved => {
|
|
1280
|
+
if (saved) {
|
|
1281
|
+
setKeys(current => Object.fromEntries(Object.entries(current).filter(([ref]) => !savedRefs.has(ref))));
|
|
1282
|
+
}
|
|
1283
|
+
});
|
|
1114
1284
|
}
|
|
1115
1285
|
catch (error) {
|
|
1116
1286
|
setDraftError(error instanceof Error ? error.message : String(error));
|
|
1117
1287
|
}
|
|
1118
1288
|
};
|
|
1119
1289
|
const busy = state.action !== undefined;
|
|
1120
|
-
const
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1123
|
-
const
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
const canSave = snapshot.writable || (
|
|
1290
|
+
const selectedProvider = draft.providers[selectedIndex];
|
|
1291
|
+
const providerCredentials = snapshot.credentials ?? [];
|
|
1292
|
+
const selectedCredential = providerCredentials[selectedIndex];
|
|
1293
|
+
const selectedKey = selectedProvider === undefined ? '' : (keys[selectedProvider.credential] ?? '');
|
|
1294
|
+
const selectedKeyLocked = selectedCredential !== undefined && !selectedCredential.writable;
|
|
1295
|
+
const selectedBuiltInFree = selectedCredential?.source === 'built-in-free';
|
|
1296
|
+
const canSave = snapshot.writable || Object.values(keys).some(value => value.trim().length > 0);
|
|
1127
1297
|
const runtimeErrorTitle = snapshot.runtime.ready ? t('runtimeCandidateRejected') : t('runtimeUnavailable');
|
|
1128
1298
|
const pluginUpdate = state.update;
|
|
1129
1299
|
const updateCapability = pluginUpdate ?? snapshot.release.update;
|
|
1130
1300
|
const latestVersion = pluginUpdate?.latestVersion;
|
|
1131
1301
|
const updateReason = updateCapability.reason === undefined ? undefined : t(UPDATE_REASON_KEYS[updateCapability.reason]);
|
|
1132
1302
|
const updateCheckSupported = updateCapability.checkSupported ?? updateCapability.supported;
|
|
1133
|
-
const updateHasUnsavedChanges =
|
|
1303
|
+
const updateHasUnsavedChanges = Object.values(keys).some(value => value.trim().length > 0) || settingsDraftChanged(draft, snapshot.settings.value, t);
|
|
1134
1304
|
const manualUpdateProfile = updateCapability.profile ?? 'web';
|
|
1135
1305
|
const manualUpdateCommand = `dsh plugin --profile ${manualUpdateProfile} add @mengruo/dsh-vision-toolkit@latest --registry=https://registry.npmjs.org/`;
|
|
1136
|
-
const aihubmixTutorialUrl = draft?.language === 'en' ? AIHUBMIX_TUTORIAL_URL_EN : AIHUBMIX_TUTORIAL_URL_ZH;
|
|
1137
1306
|
const copyManualUpdate = () => {
|
|
1138
1307
|
void navigator.clipboard?.writeText(manualUpdateCommand)
|
|
1139
1308
|
.then(() => {
|
|
@@ -1149,10 +1318,18 @@ function LoadedSettings({ controller, t }) {
|
|
|
1149
1318
|
return;
|
|
1150
1319
|
void controller.applyUpdate(latestVersion);
|
|
1151
1320
|
};
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
}) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-update-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('updates') }), (0, jsx_runtime_1.jsx)("p", { children: t('updatesHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${pluginUpdate?.updateAvailable ? 'warning' : pluginUpdate !== undefined && pluginUpdate.supported ? 'ok' : ''}`, children: pluginUpdate?.updateAvailable ? t('updateAvailable') : pluginUpdate !== undefined && pluginUpdate.supported ? t('upToDate') : t('pluginVersion') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-update-grid", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateInstalled') }), (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateLatest') }), (0, jsx_runtime_1.jsx)("strong", { children: latestVersion ?? '—' })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateProfile') }), (0, jsx_runtime_1.jsx)("strong", { children: updateCapability.profile ?? '—' })] })] }), !updateCapability.supported ? (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert warning", children: [(0, jsx_runtime_1.jsx)("strong", { children: t('updateUnsupported') }), (0, jsx_runtime_1.jsx)("span", { children: updateReason })] }) : null, updateCapability.supported && updateHasUnsavedChanges ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('updateSaveFirst') }) : null, pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('updateAvailableDetail', { version: latestVersion }) }) : null, pluginUpdate?.supported && !pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('upToDateDetail', { version: latestVersion }) }) : null, (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('manualUpdateHint') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-manual-update", children: [(0, jsx_runtime_1.jsx)("code", { children: manualUpdateCommand }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", onClick: copyManualUpdate, children: copiedCommand ? t('copied') : t('copy') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-actions", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "outline", disabled: busy || !updateCheckSupported || state.restart !== undefined, onClick: () => { void controller.checkUpdate(); }, children: state.action === 'check-update' ? t('checkingUpdate') : t('checkUpdate') }), pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "primary", disabled: busy || state.restart !== undefined || updateHasUnsavedChanges, onClick: applyUpdate, children: state.action === 'apply-update' ? t('updatingPlugin') : t('updateNow') }) : null] })] }), (0, jsx_runtime_1.jsxs)("details", { className: "dvt-advanced", children: [(0, jsx_runtime_1.jsxs)("summary", { children: [(0, jsx_runtime_1.jsxs)("span", { children: [(0, jsx_runtime_1.jsx)("strong", { children: t('advanced') }), (0, jsx_runtime_1.jsx)("small", { children: t('advancedHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-details-chevron", "aria-hidden": "true", children: "\u2304" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-advanced-body", children: [(0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('provider') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('credential'), hint: t('credentialHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('credential'), disabled: !snapshot.writable || busy, value: draft.credential, onChange: (event) => { update('credential', event.target.value); } }) }), draft.protocol === 'anthropic' ? (0, jsx_runtime_1.jsx)(Field, { label: t('anthropicThinking'), hint: t('anthropicThinkingHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('anthropicThinking'), value: draft.anthropicThinking, onChange: (event) => { update('anthropicThinking', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "omit", children: "omit (widest compatibility)" }), (0, jsx_runtime_1.jsx)("option", { value: "disabled", children: "disabled (model support required)" }), (0, jsx_runtime_1.jsx)("option", { value: "adaptive", children: "adaptive (model support required)" })] }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('userAgent'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { value: draft.userAgent, onChange: (event) => { update('userAgent', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('limits') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('language'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.language, onChange: (event) => { update('language', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "zh", children: "\u4E2D\u6587" }), (0, jsx_runtime_1.jsx)("option", { value: "en", children: "English" })] }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('timeout'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { inputMode: "numeric", value: draft.timeoutMs, onChange: (event) => { update('timeoutMs', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxBytes'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { inputMode: "numeric", value: draft.maxImageBytes, onChange: (event) => { update('maxImageBytes', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxPixels'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { inputMode: "numeric", value: draft.maxImagePixels, onChange: (event) => { update('maxImagePixels', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('concurrency'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { inputMode: "numeric", value: draft.concurrency, onChange: (event) => { update('concurrency', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('imageInput') }) }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.hiddenVariants, disabled: !snapshot.writable || busy, onChange: (event) => { update('hiddenVariants', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('hiddenVariantsLabel') }), (0, jsx_runtime_1.jsx)("small", { children: t('hiddenVariantsHint') })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtime') }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${snapshot.runtime.ready ? 'ok' : 'error'}`, children: snapshot.runtime.ready ? snapshot.runtime.upstream?.source === 'managed' ? t('runtimeManaged') : snapshot.runtime.upstream?.source === 'external' ? t('runtimeExternal') : t('runtimeReady') : t('runtimeUnavailable') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('runtimeMode'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.runtimeMode, onChange: (event) => { update('runtimeMode', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "managed", children: t('runtimeManaged') }), (0, jsx_runtime_1.jsx)("option", { value: "external", children: t('runtimeExternal') })] }) }), draft.runtimeMode === 'external' ? (0, jsx_runtime_1.jsx)(Field, { label: t('toolkitPath'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { value: draft.toolkitPath, onChange: (event) => { update('toolkitPath', event.target.value); } }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('python'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { placeholder: "python3", value: draft.python, onChange: (event) => { update('python', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('allowedDirs'), hint: t('allowedDirsHint'), children: (0, jsx_runtime_1.jsx)("textarea", { rows: 3, value: draft.allowedDirs, onChange: (event) => { update('allowedDirs', event.target.value); } }) })] }), snapshot.runtime.upstream === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-runtime-facts", children: [(0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.path }), (0, jsx_runtime_1.jsxs)("code", { children: [snapshot.runtime.upstream.python, " \u00B7 ", snapshot.runtime.upstream.pythonVersion] }), (0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.runtimeHome })] })] })] })] }), (0, jsx_runtime_1.jsxs)("footer", { className: "dvt-settings-footer", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-kicker", children: t('pluginKind') }), (0, jsx_runtime_1.jsx)("h2", { children: t('settingsTitle') }), (0, jsx_runtime_1.jsx)("p", { children: t('settingsIntro') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-release", children: [(0, jsx_runtime_1.jsxs)("span", { children: [t('pluginVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('upstreamVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.upstreamVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('activeGeneration'), " ", (0, jsx_runtime_1.jsx)("strong", { children: t('activeGenerationValue', { generation: snapshot.runtime.generation }) })] })] })] })] }));
|
|
1321
|
+
const providerHealth = state.providerHealth?.[selectedIndex];
|
|
1322
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-settings", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-alert notice", children: t('externalNotice') }), !snapshot.writable ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('readOnly') }) : null, draftError === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: draftError }), state.error === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: state.error }), state.message === 'saved' ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('saved') }) : null, state.message === 'restarting' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('restarting', { version: state.restart.toVersion }) }) : null, state.message === 'manual-restart-required' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('manualRestartRequired', { version: state.restart.toVersion }) }) : null, snapshot.runtime.lastError === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert error", children: [(0, jsx_runtime_1.jsx)("strong", { children: runtimeErrorTitle }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.runtime.lastError })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-essential", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('providers') }), (0, jsx_runtime_1.jsx)("p", { children: t('providerHint') })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-select", children: [(0, jsx_runtime_1.jsx)("select", { "aria-label": t('providers'), disabled: !snapshot.writable || busy, value: selectedIndex, onChange: (event) => { setSelectedIndex(Number(event.target.value)); }, children: draft.providers.map((provider, index) => ((0, jsx_runtime_1.jsxs)("option", { value: index, children: [index + 1, ". ", provider.name.trim() || provider.model.trim() || t('provider')] }, index))) }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length >= 32, onClick: addProvider, children: t('addProvider') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length <= 1, onClick: () => { removeProvider(selectedIndex); }, children: t('removeProvider') })] }), selectedProvider === undefined ? null : ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-card", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-head", children: [(0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: selectedProvider.enabled, disabled: !snapshot.writable || busy, onChange: (event) => { updateProvider(selectedIndex, 'enabled', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('enabled') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-provider-priority", children: t('priority', { index: selectedIndex + 1 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('name'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('name'), value: selectedProvider.name, onChange: (event) => { updateProvider(selectedIndex, 'name', event.target.value); }, placeholder: selectedProvider.model || t('model') }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('model'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('model'), disabled: !snapshot.writable || busy, value: selectedProvider.model, onChange: (event) => { updateProvider(selectedIndex, 'model', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('baseUrl'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('baseUrl'), disabled: !snapshot.writable || busy, value: selectedProvider.baseUrl, onChange: (event) => { updateProvider(selectedIndex, 'baseUrl', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('protocol'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('protocol'), disabled: !snapshot.writable || busy, value: selectedProvider.protocol, onChange: (event) => { updateProvider(selectedIndex, 'protocol', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "openai", children: "OpenAI Chat Completions" }), (0, jsx_runtime_1.jsx)("option", { value: "anthropic", children: "Anthropic Messages" })] }) }), selectedProvider.protocol === 'anthropic' ? (0, jsx_runtime_1.jsx)(Field, { label: t('anthropicThinking'), hint: t('anthropicThinkingHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('anthropicThinking'), value: selectedProvider.anthropicThinking, onChange: (event) => { updateProvider(selectedIndex, 'anthropicThinking', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "omit", children: "omit (widest compatibility)" }), (0, jsx_runtime_1.jsx)("option", { value: "disabled", children: "disabled (model support required)" }), (0, jsx_runtime_1.jsx)("option", { value: "adaptive", children: "adaptive (model support required)" })] }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('userAgent'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('userAgent'), value: selectedProvider.userAgent, onChange: (event) => { updateProvider(selectedIndex, 'userAgent', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('timeout'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('timeout'), inputMode: "numeric", value: selectedProvider.timeoutMs, onChange: (event) => { updateProvider(selectedIndex, 'timeoutMs', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxBytes'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxBytes'), inputMode: "numeric", value: selectedProvider.maxImageBytes, onChange: (event) => { updateProvider(selectedIndex, 'maxImageBytes', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxPixels'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxPixels'), inputMode: "numeric", value: selectedProvider.maxImagePixels, onChange: (event) => { updateProvider(selectedIndex, 'maxImagePixels', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('concurrency'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('concurrency'), inputMode: "numeric", value: selectedProvider.concurrency, onChange: (event) => { updateProvider(selectedIndex, 'concurrency', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('attempts'), hint: t('attemptsHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('attempts'), inputMode: "numeric", value: selectedProvider.attempts, onChange: (event) => { updateProvider(selectedIndex, 'attempts', event.target.value); } }) })] }), (0, jsx_runtime_1.jsx)(Field, { label: t('apiKey'), hint: selectedBuiltInFree ? t('apiKeyBuiltInFree') : selectedKeyLocked ? t('apiKeyLocked') : t('apiKeyHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('apiKey'), type: "password", autoComplete: "new-password", disabled: busy || selectedKeyLocked || selectedBuiltInFree, placeholder: selectedCredential?.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: selectedKey, onChange: (event) => { setKeys(current => ({ ...current, [selectedProvider.credential]: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-tests", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('connection', selectedIndex); }, children: state.action === 'connection' ? t('testing') : t('testConnection') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('model', selectedIndex); }, children: state.action === 'model' ? t('testingModel') : t('testModel') })] }), providerHealth === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: ['service', 'model'].map(name => {
|
|
1323
|
+
const check = providerHealth.checks[name];
|
|
1324
|
+
if (check === undefined)
|
|
1325
|
+
return null;
|
|
1326
|
+
return (0, jsx_runtime_1.jsxs)("div", { "data-status": check.status, children: [(0, jsx_runtime_1.jsx)("span", { children: t(HEALTH_NAME_KEYS[name] ?? 'health') }), (0, jsx_runtime_1.jsx)("strong", { children: t(HEALTH_STATUS_KEYS[check.status]) }), (0, jsx_runtime_1.jsx)("p", { children: healthDetail(name, check.detail, t) })] }, name);
|
|
1327
|
+
}) })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-save-row", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "primary", disabled: !canSave || busy, onClick: save, children: state.action === 'save' ? t('saving') : t('save') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "outline", disabled: busy, onClick: () => { void controller.load(); }, children: t('reload') })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('prioritySort') }), (0, jsx_runtime_1.jsx)("p", { children: t('prioritySortHint') })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-sorter", children: draft.providers.map((provider, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-sorter-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-sorter-index", children: index + 1 }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-sorter-name", children: provider.name.trim() || provider.model.trim() || t('provider') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": t('moveUp'), title: t('moveUp'), disabled: !snapshot.writable || busy || index === 0, onClick: () => { moveProvider(index, -1); }, children: "\u2191" }), (0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": t('moveDown'), title: t('moveDown'), disabled: !snapshot.writable || busy || index === draft.providers.length - 1, onClick: () => { moveProvider(index, 1); }, children: "\u2193" })] })] }, index))) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-update-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtimeCheck') }), (0, jsx_runtime_1.jsx)("p", { children: t('runtimeCheckHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-actions", children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('health'); }, children: state.action === 'health' ? t('testing') : t('runHealth') }) })] }), state.health === undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('notTested') }) : (0, jsx_runtime_1.jsx)("div", { className: "dvt-health-grid", children: ['python', 'dependencies', 'chrome'].map(name => {
|
|
1328
|
+
const check = state.health?.checks[name];
|
|
1329
|
+
if (check === undefined)
|
|
1330
|
+
return null;
|
|
1331
|
+
return (0, jsx_runtime_1.jsxs)("div", { "data-status": check.status, children: [(0, jsx_runtime_1.jsx)("span", { children: t(HEALTH_NAME_KEYS[name] ?? 'health') }), (0, jsx_runtime_1.jsx)("strong", { children: t(HEALTH_STATUS_KEYS[check.status]) }), (0, jsx_runtime_1.jsx)("p", { children: healthDetail(name, check.detail, t) })] }, name);
|
|
1332
|
+
}) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('updates') }), (0, jsx_runtime_1.jsx)("p", { children: t('updatesHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${pluginUpdate?.updateAvailable ? 'warning' : pluginUpdate !== undefined && pluginUpdate.supported ? 'ok' : ''}`, children: pluginUpdate?.updateAvailable ? t('updateAvailable') : pluginUpdate !== undefined && pluginUpdate.supported ? t('upToDate') : t('pluginVersion') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-update-grid", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateInstalled') }), (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateLatest') }), (0, jsx_runtime_1.jsx)("strong", { children: latestVersion ?? '—' })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateProfile') }), (0, jsx_runtime_1.jsx)("strong", { children: updateCapability.profile ?? '—' })] })] }), !updateCapability.supported ? (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert warning", children: [(0, jsx_runtime_1.jsx)("strong", { children: t('updateUnsupported') }), (0, jsx_runtime_1.jsx)("span", { children: updateReason })] }) : null, updateCapability.supported && updateHasUnsavedChanges ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('updateSaveFirst') }) : null, pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('updateAvailableDetail', { version: latestVersion }) }) : null, pluginUpdate?.supported && !pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('upToDateDetail', { version: latestVersion }) }) : null, (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('manualUpdateHint') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-manual-update", children: [(0, jsx_runtime_1.jsx)("code", { children: manualUpdateCommand }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", onClick: copyManualUpdate, children: copiedCommand ? t('copied') : t('copy') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-actions", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "outline", disabled: busy || !updateCheckSupported || state.restart !== undefined, onClick: () => { void controller.checkUpdate(); }, children: state.action === 'check-update' ? t('checkingUpdate') : t('checkUpdate') }), pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "primary", disabled: busy || state.restart !== undefined || updateHasUnsavedChanges, onClick: applyUpdate, children: state.action === 'apply-update' ? t('updatingPlugin') : t('updateNow') }) : null] })] }), (0, jsx_runtime_1.jsxs)("details", { className: "dvt-advanced", children: [(0, jsx_runtime_1.jsxs)("summary", { children: [(0, jsx_runtime_1.jsxs)("span", { children: [(0, jsx_runtime_1.jsx)("strong", { children: t('advanced') }), (0, jsx_runtime_1.jsx)("small", { children: t('advancedHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-details-chevron", "aria-hidden": "true", children: "\u2304" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-advanced-body", children: [(0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('language') }) }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-form-grid", children: (0, jsx_runtime_1.jsx)(Field, { label: t('language'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.language, onChange: (event) => { update('language', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "zh", children: "\u4E2D\u6587" }), (0, jsx_runtime_1.jsx)("option", { value: "en", children: "English" })] }) }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('imageInput') }) }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.hiddenVariants, disabled: !snapshot.writable || busy, onChange: (event) => { update('hiddenVariants', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('hiddenVariantsLabel') }), (0, jsx_runtime_1.jsx)("small", { children: t('hiddenVariantsHint') })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtime') }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${snapshot.runtime.ready ? 'ok' : 'error'}`, children: snapshot.runtime.ready ? snapshot.runtime.upstream?.source === 'managed' ? t('runtimeManaged') : snapshot.runtime.upstream?.source === 'external' ? t('runtimeExternal') : t('runtimeReady') : t('runtimeUnavailable') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('runtimeMode'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.runtimeMode, onChange: (event) => { update('runtimeMode', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "managed", children: t('runtimeManaged') }), (0, jsx_runtime_1.jsx)("option", { value: "external", children: t('runtimeExternal') })] }) }), draft.runtimeMode === 'external' ? (0, jsx_runtime_1.jsx)(Field, { label: t('toolkitPath'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { value: draft.toolkitPath, onChange: (event) => { update('toolkitPath', event.target.value); } }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('python'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { placeholder: "python3", value: draft.python, onChange: (event) => { update('python', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('allowedDirs'), hint: t('allowedDirsHint'), children: (0, jsx_runtime_1.jsx)("textarea", { rows: 3, value: draft.allowedDirs, onChange: (event) => { update('allowedDirs', event.target.value); } }) })] }), snapshot.runtime.upstream === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-runtime-facts", children: [(0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.path }), (0, jsx_runtime_1.jsxs)("code", { children: [snapshot.runtime.upstream.python, " \u00B7 ", snapshot.runtime.upstream.pythonVersion] }), (0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.runtimeHome })] })] })] })] }), (0, jsx_runtime_1.jsxs)("footer", { className: "dvt-settings-footer", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-kicker", children: t('pluginKind') }), (0, jsx_runtime_1.jsx)("h2", { children: t('settingsTitle') }), (0, jsx_runtime_1.jsx)("p", { children: t('settingsIntro') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-release", children: [(0, jsx_runtime_1.jsxs)("span", { children: [t('pluginVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('upstreamVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.upstreamVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('activeGeneration'), " ", (0, jsx_runtime_1.jsx)("strong", { children: t('activeGenerationValue', { generation: snapshot.runtime.generation }) })] })] })] })] }));
|
|
1156
1333
|
}
|
|
1157
1334
|
const CSS = `
|
|
1158
1335
|
.dvt-tool{margin:4px 0;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-bg-layer-1);overflow:hidden;box-shadow:var(--dsw-shadow-lv1)}
|
|
@@ -1163,6 +1340,7 @@ const CSS = `
|
|
|
1163
1340
|
.dvt-settings-footer{margin-top:8px;padding:20px 2px 4px;border-top:1px solid var(--dsw-alias-border-l1);opacity:.82}.dvt-settings-footer h2{font-size:18px;letter-spacing:-.015em;margin:3px 0 5px}.dvt-settings-footer p{font-size:11px;line-height:1.5}.dvt-release{min-width:220px}.dvt-release span{white-space:nowrap}.dvt-essential{border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 30%,var(--dsw-alias-border-l1));box-shadow:var(--dsw-shadow-lv1),0 0 0 3px color-mix(in srgb,var(--dsw-alias-state-business-primary) 5%,transparent)}.dvt-advanced{border:1px solid var(--dsw-alias-border-l1);border-radius:14px;background:var(--dsw-alias-bg-layer-1);overflow:hidden}.dvt-advanced>summary{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:14px 15px;cursor:pointer;list-style:none}.dvt-advanced>summary::-webkit-details-marker{display:none}.dvt-advanced>summary>span:first-child{display:grid;gap:3px}.dvt-advanced>summary strong{font-size:13px}.dvt-advanced>summary small{font-size:10px;line-height:1.45;color:var(--dsw-alias-label-secondary);font-weight:400}.dvt-details-chevron{font-size:15px;opacity:.55;transition:transform .16s ease}.dvt-advanced[open] .dvt-details-chevron{transform:rotate(180deg)}.dvt-advanced-body{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;padding:0 12px 12px}.dvt-advanced-body>.dvt-panel{box-shadow:none}
|
|
1164
1341
|
.dvt-health-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}.dvt-health-grid>div{padding:9px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-2);border-left:3px solid var(--dsw-alias-border-l4)}.dvt-health-grid>div[data-status=ok]{border-left-color:var(--dsw-alias-state-success-primary)}.dvt-health-grid>div[data-status=warning],.dvt-health-grid>div[data-status=not_tested]{border-left-color:var(--dsw-alias-state-warn-primary)}.dvt-health-grid>div[data-status=error]{border-left-color:var(--dsw-alias-state-error-primary)}.dvt-health-grid span{font-size:10px;text-transform:capitalize}.dvt-health-grid strong{float:right;font-size:9px;text-transform:uppercase;color:var(--dsw-alias-label-secondary)}.dvt-health-test-tag{display:inline-flex;margin-left:6px;padding:1px 6px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);font-size:9px;font-style:normal;font-weight:600;color:var(--dsw-alias-label-secondary)}.dvt-health-test-tag[data-status=ok]{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary)}.dvt-health-test-tag[data-status=warning]{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 12%,transparent);color:var(--dsw-alias-state-warn-label)}.dvt-health-test-tag[data-status=error]{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent);color:var(--dsw-alias-state-error-primary)}.dvt-health-grid p{clear:both;margin:5px 0 0;font-size:10px;line-height:1.4;color:var(--dsw-alias-label-secondary)}.dvt-loading{padding:24px;border-radius:12px;background:var(--dsw-alias-bg-layer-2);font-size:12px;color:var(--dsw-alias-label-secondary)}
|
|
1165
1342
|
.dvt-paste-dock{box-sizing:border-box;width:calc(100% - 32px);max-width:var(--dsh-composer-card-max-width,960px);margin:0 auto;display:flex;flex-wrap:wrap;gap:6px;padding:0 2px 6px}.dvt-paste-chip{max-width:100%;height:32px;box-sizing:border-box;display:flex;align-items:center;gap:7px;padding:0 6px 0 10px;border:1px solid var(--dsw-alias-border-l1);border-radius:9px;background:var(--dsw-specific-tip);font-size:12px}.dvt-paste-chip[data-status=copying]{border-color:var(--dsw-alias-state-business-primary)}.dvt-paste-chip[data-status=error]{border-color:var(--dsw-alias-state-error-primary)}.dvt-paste-name{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvt-paste-detail{color:var(--dsw-alias-label-caption);max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvt-paste-chip[data-status=error] .dvt-paste-detail{color:var(--dsw-alias-state-error-primary)}.dvt-paste-chip button{width:20px;height:20px;display:grid;place-items:center;border:0;border-radius:50%;padding:0;background:transparent;color:var(--dsw-alias-label-caption);font:inherit;font-size:16px;cursor:pointer}.dvt-paste-chip button:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.dvt-paste-chip button:disabled{opacity:.4;cursor:default}
|
|
1343
|
+
.dvt-provider-card{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:9px 10px;display:grid;gap:8px;background:var(--dsw-alias-bg-layer-2)}.dvt-provider-head{display:flex;align-items:center;gap:10px}.dvt-provider-priority{margin-left:auto;font-size:11px;color:var(--dsw-alias-label-secondary);white-space:nowrap}.dvt-provider-actions{display:flex;gap:4px}.dvt-provider-actions button{width:26px;height:26px;display:grid;place-items:center;border:1px solid var(--dsw-alias-border-l1);border-radius:7px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer;font-size:14px;line-height:1}.dvt-provider-actions button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dvt-provider-actions button:disabled{opacity:.35;cursor:default}.dvt-provider-select{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dvt-provider-select select{flex:1;min-width:180px;height:36px;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);border-radius:9px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;padding:0 10px}.dvt-provider-tests{display:flex;align-items:center;gap:7px;flex-wrap:wrap}.dvt-provider-test-result{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}.dvt-provider-test-result>div{padding:9px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-2);border-left:3px solid var(--dsw-alias-border-l4)}.dvt-provider-test-result>div[data-status=ok]{border-left-color:var(--dsw-alias-state-success-primary)}.dvt-provider-test-result>div[data-status=warning],.dvt-provider-test-result>div[data-status=not_tested]{border-left-color:var(--dsw-alias-state-warn-primary)}.dvt-provider-test-result>div[data-status=error]{border-left-color:var(--dsw-alias-state-error-primary)}.dvt-provider-test-result span{font-size:10px;text-transform:capitalize}.dvt-provider-test-result strong{float:right;font-size:9px;text-transform:uppercase;color:var(--dsw-alias-label-secondary)}.dvt-provider-test-result p{clear:both;margin:5px 0 0;font-size:10px;line-height:1.4;color:var(--dsw-alias-label-secondary)}.dvt-sorter{display:grid;gap:6px}.dvt-sorter-row{display:flex;align-items:center;gap:10px;padding:6px 8px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-2)}.dvt-sorter-index{flex:none;width:24px;height:24px;display:grid;place-items:center;border-radius:6px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-size:11px;font-weight:700}.dvt-sorter-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}
|
|
1166
1344
|
@media(max-width:720px){.dvt-settings-footer{display:grid}.dvt-release{width:auto}.dvt-form-grid,.dvt-update-grid{grid-template-columns:1fr}.dvt-metrics{grid-template-columns:1fr}.dvt-artifact-meta{align-items:flex-start;flex-direction:column}.dvt-panel-title{flex-direction:column}}
|
|
1167
1345
|
`;
|
|
1168
1346
|
function installStyles() {
|