diff --git a/frontend/src/component/feature/FeatureView/FeatureView.tsx b/frontend/src/component/feature/FeatureView/FeatureView.tsx index 80ee14b76c..2deeed8c08 100644 --- a/frontend/src/component/feature/FeatureView/FeatureView.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureView.tsx @@ -1,6 +1,20 @@ import { useState } from 'react'; -import { styled, Tab, Tabs, useMediaQuery } from '@mui/material'; -import { Archive, FileCopy, Label, WatchLater } from '@mui/icons-material'; +import { + IconButton, + styled, + Tab, + Tabs, + Tooltip, + useMediaQuery, +} from '@mui/material'; +import { + Archive, + FileCopy, + Label, + WatchLater, + LibraryAdd, + Check, +} from '@mui/icons-material'; import { Link, Route, @@ -36,6 +50,8 @@ import { ReactComponent as ChildLinkIcon } from 'assets/icons/link-child.svg'; import { ReactComponent as ParentLinkIcon } from 'assets/icons/link-parent.svg'; import { ChildrenTooltip } from './FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/ChildrenTooltip'; import { useUiFlag } from 'hooks/useUiFlag'; +import copy from 'copy-to-clipboard'; +import useToast from 'hooks/useToast'; const StyledHeader = styled('div')(({ theme }) => ({ backgroundColor: theme.palette.background.paper, @@ -128,10 +144,12 @@ export const FeatureView = () => { const { favorite, unfavorite } = useFavoriteFeaturesApi(); const { refetchFeature } = useFeature(projectId, featureId); const dependentFeatures = useUiFlag('dependentFeatures'); + const { setToastData } = useToast(); const [openTagDialog, setOpenTagDialog] = useState(false); const [showDelDialog, setShowDelDialog] = useState(false); const [openStaleDialog, setOpenStaleDialog] = useState(false); + const [isFeatureNameCopied, setIsFeatureNameCopied] = useState(false); const smallScreen = useMediaQuery(`(max-width:${500}px)`); const { feature, loading, error, status } = useFeature( @@ -185,6 +203,21 @@ export const FeatureView = () => { return
; } + const handleCopyToClipboard = () => { + try { + copy(feature.name); + setIsFeatureNameCopied(true); + setTimeout(() => { + setIsFeatureNameCopied(false); + }, 3000); + } catch (error: unknown) { + setToastData({ + type: 'error', + title: 'Could not copy feature name', + }); + } + }; + return (
@@ -199,6 +232,27 @@ export const FeatureView = () => { {feature.name}{' '} + + + {isFeatureNameCopied ? ( + + ) : ( + + )} + + { component={Link} to={`/projects/${projectId}/features/${featureId}/copy`} tooltipProps={{ - title: 'Copy feature toggle', + title: 'Clone', }} > - + ({ display: 'flex', @@ -49,6 +53,8 @@ export const ActionsCell: VFC = ({ onOpenStaleDialog, }) => { const [anchorEl, setAnchorEl] = useState(null); + const [isFeatureNameCopied, setIsFeatureNameCopied] = useState(false); + const { setToastData } = useToast(); const { original: { name: featureId, stale }, } = row; @@ -63,6 +69,23 @@ export const ActionsCell: VFC = ({ const id = `feature-${featureId}-actions`; const menuId = `${id}-menu`; + const handleCopyToClipboard = () => { + try { + copy(featureId); + setIsFeatureNameCopied(true); + + setTimeout(() => { + handleClose(); + setIsFeatureNameCopied(false); + }, 1000); + } catch (error: unknown) { + setToastData({ + type: 'error', + title: 'Could not copy feature name', + }); + } + }; + return ( @@ -93,6 +116,23 @@ export const ActionsCell: VFC = ({ }} > + + + {isFeatureNameCopied ? ( + + ) : ( + + )} + + + + {isFeatureNameCopied ? 'Copied!' : 'Copy Name'} + + + = ({ to={`/projects/${projectId}/features/${featureId}/copy`} > - + - Copy + Clone