feat: add [homarr_base] replacement for external urls (#2024)

This commit is contained in:
Jelte Lagendijk
2024-05-07 19:47:19 +02:00
committed by GitHub
parent 477d249da8
commit 5fbb444d5f
8 changed files with 117 additions and 37 deletions

View File

@@ -75,7 +75,11 @@ export const EditAppModal = ({
return t('validation.noExternalUri');
}
if (!url.match(appUrlWithAnyProtocolRegex)) {
if (
!url.match(appUrlWithAnyProtocolRegex) &&
!url.startsWith('[homarr_base]') &&
!url.startsWith('[homarr_protocol]://')
) {
return t('validation.invalidExternalUri');
}
@@ -110,7 +114,7 @@ export const EditAppModal = ({
// also close the parent modal
context.closeAll();
umami.track('Add app', { name: values.name });
umami.track('Add app', { name: values.name });
};
const [activeTab, setActiveTab] = useState<EditAppModalTab>('general');

View File

@@ -3,6 +3,7 @@ import { UseFormReturnType } from '@mantine/form';
import { useDisclosure } from '@mantine/hooks';
import { IconClick, IconCursorText, IconLink } from '@tabler/icons-react';
import { useTranslation } from 'next-i18next';
import { InfoCard } from '~/components/InfoCard/InfoCard';
import { AppType } from '~/types/app';
import { EditAppModalTab } from '../type';
@@ -50,14 +51,21 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => {
form.setFieldValue('url', e.target.value);
}}
/>
<TextInput
icon={<IconClick size={16} />}
label={t('general.externalAddress.label')}
description={t('general.externalAddress.description')}
placeholder="https://homarr.mywebsite.com/"
variant="default"
{...form.getInputProps('behaviour.externalUrl')}
/>
<Stack style={{ gap: 0 }}>
<Group style={{ gap: '0.25rem' }}>
<Text size="0.875rem" weight={500}>
{t('general.externalAddress.label')}
</Text>
<InfoCard message={t('general.externalAddress.tooltip')} />
</Group>
<TextInput
icon={<IconClick size={16} />}
description={t('general.externalAddress.description')}
placeholder="https://homarr.mywebsite.com/"
variant="default"
{...form.getInputProps('behaviour.externalUrl')}
/>
</Stack>
<Collapse in={opened}>
<Card withBorder>
@@ -81,7 +89,9 @@ export const GeneralTab = ({ form, openTab }: GeneralTabProps) => {
</Collapse>
{!form.values.behaviour.externalUrl.startsWith('https://') &&
!form.values.behaviour.externalUrl.startsWith('http://') && (
!form.values.behaviour.externalUrl.startsWith('http://') &&
!form.values.behaviour.externalUrl.startsWith('[homarr_base]') &&
!form.values.behaviour.externalUrl.startsWith('[homarr_protocol]://') && (
<Text color="red" mt="sm" size="sm">
{t('behaviour.customProtocolWarning')}
</Text>

View File

@@ -1,7 +1,7 @@
import { Affix, Box, Text, Tooltip, UnstyledButton } from '@mantine/core';
import { Box, Text, Tooltip, UnstyledButton } from '@mantine/core';
import { createStyles, useMantineTheme } from '@mantine/styles';
import { motion } from 'framer-motion';
import Link from 'next/link';
import { useExternalUrl } from '~/hooks/useExternalUrl';
import { AppType } from '~/types/app';
import { useEditModeStore } from '../../Views/useEditModeStore';
@@ -26,6 +26,7 @@ export const AppTile = ({ className, app }: AppTileProps) => {
.join(': ');
const isRow = app.appearance.positionAppName.includes('row');
const href = useExternalUrl(app);
function Inner() {
return (
@@ -88,7 +89,7 @@ export const AppTile = ({ className, app }: AppTileProps) => {
<UnstyledButton
style={{ pointerEvents: isEditMode ? 'none' : 'auto' }}
component="a"
href={app.behaviour.externalUrl.length > 0 ? app.behaviour.externalUrl : app.url}
href={href}
target={app.behaviour.isOpeningNewTab ? '_blank' : '_self'}
className={`${classes.button} ${classes.base}`}
>

View File

@@ -14,6 +14,7 @@ import { modals } from '@mantine/modals';
import { IconDotsVertical, IconShare3 } from '@tabler/icons-react';
import { useTranslation } from 'next-i18next';
import { useConfigContext } from '~/config/provider';
import { useGetExternalUrl } from '~/hooks/useExternalUrl';
import { CategoryType } from '~/types/category';
import { useCardStyles } from '../../../layout/Common/useCardStyles';
@@ -33,6 +34,7 @@ export const DashboardCategory = ({ category }: DashboardCategoryProps) => {
const { classes: cardClasses, cx } = useCardStyles(true);
const { classes } = useStyles();
const { t } = useTranslation(['layout/common', 'common']);
const getAppUrl = useGetExternalUrl();
const categoryList = config?.categories.map((x) => x.name) ?? [];
const [toggledCategories, setToggledCategories] = useLocalStorage({
@@ -44,7 +46,8 @@ export const DashboardCategory = ({ category }: DashboardCategoryProps) => {
const handleMenuClick = () => {
for (let i = 0; i < apps.length; i += 1) {
const app = apps[i];
const popUp = window.open(app.url, app.id);
const appUrl = getAppUrl(app);
const popUp = window.open(appUrl, app.id);
if (popUp === null) {
modals.openConfirmModal({
@@ -114,7 +117,9 @@ export const DashboardCategory = ({ category }: DashboardCategoryProps) => {
</Menu.Item>
</Menu.Dropdown>
</Menu>
) : <CategoryEditMenu category={category} />}
) : (
<CategoryEditMenu category={category} />
)}
</Box>
<Accordion.Panel>
<div