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