1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-04 00:18:01 +01:00

feat: add copy button to feature flag name (#4098) (#5031)

In ActionsCell.tsx file, 'Copy' with FileCopy icon is changed to 'Clone'
with 'LibraryAdd' icon as this feature is used to clone a new feature
from existing one. Upon copying the icon and text will change to 'Check'
icon with 'Copied!' for one sec and closes automatically.
This commit is contained in:
Mohan Raj A 2023-10-30 20:08:59 +05:30 committed by GitHub
parent df79e0b2ee
commit 0c43089ea2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 6 deletions

View File

@ -1,6 +1,20 @@
import { useState } from 'react'; import { useState } from 'react';
import { styled, Tab, Tabs, useMediaQuery } from '@mui/material'; import {
import { Archive, FileCopy, Label, WatchLater } from '@mui/icons-material'; IconButton,
styled,
Tab,
Tabs,
Tooltip,
useMediaQuery,
} from '@mui/material';
import {
Archive,
FileCopy,
Label,
WatchLater,
LibraryAdd,
Check,
} from '@mui/icons-material';
import { import {
Link, Link,
Route, 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 { ReactComponent as ParentLinkIcon } from 'assets/icons/link-parent.svg';
import { ChildrenTooltip } from './FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/ChildrenTooltip'; import { ChildrenTooltip } from './FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanelDetails/ChildrenTooltip';
import { useUiFlag } from 'hooks/useUiFlag'; import { useUiFlag } from 'hooks/useUiFlag';
import copy from 'copy-to-clipboard';
import useToast from 'hooks/useToast';
const StyledHeader = styled('div')(({ theme }) => ({ const StyledHeader = styled('div')(({ theme }) => ({
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
@ -128,10 +144,12 @@ export const FeatureView = () => {
const { favorite, unfavorite } = useFavoriteFeaturesApi(); const { favorite, unfavorite } = useFavoriteFeaturesApi();
const { refetchFeature } = useFeature(projectId, featureId); const { refetchFeature } = useFeature(projectId, featureId);
const dependentFeatures = useUiFlag('dependentFeatures'); const dependentFeatures = useUiFlag('dependentFeatures');
const { setToastData } = useToast();
const [openTagDialog, setOpenTagDialog] = useState(false); const [openTagDialog, setOpenTagDialog] = useState(false);
const [showDelDialog, setShowDelDialog] = useState(false); const [showDelDialog, setShowDelDialog] = useState(false);
const [openStaleDialog, setOpenStaleDialog] = useState(false); const [openStaleDialog, setOpenStaleDialog] = useState(false);
const [isFeatureNameCopied, setIsFeatureNameCopied] = useState(false);
const smallScreen = useMediaQuery(`(max-width:${500}px)`); const smallScreen = useMediaQuery(`(max-width:${500}px)`);
const { feature, loading, error, status } = useFeature( const { feature, loading, error, status } = useFeature(
@ -185,6 +203,21 @@ export const FeatureView = () => {
return <div ref={ref} />; return <div ref={ref} />;
} }
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 ( return (
<div ref={ref}> <div ref={ref}>
<StyledHeader> <StyledHeader>
@ -199,6 +232,27 @@ export const FeatureView = () => {
<StyledFeatureViewHeader data-loading> <StyledFeatureViewHeader data-loading>
{feature.name}{' '} {feature.name}{' '}
</StyledFeatureViewHeader> </StyledFeatureViewHeader>
<Tooltip
title={
isFeatureNameCopied
? 'Copied!'
: 'Copy name'
}
arrow
>
<IconButton
onClick={handleCopyToClipboard}
style={{ marginLeft: 8 }}
>
{isFeatureNameCopied ? (
<Check style={{ fontSize: 16 }} />
) : (
<FileCopy
style={{ fontSize: 16 }}
/>
)}
</IconButton>
</Tooltip>
<ConditionallyRender <ConditionallyRender
condition={!smallScreen} condition={!smallScreen}
show={ show={
@ -250,10 +304,10 @@ export const FeatureView = () => {
component={Link} component={Link}
to={`/projects/${projectId}/features/${featureId}/copy`} to={`/projects/${projectId}/features/${featureId}/copy`}
tooltipProps={{ tooltipProps={{
title: 'Copy feature toggle', title: 'Clone',
}} }}
> >
<FileCopy /> <LibraryAdd />
</PermissionIconButton> </PermissionIconButton>
<PermissionIconButton <PermissionIconButton
permission={DELETE_FEATURE} permission={DELETE_FEATURE}

View File

@ -14,6 +14,8 @@ import {
import { Link as RouterLink } from 'react-router-dom'; import { Link as RouterLink } from 'react-router-dom';
import MoreVertIcon from '@mui/icons-material/MoreVert'; import MoreVertIcon from '@mui/icons-material/MoreVert';
import FileCopyIcon from '@mui/icons-material/FileCopy'; import FileCopyIcon from '@mui/icons-material/FileCopy';
import LibraryAddIcon from '@mui/icons-material/LibraryAdd';
import CheckIcon from '@mui/icons-material/Check';
import ArchiveIcon from '@mui/icons-material/Archive'; import ArchiveIcon from '@mui/icons-material/Archive';
import WatchLaterIcon from '@mui/icons-material/WatchLater'; import WatchLaterIcon from '@mui/icons-material/WatchLater';
import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC'; import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC';
@ -23,6 +25,8 @@ import {
UPDATE_FEATURE, UPDATE_FEATURE,
} from 'component/providers/AccessProvider/permissions'; } from 'component/providers/AccessProvider/permissions';
import { defaultBorderRadius } from 'themes/themeStyles'; import { defaultBorderRadius } from 'themes/themeStyles';
import copy from 'copy-to-clipboard';
import useToast from 'hooks/useToast';
const StyledBoxCell = styled(Box)(({ theme }) => ({ const StyledBoxCell = styled(Box)(({ theme }) => ({
display: 'flex', display: 'flex',
@ -49,6 +53,8 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
onOpenStaleDialog, onOpenStaleDialog,
}) => { }) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [isFeatureNameCopied, setIsFeatureNameCopied] = useState(false);
const { setToastData } = useToast();
const { const {
original: { name: featureId, stale }, original: { name: featureId, stale },
} = row; } = row;
@ -63,6 +69,23 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
const id = `feature-${featureId}-actions`; const id = `feature-${featureId}-actions`;
const menuId = `${id}-menu`; 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 ( return (
<StyledBoxCell> <StyledBoxCell>
<Tooltip title='Feature toggle actions' arrow describeChild> <Tooltip title='Feature toggle actions' arrow describeChild>
@ -93,6 +116,23 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
}} }}
> >
<MenuList aria-labelledby={id}> <MenuList aria-labelledby={id}>
<MenuItem
sx={defaultBorderRadius}
onClick={handleCopyToClipboard}
>
<ListItemIcon>
{isFeatureNameCopied ? (
<CheckIcon />
) : (
<FileCopyIcon />
)}
</ListItemIcon>
<ListItemText>
<Typography variant='body2'>
{isFeatureNameCopied ? 'Copied!' : 'Copy Name'}
</Typography>
</ListItemText>
</MenuItem>
<PermissionHOC <PermissionHOC
projectId={projectId} projectId={projectId}
permission={CREATE_FEATURE} permission={CREATE_FEATURE}
@ -106,11 +146,11 @@ export const ActionsCell: VFC<IActionsCellProps> = ({
to={`/projects/${projectId}/features/${featureId}/copy`} to={`/projects/${projectId}/features/${featureId}/copy`}
> >
<ListItemIcon> <ListItemIcon>
<FileCopyIcon /> <LibraryAddIcon />
</ListItemIcon> </ListItemIcon>
<ListItemText> <ListItemText>
<Typography variant='body2'> <Typography variant='body2'>
Copy Clone
</Typography> </Typography>
</ListItemText> </ListItemText>
</MenuItem> </MenuItem>