mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-01 13:47:27 +02:00
chore: make project list table take less horizontal space (#10480)
https://linear.app/unleash/issue/2-3761/address-ux-feedback-make-table-take-less-horizontal-space-to-prevent Addresses UX feedback by making the project list table take less horizontal space. This should prevent us from having to scroll horizontally in most cases. <img width="1103" height="647" alt="image" src="https://github.com/user-attachments/assets/e5cc22a2-5eda-4cb5-a226-c54993c019ce" />
This commit is contained in:
parent
60a2fa675b
commit
937cba4c1a
@ -10,15 +10,21 @@ import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
|
|||||||
|
|
||||||
type ProjectLastSeenProps = {
|
type ProjectLastSeenProps = {
|
||||||
date?: Date | number | string | null;
|
date?: Date | number | string | null;
|
||||||
|
hideLabel?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledContainer = styled(Box)(({ theme }) => ({
|
const StyledContainer = styled(Box, {
|
||||||
|
shouldForwardProp: (prop) => prop !== 'secondary',
|
||||||
|
})<{ secondary?: boolean }>(({ theme, secondary }) => ({
|
||||||
...flexRow,
|
...flexRow,
|
||||||
justifyContent: 'flex-start',
|
justifyContent: 'flex-start',
|
||||||
textWrap: 'nowrap',
|
textWrap: 'nowrap',
|
||||||
width: '50%',
|
width: '50%',
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
cursor: 'default',
|
cursor: 'default',
|
||||||
|
color: secondary
|
||||||
|
? theme.palette.text.secondary
|
||||||
|
: theme.palette.text.primary,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledIcon = styled(StyledIconWrapper)<{ background: string }>(
|
const StyledIcon = styled(StyledIconWrapper)<{ background: string }>(
|
||||||
@ -28,13 +34,18 @@ const StyledIcon = styled(StyledIconWrapper)<{ background: string }>(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const Title = () => (
|
const Title = ({ date }: Pick<ProjectLastSeenProps, 'date'>) => (
|
||||||
<>
|
<>
|
||||||
<Typography
|
<Typography
|
||||||
component='span'
|
component='span'
|
||||||
sx={(theme) => ({ fontSize: theme.fontSizes.smallBody })}
|
sx={(theme) => ({ fontSize: theme.fontSizes.smallBody })}
|
||||||
>
|
>
|
||||||
Last usage reported
|
Last usage reported:{' '}
|
||||||
|
{date ? (
|
||||||
|
<TimeAgo date={date} refresh={false} />
|
||||||
|
) : (
|
||||||
|
<span>No activity</span>
|
||||||
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography
|
<Typography
|
||||||
sx={(theme) => ({
|
sx={(theme) => ({
|
||||||
@ -48,32 +59,29 @@ const Title = () => (
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const ProjectLastSeen: FC<ProjectLastSeenProps> = ({ date }) => {
|
export const ProjectLastSeen: FC<ProjectLastSeenProps> = ({
|
||||||
|
date,
|
||||||
|
hideLabel,
|
||||||
|
}) => {
|
||||||
const getColor = useLastSeenColors();
|
const getColor = useLastSeenColors();
|
||||||
const { text, background } = getColor(date);
|
const { text, background } = getColor(date);
|
||||||
|
|
||||||
if (!date) {
|
|
||||||
return (
|
|
||||||
<HtmlTooltip title={<Title />} arrow>
|
|
||||||
<StyledContainer
|
|
||||||
sx={(theme) => ({ color: theme.palette.text.secondary })}
|
|
||||||
>
|
|
||||||
<StyledIcon background={background}>
|
|
||||||
<UsageLine stroke={text} />
|
|
||||||
</StyledIcon>{' '}
|
|
||||||
<div>No activity</div>
|
|
||||||
</StyledContainer>
|
|
||||||
</HtmlTooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HtmlTooltip title={<Title />} arrow>
|
<HtmlTooltip title={<Title date={date} />} arrow>
|
||||||
<StyledContainer>
|
<StyledContainer secondary={!date}>
|
||||||
<StyledIcon background={background}>
|
<StyledIcon background={background}>
|
||||||
<UsageRate stroke={text} />
|
{date ? (
|
||||||
|
<UsageRate stroke={text} />
|
||||||
|
) : (
|
||||||
|
<UsageLine stroke={text} />
|
||||||
|
)}
|
||||||
</StyledIcon>{' '}
|
</StyledIcon>{' '}
|
||||||
<TimeAgo date={date} refresh={false} />
|
{!hideLabel &&
|
||||||
|
(date ? (
|
||||||
|
<TimeAgo date={date} refresh={false} />
|
||||||
|
) : (
|
||||||
|
<div>No activity</div>
|
||||||
|
))}
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</HtmlTooltip>
|
</HtmlTooltip>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
import { styled } from '@mui/material';
|
||||||
|
import { ProjectLastSeen } from 'component/project/ProjectCard/ProjectLastSeen/ProjectLastSeen';
|
||||||
|
|
||||||
|
const StyledContainer = styled('div', {
|
||||||
|
shouldForwardProp: (prop) => prop !== 'hideLabel',
|
||||||
|
})<{ hideLabel?: boolean }>(({ theme, hideLabel }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: hideLabel ? 'center' : 'start',
|
||||||
|
padding: theme.spacing(1, 2),
|
||||||
|
}));
|
||||||
|
|
||||||
|
type ProjectListTableLastSeenCellProps = {
|
||||||
|
value?: Date | number | string | null;
|
||||||
|
hideLabel?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ProjectListTableLastSeenCell = ({
|
||||||
|
value,
|
||||||
|
hideLabel,
|
||||||
|
}: ProjectListTableLastSeenCellProps) => (
|
||||||
|
<StyledContainer hideLabel={hideLabel}>
|
||||||
|
<ProjectLastSeen date={value} hideLabel={hideLabel} />
|
||||||
|
</StyledContainer>
|
||||||
|
);
|
@ -4,14 +4,16 @@ import { HighlightCell } from 'component/common/Table/cells/HighlightCell/Highli
|
|||||||
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
||||||
import { TimeAgoCell } from 'component/common/Table/cells/TimeAgoCell/TimeAgoCell';
|
import { TimeAgoCell } from 'component/common/Table/cells/TimeAgoCell/TimeAgoCell';
|
||||||
import { ProjectOwners } from 'component/project/ProjectCard/ProjectCardFooter/ProjectOwners/ProjectOwners';
|
import { ProjectOwners } from 'component/project/ProjectCard/ProjectCardFooter/ProjectOwners/ProjectOwners';
|
||||||
import { ProjectLastSeen } from 'component/project/ProjectCard/ProjectLastSeen/ProjectLastSeen';
|
|
||||||
import { useFavoriteProjectsApi } from 'hooks/api/actions/useFavoriteProjectsApi/useFavoriteProjectsApi';
|
import { useFavoriteProjectsApi } from 'hooks/api/actions/useFavoriteProjectsApi/useFavoriteProjectsApi';
|
||||||
import useProjects from 'hooks/api/getters/useProjects/useProjects';
|
import useProjects from 'hooks/api/getters/useProjects/useProjects';
|
||||||
import type { ProjectSchema, ProjectSchemaOwners } from 'openapi';
|
import type { ProjectSchema, ProjectSchemaOwners } from 'openapi';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useFlexLayout, useTable } from 'react-table';
|
import { useFlexLayout, useTable } from 'react-table';
|
||||||
import { formatDateYMDHMS } from 'utils/formatDate';
|
import { formatDateYMDHMS } from 'utils/formatDate';
|
||||||
import { ProjectsListTableProjectName } from './ProjectsListTableProjectName.tsx';
|
import { ProjectsListTableNameCell } from './ProjectsListTableNameCell.tsx';
|
||||||
|
import { useMediaQuery } from '@mui/material';
|
||||||
|
import theme from 'themes/theme.ts';
|
||||||
|
import { ProjectListTableLastSeenCell } from './ProjectListTableLastSeenCell.tsx';
|
||||||
|
|
||||||
type ProjectsListTableProps = {
|
type ProjectsListTableProps = {
|
||||||
projects: ProjectSchema[];
|
projects: ProjectSchema[];
|
||||||
@ -20,6 +22,7 @@ type ProjectsListTableProps = {
|
|||||||
export const ProjectsListTable = ({ projects }: ProjectsListTableProps) => {
|
export const ProjectsListTable = ({ projects }: ProjectsListTableProps) => {
|
||||||
const { refetch } = useProjects();
|
const { refetch } = useProjects();
|
||||||
const { favorite, unfavorite } = useFavoriteProjectsApi();
|
const { favorite, unfavorite } = useFavoriteProjectsApi();
|
||||||
|
const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg'));
|
||||||
|
|
||||||
const onFavorite = useCallback(
|
const onFavorite = useCallback(
|
||||||
async (project: ProjectSchema) => {
|
async (project: ProjectSchema) => {
|
||||||
@ -51,7 +54,7 @@ export const ProjectsListTable = ({ projects }: ProjectsListTableProps) => {
|
|||||||
accessor: 'name',
|
accessor: 'name',
|
||||||
minWidth: 200,
|
minWidth: 200,
|
||||||
searchable: true,
|
searchable: true,
|
||||||
Cell: ProjectsListTableProjectName,
|
Cell: ProjectsListTableNameCell,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Last updated',
|
Header: 'Last updated',
|
||||||
@ -64,15 +67,17 @@ export const ProjectsListTable = ({ projects }: ProjectsListTableProps) => {
|
|||||||
dateFormat={formatDateYMDHMS}
|
dateFormat={formatDateYMDHMS}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
width: 150,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Number of flags',
|
Header: 'Flags',
|
||||||
accessor: 'featureCount',
|
accessor: 'featureCount',
|
||||||
Cell: ({ value }: { value: number }) => (
|
Cell: ({ value }: { value: number }) => (
|
||||||
<TextCell>
|
<TextCell>
|
||||||
{value} flag{value === 1 ? '' : 's'}
|
{value} flag{value === 1 ? '' : 's'}
|
||||||
</TextCell>
|
</TextCell>
|
||||||
),
|
),
|
||||||
|
width: 90,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Health',
|
Header: 'Health',
|
||||||
@ -80,24 +85,30 @@ export const ProjectsListTable = ({ projects }: ProjectsListTableProps) => {
|
|||||||
Cell: ({ value }: { value: number }) => (
|
Cell: ({ value }: { value: number }) => (
|
||||||
<TextCell>{value}%</TextCell>
|
<TextCell>{value}%</TextCell>
|
||||||
),
|
),
|
||||||
width: 100,
|
width: 70,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Last seen',
|
Header: 'Last seen',
|
||||||
accessor: 'lastReportedFlagUsage',
|
accessor: 'lastReportedFlagUsage',
|
||||||
Cell: ({ value }: { value: Date }) => (
|
Cell: ({ value }: { value: Date }) => (
|
||||||
<ProjectLastSeen date={value} />
|
<ProjectListTableLastSeenCell
|
||||||
|
value={value}
|
||||||
|
hideLabel={isMediumScreen}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
|
width: isMediumScreen ? 100 : 140,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Owner',
|
Header: 'Owner',
|
||||||
accessor: 'owners',
|
accessor: 'owners',
|
||||||
Cell: ({ value }: { value: ProjectSchemaOwners }) => (
|
Cell: ({ value }: { value: ProjectSchemaOwners }) => (
|
||||||
<ProjectOwners
|
<TextCell>
|
||||||
owners={value?.filter(
|
<ProjectOwners
|
||||||
(owner) => owner.ownerType !== 'system',
|
owners={value?.filter(
|
||||||
)}
|
(owner) => owner.ownerType !== 'system',
|
||||||
/>
|
)}
|
||||||
|
/>
|
||||||
|
</TextCell>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -106,6 +117,7 @@ export const ProjectsListTable = ({ projects }: ProjectsListTableProps) => {
|
|||||||
Cell: ({ value }: { value: number }) => (
|
Cell: ({ value }: { value: number }) => (
|
||||||
<TextCell>{value} members</TextCell>
|
<TextCell>{value} members</TextCell>
|
||||||
),
|
),
|
||||||
|
width: 120,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[onFavorite],
|
[onFavorite],
|
||||||
|
@ -20,15 +20,15 @@ const StyledFeatureLink = styled(Link)({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
type ProjectsListTableProjectNameProps = {
|
type ProjectsListTableNameCellProps = {
|
||||||
row: {
|
row: {
|
||||||
original: ProjectSchema;
|
original: ProjectSchema;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ProjectsListTableProjectName = ({
|
export const ProjectsListTableNameCell = ({
|
||||||
row,
|
row,
|
||||||
}: ProjectsListTableProjectNameProps) => {
|
}: ProjectsListTableNameCellProps) => {
|
||||||
const { searchQuery } = useSearchHighlightContext();
|
const { searchQuery } = useSearchHighlightContext();
|
||||||
|
|
||||||
return (
|
return (
|
Loading…
Reference in New Issue
Block a user