Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: info about unlimited projects option #8814

Merged
merged 1 commit into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added frontend/src/assets/img/upgradeProjects.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>(
Expand All @@ -34,7 +34,7 @@ export const ProjectCardFooter: FC<IProjectCardFooterProps> = ({
}) => {
return (
<StyledFooter disabled={disabled}>
<ProjectOwners owners={owners} />
{owners ? <ProjectOwners owners={owners} /> : null}
{children}
</StyledFooter>
);
Expand Down
110 changes: 110 additions & 0 deletions frontend/src/component/project/ProjectCard/UpgradeProjectCard.tsx
Original file line number Diff line number Diff line change
@@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what unit is it?

}));

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>
);
};
58 changes: 9 additions & 49 deletions frontend/src/component/project/ProjectList/ProjectGroup.tsx
Original file line number Diff line number Diff line change
@@ -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',
Expand Down Expand Up @@ -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={
Expand Down Expand Up @@ -157,9 +116,10 @@ export const ProjectGroup = ({
</>
)}
/>
{isOss() ? <UpgradeProjectCard /> : null}
</StyledGridContainer>
}
/>
</StyledContainer>
</>
);
};
64 changes: 40 additions & 24 deletions frontend/src/component/project/ProjectList/ProjectList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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'));

Expand Down Expand Up @@ -63,7 +66,7 @@ export const ProjectList = () => {
actions={
<>
<ConditionallyRender
condition={!isSmallScreen}
condition={!isOss && !isSmallScreen}
show={
<>
<Search
Expand All @@ -88,7 +91,7 @@ export const ProjectList = () => {
}
>
<ConditionallyRender
condition={isSmallScreen}
condition={!isOss() && isSmallScreen}
show={
<Search
initialValue={state.query || ''}
Expand All @@ -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>
Expand Down
Original file line number Diff line number Diff line change
@@ -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