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

feat: new flag header (#9302)

Initial spike to add the new design for the flag page header
This commit is contained in:
Thomas Heartman 2025-02-14 14:33:35 +01:00 committed by GitHub
parent 8dc6fbf149
commit aafacc68cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 263 additions and 132 deletions

View File

@ -1,18 +1,24 @@
import { useState } from 'react'; import { type PropsWithChildren, useState, type FC } from 'react';
import { import {
IconButton, IconButton,
styled, styled,
Tab, Tab,
Tabs, Tabs,
Tooltip, Tooltip,
Typography,
useMediaQuery, useMediaQuery,
} from '@mui/material'; } from '@mui/material';
import Archive from '@mui/icons-material/Archive'; import Archive from '@mui/icons-material/Archive';
import ArchiveOutlined from '@mui/icons-material/ArchiveOutlined';
import FileCopy from '@mui/icons-material/FileCopy'; import FileCopy from '@mui/icons-material/FileCopy';
import FileCopyOutlined from '@mui/icons-material/FileCopyOutlined';
import Label from '@mui/icons-material/Label'; import Label from '@mui/icons-material/Label';
import WatchLater from '@mui/icons-material/WatchLater'; import WatchLater from '@mui/icons-material/WatchLater';
import WatchLaterOutlined from '@mui/icons-material/WatchLaterOutlined';
import LibraryAdd from '@mui/icons-material/LibraryAdd'; import LibraryAdd from '@mui/icons-material/LibraryAdd';
import LibraryAddOutlined from '@mui/icons-material/LibraryAddOutlined';
import Check from '@mui/icons-material/Check'; import Check from '@mui/icons-material/Check';
import Star from '@mui/icons-material/Star';
import { import {
Link, Link,
Route, Route,
@ -49,6 +55,46 @@ import useToast from 'hooks/useToast';
import { useUiFlag } from 'hooks/useUiFlag'; import { useUiFlag } from 'hooks/useUiFlag';
import type { IFeatureToggle } from 'interfaces/featureToggle'; import type { IFeatureToggle } from 'interfaces/featureToggle';
import { Collaborators } from './Collaborators'; import { Collaborators } from './Collaborators';
import StarBorder from '@mui/icons-material/StarBorder';
import { TooltipResolver } from 'component/common/TooltipResolver/TooltipResolver';
const NewStyledHeader = styled('div')(({ theme }) => ({
backgroundColor: 'none',
marginBottom: theme.spacing(2),
borderBottom: `1px solid ${theme.palette.divider}`,
}));
const LowerHeaderRow = styled('div')(({ theme }) => ({
display: 'flex',
flexFlow: 'row nowrap',
justifyContent: 'space-between',
gap: theme.spacing(4),
}));
const HeaderActions = styled('div')(({ theme }) => ({
display: 'flex',
flexFlow: 'row nowrap',
alignItems: 'center',
}));
const IconButtonWithTooltip: FC<
PropsWithChildren<{
onClick: () => void;
label: string;
}>
> = ({ children, label, onClick }) => {
return (
<TooltipResolver
title={label}
arrow
onClick={(e) => e.preventDefault()}
>
<IconButton aria-label={label} onClick={onClick}>
{children}
</IconButton>
</TooltipResolver>
);
};
const StyledHeader = styled('div')(({ theme }) => ({ const StyledHeader = styled('div')(({ theme }) => ({
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
@ -139,6 +185,7 @@ const useLegacyVariants = (environments: IFeatureToggle['environments']) => {
export const FeatureView = () => { export const FeatureView = () => {
const projectId = useRequiredPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const featureId = useRequiredPathParam('featureId'); const featureId = useRequiredPathParam('featureId');
const flagOverviewRedesign = useUiFlag('flagOverviewRedesign');
const { favorite, unfavorite } = useFavoriteFeaturesApi(); const { favorite, unfavorite } = useFavoriteFeaturesApi();
const { refetchFeature } = useFeature(projectId, featureId); const { refetchFeature } = useFeature(projectId, featureId);
const { setToastData, setToastApiError } = useToast(); const { setToastData, setToastApiError } = useToast();
@ -231,6 +278,84 @@ export const FeatureView = () => {
return ( return (
<div ref={ref}> <div ref={ref}>
{flagOverviewRedesign ? (
<NewStyledHeader>
<Typography variant='h1'>{feature.name}</Typography>
<LowerHeaderRow>
<Tabs
value={activeTab.path}
indicatorColor='primary'
textColor='primary'
>
{tabData.map((tab) => (
<StyledTabButton
key={tab.title}
label={tab.title}
value={tab.path}
onClick={() => navigate(tab.path)}
data-testid={`TAB-${tab.title}`}
/>
))}
</Tabs>
<HeaderActions>
<IconButtonWithTooltip
label='Favorite this feature flag'
onClick={onFavorite}
data-loading
>
{feature?.favorite ? <Star /> : <StarBorder />}
</IconButtonWithTooltip>
<IconButtonWithTooltip
label='Copy flag name'
onClick={handleCopyToClipboard}
data-loading
>
{isFeatureNameCopied ? (
<Check />
) : (
<FileCopyOutlined />
)}
</IconButtonWithTooltip>
<PermissionIconButton
permission={CREATE_FEATURE}
projectId={projectId}
data-loading
component={Link}
to={`/projects/${projectId}/features/${featureId}/copy`}
tooltipProps={{
title: 'Clone',
}}
>
<LibraryAddOutlined />
</PermissionIconButton>
<PermissionIconButton
permission={DELETE_FEATURE}
projectId={projectId}
tooltipProps={{
title: 'Archive feature flag',
}}
data-loading
onClick={() => setShowDelDialog(true)}
>
<ArchiveOutlined />
</PermissionIconButton>
<PermissionIconButton
onClick={() => setOpenStaleDialog(true)}
permission={UPDATE_FEATURE}
projectId={projectId}
tooltipProps={{
title: 'Toggle stale state',
}}
data-loading
>
<WatchLaterOutlined />
</PermissionIconButton>
</HeaderActions>
</LowerHeaderRow>
</NewStyledHeader>
) : (
<StyledHeader> <StyledHeader>
<StyledInnerContainer> <StyledInnerContainer>
<StyledFlagInfoContainer> <StyledFlagInfoContainer>
@ -256,7 +381,9 @@ export const FeatureView = () => {
style={{ marginLeft: 8 }} style={{ marginLeft: 8 }}
> >
{isFeatureNameCopied ? ( {isFeatureNameCopied ? (
<Check style={{ fontSize: 16 }} /> <Check
style={{ fontSize: 16 }}
/>
) : ( ) : (
<FileCopy <FileCopy
style={{ fontSize: 16 }} style={{ fontSize: 16 }}
@ -281,7 +408,10 @@ export const FeatureView = () => {
<StyledLink <StyledLink
to={`/projects/${feature.project}/features/${feature?.dependencies[0]?.feature}`} to={`/projects/${feature.project}/features/${feature?.dependencies[0]?.feature}`}
> >
{feature?.dependencies[0]?.feature} {
feature?.dependencies[0]
?.feature
}
</StyledLink> </StyledLink>
</StyledDependency> </StyledDependency>
} }
@ -369,6 +499,7 @@ export const FeatureView = () => {
/> />
</StyledTabRow> </StyledTabRow>
</StyledHeader> </StyledHeader>
)}
<Routes> <Routes>
<Route path='metrics' element={<FeatureMetrics />} /> <Route path='metrics' element={<FeatureMetrics />} />
<Route path='logs' element={<FeatureLog />} /> <Route path='logs' element={<FeatureLog />} />

View File

@ -52,7 +52,7 @@ process.nextTick(async () => {
releasePlans: false, releasePlans: false,
releasePlanChangeRequests: false, releasePlanChangeRequests: false,
showUserDeviceCount: true, showUserDeviceCount: true,
flagOverviewRedesign: false, flagOverviewRedesign: true,
granularAdminPermissions: true, granularAdminPermissions: true,
deltaApi: true, deltaApi: true,
uniqueSdkTracking: true, uniqueSdkTracking: true,