Skip to content

Commit

Permalink
UI/bulk select (#3267)
Browse files Browse the repository at this point in the history
Select multiple toggles on project overview.
  • Loading branch information
Tymek committed Mar 14, 2023
1 parent cb75a68 commit 30a753b
Show file tree
Hide file tree
Showing 13 changed files with 406 additions and 213 deletions.
Expand Up @@ -23,7 +23,13 @@ import {
IPersonalAPIToken,
} from 'interfaces/personalAPIToken';
import { useMemo, useState } from 'react';
import { useTable, SortingRule, useSortBy, useFlexLayout } from 'react-table';
import {
useTable,
SortingRule,
useSortBy,
useFlexLayout,
Column,
} from 'react-table';
import { sortTypes } from 'utils/sortTypes';
import { ServiceAccountCreateTokenDialog } from './ServiceAccountCreateTokenDialog/ServiceAccountCreateTokenDialog';
import { ServiceAccountTokenDialog } from 'component/admin/serviceAccounts/ServiceAccountsTable/ServiceAccountTokenDialog/ServiceAccountTokenDialog';
Expand Down Expand Up @@ -151,65 +157,69 @@ export const ServiceAccountTokens = ({
};

const columns = useMemo(
() => [
{
Header: 'Description',
accessor: 'description',
Cell: HighlightCell,
minWidth: 100,
searchable: true,
},
{
Header: 'Expires',
accessor: 'expiresAt',
Cell: ({ value }: { value: string }) => {
const date = new Date(value);
if (date.getFullYear() > new Date().getFullYear() + 100) {
return <TextCell>Never</TextCell>;
}
return <DateCell value={value} />;
() =>
[
{
Header: 'Description',
accessor: 'description',
Cell: HighlightCell,
minWidth: 100,
searchable: true,
},
sortType: 'date',
maxWidth: 150,
},
{
Header: 'Created',
accessor: 'createdAt',
Cell: DateCell,
sortType: 'date',
maxWidth: 150,
},
{
Header: 'Last seen',
accessor: 'seenAt',
Cell: TimeAgoCell,
sortType: 'date',
maxWidth: 150,
},
{
Header: 'Actions',
id: 'Actions',
align: 'center',
Cell: ({ row: { original: rowToken } }: any) => (
<ActionCell>
<Tooltip title="Delete token" arrow describeChild>
<span>
<IconButton
onClick={() => {
setSelectedToken(rowToken);
setDeleteOpen(true);
}}
>
<Delete />
</IconButton>
</span>
</Tooltip>
</ActionCell>
),
maxWidth: 100,
disableSortBy: true,
},
],
{
Header: 'Expires',
accessor: 'expiresAt',
Cell: ({ value }: { value: string }) => {
const date = new Date(value);
if (
date.getFullYear() >
new Date().getFullYear() + 100
) {
return <TextCell>Never</TextCell>;
}
return <DateCell value={value} />;
},
sortType: 'date',
maxWidth: 150,
},
{
Header: 'Created',
accessor: 'createdAt',
Cell: DateCell,
sortType: 'date',
maxWidth: 150,
},
{
Header: 'Last seen',
accessor: 'seenAt',
Cell: TimeAgoCell,
sortType: 'date',
maxWidth: 150,
},
{
Header: 'Actions',
id: 'Actions',
align: 'center',
Cell: ({ row: { original: rowToken } }: any) => (
<ActionCell>
<Tooltip title="Delete token" arrow describeChild>
<span>
<IconButton
onClick={() => {
setSelectedToken(rowToken);
setDeleteOpen(true);
}}
>
<Delete />
</IconButton>
</span>
</Tooltip>
</ActionCell>
),
maxWidth: 100,
disableSortBy: true,
},
] as Column<IPersonalAPIToken>[],
[setSelectedToken, setDeleteOpen]
);

Expand Down
@@ -1,23 +1,20 @@
import { VFC } from 'react';
import { TableHead, TableRow } from '@mui/material';
import { HeaderGroup } from 'react-table';
import { CellSortable } from './CellSortable/CellSortable';

interface ISortableTableHeaderProps {
headerGroups: HeaderGroup<object>[];
className?: string;
flex?: boolean;
}

export const SortableTableHeader: VFC<ISortableTableHeaderProps> = ({
export const SortableTableHeader = <T extends object>({
headerGroups,
className,
flex,
}: {
headerGroups: HeaderGroup<T>[];
className?: string;
flex?: boolean;
}) => (
<TableHead className={className}>
{headerGroups.map(headerGroup => (
<TableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column: HeaderGroup) => {
{headerGroup.headers.map((column: HeaderGroup<T>) => {
const content = column.render('Header');

return (
Expand Down
@@ -1,4 +1,4 @@
import { useMemo, VFC } from 'react';
import { useMemo } from 'react';
import { useTheme } from '@mui/material';
import {
SortableTableHeader,
Expand All @@ -10,13 +10,6 @@ import {
import { useVirtualizedRange } from 'hooks/useVirtualizedRange';
import { HeaderGroup, Row } from 'react-table';

interface IVirtualizedTableProps {
rowHeight?: number;
headerGroups: HeaderGroup<object>[];
rows: Row<object>[];
prepareRow: (row: Row) => void;
}

/**
* READ BEFORE USE
*
Expand All @@ -27,11 +20,16 @@ interface IVirtualizedTableProps {
* Remember to add `useFlexLayout` to `useTable`
* (more at: https://react-table-v7.tanstack.com/docs/api/useFlexLayout)
*/
export const VirtualizedTable: VFC<IVirtualizedTableProps> = ({
export const VirtualizedTable = <T extends object>({
rowHeight: rowHeightOverride,
headerGroups,
rows,
prepareRow,
}: {
rowHeight?: number;
headerGroups: HeaderGroup<T>[];
rows: Row<T>[];
prepareRow: (row: Row<T>) => void;
}) => {
const theme = useTheme();
const rowHeight = useMemo(
Expand Down
18 changes: 7 additions & 11 deletions frontend/src/component/feature/FeatureToggleList/ExportDialog.tsx
@@ -1,16 +1,16 @@
import { createRef, useState } from 'react';
import { styled, Typography, Box } from '@mui/material';
import { Dialogue } from 'component/common/Dialogue/Dialogue';
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
import { useExportApi } from 'hooks/api/actions/useExportApi/useExportApi';
import useToast from 'hooks/useToast';
import { FeatureSchema } from 'openapi';
import type { FeatureSchema } from 'openapi';

import { createRef, useEffect, useState } from 'react';
import { formatUnknownError } from 'utils/formatUnknownError';

interface IExportDialogProps {
showExportDialog: boolean;
data: FeatureSchema[];
data: Pick<FeatureSchema, 'name'>[];
onClose: () => void;
environments: string[];
}
Expand All @@ -37,13 +37,6 @@ export const ExportDialog = ({
label: env,
}));

const getPayload = () => {
return {
features: data.map(feature => feature.name),
environment: selected,
};
};

const downloadFile = (json: any) => {
const link = document.createElement('a');
ref.current?.appendChild(link);
Expand All @@ -65,7 +58,10 @@ export const ExportDialog = ({

const onClick = async () => {
try {
const payload = getPayload();
const payload = {
features: data.map(feature => feature.name),
environment: selected,
};
const res = await createExport(payload);
const body = await res.json();
downloadFile(body);
Expand Down

0 comments on commit 30a753b

Please sign in to comment.