Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Environment select creation #289

Merged
merged 8 commits into from
Sep 22, 2023
1 change: 1 addition & 0 deletions components/clusterDetails/clusterDetails.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const Default: StoryObj<typeof ClusterDetails> = {
gitUser: 'D-B-Hawk',
},
type: mockClusterConfig.type as ClusterType,
environment: undefined,
},
},
};
9 changes: 6 additions & 3 deletions components/clusterTable/clusterTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
ClusterType,
Cluster,
WorkloadCluster,
DraftCluster,
} from '../../types/provision';
import { InstallationType } from '../../types/redux';
import Typography from '../../components/typography';
Expand Down Expand Up @@ -139,7 +140,9 @@ const ClusterRow: FunctionComponent<ClusterRowProps> = ({
</StyledTableCell>
<StyledTableCell selected={rowSelected}>
<StyledCellText variant="body2">
{environment && <Tag text={environment} bgColor="light-blue" />}
{environment && (
<Tag text={environment.environmentName} bgColor={environment.labelColor} />
)}
</StyledCellText>
</StyledTableCell>
<StyledTableCell align="left" selected={rowSelected}>
Expand Down Expand Up @@ -267,7 +270,7 @@ const ClusterTableHead: FunctionComponent<ClusterTableHeadProps> = ({ orderBy, o

interface ClusterTableProps extends ComponentPropsWithoutRef<'div'> {
managementCluster: ManagementCluster;
draftCluster?: WorkloadCluster;
draftCluster?: DraftCluster;
onDeleteCluster: () => void;
onMenuOpenClose: (presentedCluster?: Cluster) => void;
presentedClusterId?: string;
Expand Down Expand Up @@ -296,7 +299,7 @@ export const ClusterTable: FunctionComponent<ClusterTableProps> = ({
const filteredWorkloadClusters = useMemo(() => {
const clustersCopy = [...workloadClusters];
if (draftCluster) {
clustersCopy.push(draftCluster);
clustersCopy.push(draftCluster as WorkloadCluster);
}

return clustersCopy
Expand Down
2 changes: 1 addition & 1 deletion components/controlledFields/TextField.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo, useState } from 'react';
import React, { useState } from 'react';
import { Control, Controller, FieldValues, UseControllerProps } from 'react-hook-form';

import TextFieldWithRef from '../textField/index';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React, { useState } from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { useForm } from 'react-hook-form';

import { CreateEnvironmentMenu } from '../../createEnvironmentMenu';
import Modal from '../../modal';
import useModal from '../../../hooks/useModal';
import { ClusterEnvironment } from '../../../types/provision';

import ControlledEnvironmentSelect from './index';

const meta: Meta<typeof ControlledEnvironmentSelect> = {
component: ControlledEnvironmentSelect,
};

export default meta;

const previouslyCreatedEnvironment: ClusterEnvironment = {
environmentName: 'development',
description: 'Environment for development',
labelColor: 'dark-sky-blue',
};

const ControlledEnvironmentSelectWithHooks = () => {
const { isOpen, openModal, closeModal } = useModal(false);

const [environments, setEnvironments] = useState<ClusterEnvironment[]>([
previouslyCreatedEnvironment,
]);

const {
control,
setValue,
formState: { errors },
} = useForm<{ environment: ClusterEnvironment }>({
mode: 'onBlur',
});

const handleAddEnvironment = (environment: ClusterEnvironment) => {
setEnvironments((curState) => [...curState, environment]);
setValue('environment', environment);
closeModal();
};

return (
<>
<ControlledEnvironmentSelect
control={control}
rules={{
required: 'environment is required',
}}
name="environment"
label="Environment cluster will host"
required
onErrorText={errors.environment?.message}
options={environments}
onAddNewEnvironment={openModal}
/>
<Modal
padding={0}
isOpen={isOpen}
styleOverrides={{ width: '100%', maxWidth: '630px' }}
onCloseModal={closeModal}
>
<CreateEnvironmentMenu
onSubmit={handleAddEnvironment}
onClose={closeModal}
previouslyCreatedEnvironments={environments}
/>
</Modal>
</>
);
};

export const Default: StoryObj<typeof ControlledEnvironmentSelect> = {
render: () => <ControlledEnvironmentSelectWithHooks />,
};
49 changes: 49 additions & 0 deletions components/controlledFields/environmentSelect/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { Control, Controller, UseControllerProps, FieldValues } from 'react-hook-form';

import { EnvironmentSelectWithRef } from '../../select/';
import { ClusterEnvironment } from '../../../types/provision';

export interface ControlledEnvironmentSelectProps<T extends FieldValues>
extends UseControllerProps<T> {
label: string;
required?: boolean;
control: Control<T>;
options: ClusterEnvironment[];
onAddNewEnvironment: () => void;
helperText?: string;
onErrorText?: string;
}

function ControlledEnvironmentSelect<T extends FieldValues>({
label,
name,
required,
rules,
options,
onAddNewEnvironment,
...rest
}: ControlledEnvironmentSelectProps<T>) {
return (
<Controller
name={name}
rules={rules}
{...rest}
render={({ field, fieldState: { error } }) => (
<EnvironmentSelectWithRef
{...field}
inputRef={field.ref}
fullWidth
label={label}
error={!!error}
required={required}
options={options}
helperText={error ? rest.onErrorText : rest.helperText}
onAddNewEnvironment={onAddNewEnvironment}
/>
)}
/>
);
}

export default ControlledEnvironmentSelect;
44 changes: 44 additions & 0 deletions components/controlledFields/tagSelect/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import { Control, Controller, UseControllerProps, FieldValues } from 'react-hook-form';

import { TagSelectWithRef } from '../../select/';

export interface ControlledTagSelectProps<T extends FieldValues> extends UseControllerProps<T> {
label: string;
required?: boolean;
control: Control<T>;
options: readonly string[];
helperText?: string;
onErrorText?: string;
}

function ControlledTagSelect<T extends FieldValues>({
label,
name,
required,
rules,
options,
...rest
}: ControlledTagSelectProps<T>) {
return (
<Controller
name={name}
rules={rules}
{...rest}
render={({ field, fieldState: { error } }) => (
<TagSelectWithRef
{...field}
inputRef={field.ref}
fullWidth
label={label}
error={!!error}
required={required}
options={options}
helperText={error ? rest.onErrorText : rest.helperText}
/>
)}
/>
);
}

export default ControlledTagSelect;
38 changes: 38 additions & 0 deletions components/controlledFields/tagSelect/tagSelect.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { useForm } from 'react-hook-form';

import { TAG_COLOR_OPTIONS, TagColor } from '../../tag';

import ControlledTagSelect from './index';

const meta: Meta<typeof ControlledTagSelect> = {
component: ControlledTagSelect,
};

export default meta;

const ControlledTagSelectWithHooks = () => {
const {
control,
formState: { errors },
} = useForm<{ labelColor: TagColor }>({ defaultValues: { labelColor: 'grey' }, mode: 'onBlur' });

return (
<ControlledTagSelect
control={control}
rules={{
required: 'label color is required',
}}
name="labelColor"
label="Label color"
required
onErrorText={errors.labelColor?.message}
options={TAG_COLOR_OPTIONS}
/>
);
};

export const Default: StoryObj<typeof ControlledTagSelect> = {
render: () => <ControlledTagSelectWithHooks />,
};
39 changes: 39 additions & 0 deletions components/controlledFields/textArea/TextArea.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { useForm } from 'react-hook-form';

import ControlledTextArea from './index';

const meta: Meta<typeof ControlledTextArea> = {
component: ControlledTextArea,
};

export default meta;

const ControlledTextAreaWithHooks = () => {
const {
control,
formState: { errors },
} = useForm({ defaultValues: { description: 'test' }, mode: 'onBlur' });

return (
<ControlledTextArea
control={control}
rules={{
required: 'Description is required',
maxLength: {
value: 280,
message: 'Max 280 characters are permitted',
},
}}
label="Description"
name="description"
required
onErrorText={errors.description?.message}
/>
);
};

export const Default: StoryObj<typeof ControlledTextArea> = {
render: () => <ControlledTextAreaWithHooks />,
};
34 changes: 34 additions & 0 deletions components/controlledFields/textArea/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { Control, Controller, FieldValues, UseControllerProps } from 'react-hook-form';

import TextAreaWithRef from '../../textArea/';

export interface ControlledTextAreaProps<T extends FieldValues> extends UseControllerProps<T> {
label: string;
required?: boolean;
control: Control<T>;
helperText?: string;
onErrorText?: string;
}

function ControlledTextArea<T extends FieldValues>({
label,
...props
}: ControlledTextAreaProps<T>) {
return (
<Controller
{...props}
render={({ field, fieldState: { error } }) => (
<TextAreaWithRef
{...field}
required={props.required}
label={label}
error={!!error}
helperText={error ? props.onErrorText : props.helperText}
/>
)}
/>
);
}

export default ControlledTextArea;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { useForm } from 'react-hook-form';

Expand Down
17 changes: 17 additions & 0 deletions components/createEnvironmentMenu/createEnvironmentMenu.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Meta, StoryObj } from '@storybook/react';

import { CreateEnvironmentMenu } from '.';

const meta: Meta<typeof CreateEnvironmentMenu> = {
component: CreateEnvironmentMenu,
};

export default meta;

export const Default: StoryObj<typeof CreateEnvironmentMenu> = {
args: {
previouslyCreatedEnvironments: [
{ environmentName: 'development', labelColor: 'dark-sky-blue' },
],
},
};
Loading