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

Feat/private project badge (#5373)

Adds an icon with tooltip for private projects in ProjectCard and
Project header:

<img width="528" alt="Skjermbilde 2023-11-21 kl 10 58 13"
src="https://github.com/Unleash/unleash/assets/16081982/28004c11-a20d-4740-98f4-127f41639896">
This commit is contained in:
Fredrik Strand Oseberg 2023-11-21 11:49:50 +01:00 committed by GitHub
parent d5049e6197
commit 83fe430a14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 51 additions and 8 deletions

View File

@ -0,0 +1,17 @@
import { styled } from '@mui/material';
import { VisibilityOff } from '@mui/icons-material';
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
export const StyledVisibilityIcon = styled(VisibilityOff)(({ theme }) => ({
color: theme.palette.action.disabled,
}));
export const HiddenProjectIconWithTooltip = () => (
<HtmlTooltip
title={`This projects collaboration mode is set to private. The project and associated feature
toggles can only be seen by you and the members of the project`}
arrow
>
<StyledVisibilityIcon />
</HtmlTooltip>
);

View File

@ -41,6 +41,7 @@ import { Badge } from 'component/common/Badge/Badge';
import { ProjectDoraMetrics } from './ProjectDoraMetrics/ProjectDoraMetrics'; import { ProjectDoraMetrics } from './ProjectDoraMetrics/ProjectDoraMetrics';
import { UiFlags } from 'interfaces/uiConfig'; import { UiFlags } from 'interfaces/uiConfig';
import { ExperimentalProjectFeatures } from './ExperimentalProjectFeatures/ExperimentalProjectFeatures'; import { ExperimentalProjectFeatures } from './ExperimentalProjectFeatures/ExperimentalProjectFeatures';
import { HiddenProjectIconWithTooltip } from './HiddenProjectIconWithTooltip/HiddenProjectIconWithTooltip';
const StyledBadge = styled(Badge)(({ theme }) => ({ const StyledBadge = styled(Badge)(({ theme }) => ({
position: 'absolute', position: 'absolute',
@ -189,6 +190,10 @@ export const Project = () => {
isFavorite={project?.favorite} isFavorite={project?.favorite}
/> />
<StyledProjectTitle> <StyledProjectTitle>
<ConditionallyRender
condition={project?.mode === 'private'}
show={<HiddenProjectIconWithTooltip />}
/>
<StyledName data-loading> <StyledName data-loading>
{projectName} {projectName}
</StyledName> </StyledName>

View File

@ -23,13 +23,13 @@ export const CollaborationModeTooltip: FC = () => {
<Box> <Box>
<StyledTitle>open: </StyledTitle> <StyledTitle>open: </StyledTitle>
<StyledDescription> <StyledDescription>
everyone can submit change requests Everyone can submit change requests
</StyledDescription> </StyledDescription>
</Box> </Box>
<Box sx={{ mt: 2 }}> <Box sx={{ mt: 2 }}>
<StyledTitle>protected: </StyledTitle> <StyledTitle>protected: </StyledTitle>
<StyledDescription> <StyledDescription>
only admins and project members can submit change Only admins and project members can submit change
requests requests
</StyledDescription> </StyledDescription>
</Box> </Box>
@ -39,8 +39,9 @@ export const CollaborationModeTooltip: FC = () => {
<Box sx={{ mt: 2 }}> <Box sx={{ mt: 2 }}>
<StyledTitle>private: </StyledTitle> <StyledTitle>private: </StyledTitle>
<StyledDescription> <StyledDescription>
only projects members can and access see the Only admins, editors and project members can
project see and access the project and associated
feature toggles
</StyledDescription> </StyledDescription>
</Box> </Box>
} }

View File

@ -75,3 +75,8 @@ export const StyledParagraphInfo = styled('p')(({ theme }) => ({
color: theme.palette.primary.dark, color: theme.palette.primary.dark,
fontWeight: 'bold', fontWeight: 'bold',
})); }));
export const StyledIconBox = styled(Box)(() => ({
display: 'flex',
justifyContent: 'center',
}));

View File

@ -1,4 +1,4 @@
import { Menu, MenuItem } from '@mui/material'; import { Menu, MenuItem, Tooltip, Box } from '@mui/material';
import MoreVertIcon from '@mui/icons-material/MoreVert'; import MoreVertIcon from '@mui/icons-material/MoreVert';
import React, { SyntheticEvent, useContext, useState } from 'react'; import React, { SyntheticEvent, useContext, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -26,8 +26,10 @@ import {
StyledDivInfo, StyledDivInfo,
StyledDivInfoContainer, StyledDivInfoContainer,
StyledParagraphInfo, StyledParagraphInfo,
StyledIconBox,
} from './ProjectCard.styles'; } from './ProjectCard.styles';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import { HiddenProjectIconWithTooltip } from '../Project/HiddenProjectIconWithTooltip/HiddenProjectIconWithTooltip';
interface IProjectCardProps { interface IProjectCardProps {
name: string; name: string;
@ -37,6 +39,7 @@ interface IProjectCardProps {
id: string; id: string;
onHover: () => void; onHover: () => void;
isFavorite?: boolean; isFavorite?: boolean;
mode: string;
} }
export const ProjectCard = ({ export const ProjectCard = ({
@ -46,6 +49,7 @@ export const ProjectCard = ({
memberCount, memberCount,
onHover, onHover,
id, id,
mode,
isFavorite = false, isFavorite = false,
}: IProjectCardProps) => { }: IProjectCardProps) => {
const { hasAccess } = useContext(AccessContext); const { hasAccess } = useContext(AccessContext);
@ -127,9 +131,13 @@ export const ProjectCard = ({
</MenuItem> </MenuItem>
</Menu> </Menu>
</StyledDivHeader> </StyledDivHeader>
<div data-loading> <StyledIconBox data-loading>
<StyledProjectIcon /> <ConditionallyRender
</div> condition={mode === 'private'}
show={<HiddenProjectIconWithTooltip />}
elseShow={<StyledProjectIcon />}
/>
</StyledIconBox>
<StyledDivInfo> <StyledDivInfo>
<StyledDivInfoContainer> <StyledDivInfoContainer>
<StyledParagraphInfo data-loading> <StyledParagraphInfo data-loading>

View File

@ -245,6 +245,7 @@ export const ProjectListNew = () => {
key={project.id} key={project.id}
name={project.name} name={project.name}
id={project.id} id={project.id}
mode={project.mode}
memberCount={2} memberCount={2}
health={95} health={95}
featureCount={4} featureCount={4}
@ -263,6 +264,7 @@ export const ProjectListNew = () => {
handleHover(project.id) handleHover(project.id)
} }
name={project.name} name={project.name}
mode={project.mode}
memberCount={ memberCount={
project.memberCount ?? 0 project.memberCount ?? 0
} }

View File

@ -7,6 +7,7 @@ const loadingData = [
featureCount: 4, featureCount: 4,
createdAt: '', createdAt: '',
description: '', description: '',
mode: '',
}, },
{ {
id: 'loading2', id: 'loading2',
@ -16,6 +17,7 @@ const loadingData = [
featureCount: 4, featureCount: 4,
createdAt: '', createdAt: '',
description: '', description: '',
mode: '',
}, },
{ {
id: 'loading3', id: 'loading3',
@ -25,6 +27,7 @@ const loadingData = [
featureCount: 4, featureCount: 4,
createdAt: '', createdAt: '',
description: '', description: '',
mode: '',
}, },
{ {
id: 'loading4', id: 'loading4',
@ -34,6 +37,7 @@ const loadingData = [
featureCount: 4, featureCount: 4,
createdAt: '', createdAt: '',
description: '', description: '',
mode: '',
}, },
]; ];

View File

@ -10,6 +10,7 @@ export interface IProjectCard {
health: number; health: number;
description: string; description: string;
featureCount: number; featureCount: number;
mode: string;
memberCount?: number; memberCount?: number;
favorite?: boolean; favorite?: boolean;
} }