1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-04 13:48:56 +02:00

fix: misc UI/UX fixes, mostly related with favorites (#2683)

https://linear.app/unleash/issue/2-504/misc-frontend-related-fixes-mostly-related-with-favorites
This commit is contained in:
Nuno Góis 2022-12-13 13:19:21 +00:00 committed by GitHub
parent a8cd3166d1
commit e05d924663
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 91 additions and 109 deletions

View File

@ -1,11 +1,5 @@
import { useEffect, useMemo, useState, VFC } from 'react'; import { useEffect, useMemo, useState, VFC } from 'react';
import { import { IconButton, Tooltip, useMediaQuery, useTheme } from '@mui/material';
IconButton,
styled,
Tooltip,
useMediaQuery,
useTheme,
} from '@mui/material';
import { useSearchParams, Link } from 'react-router-dom'; import { useSearchParams, Link } from 'react-router-dom';
import { SortingRule, useFlexLayout, useSortBy, useTable } from 'react-table'; import { SortingRule, useFlexLayout, useSortBy, useTable } from 'react-table';
import { TablePlaceholder, VirtualizedTable } from 'component/common/Table'; import { TablePlaceholder, VirtualizedTable } from 'component/common/Table';
@ -41,14 +35,6 @@ import {
UG_REMOVE_USER_BTN_ID, UG_REMOVE_USER_BTN_ID,
} from 'utils/testIds'; } from 'utils/testIds';
const StyledEdit = styled(Edit)(({ theme }) => ({
fontSize: theme.fontSizes.mainHeader,
}));
const StyledDelete = styled(Delete)(({ theme }) => ({
fontSize: theme.fontSizes.mainHeader,
}));
export const groupUsersPlaceholder: IGroupUser[] = Array(15).fill({ export const groupUsersPlaceholder: IGroupUser[] = Array(15).fill({
name: 'Name of the user', name: 'Name of the user',
username: 'Username of the user', username: 'Username of the user',
@ -248,7 +234,7 @@ export const Group: VFC = () => {
title: 'Edit group', title: 'Edit group',
}} }}
> >
<StyledEdit /> <Edit />
</PermissionIconButton> </PermissionIconButton>
<PermissionIconButton <PermissionIconButton
data-testid={UG_DELETE_BTN_ID} data-testid={UG_DELETE_BTN_ID}
@ -259,7 +245,7 @@ export const Group: VFC = () => {
title: 'Delete group', title: 'Delete group',
}} }}
> >
<StyledDelete /> <Delete />
</PermissionIconButton> </PermissionIconButton>
</> </>
} }

View File

@ -1,5 +1,5 @@
import React, { VFC } from 'react'; import { VFC } from 'react';
import { IconButton, SxProps, Theme } from '@mui/material'; import { IconButton, IconButtonProps } from '@mui/material';
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
import { import {
Star as StarIcon, Star as StarIcon,
@ -7,30 +7,24 @@ import {
} from '@mui/icons-material'; } from '@mui/icons-material';
import { TooltipResolver } from '../TooltipResolver/TooltipResolver'; import { TooltipResolver } from '../TooltipResolver/TooltipResolver';
interface IFavoriteIconButtonProps { interface IFavoriteIconButtonProps extends IconButtonProps {
onClick: (event?: any) => void;
isFavorite: boolean; isFavorite: boolean;
size?: 'medium' | 'large'; size?: 'medium' | 'large';
sx?: SxProps<Theme>;
} }
export const FavoriteIconButton: VFC<IFavoriteIconButtonProps> = ({ export const FavoriteIconButton: VFC<IFavoriteIconButtonProps> = ({
onClick,
isFavorite, isFavorite,
size = 'large', size = 'large',
sx, ...props
}) => { }) => {
return ( return (
<IconButton <TooltipResolver
size={size} title={isFavorite ? 'Remove from favorites' : 'Add to favorites'}
data-loading
sx={{ mr: 1, ...sx }}
onClick={onClick}
> >
<ConditionallyRender <IconButton size={size} data-loading {...props}>
condition={isFavorite} <ConditionallyRender
show={ condition={isFavorite}
<TooltipResolver title={'Remove from favorites'}> show={
<StarIcon <StarIcon
color="primary" color="primary"
sx={{ sx={{
@ -40,10 +34,8 @@ export const FavoriteIconButton: VFC<IFavoriteIconButtonProps> = ({
: theme.spacing(3), : theme.spacing(3),
}} }}
/> />
</TooltipResolver> }
} elseShow={
elseShow={
<TooltipResolver title={'Add to favorites'}>
<StarBorderIcon <StarBorderIcon
sx={{ sx={{
fontSize: theme => fontSize: theme =>
@ -52,9 +44,9 @@ export const FavoriteIconButton: VFC<IFavoriteIconButtonProps> = ({
: theme.spacing(3), : theme.spacing(3),
}} }}
/> />
</TooltipResolver> }
} />
/> </IconButton>
</IconButton> </TooltipResolver>
); );
}; };

View File

@ -13,7 +13,7 @@ const StyledMainHeader = styled(Paper)(({ theme }) => ({
const StyledTitleHeader = styled('div')(({ theme }) => ({ const StyledTitleHeader = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
alignItems: 'flex-start', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
})); }));

View File

@ -4,6 +4,11 @@ export const useStyles = makeStyles()(() => ({
row: { row: {
position: 'absolute', position: 'absolute',
width: '100%', width: '100%',
'&:hover': {
'.show-row-hover': {
display: 'inherit',
},
},
}, },
cell: { cell: {
alignItems: 'center', alignItems: 'center',

View File

@ -5,7 +5,7 @@ import {
StarBorder as StarBorderIcon, StarBorder as StarBorderIcon,
} from '@mui/icons-material'; } from '@mui/icons-material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { TooltipResolver } from '../../../TooltipResolver/TooltipResolver'; import { TooltipResolver } from 'component/common/TooltipResolver/TooltipResolver';
interface IFavoriteIconCellProps { interface IFavoriteIconCellProps {
value?: boolean; value?: boolean;
@ -13,17 +13,15 @@ interface IFavoriteIconCellProps {
} }
const InactiveIconButton = styled(IconButton)(({ theme }) => ({ const InactiveIconButton = styled(IconButton)(({ theme }) => ({
color: 'transparent', color: theme.palette.primary.main,
'&:hover, &:focus': { display: 'none',
color: theme.palette.primary.main,
},
})); }));
export const FavoriteIconCell: VFC<IFavoriteIconCellProps> = ({ export const FavoriteIconCell: VFC<IFavoriteIconCellProps> = ({
value = false, value = false,
onClick, onClick,
}) => ( }) => (
<Box sx={{ pl: 1.25 }}> <Box sx={{ pl: 1.25, display: 'inline-flex' }}>
<ConditionallyRender <ConditionallyRender
condition={value} condition={value}
show={ show={
@ -41,6 +39,7 @@ export const FavoriteIconCell: VFC<IFavoriteIconCellProps> = ({
elseShow={ elseShow={
<TooltipResolver title={'Add to favorites'}> <TooltipResolver title={'Add to favorites'}>
<InactiveIconButton <InactiveIconButton
className="show-row-hover"
onClick={onClick} onClick={onClick}
size="small" size="small"
sx={{ padding: 1.25 }} sx={{ padding: 1.25 }}

View File

@ -1,5 +1,5 @@
import { Tab, Tabs, useMediaQuery } from '@mui/material'; import { Tab, Tabs, useMediaQuery } from '@mui/material';
import React, { useState } from 'react'; import { useState } from 'react';
import { Archive, FileCopy, Label, WatchLater } from '@mui/icons-material'; import { Archive, FileCopy, Label, WatchLater } from '@mui/icons-material';
import { import {
Link, Link,
@ -123,7 +123,6 @@ export const FeatureView = () => {
<FavoriteIconButton <FavoriteIconButton
onClick={onFavorite} onClick={onFavorite}
isFavorite={feature?.favorite} isFavorite={feature?.favorite}
sx={{ pr: 0.25 }}
/> />
)} )}
/> />

View File

@ -48,7 +48,6 @@ export const useStyles = makeStyles()(theme => ({
width: '100%', width: '100%',
fontSize: theme.fontSizes.mainHeader, fontSize: theme.fontSizes.mainHeader,
fontWeight: 'bold', fontWeight: 'bold',
marginBottom: '0.5rem',
display: 'flex', display: 'flex',
justifyContent: 'space-between', justifyContent: 'space-between',
alignItems: 'center', alignItems: 'center',

View File

@ -7,7 +7,7 @@ import { styled, Tab, Tabs } from '@mui/material';
import { Delete, Edit } from '@mui/icons-material'; import { Delete, Edit } from '@mui/icons-material';
import useToast from 'hooks/useToast'; import useToast from 'hooks/useToast';
import useQueryParams from 'hooks/useQueryParams'; import useQueryParams from 'hooks/useQueryParams';
import React, { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import ProjectEnvironment from '../ProjectEnvironment/ProjectEnvironment'; import ProjectEnvironment from '../ProjectEnvironment/ProjectEnvironment';
import { ProjectFeaturesArchive } from './ProjectFeaturesArchive/ProjectFeaturesArchive'; import { ProjectFeaturesArchive } from './ProjectFeaturesArchive/ProjectFeaturesArchive';
import ProjectOverview from './ProjectOverview'; import ProjectOverview from './ProjectOverview';
@ -28,18 +28,18 @@ import { MainLayout } from 'component/layout/MainLayout/MainLayout';
import { ProjectChangeRequests } from '../../changeRequest/ProjectChangeRequests/ProjectChangeRequests'; import { ProjectChangeRequests } from '../../changeRequest/ProjectChangeRequests/ProjectChangeRequests';
import { ProjectSettings } from './ProjectSettings/ProjectSettings'; import { ProjectSettings } from './ProjectSettings/ProjectSettings';
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled'; import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
import { FavoriteIconButton } from '../../common/FavoriteIconButton/FavoriteIconButton'; import { FavoriteIconButton } from 'component/common/FavoriteIconButton/FavoriteIconButton';
import { useFavoriteProjectsApi } from '../../../hooks/api/actions/useFavoriteProjectsApi/useFavoriteProjectsApi'; import { useFavoriteProjectsApi } from 'hooks/api/actions/useFavoriteProjectsApi/useFavoriteProjectsApi';
const StyledDiv = styled('div')(() => ({ const StyledDiv = styled('div')(() => ({
display: 'flex', display: 'flex',
})); }));
const Row = styled('div')(({ theme }) => ({ const StyledTopRow = styled('div')(() => ({
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'center', justifyContent: 'space-between',
paddingBottom: theme.spacing(0.25), width: '100%',
})); }));
const Column = styled('div')(() => ({ const Column = styled('div')(() => ({
@ -47,11 +47,10 @@ const Column = styled('div')(() => ({
flexDirection: 'column', flexDirection: 'column',
})); }));
const StyledName = styled('div')(({ theme }) => ({ const StyledName = styled('div')(() => ({
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
paddingTop: theme.spacing(1),
})); }));
const StyledTitle = styled('span')(({ theme }) => ({ const StyledTitle = styled('span')(({ theme }) => ({
@ -62,6 +61,10 @@ const StyledText = styled(StyledTitle)(({ theme }) => ({
color: theme.palette.grey[800], color: theme.palette.grey[800],
})); }));
const StyledFavoriteIconButton = styled(FavoriteIconButton)(({ theme }) => ({
marginLeft: theme.spacing(-1.5),
}));
const Project = () => { const Project = () => {
const projectId = useRequiredPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const params = useQueryParams(); const params = useQueryParams();
@ -158,21 +161,54 @@ const Project = () => {
> >
<div className={styles.header}> <div className={styles.header}>
<div className={styles.innerContainer}> <div className={styles.innerContainer}>
<Row> <StyledTopRow>
<ConditionallyRender <StyledDiv>
condition={Boolean(uiConfig?.flags?.favorites)} <ConditionallyRender
show={() => ( condition={Boolean(uiConfig?.flags?.favorites)}
<FavoriteIconButton show={() => (
onClick={onFavorite} <StyledFavoriteIconButton
isFavorite={project?.favorite} onClick={onFavorite}
sx={{ pl: 0, pr: 0.25 }} isFavorite={project?.favorite}
/> />
)} )}
/> />
<h2 className={styles.title}> <h2 className={styles.title}>
<StyledName data-loading>{projectName}</StyledName> <StyledName data-loading>
</h2> {projectName}
</Row> </StyledName>
</h2>
</StyledDiv>
<StyledDiv>
<PermissionIconButton
permission={UPDATE_PROJECT}
projectId={projectId}
sx={{
visibility: isOss() ? 'hidden' : 'visible',
}}
onClick={() =>
navigate(`/projects/${projectId}/edit`)
}
tooltipProps={{ title: 'Edit project' }}
data-loading
>
<Edit />
</PermissionIconButton>
<PermissionIconButton
permission={DELETE_PROJECT}
projectId={projectId}
sx={{
visibility: isOss() ? 'hidden' : 'visible',
}}
onClick={() => {
setShowDelDialog(true);
}}
tooltipProps={{ title: 'Delete project' }}
data-loading
>
<Delete />
</PermissionIconButton>
</StyledDiv>
</StyledTopRow>
<Column> <Column>
<h2 className={styles.title}> <h2 className={styles.title}>
<div> <div>
@ -198,40 +234,6 @@ const Project = () => {
</StyledText> </StyledText>
</StyledDiv> </StyledDiv>
</div> </div>
<StyledDiv>
<PermissionIconButton
permission={UPDATE_PROJECT}
projectId={projectId}
sx={{
visibility: isOss()
? 'hidden'
: 'visible',
}}
onClick={() =>
navigate(`/projects/${projectId}/edit`)
}
tooltipProps={{ title: 'Edit project' }}
data-loading
>
<Edit />
</PermissionIconButton>
<PermissionIconButton
permission={DELETE_PROJECT}
projectId={projectId}
sx={{
visibility: isOss()
? 'hidden'
: 'visible',
}}
onClick={() => {
setShowDelDialog(true);
}}
tooltipProps={{ title: 'Delete project' }}
data-loading
>
<Delete />
</PermissionIconButton>
</StyledDiv>
</h2> </h2>
</Column> </Column>
</div> </div>

View File

@ -56,7 +56,7 @@ export const ProjectCard = ({
const canDeleteProject = const canDeleteProject =
hasAccess(DELETE_PROJECT, id) && id !== DEFAULT_PROJECT_ID; hasAccess(DELETE_PROJECT, id) && id !== DEFAULT_PROJECT_ID;
const onFavorite = async (e: Event) => { const onFavorite = async (e: React.SyntheticEvent) => {
e.preventDefault(); e.preventDefault();
if (isFavorite) { if (isFavorite) {
await unfavorite(id); await unfavorite(id);