Form updates
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user