1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-27 00:19:39 +01:00

fix: use the first project if there's no default project (#859)

* refactor: extract FeatureToggleListCreate component

* fix: use the first project if there's no default project
This commit is contained in:
olav 2022-04-07 11:08:05 +02:00 committed by GitHub
parent f33ca9db4b
commit fb8d0e7efc
6 changed files with 120 additions and 119 deletions

View File

@ -0,0 +1,57 @@
import classnames from 'classnames';
import { Link } from 'react-router-dom';
import { Button, IconButton, Tooltip } from '@material-ui/core';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import { Add } from '@material-ui/icons';
import ConditionallyRender from 'component/common/ConditionallyRender/ConditionallyRender';
import { NAVIGATE_TO_CREATE_FEATURE } from 'utils/testIds';
import { IFeaturesFilter } from 'hooks/useFeaturesFilter';
import { useCreateFeaturePath } from 'component/feature/CreateFeatureButton/useCreateFeaturePath';
interface ICreateFeatureButtonProps {
loading: boolean;
filter: IFeaturesFilter;
}
export const CreateFeatureButton = ({
loading,
filter,
}: ICreateFeatureButtonProps) => {
const smallScreen = useMediaQuery('(max-width:800px)');
const createFeature = useCreateFeaturePath(filter);
if (!createFeature) {
return null;
}
return (
<ConditionallyRender
condition={smallScreen}
show={
<Tooltip title="Create feature toggle">
<IconButton
component={Link}
to={createFeature.path}
data-test={NAVIGATE_TO_CREATE_FEATURE}
disabled={!createFeature.access}
>
<Add titleAccess="New" />
</IconButton>
</Tooltip>
}
elseShow={
<Button
to={createFeature.path}
color="primary"
variant="contained"
component={Link}
data-test={NAVIGATE_TO_CREATE_FEATURE}
disabled={!createFeature.access}
className={classnames({ skeleton: loading })}
>
New feature toggle
</Button>
}
/>
);
};

View File

@ -0,0 +1,34 @@
import { useDefaultProjectId } from 'hooks/api/getters/useDefaultProject/useDefaultProjectId';
import { IFeaturesFilter } from 'hooks/useFeaturesFilter';
import { getCreateTogglePath } from 'utils/routePathHelpers';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import AccessContext from 'contexts/AccessContext';
import { useContext } from 'react';
interface IUseCreateFeaturePathOutput {
path: string;
access: boolean;
}
export const useCreateFeaturePath = (
filter: IFeaturesFilter
): IUseCreateFeaturePathOutput | undefined => {
const { hasAccess } = useContext(AccessContext);
const defaultProjectId = useDefaultProjectId();
const { uiConfig } = useUiConfig();
const selectedProjectId =
filter.project === '*' || !filter.project
? defaultProjectId
: filter.project;
if (!selectedProjectId) {
return;
}
return {
path: getCreateTogglePath(selectedProjectId, uiConfig.flags.E),
access: hasAccess(CREATE_FEATURE, selectedProjectId),
};
};

View File

@ -2,9 +2,8 @@ import { useContext } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Link } from 'react-router-dom';
import { Button, IconButton, List, ListItem, Tooltip } from '@material-ui/core';
import { List, ListItem } from '@material-ui/core';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import { Add } from '@material-ui/icons';
import FeatureToggleListItem from './FeatureToggleListItem';
import { SearchField } from 'component/common/SearchField/SearchField';
import FeatureToggleListActions from './FeatureToggleListActions';
@ -12,13 +11,11 @@ import ConditionallyRender from 'component/common/ConditionallyRender/Conditiona
import PageContent from 'component/common/PageContent/PageContent';
import HeaderTitle from 'component/common/HeaderTitle';
import loadingFeatures from './loadingFeatures';
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
import AccessContext from 'contexts/AccessContext';
import { useStyles } from './styles';
import ListPlaceholder from 'component/common/ListPlaceholder/ListPlaceholder';
import { getCreateTogglePath } from 'utils/routePathHelpers';
import { NAVIGATE_TO_CREATE_FEATURE } from 'utils/testIds';
import { resolveFilteredProjectId } from 'hooks/useFeaturesFilter';
import { CreateFeatureButton } from '../CreateFeatureButton/CreateFeatureButton';
import { useCreateFeaturePath } from '../CreateFeatureButton/useCreateFeaturePath';
const FeatureToggleList = ({
features,
@ -32,6 +29,7 @@ const FeatureToggleList = ({
setSort,
}) => {
const { hasAccess } = useContext(AccessContext);
const createFeature = useCreateFeaturePath(filter);
const styles = useStyles();
const smallScreen = useMediaQuery('(max-width:800px)');
const mobileView = useMediaQuery('(max-width:600px)');
@ -41,9 +39,6 @@ const FeatureToggleList = ({
setFilter(prev => ({ ...prev, query }));
};
const resolvedProjectId = resolveFilteredProjectId(filter);
const createURL = getCreateTogglePath(resolvedProjectId, flags.E);
const renderFeatures = () => {
features.forEach(e => {
e.reviveName = e.name;
@ -83,11 +78,15 @@ const FeatureToggleList = ({
</ListItem>
}
elseShow={
<ListPlaceholder
text="No features available. Get started by adding a
new feature toggle."
link={createURL}
linkText="Add your first toggle"
<ConditionallyRender
condition={Boolean(createFeature?.access)}
show={() => (
<ListPlaceholder
text="No features available. Get started by adding a new feature toggle."
link={createFeature.path}
linkText="Add your first toggle"
/>
)}
/>
}
/>
@ -143,49 +142,9 @@ const FeatureToggleList = ({
<ConditionallyRender
condition={!archive}
show={
<ConditionallyRender
condition={smallScreen}
show={
<Tooltip title="Create feature toggle">
<IconButton
component={Link}
to={createURL}
data-test={
NAVIGATE_TO_CREATE_FEATURE
}
disabled={
!hasAccess(
CREATE_FEATURE,
resolvedProjectId
)
}
>
<Add />
</IconButton>
</Tooltip>
}
elseShow={
<Button
to={createURL}
color="primary"
variant="contained"
component={Link}
data-test={
NAVIGATE_TO_CREATE_FEATURE
}
disabled={
!hasAccess(
CREATE_FEATURE,
resolvedProjectId
)
}
className={classnames({
skeleton: loading,
})}
>
New feature toggle
</Button>
}
<CreateFeatureButton
filter={filter}
loading={loading}
/>
}
/>

View File

@ -142,32 +142,6 @@ exports[`renders correctly with one feature 1`] = `
</span>
</button>
</div>
<a
aria-disabled={true}
className="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary Mui-disabled Mui-disabled"
data-test="NAVIGATE_TO_CREATE_FEATURE"
href="/projects/default/create-toggle"
onBlur={[Function]}
onClick={[Function]}
onDragLeave={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onMouseLeave={[Function]}
onMouseUp={[Function]}
onTouchEnd={[Function]}
onTouchMove={[Function]}
onTouchStart={[Function]}
role="button"
tabIndex={-1}
>
<span
className="MuiButton-label"
>
New feature toggle
</span>
</a>
</div>
</div>
</div>
@ -339,32 +313,6 @@ exports[`renders correctly with one feature without permissions 1`] = `
/>
</button>
</div>
<a
aria-disabled={true}
className="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary Mui-disabled Mui-disabled"
data-test="NAVIGATE_TO_CREATE_FEATURE"
href="/projects/default/create-toggle"
onBlur={[Function]}
onClick={[Function]}
onDragLeave={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onMouseLeave={[Function]}
onMouseUp={[Function]}
onTouchEnd={[Function]}
onTouchMove={[Function]}
onTouchStart={[Function]}
role="button"
tabIndex={-1}
>
<span
className="MuiButton-label"
>
New feature toggle
</span>
</a>
</div>
</div>
</div>

View File

@ -0,0 +1,13 @@
import useProjects from 'hooks/api/getters/useProjects/useProjects';
const DEFAULT_PROJECT_ID = 'default';
export const useDefaultProjectId = (): string | undefined => {
const { projects = [] } = useProjects();
const defaultProject = projects.find(project => {
return project.id === DEFAULT_PROJECT_ID;
});
return defaultProject?.id || projects[0]?.id;
};

View File

@ -36,16 +36,6 @@ export const useFeaturesFilter = (
};
};
// Return the current project ID a project has been selected,
// or the 'default' project if showing all projects.
export const resolveFilteredProjectId = (filter: IFeaturesFilter): string => {
if (!filter.project || filter.project === '*') {
return 'default';
}
return filter.project;
};
const filterFeatures = (
features: IFeatureToggle[],
filter: IFeaturesFilter