From cc8a950348a29653ceab83096484acce8c5e07d5 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Wed, 3 Sep 2025 15:58:39 +0200 Subject: [PATCH] feat: delete flag impact metrics (#10613) --- .../FeatureMetrics/FeatureImpactMetrics.tsx | 34 +++++++++++++++---- .../component/impact-metrics/ChartItem.tsx | 18 +++++++--- .../impact-metrics/ImpactMetrics.tsx | 7 ++-- .../useImpactMetricsApi.ts | 17 ++++++++++ 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureImpactMetrics.tsx b/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureImpactMetrics.tsx index 76b58dc96d..41fa3f4282 100644 --- a/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureImpactMetrics.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureMetrics/FeatureImpactMetrics.tsx @@ -1,6 +1,6 @@ import { PageContent } from 'component/common/PageContent/PageContent.tsx'; import { PageHeader } from '../../../common/PageHeader/PageHeader.tsx'; -import { Button, styled, Typography } from '@mui/material'; +import { styled, Typography } from '@mui/material'; import Add from '@mui/icons-material/Add'; import { useImpactMetricsMetadata } from 'hooks/api/getters/useImpactMetricsMetadata/useImpactMetricsMetadata.ts'; import { type FC, useMemo, useState } from 'react'; @@ -9,6 +9,10 @@ import { useImpactMetricsApi } from 'hooks/api/actions/useImpactMetricsSettingsA import { useRequiredPathParam } from 'hooks/useRequiredPathParam.ts'; import { useFeatureImpactMetrics } from 'hooks/api/getters/useFeatureImpactMetrics/useFeatureImpactMetrics.ts'; import { ChartItem } from '../../../impact-metrics/ChartItem.tsx'; +import PermissionButton from 'component/common/PermissionButton/PermissionButton.tsx'; +import { ADMIN } from 'component/providers/AccessProvider/permissions.ts'; +import useToast from 'hooks/useToast.tsx'; +import { formatUnknownError } from 'utils/formatUnknownError.ts'; const StyledHeaderTitle = styled(Typography)(({ theme }) => ({ fontSize: theme.fontSizes.mainHeader, @@ -19,8 +23,9 @@ const StyledHeaderTitle = styled(Typography)(({ theme }) => ({ export const FeatureImpactMetrics: FC = () => { const feature = useRequiredPathParam('featureId'); const [modalOpen, setModalOpen] = useState(false); - const { createImpactMetric } = useImpactMetricsApi(); - const { impactMetrics } = useFeatureImpactMetrics(feature); + const { createImpactMetric, deleteImpactMetric } = useImpactMetricsApi(); + const { impactMetrics, refetch } = useFeatureImpactMetrics(feature); + const { setToastApiError } = useToast(); const { metadata, @@ -49,14 +54,15 @@ export const FeatureImpactMetrics: FC = () => { Impact Metrics } actions={ - + } /> @@ -65,7 +71,14 @@ export const FeatureImpactMetrics: FC = () => { {}} - onDelete={() => {}} + onDelete={async () => { + try { + await deleteImpactMetric(config.id); + refetch(); + } catch (error: unknown) { + setToastApiError(formatUnknownError(error)); + } + }} /> ))} @@ -73,7 +86,14 @@ export const FeatureImpactMetrics: FC = () => { setModalOpen(false)} - onSave={(data) => createImpactMetric({ ...data, feature })} + onSave={async (data) => { + try { + await createImpactMetric({ ...data, feature }); + refetch(); + } catch (error: unknown) { + setToastApiError(formatUnknownError(error)); + } + }} initialConfig={undefined} metricSeries={metricSeries} loading={metadataLoading} diff --git a/frontend/src/component/impact-metrics/ChartItem.tsx b/frontend/src/component/impact-metrics/ChartItem.tsx index 7d69d67d61..2fb3d458df 100644 --- a/frontend/src/component/impact-metrics/ChartItem.tsx +++ b/frontend/src/component/impact-metrics/ChartItem.tsx @@ -1,10 +1,12 @@ import type { FC } from 'react'; -import { Box, Typography, IconButton, styled, Paper } from '@mui/material'; +import { Box, Typography, styled, Paper } from '@mui/material'; import Edit from '@mui/icons-material/Edit'; import Delete from '@mui/icons-material/Delete'; import DragHandle from '@mui/icons-material/DragHandle'; import { ImpactMetricsChart } from './ImpactMetricsChart.tsx'; import type { ChartConfig, DisplayChartConfig } from './types.ts'; +import PermissionIconButton from '../common/PermissionIconButton/PermissionIconButton.tsx'; +import { ADMIN } from '../providers/AccessProvider/permissions.ts'; export interface ChartItemProps { config: DisplayChartConfig; @@ -117,12 +119,18 @@ export const ChartItem: FC = ({ config, onEdit, onDelete }) => ( - onEdit(config)}> + onEdit(config)} + permission={ADMIN} + > - - onDelete(config.id)}> + + onDelete(config.id)} + permission={ADMIN} + > - + diff --git a/frontend/src/component/impact-metrics/ImpactMetrics.tsx b/frontend/src/component/impact-metrics/ImpactMetrics.tsx index b7c11bd815..1b636f0993 100644 --- a/frontend/src/component/impact-metrics/ImpactMetrics.tsx +++ b/frontend/src/component/impact-metrics/ImpactMetrics.tsx @@ -11,6 +11,8 @@ import { useImpactMetricsState } from './hooks/useImpactMetricsState.ts'; import type { ChartConfig, LayoutItem } from './types.ts'; import useToast from 'hooks/useToast'; import { formatUnknownError } from 'utils/formatUnknownError'; +import PermissionButton from 'component/common/PermissionButton/PermissionButton.tsx'; +import { ADMIN } from '../providers/AccessProvider/permissions.ts'; const StyledEmptyState = styled(Paper)(({ theme }) => ({ textAlign: 'center', @@ -138,14 +140,15 @@ export const ImpactMetrics: FC = () => { } actions={ - + } /> diff --git a/frontend/src/hooks/api/actions/useImpactMetricsSettingsApi/useImpactMetricsApi.ts b/frontend/src/hooks/api/actions/useImpactMetricsSettingsApi/useImpactMetricsApi.ts index 933f380f3b..101343eb5b 100644 --- a/frontend/src/hooks/api/actions/useImpactMetricsSettingsApi/useImpactMetricsApi.ts +++ b/frontend/src/hooks/api/actions/useImpactMetricsSettingsApi/useImpactMetricsApi.ts @@ -24,8 +24,25 @@ export const useImpactMetricsApi = () => { [makeRequest, createRequest], ); + const deleteImpactMetric = useCallback( + async (metricId: string) => { + const path = `api/admin/impact-metrics/config/${metricId}`; + const req = createRequest( + path, + { + method: 'DELETE', + }, + 'deleteImpactMetric', + ); + + return makeRequest(req.caller, req.id); + }, + [makeRequest, createRequest], + ); + return { createImpactMetric, + deleteImpactMetric, errors, loading, };