mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
feat: info about unlimited projects option (#8814)
- refactored projects list header - added info about unlimited projects to open-source version
This commit is contained in:
parent
b7af9b7ec3
commit
01bd877a81
BIN
frontend/src/assets/img/upgradeProjects.png
Normal file
BIN
frontend/src/assets/img/upgradeProjects.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
@ -32,6 +32,7 @@ export const StyledProjectCardBody = styled(Box)(({ theme }) => ({
|
||||
flexFlow: 'column',
|
||||
justifyContent: 'space-between',
|
||||
height: '100%',
|
||||
position: 'relative',
|
||||
}));
|
||||
|
||||
export const StyledDivHeader = styled('div')(({ theme }) => ({
|
||||
|
@ -11,7 +11,7 @@ interface IProjectCardFooterProps {
|
||||
isFavorite?: boolean;
|
||||
children?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
owners: IProjectOwnersProps['owners'];
|
||||
owners?: IProjectOwnersProps['owners'];
|
||||
}
|
||||
|
||||
const StyledFooter = styled(Box)<{ disabled: boolean }>(
|
||||
@ -34,7 +34,7 @@ export const ProjectCardFooter: FC<IProjectCardFooterProps> = ({
|
||||
}) => {
|
||||
return (
|
||||
<StyledFooter disabled={disabled}>
|
||||
<ProjectOwners owners={owners} />
|
||||
{owners ? <ProjectOwners owners={owners} /> : null}
|
||||
{children}
|
||||
</StyledFooter>
|
||||
);
|
||||
|
@ -0,0 +1,110 @@
|
||||
import { IconButton, styled, Tooltip, Typography } from '@mui/material';
|
||||
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { StyledProjectCard, StyledProjectCardBody } from './ProjectCard.styles';
|
||||
import { ProjectCardFooter } from './ProjectCardFooter/ProjectCardFooter';
|
||||
import upgradeProjects from 'assets/img/upgradeProjects.png';
|
||||
import { formatAssetPath } from 'utils/formatPath';
|
||||
import { useLocalStorageState } from 'hooks/useLocalStorageState';
|
||||
|
||||
const StyledFooter = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: theme.spacing(0.5, 1, 0.5, 2),
|
||||
height: 53,
|
||||
}));
|
||||
|
||||
const StyledCloseButton = styled(IconButton)(({ theme }) => ({
|
||||
position: 'absolute',
|
||||
top: theme.spacing(0.75),
|
||||
right: theme.spacing(0.75),
|
||||
}));
|
||||
|
||||
const StyledInfo = styled('a')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
gap: theme.spacing(1),
|
||||
textDecoration: 'none',
|
||||
color: 'inherit',
|
||||
height: '100%',
|
||||
paddingTop: theme.spacing(0.5),
|
||||
}));
|
||||
|
||||
const StyledImage = styled('img')(({ theme }) => ({
|
||||
width: 95,
|
||||
margin: theme.spacing(1),
|
||||
}));
|
||||
|
||||
export const UpgradeProjectCard = () => {
|
||||
const [moreProjectsUpgrade, setMoreProjectsUpgrade] = useLocalStorageState<
|
||||
'open' | 'closed'
|
||||
>('upgrade-projects:v1', 'open');
|
||||
|
||||
if (moreProjectsUpgrade === 'closed') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onDismiss = () => {
|
||||
setMoreProjectsUpgrade('closed');
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledProjectCard>
|
||||
<StyledProjectCardBody>
|
||||
<Tooltip title='Dismiss' arrow>
|
||||
<StyledCloseButton
|
||||
aria-label='dismiss'
|
||||
onClick={onDismiss}
|
||||
size='small'
|
||||
>
|
||||
<CloseIcon fontSize='inherit' />
|
||||
</StyledCloseButton>
|
||||
</Tooltip>
|
||||
<StyledInfo
|
||||
href='https://www.getunleash.io/upgrade-unleash?utm_source=projects'
|
||||
target='_blank'
|
||||
>
|
||||
<Typography component='span' fontWeight='bold'>
|
||||
More{' '}
|
||||
<Typography
|
||||
component='span'
|
||||
color='secondary'
|
||||
fontWeight='bold'
|
||||
>
|
||||
projects
|
||||
</Typography>{' '}
|
||||
–
|
||||
<br />
|
||||
easy collaboration
|
||||
</Typography>
|
||||
<StyledImage
|
||||
src={formatAssetPath(upgradeProjects)}
|
||||
alt='Upgrade projects'
|
||||
/>
|
||||
</StyledInfo>
|
||||
</StyledProjectCardBody>
|
||||
<ProjectCardFooter>
|
||||
<StyledFooter>
|
||||
<Typography
|
||||
variant='body2'
|
||||
color='text.secondary'
|
||||
lineHeight={1.2}
|
||||
>
|
||||
Get unlimited projects, and scale Unleash in your
|
||||
organization
|
||||
</Typography>
|
||||
<IconButton
|
||||
color='primary'
|
||||
href='https://www.getunleash.io/upgrade-unleash?utm_source=projects'
|
||||
target='_blank'
|
||||
>
|
||||
<ArrowForwardIcon />
|
||||
</IconButton>
|
||||
</StyledFooter>
|
||||
</ProjectCardFooter>
|
||||
</StyledProjectCard>
|
||||
);
|
||||
};
|
@ -1,32 +1,14 @@
|
||||
import type { ComponentType, ReactNode } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { ProjectCard as NewProjectCard } from '../ProjectCard/ProjectCard';
|
||||
import { ProjectCard as DefaultProjectCard } from '../ProjectCard/ProjectCard';
|
||||
import type { ProjectSchema } from 'openapi';
|
||||
import loadingData from './loadingData';
|
||||
import { TablePlaceholder } from 'component/common/Table';
|
||||
import { styled, Typography } from '@mui/material';
|
||||
import { styled } from '@mui/material';
|
||||
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||
import { flexColumn } from 'themes/themeStyles';
|
||||
|
||||
const StyledContainer = styled('article')(({ theme }) => ({
|
||||
...flexColumn,
|
||||
gap: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledHeaderContainer = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column-reverse',
|
||||
gap: theme.spacing(2),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledHeaderTitle = styled('div')(() => ({
|
||||
flexGrow: 0,
|
||||
}));
|
||||
import { UpgradeProjectCard } from '../ProjectCard/UpgradeProjectCard';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
|
||||
const StyledGridContainer = styled('div')(({ theme }) => ({
|
||||
display: 'grid',
|
||||
@ -56,41 +38,18 @@ type ProjectGroupProps = {
|
||||
};
|
||||
|
||||
export const ProjectGroup = ({
|
||||
sectionTitle,
|
||||
sectionSubtitle,
|
||||
HeaderActions,
|
||||
projects,
|
||||
loading,
|
||||
placeholder = 'No projects available.',
|
||||
ProjectCardComponent,
|
||||
link = true,
|
||||
}: ProjectGroupProps) => {
|
||||
const ProjectCard = ProjectCardComponent ?? NewProjectCard;
|
||||
const ProjectCard = ProjectCardComponent ?? DefaultProjectCard;
|
||||
const { isOss } = useUiConfig();
|
||||
const { searchQuery } = useSearchHighlightContext();
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledHeaderContainer>
|
||||
<StyledHeaderTitle>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(sectionTitle)}
|
||||
show={
|
||||
<Typography component='h2' variant='h2'>
|
||||
{sectionTitle}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(sectionSubtitle)}
|
||||
show={
|
||||
<Typography variant='body2' color='text.secondary'>
|
||||
{sectionSubtitle}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</StyledHeaderTitle>
|
||||
{HeaderActions}
|
||||
</StyledHeaderContainer>
|
||||
<>
|
||||
<ConditionallyRender
|
||||
condition={projects.length < 1 && !loading}
|
||||
show={
|
||||
@ -157,9 +116,10 @@ export const ProjectGroup = ({
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
{isOss() ? <UpgradeProjectCard /> : null}
|
||||
</StyledGridContainer>
|
||||
}
|
||||
/>
|
||||
</StyledContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -16,6 +16,8 @@ import { ProjectCreationButton } from './ProjectCreationButton/ProjectCreationBu
|
||||
import { useGroupedProjects } from './hooks/useGroupedProjects';
|
||||
import { useProjectsSearchAndSort } from './hooks/useProjectsSearchAndSort';
|
||||
import { ProjectArchiveLink } from './ProjectArchiveLink/ProjectArchiveLink';
|
||||
import { ProjectsListHeader } from './ProjectsListHeader/ProjectsListHeader';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
|
||||
const StyledApiError = styled(ApiError)(({ theme }) => ({
|
||||
maxWidth: '500px',
|
||||
@ -30,6 +32,7 @@ const StyledContainer = styled('div')(({ theme }) => ({
|
||||
|
||||
export const ProjectList = () => {
|
||||
const { projects, loading, error, refetch } = useProjects();
|
||||
const { isOss } = useUiConfig();
|
||||
|
||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
||||
|
||||
@ -63,7 +66,7 @@ export const ProjectList = () => {
|
||||
actions={
|
||||
<>
|
||||
<ConditionallyRender
|
||||
condition={!isSmallScreen}
|
||||
condition={!isOss && !isSmallScreen}
|
||||
show={
|
||||
<>
|
||||
<Search
|
||||
@ -88,7 +91,7 @@ export const ProjectList = () => {
|
||||
}
|
||||
>
|
||||
<ConditionallyRender
|
||||
condition={isSmallScreen}
|
||||
condition={!isOss() && isSmallScreen}
|
||||
show={
|
||||
<Search
|
||||
initialValue={state.query || ''}
|
||||
@ -110,29 +113,42 @@ export const ProjectList = () => {
|
||||
)}
|
||||
/>
|
||||
<SearchHighlightProvider value={state.query || ''}>
|
||||
<ProjectGroup
|
||||
sectionTitle='My projects'
|
||||
sectionSubtitle='Favorite projects, projects you own, and projects you are a member of'
|
||||
HeaderActions={
|
||||
<ProjectsListSort
|
||||
sortBy={state.sortBy}
|
||||
setSortBy={(sortBy) =>
|
||||
setState({
|
||||
sortBy: sortBy as typeof state.sortBy,
|
||||
})
|
||||
}
|
||||
<div>
|
||||
<ProjectsListHeader
|
||||
subtitle='Favorite projects, projects you own, and projects you are a member of'
|
||||
actions={
|
||||
<ProjectsListSort
|
||||
sortBy={state.sortBy}
|
||||
setSortBy={(sortBy) =>
|
||||
setState({
|
||||
sortBy: sortBy as typeof state.sortBy,
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
My projects
|
||||
</ProjectsListHeader>
|
||||
<ProjectGroup
|
||||
loading={loading}
|
||||
projects={
|
||||
isOss()
|
||||
? sortedProjects
|
||||
: groupedProjects.myProjects
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{!isOss() ? (
|
||||
<div>
|
||||
<ProjectsListHeader subtitle='Projects in Unleash that you have access to.'>
|
||||
Other projects
|
||||
</ProjectsListHeader>
|
||||
<ProjectGroup
|
||||
loading={loading}
|
||||
projects={groupedProjects.otherProjects}
|
||||
/>
|
||||
}
|
||||
loading={loading}
|
||||
projects={groupedProjects.myProjects}
|
||||
/>
|
||||
|
||||
<ProjectGroup
|
||||
sectionTitle='Other projects'
|
||||
sectionSubtitle='Projects in Unleash that you have access to.'
|
||||
loading={loading}
|
||||
projects={groupedProjects.otherProjects}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</SearchHighlightProvider>
|
||||
</StyledContainer>
|
||||
</PageContent>
|
||||
|
@ -0,0 +1,47 @@
|
||||
import { styled, Typography } from '@mui/material';
|
||||
import type { FC, ReactNode } from 'react';
|
||||
|
||||
type ProjectsListHeaderProps = {
|
||||
children?: ReactNode;
|
||||
subtitle?: string;
|
||||
actions?: ReactNode;
|
||||
};
|
||||
|
||||
const StyledHeaderContainer = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column-reverse',
|
||||
gap: theme.spacing(2),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
marginBottom: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledHeaderTitle = styled('div')(() => ({
|
||||
flexGrow: 0,
|
||||
}));
|
||||
|
||||
export const ProjectsListHeader: FC<ProjectsListHeaderProps> = ({
|
||||
children,
|
||||
subtitle,
|
||||
actions,
|
||||
}) => {
|
||||
return (
|
||||
<StyledHeaderContainer>
|
||||
<StyledHeaderTitle>
|
||||
{children ? (
|
||||
<Typography component='h2' variant='h2'>
|
||||
{children}
|
||||
</Typography>
|
||||
) : null}
|
||||
{subtitle ? (
|
||||
<Typography variant='body2' color='text.secondary'>
|
||||
{subtitle}
|
||||
</Typography>
|
||||
) : null}
|
||||
</StyledHeaderTitle>
|
||||
{actions}
|
||||
</StyledHeaderContainer>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user