Bulk deletion of pages

This commit is contained in:
Kacper Donat 2020-11-14 22:38:39 +01:00
parent 24e2527c1b
commit 08e1467bb1
4 changed files with 32 additions and 10 deletions

View File

@ -2,6 +2,7 @@ export type Nullable<T> = { [P in keyof T]: T[P] | null }
export type Subset<T> = { [K in keyof T]?: Subset<T[K]> } export type Subset<T> = { [K in keyof T]?: Subset<T[K]> }
export type Dictionary<T> = { [key: string]: T }; export type Dictionary<T> = { [key: string]: T };
export type OneOrMany<T> = T | T[];
export type Index = string | symbol | number; export type Index = string | symbol | number;
@ -27,7 +28,7 @@ export function throttle<TArgs extends any[]>(decorated: (...args: TArgs) => voi
} }
} }
export function encapsulate<T>(value: T|T[]): T[] { export function encapsulate<T>(value: OneOrMany<T>): T[] {
if (value instanceof Array) { if (value instanceof Array) {
return value; return value;
} }
@ -35,7 +36,7 @@ export function encapsulate<T>(value: T|T[]): T[] {
return [ value ]; return [ value ];
} }
export function one<T>(value: T|T[]): T { export function one<T>(value: OneOrMany<T>): T {
if (value instanceof Array) { if (value instanceof Array) {
return value[0]; return value[0];
} }

View File

@ -3,6 +3,7 @@ import pageDtoTransformer, { PageDTO } from "@/api/dto/page";
import { axios } from "@/api"; import { axios } from "@/api";
import { STATIC_PAGE_ENDPOINT } from "@/api/page"; import { STATIC_PAGE_ENDPOINT } from "@/api/page";
import { prepare } from "@/routing"; import { prepare } from "@/routing";
import { encapsulate, OneOrMany } from "@/helpers";
const STATIC_PAGE_INDEX_ENDPOINT = "/staticPage"; const STATIC_PAGE_INDEX_ENDPOINT = "/staticPage";
@ -13,8 +14,10 @@ export async function all(): Promise<Page[]> {
return response.data.map(dto => pageDtoTransformer.transform(dto)); return response.data.map(dto => pageDtoTransformer.transform(dto));
} }
export async function remove(page: Pick<Page, "slug">): Promise<void> { export async function remove(page: OneOrMany<Pick<Page, "slug">>): Promise<void> {
await axios.delete(prepare(STATIC_PAGE_ENDPOINT, { slug: page.slug })); const pages = encapsulate(page);
await Promise.all(pages.map(page => axios.delete(prepare(STATIC_PAGE_ENDPOINT, { slug: page.slug }))));
} }
export async function save(page: Page): Promise<Page> { export async function save(page: Page): Promise<Page> {

View File

@ -9,7 +9,7 @@ import { Async } from "@/components/async";
import MaterialTable, { Action, Column } from "material-table"; import MaterialTable, { Action, Column } from "material-table";
import { default as StaticPage } from "@/data/page"; import { default as StaticPage } from "@/data/page";
import { Delete, FileFind, Pencil, Refresh } from "mdi-material-ui"; import { Delete, FileFind, Pencil, Refresh } from "mdi-material-ui";
import { encapsulate, one } from "@/helpers"; import { encapsulate, one, OneOrMany } from "@/helpers";
import { Actions } from "@/components"; import { Actions } from "@/components";
import { useSpacing } from "@/styles"; import { useSpacing } from "@/styles";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
@ -21,6 +21,7 @@ import { Confirm } from "@/components/confirm";
export const StaticPageManagement = () => { export const StaticPageManagement = () => {
const { t } = useTranslation("management"); const { t } = useTranslation("management");
const [ result, setPagesPromise ] = useAsyncState<StaticPage[]>(); const [ result, setPagesPromise ] = useAsyncState<StaticPage[]>();
const [ selected, setSelected ] = useState<StaticPage[]>([]);
const spacing = useSpacing(2); const spacing = useSpacing(2);
const updatePageList = () => { const updatePageList = () => {
@ -67,20 +68,28 @@ export const StaticPageManagement = () => {
</> </>
} }
const DeleteStaticPageAction = ({ page }: { page: StaticPage }) => { const DeleteStaticPageAction = ({ page, children }: { page: OneOrMany<StaticPage>, children?: (action: any) => React.ReactNode }) => {
const handlePageDeletion = async () => { const handlePageDeletion = async () => {
await api.page.remove(page); await api.page.remove(page);
updatePageList(); updatePageList();
} }
const confirmation = <> const confirmation = <>
<Trans i18nKey="page.confirm.delete"> { !Array.isArray(page)
Czy na pewno chcesz usunąć stronę <strong>{ page.title.pl }</strong>? ? <Trans i18nKey="page.confirm.delete">
</Trans> Czy na pewno chcesz usunąć stronę <strong>{ page.title.pl }</strong>?
</Trans>
: <>
{ t("page.confirm.bulk-delete") }
<ul>
{ page.map(page => <li key={ page.slug }>{ page.title.pl }</li>) }
</ul>
</>
}
</>; </>;
return <Confirm onConfirm={ handlePageDeletion } content={ confirmation }> return <Confirm onConfirm={ handlePageDeletion } content={ confirmation }>
{ action => <Tooltip title={ t("actions.delete") as string }><IconButton onClick={ action }><Delete /></IconButton></Tooltip> } { action => children ? children(action) : <Tooltip title={ t("actions.delete") as string }><IconButton onClick={ action }><Delete /></IconButton></Tooltip> }
</Confirm>; </Confirm>;
} }
@ -143,12 +152,19 @@ export const StaticPageManagement = () => {
<CreateStaticPageAction /> <CreateStaticPageAction />
<Button onClick={ updatePageList } startIcon={ <Refresh /> }>{ t("refresh") }</Button> <Button onClick={ updatePageList } startIcon={ <Refresh /> }>{ t("refresh") }</Button>
</Actions> </Actions>
{ selected.length > 0 && <Actions>
<DeleteStaticPageAction page={ selected }>
{ action => <Button startIcon={ <Delete /> } onClick={ action }>{ t("actions.delete") }</Button> }
</DeleteStaticPageAction>
</Actions> }
<Async async={ result } keepValue>{ <Async async={ result } keepValue>{
pages => <MaterialTable pages => <MaterialTable
title={ <div style={{ display: "flex", alignItems: "center" }}>{ t("page.index.title") } { result.isLoading && <CircularProgress size="1.5rem" style={{ marginLeft: "1rem" }}/> }</div> } title={ <div style={{ display: "flex", alignItems: "center" }}>{ t("page.index.title") } { result.isLoading && <CircularProgress size="1.5rem" style={{ marginLeft: "1rem" }}/> }</div> }
columns={ columns } columns={ columns }
data={ pages } data={ pages }
detailPanel={ page => <PagePreview page={ page } /> } detailPanel={ page => <PagePreview page={ page } /> }
onSelectionChange={ pages => setSelected(pages) }
options={{ selection: true }}
/> />
}</Async> }</Async>
</Container> </Container>

View File

@ -31,3 +31,5 @@ page:
title: Utwórz stronę statyczną title: Utwórz stronę statyczną
edit: edit:
title: Zmień stronę statyczną title: Zmień stronę statyczną
confirm:
bulk-delete: Czy na pewno chcesz usunąć wszystkie wybrane strony?