From da193e7aa07c0e9625f064815336b867f84d0fb5 Mon Sep 17 00:00:00 2001 From: Fredrik Strand Oseberg Date: Tue, 10 Jan 2023 16:47:19 +0100 Subject: [PATCH] Feat/export UI (#2867) MVP for the export feature scoped export UI --- .../FeatureToggleList/ExportDialog.tsx | 70 +++++++++++++++++++ .../FeatureToggleListTable.tsx | 57 ++++++++++++++- frontend/src/interfaces/uiConfig.ts | 1 + 3 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 frontend/src/component/feature/FeatureToggleList/ExportDialog.tsx diff --git a/frontend/src/component/feature/FeatureToggleList/ExportDialog.tsx b/frontend/src/component/feature/FeatureToggleList/ExportDialog.tsx new file mode 100644 index 0000000000..8e3a00ef3f --- /dev/null +++ b/frontend/src/component/feature/FeatureToggleList/ExportDialog.tsx @@ -0,0 +1,70 @@ +import { styled, Typography } from '@mui/material'; +import { Dialogue } from 'component/common/Dialogue/Dialogue'; +import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect'; +import { IEnvironment } from 'interfaces/environments'; +import { FeatureSchema } from 'openapi'; +import { useState } from 'react'; + +interface IExportDialogProps { + showExportDialog: boolean; + data: FeatureSchema[]; + onClose: () => void; + environments: IEnvironment[]; +} + +const StyledSelect = styled(GeneralSelect)(({ theme }) => ({ + minWidth: '250px', + marginTop: theme.spacing(2), +})); + +export const ExportDialog = ({ + showExportDialog, + data, + onClose, + environments, +}: IExportDialogProps) => { + const [selected, setSelected] = useState(environments[0].name); + + const getOptions = () => + environments.map(env => ({ + key: env.name, + label: env.name, + })); + + const getPayload = () => { + return { + features: data.map(feature => feature.name), + environment: selected, + }; + }; + + const onClick = () => { + // const payload = getPayload(); + // make API call + }; + + return ( + + The current search filter will be used to export feature toggles. + Currently {data.length} feature toggles will be exported. +
+
+ + Select which environment to export feature toggle configuration + from: + + setSelected(option)} + /> +
+ ); +}; diff --git a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx index ba0960130a..45e6e52f5c 100644 --- a/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx +++ b/frontend/src/component/feature/FeatureToggleList/FeatureToggleListTable.tsx @@ -1,5 +1,11 @@ import { useCallback, useEffect, useMemo, useState, VFC } from 'react'; -import { Link, useMediaQuery, useTheme } from '@mui/material'; +import { + IconButton, + Link, + Tooltip, + useMediaQuery, + useTheme, +} from '@mui/material'; import { Link as RouterLink, useSearchParams } from 'react-router-dom'; import { SortingRule, useFlexLayout, useSortBy, useTable } from 'react-table'; import { TablePlaceholder, VirtualizedTable } from 'component/common/Table'; @@ -24,9 +30,14 @@ import { usePinnedFavorites } from 'hooks/usePinnedFavorites'; import { useFavoriteFeaturesApi } from 'hooks/api/actions/useFavoriteFeaturesApi/useFavoriteFeaturesApi'; import { FavoriteIconCell } from 'component/common/Table/cells/FavoriteIconCell/FavoriteIconCell'; import { FavoriteIconHeader } from 'component/common/Table/FavoriteIconHeader/FavoriteIconHeader'; -import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { useGlobalLocalStorage } from 'hooks/useGlobalLocalStorage'; import { useConditionallyHiddenColumns } from 'hooks/useConditionallyHiddenColumns'; +import FileDownload from '@mui/icons-material/FileDownload'; +import { Dialogue } from 'component/common/Dialogue/Dialogue'; +import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect'; +import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments'; +import { ExportDialog } from './ExportDialog'; +import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; export const featuresPlaceholder: FeatureSchema[] = Array(15).fill({ name: 'Name of the feature', @@ -49,10 +60,13 @@ const { value: storedParams, setValue: setStoredParams } = createLocalStorage( export const FeatureToggleListTable: VFC = () => { const theme = useTheme(); + const { environments } = useEnvironments(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg')); + const [showExportDialog, setShowExportDialog] = useState(false); const { features = [], loading, refetchFeatures } = useFeatures(); const [searchParams, setSearchParams] = useSearchParams(); + const { uiConfig } = useUiConfig(); const [initialState] = useState(() => ({ sortBy: [ { @@ -75,7 +89,6 @@ export const FeatureToggleListTable: VFC = () => { ); const [searchValue, setSearchValue] = useState(initialState.globalFilter); const { favorite, unfavorite } = useFavoriteFeaturesApi(); - const { uiConfig } = useUiConfig(); const onFavorite = useCallback( async (feature: any) => { if (feature?.favorite) { @@ -258,6 +271,10 @@ export const FeatureToggleListTable: VFC = () => { })); }, [sortBy, searchValue, setSearchParams, isFavoritesPinned]); + if (!(environments.length > 0)) { + return null; + } + return ( { > View archive + + + setShowExportDialog(true) + } + sx={theme => ({ + marginRight: theme.spacing(2), + })} + > + + + + } + /> + { /> } /> + setShowExportDialog(false)} + environments={environments} + /> + } + /> ); }; diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index 5afe0c0a88..ef83617111 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -44,6 +44,7 @@ export interface IFlags { maintenance?: boolean; messageBanner?: boolean; serviceAccounts?: boolean; + featuresExportImport?: boolean; } export interface IVersionInfo {