@klarkxy/dsh-web-search-manager 0.2.4 → 0.3.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.md +14 -8
- package/docs/README.zh-CN.md +13 -7
- package/lib/client.inner.cjs +437 -423
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +437 -423
- package/lib/contracts.d.ts +7 -1
- package/lib/contracts.js +6 -1
- package/lib/contracts.js.map +1 -1
- package/lib/index.d.ts +7 -2
- package/lib/index.js +287 -62
- package/lib/index.js.map +1 -1
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +15 -12
package/lib/client.inner.cjs
CHANGED
|
@@ -405,6 +405,29 @@ ${scope} {
|
|
|
405
405
|
& .dsh-ui-select:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }
|
|
406
406
|
& .dsh-ui-select[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }
|
|
407
407
|
|
|
408
|
+
/* --- Native textarea. The primitives ship no textarea either, so a settings
|
|
409
|
+
* prompt keeps the platform element and the same field shell as the select:
|
|
410
|
+
* 0.5px l4, radius-md, layer-3, 13/1.5 type. It grows vertically instead of
|
|
411
|
+
* locking to the select's 34px row. --- */
|
|
412
|
+
& .dsh-ui-textarea {
|
|
413
|
+
box-sizing: border-box;
|
|
414
|
+
width: 100%;
|
|
415
|
+
min-width: 0;
|
|
416
|
+
resize: vertical;
|
|
417
|
+
padding: 8px 12px;
|
|
418
|
+
border: 0.5px solid var(--dsw-alias-border-l4);
|
|
419
|
+
border-radius: var(--dsw-radius-md);
|
|
420
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
421
|
+
font: inherit;
|
|
422
|
+
font-size: 13px;
|
|
423
|
+
line-height: 1.5;
|
|
424
|
+
color: var(--dsw-alias-label-primary);
|
|
425
|
+
}
|
|
426
|
+
& .dsh-ui-textarea:focus-visible { outline: none; border-color: var(--dsw-alias-state-business-primary); }
|
|
427
|
+
& .dsh-ui-textarea:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }
|
|
428
|
+
& .dsh-ui-textarea::placeholder { color: var(--dsw-alias-label-dimmed); }
|
|
429
|
+
& .dsh-ui-textarea[aria-invalid='true'] { border-color: var(--dsw-alias-state-error-primary); }
|
|
430
|
+
|
|
408
431
|
/* Long panels scroll inside themselves instead of growing the host page. */
|
|
409
432
|
& .dsh-ui-panel { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
|
|
410
433
|
& .dsh-ui-panel-wide { max-width: 100%; }
|
|
@@ -444,8 +467,8 @@ function createPluginReadGate(now = Date.now) {
|
|
|
444
467
|
//#endregion
|
|
445
468
|
//#region src/contracts.ts
|
|
446
469
|
const WEB_SEARCH_RPC_CHANNEL = "/web-search-manager";
|
|
447
|
-
function
|
|
448
|
-
return
|
|
470
|
+
function providerKey(kind, id) {
|
|
471
|
+
return `${kind}:${id}`;
|
|
449
472
|
}
|
|
450
473
|
function safeConfigurationUrl(value) {
|
|
451
474
|
if (typeof value !== "string" || !value || /[\u0000-\u0020\\]/.test(value)) return;
|
|
@@ -462,6 +485,21 @@ function safeConfigurationUrl(value) {
|
|
|
462
485
|
//#region src/provider-info.ts
|
|
463
486
|
const PROVIDER_PRICING_CHECKED = "2026-09-21";
|
|
464
487
|
const providerInfo = {
|
|
488
|
+
perplexity: {
|
|
489
|
+
description: "通过 Perplexity Search API 获取网页来源,不生成回答。",
|
|
490
|
+
pricing: "按 Search API 请求计费;实际价格与额度以官方账户为准。",
|
|
491
|
+
pricingUrl: "https://docs.perplexity.ai/docs/getting-started/pricing"
|
|
492
|
+
},
|
|
493
|
+
you: {
|
|
494
|
+
description: "通过 You.com 获取网页与新闻结果,不请求额外全文提取。",
|
|
495
|
+
pricing: "按 Web Search API 请求计费;实际价格与额度以官方账户为准。",
|
|
496
|
+
pricingUrl: "https://you.com/docs/administration/billing"
|
|
497
|
+
},
|
|
498
|
+
"firecrawl-fetch": {
|
|
499
|
+
description: "读取网页 Markdown;与 Firecrawl 搜索共用 Key。",
|
|
500
|
+
pricing: "网页读取使用 Firecrawl 积分,与搜索分别计费;实际消耗以官方账户为准。",
|
|
501
|
+
pricingUrl: "https://www.firecrawl.dev/pricing"
|
|
502
|
+
},
|
|
465
503
|
ddg: {
|
|
466
504
|
description: "搜索 DuckDuckGo 公开网页,无需注册或 API Key。",
|
|
467
505
|
pricing: "免费使用,不产生搜索 API 费用。",
|
|
@@ -504,6 +542,18 @@ const providerInfo = {
|
|
|
504
542
|
}
|
|
505
543
|
};
|
|
506
544
|
const englishInfo = {
|
|
545
|
+
perplexity: {
|
|
546
|
+
description: "Get web sources through the Perplexity Search API without generating an answer.",
|
|
547
|
+
pricing: "Charged per Search API request; current prices and credits depend on your official account."
|
|
548
|
+
},
|
|
549
|
+
you: {
|
|
550
|
+
description: "Get web and news results through You.com without requesting extra full-page extraction.",
|
|
551
|
+
pricing: "Charged per Web Search API request; current prices and credits depend on your official account."
|
|
552
|
+
},
|
|
553
|
+
"firecrawl-fetch": {
|
|
554
|
+
description: "Read page Markdown using the same key as Firecrawl search.",
|
|
555
|
+
pricing: "Page reads use Firecrawl credits and are charged separately from search; your official account determines usage."
|
|
556
|
+
},
|
|
507
557
|
ddg: {
|
|
508
558
|
description: "Search public DuckDuckGo pages without registration or an API key.",
|
|
509
559
|
pricing: "Free to use; no search API fees."
|
|
@@ -538,6 +588,9 @@ const englishInfo = {
|
|
|
538
588
|
}
|
|
539
589
|
};
|
|
540
590
|
const bundledDescriptions = {
|
|
591
|
+
perplexity: ["Search API;返回网页来源,不生成回答。", "Search API returning web sources without generating an answer."],
|
|
592
|
+
you: ["网页与新闻搜索;不额外提取全文。", "Web and news search without extra full-page extraction."],
|
|
593
|
+
"firecrawl-fetch": ["读取网页 Markdown;与 Firecrawl 搜索共用 Key。", "Read page Markdown using the same key as Firecrawl search."],
|
|
541
594
|
ddg: ["无需注册。默认后端。", "No registration required. Default backend."],
|
|
542
595
|
"deepseek-official": ["使用已配置的 DeepSeek API Key,可能产生额外搜索费用。", "Uses the configured DeepSeek API key; additional search fees may apply."],
|
|
543
596
|
exa: ["独立 Search API。", "Independent Search API."],
|
|
@@ -557,6 +610,7 @@ function providerDisplayLabel(provider, locale) {
|
|
|
557
610
|
}
|
|
558
611
|
function bundledCatalogId(provider) {
|
|
559
612
|
if (!(typeof provider.configurationOwned === "boolean" ? provider.configurationOwned : !provider.configurationOwner || provider.configurationOwner === "@klarkxy/dsh-web-search-manager")) return;
|
|
613
|
+
if (provider.kind === "fetch" && provider.id === "firecrawl") return "firecrawl-fetch";
|
|
560
614
|
return provider.id === "deepseek-managed" ? "deepseek-official" : provider.id;
|
|
561
615
|
}
|
|
562
616
|
function missingPricing(locale) {
|
|
@@ -565,7 +619,11 @@ function missingPricing(locale) {
|
|
|
565
619
|
function usesBundledPricing(provider) {
|
|
566
620
|
if (provider.pricing?.trim()) return false;
|
|
567
621
|
const catalogId = bundledCatalogId(provider);
|
|
568
|
-
return Boolean(catalogId &&
|
|
622
|
+
return Boolean(catalogId && ![
|
|
623
|
+
"perplexity",
|
|
624
|
+
"you",
|
|
625
|
+
"firecrawl-fetch"
|
|
626
|
+
].includes(catalogId) && Object.hasOwn(providerInfo, catalogId));
|
|
569
627
|
}
|
|
570
628
|
function searchProviderInfo(provider, locale = "zh") {
|
|
571
629
|
const catalogId = bundledCatalogId(provider);
|
|
@@ -662,52 +720,61 @@ function bindStatusRefresh(options) {
|
|
|
662
720
|
};
|
|
663
721
|
}
|
|
664
722
|
function isProviderOn(status, provider) {
|
|
665
|
-
if (provider.kind === "fetch") return status.fetchActive && status
|
|
723
|
+
if (provider.kind === "fetch") return status.fetchActive && selectedBackend(status, "fetch")?.id === provider.id;
|
|
666
724
|
return status.searchActive && selectedSearchBackend(status)?.id === provider.id;
|
|
667
725
|
}
|
|
668
726
|
function dormantSearchPlaceholder(id) {
|
|
727
|
+
return dormantPlaceholder(id, "search");
|
|
728
|
+
}
|
|
729
|
+
function dormantPlaceholder(id, kind) {
|
|
669
730
|
return {
|
|
670
731
|
id,
|
|
671
732
|
label: id,
|
|
672
733
|
description: "",
|
|
673
734
|
billing: "unknown",
|
|
674
|
-
kind
|
|
735
|
+
kind,
|
|
675
736
|
configured: false,
|
|
676
737
|
calls: 0,
|
|
677
738
|
failures: 0,
|
|
678
739
|
configurationOwned: false
|
|
679
740
|
};
|
|
680
741
|
}
|
|
742
|
+
function isRegistered(status, id, kind) {
|
|
743
|
+
return status.providers.some((provider) => provider.kind === kind && provider.id === id);
|
|
744
|
+
}
|
|
681
745
|
function isRegisteredSearch(status, id) {
|
|
682
|
-
return status
|
|
746
|
+
return isRegistered(status, id, "search");
|
|
683
747
|
}
|
|
684
|
-
function
|
|
685
|
-
|
|
748
|
+
function providerOrder(settings, kind) {
|
|
749
|
+
return kind === "search" ? settings.searchOrder : settings.fetchOrder;
|
|
750
|
+
}
|
|
751
|
+
function catalogBackends(status, kind) {
|
|
752
|
+
const byId = new Map(status.providers.filter((provider) => provider.kind === kind).map((provider) => [provider.id, provider]));
|
|
686
753
|
const rows = [];
|
|
687
754
|
const seen = /* @__PURE__ */ new Set();
|
|
688
|
-
for (const id of status.settings
|
|
755
|
+
for (const id of providerOrder(status.settings, kind)) {
|
|
689
756
|
if (!id || seen.has(id)) continue;
|
|
690
757
|
seen.add(id);
|
|
691
|
-
rows.push(byId.get(id) ??
|
|
692
|
-
}
|
|
693
|
-
for (const provider of status.providers) {
|
|
694
|
-
if (provider.kind !== "search" || seen.has(provider.id)) continue;
|
|
695
|
-
rows.push(provider);
|
|
758
|
+
rows.push(byId.get(id) ?? dormantPlaceholder(id, kind));
|
|
696
759
|
}
|
|
760
|
+
for (const provider of byId.values()) if (!seen.has(provider.id)) rows.push(provider);
|
|
697
761
|
return rows;
|
|
698
762
|
}
|
|
763
|
+
function catalogSearchBackends(status) {
|
|
764
|
+
return catalogBackends(status, "search");
|
|
765
|
+
}
|
|
699
766
|
function searchBackends(status) {
|
|
700
|
-
|
|
701
|
-
|
|
767
|
+
return catalogSearchBackends(status).filter((provider) => status.settings.searchOrder.includes(provider.id));
|
|
768
|
+
}
|
|
769
|
+
function selectedBackend(status, kind) {
|
|
770
|
+
return providerOrder(status.settings, kind).flatMap((id) => status.providers.find((provider) => provider.kind === kind && provider.id === id) ?? []).find((provider) => provider.configured);
|
|
702
771
|
}
|
|
703
772
|
function selectedSearchBackend(status) {
|
|
704
|
-
|
|
705
|
-
const id = pickActiveSearch(backends.map((provider) => provider.id), (id) => Boolean(backends.find((provider) => provider.id === id)?.configured));
|
|
706
|
-
return backends.find((provider) => provider.id === id);
|
|
773
|
+
return selectedBackend(status, "search");
|
|
707
774
|
}
|
|
708
|
-
function droppedDormantIds(settings, order, providers) {
|
|
709
|
-
const known = new Set(providers.filter((provider) => provider.kind ===
|
|
710
|
-
return [...new Set(settings.
|
|
775
|
+
function droppedDormantIds(settings, order, providers, kind = "search") {
|
|
776
|
+
const known = new Set(providers.filter((provider) => provider.kind === kind).map((provider) => provider.id));
|
|
777
|
+
return [...new Set(providerOrder(settings, kind).filter((id) => id && !known.has(id) && !order.includes(id)))];
|
|
711
778
|
}
|
|
712
779
|
function configurationAccess(provider) {
|
|
713
780
|
if (ownsProviderConfiguration(provider)) return { kind: "owned" };
|
|
@@ -788,8 +855,9 @@ function ConfirmButton(props) {
|
|
|
788
855
|
const copy = {
|
|
789
856
|
zh: {
|
|
790
857
|
tabsLabel: "网络搜索设置",
|
|
791
|
-
|
|
792
|
-
|
|
858
|
+
tabSearch: "web-search",
|
|
859
|
+
tabFetch: "web-fetch",
|
|
860
|
+
tabLimits: "设置",
|
|
793
861
|
loading: "正在读取设置…",
|
|
794
862
|
loadFailed: "读取设置失败:",
|
|
795
863
|
reconnect: "重新连接",
|
|
@@ -830,13 +898,16 @@ const copy = {
|
|
|
830
898
|
maxFetchChars: "正文字符上限",
|
|
831
899
|
fetchTitle: "网页读取",
|
|
832
900
|
fetchProvider: "读取服务",
|
|
901
|
+
fetchBackends: "读取后端",
|
|
902
|
+
needFetchBackend: "需选择并配置读取服务。",
|
|
833
903
|
ownerSettings: "配置入口:",
|
|
834
904
|
unknownOwner: "请在服务所属插件中配置"
|
|
835
905
|
},
|
|
836
906
|
en: {
|
|
837
907
|
tabsLabel: "Web search settings",
|
|
838
|
-
|
|
839
|
-
|
|
908
|
+
tabSearch: "web-search",
|
|
909
|
+
tabFetch: "web-fetch",
|
|
910
|
+
tabLimits: "Settings",
|
|
840
911
|
loading: "Loading settings…",
|
|
841
912
|
loadFailed: "Could not load settings: ",
|
|
842
913
|
reconnect: "Reconnect",
|
|
@@ -877,6 +948,8 @@ const copy = {
|
|
|
877
948
|
maxFetchChars: "Max text chars",
|
|
878
949
|
fetchTitle: "Read web pages",
|
|
879
950
|
fetchProvider: "Fetch service",
|
|
951
|
+
fetchBackends: "Fetch backends",
|
|
952
|
+
needFetchBackend: "Choose and configure a fetch service.",
|
|
880
953
|
ownerSettings: "Configure in: ",
|
|
881
954
|
unknownOwner: "Configure this service in its plugin"
|
|
882
955
|
}
|
|
@@ -893,7 +966,7 @@ function uiMessage(message, locale, providers = []) {
|
|
|
893
966
|
if ("key" in message) return copy[locale][message.key];
|
|
894
967
|
if ("sources" in message) return testOkText(locale, message.sources);
|
|
895
968
|
if ("moved" in message) {
|
|
896
|
-
const provider = providers.find((item) => item.id === message.moved);
|
|
969
|
+
const provider = providers.find((item) => item.id === message.moved && item.kind === message.kind);
|
|
897
970
|
return movedText(locale, provider ? providerDisplayLabel(provider, locale) : message.moved, message.position);
|
|
898
971
|
}
|
|
899
972
|
return message.invalid.map((key) => {
|
|
@@ -946,15 +1019,15 @@ function parseLimit(raw, min, max) {
|
|
|
946
1019
|
* Settings written by an immediate action (a switch or a reorder). It keeps the
|
|
947
1020
|
* saved limits and never includes typed-but-unsaved keys or limit drafts.
|
|
948
1021
|
*/
|
|
949
|
-
function immediateUpdate(settings, on, order, providers, remove = []) {
|
|
1022
|
+
function immediateUpdate(settings, on, order, providers, remove = [], kind = "search") {
|
|
950
1023
|
let searchOrder = order;
|
|
951
1024
|
if (providers) {
|
|
952
|
-
const known = new Set(providers.filter((provider) => provider.kind ===
|
|
1025
|
+
const known = new Set(providers.filter((provider) => provider.kind === kind).map((provider) => provider.id));
|
|
953
1026
|
const removed = new Set(remove);
|
|
954
1027
|
const following = order.filter((id) => !removed.has(id));
|
|
955
1028
|
if (following.some((id) => !known.has(id))) searchOrder = following;
|
|
956
1029
|
else {
|
|
957
|
-
searchOrder = settings.
|
|
1030
|
+
searchOrder = providerOrder(settings, kind).flatMap((id) => {
|
|
958
1031
|
if (removed.has(id)) return [];
|
|
959
1032
|
return known.has(id) ? following.splice(0, 1) : [id];
|
|
960
1033
|
});
|
|
@@ -963,8 +1036,13 @@ function immediateUpdate(settings, on, order, providers, remove = []) {
|
|
|
963
1036
|
}
|
|
964
1037
|
return {
|
|
965
1038
|
...editable(settings),
|
|
966
|
-
|
|
967
|
-
|
|
1039
|
+
...kind === "search" ? {
|
|
1040
|
+
searchOrder,
|
|
1041
|
+
searchEnabled: on
|
|
1042
|
+
} : {
|
|
1043
|
+
fetchOrder: searchOrder,
|
|
1044
|
+
fetchEnabled: on
|
|
1045
|
+
}
|
|
968
1046
|
};
|
|
969
1047
|
}
|
|
970
1048
|
function limitTexts(settings) {
|
|
@@ -986,7 +1064,7 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
986
1064
|
const locale = useHostLocale(client);
|
|
987
1065
|
const text = copy[locale];
|
|
988
1066
|
const tabsId = (0, react.useId)();
|
|
989
|
-
const [tab, setTab] = (0, react.useState)("
|
|
1067
|
+
const [tab, setTab] = (0, react.useState)("search");
|
|
990
1068
|
const [status, setStatus] = (0, react.useState)();
|
|
991
1069
|
const [limitDraft, setLimitDraft] = (0, react.useState)();
|
|
992
1070
|
const [invalid, setInvalid] = (0, react.useState)({});
|
|
@@ -1003,6 +1081,7 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1003
1081
|
const statusRef = (0, react.useRef)(status);
|
|
1004
1082
|
statusRef.current = status;
|
|
1005
1083
|
const pendingRef = (0, react.useRef)(null);
|
|
1084
|
+
const dragRef = (0, react.useRef)(null);
|
|
1006
1085
|
const timerRef = (0, react.useRef)(void 0);
|
|
1007
1086
|
const handleRefs = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
1008
1087
|
const refocusRef = (0, react.useRef)(null);
|
|
@@ -1038,7 +1117,7 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1038
1117
|
mounted: mountedRef.current,
|
|
1039
1118
|
hidden: isPageHidden(hiddenRef.current),
|
|
1040
1119
|
busy: busyRef.current,
|
|
1041
|
-
reordering: pendingRef.current !== null,
|
|
1120
|
+
reordering: pendingRef.current !== null || dragRef.current !== null,
|
|
1042
1121
|
reading: readingRef.current
|
|
1043
1122
|
});
|
|
1044
1123
|
}
|
|
@@ -1075,7 +1154,7 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1075
1154
|
requestId: mine,
|
|
1076
1155
|
latestRequestId: requestSeq.current,
|
|
1077
1156
|
busy: busyRef.current,
|
|
1078
|
-
reordering: pendingRef.current !== null,
|
|
1157
|
+
reordering: pendingRef.current !== null || dragRef.current !== null,
|
|
1079
1158
|
hidden: isPageHidden(hiddenRef.current),
|
|
1080
1159
|
currentRevision: statusRef.current?.settings.revision,
|
|
1081
1160
|
incomingRevision: next.settings.revision
|
|
@@ -1125,7 +1204,7 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1125
1204
|
const current = statusRef.current;
|
|
1126
1205
|
const next = pendingRef.current;
|
|
1127
1206
|
if (current && next) call("update", {
|
|
1128
|
-
settings: immediateUpdate(current.settings, current.settings.searchEnabled, next, current.providers),
|
|
1207
|
+
settings: immediateUpdate(current.settings, next.kind === "search" ? current.settings.searchEnabled : current.settings.fetchEnabled, next.order, current.providers, [], next.kind),
|
|
1129
1208
|
expectedRevision: current.settings.revision
|
|
1130
1209
|
}).catch(() => {});
|
|
1131
1210
|
};
|
|
@@ -1143,6 +1222,7 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1143
1222
|
if (handle && document.activeElement !== handle) handle.focus();
|
|
1144
1223
|
});
|
|
1145
1224
|
async function action(run) {
|
|
1225
|
+
if (busyRef.current) return;
|
|
1146
1226
|
readGate.reset();
|
|
1147
1227
|
requestSeq.current += 1;
|
|
1148
1228
|
busyRef.current = true;
|
|
@@ -1160,18 +1240,17 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1160
1240
|
}
|
|
1161
1241
|
}
|
|
1162
1242
|
/** Switches and reorders: settings only, applied at once. */
|
|
1163
|
-
function runImmediate(on, order, remove = []) {
|
|
1243
|
+
function runImmediate(on, order, remove = [], kind = "search") {
|
|
1164
1244
|
clearTimeout(timerRef.current);
|
|
1165
1245
|
timerRef.current = void 0;
|
|
1166
1246
|
pendingRef.current = null;
|
|
1167
1247
|
action(async () => {
|
|
1168
1248
|
const current = statusRef.current;
|
|
1169
1249
|
if (!current) return;
|
|
1170
|
-
|
|
1171
|
-
settings: immediateUpdate(current.settings, on, order, current.providers, remove),
|
|
1250
|
+
adopt(await call("update", {
|
|
1251
|
+
settings: immediateUpdate(current.settings, on, order, current.providers, remove, kind),
|
|
1172
1252
|
expectedRevision: current.settings.revision
|
|
1173
|
-
});
|
|
1174
|
-
setStatus(next);
|
|
1253
|
+
}));
|
|
1175
1254
|
await load();
|
|
1176
1255
|
}).then(() => {
|
|
1177
1256
|
if (pendingRef.current === null) setPendingOrder(null);
|
|
@@ -1181,24 +1260,27 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1181
1260
|
async function saveKeys(only) {
|
|
1182
1261
|
if (!status) return;
|
|
1183
1262
|
for (const provider of status.providers) {
|
|
1184
|
-
if (
|
|
1185
|
-
const snapshot = keys[provider.id] ?? "";
|
|
1263
|
+
if (only && providerKey(provider.kind, provider.id) !== providerKey(only.kind, only.id)) continue;
|
|
1264
|
+
const snapshot = keys[providerKey(provider.kind, provider.id)] ?? "";
|
|
1186
1265
|
const typed = snapshot.trim();
|
|
1187
1266
|
if (!ownsProviderConfiguration(provider) || !provider.credentialRef || !typed) continue;
|
|
1188
1267
|
if (writable[provider.credentialRef] === false) throw new UiError("readOnly");
|
|
1189
1268
|
unwrap(await client.remote.credentials.set(provider.credentialRef, typed));
|
|
1190
|
-
setKeys((current) => current[provider.id] === snapshot ? {
|
|
1269
|
+
setKeys((current) => current[providerKey(provider.kind, provider.id)] === snapshot ? {
|
|
1191
1270
|
...current,
|
|
1192
|
-
[provider.id]: ""
|
|
1271
|
+
[providerKey(provider.kind, provider.id)]: ""
|
|
1193
1272
|
} : current);
|
|
1194
1273
|
}
|
|
1195
1274
|
}
|
|
1275
|
+
async function saveKeysForKind(kind) {
|
|
1276
|
+
for (const provider of statusRef.current?.providers ?? []) if (provider.kind === kind) await saveKeys(provider);
|
|
1277
|
+
}
|
|
1196
1278
|
async function removeKey(provider) {
|
|
1197
1279
|
if (!ownsProviderConfiguration(provider) || !provider.credentialRef || provider.credentialShared || !status) return;
|
|
1198
1280
|
unwrap(await client.remote.credentials.unset(provider.credentialRef));
|
|
1199
1281
|
setKeys((current) => ({
|
|
1200
1282
|
...current,
|
|
1201
|
-
[provider.id]: ""
|
|
1283
|
+
[providerKey(provider.kind, provider.id)]: ""
|
|
1202
1284
|
}));
|
|
1203
1285
|
await load();
|
|
1204
1286
|
setNote({ key: "keyDeleted" });
|
|
@@ -1227,28 +1309,30 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1227
1309
|
}) : null]
|
|
1228
1310
|
});
|
|
1229
1311
|
const saved = status;
|
|
1230
|
-
const savedOrder = searchBackends(saved).map((provider) => provider.id);
|
|
1231
|
-
const order = pendingOrder ?? savedOrder;
|
|
1232
|
-
const catalog = catalogSearchBackends(saved);
|
|
1233
|
-
const backends = [...order.flatMap((id) => catalog.find((provider) => provider.id === id) ?? []), ...catalog.filter((provider) => !order.includes(provider.id))];
|
|
1234
|
-
const selected = selectedSearchBackend(saved);
|
|
1235
|
-
const on = saved.settings.searchEnabled;
|
|
1236
|
-
const canEnable = canEnableSearch(order, saved.providers, {}, writable);
|
|
1237
1312
|
const savedLimits = limitTexts(saved.settings);
|
|
1238
1313
|
const limitsDirty = LIMITS.some(([key]) => limitDraft[key] !== savedLimits[key]);
|
|
1239
1314
|
const keysDirty = Object.values(keys).some((value) => value.trim());
|
|
1240
|
-
const reordering = pendingOrder !== null;
|
|
1241
|
-
function move(id, nextIndex, keyboard = false) {
|
|
1315
|
+
const reordering = pendingOrder !== null || dragSource !== null;
|
|
1316
|
+
function move(kind, id, nextIndex, keyboard = false) {
|
|
1317
|
+
if (pendingRef.current && pendingRef.current.kind !== kind) return;
|
|
1318
|
+
const order = pendingRef.current?.order ?? providerOrder(statusRef.current.settings, kind);
|
|
1242
1319
|
const index = order.indexOf(id);
|
|
1243
1320
|
if (busy || index < 0 || nextIndex < 0 || nextIndex >= order.length || index === nextIndex) return;
|
|
1244
1321
|
const next = [...order];
|
|
1245
1322
|
const [item] = next.splice(index, 1);
|
|
1246
1323
|
next.splice(nextIndex, 0, item);
|
|
1247
|
-
pendingRef.current =
|
|
1248
|
-
|
|
1249
|
-
|
|
1324
|
+
pendingRef.current = {
|
|
1325
|
+
kind,
|
|
1326
|
+
order: next
|
|
1327
|
+
};
|
|
1328
|
+
setPendingOrder({
|
|
1329
|
+
kind,
|
|
1330
|
+
order: next
|
|
1331
|
+
});
|
|
1332
|
+
if (keyboard) refocusRef.current = providerKey(kind, id);
|
|
1250
1333
|
setSortAnnouncement({
|
|
1251
1334
|
moved: id,
|
|
1335
|
+
kind,
|
|
1252
1336
|
position: nextIndex + 1
|
|
1253
1337
|
});
|
|
1254
1338
|
clearTimeout(timerRef.current);
|
|
@@ -1256,10 +1340,11 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1256
1340
|
timerRef.current = void 0;
|
|
1257
1341
|
const batched = pendingRef.current;
|
|
1258
1342
|
const current = statusRef.current;
|
|
1259
|
-
if (batched && current) runImmediate(current.settings.searchEnabled, batched);
|
|
1343
|
+
if (batched && current) runImmediate(batched.kind === "search" ? current.settings.searchEnabled : current.settings.fetchEnabled, batched.order, [], batched.kind);
|
|
1260
1344
|
}, keyboard ? REORDER_DEBOUNCE_MS : 0);
|
|
1261
1345
|
}
|
|
1262
1346
|
function endDrag() {
|
|
1347
|
+
dragRef.current = null;
|
|
1263
1348
|
setDragSource(null);
|
|
1264
1349
|
setDropTarget(null);
|
|
1265
1350
|
}
|
|
@@ -1302,17 +1387,26 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1302
1387
|
value: tab,
|
|
1303
1388
|
onChange: setTab,
|
|
1304
1389
|
label: text.tabsLabel,
|
|
1305
|
-
items: [
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1390
|
+
items: [
|
|
1391
|
+
{
|
|
1392
|
+
value: "search",
|
|
1393
|
+
label: text.tabSearch,
|
|
1394
|
+
id: tabsId + "-search-tab",
|
|
1395
|
+
panelId: tabsId + "-search-panel"
|
|
1396
|
+
},
|
|
1397
|
+
{
|
|
1398
|
+
value: "fetch",
|
|
1399
|
+
label: text.tabFetch,
|
|
1400
|
+
id: tabsId + "-fetch-tab",
|
|
1401
|
+
panelId: tabsId + "-fetch-panel"
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
value: "limits",
|
|
1405
|
+
label: text.tabLimits,
|
|
1406
|
+
id: tabsId + "-limits-tab",
|
|
1407
|
+
panelId: tabsId + "-limits-panel"
|
|
1408
|
+
}
|
|
1409
|
+
]
|
|
1316
1410
|
}),
|
|
1317
1411
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1318
1412
|
className: "ws-sr-only",
|
|
@@ -1351,374 +1445,294 @@ function NetworkSearchSettings({ client, hidden }) {
|
|
|
1351
1445
|
className: "dsh-ui-banner dsh-ui-banner--danger",
|
|
1352
1446
|
children: text.storageFailed
|
|
1353
1447
|
}),
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
checked: on,
|
|
1378
|
-
label: text.toolTitle,
|
|
1379
|
-
disabled: busy || !on && !canEnable,
|
|
1380
|
-
onChange: (next) => runImmediate(next, order)
|
|
1381
|
-
})]
|
|
1382
|
-
}),
|
|
1383
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
|
|
1384
|
-
className: "web-search-rank",
|
|
1385
|
-
"aria-label": text.backends,
|
|
1386
|
-
children: backends.map((provider) => {
|
|
1387
|
-
const participating = order.includes(provider.id);
|
|
1388
|
-
const rank = order.indexOf(provider.id);
|
|
1389
|
-
const dormant = !isRegisteredSearch(saved, provider.id);
|
|
1390
|
-
const active = !dormant && saved.searchActive && selected?.id === provider.id;
|
|
1391
|
-
const info = searchProviderInfo(provider, locale);
|
|
1392
|
-
const owned = ownsProviderConfiguration(provider);
|
|
1393
|
-
const access = configurationAccess(provider);
|
|
1394
|
-
const needsKey = owned && Boolean(provider.credentialRef);
|
|
1395
|
-
const shared = Boolean(provider.credentialShared);
|
|
1396
|
-
const showKey = !dormant && needsKey && participating && (!shared || !provider.configured);
|
|
1397
|
-
const canSort = participating && order.length > 1;
|
|
1398
|
-
const readOnly = writable[provider.credentialRef ?? ""] === false;
|
|
1399
|
-
const typedKey = (keys[provider.id] ?? "").trim();
|
|
1400
|
-
const availability = dormant ? "dormant" : provider.configured ? "available" : "unavailable";
|
|
1401
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
1402
|
-
className: active ? "is-active" : void 0,
|
|
1403
|
-
"data-testid": `web-search-rank-${provider.id}`,
|
|
1404
|
-
"data-availability": availability,
|
|
1405
|
-
"data-in-use": active || void 0,
|
|
1406
|
-
"data-dragging": dragSource === provider.id || void 0,
|
|
1407
|
-
"data-drop": dropTarget === provider.id && dragSource ? order.indexOf(dragSource) < rank ? "after" : "before" : void 0,
|
|
1408
|
-
onDragOver: (event) => {
|
|
1409
|
-
if (busy || !canSort || !dragSource || dragSource === provider.id) return;
|
|
1410
|
-
event.preventDefault();
|
|
1411
|
-
event.dataTransfer.dropEffect = "move";
|
|
1412
|
-
setDropTarget(provider.id);
|
|
1413
|
-
},
|
|
1414
|
-
onDragLeave: (event) => {
|
|
1415
|
-
if (!event.currentTarget.contains(event.relatedTarget)) setDropTarget(null);
|
|
1416
|
-
},
|
|
1417
|
-
onDrop: (event) => {
|
|
1418
|
-
if (busy || !canSort || !dragSource) return;
|
|
1419
|
-
event.preventDefault();
|
|
1420
|
-
move(dragSource, rank);
|
|
1421
|
-
endDrag();
|
|
1422
|
-
},
|
|
1423
|
-
children: [
|
|
1424
|
-
canSort ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1425
|
-
variant: "ghost",
|
|
1426
|
-
size: "sm",
|
|
1427
|
-
className: "web-search-drag-handle",
|
|
1428
|
-
ref: (element) => {
|
|
1429
|
-
if (element) handleRefs.current.set(provider.id, element);
|
|
1430
|
-
else handleRefs.current.delete(provider.id);
|
|
1431
|
-
},
|
|
1432
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
1433
|
-
width: "16",
|
|
1434
|
-
height: "20",
|
|
1435
|
-
viewBox: "0 0 16 20",
|
|
1436
|
-
fill: "currentColor",
|
|
1437
|
-
"aria-hidden": "true",
|
|
1438
|
-
children: [
|
|
1439
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1440
|
-
cx: "5",
|
|
1441
|
-
cy: "5",
|
|
1442
|
-
r: "1.5"
|
|
1443
|
-
}),
|
|
1444
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1445
|
-
cx: "11",
|
|
1446
|
-
cy: "5",
|
|
1447
|
-
r: "1.5"
|
|
1448
|
-
}),
|
|
1449
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1450
|
-
cx: "5",
|
|
1451
|
-
cy: "10",
|
|
1452
|
-
r: "1.5"
|
|
1453
|
-
}),
|
|
1454
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1455
|
-
cx: "11",
|
|
1456
|
-
cy: "10",
|
|
1457
|
-
r: "1.5"
|
|
1458
|
-
}),
|
|
1459
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1460
|
-
cx: "5",
|
|
1461
|
-
cy: "15",
|
|
1462
|
-
r: "1.5"
|
|
1463
|
-
}),
|
|
1464
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1465
|
-
cx: "11",
|
|
1466
|
-
cy: "15",
|
|
1467
|
-
r: "1.5"
|
|
1468
|
-
})
|
|
1469
|
-
]
|
|
1470
|
-
}),
|
|
1471
|
-
draggable: !busy,
|
|
1472
|
-
"aria-disabled": busy,
|
|
1473
|
-
"aria-label": text.dragPrefix + providerDisplayLabel(provider, locale),
|
|
1474
|
-
title: text.dragHint,
|
|
1475
|
-
onDragStart: (event) => {
|
|
1476
|
-
if (busy) {
|
|
1477
|
-
event.preventDefault();
|
|
1478
|
-
return;
|
|
1479
|
-
}
|
|
1480
|
-
event.dataTransfer.effectAllowed = "move";
|
|
1481
|
-
event.dataTransfer.setData("application/x-dsh-search-provider", provider.id);
|
|
1482
|
-
const row = event.currentTarget.closest("li");
|
|
1483
|
-
if (row) event.dataTransfer.setDragImage(row, 16, 16);
|
|
1484
|
-
setDragSource(provider.id);
|
|
1485
|
-
setSortAnnouncement("");
|
|
1486
|
-
},
|
|
1487
|
-
onDragEnd: endDrag,
|
|
1488
|
-
onKeyDown: (event) => {
|
|
1489
|
-
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
1490
|
-
event.preventDefault();
|
|
1491
|
-
move(provider.id, rank + (event.key === "ArrowUp" ? -1 : 1), true);
|
|
1492
|
-
}
|
|
1493
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1494
|
-
className: "web-search-rank-index",
|
|
1495
|
-
children: participating ? rank + 1 : "—"
|
|
1496
|
-
}),
|
|
1497
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1498
|
-
className: "web-search-provider",
|
|
1499
|
-
children: [
|
|
1500
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1501
|
-
className: "web-search-provider-heading",
|
|
1502
|
-
children: [
|
|
1503
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
1504
|
-
className: "dsh-ui-heading",
|
|
1505
|
-
children: providerDisplayLabel(provider, locale)
|
|
1506
|
-
}),
|
|
1507
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1508
|
-
className: "ws-provider-note",
|
|
1509
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: dormant ? "idle" : provider.configured ? "done" : "warning" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: dormant ? text.dormant : provider.configured ? text.available : text.unavailable })]
|
|
1510
|
-
}),
|
|
1511
|
-
active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1512
|
-
tone: "success",
|
|
1513
|
-
children: text.inUse
|
|
1514
|
-
}),
|
|
1515
|
-
provider.signupUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppLink, {
|
|
1516
|
-
url: provider.signupUrl,
|
|
1517
|
-
label: providerDisplayLabel(provider, locale) + " " + text.signup,
|
|
1518
|
-
children: text.signup
|
|
1519
|
-
})
|
|
1520
|
-
]
|
|
1521
|
-
}),
|
|
1522
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1523
|
-
className: "web-search-provider-info",
|
|
1524
|
-
children: [info.description ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: info.description }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [info.pricing, info.pricingUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppLink, {
|
|
1525
|
-
url: info.pricingUrl,
|
|
1526
|
-
label: providerDisplayLabel(provider, locale) + " " + text.pricing,
|
|
1527
|
-
children: provider.id === "ddg" ? text.website : text.pricing
|
|
1528
|
-
})] })] })]
|
|
1529
|
-
}),
|
|
1530
|
-
access.kind === "link" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1531
|
-
className: "dsh-ui-hint",
|
|
1532
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppLink, {
|
|
1533
|
-
url: access.url,
|
|
1534
|
-
label: text.openConfig,
|
|
1535
|
-
children: text.openConfig
|
|
1536
|
-
})
|
|
1537
|
-
}) : access.kind === "owner" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1538
|
-
className: "dsh-ui-hint",
|
|
1539
|
-
children: [text.ownerSettings, access.name]
|
|
1540
|
-
}) : access.kind === "unknown" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1541
|
-
className: "dsh-ui-hint",
|
|
1542
|
-
children: text.unknownOwner
|
|
1543
|
-
}) : null,
|
|
1544
|
-
shared && participating && owned ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
|
|
1545
|
-
className: "dsh-ui-meta",
|
|
1546
|
-
children: provider.credentialHint === "与模型设置共用 Key" ? locale === "zh" ? provider.credentialHint : "Shares a key with model settings" : provider.credentialHint ?? text.sharedKey
|
|
1547
|
-
}) : null,
|
|
1548
|
-
showKey ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1549
|
-
className: "dsh-ui-field",
|
|
1550
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1551
|
-
className: "dsh-ui-label",
|
|
1552
|
-
children: "API Key"
|
|
1553
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
1554
|
-
className: "ws-input",
|
|
1555
|
-
type: "password",
|
|
1556
|
-
autoComplete: "off",
|
|
1557
|
-
spellCheck: false,
|
|
1558
|
-
disabled: busy || readOnly,
|
|
1559
|
-
value: keys[provider.id] ?? "",
|
|
1560
|
-
placeholder: provider.configured ? text.keyConfigured : text.keyPlaceholder,
|
|
1561
|
-
onChange: (event) => setKeys((current) => ({
|
|
1562
|
-
...current,
|
|
1563
|
-
[provider.id]: event.target.value
|
|
1564
|
-
}))
|
|
1565
|
-
})]
|
|
1566
|
-
}) : null,
|
|
1567
|
-
showKey || needsKey && !shared && provider.configured ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1568
|
-
className: "dsh-ui-actions",
|
|
1569
|
-
children: [showKey ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1570
|
-
variant: "outline",
|
|
1571
|
-
size: "sm",
|
|
1572
|
-
disabled: busy || readOnly || !typedKey,
|
|
1573
|
-
onClick: () => void action(async () => {
|
|
1574
|
-
await saveKeys(provider);
|
|
1575
|
-
await load();
|
|
1576
|
-
setNote({ key: "keySaved" });
|
|
1577
|
-
}),
|
|
1578
|
-
children: text.saveKey
|
|
1579
|
-
}) : null, needsKey && !shared && provider.configured ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmButton, {
|
|
1580
|
-
disabled: busy || readOnly,
|
|
1581
|
-
label: text.deleteKey,
|
|
1582
|
-
confirmLabel: text.confirmDelete,
|
|
1583
|
-
onConfirm: () => void action(() => removeKey(provider))
|
|
1584
|
-
}) : null]
|
|
1585
|
-
}) : null
|
|
1586
|
-
]
|
|
1587
|
-
}),
|
|
1588
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1589
|
-
className: "web-search-rank-move",
|
|
1590
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
1591
|
-
checked: participating,
|
|
1592
|
-
label: providerDisplayLabel(provider, locale),
|
|
1593
|
-
disabled: busy,
|
|
1594
|
-
onChange: (next) => {
|
|
1595
|
-
const following = next ? [...order, provider.id] : order.filter((id) => id !== provider.id);
|
|
1596
|
-
runImmediate(nextSearchEnabled(saved.settings.searchEnabled, following, saved.providers, {}, writable), following, droppedDormantIds(saved.settings, following, saved.providers));
|
|
1597
|
-
}
|
|
1598
|
-
})
|
|
1599
|
-
})
|
|
1600
|
-
]
|
|
1601
|
-
}, provider.id);
|
|
1602
|
-
})
|
|
1603
|
-
}),
|
|
1604
|
-
backends.some(usesBundledPricing) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1605
|
-
className: "dsh-ui-hint",
|
|
1606
|
-
children: pricingCheckedText(locale, PROVIDER_PRICING_CHECKED)
|
|
1607
|
-
}) : null,
|
|
1608
|
-
on ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1609
|
-
className: "dsh-ui-actions",
|
|
1610
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1611
|
-
variant: "outline",
|
|
1612
|
-
size: "md",
|
|
1613
|
-
disabled: busy || reordering,
|
|
1614
|
-
onClick: () => void action(async () => {
|
|
1615
|
-
await saveKeys();
|
|
1616
|
-
const result = await call("test");
|
|
1617
|
-
await load();
|
|
1618
|
-
setNote({ sources: result.sources });
|
|
1619
|
-
}),
|
|
1620
|
-
children: text.test
|
|
1621
|
-
})
|
|
1622
|
-
}) : null
|
|
1623
|
-
]
|
|
1624
|
-
}), (saved.providers.some((provider) => provider.kind === "fetch") || saved.settings.fetchProvider) && (() => {
|
|
1625
|
-
const fetchId = saved.settings.fetchProvider;
|
|
1626
|
-
const fetchSelected = saved.providers.find((provider) => provider.kind === "fetch" && provider.id === fetchId);
|
|
1627
|
-
const fetchDormant = Boolean(fetchId) && !fetchSelected;
|
|
1628
|
-
const fetchActive = Boolean(fetchSelected && saved.fetchActive && fetchSelected.configured);
|
|
1629
|
-
const fetchAccess = fetchSelected ? configurationAccess(fetchSelected) : fetchDormant ? { kind: "unknown" } : void 0;
|
|
1630
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
1631
|
-
className: "dsh-ui-card dsh-ui-card--flat",
|
|
1632
|
-
"data-testid": "web-search-fetch",
|
|
1633
|
-
"data-availability": fetchDormant ? "dormant" : fetchSelected?.configured ? "available" : "unavailable",
|
|
1634
|
-
"data-in-use": fetchActive || void 0,
|
|
1448
|
+
["search", "fetch"].map((kind) => {
|
|
1449
|
+
const order = pendingOrder?.kind === kind ? pendingOrder.order : providerOrder(saved.settings, kind);
|
|
1450
|
+
const catalog = catalogBackends(saved, kind);
|
|
1451
|
+
const backends = [...order.flatMap((id) => catalog.find((provider) => provider.id === id) ?? []), ...catalog.filter((provider) => !order.includes(provider.id))];
|
|
1452
|
+
const selected = selectedBackend(saved, kind);
|
|
1453
|
+
const on = kind === "search" ? saved.settings.searchEnabled : saved.settings.fetchEnabled;
|
|
1454
|
+
const canEnable = order.some((id) => saved.providers.some((provider) => provider.kind === kind && provider.id === id && provider.configured));
|
|
1455
|
+
const sortingOther = pendingOrder !== null && pendingOrder.kind !== kind;
|
|
1456
|
+
const locked = busy || sortingOther || Boolean(dragSource && !dragSource.startsWith(kind + ":"));
|
|
1457
|
+
const title = kind === "search" ? text.toolTitle : text.fetchTitle;
|
|
1458
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1459
|
+
role: "tabpanel",
|
|
1460
|
+
id: tabsId + "-" + kind + "-panel",
|
|
1461
|
+
"aria-labelledby": tabsId + "-" + kind + "-tab",
|
|
1462
|
+
hidden: tab !== kind,
|
|
1463
|
+
tabIndex: 0,
|
|
1464
|
+
children: backends.length === 0 ? kind === "search" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1465
|
+
className: "dsh-ui-empty",
|
|
1466
|
+
children: text.empty
|
|
1467
|
+
}) : null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
1468
|
+
className: "web-search-card dsh-ui-card dsh-ui-card--flat",
|
|
1469
|
+
"data-testid": kind === "search" ? "web-search-tool" : "web-search-fetch",
|
|
1470
|
+
"data-on": on ? "true" : "false",
|
|
1635
1471
|
children: [
|
|
1636
1472
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
1637
1473
|
className: "ws-card-head",
|
|
1638
1474
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1639
1475
|
className: "dsh-ui-title",
|
|
1640
|
-
children:
|
|
1641
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1642
|
-
className: "
|
|
1643
|
-
children:
|
|
1644
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: fetchDormant ? "idle" : fetchSelected?.configured ? "done" : "warning" }),
|
|
1645
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fetchDormant ? text.dormant : fetchSelected?.configured ? text.available : text.unavailable }),
|
|
1646
|
-
fetchActive ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1647
|
-
tone: "success",
|
|
1648
|
-
children: text.inUse
|
|
1649
|
-
}) : null
|
|
1650
|
-
]
|
|
1476
|
+
children: title
|
|
1477
|
+
}), !canEnable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1478
|
+
className: "dsh-ui-hint",
|
|
1479
|
+
children: kind === "search" ? text.needBackend : text.needFetchBackend
|
|
1651
1480
|
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
1652
|
-
checked:
|
|
1653
|
-
label:
|
|
1654
|
-
disabled:
|
|
1655
|
-
onChange: (next) =>
|
|
1656
|
-
const current = statusRef.current;
|
|
1657
|
-
adopt(await call("update", {
|
|
1658
|
-
settings: {
|
|
1659
|
-
...editable(current.settings),
|
|
1660
|
-
fetchEnabled: next
|
|
1661
|
-
},
|
|
1662
|
-
expectedRevision: current.settings.revision
|
|
1663
|
-
}));
|
|
1664
|
-
await load();
|
|
1665
|
-
})
|
|
1481
|
+
checked: on,
|
|
1482
|
+
label: title,
|
|
1483
|
+
disabled: locked || dragSource !== null || !on && !canEnable,
|
|
1484
|
+
onChange: (next) => runImmediate(next, order, [], kind)
|
|
1666
1485
|
})]
|
|
1667
1486
|
}),
|
|
1668
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1669
|
-
className: "
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
"
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1487
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
|
|
1488
|
+
className: "web-search-rank",
|
|
1489
|
+
"aria-label": kind === "search" ? text.backends : text.fetchBackends,
|
|
1490
|
+
children: backends.map((provider) => {
|
|
1491
|
+
const participating = order.includes(provider.id);
|
|
1492
|
+
const rank = order.indexOf(provider.id);
|
|
1493
|
+
const dormant = !isRegistered(saved, provider.id, kind);
|
|
1494
|
+
const active = !dormant && (kind === "search" ? saved.searchActive : saved.fetchActive) && selected?.id === provider.id;
|
|
1495
|
+
const info = kind === "search" || ownsProviderConfiguration(provider) && provider.id === "firecrawl" ? searchProviderInfo(provider, locale) : {
|
|
1496
|
+
description: ownsProviderConfiguration(provider) && provider.id === "http-managed" && provider.description === "优先匿名 Jina Reader 读取,失败后本机 HTTP 直连;无需 Key。" && locale === "en" ? "Reads with anonymous Jina Reader first, then direct HTTP if needed; no key required." : provider.description,
|
|
1497
|
+
pricing: provider.pricing ?? "",
|
|
1498
|
+
pricingUrl: provider.pricingUrl
|
|
1499
|
+
};
|
|
1500
|
+
const owned = ownsProviderConfiguration(provider);
|
|
1501
|
+
const access = configurationAccess(provider);
|
|
1502
|
+
const needsKey = owned && Boolean(provider.credentialRef);
|
|
1503
|
+
const shared = Boolean(provider.credentialShared);
|
|
1504
|
+
const showKey = !dormant && needsKey && participating && (!shared || !provider.configured);
|
|
1505
|
+
const canSort = participating && order.length > 1;
|
|
1506
|
+
const readOnly = writable[provider.credentialRef ?? ""] === false;
|
|
1507
|
+
const typedKey = (keys[providerKey(provider.kind, provider.id)] ?? "").trim();
|
|
1508
|
+
const availability = dormant ? "dormant" : provider.configured ? "available" : "unavailable";
|
|
1509
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
1510
|
+
className: active ? "is-active" : void 0,
|
|
1511
|
+
"data-testid": `web-${kind}-rank-${provider.id}`,
|
|
1512
|
+
"data-availability": availability,
|
|
1513
|
+
"data-in-use": active || void 0,
|
|
1514
|
+
"data-dragging": dragSource === providerKey(kind, provider.id) || void 0,
|
|
1515
|
+
"data-drop": dropTarget === providerKey(kind, provider.id) && dragSource ? order.indexOf(dragSource.slice(kind.length + 1)) < rank ? "after" : "before" : void 0,
|
|
1516
|
+
onDragOver: (event) => {
|
|
1517
|
+
if (locked || !canSort || !dragSource?.startsWith(kind + ":") || dragSource === providerKey(kind, provider.id)) return;
|
|
1518
|
+
event.preventDefault();
|
|
1519
|
+
event.dataTransfer.dropEffect = "move";
|
|
1520
|
+
setDropTarget(providerKey(kind, provider.id));
|
|
1521
|
+
},
|
|
1522
|
+
onDragLeave: (event) => {
|
|
1523
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setDropTarget(null);
|
|
1524
|
+
},
|
|
1525
|
+
onDrop: (event) => {
|
|
1526
|
+
if (locked || !canSort || !dragSource?.startsWith(kind + ":")) return;
|
|
1527
|
+
event.preventDefault();
|
|
1528
|
+
move(kind, dragSource.slice(kind.length + 1), rank);
|
|
1529
|
+
endDrag();
|
|
1530
|
+
},
|
|
1694
1531
|
children: [
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1532
|
+
canSort ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1533
|
+
variant: "ghost",
|
|
1534
|
+
size: "sm",
|
|
1535
|
+
className: "web-search-drag-handle",
|
|
1536
|
+
ref: (element) => {
|
|
1537
|
+
if (element) handleRefs.current.set(providerKey(kind, provider.id), element);
|
|
1538
|
+
else handleRefs.current.delete(providerKey(kind, provider.id));
|
|
1539
|
+
},
|
|
1540
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
1541
|
+
width: "16",
|
|
1542
|
+
height: "20",
|
|
1543
|
+
viewBox: "0 0 16 20",
|
|
1544
|
+
fill: "currentColor",
|
|
1545
|
+
"aria-hidden": "true",
|
|
1546
|
+
children: [
|
|
1547
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1548
|
+
cx: "5",
|
|
1549
|
+
cy: "5",
|
|
1550
|
+
r: "1.5"
|
|
1551
|
+
}),
|
|
1552
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1553
|
+
cx: "11",
|
|
1554
|
+
cy: "5",
|
|
1555
|
+
r: "1.5"
|
|
1556
|
+
}),
|
|
1557
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1558
|
+
cx: "5",
|
|
1559
|
+
cy: "10",
|
|
1560
|
+
r: "1.5"
|
|
1561
|
+
}),
|
|
1562
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1563
|
+
cx: "11",
|
|
1564
|
+
cy: "10",
|
|
1565
|
+
r: "1.5"
|
|
1566
|
+
}),
|
|
1567
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1568
|
+
cx: "5",
|
|
1569
|
+
cy: "15",
|
|
1570
|
+
r: "1.5"
|
|
1571
|
+
}),
|
|
1572
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1573
|
+
cx: "11",
|
|
1574
|
+
cy: "15",
|
|
1575
|
+
r: "1.5"
|
|
1576
|
+
})
|
|
1577
|
+
]
|
|
1578
|
+
}),
|
|
1579
|
+
draggable: !locked,
|
|
1580
|
+
"aria-disabled": locked,
|
|
1581
|
+
"aria-label": text.dragPrefix + providerDisplayLabel(provider, locale),
|
|
1582
|
+
title: text.dragHint,
|
|
1583
|
+
onDragStart: (event) => {
|
|
1584
|
+
if (locked || pendingRef.current && pendingRef.current.kind !== kind) {
|
|
1585
|
+
event.preventDefault();
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
event.dataTransfer.effectAllowed = "move";
|
|
1589
|
+
event.dataTransfer.setData(`application/x-dsh-${kind}-provider`, provider.id);
|
|
1590
|
+
const row = event.currentTarget.closest("li");
|
|
1591
|
+
if (row) event.dataTransfer.setDragImage(row, 16, 16);
|
|
1592
|
+
dragRef.current = providerKey(kind, provider.id);
|
|
1593
|
+
requestSeq.current += 1;
|
|
1594
|
+
setDragSource(providerKey(kind, provider.id));
|
|
1595
|
+
setSortAnnouncement("");
|
|
1596
|
+
},
|
|
1597
|
+
onDragEnd: endDrag,
|
|
1598
|
+
onKeyDown: (event) => {
|
|
1599
|
+
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
1600
|
+
event.preventDefault();
|
|
1601
|
+
move(kind, provider.id, rank + (event.key === "ArrowUp" ? -1 : 1), true);
|
|
1602
|
+
}
|
|
1603
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1604
|
+
className: "web-search-rank-index",
|
|
1605
|
+
children: participating ? rank + 1 : "—"
|
|
1606
|
+
}),
|
|
1607
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1608
|
+
className: "web-search-provider",
|
|
1609
|
+
children: [
|
|
1610
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1611
|
+
className: "web-search-provider-heading",
|
|
1612
|
+
children: [
|
|
1613
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
1614
|
+
className: "dsh-ui-heading",
|
|
1615
|
+
children: providerDisplayLabel(provider, locale)
|
|
1616
|
+
}),
|
|
1617
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1618
|
+
className: "ws-provider-note",
|
|
1619
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: dormant ? "idle" : provider.configured ? "done" : "warning" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: dormant ? text.dormant : provider.configured ? text.available : text.unavailable })]
|
|
1620
|
+
}),
|
|
1621
|
+
active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1622
|
+
tone: "success",
|
|
1623
|
+
children: text.inUse
|
|
1624
|
+
}),
|
|
1625
|
+
provider.signupUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppLink, {
|
|
1626
|
+
url: provider.signupUrl,
|
|
1627
|
+
label: providerDisplayLabel(provider, locale) + " " + text.signup,
|
|
1628
|
+
children: text.signup
|
|
1629
|
+
})
|
|
1630
|
+
]
|
|
1631
|
+
}),
|
|
1632
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1633
|
+
className: "web-search-provider-info",
|
|
1634
|
+
children: [info.description ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: info.description }) : null, info.pricing || info.pricingUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [info.pricing, info.pricingUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppLink, {
|
|
1635
|
+
url: info.pricingUrl,
|
|
1636
|
+
label: providerDisplayLabel(provider, locale) + " " + text.pricing,
|
|
1637
|
+
children: provider.id === "ddg" ? text.website : text.pricing
|
|
1638
|
+
})] })] }) : null]
|
|
1639
|
+
}),
|
|
1640
|
+
access.kind === "link" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1641
|
+
className: "dsh-ui-hint",
|
|
1642
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppLink, {
|
|
1643
|
+
url: access.url,
|
|
1644
|
+
label: text.openConfig,
|
|
1645
|
+
children: text.openConfig
|
|
1646
|
+
})
|
|
1647
|
+
}) : access.kind === "owner" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1648
|
+
className: "dsh-ui-hint",
|
|
1649
|
+
children: [text.ownerSettings, access.name]
|
|
1650
|
+
}) : access.kind === "unknown" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1651
|
+
className: "dsh-ui-hint",
|
|
1652
|
+
children: text.unknownOwner
|
|
1653
|
+
}) : null,
|
|
1654
|
+
shared && participating && owned ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
|
|
1655
|
+
className: "dsh-ui-meta",
|
|
1656
|
+
children: provider.credentialHint === "与模型设置共用 Key" ? locale === "zh" ? provider.credentialHint : "Shares a key with model settings" : owned && provider.id === "firecrawl" && locale === "en" ? "Search and page reads share a Firecrawl key" : provider.credentialHint ?? text.sharedKey
|
|
1657
|
+
}) : null,
|
|
1658
|
+
showKey ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1659
|
+
className: "dsh-ui-field",
|
|
1660
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1661
|
+
className: "dsh-ui-label",
|
|
1662
|
+
children: "API Key"
|
|
1663
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
1664
|
+
className: "ws-input",
|
|
1665
|
+
type: "password",
|
|
1666
|
+
autoComplete: "off",
|
|
1667
|
+
spellCheck: false,
|
|
1668
|
+
disabled: busy || reordering || readOnly,
|
|
1669
|
+
value: keys[providerKey(provider.kind, provider.id)] ?? "",
|
|
1670
|
+
placeholder: provider.configured ? text.keyConfigured : text.keyPlaceholder,
|
|
1671
|
+
onChange: (event) => setKeys((current) => ({
|
|
1672
|
+
...current,
|
|
1673
|
+
[providerKey(provider.kind, provider.id)]: event.target.value
|
|
1674
|
+
}))
|
|
1675
|
+
})]
|
|
1676
|
+
}) : null,
|
|
1677
|
+
showKey || needsKey && !shared && provider.configured ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1678
|
+
className: "dsh-ui-actions",
|
|
1679
|
+
children: [showKey ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1680
|
+
variant: "outline",
|
|
1681
|
+
size: "sm",
|
|
1682
|
+
disabled: busy || reordering || readOnly || !typedKey,
|
|
1683
|
+
onClick: () => void action(async () => {
|
|
1684
|
+
await saveKeys(provider);
|
|
1685
|
+
await load();
|
|
1686
|
+
setNote({ key: "keySaved" });
|
|
1687
|
+
}),
|
|
1688
|
+
children: text.saveKey
|
|
1689
|
+
}) : null, needsKey && !shared && provider.configured ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmButton, {
|
|
1690
|
+
disabled: busy || reordering || readOnly,
|
|
1691
|
+
label: text.deleteKey,
|
|
1692
|
+
confirmLabel: text.confirmDelete,
|
|
1693
|
+
onConfirm: () => void action(() => removeKey(provider))
|
|
1694
|
+
}) : null]
|
|
1695
|
+
}) : null
|
|
1696
|
+
]
|
|
1697
|
+
}),
|
|
1698
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1699
|
+
className: "web-search-rank-move",
|
|
1700
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
1701
|
+
checked: participating,
|
|
1702
|
+
label: providerDisplayLabel(provider, locale),
|
|
1703
|
+
disabled: locked || dragSource !== null,
|
|
1704
|
+
onChange: (next) => {
|
|
1705
|
+
const following = next ? [...order, provider.id] : order.filter((id) => id !== provider.id);
|
|
1706
|
+
runImmediate(on && following.some((id) => saved.providers.some((item) => item.kind === kind && item.id === id && item.configured)), following, droppedDormantIds(saved.settings, following, saved.providers, kind), kind);
|
|
1707
|
+
}
|
|
1708
|
+
})
|
|
1709
|
+
})
|
|
1698
1710
|
]
|
|
1699
|
-
}
|
|
1700
|
-
|
|
1701
|
-
children: [providerDisplayLabel(provider, locale), provider.configured ? "" : " · " + text.unavailable]
|
|
1702
|
-
}, provider.id))]
|
|
1703
|
-
})]
|
|
1711
|
+
}, provider.id);
|
|
1712
|
+
})
|
|
1704
1713
|
}),
|
|
1705
|
-
|
|
1714
|
+
kind === "search" && backends.some(usesBundledPricing) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1706
1715
|
className: "dsh-ui-hint",
|
|
1707
|
-
children:
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1716
|
+
children: pricingCheckedText(locale, PROVIDER_PRICING_CHECKED)
|
|
1717
|
+
}) : null,
|
|
1718
|
+
on && kind === "search" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1719
|
+
className: "dsh-ui-actions",
|
|
1720
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1721
|
+
variant: "outline",
|
|
1722
|
+
size: "md",
|
|
1723
|
+
disabled: busy || reordering,
|
|
1724
|
+
onClick: () => void action(async () => {
|
|
1725
|
+
await saveKeysForKind("search");
|
|
1726
|
+
const result = await call("test");
|
|
1727
|
+
await load();
|
|
1728
|
+
setNote({ sources: result.sources });
|
|
1729
|
+
}),
|
|
1730
|
+
children: text.test
|
|
1711
1731
|
})
|
|
1712
|
-
}) : fetchAccess?.kind === "owner" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1713
|
-
className: "dsh-ui-hint",
|
|
1714
|
-
children: [text.ownerSettings, fetchAccess.name]
|
|
1715
|
-
}) : fetchAccess?.kind === "unknown" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1716
|
-
className: "dsh-ui-hint",
|
|
1717
|
-
children: text.unknownOwner
|
|
1718
1732
|
}) : null
|
|
1719
1733
|
]
|
|
1720
|
-
})
|
|
1721
|
-
})
|
|
1734
|
+
})
|
|
1735
|
+
}, kind);
|
|
1722
1736
|
}),
|
|
1723
1737
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1724
1738
|
role: "tabpanel",
|