Skip to content

Commit

Permalink
feat: Add readonly attributes to edit forms
Browse files Browse the repository at this point in the history
  • Loading branch information
yquansah committed Aug 7, 2023
1 parent 0c3af94 commit a4c37a3
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 14 deletions.
15 changes: 15 additions & 0 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"react-redux": "^8.1.1",
"react-router-dom": "^6.14.1",
"swr": "^2.2.0",
"tailwind-merge": "^1.14.0",
"uuid": "^9.0.0",
"yup": "^0.32.11"
},
Expand Down
7 changes: 6 additions & 1 deletion ui/src/components/forms/Combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Combobox as C } from '@headlessui/react';
import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/24/outline';
import { useField } from 'formik';
import { useState } from 'react';
import { twMerge } from 'tailwind-merge';
import { IFilterable } from '~/types/Selectable';
import { classNames } from '~/utils/helpers';

Expand All @@ -14,6 +15,7 @@ type ComboboxProps<T extends IFilterable> = {
setSelected?: (v: T | null) => void;
disabled?: boolean;
className?: string;
inputClassNames?: string;
};

export default function Combobox<T extends IFilterable>(
Expand All @@ -22,6 +24,7 @@ export default function Combobox<T extends IFilterable>(
const {
id,
className,
inputClassNames,
values,
selected,
setSelected,
Expand Down Expand Up @@ -51,7 +54,9 @@ export default function Combobox<T extends IFilterable>(
<div className="relative flex w-full flex-row">
<C.Input
id={id}
className="text-gray-900 bg-gray-50 border-gray-300 w-full rounded-md border py-2 pl-3 pr-10 shadow-sm focus:border-violet-500 focus:outline-none focus:ring-1 focus:ring-violet-500 sm:text-sm"
className={twMerge(
`text-gray-900 bg-gray-50 border-gray-300 w-full rounded-md border py-2 pl-3 pr-10 shadow-sm focus:border-violet-500 focus:outline-none focus:ring-1 focus:ring-violet-500 sm:text-sm ${inputClassNames}`
)}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setQuery(e.target.value);
}}
Expand Down
22 changes: 19 additions & 3 deletions ui/src/components/forms/SegmentsPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { MinusSmallIcon, PlusSmallIcon } from '@heroicons/react/24/outline';
import { useRef, useState } from 'react';
import { twMerge } from 'tailwind-merge';
import Combobox from '~/components/forms/Combobox';
import { FilterableSegment, ISegment } from '~/types/Segment';
import { truncateKey } from '~/utils/helpers';

type SegmentPickerProps = {
readonly?: boolean;
editMode?: boolean;
segments: ISegment[];
selectedSegments: FilterableSegment[];
Expand All @@ -14,6 +16,7 @@ type SegmentPickerProps = {
};

export default function SegmentsPicker({
readonly = false,
editMode = false,
segments,
selectedSegments: parentSegments,
Expand All @@ -25,6 +28,8 @@ export default function SegmentsPicker({
new Set<string>(parentSegments.map((s) => s.key))
);

const [editing, setEditing] = useState<boolean>(editMode);

const handleSegmentRemove = (index: number) => {
const filterableSegment = parentSegments[index];

Expand All @@ -37,8 +42,6 @@ export default function SegmentsPicker({
}
};

const [editing, setEditing] = useState<boolean>(editMode);

const handleSegmentSelected = (
index: number,
segment: FilterableSegment | null
Expand Down Expand Up @@ -76,18 +79,29 @@ export default function SegmentsPicker({
filterValue: truncateKey(s.key),
displayValue: s.name
}))}
disabled={readonly}
selected={selectedSegment}
setSelected={(filterableSegment) => {
handleSegmentSelected(index, filterableSegment);
}}
inputClassNames={
readonly
? 'cursor-not-allowed bg-gray-100 text-gray-500'
: undefined
}
/>
</div>
{editing && parentSegments.length - 1 === index ? (
<div>
<button
type="button"
className="text-gray-400 mt-2 hover:text-gray-500"
className={twMerge(`
text-gray-400 mt-2 hover:text-gray-500 ${
readonly ? 'hover:text-gray-400' : undefined
}`)}
onClick={() => setEditing(false)}
title={readonly ? 'Not allowed in Read-Only mode' : undefined}
disabled={readonly}
>
<PlusSmallIcon className="h-6 w-6" aria-hidden="true" />
</button>
Expand All @@ -98,6 +112,8 @@ export default function SegmentsPicker({
type="button"
className="text-gray-400 mt-2 hover:text-gray-500"
onClick={() => handleSegmentRemove(index)}
title={readonly ? 'Not allowed in Read-Only mode' : undefined}
disabled={readonly}
>
<MinusSmallIcon className="h-6 w-6" aria-hidden="true" />
</button>
Expand Down
18 changes: 16 additions & 2 deletions ui/src/components/forms/Select.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useField } from 'formik';
import { twMerge } from 'tailwind-merge';

type SelectProps = {
id: string;
Expand All @@ -8,10 +9,20 @@ type SelectProps = {
className?: string;
value?: string;
onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void;
disabled?: boolean;
};

export default function Select(props: SelectProps) {
const { id, name, options, children, className, value, onChange } = props;
const {
id,
name,
options,
children,
className,
value,
onChange,
disabled = false
} = props;

const [field] = useField({
name,
Expand All @@ -23,9 +34,12 @@ export default function Select(props: SelectProps) {
{...field}
id={id}
name={name}
className={`text-gray-900 bg-gray-50 border-gray-300 block rounded-md py-2 pl-3 pr-10 text-base focus:border-violet-300 focus:outline-none focus:ring-violet-300 sm:text-sm ${className}`}
className={twMerge(
`text-gray-900 bg-gray-50 border-gray-300 block rounded-md py-2 pl-3 pr-10 text-base focus:border-violet-300 focus:outline-none focus:ring-violet-300 sm:text-sm ${className}`
)}
value={value}
onChange={onChange || field.onChange}
disabled={disabled}
>
{options &&
options.map((option) => (
Expand Down
17 changes: 16 additions & 1 deletion ui/src/components/rollouts/forms/EditRolloutForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Dialog } from '@headlessui/react';
import { XMarkIcon } from '@heroicons/react/24/outline';
import { FieldArray, Form, Formik } from 'formik';
import { useSelector } from 'react-redux';
import { twMerge } from 'tailwind-merge';
import { selectReadonly } from '~/app/meta/metaSlice';
import { selectCurrentNamespace } from '~/app/namespaces/namespacesSlice';
import Button from '~/components/forms/buttons/Button';
import Input from '~/components/forms/Input';
Expand Down Expand Up @@ -62,6 +64,8 @@ export default function EditRolloutForm(props: EditRolloutFormProps) {
? rollout.segment.segmentOperator
: SegmentOperatorType.OR;

const readOnly = useSelector(selectReadonly);

const handleSegmentSubmit = (values: RolloutFormValues) => {
let rolloutSegment = rollout;
rolloutSegment.threshold = undefined;
Expand Down Expand Up @@ -282,6 +286,7 @@ export default function EditRolloutForm(props: EditRolloutFormProps) {
name="segmentKeys"
render={(arrayHelpers) => (
<SegmentsPicker
readonly={readOnly}
editMode
segments={segments}
segmentAdd={(segment: FilterableSegment) =>
Expand All @@ -307,7 +312,11 @@ export default function EditRolloutForm(props: EditRolloutFormProps) {
id={segmentOperator.id}
name="operator"
type="radio"
className="text-violet-400 border-gray-300 h-4 w-4 focus:ring-violet-400"
className={twMerge(
`text-violet-400 border-gray-300 h-4 w-4 focus:ring-violet-400 ${
readOnly ? 'cursor-not-allowed' : undefined
}`
)}
onChange={() => {
formik.setFieldValue(
'operator',
Expand All @@ -318,6 +327,12 @@ export default function EditRolloutForm(props: EditRolloutFormProps) {
segmentOperator.id === formik.values.operator
}
value={segmentOperator.id}
disabled={readOnly}
title={
readOnly
? 'Not allowed in Read-Only mode'
: undefined
}
/>
</div>
<div>
Expand Down
26 changes: 24 additions & 2 deletions ui/src/components/rollouts/forms/QuickEditRolloutForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { FieldArray, Form, Formik } from 'formik';
import { useSelector } from 'react-redux';
import { twMerge } from 'tailwind-merge';
import { selectReadonly } from '~/app/meta/metaSlice';
import { selectCurrentNamespace } from '~/app/namespaces/namespacesSlice';
import TextButton from '~/components/forms/buttons/TextButton';
import Input from '~/components/forms/Input';
Expand Down Expand Up @@ -45,6 +47,8 @@ export default function QuickEditRolloutForm(props: QuickEditRolloutFormProps) {
? rollout.segment.segmentOperator
: SegmentOperatorType.OR;

const readOnly = useSelector(selectReadonly);

const handleSegmentSubmit = (values: RolloutFormValues) => {
let rolloutSegment = rollout;
rolloutSegment.threshold = undefined;
Expand Down Expand Up @@ -188,6 +192,7 @@ export default function QuickEditRolloutForm(props: QuickEditRolloutFormProps) {
name="segmentKeys"
render={(arrayHelpers) => (
<SegmentsPicker
readonly={readOnly}
editMode
segments={segments}
segmentAdd={(segment: FilterableSegment) =>
Expand All @@ -213,7 +218,11 @@ export default function QuickEditRolloutForm(props: QuickEditRolloutFormProps) {
id={segmentOperator.id}
name="operator"
type="radio"
className="text-violet-400 border-gray-300 h-4 w-4 focus:ring-violet-400"
className={twMerge(
`text-violet-400 border-gray-300 h-4 w-4 focus:ring-violet-400 ${
readOnly ? 'cursor-not-allowed' : undefined
}`
)}
onChange={() => {
formik.setFieldValue(
'operator',
Expand All @@ -224,6 +233,12 @@ export default function QuickEditRolloutForm(props: QuickEditRolloutFormProps) {
segmentOperator.id === formik.values.operator
}
value={segmentOperator.id}
disabled={readOnly}
title={
readOnly
? 'Not allowed in Read-Only mode'
: undefined
}
/>
</div>
<div>
Expand Down Expand Up @@ -258,7 +273,14 @@ export default function QuickEditRolloutForm(props: QuickEditRolloutFormProps) {
{ label: 'True', value: 'true' },
{ label: 'False', value: 'false' }
]}
className="w-full cursor-pointer appearance-none self-center rounded-lg py-1 align-middle"
className={twMerge(
`w-full cursor-pointer appearance-none self-center rounded-lg py-1 align-middle ${
readOnly
? 'text-gray-500 bg-gray-100 cursor-not-allowed'
: undefined
}`
)}
disabled={readOnly}
/>
</div>
</div>
Expand Down
Loading

0 comments on commit a4c37a3

Please sign in to comment.