From 47579e26164277d2df2cf0e34164dabb63b30bec Mon Sep 17 00:00:00 2001 From: Fredrik Strand Oseberg Date: Fri, 1 Oct 2021 13:49:18 +0200 Subject: [PATCH] Feat/toggle view (#389) * feat: toggle view * fix: navigation * eat: toggle view * fix: resolve lint * fix: remove console logs * fix: reimplement feature validation --- frontend/src/app.css | 4 + .../FeatureLog/FeatureLog.styles.ts | 9 + .../FeatureView2/FeatureLog/FeatureLog.tsx | 19 ++ .../FeatureMetrics/FeatureMetrics.styles.ts | 9 + .../FeatureMetrics/FeatureMetrics.tsx | 19 ++ .../FeatureOverview/FeatureOverview.styles.ts | 10 + .../FeatureOverview/FeatureOverview.tsx | 21 +++ .../FeatureOverviewEnvironment.styles.ts | 77 ++++++++ .../FeatureOverviewEnvironment.tsx | 173 ++++++++++++++++++ .../FeatureOverviewStrategyCard.styles.ts | 36 ++++ .../FeatureOverviewStrategyCard.tsx | 42 +++++ .../FeatureOverviewStrategies.styles.ts | 27 +++ .../FeatureOverviewStrategies.tsx | 54 ++++++ .../FeatureOverviewTags.styles.ts | 40 ++++ .../FeatureOverviewTags.tsx | 101 ++++++++++ .../FeatureViewMetaData.tsx | 59 ++++++ .../FeatureViewMetadata.styles.ts | 21 +++ .../FeatureStrategiesConfigure.tsx | 4 +- .../useFeatureStrategiesEnvironmentList.ts | 7 +- .../FeatureStrategiesEnvironments.tsx | 37 +++- .../FeatureStrategyCard.styles.ts | 1 + .../FeatureVariants/FeatureVariants.styles.ts | 9 + .../FeatureVariants/FeatureVariants.tsx | 20 ++ .../feature/FeatureView2/FeatureView2.tsx | 92 ++++------ .../FeatureViewMetaData.tsx | 58 ------ .../variant/update-variant-container.jsx | 3 +- .../__snapshots__/routes-test.jsx.snap | 2 +- frontend/src/component/menu/routes.js | 2 +- .../actions/useFeatureApi/useFeatureApi.ts | 93 +++++++++- .../api/getters/useFeature/useFeature.ts | 2 +- .../api/getters/useTagTypes/useTagTypes.ts | 36 ++++ .../src/hooks/api/getters/useTags/useTags.ts | 36 ++++ frontend/src/interfaces/tags.ts | 10 + 33 files changed, 1005 insertions(+), 128 deletions(-) create mode 100644 frontend/src/component/feature/FeatureView2/FeatureLog/FeatureLog.styles.ts create mode 100644 frontend/src/component/feature/FeatureView2/FeatureLog/FeatureLog.tsx create mode 100644 frontend/src/component/feature/FeatureView2/FeatureMetrics/FeatureMetrics.styles.ts create mode 100644 frontend/src/component/feature/FeatureView2/FeatureMetrics/FeatureMetrics.tsx create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverview.styles.ts create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverview.tsx create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewEnvironment.styles.ts create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewEnvironment.tsx create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewStrategyCard/FeatureOverviewStrategyCard.styles.ts create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewStrategyCard/FeatureOverviewStrategyCard.tsx create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewStrategies.styles.ts create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewStrategies.tsx create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewTags/FeatureOverviewTags.styles.ts create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewTags/FeatureOverviewTags.tsx create mode 100644 frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureViewMetaData/FeatureViewMetaData.tsx rename frontend/src/component/feature/FeatureView2/{ => FeatureOverview}/FeatureViewMetaData/FeatureViewMetadata.styles.ts (52%) create mode 100644 frontend/src/component/feature/FeatureView2/FeatureVariants/FeatureVariants.styles.ts create mode 100644 frontend/src/component/feature/FeatureView2/FeatureVariants/FeatureVariants.tsx delete mode 100644 frontend/src/component/feature/FeatureView2/FeatureViewMetaData/FeatureViewMetaData.tsx create mode 100644 frontend/src/hooks/api/getters/useTagTypes/useTagTypes.ts create mode 100644 frontend/src/hooks/api/getters/useTags/useTags.ts create mode 100644 frontend/src/interfaces/tags.ts diff --git a/frontend/src/app.css b/frontend/src/app.css index a988c73e9f..015916508f 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -13,6 +13,10 @@ body { font-family: 'Sen', sans-serif; } +button { + font-family: 'Sen', sans-serif; +} + .MuiButton-root { border-radius: 3px; text-transform: none; diff --git a/frontend/src/component/feature/FeatureView2/FeatureLog/FeatureLog.styles.ts b/frontend/src/component/feature/FeatureView2/FeatureLog/FeatureLog.styles.ts new file mode 100644 index 0000000000..10dae26fef --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureLog/FeatureLog.styles.ts @@ -0,0 +1,9 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export const useStyles = makeStyles(theme => ({ + container: { + borderRadius: '12.5px', + backgroundColor: '#fff', + padding: '2rem', + }, +})); diff --git a/frontend/src/component/feature/FeatureView2/FeatureLog/FeatureLog.tsx b/frontend/src/component/feature/FeatureView2/FeatureLog/FeatureLog.tsx new file mode 100644 index 0000000000..4a1453bf4c --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureLog/FeatureLog.tsx @@ -0,0 +1,19 @@ +import { useParams } from 'react-router'; +import useFeature from '../../../../hooks/api/getters/useFeature/useFeature'; +import { useStyles } from './FeatureLog.styles'; +import { IFeatureViewParams } from '../../../../interfaces/params'; +import HistoryComponent from '../../../history/FeatureEventHistory'; + +const FeatureLog = () => { + const styles = useStyles(); + const { projectId, featureId } = useParams(); + const { feature } = useFeature(projectId, featureId); + + return ( +
+ ; +
+ ); +}; + +export default FeatureLog; diff --git a/frontend/src/component/feature/FeatureView2/FeatureMetrics/FeatureMetrics.styles.ts b/frontend/src/component/feature/FeatureView2/FeatureMetrics/FeatureMetrics.styles.ts new file mode 100644 index 0000000000..10dae26fef --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureMetrics/FeatureMetrics.styles.ts @@ -0,0 +1,9 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export const useStyles = makeStyles(theme => ({ + container: { + borderRadius: '12.5px', + backgroundColor: '#fff', + padding: '2rem', + }, +})); diff --git a/frontend/src/component/feature/FeatureView2/FeatureMetrics/FeatureMetrics.tsx b/frontend/src/component/feature/FeatureView2/FeatureMetrics/FeatureMetrics.tsx new file mode 100644 index 0000000000..00e3d309fd --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureMetrics/FeatureMetrics.tsx @@ -0,0 +1,19 @@ +import { useParams } from 'react-router'; +import useFeature from '../../../../hooks/api/getters/useFeature/useFeature'; +import MetricComponent from '../../view/metric-container'; +import { useStyles } from './FeatureMetrics.styles'; +import { IFeatureViewParams } from '../../../../interfaces/params'; + +const FeatureMetrics = () => { + const styles = useStyles(); + const { projectId, featureId } = useParams(); + const { feature } = useFeature(projectId, featureId); + + return ( +
+ +
+ ); +}; + +export default FeatureMetrics; diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverview.styles.ts b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverview.styles.ts new file mode 100644 index 0000000000..1af8d4ceaa --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverview.styles.ts @@ -0,0 +1,10 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export const useStyles = makeStyles(theme => ({ + container: { display: 'flex', width: '100%' }, + mainContent: { + display: 'flex', + flexDirection: 'column', + width: '100%', + }, +})); diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverview.tsx b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverview.tsx new file mode 100644 index 0000000000..c0e8ca75d7 --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverview.tsx @@ -0,0 +1,21 @@ +import FeatureViewMetaData from './FeatureViewMetaData/FeatureViewMetaData'; +import FeatureOverviewStrategies from './FeatureOverviewStrategies/FeatureOverviewStrategies'; +import { useStyles } from './FeatureOverview.styles'; +import FeatureOverviewTags from './FeatureOverviewTags/FeatureOverviewTags'; + +const FeatureOverview = () => { + const styles = useStyles(); + return ( +
+
+ + +
+
+ +
+
+ ); +}; + +export default FeatureOverview; diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewEnvironment.styles.ts b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewEnvironment.styles.ts new file mode 100644 index 0000000000..b8ba159492 --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewEnvironment.styles.ts @@ -0,0 +1,77 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export const useStyles = makeStyles(theme => ({ + container: { + marginBottom: '2rem', + border: `1px solid ${theme.palette.grey[300]}`, + borderRadius: '5px', + position: 'relative', + }, + header: { + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + borderBottom: `1px solid ${theme.palette.grey[300]}`, + padding: '1rem', + }, + icon: { + fill: '#fff', + height: '17.5px', + width: '17.5px', + }, + strategiesContainer: { + padding: '1rem 0', + ['& > *']: { + margin: '0.5rem 0', + }, + }, + environmentIdentifier: { + position: 'absolute', + right: '42.5%', + top: '-25px', + display: 'flex', + background: theme.palette.primary.light, + borderRadius: '25px', + padding: '0.4rem 1rem', + minWidth: '150px', + color: '#fff', + + alignItems: 'center', + }, + environmentBadgeParagraph: { + fontSize: theme.fontSizes.smallBody, + }, + iconContainer: { + padding: '0.25rem', + borderRadius: '50%', + alignItems: 'center', + justifyContent: 'center', + display: 'flex', + border: '1px solid #fff', + marginRight: '0.5rem', + }, + body: { + padding: '1rem', + }, + disabledEnvContainer: { + backgroundColor: theme.palette.grey[300], + color: theme.palette.grey[600], + }, + disabledIconContainer: { + border: `1px solid ${theme.palette.grey[500]}`, + }, + iconDisabled: { + fill: theme.palette.grey[500], + }, + + toggleText: { + fontSize: theme.fontSizes.smallBody, + }, + toggleLink: { + color: theme.palette.primary.main, + fontSize: theme.fontSizes.smallBody, + }, + headerDisabledEnv: { + border: 'none', + }, +})); diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewEnvironment.tsx b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewEnvironment.tsx new file mode 100644 index 0000000000..4fb8b4e4b1 --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewEnvironment.tsx @@ -0,0 +1,173 @@ +import { Cloud } from '@material-ui/icons'; +import { IFeatureEnvironment } from '../../../../../../interfaces/featureToggle'; +import { Switch } from '@material-ui/core'; +import { useStyles } from './FeatureOverviewEnvironment.styles'; +import FeatureOverviewStrategyCard from './FeatureOverviewStrategyCard/FeatureOverviewStrategyCard'; +import classNames from 'classnames'; +import ConditionallyRender from '../../../../../common/ConditionallyRender'; +import useFeatureApi from '../../../../../../hooks/api/actions/useFeatureApi/useFeatureApi'; +import { useHistory, useParams, Link } from 'react-router-dom'; +import { IFeatureViewParams } from '../../../../../../interfaces/params'; +import useToast from '../../../../../../hooks/useToast'; + +interface IFeatureOverviewEnvironmentProps { + env: IFeatureEnvironment; + refetch: () => void; +} + +const FeatureOverviewEnvironment = ({ + env, + refetch, +}: IFeatureOverviewEnvironmentProps) => { + const { featureId, projectId } = useParams(); + const { toggleFeatureEnvironmentOn, toggleFeatureEnvironmentOff } = + useFeatureApi(); + const styles = useStyles(); + const { toast, setToastData } = useToast(); + const history = useHistory(); + + console.log(env); + + const handleClick = () => { + history.push( + `/projects/${projectId}/features2/${featureId}/strategies?environment=${env.name}` + ); + }; + + const renderStrategies = () => { + const { strategies } = env; + + return strategies.map(strategy => { + return ( + + ); + }); + }; + + const handleToggleEnvironmentOn = async () => { + try { + await toggleFeatureEnvironmentOn(projectId, featureId, env.name); + setToastData({ + type: 'success', + show: true, + text: 'Successfully turned environment on.', + }); + refetch(); + } catch (e) { + setToastData({ + show: true, + type: 'error', + text: e.toString(), + }); + } + }; + + const handleToggleEnvironmentOff = async () => { + try { + await toggleFeatureEnvironmentOff(projectId, featureId, env.name); + setToastData({ + type: 'success', + show: true, + text: 'Successfully turned environment off.', + }); + refetch(); + } catch (e) { + setToastData({ + show: true, + type: 'error', + text: e.toString(), + }); + } + }; + + const toggleEnvironment = (e: React.ChangeEvent) => { + if (env.enabled) { + handleToggleEnvironmentOff(); + return; + } + handleToggleEnvironmentOn(); + }; + + const iconContainerClasses = classNames(styles.iconContainer, { + [styles.disabledIconContainer]: !env.enabled, + }); + + const iconClasses = classNames(styles.icon, { + [styles.iconDisabled]: !env.enabled, + }); + + const headerClasses = classNames(styles.header, { + [styles.headerDisabledEnv]: !env.enabled, + }); + + const environmentIdentifierClasses = classNames( + styles.environmentIdentifier, + { [styles.disabledEnvContainer]: !env.enabled } + ); + + return ( +
+
+
+ +
+

{env.type}

+
+ +
+
+

{env.name}

+
+
+ 0} + show={ + <> + {' '} + + This environment is{' '} + {env.enabled ? 'enabled' : 'disabled'} + + + } + elseShow={ + <> +

+ No strategies configured for environment. +

+ + Configure strategies for {env.name} + + + } + /> +
+
+ + +
+ {renderStrategies()} +
+
+ } + /> + {toast} + + ); +}; + +export default FeatureOverviewEnvironment; diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewStrategyCard/FeatureOverviewStrategyCard.styles.ts b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewStrategyCard/FeatureOverviewStrategyCard.styles.ts new file mode 100644 index 0000000000..cf610c3638 --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewStrategyCard/FeatureOverviewStrategyCard.styles.ts @@ -0,0 +1,36 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export const useStyles = makeStyles(theme => ({ + card: { + border: `1px solid ${theme.palette.grey[300]}`, + borderRadius: '5px', + transition: 'transform 0.3s ease', + transitionDelay: '0.1s', + position: 'relative', + background: 'transparent', + width: '100%', + display: 'flex', + alignItems: 'center', + padding: '0.75rem', + fontSize: theme.fontSizes.bodySize, + }, + cardHeader: { + maxWidth: '200px', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + overflow: 'hidden', + [theme.breakpoints.down(700)]: { + maxWidth: '100px', + fontSize: theme.fontSizes.smallBody, + }, + }, + icon: { + marginRight: '0.5rem', + fill: theme.palette.primary.main, + minWidth: '35px', + }, + rollout: { + fontSize: theme.fontSizes.smallBody, + marginLeft: '0.5rem', + }, +})); diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewStrategyCard/FeatureOverviewStrategyCard.tsx b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewStrategyCard/FeatureOverviewStrategyCard.tsx new file mode 100644 index 0000000000..58d927eccc --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewEnvironment/FeatureOverviewStrategyCard/FeatureOverviewStrategyCard.tsx @@ -0,0 +1,42 @@ +import { useMediaQuery } from '@material-ui/core'; +import { IFeatureStrategy } from '../../../../../../../interfaces/strategy'; +import { + getFeatureStrategyIcon, + getHumanReadbleStrategyName, +} from '../../../../../../../utils/strategy-names'; +import ConditionallyRender from '../../../../../../common/ConditionallyRender'; +import { useStyles } from './FeatureOverviewStrategyCard.styles'; + +interface IFeatureOverviewStrategyCardProps { + strategy: IFeatureStrategy; + onClick: () => void; +} + +const FeatureOverviewStrategyCard = ({ + strategy, + onClick, +}: IFeatureOverviewStrategyCardProps) => { + const styles = useStyles(); + const smallScreen = useMediaQuery('(max-width:500px)'); + const strategyName = getHumanReadbleStrategyName(strategy.name); + const Icon = getFeatureStrategyIcon(strategy.name); + + const { parameters } = strategy; + return ( + + ); +}; + +export default FeatureOverviewStrategyCard; diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewStrategies.styles.ts b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewStrategies.styles.ts new file mode 100644 index 0000000000..06b52ffb6a --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewStrategies.styles.ts @@ -0,0 +1,27 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export const useStyles = makeStyles(theme => ({ + container: { + borderRadius: '12.5px', + width: '100%', + backgroundColor: '#fff', + }, + headerContainer: { + borderBottom: `1px solid ${theme.palette.grey[300]}`, + }, + headerTitle: { + fontSize: theme.fontSizes.subHeader, + fontWeight: 'normal', + margin: 0, + }, + headerInnerContainer: { + padding: '1.5rem 2rem', + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + }, + actions: { position: 'relative' }, + bodyContainer: { + padding: '3rem 2rem', + }, +})); diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewStrategies.tsx b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewStrategies.tsx new file mode 100644 index 0000000000..3ea0cfe782 --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewStrategies/FeatureOverviewStrategies.tsx @@ -0,0 +1,54 @@ +import { Add } from '@material-ui/icons'; +import { Link, useParams } from 'react-router-dom'; +import useFeature from '../../../../../hooks/api/getters/useFeature/useFeature'; +import { IFeatureViewParams } from '../../../../../interfaces/params'; +import ResponsiveButton from '../../../../common/ResponsiveButton/ResponsiveButton'; +import FeatureOverviewEnvironment from './FeatureOverviewEnvironment/FeatureOverviewEnvironment'; +import { useStyles } from './FeatureOverviewStrategies.styles'; + +const FeatureOverviewStrategies = () => { + const styles = useStyles(); + const { projectId, featureId } = useParams(); + const { feature, refetch } = useFeature(projectId, featureId); + + if (!feature) return null; + + const { environments } = feature; + + const renderEnvironments = () => { + return environments?.map(env => { + return ( + + ); + }); + }; + + return ( +
+
+
+

Toggle Strategies

+
+ + Add new strategy + +
+
+
+ +
{renderEnvironments()}
+
+ ); +}; + +export default FeatureOverviewStrategies; diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewTags/FeatureOverviewTags.styles.ts b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewTags/FeatureOverviewTags.styles.ts new file mode 100644 index 0000000000..f5562e2443 --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewTags/FeatureOverviewTags.styles.ts @@ -0,0 +1,40 @@ +import { makeStyles } from '@material-ui/core/styles'; + +export const useStyles = makeStyles(theme => ({ + container: { + borderRadius: '10px', + backgroundColor: '#fff', + display: 'flex', + flexDirection: 'column', + + maxWidth: '350px', + minWidth: '350px', + marginRight: '1rem', + marginTop: '1rem', + }, + tagheaderContainer: { + display: 'flex', + alignItems: 'center', + padding: '1.5rem', + justifyContent: 'space-between', + borderBottom: `1px solid ${theme.palette.grey[300]}`, + }, + tagHeader: { + display: 'flex', + alignItems: 'center', + }, + tag: { + height: '40px', + width: '40px', + fill: theme.palette.primary.main, + marginRight: '0.8rem', + }, + tagHeaderText: { + fontSize: theme.fontSizes.subHeader, + fontWeight: 'normal', + margin: 0, + }, + tagContent: { + padding: '1.5rem', + }, +})); diff --git a/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewTags/FeatureOverviewTags.tsx b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewTags/FeatureOverviewTags.tsx new file mode 100644 index 0000000000..d0b8601933 --- /dev/null +++ b/frontend/src/component/feature/FeatureView2/FeatureOverview/FeatureOverviewTags/FeatureOverviewTags.tsx @@ -0,0 +1,101 @@ +import { Chip } from '@material-ui/core'; +import { Label } from '@material-ui/icons'; +import { useParams } from 'react-router-dom'; +import useTags from '../../../../../hooks/api/getters/useTags/useTags'; +import { IFeatureViewParams } from '../../../../../interfaces/params'; +import { useStyles } from './FeatureOverviewTags.styles'; + +import slackIcon from '../../../../../assets/icons/slack.svg'; +import jiraIcon from '../../../../../assets/icons/jira.svg'; +import webhookIcon from '../../../../../assets/icons/webhooks.svg'; +import { formatAssetPath } from '../../../../../utils/format-path'; +import useTagTypes from '../../../../../hooks/api/getters/useTagTypes/useTagTypes'; +import useFeatureApi from '../../../../../hooks/api/actions/useFeatureApi/useFeatureApi'; +import AddTagDialogContainer from '../../../add-tag-dialog-container'; + +const FeatureOverviewTags = () => { + const styles = useStyles(); + const { featureId } = useParams(); + const { tags, refetch } = useTags(featureId); + const { tagTypes } = useTagTypes(); + const { deleteTag } = useFeatureApi(); + + const handleDelete = async (type: string, value: string) => { + try { + await deleteTag(featureId, type, value); + refetch(); + } catch (e) { + // TODO: Handle error + console.log(e); + } + }; + + const tagIcon = (typeName: string) => { + let tagType = tagTypes.find(type => type.name === typeName); + + const style = { width: '20px', height: '20px', marginRight: '5px' }; + + if (tagType && tagType.icon) { + switch (tagType.name) { + case 'slack': + return ( + slack + ); + case 'jira': + return ( + jira + ); + case 'webhook': + return ( + webhook + ); + default: + return