feat(apps): remove url variables (#1771)

This commit is contained in:
Meier Lukas
2024-12-24 14:16:24 +01:00
committed by GitHub
parent 425359be02
commit 8df398c3c7
11 changed files with 41 additions and 80 deletions

View File

@@ -6,7 +6,6 @@ import { IconBox, IconPencil } from "@tabler/icons-react";
import type { RouterOutputs } from "@homarr/api"; import type { RouterOutputs } from "@homarr/api";
import { api } from "@homarr/api/server"; import { api } from "@homarr/api/server";
import { auth } from "@homarr/auth/next"; import { auth } from "@homarr/auth/next";
import { parseAppHrefWithVariablesServer } from "@homarr/common/server";
import { getI18n, getScopedI18n } from "@homarr/translation/server"; import { getI18n, getScopedI18n } from "@homarr/translation/server";
import { ManageContainer } from "~/components/manage/manage-container"; import { ManageContainer } from "~/components/manage/manage-container";
@@ -82,8 +81,8 @@ const AppCard = async ({ app }: AppCardProps) => {
</Text> </Text>
)} )}
{app.href && ( {app.href && (
<Anchor href={parseAppHrefWithVariablesServer(app.href)} lineClamp={1} size="sm" w="min-content"> <Anchor href={app.href} lineClamp={1} size="sm" w="min-content">
{parseAppHrefWithVariablesServer(app.href)} {app.href}
</Anchor> </Anchor>
)} )}
</Stack> </Stack>

View File

@@ -28,8 +28,7 @@
"@homarr/log": "workspace:^0.1.0", "@homarr/log": "workspace:^0.1.0",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"next": "^14.2.21", "next": "^14.2.21",
"react": "^19.0.0", "react": "^19.0.0"
"tldts": "^6.1.69"
}, },
"devDependencies": { "devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0", "@homarr/eslint-config": "workspace:^0.2.0",

View File

@@ -1,23 +0,0 @@
import * as tldts from "tldts";
const safeParseTldts = (url: string) => {
try {
return tldts.parse(url);
} catch {
return null;
}
};
export const parseAppHrefWithVariables = <TInput extends string | null>(url: TInput, currentHref: string): TInput => {
if (!url || url.length === 0) return url;
const tldtsResult = safeParseTldts(currentHref);
const urlObject = new URL(currentHref);
return url
.replaceAll("[homarr_base]", `${urlObject.protocol}//${urlObject.hostname}`)
.replaceAll("[homarr_hostname]", tldtsResult?.hostname ?? "")
.replaceAll("[homarr_domain]", tldtsResult?.domain ?? "")
.replaceAll("[homarr_protocol]", urlObject.protocol.replace(":", "")) as TInput;
};

View File

@@ -1,6 +0,0 @@
import { parseAppHrefWithVariables } from "./base";
export const parseAppHrefWithVariablesClient = <TInput extends string | null>(url: TInput): TInput => {
if (typeof window === "undefined") return url;
return parseAppHrefWithVariables(url, window.location.href);
};

View File

@@ -1,8 +0,0 @@
import { headers } from "next/headers";
import { extractBaseUrlFromHeaders } from "../url";
import { parseAppHrefWithVariables } from "./base";
export const parseAppHrefWithVariablesServer = <TInput extends string | null>(url: TInput): TInput => {
return parseAppHrefWithVariables(url, extractBaseUrlFromHeaders(headers()));
};

View File

@@ -1,2 +1 @@
export * from "./app-url/client";
export * from "./revalidate-path-action"; export * from "./revalidate-path-action";

View File

@@ -1,3 +1,2 @@
export * from "./app-url/server";
export * from "./security"; export * from "./security";
export * from "./encryption"; export * from "./encryption";

View File

@@ -7,7 +7,6 @@ import { IconLoader } from "@tabler/icons-react";
import combineClasses from "clsx"; import combineClasses from "clsx";
import { clientApi } from "@homarr/api/client"; import { clientApi } from "@homarr/api/client";
import { parseAppHrefWithVariablesClient } from "@homarr/common/client";
import { useRegisterSpotlightContextResults } from "@homarr/spotlight"; import { useRegisterSpotlightContextResults } from "@homarr/spotlight";
import { useI18n } from "@homarr/translation/client"; import { useI18n } from "@homarr/translation/client";
@@ -31,26 +30,30 @@ export default function AppWidget({ options, isEditMode }: WidgetComponentProps<
); );
useRegisterSpotlightContextResults( useRegisterSpotlightContextResults(
`app-${app.id}`, `app-${app.id}`,
[ app.href
{ ? [
id: app.id, {
name: app.name, id: app.id,
icon: app.iconUrl, name: app.name,
interaction() { icon: app.iconUrl,
return { interaction() {
type: "link", return {
href: parseAppHrefWithVariablesClient(app.href ?? ""), type: "link",
newTab: options.openInNewTab, // We checked above that app.href is defined
}; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
}, href: app.href!,
}, newTab: options.openInNewTab,
], };
},
},
]
: [],
[app, options.openInNewTab], [app, options.openInNewTab],
); );
return ( return (
<AppLink <AppLink
href={parseAppHrefWithVariablesClient(app.href ?? "")} href={app.href ?? undefined}
openInNewTab={options.openInNewTab} openInNewTab={options.openInNewTab}
enabled={Boolean(app.href) && !isEditMode} enabled={Boolean(app.href) && !isEditMode}
> >
@@ -88,7 +91,7 @@ export default function AppWidget({ options, isEditMode }: WidgetComponentProps<
} }
interface AppLinkProps { interface AppLinkProps {
href: string; href: string | undefined;
openInNewTab: boolean; openInNewTab: boolean;
enabled: boolean; enabled: boolean;
} }

View File

@@ -3,7 +3,6 @@ import { IconCheck, IconX } from "@tabler/icons-react";
import type { RouterOutputs } from "@homarr/api"; import type { RouterOutputs } from "@homarr/api";
import { clientApi } from "@homarr/api/client"; import { clientApi } from "@homarr/api/client";
import { parseAppHrefWithVariablesClient } from "@homarr/common/client";
import { PingDot } from "./ping-dot"; import { PingDot } from "./ping-dot";
@@ -14,7 +13,7 @@ interface PingIndicatorProps {
export const PingIndicator = ({ href }: PingIndicatorProps) => { export const PingIndicator = ({ href }: PingIndicatorProps) => {
const [ping] = clientApi.widget.app.ping.useSuspenseQuery( const [ping] = clientApi.widget.app.ping.useSuspenseQuery(
{ {
url: parseAppHrefWithVariablesClient(href), url: href,
}, },
{ {
refetchOnMount: false, refetchOnMount: false,
@@ -25,7 +24,7 @@ export const PingIndicator = ({ href }: PingIndicatorProps) => {
const [pingResult, setPingResult] = useState<RouterOutputs["widget"]["app"]["ping"]>(ping); const [pingResult, setPingResult] = useState<RouterOutputs["widget"]["app"]["ping"]>(ping);
clientApi.widget.app.updatedPing.useSubscription( clientApi.widget.app.updatedPing.useSubscription(
{ url: parseAppHrefWithVariablesClient(href) }, { url: href },
{ {
onData(data) { onData(data) {
setPingResult(data); setPingResult(data);

View File

@@ -4,7 +4,6 @@ import { Anchor, Box, Card, Divider, Flex, Group, Stack, Text, Title, UnstyledBu
import type { RouterOutputs } from "@homarr/api"; import type { RouterOutputs } from "@homarr/api";
import { clientApi } from "@homarr/api/client"; import { clientApi } from "@homarr/api/client";
import { parseAppHrefWithVariablesClient } from "@homarr/common/client";
import { useRegisterSpotlightContextResults } from "@homarr/spotlight"; import { useRegisterSpotlightContextResults } from "@homarr/spotlight";
import type { WidgetComponentProps } from "../definition"; import type { WidgetComponentProps } from "../definition";
@@ -19,18 +18,22 @@ export default function BookmarksWidget({ options, width, height, itemId }: Widg
useRegisterSpotlightContextResults( useRegisterSpotlightContextResults(
`bookmark-${itemId}`, `bookmark-${itemId}`,
data.map((app) => ({ data
id: app.id, .filter((app) => app.href !== null)
name: app.name, .map((app) => ({
icon: app.iconUrl, id: app.id,
interaction() { name: app.name,
return { icon: app.iconUrl,
type: "link", interaction() {
href: parseAppHrefWithVariablesClient(app.href ?? ""), return {
newTab: false, type: "link",
}; // We checked above that app.href is defined
}, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
})), href: app.href!,
newTab: false,
};
},
})),
[data], [data],
); );

3
pnpm-lock.yaml generated
View File

@@ -707,9 +707,6 @@ importers:
react: react:
specifier: ^19.0.0 specifier: ^19.0.0
version: 19.0.0 version: 19.0.0
tldts:
specifier: ^6.1.69
version: 6.1.69
devDependencies: devDependencies:
'@homarr/eslint-config': '@homarr/eslint-config':
specifier: workspace:^0.2.0 specifier: workspace:^0.2.0