Add new types for integration configuration

This commit is contained in:
Meierschlumpf
2022-12-11 19:16:31 +01:00
parent 68a97e5f27
commit ed64d138c5
10 changed files with 153 additions and 66 deletions

View File

@@ -12,15 +12,15 @@ import {
ThemeIcon,
Title,
} from '@mantine/core';
import { IconDeviceFloppy } from '@tabler/icons';
import { IconDeviceFloppy, TablerIcon } from '@tabler/icons';
import { ReactNode, useState } from 'react';
interface GenericSecretInputProps {
label: string;
value: string;
secretIsPresent: boolean;
unsetIcon: ReactNode;
setIcon: ReactNode;
unsetIcon: TablerIcon;
setIcon: TablerIcon;
}
export const GenericSecretInput = ({
@@ -33,13 +33,15 @@ export const GenericSecretInput = ({
const { classes } = useStyles();
const [dirty, setDirty] = useState(false);
const IconComponent = secretIsPresent ? setIcon : unsetIcon;
return (
<Card withBorder>
<Grid>
<Grid.Col className={classes.alignSelfCenter} xs={12} md={6}>
<Group spacing="sm">
<ThemeIcon color={secretIsPresent ? 'green' : 'red'} variant="light">
{secretIsPresent ? setIcon : unsetIcon}
<IconComponent size={16} />
</ThemeIcon>
<Stack spacing={0}>
<Title className={classes.subtitle} order={6}>

View File

@@ -3,7 +3,15 @@ import { Group, Select, SelectItem, Text } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form';
import { useTranslation } from 'next-i18next';
import { forwardRef } from 'react';
import { ServiceType } from '../../../../../../../../types/service';
import { IntegrationsType } from '../../../../../../../../types/integration';
import {
IntegrationField,
integrationFieldDefinitions,
integrationFieldProperties,
ServiceIntegrationPropertyType,
ServiceIntegrationType,
ServiceType,
} from '../../../../../../../../types/service';
interface IntegrationSelectorProps {
form: UseFormReturnType<ServiceType, (item: ServiceType) => ServiceType>;
@@ -44,7 +52,23 @@ export const IntegrationSelector = ({ form }: IntegrationSelectorProps) => {
image: 'https://cdn.jsdelivr.net/gh/walkxhub/dashboard-icons/png/overseerr.png',
label: 'Overseerr',
},
];
].filter((x) => Object.keys(integrationFieldProperties).includes(x.value));
const inputProps = form.getInputProps('integration.type');
const getNewProperties = (value: string | null): ServiceIntegrationPropertyType[] => {
if (!value) return [];
const requiredProperties = Object.entries(integrationFieldDefinitions).filter(([k, v]) => {
const val = integrationFieldProperties[value as ServiceIntegrationType['type']];
return val.includes(k as IntegrationField);
})!;
return requiredProperties.map(([k, value]) => ({
type: value.type,
field: k as IntegrationField,
value: undefined,
isDefined: false,
}));
};
return (
<>
@@ -58,8 +82,22 @@ export const IntegrationSelector = ({ form }: IntegrationSelectorProps) => {
clearable
variant="default"
mb="md"
icon={form.values.integration?.type && <img src={data.find(x => x.value === form.values.integration?.type)?.image} alt="test" width={20} height={20} />}
{...form.getInputProps('integration.type')}
icon={
form.values.integration?.type && (
<img
src={data.find((x) => x.value === form.values.integration?.type)?.image}
alt="test"
width={20}
height={20}
/>
)
}
{...inputProps}
onChange={(value) => {
form.setFieldValue('integration.properties', getNewProperties(value));
console.log(`changed to value ${value}`);
inputProps.onChange(value);
}}
/>
</>
);

View File

@@ -3,9 +3,9 @@ import { UseFormReturnType } from '@mantine/form';
import { IconKey, IconKeyOff, IconLock, IconLockOff, IconUser, IconUserOff } from '@tabler/icons';
import {
IntegrationField,
IntegrationFieldDefinitionType,
integrationFieldDefinitions,
integrationFieldProperties,
ServiceIntegrationPropertyType,
ServiceType,
} from '../../../../../../../../types/service';
import { GenericSecretInput } from '../InputElements/GenericSecretInput';
@@ -14,27 +14,6 @@ interface IntegrationOptionsRendererProps {
form: UseFormReturnType<ServiceType, (values: ServiceType) => ServiceType>;
}
const secretMappings = [
{
label: 'username',
prettyName: 'Username',
icon: <IconUser size={18} />,
iconUnset: <IconUserOff size={18} />,
},
{
label: 'password',
prettyName: 'Password',
icon: <IconLock size={18} />,
iconUnset: <IconLockOff size={18} />,
},
{
label: 'apiKey',
prettyName: 'API Key',
icon: <IconKey size={18} />,
iconUnset: <IconKeyOff size={18} />,
},
];
export const IntegrationOptionsRenderer = ({ form }: IntegrationOptionsRendererProps) => {
const selectedIntegration = form.values.integration?.type;
@@ -44,31 +23,49 @@ export const IntegrationOptionsRenderer = ({ form }: IntegrationOptionsRendererP
return (
<Stack spacing="xs" mb="md">
{displayedProperties.map((property) => {
const mapping = Object.entries(integrationFieldDefinitions).find(
([key, value]) => key as IntegrationField === property
);
const isPresent = entry[1] !== undefined;
{displayedProperties.map((property, index) => {
const [_, definition] = Object.entries(integrationFieldDefinitions).find(
([key]) => property === key
)!;
if (!mapping) {
let indexInFormValue =
form.values.integration?.properties.findIndex((p) => p.field === property) ?? -1;
if (indexInFormValue === -1) {
const type = Object.entries(integrationFieldDefinitions).find(
([k, v]) => k === property
)![1].type;
const newProperty: ServiceIntegrationPropertyType = {
type,
field: property as IntegrationField,
isDefined: false,
};
form.insertListItem('integration.properties', newProperty);
indexInFormValue = form.values.integration!.properties.length;
}
const formValue = form.values.integration?.properties[indexInFormValue];
const isPresent = formValue?.isDefined;
if (!definition) {
return (
<GenericSecretInput
label={`${entry[0]} (potentionally unmapped)`}
value={entry[1]}
label={`${property} (potentionally unmapped)`}
secretIsPresent={isPresent}
setIcon={<IconKey size={18} />}
unsetIcon={<IconKeyOff size={18} />}
setIcon={IconKey}
unsetIcon={IconKeyOff}
{...form.getInputProps(`integration.properties.${index}.value`)}
/>
);
}
return (
<GenericSecretInput
label={mapping.prettyName}
value={entry[1]}
label={definition.label}
value=""
secretIsPresent={isPresent}
setIcon={mapping.icon}
unsetIcon={mapping.iconUnset}
setIcon={definition.icon}
unsetIcon={definition.iconUnset}
{...form.getInputProps(`integration.properties.${index}.value`)}
/>
);
})}

View File

@@ -64,7 +64,7 @@ export const Tiles: TileDefinitionProps = {
maxHeight: 12,
},
useNet: {
component: UseNetTile, //CalendarTile,
component: UseNetTile,
minWidth: 4,
maxWidth: 12,
minHeight: 5,