Skip to content

Commit

Permalink
feat: flag exposure in personal dashboard (#8247)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew authored Sep 25, 2024
1 parent 289324f commit a1a24ea
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const FeatureLifecycle: FC<{
return currentStage ? (
<FeatureLifecycleTooltip
stage={currentStage!}
project={feature.project}
onArchive={onArchive}
onComplete={onComplete}
onUncomplete={onUncompleteHandler}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
DELETE_FEATURE,
UPDATE_FEATURE,
} from 'component/providers/AccessProvider/permissions';
import { Route, Routes } from 'react-router-dom';

const currentTime = '2024-04-25T08:05:00.000Z';
const twoMinutesAgo = '2024-04-25T08:03:00.000Z';
Expand All @@ -23,24 +22,17 @@ const renderOpenTooltip = (
loading = false,
) => {
render(
<Routes>
<Route
path={'/projects/:projectId'}
element={
<FeatureLifecycleTooltip
stage={stage}
onArchive={onArchive}
onComplete={onComplete}
onUncomplete={onUncomplete}
loading={loading}
>
<span>child</span>
</FeatureLifecycleTooltip>
}
/>
</Routes>,
<FeatureLifecycleTooltip
stage={stage}
onArchive={onArchive}
onComplete={onComplete}
onUncomplete={onUncomplete}
loading={loading}
project={'default'}
>
<span>child</span>
</FeatureLifecycleTooltip>,
{
route: '/projects/default',
permissions: [
{ permission: DELETE_FEATURE },
{ permission: UPDATE_FEATURE },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { isSafeToArchive } from './isSafeToArchive';
import { useLocationSettings } from 'hooks/useLocationSettings';
import { formatDateYMDHMS } from 'utils/formatDate';
import { formatDistanceToNow, parseISO } from 'date-fns';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';

const TimeLabel = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
Expand Down Expand Up @@ -96,7 +95,7 @@ const StageBox = styled(Box, {
...(active && {
backgroundColor: theme.palette.primary.light,
color: theme.palette.primary.contrastText,
fontWeight: theme.fontWeight.bold,
fontWeight: theme.typography.fontWeightBold,
borderRadius: theme.spacing(0.5),
}),
},
Expand Down Expand Up @@ -247,17 +246,16 @@ const PreLiveStageDescription: FC<{ children?: React.ReactNode }> = ({
const BoldTitle = styled(Typography)(({ theme }) => ({
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
fontSize: theme.fontSizes.smallBody,
fontWeight: theme.fontWeight.bold,
fontSize: theme.typography.body2.fontSize,
fontWeight: theme.typography.fontWeightBold,
}));

const LiveStageDescription: FC<{
onComplete: () => void;
loading: boolean;
children?: React.ReactNode;
}> = ({ children, onComplete, loading }) => {
const projectId = useRequiredPathParam('projectId');

project: string;
}> = ({ children, onComplete, loading, project }) => {
return (
<>
<BoldTitle>Is this feature complete?</BoldTitle>
Expand All @@ -276,7 +274,7 @@ const LiveStageDescription: FC<{
size='small'
onClick={onComplete}
disabled={loading}
projectId={projectId}
projectId={project}
>
Mark completed
</PermissionButton>
Expand All @@ -294,9 +292,8 @@ const SafeToArchive: FC<{
onArchive: () => void;
onUncomplete: () => void;
loading: boolean;
}> = ({ onArchive, onUncomplete, loading }) => {
const projectId = useRequiredPathParam('projectId');

project: string;
}> = ({ onArchive, onUncomplete, loading, project }) => {
return (
<>
<BoldTitle>Safe to archive</BoldTitle>
Expand Down Expand Up @@ -324,7 +321,7 @@ const SafeToArchive: FC<{
size='small'
onClick={onUncomplete}
disabled={loading}
projectId={projectId}
projectId={project}
>
Revert to live
</PermissionButton>
Expand All @@ -335,7 +332,7 @@ const SafeToArchive: FC<{
size='small'
sx={{ mb: 2 }}
onClick={onArchive}
projectId={projectId}
projectId={project}
>
Archive feature
</PermissionButton>
Expand Down Expand Up @@ -393,7 +390,15 @@ const CompletedStageDescription: FC<{
lastSeenAt: string;
}>;
children?: React.ReactNode;
}> = ({ children, environments, onArchive, onUncomplete, loading }) => {
project: string;
}> = ({
children,
environments,
onArchive,
onUncomplete,
loading,
project,
}) => {
return (
<ConditionallyRender
condition={isSafeToArchive(environments)}
Expand All @@ -402,6 +407,7 @@ const CompletedStageDescription: FC<{
onArchive={onArchive}
onUncomplete={onUncomplete}
loading={loading}
project={project}
/>
}
elseShow={
Expand Down Expand Up @@ -432,11 +438,20 @@ const FormatElapsedTime: FC<{
export const FeatureLifecycleTooltip: FC<{
children: React.ReactElement<any, any>;
stage: LifecycleStage;
project: string;
onArchive: () => void;
onComplete: () => void;
onUncomplete: () => void;
loading: boolean;
}> = ({ children, stage, onArchive, onComplete, onUncomplete, loading }) => (
}> = ({
children,
stage,
project,
onArchive,
onComplete,
onUncomplete,
loading,
}) => (
<HtmlTooltip
maxHeight={800}
maxWidth={350}
Expand Down Expand Up @@ -482,6 +497,7 @@ export const FeatureLifecycleTooltip: FC<{
<LiveStageDescription
onComplete={onComplete}
loading={loading}
project={project}
>
<Environments environments={stage.environments} />
</LiveStageDescription>
Expand All @@ -492,6 +508,7 @@ export const FeatureLifecycleTooltip: FC<{
onArchive={onArchive}
onUncomplete={onUncomplete}
loading={loading}
project={project}
>
<Environments environments={stage.environments} />
</CompletedStageDescription>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { type FC, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
import type { ILastSeenEnvironments } from 'interfaces/featureToggle';
import { Box } from '@mui/material';
import { FeatureEnvironmentSeen } from '../../FeatureEnvironmentSeen/FeatureEnvironmentSeen';
import { FeatureLifecycle } from './FeatureLifecycle';
import { FeatureArchiveNotAllowedDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveNotAllowedDialog';
import { FeatureArchiveDialog } from 'component/common/FeatureArchiveDialog/FeatureArchiveDialog';
import { MarkCompletedDialogue } from './MarkCompletedDialogue';

export const FlagExposure: FC<{
project: string;
flagName: string;
onArchive: () => void;
}> = ({ project, flagName, onArchive }) => {
const navigate = useNavigate();
const { feature, refetchFeature } = useFeature(project, flagName);
const lastSeenEnvironments: ILastSeenEnvironments[] =
feature.environments?.map((env) => ({
name: env.name,
lastSeenAt: env.lastSeenAt,
enabled: env.enabled,
yes: env.yes,
no: env.no,
}));
const [showDelDialog, setShowDelDialog] = useState(false);
const [showMarkCompletedDialogue, setShowMarkCompletedDialogue] =
useState(false);

return (
<Box sx={{ display: 'flex' }}>
<FeatureEnvironmentSeen
featureLastSeen={feature.lastSeenAt}
environments={lastSeenEnvironments}
/>
<FeatureLifecycle
feature={feature}
onArchive={() => setShowDelDialog(true)}
onComplete={() => setShowMarkCompletedDialogue(true)}
onUncomplete={refetchFeature}
/>

{feature.children.length > 0 ? (
<FeatureArchiveNotAllowedDialog
features={feature.children}
project={project}
isOpen={showDelDialog}
onClose={() => setShowDelDialog(false)}
/>
) : (
<FeatureArchiveDialog
isOpen={showDelDialog}
onConfirm={onArchive}
onClose={() => setShowDelDialog(false)}
projectId={project}
featureIds={[flagName]}
/>
)}

{feature.project ? (
<MarkCompletedDialogue
isOpen={showMarkCompletedDialogue}
setIsOpen={setShowMarkCompletedDialogue}
projectId={feature.project}
featureId={feature.name}
onComplete={refetchFeature}
/>
) : null}
</Box>
);
};
19 changes: 17 additions & 2 deletions frontend/src/component/personalDashboard/PersonalDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { ProjectSetupComplete } from './ProjectSetupComplete';
import { usePersonalDashboard } from 'hooks/api/getters/usePersonalDashboard/usePersonalDashboard';
import { getFeatureTypeIcons } from 'utils/getFeatureTypeIcons';
import type { PersonalDashboardSchema } from '../../openapi';
import { FlagExposure } from 'component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure';

const ScreenExplanation = styled(Typography)(({ theme }) => ({
marginTop: theme.spacing(1),
Expand Down Expand Up @@ -177,7 +178,8 @@ export const PersonalDashboard = () => {

const { projects, activeProject, setActiveProject } = useProjects();

const { personalDashboard } = usePersonalDashboard();
const { personalDashboard, refetch: refetchDashboard } =
usePersonalDashboard();
const [activeFlag, setActiveFlag] = useState<
PersonalDashboardSchema['flags'][0] | null
>(null);
Expand Down Expand Up @@ -298,7 +300,20 @@ export const PersonalDashboard = () => {
<SpacedGridItem item lg={4} md={1}>
<Typography variant='h3'>My feature flags</Typography>
</SpacedGridItem>
<SpacedGridItem item lg={8} md={1} />
<SpacedGridItem
item
lg={8}
md={1}
sx={{ display: 'flex', justifyContent: 'flex-end' }}
>
{activeFlag ? (
<FlagExposure
project={activeFlag.project}
flagName={activeFlag.name}
onArchive={refetchDashboard}
/>
) : null}
</SpacedGridItem>
<SpacedGridItem item lg={4} md={1}>
{personalDashboard && personalDashboard.flags.length > 0 ? (
<List
Expand Down

0 comments on commit a1a24ea

Please sign in to comment.