Remove unset icon, use local form instead of API

This commit is contained in:
Manuel Ruwe
2022-12-16 19:44:57 +01:00
parent 786ef505b4
commit 657e8c9102
4 changed files with 47 additions and 56 deletions

View File

@@ -7,80 +7,75 @@ import {
Grid, Grid,
Group, Group,
Stack, Stack,
Text,
TextInput, TextInput,
ThemeIcon, ThemeIcon,
Title, Title,
Tooltip,
} from '@mantine/core'; } from '@mantine/core';
import { IconDeviceFloppy, TablerIcon } from '@tabler/icons'; import { IconDeviceFloppy, TablerIcon } from '@tabler/icons';
import { ReactNode, useState } from 'react'; import { useState } from 'react';
interface GenericSecretInputProps { interface GenericSecretInputProps {
label: string; label: string;
value: string; value: string;
secretIsPresent: boolean;
unsetIcon: TablerIcon;
setIcon: TablerIcon; setIcon: TablerIcon;
onClickUpdateButton: (value: string | undefined) => void;
} }
export const GenericSecretInput = ({ export const GenericSecretInput = ({
label, label,
value, value,
secretIsPresent,
setIcon, setIcon,
unsetIcon, onClickUpdateButton,
}: GenericSecretInputProps) => { }: GenericSecretInputProps) => {
const { classes } = useStyles(); const { classes } = useStyles();
const [dirty, setDirty] = useState(false);
const IconComponent = secretIsPresent ? setIcon : unsetIcon; const Icon = setIcon;
const [fieldValue, setFieldValue] = useState<string>(value);
return ( return (
<Card withBorder> <Card withBorder>
<Grid> <Grid>
<Grid.Col className={classes.alignSelfCenter} xs={12} md={6}> <Grid.Col className={classes.alignSelfCenter} xs={12} md={6}>
<Group spacing="sm"> <Group spacing="sm">
<ThemeIcon color={secretIsPresent ? 'green' : 'red'} variant="light"> <ThemeIcon color="green" variant="light">
<IconComponent size={16} /> <Icon size={18} />
</ThemeIcon> </ThemeIcon>
<Stack spacing={0}> <Stack spacing={0}>
<Title className={classes.subtitle} order={6}> <Title className={classes.subtitle} order={6}>
{label} {label}
</Title> </Title>
<Text size="xs" color="dimmed">
{secretIsPresent
? 'Secret is defined in the configuration'
: 'Secret has not been defined'}
</Text>
</Stack> </Stack>
</Group> </Group>
</Grid.Col> </Grid.Col>
<Grid.Col xs={12} md={6}> <Grid.Col xs={12} md={6}>
<Flex gap={10} justify="end" align="end"> <Flex gap={10} justify="end" align="end">
{secretIsPresent ? ( <Button
<> onClick={() => {
<Button variant="subtle" color="gray" px="xl"> setFieldValue('');
Clear Secret onClickUpdateButton(undefined);
</Button> }}
<TextInput variant="subtle"
type="password" color="gray"
placeholder="Leave empty" px="xl"
description={`Update secret${dirty ? ' (unsaved)' : ''}`} >
rightSection={ Clear Secret
<ActionIcon disabled={!dirty}> </Button>
<IconDeviceFloppy size={18} /> <TextInput
</ActionIcon> onChange={(event) => setFieldValue(event.currentTarget.value)}
} rightSection={
defaultValue={value} <Tooltip label="Update this secret" withinPortal>
onChange={() => setDirty(true)} <ActionIcon onClick={() => onClickUpdateButton(fieldValue)}>
withAsterisk <IconDeviceFloppy width={20} strokeWidth={1.2} />
/> </ActionIcon>
</> </Tooltip>
) : ( }
<Button variant="light" px="xl"> value={fieldValue}
Define secret type="password"
</Button> placeholder="no value is set"
)} withAsterisk
/>
</Flex> </Flex>
</Grid.Col> </Grid.Col>
</Grid> </Grid>

View File

@@ -1,6 +1,6 @@
import { Stack } from '@mantine/core'; import { Stack } from '@mantine/core';
import { UseFormReturnType } from '@mantine/form'; import { UseFormReturnType } from '@mantine/form';
import { IconKey, IconKeyOff } from '@tabler/icons'; import { IconKey } from '@tabler/icons';
import { import {
IntegrationField, IntegrationField,
integrationFieldDefinitions, integrationFieldDefinitions,
@@ -49,11 +49,13 @@ export const IntegrationOptionsRenderer = ({ form }: IntegrationOptionsRendererP
if (!definition) { if (!definition) {
return ( return (
<GenericSecretInput <GenericSecretInput
onClickUpdateButton={(value) => {
form.setFieldValue(`integration.properties.${index}.value`, value);
}}
key={`input-${property}`} key={`input-${property}`}
label={`${property} (potentionally unmapped)`} label={`${property} (potentionally unmapped)`}
secretIsPresent={isPresent} secretIsPresent={isPresent}
setIcon={IconKey} setIcon={IconKey}
unsetIcon={IconKeyOff}
{...form.getInputProps(`integration.properties.${index}.value`)} {...form.getInputProps(`integration.properties.${index}.value`)}
/> />
); );
@@ -61,12 +63,14 @@ export const IntegrationOptionsRenderer = ({ form }: IntegrationOptionsRendererP
return ( return (
<GenericSecretInput <GenericSecretInput
onClickUpdateButton={(value) => {
form.setFieldValue(`integration.properties.${index}.value`, value);
}}
key={`input-${definition.label}`} key={`input-${definition.label}`}
label={definition.label} label={definition.label}
value="" value=""
secretIsPresent={isPresent} secretIsPresent={isPresent}
setIcon={definition.icon} setIcon={definition.icon}
unsetIcon={definition.iconUnset}
{...form.getInputProps(`integration.properties.${index}.value`)} {...form.getInputProps(`integration.properties.${index}.value`)}
/> />
); );

View File

@@ -21,6 +21,10 @@ export const IntegrationTab = ({ form }: IntegrationTabProps) => {
{hasIntegrationSelected && ( {hasIntegrationSelected && (
<> <>
<Divider label="Integration Configuration" labelPosition="center" mt="xl" mb="md" /> <Divider label="Integration Configuration" labelPosition="center" mt="xl" mb="md" />
<Text size="sm" color="dimmed" mb="lg">
To update a secret, enter a value and click the save button. To remove a secret, use the
clear button.
</Text>
<IntegrationOptionsRenderer form={form} /> <IntegrationOptionsRenderer form={form} />
<Alert icon={<IconAlertTriangle />} color="yellow"> <Alert icon={<IconAlertTriangle />} color="yellow">
<Text> <Text>

View File

@@ -1,12 +1,4 @@
import { import { IconKey, IconPassword, IconUser, TablerIcon } from '@tabler/icons';
IconKey,
IconKeyOff,
IconLockOff,
IconPassword,
IconUser,
IconUserOff,
TablerIcon,
} from '@tabler/icons';
import { TileBaseType } from './tile'; import { TileBaseType } from './tile';
export interface ServiceType extends TileBaseType { export interface ServiceType extends TileBaseType {
@@ -62,7 +54,7 @@ export type ConfigServiceIntegrationType = Omit<ServiceIntegrationType, 'propert
export type ServiceIntegrationPropertyType = { export type ServiceIntegrationPropertyType = {
type: 'private' | 'public'; type: 'private' | 'public';
field: IntegrationField; field: IntegrationField;
value?: string | null; value?: string | undefined;
isDefined: boolean; isDefined: boolean;
}; };
@@ -89,7 +81,6 @@ export const integrationFieldProperties: {
export type IntegrationFieldDefinitionType = { export type IntegrationFieldDefinitionType = {
type: 'private' | 'public'; type: 'private' | 'public';
icon: TablerIcon; icon: TablerIcon;
iconUnset: TablerIcon;
label: string; label: string;
}; };
@@ -99,19 +90,16 @@ export const integrationFieldDefinitions: {
apiKey: { apiKey: {
type: 'private', type: 'private',
icon: IconKey, icon: IconKey,
iconUnset: IconKeyOff,
label: 'API Key', label: 'API Key',
}, },
username: { username: {
type: 'public', type: 'public',
icon: IconUser, icon: IconUser,
iconUnset: IconUserOff,
label: 'Username', label: 'Username',
}, },
password: { password: {
type: 'private', type: 'private',
icon: IconPassword, icon: IconPassword,
iconUnset: IconLockOff,
label: 'Password', label: 'Password',
}, },
}; };