From b41dd03276440a5f9c6ab3e4d2d6578a5e32d166 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Fri, 23 Jun 2023 16:21:30 +0200 Subject: [PATCH] fix(ui): texts for feature flags, colors and stuff --- frontend/app/Router.js | 21 +++- .../components/FFlags/FFlagItem/FFlagItem.tsx | 46 ++++--- .../components/FFlags/FFlagsListHeader.tsx | 9 +- .../components/FFlags/FlagView/FlagView.tsx | 117 ++++++++++++++++++ .../app/components/FFlags/NewFFlag/Header.tsx | 25 +++- .../components/FFlags/NewFFlag/Helpers.tsx | 6 +- .../components/FFlags/NewFFlag/NewFFlag.tsx | 6 +- frontend/app/components/Overview/Overview.tsx | 6 +- frontend/app/mstore/types/FeatureFlag.ts | 7 +- frontend/app/routes.js | 2 + 10 files changed, 203 insertions(+), 42 deletions(-) create mode 100644 frontend/app/components/FFlags/FlagView/FlagView.tsx diff --git a/frontend/app/Router.js b/frontend/app/Router.js index e24997caf..da52b3ee9 100644 --- a/frontend/app/Router.js +++ b/frontend/app/Router.js @@ -67,6 +67,7 @@ const SESSIONS_PATH = routes.sessions(); const FFLAGS_PATH = routes.fflags(); const FFLAG_PATH = routes.fflag(); const FFLAG_CREATE_PATH = routes.newFFlag(); +const FFLAG_READ_PATH = routes.fflagRead() const NOTES_PATH = routes.notes(); const BOOKMARKS_PATH = routes.bookmarks(); const ASSIST_PATH = routes.assist(); @@ -235,12 +236,20 @@ class Router extends React.Component { - - - - - - + } /> diff --git a/frontend/app/components/FFlags/FFlagItem/FFlagItem.tsx b/frontend/app/components/FFlags/FFlagItem/FFlagItem.tsx index df5cad409..5e9b1a898 100644 --- a/frontend/app/components/FFlags/FFlagItem/FFlagItem.tsx +++ b/frontend/app/components/FFlags/FFlagItem/FFlagItem.tsx @@ -1,6 +1,6 @@ -import React from 'react' -import FeatureFlag from 'App/mstore/types/FeatureFlag' -import { Icon, Toggler, Link, TextEllipsis } from 'UI' +import React from 'react'; +import FeatureFlag from 'App/mstore/types/FeatureFlag'; +import { Icon, Toggler, Link, TextEllipsis, Tooltip } from 'UI'; import { useStore } from 'App/mstore'; import { observer } from 'mobx-react-lite'; import { resentOrDate } from 'App/date'; @@ -10,32 +10,42 @@ function FFlagItem({ flag }: { flag: FeatureFlag }) { const { featureFlagsStore, userStore } = useStore(); const toggleActivity = () => { - const newValue = !flag.isActive + const newValue = !flag.isActive; flag.setIsEnabled(newValue); - featureFlagsStore.updateFlagStatus(flag.featureFlagId, newValue).then(() => { - toast.success('Feature flag status has been updated.'); - }) + featureFlagsStore + .updateFlagStatus(flag.featureFlagId, newValue) + .then(() => { + toast.success('Feature flag status has been updated.'); + }) .catch(() => { flag.setIsEnabled(!newValue); - toast.error('Something went wrong, please try again.') - }) - } + toast.error('Something went wrong, please try again.'); + }); + }; - const flagIcon = flag.isSingleOption ? 'fflag-single' : 'fflag-multi' as const - const flagOwner = flag.updatedBy || flag.createdBy - const user = userStore.list.length > 0 ? userStore.list.find(u => parseInt(u.userId) === flagOwner!)?.name : flagOwner; + const flagIcon = flag.isSingleOption ? 'fflag-single' : ('fflag-multi' as const); + const flagOwner = flag.updatedBy || flag.createdBy; + const user = + userStore.list.length > 0 + ? userStore.list.find((u) => parseInt(u.userId) === flagOwner!)?.name + : flagOwner; return (
- + + +
{flag.flagKey} - {flag.description - ? ( - - ) : null} + {flag.description ? ( + + ) : null}
diff --git a/frontend/app/components/FFlags/FFlagsListHeader.tsx b/frontend/app/components/FFlags/FFlagsListHeader.tsx index 49c28c888..1ff06259e 100644 --- a/frontend/app/components/FFlags/FFlagsListHeader.tsx +++ b/frontend/app/components/FFlags/FFlagsListHeader.tsx @@ -3,22 +3,15 @@ import { Button, PageTitle } from 'UI' import FFlagsSearch from "Components/FFlags/FFlagsSearch"; import { useHistory } from "react-router"; import { newFFlag, withSiteId } from 'App/routes'; -import ReloadButton from "Shared/ReloadButton"; -import { useStore } from 'App/mstore'; import { observer } from 'mobx-react-lite'; function FFlagsListHeader({ siteId }: { siteId: string }) { const history = useHistory(); - const { featureFlagsStore } = useStore(); - const onReload = () => { - void featureFlagsStore.fetchFlags(); - } return (
-
+ +
+
+ {current.description || 'There is no description for this feature flag.'} +
+ +
+ + +
+
+ +
+ {current.isPersist + ? 'This flag maintains its state through successive authentication events.' + : 'This flag is not persistent.'} +
+
+ {current.conditions.length > 0 ? ( +
+ + {current.conditions.map((condition, index) => ( + + + + ))} +
+ ) : null} +
+ +
+ ); +} + +export default observer(FlagView); diff --git a/frontend/app/components/FFlags/NewFFlag/Header.tsx b/frontend/app/components/FFlags/NewFFlag/Header.tsx index b4e76dce9..389fb9494 100644 --- a/frontend/app/components/FFlags/NewFFlag/Header.tsx +++ b/frontend/app/components/FFlags/NewFFlag/Header.tsx @@ -1,13 +1,31 @@ import React from 'react'; import { Button } from 'UI'; import { observer } from 'mobx-react-lite'; -import cn from "classnames"; +import cn from 'classnames'; +import { ItemMenu } from 'UI'; +import { useStore } from 'App/mstore'; +import { useHistory } from 'react-router'; +import { toast } from 'react-toastify'; +import { fflags, withSiteId } from "App/routes"; -function Header({ current, onCancel, onSave, isNew }: any) { +function Header({ current, onCancel, onSave, isNew, siteId }: any) { + const { featureFlagsStore } = useStore(); + const history = useHistory(); + + const deleteHandler = () => { + featureFlagsStore.deleteFlag(current.featureFlagId).then(() => { + toast.success('Feature flag deleted.'); + history.push(withSiteId(fflags(), siteId)); + }); + }; + + const menuItems = [{ icon: 'trash', text: 'Delete', onClick: deleteHandler }]; return ( <>
-

{!current.flagKey ? 'New Feature Flag' : current.flagKey}

+

+ {!current.flagKey ? 'New Feature Flag' : current.flagKey} +

@@ -17,6 +35,7 @@ function Header({ current, onCancel, onSave, isNew }: any) { + {!isNew ? : null}
); diff --git a/frontend/app/components/FFlags/NewFFlag/Helpers.tsx b/frontend/app/components/FFlags/NewFFlag/Helpers.tsx index a1c2ecbaa..652fd80bc 100644 --- a/frontend/app/components/FFlags/NewFFlag/Helpers.tsx +++ b/frontend/app/components/FFlags/NewFFlag/Helpers.tsx @@ -4,15 +4,15 @@ import { QuestionMarkHint } from 'UI'; function Rollout() { return (
- Rollout + Rollout %
); } function Payload() { return ( -
- Payload (Optional) +
+ Payload (Optional)
) } diff --git a/frontend/app/components/FFlags/NewFFlag/NewFFlag.tsx b/frontend/app/components/FFlags/NewFFlag/NewFFlag.tsx index 23936c307..c7e4d7abd 100644 --- a/frontend/app/components/FFlags/NewFFlag/NewFFlag.tsx +++ b/frontend/app/components/FFlags/NewFFlag/NewFFlag.tsx @@ -23,6 +23,9 @@ function NewFFlag({ siteId, fflagId }: { siteId: string; fflagId?: string }) { } else { featureFlagsStore.initNewFlag(); } + return () => { + featureFlagsStore.setCurrentFlag(null); + } }, [fflagId]); const current = featureFlagsStore.currentFflag; @@ -47,7 +50,6 @@ function NewFFlag({ siteId, fflagId }: { siteId: string; fflagId?: string }) { }; const onCancel = () => { - featureFlagsStore.setCurrentFlag(null); history.push(withSiteId(fflags(), siteId)); }; @@ -90,7 +92,7 @@ function NewFFlag({ siteId, fflagId }: { siteId: string; fflagId?: string }) { />
-
+
diff --git a/frontend/app/components/Overview/Overview.tsx b/frontend/app/components/Overview/Overview.tsx index 2014ab905..4e5d0be78 100644 --- a/frontend/app/components/Overview/Overview.tsx +++ b/frontend/app/components/Overview/Overview.tsx @@ -9,8 +9,9 @@ import OverviewMenu from 'Shared/OverviewMenu'; import FFlagsList from 'Components/FFlags'; import NewFFlag from 'Components/FFlags/NewFFlag'; import { Switch, Route } from 'react-router'; -import { sessions, fflags, withSiteId, newFFlag, fflag, notes, bookmarks } from 'App/routes'; +import { sessions, fflags, withSiteId, newFFlag, fflag, notes, fflagRead, bookmarks } from 'App/routes'; import { withRouter, RouteComponentProps } from 'react-router-dom'; +import FlagView from 'Components/FFlags/FlagView/FlagView' // @ts-ignore interface IProps extends RouteComponentProps { @@ -50,6 +51,9 @@ function Overview({ match: { params } }: IProps) { + + +
diff --git a/frontend/app/mstore/types/FeatureFlag.ts b/frontend/app/mstore/types/FeatureFlag.ts index cbd8a5b22..9b6f689c2 100644 --- a/frontend/app/mstore/types/FeatureFlag.ts +++ b/frontend/app/mstore/types/FeatureFlag.ts @@ -106,9 +106,14 @@ export default class FeatureFlag { ...data, isSingleOption: data ? data.flagType === 'single' : true, conditions: data?.conditions?.map(c => new Conditions(c)) || [new Conditions()], - variants: data?.flagType === 'multi' ? data?.variants?.map((v, i) => new Variant(i, v)) : [new Variant(1)], + variants: data?.flagType === 'multi' ? data?.variants?.map((v, i) => new Variant(i, v)) : [], }); + if (this.variants?.length === 0) { + this.addVariant() + this.addVariant() + this.hasChanged = false + } makeAutoObservable(this); } diff --git a/frontend/app/routes.js b/frontend/app/routes.js index 0337820e8..c597c46a7 100644 --- a/frontend/app/routes.js +++ b/frontend/app/routes.js @@ -86,6 +86,8 @@ export const sessions = params => queried('/sessions', params); export const fflags = params => queried('/feature-flags', params); export const newFFlag = () => '/feature-flags/create'; export const fflag = (id = ':fflagId', hash) => hashed(`/feature-flags/${ id }`, hash); +export const fflagRead = (id = ':fflagId', hash) => hashed(`/feature-flags/get/${ id }`, hash); + export const notes = params => queried('/notes', params); export const bookmarks = params => queried('/bookmarks', params); export const assist = params => queried('/assist', params);