mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-15 01:36:22 +01:00
Merge branch 'feature/add-basic-authentication' of https://github.com/ajnart/homarr into feature/add-basic-authentication
This commit is contained in:
@@ -8,7 +8,7 @@ import { createDashboardSchemaValidation } from '~/validations/dashboards';
|
|||||||
|
|
||||||
export const CreateDashboardModal = ({ context, id, innerProps }: ContextModalProps<{}>) => {
|
export const CreateDashboardModal = ({ context, id, innerProps }: ContextModalProps<{}>) => {
|
||||||
const apiContext = api.useContext();
|
const apiContext = api.useContext();
|
||||||
const { isLoading, mutateAsync } = api.config.save.useMutation({
|
const { isLoading, mutate } = api.config.save.useMutation({
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
await apiContext.config.all.invalidate();
|
await apiContext.config.all.invalidate();
|
||||||
modals.close(id);
|
modals.close(id);
|
||||||
@@ -24,37 +24,43 @@ export const CreateDashboardModal = ({ context, id, innerProps }: ContextModalPr
|
|||||||
validate: i18nZodResolver(createDashboardSchemaValidation),
|
validate: i18nZodResolver(createDashboardSchemaValidation),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
const fallbackConfig = getStaticFallbackConfig(form.values.name);
|
||||||
|
mutate({
|
||||||
|
name: form.values.name,
|
||||||
|
config: fallbackConfig,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||||
<Text>A name cannot be changed after a dashboard has been created.</Text>
|
<Stack>
|
||||||
|
<Text>A name cannot be changed after a dashboard has been created.</Text>
|
||||||
|
|
||||||
<TextInput label="Name" withAsterisk {...form.getInputProps('name')} />
|
<TextInput label="Name" withAsterisk {...form.getInputProps('name')} />
|
||||||
|
|
||||||
<Group grow>
|
<Group grow>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
modals.close(id);
|
modals.close(id);
|
||||||
}}
|
}}
|
||||||
variant="light"
|
variant="light"
|
||||||
color="gray"
|
color="gray"
|
||||||
>
|
type="button"
|
||||||
Cancel
|
>
|
||||||
</Button>
|
Cancel
|
||||||
<Button
|
</Button>
|
||||||
onClick={async () => {
|
<Button
|
||||||
const fallbackConfig = getStaticFallbackConfig(form.values.name);
|
type="submit"
|
||||||
await mutateAsync({
|
onClick={async () => {}}
|
||||||
name: form.values.name,
|
disabled={isLoading}
|
||||||
config: fallbackConfig,
|
variant="light"
|
||||||
});
|
color="green"
|
||||||
}}
|
>
|
||||||
disabled={isLoading}
|
Create
|
||||||
variant="light"
|
</Button>
|
||||||
color="green"
|
</Group>
|
||||||
>
|
</Stack>
|
||||||
Create
|
</form>
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
</Stack>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
52
src/modals/delete-board/delete-board.modal.tsx
Normal file
52
src/modals/delete-board/delete-board.modal.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { Button, Group, Stack, Text } from '@mantine/core';
|
||||||
|
import { ContextModalProps, modals } from '@mantine/modals';
|
||||||
|
import { api } from '~/utils/api';
|
||||||
|
|
||||||
|
export const DeleteBoardModal = ({
|
||||||
|
context,
|
||||||
|
id,
|
||||||
|
innerProps,
|
||||||
|
}: ContextModalProps<{ boardName: string; onConfirm: () => Promise<void> }>) => {
|
||||||
|
const apiContext = api.useContext();
|
||||||
|
const { isLoading, mutateAsync } = api.config.delete.useMutation({
|
||||||
|
onSuccess: async () => {
|
||||||
|
await apiContext.config.all.invalidate();
|
||||||
|
modals.close(id);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack>
|
||||||
|
<Text>
|
||||||
|
Are you sure, that you want to delete this board? This action cannot be undone and your data
|
||||||
|
will be lost permanently.
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Group grow>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
modals.close(id);
|
||||||
|
}}
|
||||||
|
variant="light"
|
||||||
|
color="gray"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={async () => {
|
||||||
|
modals.close(id);
|
||||||
|
await innerProps.onConfirm();
|
||||||
|
await mutateAsync({
|
||||||
|
name: innerProps.boardName,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
disabled={isLoading}
|
||||||
|
variant="light"
|
||||||
|
color="red"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -11,6 +11,7 @@ import { CreateRegistrationTokenModal } from './create-registration-token/create
|
|||||||
import { DeleteRegistrationTokenModal } from './delete-registration-token/delete-registration-token.modal';
|
import { DeleteRegistrationTokenModal } from './delete-registration-token/delete-registration-token.modal';
|
||||||
import { CreateDashboardModal } from './create-dashboard/create-dashboard.modal';
|
import { CreateDashboardModal } from './create-dashboard/create-dashboard.modal';
|
||||||
import { CopyRegistrationToken } from './copy-regristration-token/copy-registration-token.modal';
|
import { CopyRegistrationToken } from './copy-regristration-token/copy-registration-token.modal';
|
||||||
|
import { DeleteBoardModal } from './delete-board/delete-board.modal';
|
||||||
|
|
||||||
export const modals = {
|
export const modals = {
|
||||||
editApp: EditAppModal,
|
editApp: EditAppModal,
|
||||||
@@ -25,6 +26,7 @@ export const modals = {
|
|||||||
deleteRegistrationTokenModal: DeleteRegistrationTokenModal,
|
deleteRegistrationTokenModal: DeleteRegistrationTokenModal,
|
||||||
createDashboardModal: CreateDashboardModal,
|
createDashboardModal: CreateDashboardModal,
|
||||||
copyRegistrationTokenModal: CopyRegistrationToken,
|
copyRegistrationTokenModal: CopyRegistrationToken,
|
||||||
|
deleteBoardModal: DeleteBoardModal
|
||||||
};
|
};
|
||||||
|
|
||||||
declare module '@mantine/modals' {
|
declare module '@mantine/modals' {
|
||||||
|
|||||||
@@ -14,7 +14,13 @@ import {
|
|||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useListState } from '@mantine/hooks';
|
import { useListState } from '@mantine/hooks';
|
||||||
import { modals } from '@mantine/modals';
|
import { modals } from '@mantine/modals';
|
||||||
import { IconDotsVertical, IconPlus, IconTrash } from '@tabler/icons-react';
|
import {
|
||||||
|
IconDotsVertical,
|
||||||
|
IconFile,
|
||||||
|
IconFolderFilled,
|
||||||
|
IconPlus,
|
||||||
|
IconTrash,
|
||||||
|
} from '@tabler/icons-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { MainLayout } from '~/components/layout/admin/main-admin.layout';
|
import { MainLayout } from '~/components/layout/admin/main-admin.layout';
|
||||||
import { CommonHeader } from '~/components/layout/common-header';
|
import { CommonHeader } from '~/components/layout/common-header';
|
||||||
@@ -45,14 +51,14 @@ const BoardsPage = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
modals.openContextModal({
|
modals.openContextModal({
|
||||||
modal: 'createDashboardModal',
|
modal: 'createDashboardModal',
|
||||||
title: <Text>Create new dashboard</Text>,
|
title: <Text>Create new board</Text>,
|
||||||
innerProps: {},
|
innerProps: {},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
leftIcon={<IconPlus size="1rem" />}
|
leftIcon={<IconPlus size="1rem" />}
|
||||||
variant="default"
|
variant="default"
|
||||||
>
|
>
|
||||||
Create new dashboard
|
Create new board
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
@@ -68,9 +74,13 @@ const BoardsPage = () => {
|
|||||||
{data.map((board, index) => (
|
{data.map((board, index) => (
|
||||||
<Card key={index} shadow="sm" padding="lg" radius="md" pos="relative" withBorder>
|
<Card key={index} shadow="sm" padding="lg" radius="md" pos="relative" withBorder>
|
||||||
<LoadingOverlay visible={deletingDashboards.includes(board)} />
|
<LoadingOverlay visible={deletingDashboards.includes(board)} />
|
||||||
<Group position="apart" mb="xs">
|
|
||||||
<Text weight={500}>{board}</Text>
|
<Text weight={500} mb="xs">
|
||||||
<Badge color="pink" variant="light">
|
{board}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Group mb="xl">
|
||||||
|
<Badge leftSection={<IconFolderFilled size=".7rem" />} color="pink" variant="light">
|
||||||
Filesystem
|
Filesystem
|
||||||
</Badge>
|
</Badge>
|
||||||
</Group>
|
</Group>
|
||||||
@@ -100,14 +110,18 @@ const BoardsPage = () => {
|
|||||||
<Menu.Dropdown>
|
<Menu.Dropdown>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
append(board);
|
modals.openContextModal({
|
||||||
// give user feedback, that it's being deleted
|
modal: 'deleteBoardModal',
|
||||||
await sleep(500);
|
title: <Text weight={500}>Delete board</Text>,
|
||||||
deletionMutationAsync({
|
innerProps: {
|
||||||
name: board,
|
boardName: board,
|
||||||
}).finally(async () => {
|
onConfirm: async () => {
|
||||||
await sleep(500);
|
append(board);
|
||||||
filter((item, _) => item !== board);
|
// give user feedback, that it's being deleted
|
||||||
|
await sleep(500);
|
||||||
|
filter((item, _) => item !== board);
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
icon={<IconTrash size="1rem" />}
|
icon={<IconTrash size="1rem" />}
|
||||||
|
|||||||
Reference in New Issue
Block a user