Merge remote-tracking branch 'origin/master' into ji
This commit is contained in:
commit
89cb5ab2f1
61 files changed
+1716
-1693
No files matched your search
@@ -51,7 +51,14 @@ export function readExternalLoginParams(): Required<ExternalLoginParams> {
|
||||
}
|
||||
}
|
||||
|
||||
/** 把 ``theme`` query 值映射成 ThemeContext 的 ``'dark' | 'light'`` */
|
||||
/**
|
||||
* 把外部(URL query / 无界 props)的 ``theme`` 值映射成 ThemeContext 的
|
||||
* ``'dark' | 'light'``。已知取值:
|
||||
* - ``dark-blue`` → 深色
|
||||
* - ``red`` → 浅色(当前默认红白主题)
|
||||
* - ``blue`` → 暂无该主题,先用浅色代替(命中 else 分支)
|
||||
* 其余/缺省同样回退浅色。将来若新增 blue 主题,在此扩展映射即可。
|
||||
*/
|
||||
export function resolveThemeFromQuery(themeParam: string | null | undefined): "dark" | "light" {
|
||||
return themeParam === "dark-blue" ? "dark" : "light";
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 无界(wujie)子应用运行时 props 读取。
|
||||
*
|
||||
* 本应用作为子应用被内网门户用无界嵌套时,父级通过
|
||||
* <WujieVue name="subApp" :url="..." :props="{ ticket, userId, theme, env }" />
|
||||
* 注入参数,子应用在 `window.$wujie.props` 上拿到**同一个对象**(无界在子应用
|
||||
* bootstrap 之前就已注入,因此首帧即可读)。
|
||||
*
|
||||
* 本期范围:只「读出来 + 存起来 + 打印」,**不接入对方鉴权**。读出的
|
||||
* ticket/userId/env 复用 external-login 的 localStorage 存储(与 URL 跳转登录
|
||||
* 同一套 key),theme 交给调用方(LoginPage)映射到 ThemeContext。
|
||||
*/
|
||||
import { useEffect, useMemo } from "react";
|
||||
|
||||
import { persistExternalLoginParams } from "@/core/auth/external-login";
|
||||
|
||||
/** 无界父级注入的 props 形状。除已知字段外允许透传其余未知字段便于排查。 */
|
||||
export interface WujieProps {
|
||||
/** 第三方鉴权 ticket(本期仅存储待用,不消费)。 */
|
||||
ticket?: string;
|
||||
/** 外部用户 id。 */
|
||||
userId?: string;
|
||||
/** 环境标识。 */
|
||||
env?: string;
|
||||
/** 主题色标识(映射到深/浅色)。 */
|
||||
theme?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface WujieRuntime {
|
||||
props?: WujieProps;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
/** 无界注入的子应用运行时;非无界环境下为 undefined。 */
|
||||
$wujie?: WujieRuntime;
|
||||
/** 无界注入的环境标志(子应用内为 true)。 */
|
||||
__POWERED_BY_WUJIE__?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
/** 当前是否运行在无界子应用环境中。 */
|
||||
export function isWujieEnv(): boolean {
|
||||
return typeof window !== "undefined" && !!window.__POWERED_BY_WUJIE__;
|
||||
}
|
||||
|
||||
/** 读取无界父级注入的 props;不在无界环境 / 未注入时返回空对象。 */
|
||||
export function readWujieProps(): WujieProps {
|
||||
if (typeof window === "undefined") return {};
|
||||
return window.$wujie?.props ?? {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局读取无界父级注入的 props 的 hook。
|
||||
*
|
||||
* - 首帧从 `window.$wujie.props` 读出(无界已在 bootstrap 前注入,引用稳定);
|
||||
* - 读到后把 ticket/userId/env 持久化到 localStorage(复用 external-login 存储),
|
||||
* 供后续任意页面/请求读取 —— 即「存到全局」;
|
||||
* - 返回 props 供调用方消费(如 LoginPage 取 theme)。
|
||||
*
|
||||
* 非无界环境(直接访问)下返回空对象且不做任何持久化,可安全无条件调用。
|
||||
*/
|
||||
export function useWujieProps(): WujieProps {
|
||||
const props = useMemo(() => readWujieProps(), []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!props.ticket && !props.userId && !props.env) return;
|
||||
persistExternalLoginParams({
|
||||
ticket: props.ticket,
|
||||
userId: props.userId,
|
||||
env: props.env,
|
||||
});
|
||||
}, [props.ticket, props.userId, props.env]);
|
||||
|
||||
return props;
|
||||
}
|
||||
@@ -4,11 +4,12 @@ export const DEFAULT_LOCAL_SETTINGS: LocalSettings = {
|
||||
notification: {
|
||||
enabled: true,
|
||||
},
|
||||
display: {
|
||||
streamSpeedMeterEnabled: true,
|
||||
ragModeEnabled: false,
|
||||
citationCleanupWords: [],
|
||||
},
|
||||
display: {
|
||||
streamSpeedMeterEnabled: true,
|
||||
ragModeEnabled: false,
|
||||
citationCleanupWords: [],
|
||||
fontScale: 1,
|
||||
},
|
||||
context: {
|
||||
model_name: undefined,
|
||||
mode: undefined,
|
||||
@@ -17,9 +18,9 @@ export const DEFAULT_LOCAL_SETTINGS: LocalSettings = {
|
||||
},
|
||||
};
|
||||
|
||||
export const LOCAL_SETTINGS_KEY = "deerflow.local-settings";
|
||||
export const THREAD_MODEL_KEY_PREFIX = "deerflow.thread-model.";
|
||||
export const THREAD_RAG_MODE_KEY_PREFIX = "deerflow.thread-rag-mode.";
|
||||
export const LOCAL_SETTINGS_KEY = "deerflow.local-settings";
|
||||
export const THREAD_MODEL_KEY_PREFIX = "deerflow.thread-model.";
|
||||
export const THREAD_RAG_MODE_KEY_PREFIX = "deerflow.thread-rag-mode.";
|
||||
|
||||
function isBrowser(): boolean {
|
||||
return typeof window !== "undefined";
|
||||
@@ -40,13 +41,20 @@ export interface LocalSettings {
|
||||
* Global switch for skill result display adapters. When disabled, chat
|
||||
* messages render tool results with the legacy generic search UI only.
|
||||
*/
|
||||
ragModeEnabled: boolean;
|
||||
/**
|
||||
* Admin-maintained words or short phrases removed from reference snippets
|
||||
* and dialogs, one entry per line in the settings UI.
|
||||
*/
|
||||
citationCleanupWords: string[];
|
||||
};
|
||||
ragModeEnabled: boolean;
|
||||
/**
|
||||
* Admin-maintained words or short phrases removed from reference snippets
|
||||
* and dialogs, one entry per line in the settings UI.
|
||||
*/
|
||||
citationCleanupWords: string[];
|
||||
/**
|
||||
* Global UI font scale multiplier applied to the root <html> font-size.
|
||||
* Base is 16px (deep-blue UI spec §2.1.2 body text), so `1` === 16px.
|
||||
* The user picks a size from the appearance settings page; because the
|
||||
* app sizes text/spacing in rem, the whole UI scales proportionally.
|
||||
*/
|
||||
fontScale: number;
|
||||
};
|
||||
context: Omit<
|
||||
AgentThreadContext,
|
||||
| "thread_id"
|
||||
@@ -91,10 +99,10 @@ export function getThreadModelName(threadId: string): string | undefined {
|
||||
return localStorage.getItem(getThreadModelStorageKey(threadId)) ?? undefined;
|
||||
}
|
||||
|
||||
export function saveThreadModelName(
|
||||
threadId: string,
|
||||
modelName: string | undefined,
|
||||
) {
|
||||
export function saveThreadModelName(
|
||||
threadId: string,
|
||||
modelName: string | undefined,
|
||||
) {
|
||||
if (!isBrowser()) {
|
||||
return;
|
||||
}
|
||||
@@ -103,26 +111,26 @@ export function saveThreadModelName(
|
||||
localStorage.removeItem(key);
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(key, modelName);
|
||||
}
|
||||
|
||||
function getThreadRagModeStorageKey(threadId: string): string {
|
||||
return `${THREAD_RAG_MODE_KEY_PREFIX}${threadId}`;
|
||||
}
|
||||
|
||||
export function isThreadRagModeLocked(threadId: string): boolean {
|
||||
if (!isBrowser() || !threadId) {
|
||||
return false;
|
||||
}
|
||||
return localStorage.getItem(getThreadRagModeStorageKey(threadId)) === "true";
|
||||
}
|
||||
|
||||
export function lockThreadRagMode(threadId: string) {
|
||||
if (!isBrowser() || !threadId) {
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(getThreadRagModeStorageKey(threadId), "true");
|
||||
}
|
||||
localStorage.setItem(key, modelName);
|
||||
}
|
||||
|
||||
function getThreadRagModeStorageKey(threadId: string): string {
|
||||
return `${THREAD_RAG_MODE_KEY_PREFIX}${threadId}`;
|
||||
}
|
||||
|
||||
export function isThreadRagModeLocked(threadId: string): boolean {
|
||||
if (!isBrowser() || !threadId) {
|
||||
return false;
|
||||
}
|
||||
return localStorage.getItem(getThreadRagModeStorageKey(threadId)) === "true";
|
||||
}
|
||||
|
||||
export function lockThreadRagMode(threadId: string) {
|
||||
if (!isBrowser() || !threadId) {
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(getThreadRagModeStorageKey(threadId), "true");
|
||||
}
|
||||
|
||||
export function applyThreadModelOverride(
|
||||
settings: LocalSettings,
|
||||
|
||||
Reference in new issue
Block a user