1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-21 13:47:39 +02:00

Project Archive

This commit is contained in:
andreas-unleash 2022-06-06 12:12:28 +03:00
parent b622767ae9
commit 406c187372
5 changed files with 201 additions and 89 deletions

View File

@ -10,7 +10,6 @@ import {
TableSearch, TableSearch,
} from 'component/common/Table'; } from 'component/common/Table';
import { import {
SortingRule,
useFlexLayout, useFlexLayout,
useGlobalFilter, useGlobalFilter,
useSortBy, useSortBy,
@ -23,7 +22,6 @@ import { useEffect, useMemo, useState } from 'react';
import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell'; import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell';
import { DateCell } from 'component/common/Table/cells/DateCell/DateCell'; import { DateCell } from 'component/common/Table/cells/DateCell/DateCell';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useFeaturesArchive } from '../../../hooks/api/getters/useFeaturesArchive/useFeaturesArchive';
import { FeatureTypeCell } from '../../common/Table/cells/FeatureTypeCell/FeatureTypeCell'; import { FeatureTypeCell } from '../../common/Table/cells/FeatureTypeCell/FeatureTypeCell';
import { FeatureSeenCell } from '../../common/Table/cells/FeatureSeenCell/FeatureSeenCell'; import { FeatureSeenCell } from '../../common/Table/cells/FeatureSeenCell/FeatureSeenCell';
import { LinkCell } from '../../common/Table/cells/LinkCell/LinkCell'; import { LinkCell } from '../../common/Table/cells/LinkCell/LinkCell';
@ -31,28 +29,61 @@ import { FeatureStaleCell } from '../../feature/FeatureToggleList/FeatureStaleCe
import { TimeAgoCell } from '../../common/Table/cells/TimeAgoCell/TimeAgoCell'; import { TimeAgoCell } from '../../common/Table/cells/TimeAgoCell/TimeAgoCell';
import { ReviveArchivedFeatureCell } from 'component/common/Table/cells/ReviveArchivedFeatureCell/ReviveArchivedFeatureCell'; import { ReviveArchivedFeatureCell } from 'component/common/Table/cells/ReviveArchivedFeatureCell/ReviveArchivedFeatureCell';
import { useStyles } from '../../feature/FeatureToggleList/styles'; import { useStyles } from '../../feature/FeatureToggleList/styles';
import { useSearchParams } from 'react-router-dom';
import { useLocalStorage } from '../../../hooks/useLocalStorage';
import { useVirtualizedRange } from '../../../hooks/useVirtualizedRange'; import { useVirtualizedRange } from '../../../hooks/useVirtualizedRange';
import { import {
featuresPlaceholder, featuresPlaceholder,
PageQueryType, PageQueryType,
} from '../../feature/FeatureToggleList/FeatureToggleListTable'; } from '../../feature/FeatureToggleList/FeatureToggleListTable';
import theme from 'themes/theme'; import theme from 'themes/theme';
import { FeatureSchema } from '../../../openapi';
import { useFeatureArchiveApi } from '../../../hooks/api/actions/useFeatureArchiveApi/useReviveFeatureApi';
import useToast from '../../../hooks/useToast';
const defaultSort: SortingRule<string> = { id: 'createdAt', desc: true }; export interface IFeaturesArchiveTableProps {
archivedFeatures: FeatureSchema[];
refetch: any;
loading: boolean;
inProject: boolean;
storedParams: any;
setStoredParams: any;
searchParams: any;
setSearchParams: any;
}
export const ArchiveTable = () => { export const ArchiveTable = ({
archivedFeatures = [],
loading,
inProject,
refetch,
storedParams,
setStoredParams,
searchParams,
setSearchParams,
}: IFeaturesArchiveTableProps) => {
const rowHeight = theme.shape.tableRowHeight; const rowHeight = theme.shape.tableRowHeight;
const { classes } = useStyles(); const { classes } = useStyles();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg')); const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg'));
const [searchParams, setSearchParams] = useSearchParams(); const { setToastData, setToastApiError } = useToast();
const [storedParams, setStoredParams] = useLocalStorage(
'ArchiveTable:v1', const { reviveFeature } = useFeatureArchiveApi();
defaultSort
); const onRevive = (feature: string) => {
const { archivedFeatures = [], loading } = useFeaturesArchive(); reviveFeature(feature)
.then(refetch)
.then(() =>
setToastData({
type: 'success',
title: "And we're back!",
text: 'The feature toggle has been revived.',
confetti: true,
})
)
.catch(e => setToastApiError(e.toString()));
};
const columns = useColumns(onRevive);
const data = useMemo( const data = useMemo(
() => () =>
archivedFeatures?.length === 0 && loading archivedFeatures?.length === 0 && loading
@ -85,7 +116,7 @@ export const ArchiveTable = () => {
setHiddenColumns, setHiddenColumns,
} = useTable( } = useTable(
{ {
columns: COLUMNS as any, columns: columns as any,
data: data as any, data: data as any,
initialState, initialState,
sortTypes, sortTypes,
@ -134,7 +165,9 @@ export const ArchiveTable = () => {
isLoading={loading} isLoading={loading}
header={ header={
<PageHeader <PageHeader
title={`Archived (${ title={`${
inProject ? 'Project Features Archive' : 'Archived'
} (${
rows.length < data.length rows.length < data.length
? `${rows.length} of ${data.length}` ? `${rows.length} of ${data.length}`
: data.length : data.length
@ -216,72 +249,78 @@ export const ArchiveTable = () => {
); );
}; };
const COLUMNS = [ const useColumns = (onRevive: any) => {
{ return [
id: 'Seen', {
Header: 'Seen', id: 'Seen',
maxWidth: 85, Header: 'Seen',
canSort: true, maxWidth: 85,
Cell: FeatureSeenCell, canSort: true,
disableGlobalFilter: true, Cell: FeatureSeenCell,
}, disableGlobalFilter: true,
{ },
id: 'Type', {
Header: 'Type', id: 'Type',
maxWidth: 85, Header: 'Type',
canSort: true, maxWidth: 85,
Cell: FeatureTypeCell, canSort: true,
disableGlobalFilter: true, Cell: FeatureTypeCell,
}, disableGlobalFilter: true,
{ },
Header: 'Feature toggle Name', {
accessor: 'name', Header: 'Feature toggle Name',
maxWidth: 150, accessor: 'name',
Cell: ({ value, row: { original } }: any) => ( maxWidth: 150,
<HighlightCell value={value} subtitle={original.description} /> Cell: ({ value, row: { original } }: any) => (
), <HighlightCell value={value} subtitle={original.description} />
sortType: 'alphanumeric', ),
}, sortType: 'alphanumeric',
{ },
Header: 'Created', {
accessor: 'createdAt', Header: 'Created',
maxWidth: 150, accessor: 'createdAt',
Cell: DateCell, maxWidth: 150,
sortType: 'date', Cell: DateCell,
disableGlobalFilter: true, sortType: 'date',
}, disableGlobalFilter: true,
{ },
Header: 'Archived', {
accessor: 'archivedAt', Header: 'Archived',
maxWidth: 150, accessor: 'archivedAt',
Cell: TimeAgoCell, maxWidth: 150,
sortType: 'date', Cell: TimeAgoCell,
disableGlobalFilter: true, sortType: 'date',
}, disableGlobalFilter: true,
{ },
Header: 'Project ID', {
accessor: 'project', Header: 'Project ID',
sortType: 'alphanumeric', accessor: 'project',
maxWidth: 150, sortType: 'alphanumeric',
Cell: ({ value }: any) => ( maxWidth: 150,
<LinkCell title={value} to={`/projects/${value}}`} /> Cell: ({ value }: any) => (
), <LinkCell title={value} to={`/projects/${value}}`} />
}, ),
{ },
Header: 'Status', {
accessor: 'stale', Header: 'Status',
Cell: FeatureStaleCell, accessor: 'stale',
sortType: 'boolean', Cell: FeatureStaleCell,
maxWidth: 120, sortType: 'boolean',
disableGlobalFilter: true, maxWidth: 120,
}, disableGlobalFilter: true,
{ },
Header: 'Actions', {
id: 'Actions', Header: 'Actions',
align: 'center', id: 'Actions',
maxWidth: 85, align: 'center',
canSort: false, maxWidth: 85,
disableGlobalFilter: true, canSort: false,
Cell: ReviveArchivedFeatureCell, disableGlobalFilter: true,
}, Cell: ({ row: { original } }: any) => (
]; <ReviveArchivedFeatureCell
onRevive={() => onRevive(original.name)}
/>
),
},
];
};

View File

@ -0,0 +1,34 @@
import { useFeaturesArchive } from '../../hooks/api/getters/useFeaturesArchive/useFeaturesArchive';
import { ArchiveTable } from './ArchiveTable/ArchiveTable';
import { useSearchParams } from 'react-router-dom';
import { useLocalStorage } from '../../hooks/useLocalStorage';
import { SortingRule } from 'react-table';
const defaultSort: SortingRule<string> = { id: 'createdAt', desc: true };
export const FeaturesArchiveTable = () => {
const {
archivedFeatures = [],
loading,
refetchArchived,
} = useFeaturesArchive();
const [searchParams, setSearchParams] = useSearchParams();
const [storedParams, setStoredParams] = useLocalStorage(
'FeaturesArchiveTable:v1',
defaultSort
);
return (
<ArchiveTable
archivedFeatures={archivedFeatures}
loading={loading}
searchParams={searchParams}
setSearchParams={setSearchParams}
storedParams={storedParams}
setStoredParams={setStoredParams}
refetch={refetchArchived}
inProject={false}
/>
);
};

View File

@ -0,0 +1,40 @@
import { ArchiveTable } from './ArchiveTable/ArchiveTable';
import { useSearchParams } from 'react-router-dom';
import { useLocalStorage } from '../../hooks/useLocalStorage';
import { SortingRule } from 'react-table';
import { useProjectFeaturesArchive } from '../../hooks/api/getters/useProjectFeaturesArchive/useProjectFeaturesArchive';
const defaultSort: SortingRule<string> = { id: 'archivedAt', desc: true };
interface IProjectFeaturesTable {
projectId: string;
}
export const ProjectFeaturesArchiveTable = ({
projectId,
}: IProjectFeaturesTable) => {
const {
archivedFeatures = [],
refetchArchived,
loading,
} = useProjectFeaturesArchive(projectId);
const [searchParams, setSearchParams] = useSearchParams();
const [storedParams, setStoredParams] = useLocalStorage(
'ProjectFeaturesArchiveTable:v1',
defaultSort
);
return (
<ArchiveTable
archivedFeatures={archivedFeatures}
loading={loading}
searchParams={searchParams}
setSearchParams={setSearchParams}
storedParams={storedParams}
setStoredParams={setStoredParams}
refetch={refetchArchived}
inProject={true}
/>
);
};

View File

@ -51,7 +51,7 @@ import { IRoute } from 'interfaces/route';
import { EnvironmentTable } from 'component/environments/EnvironmentTable/EnvironmentTable'; import { EnvironmentTable } from 'component/environments/EnvironmentTable/EnvironmentTable';
import { SegmentTable } from 'component/segments/SegmentTable/SegmentTable'; import { SegmentTable } from 'component/segments/SegmentTable/SegmentTable';
import RedirectAdminInvoices from 'component/admin/billing/RedirectAdminInvoices/RedirectAdminInvoices'; import RedirectAdminInvoices from 'component/admin/billing/RedirectAdminInvoices/RedirectAdminInvoices';
import { ArchiveTable } from '../archive/ArchiveTable/ArchiveTable'; import { FeaturesArchiveTable } from '../archive/FeaturesArchiveTable';
export const routes: IRoute[] = [ export const routes: IRoute[] = [
// Splash // Splash
@ -375,7 +375,7 @@ export const routes: IRoute[] = [
{ {
path: '/archive', path: '/archive',
title: 'Archived toggles', title: 'Archived toggles',
component: ArchiveTable, component: FeaturesArchiveTable,
type: 'protected', type: 'protected',
menu: {}, menu: {},
}, },

View File

@ -1,5 +1,4 @@
import { ProjectFeaturesArchiveList } from 'component/archive/ProjectFeaturesArchiveList'; import { ProjectFeaturesArchiveTable } from '../../../archive/ProjectFeaturesArchiveTable';
import { usePageTitle } from 'hooks/usePageTitle';
interface IProjectFeaturesArchiveProps { interface IProjectFeaturesArchiveProps {
projectId: string; projectId: string;
@ -8,7 +7,7 @@ interface IProjectFeaturesArchiveProps {
export const ProjectFeaturesArchive = ({ export const ProjectFeaturesArchive = ({
projectId, projectId,
}: IProjectFeaturesArchiveProps) => { }: IProjectFeaturesArchiveProps) => {
usePageTitle('Project Archived Features'); // usePageTitle('Project Archived Features');
return <ProjectFeaturesArchiveList projectId={projectId} />; return <ProjectFeaturesArchiveTable projectId={projectId} />;
}; };