Skip to content

Commit

Permalink
refactor(ui): move Segments to use Redux storage (#2441)
Browse files Browse the repository at this point in the history
  • Loading branch information
erka authored Nov 27, 2023
1 parent cd8a66d commit 38569b5
Show file tree
Hide file tree
Showing 11 changed files with 375 additions and 195 deletions.
18 changes: 5 additions & 13 deletions ui/src/app/flags/rollouts/Rollouts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import { selectReadonly } from '~/app/meta/metaSlice';
import { selectCurrentNamespace } from '~/app/namespaces/namespacesSlice';
import { useListSegmentsQuery } from '~/app/segments/segmentsApi';
import Button from '~/components/forms/buttons/Button';
import Modal from '~/components/Modal';
import DeletePanel from '~/components/panels/DeletePanel';
Expand All @@ -26,17 +27,12 @@ import RolloutForm from '~/components/rollouts/forms/RolloutForm';
import Rollout from '~/components/rollouts/Rollout';
import SortableRollout from '~/components/rollouts/SortableRollout';
import Slideover from '~/components/Slideover';
import {
deleteRollout,
listRollouts,
listSegments,
orderRollouts
} from '~/data/api';
import { deleteRollout, listRollouts, orderRollouts } from '~/data/api';
import { useError } from '~/data/hooks/error';
import { useSuccess } from '~/data/hooks/success';
import { IFlag } from '~/types/Flag';
import { IRollout, IRolloutList } from '~/types/Rollout';
import { ISegment, ISegmentList, SegmentOperatorType } from '~/types/Segment';
import { SegmentOperatorType } from '~/types/Segment';

type RolloutsProps = {
flag: IFlag;
Expand All @@ -45,7 +41,6 @@ type RolloutsProps = {
export default function Rollouts(props: RolloutsProps) {
const { flag } = props;

const [segments, setSegments] = useState<ISegment[]>([]);
const [rollouts, setRollouts] = useState<IRollout[]>([]);

const [activeRollout, setActiveRollout] = useState<IRollout | null>(null);
Expand All @@ -68,13 +63,10 @@ export default function Rollouts(props: RolloutsProps) {

const namespace = useSelector(selectCurrentNamespace);
const readOnly = useSelector(selectReadonly);
const segments = useListSegmentsQuery(namespace.key)?.data?.segments || [];

const loadData = useCallback(async () => {
// TODO: move to redux
const segmentList = (await listSegments(namespace.key)) as ISegmentList;
const { segments } = segmentList;
setSegments(segments);

const rolloutList = (await listRollouts(
namespace.key,
flag.key
Expand Down Expand Up @@ -284,7 +276,7 @@ export default function Rollouts(props: RolloutsProps) {
</p>
</div>
<div
className="border-gray-200 pattern-boxes w-full border p-4 pattern-bg-gray-50 pattern-gray-100 pattern-opacity-100 pattern-size-2 dark:pattern-bg-black dark:pattern-gray-900
className="border-gray-200 pattern-boxes w-full border p-4 pattern-bg-gray-50 pattern-gray-100 pattern-opacity-100 pattern-size-2 dark:pattern-bg-black dark:pattern-gray-900
lg:p-6"
>
{rollouts && rollouts.length > 0 && (
Expand Down
21 changes: 11 additions & 10 deletions ui/src/app/flags/rules/Rules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import {
verticalListSortingStrategy
} from '@dnd-kit/sortable';
import { PlusIcon } from '@heroicons/react/24/outline';
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { useNavigate, useOutletContext } from 'react-router-dom';
import { FlagProps } from '~/app/flags/FlagProps';
import { selectReadonly } from '~/app/meta/metaSlice';
import { selectCurrentNamespace } from '~/app/namespaces/namespacesSlice';
import { useListSegmentsQuery } from '~/app/segments/segmentsApi';
import EmptyState from '~/components/EmptyState';
import Button from '~/components/forms/buttons/Button';
import Modal from '~/components/Modal';
Expand All @@ -28,20 +29,19 @@ import RuleForm from '~/components/rules/forms/RuleForm';
import Rule from '~/components/rules/Rule';
import SortableRule from '~/components/rules/SortableRule';
import Slideover from '~/components/Slideover';
import { deleteRule, listRules, listSegments, orderRules } from '~/data/api';
import { deleteRule, listRules, orderRules } from '~/data/api';
import { useError } from '~/data/hooks/error';
import { useSuccess } from '~/data/hooks/success';
import { IDistribution } from '~/types/Distribution';
import { IEvaluatable } from '~/types/Evaluatable';
import { FlagType } from '~/types/Flag';
import { IRule, IRuleList } from '~/types/Rule';
import { ISegment, ISegmentList, SegmentOperatorType } from '~/types/Segment';
import { ISegment, SegmentOperatorType } from '~/types/Segment';
import { IVariant } from '~/types/Variant';

export default function Rules() {
const { flag } = useOutletContext<FlagProps>();

const [segments, setSegments] = useState<ISegment[]>([]);
const [rules, setRules] = useState<IEvaluatable[]>([]);

const [activeRule, setActiveRule] = useState<IEvaluatable | null>(null);
Expand All @@ -60,13 +60,14 @@ export default function Rules() {

const namespace = useSelector(selectCurrentNamespace);
const readOnly = useSelector(selectReadonly);
const listSegments = useListSegmentsQuery(namespace.key);
const segments = useMemo(
() => listSegments.data?.segments || [],
[listSegments]
);

const loadData = useCallback(async () => {
// TODO: move to redux
const segmentList = (await listSegments(namespace.key)) as ISegmentList;
const { segments } = segmentList;
setSegments(segments);

const ruleList = (await listRules(namespace.key, flag.key)) as IRuleList;

const rules = ruleList.rules.flatMap((rule: IRule) => {
Expand Down Expand Up @@ -133,7 +134,7 @@ export default function Rules() {
});

setRules(rules);
}, [namespace.key, flag]);
}, [namespace.key, flag, segments]);

const incrementRulesVersion = () => {
setRulesVersion(rulesVersion + 1);
Expand Down Expand Up @@ -283,7 +284,7 @@ export default function Rules() {
</p>
</div>
<div
className="border-gray-200 pattern-boxes w-full border p-4 pattern-bg-gray-50 pattern-gray-100 pattern-opacity-100 pattern-size-2 dark:pattern-bg-black dark:pattern-gray-900
className="border-gray-200 pattern-boxes w-full border p-4 pattern-bg-gray-50 pattern-gray-100 pattern-opacity-100 pattern-size-2 dark:pattern-bg-black dark:pattern-gray-900
lg:w-3/4 lg:p-6"
>
<DndContext
Expand Down
95 changes: 46 additions & 49 deletions ui/src/app/segments/Segment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ import {
TrashIcon
} from '@heroicons/react/24/outline';
import { formatDistanceToNowStrict, parseISO } from 'date-fns';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useMemo, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import { useNavigate, useParams } from 'react-router-dom';
import { selectReadonly } from '~/app/meta/metaSlice';
import {
selectCurrentNamespace,
selectNamespaces
} from '~/app/namespaces/namespacesSlice';
import {
useCopySegmentMutation,
useDeleteConstraintMutation,
useDeleteSegmentMutation,
useGetSegmentQuery
} from '~/app/segments/segmentsApi';
import Chips from '~/components/Chips';
import EmptyState from '~/components/EmptyState';
import Button from '~/components/forms/buttons/Button';
Expand All @@ -24,12 +30,6 @@ import DeletePanel from '~/components/panels/DeletePanel';
import ConstraintForm from '~/components/segments/ConstraintForm';
import SegmentForm from '~/components/segments/SegmentForm';
import Slideover from '~/components/Slideover';
import {
copySegment,
deleteConstraint,
deleteSegment,
getSegment
} from '~/data/api';
import { useError } from '~/data/hooks/error';
import { useSuccess } from '~/data/hooks/success';
import { useTimezone } from '~/data/hooks/timezone';
Expand All @@ -39,7 +39,6 @@ import {
constraintTypeToLabel,
IConstraint
} from '~/types/Constraint';
import { ISegment } from '~/types/Segment';

function ConstraintArrayValue({ value }: { value: string | undefined }) {
const items: string[] | number[] = useMemo(() => {
Expand Down Expand Up @@ -75,9 +74,6 @@ export default function Segment() {
let { segmentKey } = useParams();
const { inTimezone } = useTimezone();

const [segment, setSegment] = useState<ISegment | null>(null);
const [segmentVersion, setSegmentVersion] = useState(0);

const [showConstraintForm, setShowConstraintForm] = useState<boolean>(false);
const [editingConstraint, setEditingConstraint] =
useState<IConstraint | null>(null);
Expand All @@ -99,26 +95,27 @@ export default function Segment() {
const namespace = useSelector(selectCurrentNamespace);
const readOnly = useSelector(selectReadonly);

const incrementSegmentVersion = () => {
setSegmentVersion(segmentVersion + 1);
};

useEffect(() => {
if (!segmentKey) return;

getSegment(namespace.key, segmentKey)
.then((segment: ISegment) => {
setSegment(segment);
clearError();
})
.catch((err) => {
setError(err);
});
}, [segmentVersion, namespace.key, segmentKey, clearError, setError]);

const {
data: segment,
error,
isLoading,
isError
} = useGetSegmentQuery({
namespaceKey: namespace.key,
segmentKey: segmentKey || ''
});
const [deleteSegment] = useDeleteSegmentMutation();
const [deleteSegmentConstraint] = useDeleteConstraintMutation();
const [copySegment] = useCopySegmentMutation();
const constraintFormRef = useRef(null);

if (!segment) return <Loading />;
if (isError) {
setError(error);
}

if (isLoading || !segment) {
return <Loading />;
}

return (
<>
Expand All @@ -134,7 +131,7 @@ export default function Segment() {
constraint={editingConstraint || undefined}
setOpen={setShowConstraintForm}
onSuccess={() => {
incrementSegmentVersion();
clearError();
setShowConstraintForm(false);
}}
/>
Expand All @@ -157,17 +154,15 @@ export default function Segment() {
}
panelType="Constraint"
setOpen={setShowDeleteConstraintModal}
handleDelete={
() =>
deleteConstraint(
namespace.key,
segment.key,
deletingConstraint?.id ?? ''
) // TODO: Determine impact of blank ID param
handleDelete={() =>
deleteSegmentConstraint({
namespaceKey: namespace.key,
segmentKey: segment.key,
constraintId: deletingConstraint?.id ?? ''
// TODO: Determine impact of blank ID param
}).unwrap()
}
onSuccess={() => {
incrementSegmentVersion();
}}
onSuccess={() => {}}
/>
</Modal>

Expand All @@ -183,7 +178,12 @@ export default function Segment() {
}
panelType="Segment"
setOpen={setShowDeleteSegmentModal}
handleDelete={() => deleteSegment(namespace.key, segment.key)}
handleDelete={() =>
deleteSegment({
namespaceKey: namespace.key,
segmentKey: segment.key
}).unwrap()
}
onSuccess={() => {
navigate(`/namespaces/${namespace.key}/segments`);
}}
Expand All @@ -203,10 +203,10 @@ export default function Segment() {
panelType="Segment"
setOpen={setShowCopySegmentModal}
handleCopy={(namespaceKey: string) =>
copySegment(
{ namespaceKey: namespace.key, key: segment.key },
{ namespaceKey: namespaceKey, key: segment.key }
)
copySegment({
from: { namespaceKey: namespace.key, segmentKey: segment.key },
to: { namespaceKey: namespaceKey, segmentKey: segment.key }
}).unwrap()
}
onSuccess={() => {
clearError();
Expand Down Expand Up @@ -279,10 +279,7 @@ export default function Segment() {
</MoreInfo>
</div>
<div className="mt-5 md:col-span-2 md:mt-0">
<SegmentForm
segment={segment}
segmentChanged={incrementSegmentVersion}
/>
<SegmentForm segment={segment} />
</div>
</div>
</div>
Expand Down
9 changes: 3 additions & 6 deletions ui/src/app/segments/Segments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,21 @@ import { PlusIcon } from '@heroicons/react/24/outline';
import { useEffect } from 'react';
import { useSelector } from 'react-redux';
import { Link, useNavigate } from 'react-router-dom';
import useSWR from 'swr';
import { selectReadonly } from '~/app/meta/metaSlice';
import { selectCurrentNamespace } from '~/app/namespaces/namespacesSlice';
import { useListSegmentsQuery } from '~/app/segments/segmentsApi';
import EmptyState from '~/components/EmptyState';
import Button from '~/components/forms/buttons/Button';
import SegmentTable from '~/components/segments/SegmentTable';
import { useError } from '~/data/hooks/error';
import { ISegmentList } from '~/types/Segment';

export default function Segments() {
const namespace = useSelector(selectCurrentNamespace);

const path = `/namespaces/${namespace.key}/segments`;

const { data, error } = useSWR<ISegmentList>(path);

const segments = data?.segments;

const { data, error } = useListSegmentsQuery(namespace.key);
const segments = data?.segments || [];
const navigate = useNavigate();
const { setError, clearError } = useError();

Expand Down
Loading

0 comments on commit 38569b5

Please sign in to comment.