diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycle.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycle.tsx
index 995b468bcd..3df3893dce 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycle.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycle.tsx
@@ -43,6 +43,7 @@ export const FeatureLifecycle: FC<{
return currentStage ? (
{
render(
-
-
- child
-
- }
- />
- ,
+
+ child
+ ,
{
- route: '/projects/default',
permissions: [
{ permission: DELETE_FEATURE },
{ permission: UPDATE_FEATURE },
diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx
index 46d597c98d..cfd8e6e4b4 100644
--- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx
@@ -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,
@@ -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),
}),
},
@@ -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 (
<>
Is this feature complete?
@@ -276,7 +274,7 @@ const LiveStageDescription: FC<{
size='small'
onClick={onComplete}
disabled={loading}
- projectId={projectId}
+ projectId={project}
>
Mark completed
@@ -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 (
<>
Safe to archive
@@ -324,7 +321,7 @@ const SafeToArchive: FC<{
size='small'
onClick={onUncomplete}
disabled={loading}
- projectId={projectId}
+ projectId={project}
>
Revert to live
@@ -335,7 +332,7 @@ const SafeToArchive: FC<{
size='small'
sx={{ mb: 2 }}
onClick={onArchive}
- projectId={projectId}
+ projectId={project}
>
Archive feature
@@ -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 (
}
elseShow={
@@ -432,11 +438,20 @@ const FormatElapsedTime: FC<{
export const FeatureLifecycleTooltip: FC<{
children: React.ReactElement;
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,
+}) => (
@@ -492,6 +508,7 @@ export const FeatureLifecycleTooltip: FC<{
onArchive={onArchive}
onUncomplete={onUncomplete}
loading={loading}
+ project={project}
>
diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure.tsx
new file mode 100644
index 0000000000..7c1283b7f7
--- /dev/null
+++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure.tsx
@@ -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 (
+
+
+ setShowDelDialog(true)}
+ onComplete={() => setShowMarkCompletedDialogue(true)}
+ onUncomplete={refetchFeature}
+ />
+
+ {feature.children.length > 0 ? (
+ setShowDelDialog(false)}
+ />
+ ) : (
+ setShowDelDialog(false)}
+ projectId={project}
+ featureIds={[flagName]}
+ />
+ )}
+
+ {feature.project ? (
+
+ ) : null}
+
+ );
+};
diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx
index ff40f972e3..3dcf55fc5e 100644
--- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx
+++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx
@@ -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),
@@ -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);
@@ -298,7 +300,20 @@ export const PersonalDashboard = () => {
My feature flags
-
+
+ {activeFlag ? (
+
+ ) : null}
+
{personalDashboard && personalDashboard.flags.length > 0 ? (