1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-10 01:16:39 +02:00

feat: show and hide environments (#9323)

- Button to show and hide environments
- Refactored hook storing state of hidden environments
- Changed the way flag is triggered for feature overview
- Visual updates for new page look

---------

Co-authored-by: Thomas Heartman <thomas@getunleash.io>
This commit is contained in:
Tymoteusz Czech 2025-02-19 10:48:07 +01:00 committed by GitHub
parent c16f7208a1
commit 2a6487e7e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 394 additions and 223 deletions

View File

@ -1,5 +1,4 @@
import NewFeatureOverviewMetaData from './FeatureOverviewMetaData/FeatureOverviewMetaData';
import FeatureOverviewEnvironments from './FeatureOverviewEnvironments/FeatureOverviewEnvironments';
import FeatureOverviewMetaData from './FeatureOverviewMetaData/FeatureOverviewMetaData';
import { Route, Routes, useNavigate } from 'react-router-dom';
import { SidebarModal } from 'component/common/SidebarModal/SidebarModal';
import {
@ -8,21 +7,20 @@ import {
} from 'component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { usePageTitle } from 'hooks/usePageTitle';
import { FeatureOverviewSidePanel as NewFeatureOverviewSidePanel } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanel';
import { useHiddenEnvironments } from 'hooks/useHiddenEnvironments';
import { styled } from '@mui/material';
import { FeatureStrategyCreate } from 'component/feature/FeatureStrategy/FeatureStrategyCreate/FeatureStrategyCreate';
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import { useLastViewedFlags } from 'hooks/useLastViewedFlags';
import { useUiFlag } from 'hooks/useUiFlag';
import OldFeatureOverviewMetaData from './FeatureOverviewMetaData/OldFeatureOverviewMetaData';
import { OldFeatureOverviewSidePanel } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/OldFeatureOverviewSidePanel';
import { NewFeatureOverviewEnvironment } from './NewFeatureOverviewEnvironment/NewFeatureOverviewEnvironment';
import { FeatureOverviewEnvironment } from './NewFeatureOverviewEnvironment/NewFeatureOverviewEnvironment';
import { default as LegacyFleatureOverview } from './LegacyFeatureOverview';
import { useEnvironmentVisibility } from './FeatureOverviewMetaData/EnvironmentVisibilityMenu/hooks/useEnvironmentVisibility';
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
width: '100%',
[theme.breakpoints.down(1000)]: {
gap: theme.spacing(2),
[theme.breakpoints.down('md')]: {
flexDirection: 'column',
},
}));
@ -30,57 +28,43 @@ const StyledContainer = styled('div')(({ theme }) => ({
const StyledMainContent = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
width: `calc(100% - (350px + 1rem))`,
[theme.breakpoints.down(1000)]: {
width: '100%',
},
flexGrow: 1,
gap: theme.spacing(2),
}));
const FeatureOverview = () => {
export const FeatureOverview = () => {
const navigate = useNavigate();
const projectId = useRequiredPathParam('projectId');
const featureId = useRequiredPathParam('featureId');
const featurePath = formatFeaturePath(projectId, featureId);
const { hiddenEnvironments, setHiddenEnvironments } =
useHiddenEnvironments();
const { hiddenEnvironments, onEnvironmentVisibilityChange } =
useEnvironmentVisibility();
const onSidebarClose = () => navigate(featurePath);
usePageTitle(featureId);
const { setLastViewed } = useLastViewedFlags();
useEffect(() => {
setLastViewed({ featureId, projectId });
}, [featureId]);
const [environmentId, setEnvironmentId] = useState('');
const flagOverviewRedesign = useUiFlag('flagOverviewRedesign');
if (!flagOverviewRedesign) {
return <LegacyFleatureOverview />;
}
return (
<StyledContainer>
<div>
{flagOverviewRedesign ? (
<>
<NewFeatureOverviewMetaData />
<NewFeatureOverviewSidePanel
environmentId={environmentId}
setEnvironmentId={setEnvironmentId}
/>
</>
) : (
<>
<OldFeatureOverviewMetaData />
<OldFeatureOverviewSidePanel
hiddenEnvironments={hiddenEnvironments}
setHiddenEnvironments={setHiddenEnvironments}
/>
</>
)}
<FeatureOverviewMetaData
hiddenEnvironments={hiddenEnvironments}
onEnvironmentVisibilityChange={
onEnvironmentVisibilityChange
}
/>
</div>
<StyledMainContent>
{flagOverviewRedesign ? (
<NewFeatureOverviewEnvironment
environmentId={environmentId}
/>
) : (
<FeatureOverviewEnvironments />
)}
<FeatureOverviewEnvironment
hiddenEnvironments={hiddenEnvironments}
/>
</StyledMainContent>
<Routes>
<Route
@ -111,5 +95,3 @@ const FeatureOverview = () => {
</StyledContainer>
);
};
export default FeatureOverview;

View File

@ -29,6 +29,7 @@ export const AddTagButton: FC<AddTagButtonProps> = ({ project, onClick }) => (
variant='text'
onClick={onClick}
startIcon={<StyledAddIcon />}
data-loading
>
Add tag
</StyledAddTagButton>

View File

@ -0,0 +1,69 @@
import { Button, Checkbox, Menu, MenuItem, styled } from '@mui/material';
import { useState, type FC } from 'react';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
type EnvironmentVisibilityMenuProps = {
environments: Array<{ name: string }>;
hiddenEnvironments: string[];
onChange: (name: string) => void;
};
const buttonId = 'environment-visibility-button';
const menuId = 'environment-visibility-menu';
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
justifyContent: 'center',
paddingTop: theme.spacing(4),
}));
export const EnvironmentVisibilityMenu: FC<EnvironmentVisibilityMenuProps> = ({
environments,
hiddenEnvironments,
onChange,
}) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const isOpen = Boolean(anchorEl);
const handleOpen = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<StyledContainer>
<Button
onClick={handleOpen}
endIcon={isOpen ? <ExpandLessIcon /> : <ExpandMoreIcon />}
variant='outlined'
id={buttonId}
aria-controls={isOpen ? menuId : undefined}
aria-haspopup='true'
aria-expanded={isOpen ? 'true' : undefined}
data-loading
>
Hide/show environments
</Button>
<Menu
id={menuId}
anchorEl={anchorEl}
open={isOpen}
onClose={handleClose}
MenuListProps={{ 'aria-labelledby': buttonId }}
>
{environments.map(({ name }) => (
<MenuItem key={name} onClick={() => onChange(name)}>
<Checkbox
onChange={() => onChange(name)}
checked={!hiddenEnvironments?.includes(name)}
/>
{name}
</MenuItem>
))}
</Menu>
</StyledContainer>
);
};

View File

@ -0,0 +1,39 @@
import { useLocalStorageState } from 'hooks/useLocalStorageState';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { createLocalStorage } from 'utils/createLocalStorage';
// Reading legacy value will be safely refactored out in a next version - related to `flagOverviewRedesign` flag
const { value: legacyStoreValue } = createLocalStorage<{
hiddenEnvironments?: Array<string>;
}>('global:v1', {});
export const useEnvironmentVisibility = () => {
const [value, setValue] = useLocalStorageState<Array<string>>(
'environment-visibiilty',
legacyStoreValue?.hiddenEnvironments || [],
);
const { trackEvent } = usePlausibleTracker();
const onEnvironmentVisibilityChange = (environment: string) => {
if (value.includes(environment)) {
setValue(value.filter((env) => env !== environment));
trackEvent('hidden_environment', {
props: {
eventType: `environment unhidden`,
},
});
} else {
setValue([...value, environment]);
trackEvent('hidden_environment', {
props: {
eventType: `environment hidden`,
},
});
}
};
return {
hiddenEnvironments: value,
onEnvironmentVisibilityChange,
};
};

View File

@ -1,9 +1,9 @@
import { type FC, useState } from 'react';
import { styled } from '@mui/material';
import { useNavigate } from 'react-router-dom';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog';
import { useState } from 'react';
import { FeatureArchiveNotAllowedDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveNotAllowedDialog';
import { formatDateYMD } from 'utils/formatDate';
import { parseISO } from 'date-fns';
@ -15,6 +15,7 @@ import { MarkCompletedDialogue } from '../FeatureLifecycle/MarkCompletedDialogue
import { TagRow } from './TagRow';
import { capitalizeFirst } from 'utils/capitalizeFirst';
import { Collaborators } from './Collaborators';
import { EnvironmentVisibilityMenu } from './EnvironmentVisibilityMenu/EnvironmentVisibilityMenu';
const StyledMetaDataContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(3),
@ -24,7 +25,8 @@ const StyledMetaDataContainer = styled('div')(({ theme }) => ({
flexDirection: 'column',
gap: theme.spacing(2),
width: '350px',
[theme.breakpoints.down(1000)]: {
border: `1px solid ${theme.palette.divider}`,
[theme.breakpoints.down('md')]: {
width: '100%',
},
}));
@ -63,7 +65,15 @@ export const StyledMetaDataItemValue = styled('div')(({ theme }) => ({
gap: theme.spacing(1),
}));
const FeatureOverviewMetaData = () => {
type FeatureOverviewMetaDataProps = {
hiddenEnvironments?: string[];
onEnvironmentVisibilityChange?: (environment: string) => void;
};
const FeatureOverviewMetaData: FC<FeatureOverviewMetaDataProps> = ({
hiddenEnvironments,
onEnvironmentVisibilityChange,
}) => {
const projectId = useRequiredPathParam('projectId');
const featureId = useRequiredPathParam('featureId');
const { feature, refetchFeature } = useFeature(projectId, featureId);
@ -156,6 +166,13 @@ const FeatureOverviewMetaData = () => {
<DependencyRow feature={feature} />
) : null}
<TagRow feature={feature} />
{onEnvironmentVisibilityChange ? (
<EnvironmentVisibilityMenu
environments={feature.environments || []}
hiddenEnvironments={hiddenEnvironments || []}
onChange={onEnvironmentVisibilityChange}
/>
) : null}
</StyledBody>
</StyledMetaDataContainer>
{feature.children.length > 0 ? (

View File

@ -19,7 +19,7 @@ const StyledContainer = styled(Box)(({ theme }) => ({
flexDirection: 'column',
gap: theme.spacing(2),
width: '350px',
[theme.breakpoints.down(1000)]: {
[theme.breakpoints.down('md')]: {
width: '100%',
},
}));

View File

@ -0,0 +1,91 @@
import FeatureOverviewEnvironments from './FeatureOverviewEnvironments/FeatureOverviewEnvironments';
import { Route, Routes, useNavigate } from 'react-router-dom';
import { SidebarModal } from 'component/common/SidebarModal/SidebarModal';
import {
FeatureStrategyEdit,
formatFeaturePath,
} from 'component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { usePageTitle } from 'hooks/usePageTitle';
import { useHiddenEnvironments } from 'hooks/useHiddenEnvironments';
import { styled } from '@mui/material';
import { FeatureStrategyCreate } from 'component/feature/FeatureStrategy/FeatureStrategyCreate/FeatureStrategyCreate';
import { useEffect } from 'react';
import { useLastViewedFlags } from 'hooks/useLastViewedFlags';
import OldFeatureOverviewMetaData from './FeatureOverviewMetaData/OldFeatureOverviewMetaData';
import { OldFeatureOverviewSidePanel } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/OldFeatureOverviewSidePanel';
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
width: '100%',
[theme.breakpoints.down(1000)]: {
flexDirection: 'column',
},
}));
const StyledMainContent = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
width: `calc(100% - (350px + 1rem))`,
[theme.breakpoints.down(1000)]: {
width: '100%',
},
}));
const FeatureOverview = () => {
const navigate = useNavigate();
const projectId = useRequiredPathParam('projectId');
const featureId = useRequiredPathParam('featureId');
const featurePath = formatFeaturePath(projectId, featureId);
const { hiddenEnvironments, setHiddenEnvironments } =
useHiddenEnvironments();
const onSidebarClose = () => navigate(featurePath);
usePageTitle(featureId);
const { setLastViewed } = useLastViewedFlags();
useEffect(() => {
setLastViewed({ featureId, projectId });
}, [featureId]);
return (
<StyledContainer>
<div>
<OldFeatureOverviewMetaData />
<OldFeatureOverviewSidePanel
hiddenEnvironments={hiddenEnvironments}
setHiddenEnvironments={setHiddenEnvironments}
/>
</div>
<StyledMainContent>
<FeatureOverviewEnvironments />
</StyledMainContent>
<Routes>
<Route
path='strategies/create'
element={
<SidebarModal
label='Create feature strategy'
onClose={onSidebarClose}
open
>
<FeatureStrategyCreate />
</SidebarModal>
}
/>
<Route
path='strategies/edit'
element={
<SidebarModal
label='Edit feature strategy'
onClose={onSidebarClose}
open
>
<FeatureStrategyEdit />
</SidebarModal>
}
/>
</Routes>
</StyledContainer>
);
};
export default FeatureOverview;

View File

@ -8,7 +8,6 @@ import { Alert, Pagination, styled } from '@mui/material';
import useFeatureStrategyApi from 'hooks/api/actions/useFeatureStrategyApi/useFeatureStrategyApi';
import { formatUnknownError } from 'utils/formatUnknownError';
import useToast from 'hooks/useToast';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { StrategyDraggableItem } from '../FeatureOverviewEnvironments/FeatureOverviewEnvironment/EnvironmentAccordionBody/StrategyDraggableItem/StrategyDraggableItem';
import type { IFeatureEnvironment } from 'interfaces/featureToggle';
import { FeatureStrategyEmpty } from 'component/feature/FeatureStrategy/FeatureStrategyEmpty/FeatureStrategyEmpty';
@ -230,132 +229,91 @@ export const FeatureOverviewEnvironmentBody = ({
return (
<StyledAccordionBody>
<StyledAccordionBodyInnerContainer>
<ConditionallyRender
condition={
(releasePlans.length > 0 ||
strategiesToDisplay.length > 0) &&
isDisabled
}
show={() => (
<Alert severity='warning' sx={{ mb: 2 }}>
This environment is disabled, which means that none
of your strategies are executing.
</Alert>
)}
/>
<ConditionallyRender
condition={
releasePlans.length > 0 ||
strategiesToDisplay.length > 0
}
show={
<>
{releasePlans.map((plan) => (
<ReleasePlan
key={plan.id}
plan={plan}
environmentIsDisabled={isDisabled}
{(releasePlans.length > 0 || strategiesToDisplay.length > 0) &&
isDisabled ? (
<Alert severity='warning' sx={{ mb: 2 }}>
This environment is disabled, which means that none of
your strategies are executing.
</Alert>
) : null}
{releasePlans.length > 0 || strategiesToDisplay.length > 0 ? (
<>
{releasePlans.map((plan) => (
<ReleasePlan
key={plan.id}
plan={plan}
environmentIsDisabled={isDisabled}
/>
))}
{releasePlans.length > 0 && strategies.length > 0 ? (
<SectionSeparator>
<StyledBadge>OR</StyledBadge>
</SectionSeparator>
) : null}
{strategiesToDisplay.length < 50 ||
!manyStrategiesPagination ? (
<>
{strategiesToDisplay.map((strategy, index) => (
<StrategyDraggableItem
key={strategy.id}
strategy={strategy}
index={index}
environmentName={
featureEnvironment.name
}
otherEnvironments={otherEnvironments}
isDragging={
dragItem?.id === strategy.id
}
onDragStartRef={onDragStartRef}
onDragOver={onDragOver(strategy.id)}
onDragEnd={onDragEnd}
/>
))}
</>
) : (
<>
<Alert severity='error'>
We noticed you're using a high number of
activation strategies. To ensure a more
targeted approach, consider leveraging
constraints or segments.
</Alert>
<br />
{page.map((strategy, index) => (
<StrategyDraggableItem
key={strategy.id}
strategy={strategy}
index={index + pageIndex * pageSize}
environmentName={
featureEnvironment.name
}
otherEnvironments={otherEnvironments}
isDragging={false}
onDragStartRef={(() => {}) as any}
onDragOver={(() => {}) as any}
onDragEnd={(() => {}) as any}
/>
))}
<br />
<Pagination
count={pages.length}
shape='rounded'
page={pageIndex + 1}
onChange={(_, page) =>
setPageIndex(page - 1)
}
/>
))}
<ConditionallyRender
condition={
releasePlans.length > 0 &&
strategies.length > 0
}
show={
<SectionSeparator>
<StyledBadge>OR</StyledBadge>
</SectionSeparator>
}
/>
<ConditionallyRender
condition={
strategiesToDisplay.length < 50 ||
!manyStrategiesPagination
}
show={
<>
{strategiesToDisplay.map(
(strategy, index) => (
<StrategyDraggableItem
key={strategy.id}
strategy={strategy}
index={index}
environmentName={
featureEnvironment.name
}
otherEnvironments={
otherEnvironments
}
isDragging={
dragItem?.id ===
strategy.id
}
onDragStartRef={
onDragStartRef
}
onDragOver={onDragOver(
strategy.id,
)}
onDragEnd={onDragEnd}
/>
),
)}
</>
}
elseShow={
<>
<Alert severity='error'>
We noticed you're using a high
number of activation strategies. To
ensure a more targeted approach,
consider leveraging constraints or
segments.
</Alert>
<br />
{page.map((strategy, index) => (
<StrategyDraggableItem
key={strategy.id}
strategy={strategy}
index={
index + pageIndex * pageSize
}
environmentName={
featureEnvironment.name
}
otherEnvironments={
otherEnvironments
}
isDragging={false}
onDragStartRef={
(() => {}) as any
}
onDragOver={(() => {}) as any}
onDragEnd={(() => {}) as any}
/>
))}
<br />
<Pagination
count={pages.length}
shape='rounded'
page={pageIndex + 1}
onChange={(_, page) =>
setPageIndex(page - 1)
}
/>
</>
}
/>
</>
}
elseShow={
<FeatureStrategyEmpty
projectId={projectId}
featureId={featureId}
environmentId={featureEnvironment.name}
/>
}
/>
</>
)}
</>
) : (
<FeatureStrategyEmpty
projectId={projectId}
featureId={featureId}
environmentId={featureEnvironment.name}
/>
)}
</StyledAccordionBodyInnerContainer>
</StyledAccordionBody>
);

View File

@ -2,7 +2,6 @@ import { Box, styled } from '@mui/material';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
import useFeatureMetrics from 'hooks/api/getters/useFeatureMetrics/useFeatureMetrics';
import { getFeatureMetrics } from 'utils/getFeatureMetrics';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { FeatureOverviewEnvironmentBody } from './FeatureOverviewEnvironmentBody';
import FeatureOverviewEnvironmentMetrics from '../FeatureOverviewEnvironments/FeatureOverviewEnvironment/FeatureOverviewEnvironmentMetrics/FeatureOverviewEnvironmentMetrics';
import { FeatureStrategyMenu } from 'component/feature/FeatureStrategy/FeatureStrategyMenu/FeatureStrategyMenu';
@ -13,6 +12,7 @@ const StyledFeatureOverviewEnvironment = styled('div')(({ theme }) => ({
padding: theme.spacing(1, 3),
borderRadius: theme.shape.borderRadiusLarge,
backgroundColor: theme.palette.background.paper,
border: `1px solid ${theme.palette.divider}`,
}));
const StyledFeatureOverviewEnvironmentBody = styled(
@ -52,62 +52,75 @@ const StyledHeaderTitle = styled('span')(({ theme }) => ({
}));
interface INewFeatureOverviewEnvironmentProps {
environmentId: string;
hiddenEnvironments: string[];
}
export const NewFeatureOverviewEnvironment = ({
environmentId,
export const FeatureOverviewEnvironment = ({
hiddenEnvironments,
}: INewFeatureOverviewEnvironmentProps) => {
const projectId = useRequiredPathParam('projectId');
const featureId = useRequiredPathParam('featureId');
const { metrics } = useFeatureMetrics(projectId, featureId);
const { feature } = useFeature(projectId, featureId);
const featureMetrics = getFeatureMetrics(feature?.environments, metrics);
const environmentMetric = featureMetrics.find(
({ environment }) => environment === environmentId,
);
const featureEnvironment = feature?.environments.find(
({ name }) => name === environmentId,
);
const environments =
feature?.environments.filter(
({ name }) => !hiddenEnvironments.includes(name),
) || [];
if (!featureEnvironment)
if (!environments || environments.length === 0) {
return (
<StyledFeatureOverviewEnvironment className='skeleton'>
<Box sx={{ height: '400px' }} />
</StyledFeatureOverviewEnvironment>
);
}
return (
<StyledFeatureOverviewEnvironment>
<StyledHeader data-loading>
<StyledHeaderToggleContainer>
<FeatureOverviewEnvironmentToggle
environment={featureEnvironment}
return environments.map(({ name: environmentId }) => {
const featureMetrics = getFeatureMetrics(
feature?.environments,
metrics,
);
const environmentMetric = featureMetrics.find(
({ environment }) => environment === environmentId,
);
const featureEnvironment = feature?.environments.find(
({ name }) => name === environmentId,
);
if (!featureEnvironment) {
return null;
}
return (
<StyledFeatureOverviewEnvironment key={environmentId}>
<StyledHeader data-loading>
<StyledHeaderToggleContainer>
<FeatureOverviewEnvironmentToggle
environment={featureEnvironment}
/>
<StyledHeaderTitleContainer>
<StyledHeaderTitleLabel>
Environment
</StyledHeaderTitleLabel>
<StyledHeaderTitle>
{environmentId}
</StyledHeaderTitle>
</StyledHeaderTitleContainer>
</StyledHeaderToggleContainer>
<FeatureOverviewEnvironmentMetrics
environmentMetric={environmentMetric}
disabled={!featureEnvironment.enabled}
/>
<StyledHeaderTitleContainer>
<StyledHeaderTitleLabel>
Environment
</StyledHeaderTitleLabel>
<StyledHeaderTitle>{environmentId}</StyledHeaderTitle>
</StyledHeaderTitleContainer>
</StyledHeaderToggleContainer>
<FeatureOverviewEnvironmentMetrics
environmentMetric={environmentMetric}
disabled={!featureEnvironment.enabled}
</StyledHeader>
<StyledFeatureOverviewEnvironmentBody
featureEnvironment={featureEnvironment}
isDisabled={!featureEnvironment.enabled}
otherEnvironments={feature?.environments
.map(({ name }) => name)
.filter((name) => name !== environmentId)}
/>
</StyledHeader>
<StyledFeatureOverviewEnvironmentBody
featureEnvironment={featureEnvironment}
isDisabled={!featureEnvironment.enabled}
otherEnvironments={feature?.environments
.map(({ name }) => name)
.filter((name) => name !== environmentId)}
/>
<ConditionallyRender
condition={(featureEnvironment?.strategies?.length || 0) > 0}
show={
{featureEnvironment?.strategies?.length > 0 ? (
<>
<Box
sx={{
@ -124,8 +137,8 @@ export const NewFeatureOverviewEnvironment = ({
/>
</Box>
</>
}
/>
</StyledFeatureOverviewEnvironment>
);
) : null}
</StyledFeatureOverviewEnvironment>
);
});
};

View File

@ -1,7 +1,7 @@
import { Link, Route, Routes } from 'react-router-dom';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
import FeatureLog from './FeatureLog/FeatureLog';
import FeatureOverview from './FeatureOverview/FeatureOverview';
import { FeatureOverview } from './FeatureOverview/FeatureOverview';
import { FeatureEnvironmentVariants } from './FeatureVariants/FeatureEnvironmentVariants/FeatureEnvironmentVariants';
import { FeatureMetrics } from './FeatureMetrics/FeatureMetrics';
import { FeatureSettings } from './FeatureSettings/FeatureSettings';

View File

@ -5,6 +5,9 @@ interface IGlobalStore {
hiddenEnvironments?: Array<string>;
}
/**
* @deprecated use tested `useLocalStorageState` hook instead
*/
export const useGlobalLocalStorage = () => {
const { value, setValue } = createLocalStorage<IGlobalStore>(
'global:v1',

View File

@ -2,6 +2,9 @@ import { useGlobalLocalStorage } from './useGlobalLocalStorage';
import { useState } from 'react';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
/**
* @deprecated remove with `flagOverviewRedesign`
*/
export const useHiddenEnvironments = () => {
const { trackEvent } = usePlausibleTracker();
@ -25,11 +28,6 @@ export const useHiddenEnvironments = () => {
});
} else {
hiddenEnvironments.add(environment);
trackEvent('hidden_environment', {
props: {
eventType: `environment hidden`,
},
});
}
setStoredHiddenEnvironments(hiddenEnvironments);