import { ActionIcon, Badge, Button, Card, Group, LoadingOverlay, Menu, Modal, SimpleGrid, Stack, Text, Title, } from '@mantine/core'; import { useDisclosure, useListState } from '@mantine/hooks'; import { notifications } from '@mantine/notifications'; import { IconBox, IconCategory, IconCopy, IconCursorText, IconDeviceFloppy, IconDotsVertical, IconDownload, IconFolderFilled, IconLock, IconLockOff, IconPlus, IconStack, IconStarFilled, IconTrash, } from '@tabler/icons-react'; import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next'; import { useTranslation } from 'next-i18next'; import Head from 'next/head'; import Link from 'next/link'; import { useState } from 'react'; import { RenameBoardModal } from '~/components/Dashboard/Modals/RenameBoard/RenameBoardModal'; import { openCreateBoardModal } from '~/components/Manage/Board/create-board.modal'; import { openDeleteBoardModal } from '~/components/Manage/Board/delete-board.modal'; import { ManageLayout } from '~/components/layout/Templates/ManageLayout'; import { boardRouter } from '~/server/api/routers/board'; import { getServerAuthSession } from '~/server/auth'; import { sleep } from '~/tools/client/time'; import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations'; import { checkForSessionOrAskForLogin } from '~/tools/server/loginBuilder'; import { manageNamespaces } from '~/tools/server/translation-namespaces'; import { api } from '~/utils/api'; // Infer return type from the `getServerSideProps` function export default function BoardsPage({ boards, session, }: InferGetServerSidePropsType) { const [openedRenameBoardModal, { open: openRenameBoardModal, close: closeRenameBoardModal }] = useDisclosure(false); const [renameBoardName, setRenameBoardName] = useState<{ boardName: string }>(); const { data, refetch } = api.boards.all.useQuery(undefined, { initialData: boards, cacheTime: 1000 * 60 * 5, // Cache for 5 minutes }); const { mutateAsync } = api.user.makeDefaultDashboard.useMutation({ onSettled: () => { void refetch(); }, }); const utils = api.useUtils(); const { mutateAsync: mutateDuplicateBoardAsync } = api.boards.duplicateBoard.useMutation({ onSettled: () => { void utils.boards.all.invalidate(); }, onError: (error) => { notifications.show({ title: 'An error occurred while duplicating', message: error.message, }); }, }); const [deletingDashboards, { append, filter }] = useListState([]); const downloadAllBoards = async () => { const a = document.createElement('a'); a.href = `/api/download`; a.click(); }; const { t } = useTranslation('manage/boards'); const metaTitle = `${t('metaTitle')} • Homarr`; return ( {metaTitle} board.name)} onClose={closeRenameBoardModal} /> {t('pageTitle')} {session?.user.isAdmin && ( )} {data.map((board, index) => ( {board.name} } color="pink" variant="light"> {t('cards.badges.fileSystem')} : } color="green" variant="light" > {board.allowGuests ? t('common:public') : t('common:restricted')} {board.isDefaultForUser && ( } color="yellow" variant="light" > {t('cards.badges.default')} )} {t('cards.statistics.apps')} {board.countApps} {t('cards.statistics.widgets')} {board.countWidgets} {t('cards.statistics.categories')} {board.countCategories} { await mutateDuplicateBoardAsync({ boardName: board.name, }); }} icon={} > {t('cards.menu.duplicate')} { setRenameBoardName({ boardName: board.name as string, }); openRenameBoardModal(); }} icon={} disabled={board.name === 'default'} > {t('cards.menu.rename.label')} } onClick={async () => { void mutateAsync({ board: board.name, }); }} > {t('cards.menu.setAsDefault')} {session?.user.isAdmin && ( <> { openDeleteBoardModal({ boardName: board.name, onConfirm: async () => { append(board.name); // give user feedback, that it's being deleted await sleep(500); filter((item, _) => item !== board.name); }, }); }} disabled={board.name === 'default'} icon={} color="red" > {t('cards.menu.delete.label')} {board.name === 'default' && ( {t('cards.menu.delete.disabled')} )} )} ))} ); } export const getServerSideProps = async (context: GetServerSidePropsContext) => { const session = await getServerAuthSession({ req: context.req, res: context.res }); const result = checkForSessionOrAskForLogin( context, session, () => session?.user.isAdmin == true ); if (result !== undefined) { return result; } const caller = boardRouter.createCaller({ session: session, cookies: context.req.cookies, }); const boards = await caller.all(); const translations = await getServerSideTranslations( manageNamespaces, context.locale, context.req, context.res ); return { props: { boards, session, ...translations, }, }; };