Files
Homarr/src/pages/manage/boards/index.tsx

175 lines
5.2 KiB
TypeScript
Raw Normal View History

2023-07-30 22:20:20 +02:00
import {
ActionIcon,
Badge,
Button,
Card,
Flex,
Group,
LoadingOverlay,
Menu,
SimpleGrid,
2023-08-01 12:58:32 +02:00
Stack,
2023-07-30 22:20:20 +02:00
Text,
Title,
} from '@mantine/core';
import { useListState } from '@mantine/hooks';
import { modals } from '@mantine/modals';
2023-08-01 12:58:32 +02:00
import {
IconApps,
IconDotsVertical,
IconFolderFilled,
IconPlus,
IconStar,
IconStarFilled,
2023-08-01 12:58:32 +02:00
IconTrash,
} from '@tabler/icons-react';
import Head from 'next/head';
2023-07-30 22:20:20 +02:00
import Link from 'next/link';
2023-08-01 01:13:21 +02:00
import { ManageLayout } from '~/components/layout/Templates/ManageLayout';
2023-07-30 22:20:20 +02:00
import { sleep } from '~/tools/client/time';
import { api } from '~/utils/api';
const BoardsPage = () => {
2023-08-01 12:58:32 +02:00
const { data } = api.boards.all.useQuery();
2023-07-30 22:20:20 +02:00
const [deletingDashboards, { append, filter }] = useListState<string>([]);
return (
2023-08-01 01:13:21 +02:00
<ManageLayout>
<Head>
2023-07-30 22:20:20 +02:00
<title>Boards Homarr</title>
</Head>
2023-07-30 22:20:20 +02:00
<Title mb="xl">Boards</Title>
<Flex justify="end" mb="md">
<Button
onClick={() => {
modals.openContextModal({
modal: 'createDashboardModal',
title: <Text>Create new board</Text>,
2023-07-30 22:20:20 +02:00
innerProps: {},
});
}}
leftIcon={<IconPlus size="1rem" />}
variant="default"
>
Create new board
2023-07-30 22:20:20 +02:00
</Button>
</Flex>
{data && (
<SimpleGrid
cols={3}
spacing="lg"
breakpoints={[
{ maxWidth: '62rem', cols: 2, spacing: 'lg' },
{ maxWidth: '48rem', cols: 1, spacing: 'lg' },
]}
>
{data.map((board, index) => (
<Card key={index} shadow="sm" padding="lg" radius="md" pos="relative" withBorder>
2023-08-01 12:58:32 +02:00
<LoadingOverlay visible={deletingDashboards.includes(board.name)} />
<Group mb="xl" position="apart" noWrap>
<Text weight={500} mb="xs">
{board.name}
</Text>
<Group spacing="xs" noWrap>
<Badge
leftSection={<IconFolderFilled size=".7rem" />}
color="pink"
variant="light"
>
Filesystem
</Badge>
{board.isDefaultForUser && (
<Badge
leftSection={<IconStarFilled size=".7rem" />}
color="yellow"
variant="light"
>
Default
</Badge>
)}
</Group>
2023-07-30 22:20:20 +02:00
</Group>
2023-08-01 12:58:32 +02:00
<Stack spacing={3}>
<Group position="apart">
<Group spacing="xs">
<IconApps opacity={0.7} size="1rem" />
<Text color="dimmed">Apps</Text>
</Group>
<Text>{board.countApps}</Text>
</Group>
<Group position="apart">
<Group spacing="xs">
<IconApps opacity={0.7} size="1rem" />
<Text color="dimmed">Widgets</Text>
</Group>
<Text>{board.countWidgets}</Text>
</Group>
<Group position="apart">
<Group spacing="xs">
<IconApps opacity={0.7} size="1rem" />
<Text color="dimmed">Categories</Text>
</Group>
<Text>{board.countCategories}</Text>
</Group>
</Stack>
2023-07-30 22:20:20 +02:00
<Group mt="md">
<Button
component={Link}
style={{ flexGrow: 1 }}
variant="default"
color="blue"
radius="md"
href={`/board/${board}`}
>
View dashboard
</Button>
<Menu>
<Menu.Target>
<ActionIcon h={34} w={34} variant="default">
<IconDotsVertical size="1rem" />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item
onClick={async () => {
modals.openContextModal({
modal: 'deleteBoardModal',
title: <Text weight={500}>Delete board</Text>,
innerProps: {
2023-08-01 12:58:32 +02:00
boardName: board.name,
onConfirm: async () => {
2023-08-01 12:58:32 +02:00
append(board.name);
// give user feedback, that it's being deleted
await sleep(500);
2023-08-01 12:58:32 +02:00
filter((item, _) => item !== board.name);
},
},
2023-07-30 22:20:20 +02:00
});
}}
icon={<IconTrash size="1rem" />}
color="red"
>
Permanently delete
</Menu.Item>
</Menu.Dropdown>
</Menu>
</Group>
</Card>
))}
</SimpleGrid>
)}
2023-08-01 01:13:21 +02:00
</ManageLayout>
2023-07-30 22:20:20 +02:00
);
};
export default BoardsPage;