@klarkxy/dsh-web-search-manager 0.1.11 → 0.2.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 +28 -10
- package/cordis.patch.yml +1 -8
- package/docs/README.zh-CN.md +28 -10
- package/lib/client.inner.cjs +507 -83
- package/lib/client.inner.cjs.map +1 -1
- package/lib/client.js +508 -245
- package/lib/contracts.d.ts +19 -2
- package/lib/contracts.js +13 -1
- package/lib/contracts.js.map +1 -1
- package/lib/index.d.ts +18 -3
- package/lib/index.js +488 -331
- package/lib/index.js.map +1 -1
- package/package.json +23 -22
package/lib/client.inner.cjs
CHANGED
|
@@ -375,6 +375,49 @@ ${scope} {
|
|
|
375
375
|
`.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?![+>~])/gm, (_match, className) => `&${className}, & ${className}`);
|
|
376
376
|
}
|
|
377
377
|
//#endregion
|
|
378
|
+
//#region ../dsh-plugin-kit/src/client-utils.ts
|
|
379
|
+
/** Fixed pause for failing background reads; manual work is never replayed. */
|
|
380
|
+
function createPluginReadGate(now = Date.now) {
|
|
381
|
+
let pausedUntil = 0;
|
|
382
|
+
let epoch = 0;
|
|
383
|
+
return {
|
|
384
|
+
canRead: () => now() >= pausedUntil,
|
|
385
|
+
reset: () => {
|
|
386
|
+
epoch++;
|
|
387
|
+
pausedUntil = 0;
|
|
388
|
+
},
|
|
389
|
+
async run(read) {
|
|
390
|
+
const current = epoch;
|
|
391
|
+
try {
|
|
392
|
+
const value = await read();
|
|
393
|
+
if (current === epoch) pausedUntil = 0;
|
|
394
|
+
return value;
|
|
395
|
+
} catch (error) {
|
|
396
|
+
const message = error instanceof Error ? error.message : "";
|
|
397
|
+
if (current === epoch && (/(?:^|\s)transport failure for .+: HTTP (?:404|405|503)\b/.test(message) || error instanceof TypeError && /^(?:Failed to fetch|fetch failed|NetworkError when attempting to fetch resource\.?)$/i.test(message))) pausedUntil = now() + 3e4;
|
|
398
|
+
throw error;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
//#endregion
|
|
404
|
+
//#region src/contracts.ts
|
|
405
|
+
const WEB_SEARCH_RPC_CHANNEL = "/web-search-manager";
|
|
406
|
+
function pickActiveSearch(order, configured) {
|
|
407
|
+
return order.find(configured) ?? "";
|
|
408
|
+
}
|
|
409
|
+
function safeConfigurationUrl(value) {
|
|
410
|
+
if (typeof value !== "string" || !value || /[\u0000-\u0020\\]/.test(value)) return;
|
|
411
|
+
try {
|
|
412
|
+
const url = new URL(value, "https://dsh.invalid");
|
|
413
|
+
if (url.username || url.password) return;
|
|
414
|
+
if (value.startsWith("/") && !value.startsWith("//") || value.startsWith("#")) return url.origin === "https://dsh.invalid" ? value : void 0;
|
|
415
|
+
return /^https:\/\//i.test(value) && url.protocol === "https:" ? value : void 0;
|
|
416
|
+
} catch {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
//#endregion
|
|
378
421
|
//#region src/provider-info.ts
|
|
379
422
|
const PROVIDER_PRICING_CHECKED = "2026-09-21";
|
|
380
423
|
const providerInfo = {
|
|
@@ -419,22 +462,37 @@ const providerInfo = {
|
|
|
419
462
|
pricingUrl: "https://docs.tavily.com/documentation/api-credits"
|
|
420
463
|
}
|
|
421
464
|
};
|
|
422
|
-
function
|
|
423
|
-
|
|
424
|
-
return
|
|
425
|
-
description: known?.description ?? provider.description,
|
|
426
|
-
pricing: provider.pricing ?? known?.pricing ?? (provider.billing === "none" ? "该后端不收取搜索费用。" : provider.billing === "model-and-tools" ? "按模型用量与工具调用计费;额度与单价见供应商说明。" : "按 API 调用计费;额度与单价见供应商说明。"),
|
|
427
|
-
pricingUrl: provider.pricingUrl ?? known?.pricingUrl ?? provider.signupUrl
|
|
428
|
-
};
|
|
465
|
+
function bundledCatalogId(provider) {
|
|
466
|
+
if (!(typeof provider.configurationOwned === "boolean" ? provider.configurationOwned : !provider.configurationOwner || provider.configurationOwner === "@klarkxy/dsh-web-search-manager")) return;
|
|
467
|
+
return provider.id === "deepseek-managed" ? "deepseek-official" : provider.id;
|
|
429
468
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
const WEB_SEARCH_RPC_CHANNEL = "/web-search-manager";
|
|
433
|
-
function resolveSearchOrder(knownIds, settings, _keyed) {
|
|
434
|
-
return [...new Set(settings.searchOrder.filter((id) => knownIds.includes(id)))];
|
|
469
|
+
function missingPricing(locale) {
|
|
470
|
+
return locale === "zh" ? "未提供费用信息" : "No pricing information provided";
|
|
435
471
|
}
|
|
436
|
-
function
|
|
437
|
-
|
|
472
|
+
function usesBundledPricing(provider) {
|
|
473
|
+
if (provider.pricing?.trim()) return false;
|
|
474
|
+
const catalogId = bundledCatalogId(provider);
|
|
475
|
+
return Boolean(catalogId && Object.hasOwn(providerInfo, catalogId));
|
|
476
|
+
}
|
|
477
|
+
function searchProviderInfo(provider, locale = "zh") {
|
|
478
|
+
const catalogId = bundledCatalogId(provider);
|
|
479
|
+
const known = catalogId && Object.hasOwn(providerInfo, catalogId) ? providerInfo[catalogId] : void 0;
|
|
480
|
+
const description = provider.description.trim() ? provider.description : known?.description ?? provider.description;
|
|
481
|
+
if (provider.pricing?.trim()) return {
|
|
482
|
+
description,
|
|
483
|
+
pricing: provider.pricing,
|
|
484
|
+
pricingUrl: provider.pricingUrl ?? known?.pricingUrl ?? provider.signupUrl
|
|
485
|
+
};
|
|
486
|
+
if (known) return {
|
|
487
|
+
description,
|
|
488
|
+
pricing: known.pricing,
|
|
489
|
+
pricingUrl: provider.pricingUrl ?? known.pricingUrl ?? provider.signupUrl
|
|
490
|
+
};
|
|
491
|
+
return {
|
|
492
|
+
description,
|
|
493
|
+
pricing: missingPricing(locale),
|
|
494
|
+
pricingUrl: provider.pricingUrl ?? provider.signupUrl
|
|
495
|
+
};
|
|
438
496
|
}
|
|
439
497
|
//#endregion
|
|
440
498
|
//#region src/client.tsx
|
|
@@ -454,32 +512,129 @@ function editable(settings) {
|
|
|
454
512
|
const { revision: _revision, ...rest } = settings;
|
|
455
513
|
return rest;
|
|
456
514
|
}
|
|
515
|
+
const STATUS_REFRESH_MS = 3e3;
|
|
516
|
+
function isPageHidden(hidden) {
|
|
517
|
+
if (hidden) return true;
|
|
518
|
+
return typeof document !== "undefined" && document.visibilityState === "hidden";
|
|
519
|
+
}
|
|
520
|
+
function canStartStatusRead(input) {
|
|
521
|
+
if (!input.mounted) return false;
|
|
522
|
+
if (input.source === "poll") return !input.hidden && !input.busy && !input.reordering && !input.reading;
|
|
523
|
+
return true;
|
|
524
|
+
}
|
|
525
|
+
function isExternalConfigurationUrl(url) {
|
|
526
|
+
return /^https:\/\//i.test(url);
|
|
527
|
+
}
|
|
528
|
+
function shouldApplyPolledStatus(input) {
|
|
529
|
+
if (input.hidden || input.busy || input.reordering) return false;
|
|
530
|
+
if (input.requestId !== input.latestRequestId) return false;
|
|
531
|
+
if (input.currentRevision !== void 0 && input.incomingRevision < input.currentRevision) return false;
|
|
532
|
+
return true;
|
|
533
|
+
}
|
|
534
|
+
function bindStatusRefresh(options) {
|
|
535
|
+
const intervalMs = options.intervalMs ?? 3e3;
|
|
536
|
+
let inFlight = false;
|
|
537
|
+
let stopped = false;
|
|
538
|
+
const run = async () => {
|
|
539
|
+
if (stopped || inFlight || options.isHidden()) return;
|
|
540
|
+
inFlight = true;
|
|
541
|
+
try {
|
|
542
|
+
await options.tick();
|
|
543
|
+
} finally {
|
|
544
|
+
inFlight = false;
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
const timer = (options.setIntervalFn ?? setInterval)(() => {
|
|
548
|
+
run();
|
|
549
|
+
}, intervalMs);
|
|
550
|
+
const onVisible = () => {
|
|
551
|
+
if (!options.isHidden()) run();
|
|
552
|
+
};
|
|
553
|
+
const add = options.addListener ?? ((type, listener) => {
|
|
554
|
+
if (typeof document !== "undefined") document.addEventListener(type, listener);
|
|
555
|
+
});
|
|
556
|
+
const remove = options.removeListener ?? ((type, listener) => {
|
|
557
|
+
if (typeof document !== "undefined") document.removeEventListener(type, listener);
|
|
558
|
+
});
|
|
559
|
+
add("visibilitychange", onVisible);
|
|
560
|
+
return () => {
|
|
561
|
+
stopped = true;
|
|
562
|
+
(options.clearIntervalFn ?? clearInterval)(timer);
|
|
563
|
+
remove("visibilitychange", onVisible);
|
|
564
|
+
};
|
|
565
|
+
}
|
|
457
566
|
function isProviderOn(status, provider) {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
return enabled && selected === provider.id;
|
|
567
|
+
if (provider.kind === "fetch") return status.fetchActive && status.settings.fetchProvider === provider.id && provider.configured;
|
|
568
|
+
return status.searchActive && selectedSearchBackend(status)?.id === provider.id;
|
|
461
569
|
}
|
|
462
|
-
function
|
|
463
|
-
|
|
464
|
-
|
|
570
|
+
function dormantSearchPlaceholder(id) {
|
|
571
|
+
return {
|
|
572
|
+
id,
|
|
573
|
+
label: id,
|
|
574
|
+
description: "",
|
|
575
|
+
billing: "unknown",
|
|
576
|
+
kind: "search",
|
|
577
|
+
configured: false,
|
|
578
|
+
calls: 0,
|
|
579
|
+
failures: 0,
|
|
580
|
+
configurationOwned: false
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
function isRegisteredSearch(status, id) {
|
|
584
|
+
return status.providers.some((provider) => provider.kind === "search" && provider.id === id);
|
|
465
585
|
}
|
|
466
586
|
function catalogSearchBackends(status) {
|
|
467
|
-
const
|
|
468
|
-
const
|
|
469
|
-
|
|
587
|
+
const byId = new Map(status.providers.filter((provider) => provider.kind === "search").map((provider) => [provider.id, provider]));
|
|
588
|
+
const rows = [];
|
|
589
|
+
const seen = /* @__PURE__ */ new Set();
|
|
590
|
+
for (const id of status.settings.searchOrder) {
|
|
591
|
+
if (!id || seen.has(id)) continue;
|
|
592
|
+
seen.add(id);
|
|
593
|
+
rows.push(byId.get(id) ?? dormantSearchPlaceholder(id));
|
|
594
|
+
}
|
|
595
|
+
for (const provider of status.providers) {
|
|
596
|
+
if (provider.kind !== "search" || seen.has(provider.id)) continue;
|
|
597
|
+
rows.push(provider);
|
|
598
|
+
}
|
|
599
|
+
return rows;
|
|
600
|
+
}
|
|
601
|
+
function searchBackends(status) {
|
|
602
|
+
const participating = new Set(status.settings.searchOrder);
|
|
603
|
+
return catalogSearchBackends(status).filter((provider) => participating.has(provider.id));
|
|
470
604
|
}
|
|
471
605
|
function selectedSearchBackend(status) {
|
|
472
|
-
const backends = searchBackends(status);
|
|
606
|
+
const backends = searchBackends(status).filter((provider) => isRegisteredSearch(status, provider.id));
|
|
473
607
|
const id = pickActiveSearch(backends.map((provider) => provider.id), (id) => Boolean(backends.find((provider) => provider.id === id)?.configured));
|
|
474
608
|
return backends.find((provider) => provider.id === id);
|
|
475
609
|
}
|
|
476
|
-
function
|
|
610
|
+
function droppedDormantIds(settings, order, providers) {
|
|
611
|
+
const known = new Set(providers.filter((provider) => provider.kind === "search").map((provider) => provider.id));
|
|
612
|
+
return [...new Set(settings.searchOrder.filter((id) => id && !known.has(id) && !order.includes(id)))];
|
|
613
|
+
}
|
|
614
|
+
function configurationAccess(provider) {
|
|
615
|
+
if (ownsProviderConfiguration(provider)) return { kind: "owned" };
|
|
616
|
+
const url = safeConfigurationUrl(provider.configurationUrl);
|
|
617
|
+
if (url) return {
|
|
618
|
+
kind: "link",
|
|
619
|
+
url
|
|
620
|
+
};
|
|
621
|
+
if (provider.configurationOwner?.trim()) return {
|
|
622
|
+
kind: "owner",
|
|
623
|
+
name: provider.configurationOwner
|
|
624
|
+
};
|
|
625
|
+
return { kind: "unknown" };
|
|
626
|
+
}
|
|
627
|
+
function AppLink({ url, label, children }) {
|
|
628
|
+
const external = isExternalConfigurationUrl(url);
|
|
477
629
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
478
630
|
href: url,
|
|
479
|
-
|
|
480
|
-
|
|
631
|
+
...external ? {
|
|
632
|
+
target: "_blank",
|
|
633
|
+
rel: "noreferrer noopener"
|
|
634
|
+
} : {},
|
|
481
635
|
"aria-label": label,
|
|
482
636
|
onClick: (event) => {
|
|
637
|
+
if (!external) return;
|
|
483
638
|
const bridge = globalThis.dshWindow;
|
|
484
639
|
if (bridge?.openExternal) {
|
|
485
640
|
event.preventDefault();
|
|
@@ -495,9 +650,13 @@ function canEnableSearch(order, providers, keys, writable) {
|
|
|
495
650
|
if (!provider) return false;
|
|
496
651
|
if (provider.configured) return true;
|
|
497
652
|
const typed = (keys[provider.id] ?? "").trim();
|
|
498
|
-
return Boolean(provider.credentialRef && typed && writable[provider.credentialRef] !== false);
|
|
653
|
+
return Boolean(ownsProviderConfiguration(provider) && provider.credentialRef && typed && writable[provider.credentialRef] !== false);
|
|
499
654
|
});
|
|
500
655
|
}
|
|
656
|
+
function ownsProviderConfiguration(provider) {
|
|
657
|
+
if (typeof provider.configurationOwned === "boolean") return provider.configurationOwned;
|
|
658
|
+
return !provider.configurationOwner || provider.configurationOwner === "@klarkxy/dsh-web-search-manager";
|
|
659
|
+
}
|
|
501
660
|
function nextSearchEnabled(currentlyEnabled, nextOrder, providers, keys, writable) {
|
|
502
661
|
return currentlyEnabled && canEnableSearch(nextOrder, providers, keys, writable);
|
|
503
662
|
}
|
|
@@ -549,11 +708,14 @@ const copy = {
|
|
|
549
708
|
dragPrefix: "拖动排序 ",
|
|
550
709
|
dragHint: "拖动排序,或用上下方向键",
|
|
551
710
|
inUse: "当前使用",
|
|
711
|
+
available: "可用",
|
|
712
|
+
unavailable: "暂不可用",
|
|
713
|
+
dormant: "未加载,保留选择",
|
|
552
714
|
signup: "去注册",
|
|
553
715
|
pricing: "费用说明",
|
|
554
716
|
website: "官网",
|
|
717
|
+
openConfig: "打开配置",
|
|
555
718
|
needsKey: "待配置 Key",
|
|
556
|
-
unavailable: "暂不可用",
|
|
557
719
|
sharedKey: "与其他设置共用凭据",
|
|
558
720
|
keyConfigured: "已配置,留空不替换",
|
|
559
721
|
keyPlaceholder: "输入 API Key",
|
|
@@ -567,7 +729,11 @@ const copy = {
|
|
|
567
729
|
maxResults: "每条查询结果上限",
|
|
568
730
|
maxQueries: "每次调用查询上限",
|
|
569
731
|
timeoutMs: "请求超时(毫秒)",
|
|
570
|
-
maxFetchChars: "正文字符上限"
|
|
732
|
+
maxFetchChars: "正文字符上限",
|
|
733
|
+
fetchTitle: "网页读取",
|
|
734
|
+
fetchProvider: "读取服务",
|
|
735
|
+
ownerSettings: "配置入口:",
|
|
736
|
+
unknownOwner: "请在服务所属插件中配置"
|
|
571
737
|
},
|
|
572
738
|
en: {
|
|
573
739
|
tabsLabel: "Web search settings",
|
|
@@ -589,11 +755,14 @@ const copy = {
|
|
|
589
755
|
dragPrefix: "Reorder ",
|
|
590
756
|
dragHint: "Drag to reorder, or use arrow keys",
|
|
591
757
|
inUse: "In use",
|
|
758
|
+
available: "Available",
|
|
759
|
+
unavailable: "Unavailable",
|
|
760
|
+
dormant: "Not loaded; selection kept",
|
|
592
761
|
signup: "Sign up",
|
|
593
762
|
pricing: "Pricing",
|
|
594
763
|
website: "Website",
|
|
764
|
+
openConfig: "Open configuration",
|
|
595
765
|
needsKey: "Key required",
|
|
596
|
-
unavailable: "Unavailable",
|
|
597
766
|
sharedKey: "Shares a credential with other settings",
|
|
598
767
|
keyConfigured: "Configured; empty keeps it",
|
|
599
768
|
keyPlaceholder: "Enter API key",
|
|
@@ -607,14 +776,18 @@ const copy = {
|
|
|
607
776
|
maxResults: "Max results/query",
|
|
608
777
|
maxQueries: "Max queries/call",
|
|
609
778
|
timeoutMs: "Request timeout (ms)",
|
|
610
|
-
maxFetchChars: "Max text chars"
|
|
779
|
+
maxFetchChars: "Max text chars",
|
|
780
|
+
fetchTitle: "Read web pages",
|
|
781
|
+
fetchProvider: "Fetch service",
|
|
782
|
+
ownerSettings: "Configure in: ",
|
|
783
|
+
unknownOwner: "Configure this service in its plugin"
|
|
611
784
|
}
|
|
612
785
|
};
|
|
613
786
|
function movedText(locale, label, position) {
|
|
614
787
|
return locale === "zh" ? `${label} 已移至第 ${position} 位` : `${label} moved to position ${position}`;
|
|
615
788
|
}
|
|
616
789
|
function pricingCheckedText(locale, date) {
|
|
617
|
-
return locale === "zh" ?
|
|
790
|
+
return locale === "zh" ? `内置适配器价格核对于 ${date},额度与费用以供应商账户为准。` : `Bundled adapter prices checked on ${date}; your provider account is authoritative.`;
|
|
618
791
|
}
|
|
619
792
|
function testOkText(locale, sources) {
|
|
620
793
|
return locale === "zh" ? `连接正常,返回 ${sources} 条来源。` : `Connection OK: ${sources} sources returned.`;
|
|
@@ -655,13 +828,25 @@ function parseLimit(raw, min, max) {
|
|
|
655
828
|
* Settings written by an immediate action (a switch or a reorder). It keeps the
|
|
656
829
|
* saved limits and never includes typed-but-unsaved keys or limit drafts.
|
|
657
830
|
*/
|
|
658
|
-
function immediateUpdate(settings, on, order) {
|
|
831
|
+
function immediateUpdate(settings, on, order, providers, remove = []) {
|
|
832
|
+
let searchOrder = order;
|
|
833
|
+
if (providers) {
|
|
834
|
+
const known = new Set(providers.filter((provider) => provider.kind === "search").map((provider) => provider.id));
|
|
835
|
+
const removed = new Set(remove);
|
|
836
|
+
const following = order.filter((id) => !removed.has(id));
|
|
837
|
+
if (following.some((id) => !known.has(id))) searchOrder = following;
|
|
838
|
+
else {
|
|
839
|
+
searchOrder = settings.searchOrder.flatMap((id) => {
|
|
840
|
+
if (removed.has(id)) return [];
|
|
841
|
+
return known.has(id) ? following.splice(0, 1) : [id];
|
|
842
|
+
});
|
|
843
|
+
searchOrder.push(...following);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
659
846
|
return {
|
|
660
847
|
...editable(settings),
|
|
661
|
-
searchOrder
|
|
662
|
-
searchEnabled: on
|
|
663
|
-
fetchProvider: "http",
|
|
664
|
-
fetchEnabled: on
|
|
848
|
+
searchOrder,
|
|
849
|
+
searchEnabled: on
|
|
665
850
|
};
|
|
666
851
|
}
|
|
667
852
|
function limitTexts(settings) {
|
|
@@ -679,7 +864,7 @@ function useHostLocale(client) {
|
|
|
679
864
|
}
|
|
680
865
|
/** Keyboard reorders are batched: persist once the arrows stop for this long. */
|
|
681
866
|
const REORDER_DEBOUNCE_MS = 500;
|
|
682
|
-
function NetworkSearchSettings({ client }) {
|
|
867
|
+
function NetworkSearchSettings({ client, hidden }) {
|
|
683
868
|
const locale = useHostLocale(client);
|
|
684
869
|
const text = copy[locale];
|
|
685
870
|
const tabsId = (0, react.useId)();
|
|
@@ -703,6 +888,17 @@ function NetworkSearchSettings({ client }) {
|
|
|
703
888
|
const timerRef = (0, react.useRef)(void 0);
|
|
704
889
|
const handleRefs = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
705
890
|
const refocusRef = (0, react.useRef)(null);
|
|
891
|
+
const busyRef = (0, react.useRef)(false);
|
|
892
|
+
const hiddenRef = (0, react.useRef)(hidden);
|
|
893
|
+
hiddenRef.current = hidden;
|
|
894
|
+
const requestSeq = (0, react.useRef)(0);
|
|
895
|
+
const mountedRef = (0, react.useRef)(true);
|
|
896
|
+
const readingRef = (0, react.useRef)(false);
|
|
897
|
+
const readingRequest = (0, react.useRef)(0);
|
|
898
|
+
const statusRead = (0, react.useRef)(Promise.resolve());
|
|
899
|
+
const readGateRef = (0, react.useRef)(void 0);
|
|
900
|
+
if (!readGateRef.current) readGateRef.current = createPluginReadGate();
|
|
901
|
+
const readGate = readGateRef.current;
|
|
706
902
|
async function call(endpoint, payload = {}) {
|
|
707
903
|
return unwrap(await client.connection.rpc.call(WEB_SEARCH_RPC_CHANNEL, endpoint, payload));
|
|
708
904
|
}
|
|
@@ -718,30 +914,109 @@ function NetworkSearchSettings({ client }) {
|
|
|
718
914
|
});
|
|
719
915
|
if (resetDraft) setInvalid({});
|
|
720
916
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
917
|
+
function pollBlocked() {
|
|
918
|
+
return !canStartStatusRead({
|
|
919
|
+
source: "poll",
|
|
920
|
+
mounted: mountedRef.current,
|
|
921
|
+
hidden: isPageHidden(hiddenRef.current),
|
|
922
|
+
busy: busyRef.current,
|
|
923
|
+
reordering: pendingRef.current !== null,
|
|
924
|
+
reading: readingRef.current
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
async function describeOwned(next, mine) {
|
|
928
|
+
const refs = next.providers.flatMap((provider) => ownsProviderConfiguration(provider) && provider.credentialRef ? [provider.credentialRef] : []);
|
|
929
|
+
if (!refs.length) return;
|
|
930
|
+
const credentials = unwrap(await readGate.run(() => client.remote.credentials.describe(refs)));
|
|
931
|
+
if (!mountedRef.current || mine !== requestSeq.current) return;
|
|
932
|
+
setWritable(Object.fromEntries(Object.entries(credentials).map(([ref, value]) => [ref, value.writable])));
|
|
933
|
+
}
|
|
934
|
+
async function load(resetDraft = false, source = "user") {
|
|
935
|
+
if (source === "poll" && !readGate.canRead()) return;
|
|
936
|
+
if (source === "user") {
|
|
937
|
+
readGate.reset();
|
|
938
|
+
requestSeq.current += 1;
|
|
939
|
+
}
|
|
940
|
+
while (readingRef.current) {
|
|
941
|
+
if (source === "poll" || !mountedRef.current) return;
|
|
942
|
+
await statusRead.current;
|
|
943
|
+
}
|
|
944
|
+
if (!mountedRef.current) return;
|
|
945
|
+
if (source === "poll" && pollBlocked()) return;
|
|
946
|
+
const mine = ++requestSeq.current;
|
|
947
|
+
readingRef.current = true;
|
|
948
|
+
readingRequest.current = mine;
|
|
949
|
+
let release = () => {};
|
|
950
|
+
statusRead.current = new Promise((resolve) => {
|
|
951
|
+
release = resolve;
|
|
952
|
+
});
|
|
953
|
+
try {
|
|
954
|
+
const next = unwrap(await readGate.run(() => client.connection.rpc.call(WEB_SEARCH_RPC_CHANNEL, "status", {})));
|
|
955
|
+
if (!mountedRef.current || mine !== requestSeq.current) return next;
|
|
956
|
+
if (source === "poll" && !shouldApplyPolledStatus({
|
|
957
|
+
requestId: mine,
|
|
958
|
+
latestRequestId: requestSeq.current,
|
|
959
|
+
busy: busyRef.current,
|
|
960
|
+
reordering: pendingRef.current !== null,
|
|
961
|
+
hidden: isPageHidden(hiddenRef.current),
|
|
962
|
+
currentRevision: statusRef.current?.settings.revision,
|
|
963
|
+
incomingRevision: next.settings.revision
|
|
964
|
+
})) return next;
|
|
965
|
+
adopt(next, resetDraft);
|
|
966
|
+
setLoadError("");
|
|
967
|
+
await describeOwned(next, mine);
|
|
968
|
+
return next;
|
|
969
|
+
} catch (cause) {
|
|
970
|
+
if (!mountedRef.current || mine !== requestSeq.current) return;
|
|
971
|
+
setLoadError(cause instanceof Error && cause.message ? cause.message : text.failed);
|
|
972
|
+
if (source === "poll") return;
|
|
973
|
+
throw cause;
|
|
974
|
+
} finally {
|
|
975
|
+
if (readingRequest.current === mine) readingRef.current = false;
|
|
976
|
+
release();
|
|
729
977
|
}
|
|
730
|
-
return next;
|
|
731
978
|
}
|
|
732
979
|
(0, react.useEffect)(() => {
|
|
980
|
+
mountedRef.current = true;
|
|
981
|
+
readGate.reset();
|
|
733
982
|
load().catch((cause) => setLoadError(cause instanceof Error && cause.message ? cause.message : text.failed));
|
|
983
|
+
const bind = () => bindStatusRefresh({
|
|
984
|
+
isHidden: () => isPageHidden(hiddenRef.current),
|
|
985
|
+
tick: async () => {
|
|
986
|
+
await load(false, "poll").catch(() => {});
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
let stop = bind();
|
|
990
|
+
const stopConnection = client.connection.generation?.subscribe(() => {
|
|
991
|
+
readGate.reset();
|
|
992
|
+
requestSeq.current += 1;
|
|
993
|
+
readingRef.current = false;
|
|
994
|
+
statusRead.current = Promise.resolve();
|
|
995
|
+
stop();
|
|
996
|
+
stop = bind();
|
|
997
|
+
load(false, "poll");
|
|
998
|
+
});
|
|
999
|
+
return () => {
|
|
1000
|
+
mountedRef.current = false;
|
|
1001
|
+
readGate.reset();
|
|
1002
|
+
requestSeq.current += 1;
|
|
1003
|
+
stop();
|
|
1004
|
+
stopConnection?.();
|
|
1005
|
+
if (timerRef.current === void 0) return;
|
|
1006
|
+
clearTimeout(timerRef.current);
|
|
1007
|
+
const current = statusRef.current;
|
|
1008
|
+
const next = pendingRef.current;
|
|
1009
|
+
if (current && next) call("update", {
|
|
1010
|
+
settings: immediateUpdate(current.settings, current.settings.searchEnabled, next, current.providers),
|
|
1011
|
+
expectedRevision: current.settings.revision
|
|
1012
|
+
}).catch(() => {});
|
|
1013
|
+
};
|
|
734
1014
|
}, [client]);
|
|
735
|
-
(0, react.useEffect)(() =>
|
|
736
|
-
if (
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
if (current && next) call("update", {
|
|
741
|
-
settings: immediateUpdate(current.settings, current.settings.searchEnabled, next),
|
|
742
|
-
expectedRevision: current.settings.revision
|
|
743
|
-
}).catch(() => {});
|
|
744
|
-
}, []);
|
|
1015
|
+
(0, react.useEffect)(() => {
|
|
1016
|
+
if (hidden) return;
|
|
1017
|
+
if (!statusRef.current) return;
|
|
1018
|
+
load(false, "poll").catch(() => {});
|
|
1019
|
+
}, [hidden]);
|
|
745
1020
|
(0, react.useLayoutEffect)(() => {
|
|
746
1021
|
const id = refocusRef.current;
|
|
747
1022
|
if (!id) return;
|
|
@@ -750,6 +1025,9 @@ function NetworkSearchSettings({ client }) {
|
|
|
750
1025
|
if (handle && document.activeElement !== handle) handle.focus();
|
|
751
1026
|
});
|
|
752
1027
|
async function action(run) {
|
|
1028
|
+
readGate.reset();
|
|
1029
|
+
requestSeq.current += 1;
|
|
1030
|
+
busyRef.current = true;
|
|
753
1031
|
setBusy(true);
|
|
754
1032
|
setNote("");
|
|
755
1033
|
setError("");
|
|
@@ -759,11 +1037,12 @@ function NetworkSearchSettings({ client }) {
|
|
|
759
1037
|
setError(cause instanceof Error && cause.message ? cause.message : text.failed);
|
|
760
1038
|
await load().catch(() => {});
|
|
761
1039
|
} finally {
|
|
1040
|
+
busyRef.current = false;
|
|
762
1041
|
setBusy(false);
|
|
763
1042
|
}
|
|
764
1043
|
}
|
|
765
1044
|
/** Switches and reorders: settings only, applied at once. */
|
|
766
|
-
function runImmediate(on, order) {
|
|
1045
|
+
function runImmediate(on, order, remove = []) {
|
|
767
1046
|
clearTimeout(timerRef.current);
|
|
768
1047
|
timerRef.current = void 0;
|
|
769
1048
|
pendingRef.current = null;
|
|
@@ -771,7 +1050,7 @@ function NetworkSearchSettings({ client }) {
|
|
|
771
1050
|
const current = statusRef.current;
|
|
772
1051
|
if (!current) return;
|
|
773
1052
|
const next = await call("update", {
|
|
774
|
-
settings: immediateUpdate(current.settings, on, order),
|
|
1053
|
+
settings: immediateUpdate(current.settings, on, order, current.providers, remove),
|
|
775
1054
|
expectedRevision: current.settings.revision
|
|
776
1055
|
});
|
|
777
1056
|
setStatus(next);
|
|
@@ -787,7 +1066,7 @@ function NetworkSearchSettings({ client }) {
|
|
|
787
1066
|
if (provider.kind !== "search" || only && provider.id !== only.id) continue;
|
|
788
1067
|
const snapshot = keys[provider.id] ?? "";
|
|
789
1068
|
const typed = snapshot.trim();
|
|
790
|
-
if (!provider.credentialRef || !typed) continue;
|
|
1069
|
+
if (!ownsProviderConfiguration(provider) || !provider.credentialRef || !typed) continue;
|
|
791
1070
|
if (writable[provider.credentialRef] === false) throw new Error(text.readOnly);
|
|
792
1071
|
unwrap(await client.remote.credentials.set(provider.credentialRef, typed));
|
|
793
1072
|
setKeys((current) => current[provider.id] === snapshot ? {
|
|
@@ -797,7 +1076,7 @@ function NetworkSearchSettings({ client }) {
|
|
|
797
1076
|
}
|
|
798
1077
|
}
|
|
799
1078
|
async function removeKey(provider) {
|
|
800
|
-
if (!provider.credentialRef || provider.credentialShared || !status) return;
|
|
1079
|
+
if (!ownsProviderConfiguration(provider) || !provider.credentialRef || provider.credentialShared || !status) return;
|
|
801
1080
|
unwrap(await client.remote.credentials.unset(provider.credentialRef));
|
|
802
1081
|
setKeys((current) => ({
|
|
803
1082
|
...current,
|
|
@@ -886,9 +1165,7 @@ function NetworkSearchSettings({ client }) {
|
|
|
886
1165
|
adopt(await call("update", {
|
|
887
1166
|
settings: {
|
|
888
1167
|
...editable(current.settings),
|
|
889
|
-
...parsed
|
|
890
|
-
fetchProvider: "http",
|
|
891
|
-
fetchEnabled: current.settings.searchEnabled
|
|
1168
|
+
...parsed
|
|
892
1169
|
},
|
|
893
1170
|
expectedRevision: current.settings.revision
|
|
894
1171
|
}), true);
|
|
@@ -927,6 +1204,22 @@ function NetworkSearchSettings({ client }) {
|
|
|
927
1204
|
className: "dsh-ui-error",
|
|
928
1205
|
children: error
|
|
929
1206
|
}),
|
|
1207
|
+
loadError ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1208
|
+
className: "dsh-ui-stack",
|
|
1209
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1210
|
+
role: "alert",
|
|
1211
|
+
className: "dsh-ui-error",
|
|
1212
|
+
children: [text.loadFailed, loadError]
|
|
1213
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1214
|
+
variant: "outline",
|
|
1215
|
+
size: "sm",
|
|
1216
|
+
disabled: busy,
|
|
1217
|
+
onClick: () => void action(async () => {
|
|
1218
|
+
await load();
|
|
1219
|
+
}),
|
|
1220
|
+
children: text.reconnect
|
|
1221
|
+
})]
|
|
1222
|
+
}) : null,
|
|
930
1223
|
note && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
931
1224
|
role: "status",
|
|
932
1225
|
className: "dsh-ui-notice",
|
|
@@ -937,13 +1230,13 @@ function NetworkSearchSettings({ client }) {
|
|
|
937
1230
|
className: "dsh-ui-banner dsh-ui-banner--danger",
|
|
938
1231
|
children: text.storageFailed
|
|
939
1232
|
}),
|
|
940
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1233
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
941
1234
|
role: "tabpanel",
|
|
942
1235
|
id: tabsId + "-providers-panel",
|
|
943
1236
|
"aria-labelledby": tabsId + "-providers-tab",
|
|
944
1237
|
hidden: tab !== "providers",
|
|
945
1238
|
tabIndex: 0,
|
|
946
|
-
children: backends.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1239
|
+
children: [backends.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
947
1240
|
className: "dsh-ui-empty",
|
|
948
1241
|
children: text.empty
|
|
949
1242
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
@@ -972,17 +1265,23 @@ function NetworkSearchSettings({ client }) {
|
|
|
972
1265
|
children: backends.map((provider) => {
|
|
973
1266
|
const participating = order.includes(provider.id);
|
|
974
1267
|
const rank = order.indexOf(provider.id);
|
|
975
|
-
const
|
|
976
|
-
const
|
|
977
|
-
const
|
|
1268
|
+
const dormant = !isRegisteredSearch(saved, provider.id);
|
|
1269
|
+
const active = !dormant && saved.searchActive && selected?.id === provider.id;
|
|
1270
|
+
const info = searchProviderInfo(provider, locale);
|
|
1271
|
+
const owned = ownsProviderConfiguration(provider);
|
|
1272
|
+
const access = configurationAccess(provider);
|
|
1273
|
+
const needsKey = owned && Boolean(provider.credentialRef);
|
|
978
1274
|
const shared = Boolean(provider.credentialShared);
|
|
979
|
-
const showKey = needsKey && participating && (!shared || !provider.configured);
|
|
1275
|
+
const showKey = !dormant && needsKey && participating && (!shared || !provider.configured);
|
|
980
1276
|
const canSort = participating && order.length > 1;
|
|
981
1277
|
const readOnly = writable[provider.credentialRef ?? ""] === false;
|
|
982
1278
|
const typedKey = (keys[provider.id] ?? "").trim();
|
|
1279
|
+
const availability = dormant ? "dormant" : provider.configured ? "available" : "unavailable";
|
|
983
1280
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
984
1281
|
className: active ? "is-active" : void 0,
|
|
985
1282
|
"data-testid": `web-search-rank-${provider.id}`,
|
|
1283
|
+
"data-availability": availability,
|
|
1284
|
+
"data-in-use": active || void 0,
|
|
986
1285
|
"data-dragging": dragSource === provider.id || void 0,
|
|
987
1286
|
"data-drop": dropTarget === provider.id && dragSource ? order.indexOf(dragSource) < rank ? "after" : "before" : void 0,
|
|
988
1287
|
onDragOver: (event) => {
|
|
@@ -1084,11 +1383,15 @@ function NetworkSearchSettings({ client }) {
|
|
|
1084
1383
|
className: "dsh-ui-heading",
|
|
1085
1384
|
children: provider.label
|
|
1086
1385
|
}),
|
|
1386
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1387
|
+
className: "ws-provider-note",
|
|
1388
|
+
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 })]
|
|
1389
|
+
}),
|
|
1087
1390
|
active && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1088
1391
|
tone: "success",
|
|
1089
1392
|
children: text.inUse
|
|
1090
1393
|
}),
|
|
1091
|
-
provider.signupUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
1394
|
+
provider.signupUrl && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppLink, {
|
|
1092
1395
|
url: provider.signupUrl,
|
|
1093
1396
|
label: provider.label + " " + text.signup,
|
|
1094
1397
|
children: text.signup
|
|
@@ -1097,20 +1400,30 @@ function NetworkSearchSettings({ client }) {
|
|
|
1097
1400
|
}),
|
|
1098
1401
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1099
1402
|
className: "web-search-provider-info",
|
|
1100
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: info.description }), /* @__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)(
|
|
1403
|
+
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, {
|
|
1101
1404
|
url: info.pricingUrl,
|
|
1102
1405
|
label: provider.label + " " + text.pricing,
|
|
1103
1406
|
children: provider.id === "ddg" ? text.website : text.pricing
|
|
1104
1407
|
})] })] })]
|
|
1105
1408
|
}),
|
|
1106
|
-
|
|
1107
|
-
className: "
|
|
1108
|
-
children:
|
|
1409
|
+
access.kind === "link" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1410
|
+
className: "dsh-ui-hint",
|
|
1411
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppLink, {
|
|
1412
|
+
url: access.url,
|
|
1413
|
+
label: text.openConfig,
|
|
1414
|
+
children: text.openConfig
|
|
1415
|
+
})
|
|
1416
|
+
}) : access.kind === "owner" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1417
|
+
className: "dsh-ui-hint",
|
|
1418
|
+
children: [text.ownerSettings, access.name]
|
|
1419
|
+
}) : access.kind === "unknown" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1420
|
+
className: "dsh-ui-hint",
|
|
1421
|
+
children: text.unknownOwner
|
|
1109
1422
|
}) : null,
|
|
1110
|
-
shared && participating && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
|
|
1423
|
+
shared && participating && owned ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
|
|
1111
1424
|
className: "dsh-ui-meta",
|
|
1112
1425
|
children: provider.credentialHint ?? text.sharedKey
|
|
1113
|
-
}),
|
|
1426
|
+
}) : null,
|
|
1114
1427
|
showKey ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1115
1428
|
className: "dsh-ui-field",
|
|
1116
1429
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -1159,7 +1472,7 @@ function NetworkSearchSettings({ client }) {
|
|
|
1159
1472
|
disabled: busy,
|
|
1160
1473
|
onChange: (next) => {
|
|
1161
1474
|
const following = next ? [...order, provider.id] : order.filter((id) => id !== provider.id);
|
|
1162
|
-
runImmediate(nextSearchEnabled(saved.settings.searchEnabled, following, saved.providers, {}, writable), following);
|
|
1475
|
+
runImmediate(nextSearchEnabled(saved.settings.searchEnabled, following, saved.providers, {}, writable), following, droppedDormantIds(saved.settings, following, saved.providers));
|
|
1163
1476
|
}
|
|
1164
1477
|
})
|
|
1165
1478
|
})
|
|
@@ -1167,10 +1480,10 @@ function NetworkSearchSettings({ client }) {
|
|
|
1167
1480
|
}, provider.id);
|
|
1168
1481
|
})
|
|
1169
1482
|
}),
|
|
1170
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1483
|
+
backends.some(usesBundledPricing) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1171
1484
|
className: "dsh-ui-hint",
|
|
1172
1485
|
children: pricingCheckedText(locale, PROVIDER_PRICING_CHECKED)
|
|
1173
|
-
}),
|
|
1486
|
+
}) : null,
|
|
1174
1487
|
on ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1175
1488
|
className: "dsh-ui-actions",
|
|
1176
1489
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
@@ -1187,7 +1500,104 @@ function NetworkSearchSettings({ client }) {
|
|
|
1187
1500
|
})
|
|
1188
1501
|
}) : null
|
|
1189
1502
|
]
|
|
1190
|
-
})
|
|
1503
|
+
}), (saved.providers.some((provider) => provider.kind === "fetch") || saved.settings.fetchProvider) && (() => {
|
|
1504
|
+
const fetchId = saved.settings.fetchProvider;
|
|
1505
|
+
const fetchSelected = saved.providers.find((provider) => provider.kind === "fetch" && provider.id === fetchId);
|
|
1506
|
+
const fetchDormant = Boolean(fetchId) && !fetchSelected;
|
|
1507
|
+
const fetchActive = Boolean(fetchSelected && saved.fetchActive && fetchSelected.configured);
|
|
1508
|
+
const fetchAccess = fetchSelected ? configurationAccess(fetchSelected) : fetchDormant ? { kind: "unknown" } : void 0;
|
|
1509
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
1510
|
+
className: "dsh-ui-card dsh-ui-card--flat",
|
|
1511
|
+
"data-testid": "web-search-fetch",
|
|
1512
|
+
"data-availability": fetchDormant ? "dormant" : fetchSelected?.configured ? "available" : "unavailable",
|
|
1513
|
+
"data-in-use": fetchActive || void 0,
|
|
1514
|
+
children: [
|
|
1515
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
1516
|
+
className: "ws-card-head",
|
|
1517
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1518
|
+
className: "dsh-ui-title",
|
|
1519
|
+
children: text.fetchTitle
|
|
1520
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1521
|
+
className: "ws-provider-note",
|
|
1522
|
+
children: [
|
|
1523
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: fetchDormant ? "idle" : fetchSelected?.configured ? "done" : "warning" }),
|
|
1524
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fetchDormant ? text.dormant : fetchSelected?.configured ? text.available : text.unavailable }),
|
|
1525
|
+
fetchActive ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
|
|
1526
|
+
tone: "success",
|
|
1527
|
+
children: text.inUse
|
|
1528
|
+
}) : null
|
|
1529
|
+
]
|
|
1530
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
1531
|
+
checked: saved.settings.fetchEnabled,
|
|
1532
|
+
label: text.fetchTitle,
|
|
1533
|
+
disabled: busy || reordering,
|
|
1534
|
+
onChange: (next) => void action(async () => {
|
|
1535
|
+
const current = statusRef.current;
|
|
1536
|
+
adopt(await call("update", {
|
|
1537
|
+
settings: {
|
|
1538
|
+
...editable(current.settings),
|
|
1539
|
+
fetchEnabled: next
|
|
1540
|
+
},
|
|
1541
|
+
expectedRevision: current.settings.revision
|
|
1542
|
+
}));
|
|
1543
|
+
await load();
|
|
1544
|
+
})
|
|
1545
|
+
})]
|
|
1546
|
+
}),
|
|
1547
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1548
|
+
className: "dsh-ui-field",
|
|
1549
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1550
|
+
className: "dsh-ui-label",
|
|
1551
|
+
children: text.fetchProvider
|
|
1552
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
1553
|
+
className: "dsh-ui-select",
|
|
1554
|
+
"aria-label": text.fetchProvider,
|
|
1555
|
+
value: fetchId,
|
|
1556
|
+
disabled: busy || reordering,
|
|
1557
|
+
onChange: (event) => {
|
|
1558
|
+
const id = event.target.value;
|
|
1559
|
+
action(async () => {
|
|
1560
|
+
const current = statusRef.current;
|
|
1561
|
+
adopt(await call("update", {
|
|
1562
|
+
settings: {
|
|
1563
|
+
...editable(current.settings),
|
|
1564
|
+
fetchProvider: id
|
|
1565
|
+
},
|
|
1566
|
+
expectedRevision: current.settings.revision
|
|
1567
|
+
}));
|
|
1568
|
+
await load();
|
|
1569
|
+
});
|
|
1570
|
+
},
|
|
1571
|
+
children: [fetchDormant && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
1572
|
+
value: fetchId,
|
|
1573
|
+
children: [
|
|
1574
|
+
fetchId,
|
|
1575
|
+
" · ",
|
|
1576
|
+
text.dormant
|
|
1577
|
+
]
|
|
1578
|
+
}), saved.providers.filter((provider) => provider.kind === "fetch").map((provider) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
1579
|
+
value: provider.id,
|
|
1580
|
+
children: [provider.label, provider.configured ? "" : " · " + text.unavailable]
|
|
1581
|
+
}, provider.id))]
|
|
1582
|
+
})]
|
|
1583
|
+
}),
|
|
1584
|
+
fetchAccess?.kind === "link" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1585
|
+
className: "dsh-ui-hint",
|
|
1586
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppLink, {
|
|
1587
|
+
url: fetchAccess.url,
|
|
1588
|
+
label: text.openConfig,
|
|
1589
|
+
children: text.openConfig
|
|
1590
|
+
})
|
|
1591
|
+
}) : fetchAccess?.kind === "owner" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1592
|
+
className: "dsh-ui-hint",
|
|
1593
|
+
children: [text.ownerSettings, fetchAccess.name]
|
|
1594
|
+
}) : fetchAccess?.kind === "unknown" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1595
|
+
className: "dsh-ui-hint",
|
|
1596
|
+
children: text.unknownOwner
|
|
1597
|
+
}) : null
|
|
1598
|
+
]
|
|
1599
|
+
});
|
|
1600
|
+
})()]
|
|
1191
1601
|
}),
|
|
1192
1602
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1193
1603
|
role: "tabpanel",
|
|
@@ -1329,20 +1739,34 @@ function apply(ctx) {
|
|
|
1329
1739
|
ctx.effect(() => client.slots.inject("plugins.bundle.config", () => client.slots.register({
|
|
1330
1740
|
name: "plugins.bundle.config",
|
|
1331
1741
|
key: "@klarkxy/dsh-web-search-manager"
|
|
1332
|
-
}, () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NetworkSearchSettings, {
|
|
1742
|
+
}, (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NetworkSearchSettings, {
|
|
1743
|
+
client,
|
|
1744
|
+
hidden: props?.hidden
|
|
1745
|
+
}))), "web-search-manager.settings");
|
|
1333
1746
|
}
|
|
1334
1747
|
//#endregion
|
|
1335
1748
|
exports.NetworkSearchSettings = NetworkSearchSettings;
|
|
1749
|
+
exports.STATUS_REFRESH_MS = STATUS_REFRESH_MS;
|
|
1336
1750
|
exports.apply = apply;
|
|
1751
|
+
exports.bindStatusRefresh = bindStatusRefresh;
|
|
1337
1752
|
exports.canEnableSearch = canEnableSearch;
|
|
1753
|
+
exports.canStartStatusRead = canStartStatusRead;
|
|
1338
1754
|
exports.catalogSearchBackends = catalogSearchBackends;
|
|
1755
|
+
exports.configurationAccess = configurationAccess;
|
|
1756
|
+
exports.dormantSearchPlaceholder = dormantSearchPlaceholder;
|
|
1757
|
+
exports.droppedDormantIds = droppedDormantIds;
|
|
1339
1758
|
exports.immediateUpdate = immediateUpdate;
|
|
1340
1759
|
exports.inject = inject;
|
|
1760
|
+
exports.isExternalConfigurationUrl = isExternalConfigurationUrl;
|
|
1761
|
+
exports.isPageHidden = isPageHidden;
|
|
1341
1762
|
exports.isProviderOn = isProviderOn;
|
|
1763
|
+
exports.isRegisteredSearch = isRegisteredSearch;
|
|
1342
1764
|
exports.name = name;
|
|
1343
1765
|
exports.nextSearchEnabled = nextSearchEnabled;
|
|
1766
|
+
exports.ownsProviderConfiguration = ownsProviderConfiguration;
|
|
1344
1767
|
exports.parseLimit = parseLimit;
|
|
1345
1768
|
exports.searchBackends = searchBackends;
|
|
1346
1769
|
exports.selectedSearchBackend = selectedSearchBackend;
|
|
1770
|
+
exports.shouldApplyPolledStatus = shouldApplyPolledStatus;
|
|
1347
1771
|
|
|
1348
1772
|
//# sourceMappingURL=client.inner.cjs.map
|