Change the board creation modal to an inline form

This commit is contained in:
Thomas Camlong
2023-12-02 14:58:15 +01:00
parent adaa4a5b64
commit 320af5e726
3 changed files with 62 additions and 56 deletions

View File

@@ -24,7 +24,8 @@
"test:coverage": "SKIP_ENV_VALIDATION=1 vitest run --coverage",
"docker:build": "turbo build && docker build . -t homarr:local-dev",
"docker:start": "docker run -p 7575:7575 --name homarr-development homarr:local-dev",
"db:migrate": "dotenv ts-node drizzle/migrate/migrate.ts ./drizzle"
"db:migrate": "dotenv ts-node drizzle/migrate/migrate.ts ./drizzle",
"db:create": "dotenv drizzle-kit push:sqlite"
},
"dependencies": {
"@auth/drizzle-adapter": "^0.3.2",
@@ -234,4 +235,4 @@
]
}
}
}
}

View File

@@ -1,7 +1,7 @@
import { ActionIcon, Button, Group, Loader, Stack, Switch, TextInput } from '@mantine/core';
import { useForm, zodResolver } from '@mantine/form';
import { useDebouncedValue } from '@mantine/hooks';
import { ContextModalProps } from '@mantine/modals';
import { ContextModalProps, closeModal } from '@mantine/modals';
import { IconAlertTriangle, IconCheck, IconPencil, IconPencilOff } from '@tabler/icons-react';
import { useRouter } from 'next/router';
import { useState } from 'react';
@@ -9,7 +9,7 @@ import { z } from 'zod';
import { api } from '~/utils/api';
import { createBoardSchema } from '~/validations/boards';
export const CreateBoardModal = ({ id, context }: ContextModalProps<Record<string, never>>) => {
export const CreateBoardModal = ({ id }: { id: string }) => {
const [autoBoardName, setAutoBoardName] = useState(true);
const router = useRouter();
const form = useForm<FormType>({
@@ -34,7 +34,7 @@ export const CreateBoardModal = ({ id, context }: ContextModalProps<Record<strin
createBoard(values, {
onSuccess: async () => {
await router.push(`/board/${values.boardName}`);
context.closeModal(id);
closeModal(id);
utils.boards.checkNameAvailable.invalidate({ boardName: values.boardName });
},
});
@@ -43,55 +43,60 @@ export const CreateBoardModal = ({ id, context }: ContextModalProps<Record<strin
return (
<form onSubmit={form.onSubmit(handleSubmit)}>
<Stack>
<TextInput
label="Page Title"
required
{...form.getInputProps('pageTitle')}
onChange={(e) => {
form.getInputProps('pageTitle').onChange(e);
if (!autoBoardName) return;
form.setFieldValue(
'boardName',
e.currentTarget.value
.replace(/([A-z0-9])[^A-z0-9]+([A-z0-9])/g, '$1-$2')
.replace(/([A-z0-9])[^A-z0-9\-]+([A-z0-9])/g, '$1-$2')
.replace(/[^A-z\-0-9]+/g, '')
.replace(/-+/g, '-')
.toLowerCase()
);
}}
/>
<TextInput
label="Routename"
required
{...form.getInputProps('boardName')}
readOnly={autoBoardName}
rightSection={
<ActionIcon variant="transparent" onClick={() => setAutoBoardName((c) => !c)}>
{autoBoardName ? (
<IconPencil size="1.25rem" stroke={1.5} />
) : (
<IconPencilOff size="1.25rem" stroke={1.5} />
)}
</ActionIcon>
}
icon={
debouncedRouteName !== form.values.boardName || isFetching ? (
<Loader size="xs" />
) : boardNameAvailable === true ? (
<IconCheck size="1.25rem" stroke={1.5} color="green" />
) : boardNameAvailable === false ? (
<IconAlertTriangle size="1.25rem" stroke={1.5} color="red" />
) : null
}
/>
<Group grow>
<TextInput
// TODO: Add translations
label="Page Title"
description="The title of the page as it shows on your browser tab"
required
{...form.getInputProps('pageTitle')}
onChange={(e) => {
form.getInputProps('pageTitle').onChange(e);
if (!autoBoardName) return;
form.setFieldValue(
'boardName',
e.currentTarget.value
.replace(/([A-z0-9])[^A-z0-9]+([A-z0-9])/g, '$1-$2')
.replace(/([A-z0-9])[^A-z0-9\-]+([A-z0-9])/g, '$1-$2')
.replace(/[^A-z\-0-9]+/g, '')
.replace(/-+/g, '-')
.toLowerCase()
);
}}
/>
<TextInput
label="Routename"
description="The name that will be used in the URL to access your board"
required
{...form.getInputProps('boardName')}
readOnly={autoBoardName}
rightSection={
<ActionIcon variant="transparent" onClick={() => setAutoBoardName((c) => !c)}>
{autoBoardName ? (
<IconPencil size="1.25rem" stroke={1.5} />
) : (
<IconPencilOff size="1.25rem" stroke={1.5} />
)}
</ActionIcon>
}
icon={
debouncedRouteName !== form.values.boardName || isFetching ? (
<Loader size="xs" />
) : boardNameAvailable === true ? (
<IconCheck size="1.25rem" stroke={1.5} color="green" />
) : boardNameAvailable === false ? (
<IconAlertTriangle size="1.25rem" stroke={1.5} color="red" />
) : null
}
/>
</Group>
<Switch
label="Allow Guests"
description="Allow users that are not logged in to view your board"
{...form.getInputProps('allowGuests')}
/>
<Group position="right">
<Button type="button" color="gray" variant="subtle">
<Button type="button" color="gray" variant="subtle" onClick={() => closeModal(id)}>
Cancel
</Button>
<Button type="submit" color="teal" loading={isLoading || isSuccess}>

View File

@@ -9,9 +9,9 @@ import {
SimpleGrid,
Stack,
Text,
Title,
Title
} from '@mantine/core';
import { useListState } from '@mantine/hooks';
import { useDisclosure, useListState } from '@mantine/hooks';
import {
IconBox,
IconCategory,
@@ -30,7 +30,7 @@ import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import { useTranslation } from 'next-i18next';
import Head from 'next/head';
import Link from 'next/link';
import { openCreateBoardModal } from '~/components/Manage/Board/create-board.modal';
import { CreateBoardModal } from '~/components/Board/BoardCreateModal';
import { openDeleteBoardModal } from '~/components/Manage/Board/delete-board.modal';
import { ManageLayout } from '~/components/layout/Templates/ManageLayout';
import { boardRouter } from '~/server/api/routers/board';
@@ -59,6 +59,7 @@ const BoardsPage = ({
const [deletingDashboards, { append, filter }] = useListState<string>([]);
const { t } = useTranslation('manage/boards');
const [opened, handlers] = useDisclosure(false);
const metaTitle = `${t('metaTitle')} • Homarr`;
@@ -71,15 +72,14 @@ const BoardsPage = ({
<Group position="apart">
<Title mb="xl">{t('pageTitle')}</Title>
{session?.user.isAdmin && (
<Button
onClick={openCreateBoardModal}
leftIcon={<IconPlus size="1rem" />}
variant="default"
>
<Button onClick={handlers.toggle} leftIcon={<IconPlus size="1rem" />} variant="default">
{t('buttons.create')}
</Button>
)}
</Group>
<Card display={opened ? 'block' : 'none'} mb="lg">
<CreateBoardModal id={'none'} />
</Card>
<SimpleGrid
cols={3}