mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-19 18:45:15 +02:00
Merge pull request #1402 from guangyang1206/fix/extract-domain-helper-1368
Fix/extract domain helper 1368
This commit is contained in:
commit
8fc4b98593
5 changed files with 24 additions and 38 deletions
|
|
@ -24,6 +24,8 @@ import dynamic from "next/dynamic";
|
||||||
import type { FC } from "react";
|
import type { FC } from "react";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { commentsEnabledAtom, targetCommentIdAtom } from "@/atoms/chat/current-thread.atom";
|
import { commentsEnabledAtom, targetCommentIdAtom } from "@/atoms/chat/current-thread.atom";
|
||||||
|
import { tryGetHostname } from "@/lib/url";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
globalNewLLMConfigsAtom,
|
globalNewLLMConfigsAtom,
|
||||||
newLLMConfigsAtom,
|
newLLMConfigsAtom,
|
||||||
|
|
@ -99,20 +101,12 @@ const GenerateImageToolUI = dynamic(
|
||||||
import("@/components/tool-ui/generate-image").then((m) => ({ default: m.GenerateImageToolUI })),
|
import("@/components/tool-ui/generate-image").then((m) => ({ default: m.GenerateImageToolUI })),
|
||||||
{ ssr: false }
|
{ ssr: false }
|
||||||
);
|
);
|
||||||
function extractDomain(url: string): string | undefined {
|
|
||||||
try {
|
|
||||||
return new URL(url).hostname.replace(/^www\./, "");
|
|
||||||
} catch {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function useCitationsFromMetadata(): SerializableCitation[] {
|
function useCitationsFromMetadata(): SerializableCitation[] {
|
||||||
const allCitations = useAllCitationMetadata();
|
const allCitations = useAllCitationMetadata();
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const result: SerializableCitation[] = [];
|
const result: SerializableCitation[] = [];
|
||||||
for (const [url, meta] of allCitations) {
|
for (const [url, meta] of allCitations) {
|
||||||
const domain = extractDomain(url);
|
const domain = tryGetHostname(url);
|
||||||
result.push({
|
result.push({
|
||||||
id: `url-cite-${url}`,
|
id: `url-cite-${url}`,
|
||||||
href: url,
|
href: url,
|
||||||
|
|
|
||||||
|
|
@ -193,14 +193,7 @@ const SurfsenseDocCitation: FC<{ chunkId: number }> = ({ chunkId }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function extractDomain(url: string): string {
|
import { tryGetHostname } from "@/lib/url";
|
||||||
try {
|
|
||||||
const hostname = new URL(url).hostname;
|
|
||||||
return hostname.replace(/^www\./, "");
|
|
||||||
} catch {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UrlCitationProps {
|
interface UrlCitationProps {
|
||||||
url: string;
|
url: string;
|
||||||
|
|
@ -212,7 +205,7 @@ interface UrlCitationProps {
|
||||||
* page title and snippet (extracted deterministically from web_search tool results).
|
* page title and snippet (extracted deterministically from web_search tool results).
|
||||||
*/
|
*/
|
||||||
export const UrlCitation: FC<UrlCitationProps> = ({ url }) => {
|
export const UrlCitation: FC<UrlCitationProps> = ({ url }) => {
|
||||||
const domain = extractDomain(url);
|
const domain = tryGetHostname(url) ?? url;
|
||||||
const meta = useCitationMetadata(url);
|
const meta = useCitationMetadata(url);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ import "katex/dist/katex.min.css";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { processChildrenWithCitations } from "@/components/citations/citation-renderer";
|
import { processChildrenWithCitations } from "@/components/citations/citation-renderer";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
import { tryGetHostname } from "@/lib/url";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
|
|
@ -139,15 +141,6 @@ const MarkdownTextImpl = () => {
|
||||||
|
|
||||||
export const MarkdownText = memo(MarkdownTextImpl);
|
export const MarkdownText = memo(MarkdownTextImpl);
|
||||||
|
|
||||||
function extractDomain(url: string): string {
|
|
||||||
try {
|
|
||||||
const parsed = new URL(url);
|
|
||||||
return parsed.hostname.replace(/^www\./, "");
|
|
||||||
} catch {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canonical local-file virtual paths are mount-prefixed: /<mount>/<relative/path>
|
// Canonical local-file virtual paths are mount-prefixed: /<mount>/<relative/path>
|
||||||
const LOCAL_FILE_PATH_REGEX = /^\/[a-z0-9_-]+\/[^\s`]+(?:\/[^\s`]+)*$/;
|
const LOCAL_FILE_PATH_REGEX = /^\/[a-z0-9_-]+\/[^\s`]+(?:\/[^\s`]+)*$/;
|
||||||
|
|
||||||
|
|
@ -288,7 +281,7 @@ function FilePathLink({ path, className }: { path: string; className?: string })
|
||||||
function MarkdownImage({ src, alt }: { src?: string; alt?: string }) {
|
function MarkdownImage({ src, alt }: { src?: string; alt?: string }) {
|
||||||
if (!src) return null;
|
if (!src) return null;
|
||||||
|
|
||||||
const domain = extractDomain(src);
|
const domain = tryGetHostname(src) ?? "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="my-4 w-fit max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
<div className="my-4 w-fit max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none">
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,11 @@ import * as React from "react";
|
||||||
import { openSafeNavigationHref, sanitizeHref } from "../shared/media";
|
import { openSafeNavigationHref, sanitizeHref } from "../shared/media";
|
||||||
import { cn, Popover, PopoverContent, PopoverTrigger } from "./_adapter";
|
import { cn, Popover, PopoverContent, PopoverTrigger } from "./_adapter";
|
||||||
import type { CitationVariant, SerializableCitation } from "./schema";
|
import type { CitationVariant, SerializableCitation } from "./schema";
|
||||||
|
import { tryGetHostname } from "@/lib/url";
|
||||||
import { TYPE_ICONS } from "./type-icons";
|
import { TYPE_ICONS } from "./type-icons";
|
||||||
|
|
||||||
const FALLBACK_LOCALE = "en-US";
|
const FALLBACK_LOCALE = "en-US";
|
||||||
|
|
||||||
function extractDomain(url: string): string | undefined {
|
|
||||||
try {
|
|
||||||
const urlObj = new URL(url);
|
|
||||||
return urlObj.hostname.replace(/^www\./, "");
|
|
||||||
} catch {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatDate(isoString: string, locale: string): string {
|
function formatDate(isoString: string, locale: string): string {
|
||||||
try {
|
try {
|
||||||
const date = new Date(isoString);
|
const date = new Date(isoString);
|
||||||
|
|
@ -78,7 +70,7 @@ export function Citation(props: CitationProps) {
|
||||||
|
|
||||||
const locale = providedLocale ?? FALLBACK_LOCALE;
|
const locale = providedLocale ?? FALLBACK_LOCALE;
|
||||||
const sanitizedHref = sanitizeHref(rawHref);
|
const sanitizedHref = sanitizeHref(rawHref);
|
||||||
const domain = providedDomain ?? extractDomain(rawHref);
|
const domain = providedDomain ?? tryGetHostname(rawHref);
|
||||||
|
|
||||||
const citationData: SerializableCitation = {
|
const citationData: SerializableCitation = {
|
||||||
...serializable,
|
...serializable,
|
||||||
|
|
|
||||||
14
surfsense_web/lib/url.ts
Normal file
14
surfsense_web/lib/url.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* Extract a normalized hostname from a URL. Strips a leading `www.`.
|
||||||
|
* Returns `undefined` if the input is not a parseable URL.
|
||||||
|
*
|
||||||
|
* This is the canonical replacement for the four previously-duplicated
|
||||||
|
* `extractDomain` helpers that had subtly different error fallbacks.
|
||||||
|
*/
|
||||||
|
export function tryGetHostname(url: string): string | undefined {
|
||||||
|
try {
|
||||||
|
return new URL(url).hostname.replace(/^www\./, "");
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue