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

chore: flag overview page redesign - environments #8683

Merged
merged 7 commits into from
Nov 8, 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
1 change: 1 addition & 0 deletions frontend/cypress/integration/demo/demo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ describe('demo', () => {
res.body.flags = {
...res.body.flags,
demo: true,
flagOverviewRedesign: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the implications of this?

Copy link
Member Author

Choose a reason for hiding this comment

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

This makes the demo e2e tests, that we only run manually and rarely, use the new flag overview page redesign.

};
}
});
Expand Down
14 changes: 14 additions & 0 deletions frontend/cypress/integration/feature/feature.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
///<reference path="../../global.d.ts" />

describe('feature', () => {
const baseUrl = Cypress.config().baseUrl;
const randomId = String(Math.random()).split('.')[1];
const featureToggleName = `unleash-e2e-${randomId}`;
const projectName = `unleash-e2e-project-${randomId}`;
Expand Down Expand Up @@ -35,6 +36,19 @@ describe('feature', () => {
beforeEach(() => {
cy.login_UI();
cy.visit('/features');

cy.intercept('GET', `${baseUrl}/api/admin/ui-config`, (req) => {
req.headers['cache-control'] =
'no-cache, no-store, must-revalidate';
req.on('response', (res) => {
if (res.body) {
res.body.flags = {
...res.body.flags,
flagOverviewRedesign: true,
};
}
});
});
});

it('can create a feature flag', () => {
Expand Down
1 change: 0 additions & 1 deletion frontend/cypress/support/UI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ export const deleteFeatureStrategy_UI = (
},
).as('deleteUserStrategy');
cy.visit(`/projects/${project}/features/${featureToggleName}`);
cy.get('[data-testid=FEATURE_ENVIRONMENT_ACCORDION_development]').click();
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this in combination with the demo.ts change of adding the feature flag that we enable the flag to do the test, so we are only testing the new UI and not the old UI?

Copy link
Member Author

Choose a reason for hiding this comment

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

cy.get('[data-testid=STRATEGY_REMOVE_MENU_BTN]').first().click();
cy.get('[data-testid=STRATEGY_FORM_REMOVE_ID]').first().click();
if (!shouldWait) return cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Button, styled } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';

const StyledTab = styled(Button)<{ selected: boolean }>(
({ theme, selected }) => ({
Expand All @@ -17,7 +18,8 @@ const StyledTab = styled(Button)<{ selected: boolean }>(
transition: 'background-color 0.2s ease',
color: theme.palette.text.primary,
textAlign: 'left',
padding: theme.spacing(2, 4),
padding: theme.spacing(0, 2),
gap: theme.spacing(1),
fontSize: theme.fontSizes.bodySize,
fontWeight: selected
? theme.fontWeight.bold
Expand All @@ -41,27 +43,53 @@ const StyledTab = styled(Button)<{ selected: boolean }>(
}),
);

const StyledTabLabel = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(0.5),
}));

const StyledTabDescription = styled('div')(({ theme }) => ({
fontWeight: theme.fontWeight.medium,
fontSize: theme.fontSizes.smallBody,
color: theme.palette.text.secondary,
}));

interface IVerticalTabProps {
label: string;
description?: string;
selected?: boolean;
onClick: () => void;
icon?: React.ReactNode;
startIcon?: React.ReactNode;
endIcon?: React.ReactNode;
}

export const VerticalTab = ({
label,
description,
selected,
onClick,
icon,
startIcon,
endIcon,
}: IVerticalTabProps) => (
<StyledTab
selected={Boolean(selected)}
className={selected ? 'selected' : ''}
onClick={onClick}
disableElevation
disableFocusRipple
fullWidth
>
{label}
{icon}
{startIcon}
<StyledTabLabel>
{label}
<ConditionallyRender
condition={Boolean(description)}
show={
<StyledTabDescription>{description}</StyledTabDescription>
}
/>
</StyledTabLabel>
{endIcon}
</StyledTab>
);
64 changes: 41 additions & 23 deletions frontend/src/component/common/VerticalTabs/VerticalTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { styled } from '@mui/material';
import { VerticalTab } from './VerticalTab/VerticalTab';
import type { HTMLAttributes } from 'react';

const StyledTabPage = styled('div')(({ theme }) => ({
display: 'flex',
Expand All @@ -15,11 +16,13 @@ const StyledTabPageContent = styled('div')(() => ({
flexDirection: 'column',
}));

const StyledTabs = styled('div')(({ theme }) => ({
const StyledTabs = styled('div', {
shouldForwardProp: (prop) => prop !== 'fullWidth',
})<{ fullWidth?: boolean }>(({ theme, fullWidth }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
width: theme.spacing(30),
width: fullWidth ? '100%' : theme.spacing(30),
flexShrink: 0,
[theme.breakpoints.down('xl')]: {
width: '100%',
Expand All @@ -29,38 +32,53 @@ const StyledTabs = styled('div')(({ theme }) => ({
export interface ITab {
id: string;
label: string;
description?: string;
path?: string;
hidden?: boolean;
icon?: React.ReactNode;
startIcon?: React.ReactNode;
endIcon?: React.ReactNode;
}

interface IVerticalTabsProps {
interface IVerticalTabsProps
extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
tabs: ITab[];
value: string;
onChange: (tab: ITab) => void;
children: React.ReactNode;
children?: React.ReactNode;
}

export const VerticalTabs = ({
tabs,
value,
onChange,
children,
}: IVerticalTabsProps) => (
<StyledTabPage>
<StyledTabs>
{tabs
.filter((tab) => !tab.hidden)
.map((tab) => (
<VerticalTab
key={tab.id}
label={tab.label}
selected={tab.id === value}
onClick={() => onChange(tab)}
icon={tab.icon}
/>
))}
</StyledTabs>
<StyledTabPageContent>{children}</StyledTabPageContent>
</StyledTabPage>
);
...props
}: IVerticalTabsProps) => {
const verticalTabs = tabs
.filter((tab) => !tab.hidden)
.map((tab) => (
<VerticalTab
key={tab.id}
label={tab.label}
description={tab.description}
selected={tab.id === value}
onClick={() => onChange(tab)}
startIcon={tab.startIcon}
endIcon={tab.endIcon}
/>
));

if (!children) {
return (
<StyledTabs fullWidth {...props}>
{verticalTabs}
</StyledTabs>
);
}
return (
<StyledTabPage>
<StyledTabs {...props}>{verticalTabs}</StyledTabs>
<StyledTabPageContent>{children}</StyledTabPageContent>
</StyledTabPage>
);
};
7 changes: 4 additions & 3 deletions frontend/src/component/demo/demo-topics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const TOPICS: ITutorialTopic[] = [
},
{
href: `/projects/${PROJECT}/features/demoApp.step2`,
target: `div[data-testid="FEATURE_ENVIRONMENT_ACCORDION_${ENVIRONMENT}"] button`,
target: 'button[data-testid="ADD_STRATEGY_BUTTON"]',
content: (
<Description>
Add a new strategy to this environment by using this
Expand Down Expand Up @@ -363,9 +363,10 @@ export const TOPICS: ITutorialTopic[] = [
strategies by using the arrow button.
</Description>
),
optional: true,
},
{
target: `div[data-testid="FEATURE_ENVIRONMENT_ACCORDION_${ENVIRONMENT}"].Mui-expanded a[data-testid="STRATEGY_EDIT-flexibleRollout"]`,
target: `a[data-testid="STRATEGY_EDIT-flexibleRollout"]`,
content: (
<Description>
Edit the existing gradual rollout strategy by using the
Expand Down Expand Up @@ -471,7 +472,7 @@ export const TOPICS: ITutorialTopic[] = [
},
{
href: `/projects/${PROJECT}/features/demoApp.step4`,
target: `div[data-testid="FEATURE_ENVIRONMENT_ACCORDION_${ENVIRONMENT}"] button`,
target: 'button[data-testid="ADD_STRATEGY_BUTTON"]',
content: (
<Description>
Add a new strategy to this environment by using this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const FeatureStrategyMenu = ({
return (
<StyledStrategyMenu onClick={(event) => event.stopPropagation()}>
<PermissionButton
data-testid='ADD_STRATEGY_BUTTON'
permission={CREATE_FEATURE_STRATEGY}
projectId={projectId}
environmentId={environmentId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import { FeatureOverviewSidePanel as NewFeatureOverviewSidePanel } from 'compone
import { useHiddenEnvironments } from 'hooks/useHiddenEnvironments';
import { styled } from '@mui/material';
import { FeatureStrategyCreate } from 'component/feature/FeatureStrategy/FeatureStrategyCreate/FeatureStrategyCreate';
import { useEffect } from 'react';
import { useEffect, useState } 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 { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { NewFeatureOverviewEnvironment } from './NewFeatureOverviewEnvironment/NewFeatureOverviewEnvironment';

const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
Expand Down Expand Up @@ -48,26 +50,40 @@ const FeatureOverview = () => {
useEffect(() => {
setLastViewed({ featureId, projectId });
}, [featureId]);
const [environmentId, setEnvironmentId] = useState('');

const flagOverviewRedesign = useUiFlag('flagOverviewRedesign');
const FeatureOverviewMetaData = flagOverviewRedesign
? NewFeatureOverviewMetaData
: OldFeatureOverviewMetaData;
const FeatureOverviewSidePanel = flagOverviewRedesign
? NewFeatureOverviewSidePanel
: OldFeatureOverviewSidePanel;
const FeatureOverviewSidePanel = flagOverviewRedesign ? (
<NewFeatureOverviewSidePanel
environmentId={environmentId}
setEnvironmentId={setEnvironmentId}
/>
) : (
<OldFeatureOverviewSidePanel
hiddenEnvironments={hiddenEnvironments}
setHiddenEnvironments={setHiddenEnvironments}
/>
);

return (
<StyledContainer>
<div>
<FeatureOverviewMetaData />
<FeatureOverviewSidePanel
hiddenEnvironments={hiddenEnvironments}
setHiddenEnvironments={setHiddenEnvironments}
/>
{FeatureOverviewSidePanel}
</div>
<StyledMainContent>
<FeatureOverviewEnvironments />
<ConditionallyRender
condition={flagOverviewRedesign}
show={
<NewFeatureOverviewEnvironment
environmentId={environmentId}
/>
}
elseShow={<FeatureOverviewEnvironments />}
/>
</StyledMainContent>
<Routes>
<Route
Expand Down
Loading
Loading