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

feat: rollout edit + typescript enum redo #1859

Merged
merged 8 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions ui/src/app/console/Console.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ import {
keyValidation,
requiredValidation
} from '~/data/validations';
import { IConsole } from '~/types/Console';
import { FilterableFlag, flagTypeToLabel, IFlagList } from '~/types/Flag';
import {
FilterableFlag,
flagTypeToLabel,
IFlag,
IFlagList
} from '~/types/Flag';
import { INamespace } from '~/types/Namespace';
import { classNames } from '~/utils/helpers';

Expand All @@ -37,6 +41,12 @@ function ResetOnNamespaceChange({ namespace }: { namespace: INamespace }) {
return null;
}

interface ConsoleFormValues {
flagKey: string;
entityId: string;
context: string | undefined;
}

export default function Console() {
const [flags, setFlags] = useState<FilterableFlag[]>([]);
const [selectedFlag, setSelectedFlag] = useState<FilterableFlag | null>(null);
Expand Down Expand Up @@ -66,10 +76,12 @@ export default function Console() {
);
}, [namespace.key]);

const handleSubmit = (values: IConsole, flagType: string) => {
const { flagKey, entityId, context } = values;
const handleSubmit = (flag: IFlag | null, values: ConsoleFormValues) => {
const { entityId, context } = values;

const boolean = flagType === 'BOOLEAN_FLAG_TYPE';
if (!flag) {
return;
}

// need to unescape the context string
const parsed = context ? JSON.parse(context) : undefined;
Expand All @@ -79,7 +91,7 @@ export default function Console() {
context: parsed
};

evaluateV2(boolean, namespace.key, flagKey, rest)
evaluateV2(namespace.key, flag.key, flag.type, rest)
.then((resp) => {
setHasEvaluationError(false);
setResponse(JSON.stringify(resp, null, 2));
Expand All @@ -102,7 +114,7 @@ export default function Console() {
});
}, [clearError, loadData, setError]);

const initialvalues: IConsole = {
const initialvalues: ConsoleFormValues = {
flagKey: selectedFlag?.key || '',
entityId: uuidv4(),
context: undefined
Expand Down Expand Up @@ -130,7 +142,7 @@ export default function Console() {
context: jsonValidation
})}
onSubmit={(values) => {
handleSubmit(values, selectedFlag?.type || '');
handleSubmit(selectedFlag, values);
}}
onReset={() => {
setResponse(null);
Expand Down
8 changes: 3 additions & 5 deletions ui/src/app/flags/EditFlag.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useOutletContext } from 'react-router-dom';
import FlagForm from '~/components/flags/FlagForm';
import MoreInfo from '~/components/MoreInfo';
import { FlagType, flagTypeToLabel } from '~/types/Flag';
import { FlagType } from '~/types/Flag';
import { FlagProps } from './FlagProps';
import Rollouts from './rollouts/Rollouts';
import Variants from './variants/Variants';
Expand Down Expand Up @@ -32,12 +32,10 @@ export default function EditFlag() {
</div>
</div>

{flagTypeToLabel(flag.type) === FlagType.VARIANT_FLAG_TYPE && (
{flag.type === FlagType.VARIANT && (
<Variants flag={flag} flagChanged={onFlagChange} />
)}
{flagTypeToLabel(flag.type) === FlagType.BOOLEAN_FLAG_TYPE && (
<Rollouts flag={flag} />
)}
{flag.type === FlagType.BOOLEAN && <Rollouts flag={flag} />}
</div>
</>
);
Expand Down
13 changes: 8 additions & 5 deletions ui/src/app/flags/Evaluation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
sortableKeyboardCoordinates,
verticalListSortingStrategy
} from '@dnd-kit/sortable';
import { InformationCircleIcon } from '@heroicons/react/20/solid';
import { InformationCircleIcon } from '@heroicons/react/24/outline';
import { useCallback, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { useOutletContext } from 'react-router-dom';
Expand Down Expand Up @@ -200,7 +200,10 @@ export default function Evaluation() {
rank={(rules?.length || 0) + 1}
segments={segments}
setOpen={setShowRuleForm}
onSuccess={incrementRulesVersion}
onSuccess={() => {
incrementRulesVersion();
setShowRuleForm(false);
}}
/>
</Slideover>

Expand Down Expand Up @@ -247,13 +250,13 @@ export default function Evaluation() {
{rules && rules.length > 0 ? (
<div className="flex lg:space-x-5">
<div className="hidden w-1/4 flex-col space-y-7 pr-3 lg:flex">
<p className="text-sm text-gray-500">
<p className="text-sm font-light text-gray-700">
Rules are evaluated in order from{' '}
<span className="font-semibold">top to bottom</span>. The
first rule that matches will be applied.
</p>
<p className="text-sm text-gray-500">
<InformationCircleIcon className="mr-1 inline-block h-4 w-4 text-violet-300" />
<p className="text-sm font-light text-gray-700">
<InformationCircleIcon className="mr-1 inline-block h-4 w-4 text-gray-300" />
You can re-arrange rules by{' '}
<span className="font-semibold">dragging and dropping</span>{' '}
them into place.
Expand Down
4 changes: 2 additions & 2 deletions ui/src/app/flags/Flag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { copyFlag, deleteFlag, getFlag } from '~/data/api';
import { useError } from '~/data/hooks/error';
import { useSuccess } from '~/data/hooks/success';
import { useTimezone } from '~/data/hooks/timezone';
import { FlagType, flagTypeToLabel, IFlag } from '~/types/Flag';
import { FlagType, IFlag } from '~/types/Flag';

export default function Flag() {
let { flagKey } = useParams();
Expand Down Expand Up @@ -69,7 +69,7 @@ export default function Flag() {
{
name: 'Evaluation',
to: 'evaluation',
disabled: flagTypeToLabel(flag.type) === FlagType.BOOLEAN_FLAG_TYPE
disabled: flag.type === FlagType.BOOLEAN
}
];

Expand Down
82 changes: 53 additions & 29 deletions ui/src/app/flags/rollouts/Rollouts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import EmptyState from '~/components/EmptyState';
import Button from '~/components/forms/buttons/Button';
import Modal from '~/components/Modal';
import DeletePanel from '~/components/panels/DeletePanel';
import RolloutForm from '~/components/rollouts/RolloutForm';
import EditRolloutForm from '~/components/rollouts/forms/EditRolloutForm';
import RolloutForm from '~/components/rollouts/forms/RolloutForm';
import SortableRollout from '~/components/rollouts/SortableRollout';
import Slideover from '~/components/Slideover';
import { deleteRollout, listRollouts, listSegments } from '~/data/api';
Expand All @@ -28,6 +29,10 @@ export default function Rollouts(props: RolloutsProps) {
const [rolloutsVersion, setRolloutsVersion] = useState(0);
const [showRolloutForm, setShowRolloutForm] = useState<boolean>(false);

const [showEditRolloutForm, setShowEditRolloutForm] =
useState<boolean>(false);
const [editingRollout, setEditingRollout] = useState<IRollout | null>(null);

const [showDeleteRolloutModal, setShowDeleteRolloutModal] =
useState<boolean>(false);
const [deletingRollout, setDeletingRollout] = useState<IRollout | null>(null);
Expand Down Expand Up @@ -61,25 +66,6 @@ export default function Rollouts(props: RolloutsProps) {

return (
<>
{/* rollout edit form */}
<Slideover
open={showRolloutForm}
setOpen={setShowRolloutForm}
ref={rolloutFormRef}
>
<RolloutForm
flagKey={flag.key}
segments={segments}
// rollout={editingRollout || undefined}
rank={(rollouts?.length || 0) + 1}
setOpen={setShowRolloutForm}
onSuccess={() => {
setShowRolloutForm(false);
incrementRolloutsVersion();
}}
/>
</Slideover>

{/* rollout delete modal */}
<Modal open={showDeleteRolloutModal} setOpen={setShowDeleteRolloutModal}>
<DeletePanel
Expand All @@ -103,6 +89,44 @@ export default function Rollouts(props: RolloutsProps) {
/>
</Modal>

{/* rollout create form */}
<Slideover
open={showRolloutForm}
setOpen={setShowRolloutForm}
ref={rolloutFormRef}
>
<RolloutForm
flagKey={flag.key}
rank={rollouts.length + 1}
segments={segments}
setOpen={setShowRolloutForm}
onSuccess={() => {
setShowRolloutForm(false);
incrementRolloutsVersion();
}}
/>
</Slideover>

{/* rollout edit form */}
{editingRollout && (
<Slideover
open={showEditRolloutForm}
setOpen={setShowEditRolloutForm}
ref={rolloutFormRef}
>
<EditRolloutForm
flagKey={flag.key}
segments={segments}
rollout={editingRollout}
setOpen={setShowEditRolloutForm}
onSuccess={() => {
setShowEditRolloutForm(false);
incrementRolloutsVersion();
}}
/>
</Slideover>
)}

{/* rollouts */}
<div className="mt-10">
<div className="sm:flex sm:items-center">
Expand All @@ -122,7 +146,7 @@ export default function Rollouts(props: RolloutsProps) {
disabled={readOnly}
title={readOnly ? 'Not allowed in Read-Only mode' : undefined}
onClick={() => {
// setEditingRollout(null);
setEditingRollout(null);
setShowRolloutForm(true);
}}
>
Expand All @@ -139,14 +163,14 @@ export default function Rollouts(props: RolloutsProps) {
{rollouts && rollouts.length > 0 ? (
<div className="flex lg:space-x-5">
<div className="hidden w-1/4 flex-col space-y-7 pr-3 lg:flex">
<p className="text-sm text-gray-500">
<p className="text-sm font-light text-gray-700">
Rules are evaluated in order from{' '}
<span className="font-semibold">top to bottom</span>. The
first rule that matches will be applied.
</p>
<p className="text-sm text-gray-500">
<InformationCircleIcon className="mr-1 inline-block h-4 w-4 text-violet-300" />
You can re-arrange rules by{' '}
<p className="text-sm font-light text-gray-700">
<InformationCircleIcon className="mr-1 inline-block h-4 w-4 text-gray-300" />
You can re-arrange rules by clicking in the header and{' '}
<span className="font-semibold">dragging and dropping</span>{' '}
them into place.
</p>
Expand Down Expand Up @@ -174,10 +198,10 @@ export default function Rollouts(props: RolloutsProps) {
flagKey={flag.key}
rollout={rollout}
segments={segments}
onQuickEditSuccess={incrementRolloutsVersion}
onSuccess={incrementRolloutsVersion}
onEdit={() => {
// setEditingRollout(rollout);
//setShowEditRolloutForm(true);
setEditingRollout(rollout);
setShowEditRolloutForm(true);
}}
onDelete={() => {
setDeletingRollout(rollout);
Expand Down Expand Up @@ -205,7 +229,7 @@ export default function Rollouts(props: RolloutsProps) {
text="New Rollout"
disabled={readOnly}
onClick={() => {
//setEditingRollout(null);
setEditingRollout(null);
setShowRolloutForm(true);
}}
/>
Expand Down
9 changes: 4 additions & 5 deletions ui/src/app/segments/Segment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ import { useError } from '~/data/hooks/error';
import { useSuccess } from '~/data/hooks/success';
import { useTimezone } from '~/data/hooks/timezone';
import {
ComparisonType,
constraintOperatorToLabel,
ConstraintOperators,
ConstraintType,
constraintTypeToLabel,
IConstraint
} from '~/types/Constraint';
Expand Down Expand Up @@ -342,11 +342,10 @@ export default function Segment() {
{constraintTypeToLabel(constraint.type)}
</td>
<td className="hidden whitespace-nowrap px-3 py-4 text-sm text-gray-500 lg:table-cell">
{constraintOperatorToLabel(constraint.operator)}
{ConstraintOperators[constraint.operator]}
</td>
<td className="hidden whitespace-nowrap px-3 py-4 text-sm text-gray-500 lg:table-cell">
{constraintTypeToLabel(constraint.type) ===
ComparisonType.DATETIME_COMPARISON_TYPE &&
{constraint.type === ConstraintType.DATETIME &&
constraint.value !== undefined
? inTimezone(constraint.value)
: constraint.value}
Expand Down
15 changes: 6 additions & 9 deletions ui/src/components/flags/FlagForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ type FlagFormProps = {

const flagTypes = [
{
id: 'VARIANT_FLAG_TYPE',
name: FlagType.VARIANT_FLAG_TYPE
id: FlagType.VARIANT,
name: 'Variant'
},
{
id: 'BOOLEAN_FLAG_TYPE',
name: FlagType.BOOLEAN_FLAG_TYPE
id: FlagType.BOOLEAN,
name: 'Boolean'
}
];

Expand Down Expand Up @@ -55,7 +55,7 @@ export default function FlagForm(props: FlagFormProps) {
key: flag?.key || '',
name: flag?.name || '',
description: flag?.description || '',
type: flag?.type || ('VARIANT_FLAG_TYPE' as FlagType),
type: flag?.type || FlagType.VARIANT,
enabled: flag?.enabled || false
};

Expand Down Expand Up @@ -177,10 +177,7 @@ export default function FlagForm(props: FlagFormProps) {
disabled={!isNew}
className="h-4 w-4 border-gray-300 text-violet-400 focus:ring-violet-400"
onChange={() => {
formik.setFieldValue(
'type',
type.id as FlagType
);
formik.setFieldValue('type', type.id);
}}
checked={type.id === formik.values.type}
value={type.id}
Expand Down
5 changes: 2 additions & 3 deletions ui/src/components/flags/FlagTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { selectCurrentNamespace } from '~/app/namespaces/namespacesSlice';
import Pagination from '~/components/Pagination';
import Searchbox from '~/components/Searchbox';
import { useTimezone } from '~/data/hooks/timezone';
import { FlagType, IFlag } from '~/types/Flag';
import { flagTypeToLabel, IFlag } from '~/types/Flag';
import { truncateKey } from '~/utils/helpers';

type FlagTableProps = {
Expand Down Expand Up @@ -85,8 +85,7 @@ export default function FlagTable(props: FlagTableProps) {
}),
columnHelper.accessor('type', {
header: 'Type',
cell: (info) =>
FlagType[info.getValue() as unknown as keyof typeof FlagType],
cell: (info) => flagTypeToLabel(info.getValue()),
meta: {
className: 'whitespace-nowrap py-4 px-3 text-sm text-gray-600'
}
Expand Down
Loading
Loading