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:
parent
f33ca9db4b
commit
fb8d0e7efc
@ -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>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
@ -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),
|
||||
};
|
||||
};
|
@ -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}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
};
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user