Form updates
This commit is contained in:
26
package-lock.json
generated
26
package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hello-pangea/dnd": "^18.0.1",
|
"@hello-pangea/dnd": "^18.0.1",
|
||||||
"@mantine/core": "^8.0.2",
|
"@mantine/core": "^8.0.2",
|
||||||
|
"@mantine/form": "^8.0.2",
|
||||||
"@mantine/hooks": "^8.0.2",
|
"@mantine/hooks": "^8.0.2",
|
||||||
"@mantine/notifications": "^8.0.2",
|
"@mantine/notifications": "^8.0.2",
|
||||||
"@tanstack/react-query": "^5.80.6",
|
"@tanstack/react-query": "^5.80.6",
|
||||||
@@ -943,6 +944,19 @@
|
|||||||
"react-dom": "^18.x || ^19.x"
|
"react-dom": "^18.x || ^19.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mantine/form": {
|
||||||
|
"version": "8.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mantine/form/-/form-8.1.0.tgz",
|
||||||
|
"integrity": "sha512-bCLdeWRbuYfG7l5b7nSKYEdWEWLOl55g/dyifRjFEr9pOK9ZNCj7oCOtXp0Lk1QJGqopZoaKxb5mvajEwDFXoQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"klona": "^2.0.6"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.x || ^19.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@mantine/hooks": {
|
"node_modules/@mantine/hooks": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-8.0.2.tgz",
|
||||||
@@ -2713,8 +2727,7 @@
|
|||||||
"node_modules/fast-deep-equal": {
|
"node_modules/fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/fast-equals": {
|
"node_modules/fast-equals": {
|
||||||
"version": "5.2.2",
|
"version": "5.2.2",
|
||||||
@@ -3105,6 +3118,15 @@
|
|||||||
"graceful-fs": "^4.1.6"
|
"graceful-fs": "^4.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/klona": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/kolorist": {
|
"node_modules/kolorist": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hello-pangea/dnd": "^18.0.1",
|
"@hello-pangea/dnd": "^18.0.1",
|
||||||
"@mantine/core": "^8.0.2",
|
"@mantine/core": "^8.0.2",
|
||||||
|
"@mantine/form": "^8.0.2",
|
||||||
"@mantine/hooks": "^8.0.2",
|
"@mantine/hooks": "^8.0.2",
|
||||||
"@mantine/notifications": "^8.0.2",
|
"@mantine/notifications": "^8.0.2",
|
||||||
"@tanstack/react-query": "^5.80.6",
|
"@tanstack/react-query": "^5.80.6",
|
||||||
|
|||||||
@@ -71,36 +71,29 @@ export function useMutationAPI() {
|
|||||||
const response = await fetch(`${url}/${endpoint}`, options);
|
const response = await fetch(`${url}/${endpoint}`, options);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
if (typeof responseData.detail !== 'string') {
|
if (typeof responseData === 'object') {
|
||||||
const errorResponse = JSON.stringify({
|
if (responseData.error.code === 'ER_DUP_ENTRY') {
|
||||||
status: response.status,
|
setTimeout(() => {
|
||||||
statusText: response.statusText,
|
notifications.update({
|
||||||
method: options.method,
|
id: id,
|
||||||
endpoint: endpoint,
|
loading: false,
|
||||||
msg: responseData.detail[0]?.msg,
|
title: (
|
||||||
loc: responseData.detail[0]?.loc,
|
<Text fw={600} c={'var(--mantine-color-accent-0)'}>
|
||||||
type: responseData.detail[0]?.type,
|
{method} Failure!
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
message: (
|
||||||
|
<Text c={'var(--mantine-color-primary-0)'}>
|
||||||
|
Entry with that name already exists.
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
autoClose: 2500,
|
||||||
|
icon: <FaCheck size={24} />,
|
||||||
});
|
});
|
||||||
throw new Error(errorResponse);
|
}, 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({
|
return await responseData;
|
||||||
status: response.status,
|
|
||||||
statusText: response.statusText,
|
|
||||||
method: options.method,
|
|
||||||
endpoint: endpoint,
|
|
||||||
msg: responseData.detail,
|
|
||||||
});
|
|
||||||
throw new Error(errorResponse);
|
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
notifications.update({
|
notifications.update({
|
||||||
|
|||||||
@@ -247,8 +247,15 @@ function SettingsButton() {
|
|||||||
color: 'var(--mantine-color-primary-0)',
|
color: 'var(--mantine-color-primary-0)',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentThemePlaylist('All');
|
const themeList = JSON.parse(
|
||||||
handleThemeChange(allThemes, true);
|
themePlaylistData?.find(
|
||||||
|
(t: ThemePlaylist) => t?.name === currentThemePlaylist,
|
||||||
|
)?.themeList ?? '[]',
|
||||||
|
);
|
||||||
|
const filteredThemes = allThemes.filter((t: Theme) =>
|
||||||
|
themeList.includes(t.id),
|
||||||
|
);
|
||||||
|
handleThemeChange(filteredThemes, false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FaDice />
|
<FaDice />
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
|
import { isNotEmpty, useForm } from '@mantine/form';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -36,10 +37,19 @@ const ApplicationSettings = () => {
|
|||||||
url: '',
|
url: '',
|
||||||
icon: '',
|
icon: '',
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
filterName: '',
|
filterName: 'Default',
|
||||||
index: 0,
|
index: 0,
|
||||||
enabled: 1,
|
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 appsEndpoint = 'api/applications';
|
||||||
const appsOrderEndpoint = 'api/applicationOrder';
|
const appsOrderEndpoint = 'api/applicationOrder';
|
||||||
const { data: applicationData, isFetching: isAppsFetching } = useQueryAPI({
|
const { data: applicationData, isFetching: isAppsFetching } = useQueryAPI({
|
||||||
@@ -48,7 +58,6 @@ const ApplicationSettings = () => {
|
|||||||
const [applications, setApplications] = useState<Application[]>([]);
|
const [applications, setApplications] = useState<Application[]>([]);
|
||||||
const [applicationList, setApplicationList] = useState<Application[]>([]);
|
const [applicationList, setApplicationList] = useState<Application[]>([]);
|
||||||
const { isMobile, reorder } = useCommonHooks();
|
const { isMobile, reorder } = useCommonHooks();
|
||||||
const [newApplication, setNewApplication] = useState<Application>(defaultApplication);
|
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
@@ -80,7 +89,7 @@ const ApplicationSettings = () => {
|
|||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
closeModal();
|
closeModal();
|
||||||
setNewApplication(defaultApplication);
|
form.reset();
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (applicationData && !isAppsFetching) {
|
if (applicationData && !isAppsFetching) {
|
||||||
@@ -116,52 +125,57 @@ const ApplicationSettings = () => {
|
|||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
title={'Add a new application'}
|
title={'Add a new application'}
|
||||||
body={
|
body={
|
||||||
|
<form
|
||||||
|
onSubmit={form.onSubmit((values) => {
|
||||||
|
mutateAsync({
|
||||||
|
method: 'POST',
|
||||||
|
endpoint: appsEndpoint,
|
||||||
|
body: {
|
||||||
|
...values,
|
||||||
|
index: applications.length,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
handleClose();
|
||||||
|
})}
|
||||||
|
>
|
||||||
<Stack gap={0} align='center'>
|
<Stack gap={0} align='center'>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('name')}
|
||||||
|
{...form.getInputProps('name')}
|
||||||
label={'Name'}
|
label={'Name'}
|
||||||
|
placeholder='Nextcloud'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
w={'45%'}
|
w={'45%'}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newApplication.name}
|
withAsterisk
|
||||||
onChange={(event) => {
|
|
||||||
setNewApplication({
|
|
||||||
...newApplication,
|
|
||||||
name: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('baseUrl')}
|
||||||
|
{...form.getInputProps('baseUrl')}
|
||||||
label={'Base URL'}
|
label={'Base URL'}
|
||||||
|
placeholder='/nextcloud'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
w={'45%'}
|
w={'45%'}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newApplication.baseUrl}
|
|
||||||
onChange={(event) => {
|
|
||||||
setNewApplication({
|
|
||||||
...newApplication,
|
|
||||||
baseUrl: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group w={isMobile ? '94%' : '92%'} justify='center'>
|
<Group w={isMobile ? '94%' : '92%'} justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('url')}
|
||||||
|
{...form.getInputProps('url')}
|
||||||
label={'URL'}
|
label={'URL'}
|
||||||
|
placeholder='https://domain.example.com/nextcloud'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
w={'100%'}
|
w={'100%'}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newApplication.url}
|
withAsterisk
|
||||||
onChange={(event) => {
|
|
||||||
setNewApplication({
|
|
||||||
...newApplication,
|
|
||||||
url: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
<Select
|
<Select
|
||||||
|
key={form.key('icon')}
|
||||||
|
{...form.getInputProps('icon')}
|
||||||
label={'Icon'}
|
label={'Icon'}
|
||||||
className={selectClasses.settingsItem}
|
className={selectClasses.settingsItem}
|
||||||
classNames={{
|
classNames={{
|
||||||
@@ -178,16 +192,9 @@ const ApplicationSettings = () => {
|
|||||||
data={Object.keys(allIcons).map((icon) => {
|
data={Object.keys(allIcons).map((icon) => {
|
||||||
return { value: icon, label: icon };
|
return { value: icon, label: icon };
|
||||||
})}
|
})}
|
||||||
defaultValue={newApplication.icon}
|
|
||||||
comboboxProps={{
|
comboboxProps={{
|
||||||
zIndex: 3000,
|
zIndex: 3000,
|
||||||
}}
|
}}
|
||||||
onChange={(value: string | null) => {
|
|
||||||
setNewApplication({
|
|
||||||
...newApplication,
|
|
||||||
icon: value ?? '',
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
|
renderOption={(item: ComboboxLikeRenderOptionInput<ComboboxItem>) => {
|
||||||
const Icon = allIcons[item.option.value];
|
const Icon = allIcons[item.option.value];
|
||||||
return (
|
return (
|
||||||
@@ -201,40 +208,28 @@ const ApplicationSettings = () => {
|
|||||||
maxDropdownHeight={175}
|
maxDropdownHeight={175}
|
||||||
onDropdownOpen={() => setIsOpen(true)}
|
onDropdownOpen={() => setIsOpen(true)}
|
||||||
onDropdownClose={() => setIsOpen(false)}
|
onDropdownClose={() => setIsOpen(false)}
|
||||||
|
withAsterisk
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('filter')}
|
||||||
|
{...form.getInputProps('filter')}
|
||||||
label={'Filter'}
|
label={'Filter'}
|
||||||
|
placeholder='Storage'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
pt={'1rem'}
|
pt={'1rem'}
|
||||||
w={'45%'}
|
w={'45%'}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newApplication.filterName}
|
defaultValue={defaultApplication.filterName}
|
||||||
onChange={(event) => {
|
withAsterisk
|
||||||
setNewApplication({
|
|
||||||
...newApplication,
|
|
||||||
filterName: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Divider color='black' my='lg' />
|
<Divider color='black' my='lg' />
|
||||||
<Group pos={'absolute'} bottom={8}>
|
<Group pos={'absolute'} bottom={8}>
|
||||||
<Button
|
<Button
|
||||||
|
type='submit'
|
||||||
color={'green'}
|
color={'green'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
|
||||||
if (newApplication) {
|
|
||||||
mutateAsync({
|
|
||||||
method: 'POST',
|
|
||||||
endpoint: appsEndpoint,
|
|
||||||
body: {
|
|
||||||
...newApplication,
|
|
||||||
index: applications.length,
|
|
||||||
},
|
|
||||||
}).then(handleClose);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
@@ -247,6 +242,7 @@ const ApplicationSettings = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
</form>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ function DebouncedApplication({
|
|||||||
name: event.target.value,
|
name: event.target.value,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
disabled
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={'Base URL'}
|
label={'Base URL'}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
|
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
|
||||||
import { Box, Button, Card, Divider, Group, Stack, Text, TextInput } from '@mantine/core';
|
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 { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -16,6 +17,13 @@ const BookmarkSettings = () => {
|
|||||||
categoryIndex: 0,
|
categoryIndex: 0,
|
||||||
filterName: '',
|
filterName: '',
|
||||||
};
|
};
|
||||||
|
const form = useForm({
|
||||||
|
initialValues: defaultGroup,
|
||||||
|
validate: {
|
||||||
|
categoryName: isNotEmpty('Category name is required'),
|
||||||
|
filterName: isNotEmpty('Filter name is required'),
|
||||||
|
},
|
||||||
|
});
|
||||||
const bookmarksEndpoint = 'api/bookmarks';
|
const bookmarksEndpoint = 'api/bookmarks';
|
||||||
const { data: bookmarkData, isFetched: bookmarksIsFetched } = useQueryAPI({
|
const { data: bookmarkData, isFetched: bookmarksIsFetched } = useQueryAPI({
|
||||||
endpoint: bookmarksEndpoint,
|
endpoint: bookmarksEndpoint,
|
||||||
@@ -27,7 +35,6 @@ const BookmarkSettings = () => {
|
|||||||
});
|
});
|
||||||
const [dragging, setDragging] = useState(false);
|
const [dragging, setDragging] = useState(false);
|
||||||
const [groups, setGroups] = useState<BookmarkGroup[]>([]);
|
const [groups, setGroups] = useState<BookmarkGroup[]>([]);
|
||||||
const [newGroup, setNewGroup] = useState<BookmarkGroup>(defaultGroup);
|
|
||||||
const [groupList, setGroupList] = useState<BookmarkGroup[]>([]);
|
const [groupList, setGroupList] = useState<BookmarkGroup[]>([]);
|
||||||
const { isMobile, reorder } = useCommonHooks();
|
const { isMobile, reorder } = useCommonHooks();
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
@@ -37,8 +44,8 @@ const BookmarkSettings = () => {
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setNewGroup(defaultGroup);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
form.reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
function onDragEnd(result: any) {
|
function onDragEnd(result: any) {
|
||||||
@@ -118,49 +125,47 @@ const BookmarkSettings = () => {
|
|||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
title={'Add a new Bookmark Group'}
|
title={'Add a new Bookmark Group'}
|
||||||
body={
|
body={
|
||||||
|
<form
|
||||||
|
onSubmit={form.onSubmit((values) => {
|
||||||
|
mutateAsync({
|
||||||
|
method: 'POST',
|
||||||
|
endpoint: categoriesEndpoint,
|
||||||
|
body: {
|
||||||
|
...values,
|
||||||
|
categoryIndex: groups.length,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
handleClose();
|
||||||
|
})}
|
||||||
|
>
|
||||||
<Stack gap={0} w={'100%'} align='center'>
|
<Stack gap={0} w={'100%'} align='center'>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('categoryName')}
|
||||||
|
{...form.getInputProps('categoryName')}
|
||||||
label={'Category Name'}
|
label={'Category Name'}
|
||||||
|
placeholder='Shopping'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newGroup.categoryName}
|
withAsterisk
|
||||||
onChange={(event) => {
|
|
||||||
setNewGroup({
|
|
||||||
...newGroup,
|
|
||||||
categoryName: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('filterName')}
|
||||||
|
{...form.getInputProps('filterName')}
|
||||||
label={'Filter Name'}
|
label={'Filter Name'}
|
||||||
|
placeholder='Personal'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newGroup.filterName}
|
withAsterisk
|
||||||
onChange={(event) => {
|
|
||||||
setNewGroup({
|
|
||||||
...newGroup,
|
|
||||||
filterName: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Divider color='black' my='lg' />
|
<Divider color='black' my='lg' />
|
||||||
<Group pos={'absolute'} bottom={8}>
|
<Group pos={'absolute'} bottom={8}>
|
||||||
<Button
|
<Button
|
||||||
|
type='submit'
|
||||||
color={'green'}
|
color={'green'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
|
||||||
if (newGroup) {
|
|
||||||
mutateAsync({
|
|
||||||
method: 'POST',
|
|
||||||
endpoint: categoriesEndpoint,
|
|
||||||
body: { ...newGroup, categoryIndex: groups.length },
|
|
||||||
});
|
|
||||||
handleClose();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
@@ -173,6 +178,7 @@ const BookmarkSettings = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
</form>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
|
import { isNotEmpty, useForm } from '@mantine/form';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -47,6 +48,13 @@ function DebouncedGroupSettingsItem({
|
|||||||
category: group.categoryName,
|
category: group.categoryName,
|
||||||
index: 0,
|
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 [bookmarkList, setBookmarkList] = useState<Bookmark[]>(bookmarks);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
@@ -193,7 +201,7 @@ function DebouncedGroupSettingsItem({
|
|||||||
borderRadius: '100%',
|
borderRadius: '100%',
|
||||||
backgroundColor: 'var(--mantine-color-accent-0)',
|
backgroundColor: 'var(--mantine-color-accent-0)',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: isMobile ? 140 : 78,
|
top: isMobile ? 140 : 92,
|
||||||
right: 18,
|
right: 18,
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
fontSize: '1.25rem',
|
fontSize: '1.25rem',
|
||||||
@@ -307,10 +315,24 @@ function DebouncedGroupSettingsItem({
|
|||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown w={isMobile ? '90%' : undefined}>
|
<Popover.Dropdown w={isMobile ? '90%' : undefined}>
|
||||||
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
<Card className={cardClasses.settingsItem} classNames={cardClasses}>
|
||||||
|
<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'}>
|
<Stack w={'100%'} display={'flex'} pos={'relative'}>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('name')}
|
||||||
|
{...form.getInputProps('name')}
|
||||||
label={'Name'}
|
label={'Name'}
|
||||||
|
placeholder='Google'
|
||||||
labelProps={{
|
labelProps={{
|
||||||
style: {
|
style: {
|
||||||
color: 'var(--mantine-color-primary-0)',
|
color: 'var(--mantine-color-primary-0)',
|
||||||
@@ -319,14 +341,11 @@ function DebouncedGroupSettingsItem({
|
|||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
pt={'1rem'}
|
pt={'1rem'}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
onChange={(event) => {
|
withAsterisk
|
||||||
setNewBookmark({
|
|
||||||
...newBookmark,
|
|
||||||
name: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('category')}
|
||||||
|
{...form.getInputProps('category')}
|
||||||
label={'Category'}
|
label={'Category'}
|
||||||
labelProps={{
|
labelProps={{
|
||||||
style: {
|
style: {
|
||||||
@@ -338,17 +357,14 @@ function DebouncedGroupSettingsItem({
|
|||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
disabled
|
disabled
|
||||||
defaultValue={group.categoryName}
|
defaultValue={group.categoryName}
|
||||||
onChange={(event) => {
|
|
||||||
setNewBookmark({
|
|
||||||
...newBookmark,
|
|
||||||
category: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group w={'100%'} justify='center' mb={60}>
|
<Group w={'100%'} justify='center' mb={60}>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('url')}
|
||||||
|
{...form.getInputProps('url')}
|
||||||
label={'URL'}
|
label={'URL'}
|
||||||
|
placeholder='https://google.com'
|
||||||
labelProps={{
|
labelProps={{
|
||||||
style: {
|
style: {
|
||||||
color: 'var(--mantine-color-primary-0)',
|
color: 'var(--mantine-color-primary-0)',
|
||||||
@@ -358,12 +374,7 @@ function DebouncedGroupSettingsItem({
|
|||||||
w={'100%'}
|
w={'100%'}
|
||||||
pt={'1rem'}
|
pt={'1rem'}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
onChange={(event) => {
|
withAsterisk
|
||||||
setNewBookmark({
|
|
||||||
...newBookmark,
|
|
||||||
url: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group
|
<Group
|
||||||
@@ -374,18 +385,9 @@ function DebouncedGroupSettingsItem({
|
|||||||
justify='center'
|
justify='center'
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
|
type='submit'
|
||||||
color={'green'}
|
color={'green'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
|
||||||
if (newBookmark) {
|
|
||||||
mutateAsync({
|
|
||||||
method: 'POST',
|
|
||||||
endpoint: 'api/bookmarks',
|
|
||||||
body: { ...newBookmark, index: bookmarks.length },
|
|
||||||
});
|
|
||||||
setPopoverOpened(false);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
@@ -394,12 +396,14 @@ function DebouncedGroupSettingsItem({
|
|||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setPopoverOpened(false);
|
setPopoverOpened(false);
|
||||||
|
form.reset();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
</form>
|
||||||
</Card>
|
</Card>
|
||||||
</Popover.Dropdown>
|
</Popover.Dropdown>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
TextInput,
|
TextInput,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
|
import { isNotEmpty, useForm } from '@mantine/form';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -27,6 +28,14 @@ const SearchProviderSettings = () => {
|
|||||||
url: '',
|
url: '',
|
||||||
prefix: '',
|
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 endpoint = 'api/providers';
|
||||||
const { data: providerData, isFetched: providerDataIsFetched } = useQueryAPI({
|
const { data: providerData, isFetched: providerDataIsFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
@@ -34,7 +43,6 @@ const SearchProviderSettings = () => {
|
|||||||
const [providers, setProviders] = useState<Provider[]>([]);
|
const [providers, setProviders] = useState<Provider[]>([]);
|
||||||
const { isMobile } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const [newProvider, setNewProvider] = useState<Provider>(defaultProvider);
|
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
@@ -42,8 +50,8 @@ const SearchProviderSettings = () => {
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setNewProvider(defaultProvider);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
form.reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -70,62 +78,55 @@ const SearchProviderSettings = () => {
|
|||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
title={'Add a new Search Provider'}
|
title={'Add a new Search Provider'}
|
||||||
body={
|
body={
|
||||||
|
<form
|
||||||
|
onSubmit={form.onSubmit((values) => {
|
||||||
|
mutateAsync({
|
||||||
|
method: 'POST',
|
||||||
|
endpoint: endpoint,
|
||||||
|
body: values,
|
||||||
|
});
|
||||||
|
handleClose();
|
||||||
|
})}
|
||||||
|
>
|
||||||
<Stack gap={0} w={'100%'} align='center'>
|
<Stack gap={0} w={'100%'} align='center'>
|
||||||
<Stack w={'100%'} align='center'>
|
<Stack w={'100%'} align='center'>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('name')}
|
||||||
|
{...form.getInputProps('name')}
|
||||||
label={'Name'}
|
label={'Name'}
|
||||||
|
placeholder='Google'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newProvider.name}
|
withAsterisk
|
||||||
onChange={(event) => {
|
|
||||||
setNewProvider({
|
|
||||||
...newProvider,
|
|
||||||
name: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('prefix')}
|
||||||
|
{...form.getInputProps('prefix')}
|
||||||
label={'Prefix'}
|
label={'Prefix'}
|
||||||
|
placeholder='/g'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newProvider.prefix}
|
withAsterisk
|
||||||
onChange={(event) => {
|
|
||||||
setNewProvider({
|
|
||||||
...newProvider,
|
|
||||||
prefix: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('url')}
|
||||||
|
{...form.getInputProps('url')}
|
||||||
label={'Url'}
|
label={'Url'}
|
||||||
|
placeholder='https://www.google.com/search?q='
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
w={isMobile ? '64%' : '100%'}
|
w={'64%'}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newProvider.url}
|
withAsterisk
|
||||||
onChange={(event) => {
|
|
||||||
setNewProvider({
|
|
||||||
...newProvider,
|
|
||||||
url: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Divider color='black' my='lg' />
|
<Divider color='black' my='lg' />
|
||||||
<Group pos={'absolute'} bottom={8}>
|
<Group pos={'absolute'} bottom={8}>
|
||||||
<Button
|
<Button
|
||||||
|
type='submit'
|
||||||
color={'green'}
|
color={'green'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
|
||||||
if (newProvider) {
|
|
||||||
mutateAsync({
|
|
||||||
method: 'POST',
|
|
||||||
endpoint: endpoint,
|
|
||||||
body: newProvider,
|
|
||||||
}).then(handleClose);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
@@ -138,6 +139,7 @@ const SearchProviderSettings = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
</form>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
TextInput,
|
TextInput,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
|
import { isNotEmpty, matches, useForm } from '@mantine/form';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -25,6 +26,16 @@ const WolClientSettings = () => {
|
|||||||
hostname: '',
|
hostname: '',
|
||||||
macAddress: '',
|
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 endpoint = 'api/wolClients';
|
||||||
const { data: wolClientsData, isFetched: wolClientsIsFetched } = useQueryAPI({
|
const { data: wolClientsData, isFetched: wolClientsIsFetched } = useQueryAPI({
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
@@ -32,7 +43,6 @@ const WolClientSettings = () => {
|
|||||||
const [wolClients, setWolClients] = useState<WolClient[]>([]);
|
const [wolClients, setWolClients] = useState<WolClient[]>([]);
|
||||||
const { mutateAsync } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const { isMobile } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
const [newWolClient, setNewWolClient] = useState<WolClient>(defaultWolClient);
|
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
@@ -40,8 +50,8 @@ const WolClientSettings = () => {
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setNewWolClient(defaultWolClient);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
form.reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -64,62 +74,56 @@ const WolClientSettings = () => {
|
|||||||
handleClose={handleClose}
|
handleClose={handleClose}
|
||||||
title={'Add a new WoL Client'}
|
title={'Add a new WoL Client'}
|
||||||
body={
|
body={
|
||||||
|
<form
|
||||||
|
onSubmit={form.onSubmit((values) => {
|
||||||
|
mutateAsync({
|
||||||
|
method: 'POST',
|
||||||
|
endpoint: endpoint,
|
||||||
|
body: values,
|
||||||
|
});
|
||||||
|
handleClose();
|
||||||
|
})}
|
||||||
|
>
|
||||||
<Stack gap={0} w={'100%'} align='center'>
|
<Stack gap={0} w={'100%'} align='center'>
|
||||||
<Group w={'100%'} justify='center'>
|
<Group w={'100%'} justify='center'>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('hostname')}
|
||||||
|
{...form.getInputProps('hostname')}
|
||||||
label={'Hostname'}
|
label={'Hostname'}
|
||||||
|
placeholder='Workstation'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newWolClient.hostname}
|
withAsterisk
|
||||||
onChange={(event) => {
|
|
||||||
setNewWolClient({
|
|
||||||
...newWolClient,
|
|
||||||
hostname: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
|
key={form.key('macAddress')}
|
||||||
|
{...form.getInputProps('macAddress')}
|
||||||
label={'MAC Address'}
|
label={'MAC Address'}
|
||||||
|
placeholder='00:00:00:00:00:00'
|
||||||
className={textInputClasses.settingsItem}
|
className={textInputClasses.settingsItem}
|
||||||
classNames={textInputClasses}
|
classNames={textInputClasses}
|
||||||
defaultValue={newWolClient.macAddress}
|
withAsterisk
|
||||||
onChange={(event) => {
|
|
||||||
setNewWolClient({
|
|
||||||
...newWolClient,
|
|
||||||
macAddress: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
<Divider color='black' my='lg' />
|
<Divider color='black' my='lg' />
|
||||||
<Group pos={'absolute'} bottom={8}>
|
<Group pos={'absolute'} bottom={8}>
|
||||||
<Button
|
<Button
|
||||||
|
type='submit'
|
||||||
color={'green'}
|
color={'green'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
|
||||||
if (newWolClient) {
|
|
||||||
mutateAsync({
|
|
||||||
method: 'POST',
|
|
||||||
endpoint: endpoint,
|
|
||||||
body: newWolClient,
|
|
||||||
});
|
|
||||||
closeModal();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
color={'red'}
|
color={'red'}
|
||||||
styles={{ label: { color: 'black' } }}
|
styles={{ label: { color: 'black' } }}
|
||||||
onClick={() => {
|
onClick={handleClose}
|
||||||
closeModal();
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
</form>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
|
|||||||
Reference in New Issue
Block a user