Form updates

This commit is contained in:
Sean Edmunds
2025-06-13 12:53:17 -05:00
parent 29514d3290
commit c3530a23a4
10 changed files with 472 additions and 436 deletions

View File

@@ -71,36 +71,29 @@ export function useMutationAPI() {
const response = await fetch(`${url}/${endpoint}`, options);
if (!response.ok) {
const responseData = await response.json();
if (typeof responseData.detail !== 'string') {
const errorResponse = JSON.stringify({
status: response.status,
statusText: response.statusText,
method: options.method,
endpoint: endpoint,
msg: responseData.detail[0]?.msg,
loc: responseData.detail[0]?.loc,
type: responseData.detail[0]?.type,
});
throw new Error(errorResponse);
if (typeof responseData === 'object') {
if (responseData.error.code === 'ER_DUP_ENTRY') {
setTimeout(() => {
notifications.update({
id: id,
loading: false,
title: (
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
{method} Failure!
</Text>
),
message: (
<Text c={'var(--mantine-color-primary-0)'}>
Entry with that name already exists.
</Text>
),
autoClose: 2500,
icon: <FaCheck size={24} />,
});
}, 2500);
}
}
if (typeof responseData.detail === 'object') {
const errorResponse = JSON.stringify({
status: response.status,
statusText: response.statusText,
method: options.method,
endpoint: endpoint,
msg: responseData.detail.message,
});
throw new Error(errorResponse);
}
const errorResponse = JSON.stringify({
status: response.status,
statusText: response.statusText,
method: options.method,
endpoint: endpoint,
msg: responseData.detail,
});
throw new Error(errorResponse);
return await responseData;
}
setTimeout(() => {
notifications.update({

View File

@@ -247,8 +247,15 @@ function SettingsButton() {
color: 'var(--mantine-color-primary-0)',
}}
onClick={() => {
setCurrentThemePlaylist('All');
handleThemeChange(allThemes, true);
const themeList = JSON.parse(
themePlaylistData?.find(
(t: ThemePlaylist) => t?.name === currentThemePlaylist,
)?.themeList ?? '[]',
);
const filteredThemes = allThemes.filter((t: Theme) =>
themeList.includes(t.id),
);
handleThemeChange(filteredThemes, false);
}}
>
<FaDice />

View File

@@ -14,6 +14,7 @@ import {
Text,
TextInput,
} from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
@@ -36,10 +37,19 @@ const ApplicationSettings = () => {
url: '',
icon: '',
baseUrl: '',
filterName: '',
filterName: 'Default',
index: 0,
enabled: 1,
};
const form = useForm({
initialValues: defaultApplication,
validate: {
name: isNotEmpty('Name is required'),
url: isNotEmpty('URL is required'),
icon: isNotEmpty('Icon is required'),
filterName: isNotEmpty('Filter name is required'),
},
});
const appsEndpoint = 'api/applications';
const appsOrderEndpoint = 'api/applicationOrder';
const { data: applicationData, isFetching: isAppsFetching } = useQueryAPI({
@@ -48,7 +58,6 @@ const ApplicationSettings = () => {
const [applications, setApplications] = useState<Application[]>([]);
const [applicationList, setApplicationList] = useState<Application[]>([]);
const { isMobile, reorder } = useCommonHooks();
const [newApplication, setNewApplication] = useState<Application>(defaultApplication);
const { mutateAsync } = useMutationAPI();
const [searchValue, setSearchValue] = useState('');
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
@@ -80,7 +89,7 @@ const ApplicationSettings = () => {
const handleClose = () => {
closeModal();
setNewApplication(defaultApplication);
form.reset();
};
useEffect(() => {
if (applicationData && !isAppsFetching) {
@@ -116,137 +125,124 @@ const ApplicationSettings = () => {
handleClose={handleClose}
title={'Add a new application'}
body={
<Stack gap={0} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
label={'Name'}
className={textInputClasses.settingsItem}
w={'45%'}
classNames={textInputClasses}
defaultValue={newApplication.name}
onChange={(event) => {
setNewApplication({
...newApplication,
name: event.target.value,
});
}}
/>
<TextInput
label={'Base URL'}
className={textInputClasses.settingsItem}
w={'45%'}
classNames={textInputClasses}
defaultValue={newApplication.baseUrl}
onChange={(event) => {
setNewApplication({
...newApplication,
baseUrl: event.target.value,
});
}}
/>
</Group>
<Group w={isMobile ? '94%' : '92%'} justify='center'>
<TextInput
label={'URL'}
className={textInputClasses.settingsItem}
w={'100%'}
classNames={textInputClasses}
defaultValue={newApplication.url}
onChange={(event) => {
setNewApplication({
...newApplication,
url: event.target.value,
});
}}
/>
</Group>
<Group w={'100%'} justify='center'>
<Select
label={'Icon'}
className={selectClasses.settingsItem}
classNames={{
input: selectClasses.menuSelectInput,
label: selectClasses.menuSelectLabel,
options: selectClasses.menuSelectOptions,
option: selectClasses.menuSelectOption,
dropdown: selectClasses.dropdown,
}}
w={'45%'}
mt={'.75rem'}
limit={100}
placeholder='Search for an icon...'
data={Object.keys(allIcons).map((icon) => {
return { value: icon, label: icon };
})}
defaultValue={newApplication.icon}
comboboxProps={{
zIndex: 3000,
}}
onChange={(value: string | null) => {
setNewApplication({
...newApplication,
icon: value ?? '',
});
}}
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
const Icon = allIcons[item.option.value];
return (
<Group>
{item.option.value}
<Icon />
</Group>
);
}}
searchable
maxDropdownHeight={175}
onDropdownOpen={() => setIsOpen(true)}
onDropdownClose={() => setIsOpen(false)}
/>
<TextInput
label={'Filter'}
className={textInputClasses.settingsItem}
pt={'1rem'}
w={'45%'}
classNames={textInputClasses}
defaultValue={newApplication.filterName}
onChange={(event) => {
setNewApplication({
...newApplication,
filterName: event.target.value,
});
}}
/>
</Group>
<form
onSubmit={form.onSubmit((values) => {
mutateAsync({
method: 'POST',
endpoint: appsEndpoint,
body: {
...values,
index: applications.length,
},
});
handleClose();
})}
>
<Stack gap={0} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
key={form.key('name')}
{...form.getInputProps('name')}
label={'Name'}
placeholder='Nextcloud'
className={textInputClasses.settingsItem}
w={'45%'}
classNames={textInputClasses}
withAsterisk
/>
<TextInput
key={form.key('baseUrl')}
{...form.getInputProps('baseUrl')}
label={'Base URL'}
placeholder='/nextcloud'
className={textInputClasses.settingsItem}
w={'45%'}
classNames={textInputClasses}
/>
</Group>
<Group w={isMobile ? '94%' : '92%'} justify='center'>
<TextInput
key={form.key('url')}
{...form.getInputProps('url')}
label={'URL'}
placeholder='https://domain.example.com/nextcloud'
className={textInputClasses.settingsItem}
w={'100%'}
classNames={textInputClasses}
withAsterisk
/>
</Group>
<Group w={'100%'} justify='center'>
<Select
key={form.key('icon')}
{...form.getInputProps('icon')}
label={'Icon'}
className={selectClasses.settingsItem}
classNames={{
input: selectClasses.menuSelectInput,
label: selectClasses.menuSelectLabel,
options: selectClasses.menuSelectOptions,
option: selectClasses.menuSelectOption,
dropdown: selectClasses.dropdown,
}}
w={'45%'}
mt={'.75rem'}
limit={100}
placeholder='Search for an icon...'
data={Object.keys(allIcons).map((icon) => {
return { value: icon, label: icon };
})}
comboboxProps={{
zIndex: 3000,
}}
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
const Icon = allIcons[item.option.value];
return (
<Group>
{item.option.value}
<Icon />
</Group>
);
}}
searchable
maxDropdownHeight={175}
onDropdownOpen={() => setIsOpen(true)}
onDropdownClose={() => setIsOpen(false)}
withAsterisk
/>
<TextInput
key={form.key('filter')}
{...form.getInputProps('filter')}
label={'Filter'}
placeholder='Storage'
className={textInputClasses.settingsItem}
pt={'1rem'}
w={'45%'}
classNames={textInputClasses}
defaultValue={defaultApplication.filterName}
withAsterisk
/>
</Group>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newApplication) {
mutateAsync({
method: 'POST',
endpoint: appsEndpoint,
body: {
...newApplication,
index: applications.length,
},
}).then(handleClose);
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={handleClose}
>
Cancel
</Button>
</Group>
</Stack>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
type='submit'
color={'green'}
styles={{ label: { color: 'black' } }}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={handleClose}
>
Cancel
</Button>
</Group>
</Stack>
</form>
}
/>
<SettingsHeader

View File

@@ -129,6 +129,7 @@ function DebouncedApplication({
name: event.target.value,
});
}}
disabled
/>
<TextInput
label={'Base URL'}

View File

@@ -1,5 +1,6 @@
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
import { Box, Button, Card, Divider, Group, Stack, Text, TextInput } from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
@@ -16,6 +17,13 @@ const BookmarkSettings = () => {
categoryIndex: 0,
filterName: '',
};
const form = useForm({
initialValues: defaultGroup,
validate: {
categoryName: isNotEmpty('Category name is required'),
filterName: isNotEmpty('Filter name is required'),
},
});
const bookmarksEndpoint = 'api/bookmarks';
const { data: bookmarkData, isFetched: bookmarksIsFetched } = useQueryAPI({
endpoint: bookmarksEndpoint,
@@ -27,7 +35,6 @@ const BookmarkSettings = () => {
});
const [dragging, setDragging] = useState(false);
const [groups, setGroups] = useState<BookmarkGroup[]>([]);
const [newGroup, setNewGroup] = useState<BookmarkGroup>(defaultGroup);
const [groupList, setGroupList] = useState<BookmarkGroup[]>([]);
const { isMobile, reorder } = useCommonHooks();
const { mutateAsync } = useMutationAPI();
@@ -37,8 +44,8 @@ const BookmarkSettings = () => {
const [isLoading, setIsLoading] = useState(false);
const handleClose = () => {
setNewGroup(defaultGroup);
closeModal();
form.reset();
};
function onDragEnd(result: any) {
@@ -118,61 +125,60 @@ const BookmarkSettings = () => {
handleClose={handleClose}
title={'Add a new Bookmark Group'}
body={
<Stack gap={0} w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
label={'Category Name'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
defaultValue={newGroup.categoryName}
onChange={(event) => {
setNewGroup({
...newGroup,
categoryName: event.target.value,
});
}}
/>
<TextInput
label={'Filter Name'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
defaultValue={newGroup.filterName}
onChange={(event) => {
setNewGroup({
...newGroup,
filterName: event.target.value,
});
}}
/>
</Group>
<form
onSubmit={form.onSubmit((values) => {
mutateAsync({
method: 'POST',
endpoint: categoriesEndpoint,
body: {
...values,
categoryIndex: groups.length,
},
});
handleClose();
})}
>
<Stack gap={0} w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
key={form.key('categoryName')}
{...form.getInputProps('categoryName')}
label={'Category Name'}
placeholder='Shopping'
className={textInputClasses.settingsItem}
classNames={textInputClasses}
withAsterisk
/>
<TextInput
key={form.key('filterName')}
{...form.getInputProps('filterName')}
label={'Filter Name'}
placeholder='Personal'
className={textInputClasses.settingsItem}
classNames={textInputClasses}
withAsterisk
/>
</Group>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newGroup) {
mutateAsync({
method: 'POST',
endpoint: categoriesEndpoint,
body: { ...newGroup, categoryIndex: groups.length },
});
handleClose();
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={handleClose}
>
Cancel
</Button>
</Group>
</Stack>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
type='submit'
color={'green'}
styles={{ label: { color: 'black' } }}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={handleClose}
>
Cancel
</Button>
</Group>
</Stack>
</form>
}
/>
<SettingsHeader

View File

@@ -17,6 +17,7 @@ import {
TextInput,
Tooltip,
} from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI } from 'hooks';
import { useEffect, useState } from 'react';
@@ -47,6 +48,13 @@ function DebouncedGroupSettingsItem({
category: group.categoryName,
index: 0,
});
const form = useForm({
initialValues: newBookmark,
validate: {
name: isNotEmpty('Name is required'),
url: isNotEmpty('URL is required'),
},
});
const [bookmarkList, setBookmarkList] = useState<Bookmark[]>(bookmarks);
const [isOpen, setIsOpen] = useState(false);
@@ -193,7 +201,7 @@ function DebouncedGroupSettingsItem({
borderRadius: '100%',
backgroundColor: 'var(--mantine-color-accent-0)',
position: 'absolute',
top: isMobile ? 140 : 78,
top: isMobile ? 140 : 92,
right: 18,
zIndex: 10,
fontSize: '1.25rem',
@@ -307,99 +315,95 @@ function DebouncedGroupSettingsItem({
</Popover.Target>
<Popover.Dropdown w={isMobile ? '90%' : undefined}>
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
<Stack w={'100%'} display={'flex'} pos={'relative'}>
<Group w={'100%'} justify='center'>
<TextInput
label={'Name'}
labelProps={{
style: {
color: 'var(--mantine-color-primary-0)',
},
}}
className={textInputClasses.settingsItem}
pt={'1rem'}
classNames={textInputClasses}
onChange={(event) => {
setNewBookmark({
...newBookmark,
name: event.target.value,
});
}}
/>
<TextInput
label={'Category'}
labelProps={{
style: {
color: 'var(--mantine-color-primary-0)',
},
}}
className={textInputClasses.settingsItem}
pt={'1rem'}
classNames={textInputClasses}
disabled
defaultValue={group.categoryName}
onChange={(event) => {
setNewBookmark({
...newBookmark,
category: event.target.value,
});
}}
/>
</Group>
<Group w={'100%'} justify='center' mb={60}>
<TextInput
label={'URL'}
labelProps={{
style: {
color: 'var(--mantine-color-primary-0)',
},
}}
className={textInputClasses.settingsItem}
<form
onSubmit={form.onSubmit((values) => {
mutateAsync({
method: 'POST',
endpoint: 'api/bookmarks',
body: { ...values, index: bookmarks.length },
});
setPopoverOpened(false);
form.reset();
})}
>
<Stack w={'100%'} display={'flex'} pos={'relative'}>
<Group w={'100%'} justify='center'>
<TextInput
key={form.key('name')}
{...form.getInputProps('name')}
label={'Name'}
placeholder='Google'
labelProps={{
style: {
color: 'var(--mantine-color-primary-0)',
},
}}
className={textInputClasses.settingsItem}
pt={'1rem'}
classNames={textInputClasses}
withAsterisk
/>
<TextInput
key={form.key('category')}
{...form.getInputProps('category')}
label={'Category'}
labelProps={{
style: {
color: 'var(--mantine-color-primary-0)',
},
}}
className={textInputClasses.settingsItem}
pt={'1rem'}
classNames={textInputClasses}
disabled
defaultValue={group.categoryName}
/>
</Group>
<Group w={'100%'} justify='center' mb={60}>
<TextInput
key={form.key('url')}
{...form.getInputProps('url')}
label={'URL'}
placeholder='https://google.com'
labelProps={{
style: {
color: 'var(--mantine-color-primary-0)',
},
}}
className={textInputClasses.settingsItem}
w={'100%'}
pt={'1rem'}
classNames={textInputClasses}
withAsterisk
/>
</Group>
<Group
w={'100%'}
pt={'1rem'}
classNames={textInputClasses}
onChange={(event) => {
setNewBookmark({
...newBookmark,
url: event.target.value,
});
}}
/>
</Group>
<Group
w={'100%'}
pos={'absolute'}
bottom={8}
align='center'
justify='center'
>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newBookmark) {
mutateAsync({
method: 'POST',
endpoint: 'api/bookmarks',
body: { ...newBookmark, index: bookmarks.length },
});
pos={'absolute'}
bottom={8}
align='center'
justify='center'
>
<Button
type='submit'
color={'green'}
styles={{ label: { color: 'black' } }}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
setPopoverOpened(false);
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
setPopoverOpened(false);
}}
>
Cancel
</Button>
</Group>
</Stack>
form.reset();
}}
>
Cancel
</Button>
</Group>
</Stack>
</form>
</Card>
</Popover.Dropdown>
</Popover>

View File

@@ -9,6 +9,7 @@ import {
Stack,
TextInput,
} from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
@@ -27,6 +28,14 @@ const SearchProviderSettings = () => {
url: '',
prefix: '',
};
const form = useForm({
initialValues: defaultProvider,
validate: {
name: isNotEmpty('Name is required'),
url: isNotEmpty('URL is required'),
prefix: isNotEmpty('Prefix is required'),
},
});
const endpoint = 'api/providers';
const { data: providerData, isFetched: providerDataIsFetched } = useQueryAPI({
endpoint: endpoint,
@@ -34,7 +43,6 @@ const SearchProviderSettings = () => {
const [providers, setProviders] = useState<Provider[]>([]);
const { isMobile } = useCommonHooks();
const { mutateAsync } = useMutationAPI();
const [newProvider, setNewProvider] = useState<Provider>(defaultProvider);
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const [searchValue, setSearchValue] = useState('');
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
@@ -42,8 +50,8 @@ const SearchProviderSettings = () => {
const [isLoading, setIsLoading] = useState(false);
const handleClose = () => {
setNewProvider(defaultProvider);
closeModal();
form.reset();
};
useEffect(() => {
@@ -70,74 +78,68 @@ const SearchProviderSettings = () => {
handleClose={handleClose}
title={'Add a new Search Provider'}
body={
<Stack gap={0} w={'100%'} align='center'>
<Stack w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<form
onSubmit={form.onSubmit((values) => {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: values,
});
handleClose();
})}
>
<Stack gap={0} w={'100%'} align='center'>
<Stack w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
key={form.key('name')}
{...form.getInputProps('name')}
label={'Name'}
placeholder='Google'
className={textInputClasses.settingsItem}
classNames={textInputClasses}
withAsterisk
/>
<TextInput
key={form.key('prefix')}
{...form.getInputProps('prefix')}
label={'Prefix'}
placeholder='/g'
className={textInputClasses.settingsItem}
classNames={textInputClasses}
withAsterisk
/>
</Group>
<TextInput
label={'Name'}
key={form.key('url')}
{...form.getInputProps('url')}
label={'Url'}
placeholder='https://www.google.com/search?q='
className={textInputClasses.settingsItem}
w={'64%'}
classNames={textInputClasses}
defaultValue={newProvider.name}
onChange={(event) => {
setNewProvider({
...newProvider,
name: event.target.value,
});
}}
/>
<TextInput
label={'Prefix'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
defaultValue={newProvider.prefix}
onChange={(event) => {
setNewProvider({
...newProvider,
prefix: event.target.value,
});
}}
withAsterisk
/>
</Stack>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
type='submit'
color={'green'}
styles={{ label: { color: 'black' } }}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={handleClose}
>
Cancel
</Button>
</Group>
<TextInput
label={'Url'}
className={textInputClasses.settingsItem}
w={isMobile ? '64%' : '100%'}
classNames={textInputClasses}
defaultValue={newProvider.url}
onChange={(event) => {
setNewProvider({
...newProvider,
url: event.target.value,
});
}}
/>
</Stack>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newProvider) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: newProvider,
}).then(handleClose);
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={handleClose}
>
Cancel
</Button>
</Group>
</Stack>
</form>
}
/>
<SettingsHeader

View File

@@ -8,6 +8,7 @@ import {
Stack,
TextInput,
} from '@mantine/core';
import { isNotEmpty, matches, useForm } from '@mantine/form';
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
import { useEffect, useState } from 'react';
@@ -25,6 +26,16 @@ const WolClientSettings = () => {
hostname: '',
macAddress: '',
};
const form = useForm({
initialValues: defaultWolClient,
validate: {
hostname: isNotEmpty('Hostname is required'),
macAddress: matches(
/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/,
'Invalid MAC Address',
),
},
});
const endpoint = 'api/wolClients';
const { data: wolClientsData, isFetched: wolClientsIsFetched } = useQueryAPI({
endpoint: endpoint,
@@ -32,7 +43,6 @@ const WolClientSettings = () => {
const [wolClients, setWolClients] = useState<WolClient[]>([]);
const { mutateAsync } = useMutationAPI();
const { isMobile } = useCommonHooks();
const [newWolClient, setNewWolClient] = useState<WolClient>(defaultWolClient);
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
const [searchValue, setSearchValue] = useState('');
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
@@ -40,8 +50,8 @@ const WolClientSettings = () => {
const [isLoading, setIsLoading] = useState(false);
const handleClose = () => {
setNewWolClient(defaultWolClient);
closeModal();
form.reset();
};
useEffect(() => {
@@ -64,62 +74,56 @@ const WolClientSettings = () => {
handleClose={handleClose}
title={'Add a new WoL Client'}
body={
<Stack gap={0} w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
label={'Hostname'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
defaultValue={newWolClient.hostname}
onChange={(event) => {
setNewWolClient({
...newWolClient,
hostname: event.target.value,
});
}}
/>
<TextInput
label={'MAC Address'}
className={textInputClasses.settingsItem}
classNames={textInputClasses}
defaultValue={newWolClient.macAddress}
onChange={(event) => {
setNewWolClient({
...newWolClient,
macAddress: event.target.value,
});
}}
/>
</Group>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
color={'green'}
styles={{ label: { color: 'black' } }}
onClick={() => {
if (newWolClient) {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: newWolClient,
});
closeModal();
}
}}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={() => {
closeModal();
}}
>
Cancel
</Button>
</Group>
</Stack>
<form
onSubmit={form.onSubmit((values) => {
mutateAsync({
method: 'POST',
endpoint: endpoint,
body: values,
});
handleClose();
})}
>
<Stack gap={0} w={'100%'} align='center'>
<Group w={'100%'} justify='center'>
<TextInput
key={form.key('hostname')}
{...form.getInputProps('hostname')}
label={'Hostname'}
placeholder='Workstation'
className={textInputClasses.settingsItem}
classNames={textInputClasses}
withAsterisk
/>
<TextInput
key={form.key('macAddress')}
{...form.getInputProps('macAddress')}
label={'MAC Address'}
placeholder='00:00:00:00:00:00'
className={textInputClasses.settingsItem}
classNames={textInputClasses}
withAsterisk
/>
</Group>
<Divider color='black' my='lg' />
<Group pos={'absolute'} bottom={8}>
<Button
type='submit'
color={'green'}
styles={{ label: { color: 'black' } }}
>
Save
</Button>
<Button
color={'red'}
styles={{ label: { color: 'black' } }}
onClick={handleClose}
>
Cancel
</Button>
</Group>
</Stack>
</form>
}
/>
<SettingsHeader