feat(apps): remove url variables (#1771)
This commit is contained in:
@@ -6,7 +6,6 @@ import { IconBox, IconPencil } from "@tabler/icons-react";
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { api } from "@homarr/api/server";
|
||||
import { auth } from "@homarr/auth/next";
|
||||
import { parseAppHrefWithVariablesServer } from "@homarr/common/server";
|
||||
import { getI18n, getScopedI18n } from "@homarr/translation/server";
|
||||
|
||||
import { ManageContainer } from "~/components/manage/manage-container";
|
||||
@@ -82,8 +81,8 @@ const AppCard = async ({ app }: AppCardProps) => {
|
||||
</Text>
|
||||
)}
|
||||
{app.href && (
|
||||
<Anchor href={parseAppHrefWithVariablesServer(app.href)} lineClamp={1} size="sm" w="min-content">
|
||||
{parseAppHrefWithVariablesServer(app.href)}
|
||||
<Anchor href={app.href} lineClamp={1} size="sm" w="min-content">
|
||||
{app.href}
|
||||
</Anchor>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
"@homarr/log": "workspace:^0.1.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"next": "^14.2.21",
|
||||
"react": "^19.0.0",
|
||||
"tldts": "^6.1.69"
|
||||
"react": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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()));
|
||||
};
|
||||
@@ -1,2 +1 @@
|
||||
export * from "./app-url/client";
|
||||
export * from "./revalidate-path-action";
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export * from "./app-url/server";
|
||||
export * from "./security";
|
||||
export * from "./encryption";
|
||||
|
||||
@@ -7,7 +7,6 @@ import { IconLoader } from "@tabler/icons-react";
|
||||
import combineClasses from "clsx";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { parseAppHrefWithVariablesClient } from "@homarr/common/client";
|
||||
import { useRegisterSpotlightContextResults } from "@homarr/spotlight";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
@@ -31,26 +30,30 @@ export default function AppWidget({ options, isEditMode }: WidgetComponentProps<
|
||||
);
|
||||
useRegisterSpotlightContextResults(
|
||||
`app-${app.id}`,
|
||||
[
|
||||
{
|
||||
id: app.id,
|
||||
name: app.name,
|
||||
icon: app.iconUrl,
|
||||
interaction() {
|
||||
return {
|
||||
type: "link",
|
||||
href: parseAppHrefWithVariablesClient(app.href ?? ""),
|
||||
newTab: options.openInNewTab,
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
app.href
|
||||
? [
|
||||
{
|
||||
id: app.id,
|
||||
name: app.name,
|
||||
icon: app.iconUrl,
|
||||
interaction() {
|
||||
return {
|
||||
type: "link",
|
||||
// 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],
|
||||
);
|
||||
|
||||
return (
|
||||
<AppLink
|
||||
href={parseAppHrefWithVariablesClient(app.href ?? "")}
|
||||
href={app.href ?? undefined}
|
||||
openInNewTab={options.openInNewTab}
|
||||
enabled={Boolean(app.href) && !isEditMode}
|
||||
>
|
||||
@@ -88,7 +91,7 @@ export default function AppWidget({ options, isEditMode }: WidgetComponentProps<
|
||||
}
|
||||
|
||||
interface AppLinkProps {
|
||||
href: string;
|
||||
href: string | undefined;
|
||||
openInNewTab: boolean;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { IconCheck, IconX } from "@tabler/icons-react";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { parseAppHrefWithVariablesClient } from "@homarr/common/client";
|
||||
|
||||
import { PingDot } from "./ping-dot";
|
||||
|
||||
@@ -14,7 +13,7 @@ interface PingIndicatorProps {
|
||||
export const PingIndicator = ({ href }: PingIndicatorProps) => {
|
||||
const [ping] = clientApi.widget.app.ping.useSuspenseQuery(
|
||||
{
|
||||
url: parseAppHrefWithVariablesClient(href),
|
||||
url: href,
|
||||
},
|
||||
{
|
||||
refetchOnMount: false,
|
||||
@@ -25,7 +24,7 @@ export const PingIndicator = ({ href }: PingIndicatorProps) => {
|
||||
const [pingResult, setPingResult] = useState<RouterOutputs["widget"]["app"]["ping"]>(ping);
|
||||
|
||||
clientApi.widget.app.updatedPing.useSubscription(
|
||||
{ url: parseAppHrefWithVariablesClient(href) },
|
||||
{ url: href },
|
||||
{
|
||||
onData(data) {
|
||||
setPingResult(data);
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Anchor, Box, Card, Divider, Flex, Group, Stack, Text, Title, UnstyledBu
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { parseAppHrefWithVariablesClient } from "@homarr/common/client";
|
||||
import { useRegisterSpotlightContextResults } from "@homarr/spotlight";
|
||||
|
||||
import type { WidgetComponentProps } from "../definition";
|
||||
@@ -19,18 +18,22 @@ export default function BookmarksWidget({ options, width, height, itemId }: Widg
|
||||
|
||||
useRegisterSpotlightContextResults(
|
||||
`bookmark-${itemId}`,
|
||||
data.map((app) => ({
|
||||
id: app.id,
|
||||
name: app.name,
|
||||
icon: app.iconUrl,
|
||||
interaction() {
|
||||
return {
|
||||
type: "link",
|
||||
href: parseAppHrefWithVariablesClient(app.href ?? ""),
|
||||
newTab: false,
|
||||
};
|
||||
},
|
||||
})),
|
||||
data
|
||||
.filter((app) => app.href !== null)
|
||||
.map((app) => ({
|
||||
id: app.id,
|
||||
name: app.name,
|
||||
icon: app.iconUrl,
|
||||
interaction() {
|
||||
return {
|
||||
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],
|
||||
);
|
||||
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -707,9 +707,6 @@ importers:
|
||||
react:
|
||||
specifier: ^19.0.0
|
||||
version: 19.0.0
|
||||
tldts:
|
||||
specifier: ^6.1.69
|
||||
version: 6.1.69
|
||||
devDependencies:
|
||||
'@homarr/eslint-config':
|
||||
specifier: workspace:^0.2.0
|
||||
|
||||
Reference in New Issue
Block a user