From dabe426c36c87eff06f85586d237071536b0031d Mon Sep 17 00:00:00 2001
From: euvre <93761161+euvre@users.noreply.github.com>
Date: Wed, 22 Jul 2026 16:03:03 +0800
Subject: [PATCH] fix: render documentation URLs as hyperlinks in model
tooltips (#17224)
---
web/src/components/linkify-text.tsx | 68 +++++++++++++++++++
.../setting-model/layout/system-setting.tsx | 5 +-
2 files changed, 72 insertions(+), 1 deletion(-)
create mode 100644 web/src/components/linkify-text.tsx
diff --git a/web/src/components/linkify-text.tsx b/web/src/components/linkify-text.tsx
new file mode 100644
index 0000000000..ebfd8febae
--- /dev/null
+++ b/web/src/components/linkify-text.tsx
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { ReactNode } from 'react';
+
+const URL_REGEX = /(https?:\/\/[^\s<>)"{}|^`[\]]+)/gi;
+
+interface LinkifyTextProps {
+ children: ReactNode;
+ className?: string;
+}
+
+export function LinkifyText({ children, className }: LinkifyTextProps) {
+ if (typeof children !== 'string') {
+ return {children};
+ }
+
+ const parts: ReactNode[] = [];
+ let lastIndex = 0;
+ let match;
+
+ while ((match = URL_REGEX.exec(children)) !== null) {
+ if (match.index > lastIndex) {
+ parts.push(
+
+ {children.slice(lastIndex, match.index)}
+ ,
+ );
+ }
+
+ const url = match[0];
+ parts.push(
+ e.stopPropagation()}
+ >
+ {url}
+ ,
+ );
+
+ lastIndex = match.index + url.length;
+ }
+
+ if (lastIndex < children.length) {
+ parts.push(
+ {children.slice(lastIndex)},
+ );
+ }
+
+ return {parts};
+}
diff --git a/web/src/pages/user-setting/setting-model/layout/system-setting.tsx b/web/src/pages/user-setting/setting-model/layout/system-setting.tsx
index f16094d75e..11585aa817 100644
--- a/web/src/pages/user-setting/setting-model/layout/system-setting.tsx
+++ b/web/src/pages/user-setting/setting-model/layout/system-setting.tsx
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import { LinkifyText } from '@/components/linkify-text';
import { ModelTreeSelect, ModelTypeMap } from '@/components/model-tree-select';
import {
Tooltip,
@@ -56,7 +57,9 @@ function ModelFieldItem({
{label}
{tooltip && (
- {tooltip}
+
+ {tooltip}
+