mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-12 00:15:48 +01:00
✨ Open tabs in batch (#1006)
This commit is contained in:
18
public/locales/en/layout/common.json
Normal file
18
public/locales/en/layout/common.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"modals": {
|
||||||
|
"blockedPopups": {
|
||||||
|
"title": "Popups blocked",
|
||||||
|
"text": "Your browser has blocked Homarr from accessing it's API. This is most commonly caused by AdBlockers or denied permissions. Homarr is unable to request permissions automatically.",
|
||||||
|
"list": {
|
||||||
|
"browserPermission": "Click on the icon besides the URL and check the permisions. Allow Popups and windows",
|
||||||
|
"adBlockers": "Disable ad blockers and security tools from your browser",
|
||||||
|
"otherBrowser": "Try a different browser"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"category": {
|
||||||
|
"openAllInNewTab": "Open all in new tab"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ActionIcon, Menu } from '@mantine/core';
|
import { ActionIcon, Menu } from '@mantine/core';
|
||||||
import { IconDots, IconLayoutKanban, IconPencil, IconTrash } from '@tabler/icons-react';
|
import { IconLayoutKanban, IconPencil, IconSettings, IconTrash } from '@tabler/icons-react';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useEditModeStore } from '../Views/useEditModeStore';
|
import { useEditModeStore } from '../Views/useEditModeStore';
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ export const GenericTileMenu = ({
|
|||||||
right={8}
|
right={8}
|
||||||
style={{ zIndex: 1 }}
|
style={{ zIndex: 1 }}
|
||||||
>
|
>
|
||||||
<IconDots />
|
<IconSettings />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
<Menu.Dropdown w={250}>
|
<Menu.Dropdown w={250}>
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
import { Accordion, Title } from '@mantine/core';
|
import {
|
||||||
|
Accordion,
|
||||||
|
ActionIcon,
|
||||||
|
Box,
|
||||||
|
Menu,
|
||||||
|
Title,
|
||||||
|
Text,
|
||||||
|
Stack,
|
||||||
|
List,
|
||||||
|
createStyles,
|
||||||
|
} from '@mantine/core';
|
||||||
import { useLocalStorage } from '@mantine/hooks';
|
import { useLocalStorage } from '@mantine/hooks';
|
||||||
|
import { IconDotsVertical, IconShare3 } from '@tabler/icons-react';
|
||||||
|
import { modals } from '@mantine/modals';
|
||||||
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useConfigContext } from '../../../../config/provider';
|
import { useConfigContext } from '../../../../config/provider';
|
||||||
import { CategoryType } from '../../../../types/category';
|
import { CategoryType } from '../../../../types/category';
|
||||||
import { useCardStyles } from '../../../layout/useCardStyles';
|
import { useCardStyles } from '../../../layout/useCardStyles';
|
||||||
@@ -17,6 +30,8 @@ export const DashboardCategory = ({ category }: DashboardCategoryProps) => {
|
|||||||
const isEditMode = useEditModeStore((x) => x.enabled);
|
const isEditMode = useEditModeStore((x) => x.enabled);
|
||||||
const { config } = useConfigContext();
|
const { config } = useConfigContext();
|
||||||
const { classes: cardClasses, cx } = useCardStyles(true);
|
const { classes: cardClasses, cx } = useCardStyles(true);
|
||||||
|
const { classes } = useStyles();
|
||||||
|
const { t } = useTranslation(['layout/common', 'common']);
|
||||||
|
|
||||||
const categoryList = config?.categories.map((x) => x.name) ?? [];
|
const categoryList = config?.categories.map((x) => x.name) ?? [];
|
||||||
const [toggledCategories, setToggledCategories] = useLocalStorage({
|
const [toggledCategories, setToggledCategories] = useLocalStorage({
|
||||||
@@ -25,6 +40,44 @@ export const DashboardCategory = ({ category }: DashboardCategoryProps) => {
|
|||||||
defaultValue: categoryList,
|
defaultValue: categoryList,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleMenuClick = () => {
|
||||||
|
for (let i = 0; i < apps.length; i += 1) {
|
||||||
|
const app = apps[i];
|
||||||
|
const popUp = window.open(app.url, app.id);
|
||||||
|
|
||||||
|
if (popUp === null) {
|
||||||
|
modals.openConfirmModal({
|
||||||
|
title: <Text weight="bold">{t('modals.blockedPopups.title')}</Text>,
|
||||||
|
children: (
|
||||||
|
<Stack maw="100%">
|
||||||
|
<Text>{t('modals.blockedPopups.text')}</Text>
|
||||||
|
<List>
|
||||||
|
<List.Item className={classes.listItem}>
|
||||||
|
{t('modals.blockedPopups.list.browserPermission')}
|
||||||
|
</List.Item>
|
||||||
|
<List.Item className={classes.listItem}>
|
||||||
|
{t('modals.blockedPopups.list.adBlockers')}
|
||||||
|
</List.Item>
|
||||||
|
<List.Item className={classes.listItem}>
|
||||||
|
{t('modals.blockedPopups.list.otherBrowser')}
|
||||||
|
</List.Item>
|
||||||
|
</List>
|
||||||
|
</Stack>
|
||||||
|
),
|
||||||
|
labels: {
|
||||||
|
confirm: t('common:close'),
|
||||||
|
cancel: '',
|
||||||
|
},
|
||||||
|
cancelProps: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
closeOnClickOutside: false,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion
|
<Accordion
|
||||||
classNames={{
|
classNames={{
|
||||||
@@ -43,9 +96,28 @@ export const DashboardCategory = ({ category }: DashboardCategoryProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Accordion.Item value={category.name}>
|
<Accordion.Item value={category.name}>
|
||||||
<Accordion.Control icon={isEditMode && <CategoryEditMenu category={category} />}>
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<Title order={3}>{category.name}</Title>
|
<Accordion.Control icon={isEditMode && <CategoryEditMenu category={category} />}>
|
||||||
</Accordion.Control>
|
<Title order={3}>{category.name}</Title>
|
||||||
|
</Accordion.Control>
|
||||||
|
{!isEditMode && (
|
||||||
|
<Menu withArrow withinPortal>
|
||||||
|
<Menu.Target>
|
||||||
|
<ActionIcon variant="light" mr="md">
|
||||||
|
<IconDotsVertical />
|
||||||
|
</ActionIcon>
|
||||||
|
</Menu.Target>
|
||||||
|
<Menu.Dropdown>
|
||||||
|
<Menu.Item
|
||||||
|
onClick={handleMenuClick}
|
||||||
|
icon={<IconShare3 size="1rem" />}
|
||||||
|
>
|
||||||
|
{t('actions.category.openAllInNewTab')}
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.Dropdown>
|
||||||
|
</Menu>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
<div
|
<div
|
||||||
className="grid-stack grid-stack-category"
|
className="grid-stack grid-stack-category"
|
||||||
@@ -59,3 +131,11 @@ export const DashboardCategory = ({ category }: DashboardCategoryProps) => {
|
|||||||
</Accordion>
|
</Accordion>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useStyles = createStyles(() => ({
|
||||||
|
listItem: {
|
||||||
|
'& div': {
|
||||||
|
maxWidth: 'calc(100% - 23px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { ActionIcon, Menu } from '@mantine/core';
|
import { ActionIcon, Menu } from '@mantine/core';
|
||||||
import {
|
import {
|
||||||
IconDots,
|
|
||||||
IconTransitionTop,
|
IconTransitionTop,
|
||||||
IconTransitionBottom,
|
IconTransitionBottom,
|
||||||
IconRowInsertTop,
|
IconRowInsertTop,
|
||||||
IconRowInsertBottom,
|
IconRowInsertBottom,
|
||||||
IconEdit,
|
IconEdit,
|
||||||
IconTrash,
|
IconTrash,
|
||||||
|
IconSettings,
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { useConfigContext } from '../../../../config/provider';
|
import { useConfigContext } from '../../../../config/provider';
|
||||||
import { CategoryType } from '../../../../types/category';
|
import { CategoryType } from '../../../../types/category';
|
||||||
@@ -25,7 +25,7 @@ export const CategoryEditMenu = ({ category }: CategoryEditMenuProps) => {
|
|||||||
<Menu withinPortal withArrow>
|
<Menu withinPortal withArrow>
|
||||||
<Menu.Target>
|
<Menu.Target>
|
||||||
<ActionIcon>
|
<ActionIcon>
|
||||||
<IconDots />
|
<IconSettings />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Menu.Target>
|
</Menu.Target>
|
||||||
<Menu.Dropdown>
|
<Menu.Dropdown>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export const dashboardNamespaces = [
|
|||||||
'layout/modals/add-app',
|
'layout/modals/add-app',
|
||||||
'layout/modals/change-position',
|
'layout/modals/change-position',
|
||||||
'layout/modals/about',
|
'layout/modals/about',
|
||||||
|
'layout/common',
|
||||||
'layout/header/actions/toggle-edit-mode',
|
'layout/header/actions/toggle-edit-mode',
|
||||||
'layout/mobile/drawer',
|
'layout/mobile/drawer',
|
||||||
'settings/common',
|
'settings/common',
|
||||||
|
|||||||
Reference in New Issue
Block a user