diff --git a/frontend/src/component/feature/CreateFeatureButton/CreateFeatureButton.tsx b/frontend/src/component/feature/CreateFeatureButton/CreateFeatureButton.tsx new file mode 100644 index 0000000000..a177e96fae --- /dev/null +++ b/frontend/src/component/feature/CreateFeatureButton/CreateFeatureButton.tsx @@ -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 ( + + + + + + } + elseShow={ + + } + /> + ); +}; diff --git a/frontend/src/component/feature/CreateFeatureButton/useCreateFeaturePath.ts b/frontend/src/component/feature/CreateFeatureButton/useCreateFeaturePath.ts new file mode 100644 index 0000000000..7a5b571eb8 --- /dev/null +++ b/frontend/src/component/feature/CreateFeatureButton/useCreateFeaturePath.ts @@ -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), + }; +}; diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleList.jsx b/frontend/src/component/feature/FeatureToggleList/FeatureToggleList.jsx index f4c0707e28..92857f3916 100644 --- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleList.jsx +++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleList.jsx @@ -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 = ({ } elseShow={ - ( + + )} /> } /> @@ -143,49 +142,9 @@ const FeatureToggleList = ({ - - - - - } - elseShow={ - - } + } /> diff --git a/frontend/src/component/feature/FeatureToggleList/__snapshots__/FeatureToggleList.test.jsx.snap b/frontend/src/component/feature/FeatureToggleList/__snapshots__/FeatureToggleList.test.jsx.snap index e365ef90c2..693175c21b 100644 --- a/frontend/src/component/feature/FeatureToggleList/__snapshots__/FeatureToggleList.test.jsx.snap +++ b/frontend/src/component/feature/FeatureToggleList/__snapshots__/FeatureToggleList.test.jsx.snap @@ -142,32 +142,6 @@ exports[`renders correctly with one feature 1`] = ` - - - New feature toggle - - @@ -339,32 +313,6 @@ exports[`renders correctly with one feature without permissions 1`] = ` /> - - - New feature toggle - - diff --git a/frontend/src/hooks/api/getters/useDefaultProject/useDefaultProjectId.ts b/frontend/src/hooks/api/getters/useDefaultProject/useDefaultProjectId.ts new file mode 100644 index 0000000000..1a5542f178 --- /dev/null +++ b/frontend/src/hooks/api/getters/useDefaultProject/useDefaultProjectId.ts @@ -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; +}; diff --git a/frontend/src/hooks/useFeaturesFilter.ts b/frontend/src/hooks/useFeaturesFilter.ts index 82114b75de..a2afed09db 100644 --- a/frontend/src/hooks/useFeaturesFilter.ts +++ b/frontend/src/hooks/useFeaturesFilter.ts @@ -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