feat(webui): add guided setup flows

* feat(channels): add guided setup flows

* test(channels): preserve setup config values

* fix(channels): reflect saved setup state

* refactor(channels): simplify setup state metadata

* fix(channels): harden setup lifecycle

* refactor(channels): centralize setup contracts

* fix(channels): route setup actions through webui shim

* fix(channels): adapt settings for compact screens

* fix(models): preserve default preset display

* feat(models): add curated Codex catalog

* fix(webui): stop attached gateway on interrupt

* fix(webui): simplify apps catalog

* docs(webui): clarify apps and runtime features

* feat(settings): add guided capability setup

* fix(webui): harden setup and managed services

* test: keep managed runtime checks portable

* test: scope POSIX runtime coverage

* fix(webui): simplify file settings

* feat(files): bundle document reading

* fix(webui): harden setup request boundaries

* fix(webui): prevent channel setup status squeeze

* fix(settings): group provider compatibility aliases

* refactor(settings): remove redundant setup surfaces

* fix(webui): harden guided setup lifecycle

* fix(webui): preserve channel setup compatibility
This commit is contained in:
Xubin Ren
2026-07-13 13:11:46 +08:00
committed by GitHub
parent 791c7fd505
commit fe0717b385
92 changed files with 15058 additions and 1311 deletions
+8 -15
View File
@@ -1,10 +1,7 @@
import {
Children,
isValidElement,
useCallback,
useEffect,
useMemo,
useState,
type ReactNode,
} from "react";
import type { Components, Options as ReactMarkdownOptions } from "react-markdown";
@@ -22,6 +19,7 @@ import {
isFilePatternReference,
isLikelyFilePath,
} from "@/components/FileReferenceChip";
import { useLogoFallback } from "@/hooks/useLogoFallback";
import { inferMediaKind } from "@/lib/media";
import { faviconUrls } from "@/lib/provider-brand";
import { remarkTexMath } from "@/lib/remark-tex-math";
@@ -304,7 +302,7 @@ function inlineLinkPreviewFromChildren(children: ReactNode): InlineLinkPreview |
}
function InlineLinkPreviewRow({ link }: { link: InlineLinkPreview }) {
const { favicon, onFaviconError } = useFaviconFallback(link.host);
const { favicon, onFaviconError, onFaviconLoad } = useFaviconFallback(link.host);
const label = link.prefix
? `${link.prefix}${link.title}`
: link.title;
@@ -332,7 +330,9 @@ function InlineLinkPreviewRow({ link }: { link: InlineLinkPreview }) {
src={favicon}
alt=""
className="h-3 w-3 rounded-[2px] object-contain"
decoding="async"
loading="lazy"
onLoad={onFaviconLoad}
onError={onFaviconError}
/>
) : (
@@ -348,19 +348,12 @@ function InlineLinkPreviewRow({ link }: { link: InlineLinkPreview }) {
function useFaviconFallback(host: string) {
const faviconCandidates = useMemo(() => faviconUrls(host), [host]);
const [faviconIndex, setFaviconIndex] = useState(0);
useEffect(() => {
setFaviconIndex(0);
}, [host]);
const onFaviconError = useCallback(() => {
setFaviconIndex((index) => Math.min(index + 1, faviconCandidates.length));
}, [faviconCandidates.length]);
const { logoUrl, onLogoError, onLogoLoad } = useLogoFallback(faviconCandidates);
return {
favicon: faviconCandidates[faviconIndex] ?? null,
onFaviconError,
favicon: logoUrl ?? null,
onFaviconError: onLogoError,
onFaviconLoad: onLogoLoad,
};
}