2022-12-08 20:42:12 +01:00
|
|
|
import { Alert, Button, createStyles, Group, Stack, Tabs, Text, ThemeIcon } from '@mantine/core';
|
2022-12-04 21:19:40 +01:00
|
|
|
import { useForm } from '@mantine/form';
|
2022-12-05 21:43:47 +01:00
|
|
|
import { ContextModalProps } from '@mantine/modals';
|
2022-12-08 20:42:12 +01:00
|
|
|
import {
|
|
|
|
|
IconAccessPoint,
|
|
|
|
|
IconAdjustments,
|
|
|
|
|
IconAlertTriangle,
|
|
|
|
|
IconBrush,
|
|
|
|
|
IconClick,
|
|
|
|
|
IconPlug,
|
|
|
|
|
} from '@tabler/icons';
|
2022-12-04 21:19:40 +01:00
|
|
|
import { useTranslation } from 'next-i18next';
|
2022-12-06 20:48:35 +01:00
|
|
|
import { useState } from 'react';
|
|
|
|
|
import { useConfigContext } from '../../../../config/provider';
|
|
|
|
|
import { useConfigStore } from '../../../../config/store';
|
2022-12-18 22:27:01 +01:00
|
|
|
import { AppType } from '../../../../types/app';
|
2022-12-04 21:19:40 +01:00
|
|
|
import { AppearanceTab } from './Tabs/AppereanceTab/AppereanceTab';
|
|
|
|
|
import { BehaviourTab } from './Tabs/BehaviourTab/BehaviourTab';
|
|
|
|
|
import { GeneralTab } from './Tabs/GeneralTab/GeneralTab';
|
|
|
|
|
import { IntegrationTab } from './Tabs/IntegrationTab/IntegrationTab';
|
|
|
|
|
import { NetworkTab } from './Tabs/NetworkTab/NetworkTab';
|
2022-12-18 22:27:01 +01:00
|
|
|
import { DebouncedAppIcon } from './Tabs/Shared/DebouncedAppIcon';
|
|
|
|
|
import { EditAppModalTab } from './Tabs/type';
|
2022-12-06 20:48:35 +01:00
|
|
|
|
2022-12-18 22:27:01 +01:00
|
|
|
const appUrlRegex =
|
2022-12-06 20:48:35 +01:00
|
|
|
'(https?://(?:www.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9].[^\\s]{2,}|www.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9].[^\\s]{2,}|https?://(?:www.|(?!www))[a-zA-Z0-9]+.[^\\s]{2,}|www.[a-zA-Z0-9]+.[^\\s]{2,})';
|
2022-12-04 21:19:40 +01:00
|
|
|
|
2022-12-18 22:27:01 +01:00
|
|
|
export const EditAppModal = ({
|
2022-12-04 21:19:40 +01:00
|
|
|
context,
|
|
|
|
|
id,
|
|
|
|
|
innerProps,
|
2022-12-18 22:27:01 +01:00
|
|
|
}: ContextModalProps<{ app: AppType; allowAppNamePropagation: boolean }>) => {
|
2022-12-04 21:19:40 +01:00
|
|
|
const { t } = useTranslation();
|
2022-12-06 20:48:35 +01:00
|
|
|
const { name: configName, config } = useConfigContext();
|
|
|
|
|
const updateConfig = useConfigStore((store) => store.updateConfig);
|
2022-12-18 22:27:01 +01:00
|
|
|
const [allowAppNamePropagation, setAllowAppNamePropagation] = useState<boolean>(
|
|
|
|
|
innerProps.allowAppNamePropagation
|
2022-12-11 19:32:51 +01:00
|
|
|
);
|
2022-12-04 21:19:40 +01:00
|
|
|
|
2022-12-18 22:27:01 +01:00
|
|
|
const form = useForm<AppType>({
|
|
|
|
|
initialValues: innerProps.app,
|
2022-12-06 20:48:35 +01:00
|
|
|
validate: {
|
|
|
|
|
name: (name) => (!name ? 'Name is required' : null),
|
|
|
|
|
url: (url) => {
|
|
|
|
|
if (!url) {
|
|
|
|
|
return 'Url is required';
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-18 22:27:01 +01:00
|
|
|
if (!url.match(appUrlRegex)) {
|
2022-12-06 20:48:35 +01:00
|
|
|
return 'Value is not a valid url';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
},
|
2022-12-08 20:42:12 +01:00
|
|
|
appearance: {
|
|
|
|
|
iconUrl: (url: string) => {
|
|
|
|
|
if (url.length < 1) {
|
|
|
|
|
return 'This field is required';
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 20:48:35 +01:00
|
|
|
return null;
|
2022-12-08 20:42:12 +01:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
behaviour: {
|
|
|
|
|
onClickUrl: (url: string) => {
|
|
|
|
|
if (url === undefined || url.length < 1) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2022-12-06 20:48:35 +01:00
|
|
|
|
2022-12-18 22:27:01 +01:00
|
|
|
if (!url.match(appUrlRegex)) {
|
2022-12-08 20:42:12 +01:00
|
|
|
return 'Uri override is not a valid uri';
|
|
|
|
|
}
|
2022-12-06 20:48:35 +01:00
|
|
|
|
2022-12-08 20:42:12 +01:00
|
|
|
return null;
|
|
|
|
|
},
|
2022-12-06 20:48:35 +01:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
validateInputOnChange: true,
|
2022-12-04 21:19:40 +01:00
|
|
|
});
|
|
|
|
|
|
2022-12-18 22:27:01 +01:00
|
|
|
const onSubmit = (values: AppType) => {
|
2022-12-06 20:48:35 +01:00
|
|
|
if (!configName) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateConfig(configName, (previousConfig) => ({
|
|
|
|
|
...previousConfig,
|
2022-12-18 22:27:01 +01:00
|
|
|
apps: [...previousConfig.apps.filter((x) => x.id !== form.values.id), form.values],
|
2022-12-06 20:48:35 +01:00
|
|
|
}));
|
2022-12-07 10:48:20 +01:00
|
|
|
|
|
|
|
|
// also close the parent modal
|
|
|
|
|
context.closeAll();
|
2022-12-04 21:19:40 +01:00
|
|
|
};
|
|
|
|
|
|
2022-12-18 22:27:01 +01:00
|
|
|
const [activeTab, setActiveTab] = useState<EditAppModalTab>('general');
|
2022-12-06 20:48:35 +01:00
|
|
|
|
2022-12-11 19:32:51 +01:00
|
|
|
const closeModal = () => {
|
2022-12-04 21:19:40 +01:00
|
|
|
context.closeModal(id);
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-08 20:42:12 +01:00
|
|
|
const validationErrors = Object.keys(form.errors);
|
|
|
|
|
|
|
|
|
|
const ValidationErrorIndicator = ({ keys }: { keys: string[] }) => {
|
|
|
|
|
const relevantErrors = validationErrors.filter((x) => keys.includes(x));
|
|
|
|
|
|
|
|
|
|
return (
|
2022-12-11 21:01:13 +01:00
|
|
|
<ThemeIcon
|
|
|
|
|
opacity={relevantErrors.length === 0 ? 0 : 1}
|
|
|
|
|
color="red"
|
|
|
|
|
size={18}
|
|
|
|
|
variant="light"
|
|
|
|
|
>
|
2022-12-08 20:42:12 +01:00
|
|
|
<IconAlertTriangle size={15} />
|
|
|
|
|
</ThemeIcon>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-04 21:19:40 +01:00
|
|
|
return (
|
|
|
|
|
<>
|
2022-12-06 20:48:35 +01:00
|
|
|
{configName === undefined ||
|
|
|
|
|
(config === undefined && (
|
|
|
|
|
<Alert color="red">
|
|
|
|
|
There was an unexpected problem loading the configuration. Functionality might be
|
|
|
|
|
restricted. Please report this incident.
|
|
|
|
|
</Alert>
|
|
|
|
|
))}
|
2022-12-04 21:19:40 +01:00
|
|
|
<Stack spacing={0} align="center" my="lg">
|
2022-12-18 22:27:01 +01:00
|
|
|
<DebouncedAppIcon form={form} width={120} height={120} />
|
2022-12-04 21:19:40 +01:00
|
|
|
|
|
|
|
|
<Text align="center" weight="bold" size="lg" mt="md">
|
2022-12-18 22:27:01 +01:00
|
|
|
{form.values.name ?? 'New App'}
|
2022-12-04 21:19:40 +01:00
|
|
|
</Text>
|
|
|
|
|
</Stack>
|
2022-12-08 20:42:12 +01:00
|
|
|
|
2022-12-04 21:19:40 +01:00
|
|
|
<form onSubmit={form.onSubmit(onSubmit)}>
|
2022-12-06 20:48:35 +01:00
|
|
|
<Tabs
|
|
|
|
|
value={activeTab}
|
2022-12-18 22:27:01 +01:00
|
|
|
onTabChange={(tab) => setActiveTab(tab as EditAppModalTab)}
|
2022-12-06 20:48:35 +01:00
|
|
|
defaultValue="general"
|
|
|
|
|
>
|
2022-12-04 21:19:40 +01:00
|
|
|
<Tabs.List grow>
|
2022-12-08 20:42:12 +01:00
|
|
|
<Tabs.Tab
|
|
|
|
|
rightSection={<ValidationErrorIndicator keys={['name', 'url']} />}
|
|
|
|
|
icon={<IconAdjustments size={14} />}
|
|
|
|
|
value="general"
|
|
|
|
|
>
|
2022-12-04 21:19:40 +01:00
|
|
|
General
|
|
|
|
|
</Tabs.Tab>
|
2022-12-08 20:42:12 +01:00
|
|
|
<Tabs.Tab
|
|
|
|
|
rightSection={<ValidationErrorIndicator keys={['behaviour.onClickUrl']} />}
|
|
|
|
|
icon={<IconClick size={14} />}
|
|
|
|
|
value="behaviour"
|
|
|
|
|
>
|
2022-12-04 21:19:40 +01:00
|
|
|
Behaviour
|
|
|
|
|
</Tabs.Tab>
|
2022-12-08 20:42:12 +01:00
|
|
|
<Tabs.Tab
|
|
|
|
|
rightSection={<ValidationErrorIndicator keys={[]} />}
|
|
|
|
|
icon={<IconAccessPoint size={14} />}
|
|
|
|
|
value="network"
|
|
|
|
|
>
|
2022-12-04 21:19:40 +01:00
|
|
|
Network
|
|
|
|
|
</Tabs.Tab>
|
2022-12-08 20:42:12 +01:00
|
|
|
<Tabs.Tab
|
|
|
|
|
rightSection={<ValidationErrorIndicator keys={['appearance.iconUrl']} />}
|
|
|
|
|
icon={<IconBrush size={14} />}
|
|
|
|
|
value="appearance"
|
|
|
|
|
>
|
2022-12-04 21:19:40 +01:00
|
|
|
Appearance
|
|
|
|
|
</Tabs.Tab>
|
2022-12-08 20:42:12 +01:00
|
|
|
<Tabs.Tab
|
|
|
|
|
rightSection={<ValidationErrorIndicator keys={[]} />}
|
|
|
|
|
icon={<IconPlug size={14} />}
|
|
|
|
|
value="integration"
|
|
|
|
|
>
|
2022-12-04 21:19:40 +01:00
|
|
|
Integration
|
|
|
|
|
</Tabs.Tab>
|
|
|
|
|
</Tabs.List>
|
|
|
|
|
|
2022-12-06 20:48:35 +01:00
|
|
|
<GeneralTab form={form} openTab={(targetTab) => setActiveTab(targetTab)} />
|
2022-12-04 21:19:40 +01:00
|
|
|
<BehaviourTab form={form} />
|
|
|
|
|
<NetworkTab form={form} />
|
2022-12-11 19:32:51 +01:00
|
|
|
<AppearanceTab
|
|
|
|
|
form={form}
|
2022-12-18 22:27:01 +01:00
|
|
|
disallowAppNameProgagation={() => setAllowAppNamePropagation(false)}
|
|
|
|
|
allowAppNamePropagation={allowAppNamePropagation}
|
2022-12-11 19:32:51 +01:00
|
|
|
/>
|
2022-12-04 21:19:40 +01:00
|
|
|
<IntegrationTab form={form} />
|
|
|
|
|
</Tabs>
|
|
|
|
|
|
|
|
|
|
<Group position="right" mt={100}>
|
2022-12-11 19:32:51 +01:00
|
|
|
<Button onClick={closeModal} px={50} variant="light" color="gray">
|
2022-12-04 21:19:40 +01:00
|
|
|
Cancel
|
|
|
|
|
</Button>
|
2022-12-08 20:42:12 +01:00
|
|
|
<Button disabled={!form.isValid()} px={50} type="submit">
|
2022-12-04 21:19:40 +01:00
|
|
|
Save
|
|
|
|
|
</Button>
|
|
|
|
|
</Group>
|
|
|
|
|
</form>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
};
|