mirror of
https://github.com/zhigang1992/firecms.git
synced 2026-01-12 22:47:25 +08:00
Refactor of collection table internal API
This commit is contained in:
@@ -1,22 +1,8 @@
|
||||
import React, {
|
||||
MouseEvent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef
|
||||
} from "react";
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from "react";
|
||||
import BaseTable, { Column } from "react-base-table";
|
||||
import Measure, { ContentRect } from "react-measure";
|
||||
import "react-base-table/styles.css";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Paper,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme
|
||||
} from "@material-ui/core";
|
||||
import { Add, Delete } from "@material-ui/icons";
|
||||
import { Box, Paper, Typography } from "@material-ui/core";
|
||||
|
||||
import {
|
||||
AdditionalColumnDelegate,
|
||||
@@ -34,7 +20,6 @@ import { getIconForProperty } from "../util/property_icons";
|
||||
import { CollectionTableToolbar } from "./CollectionTableToolbar";
|
||||
import SkeletonComponent from "../preview/components/SkeletonComponent";
|
||||
import ErrorBoundary from "../components/ErrorBoundary";
|
||||
import DeleteEntityDialog from "./DeleteEntityDialog";
|
||||
import TableCell from "./TableCell";
|
||||
import PopupFormField from "./popup_field/PopupFormField";
|
||||
import { OutsideAlerter } from "../util/OutsideAlerter";
|
||||
@@ -46,7 +31,6 @@ import { TableCellProps } from "./SelectedCellContext";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { CircularProgressCenter } from "../components";
|
||||
import { useTableStyles } from "./styles";
|
||||
import { CollectionRowActions } from "./CollectionRowActions";
|
||||
import { getPreviewSizeFrom } from "../preview/util";
|
||||
|
||||
const PAGE_SIZE = 50;
|
||||
@@ -69,30 +53,24 @@ type Order = "asc" | "desc" | undefined;
|
||||
export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
Key extends string = string,
|
||||
P extends Properties<Key> = Properties<Key>>({
|
||||
includeToolbar,
|
||||
initialFilter,
|
||||
initialSort,
|
||||
collectionPath,
|
||||
schema,
|
||||
paginationEnabled,
|
||||
properties,
|
||||
deleteEnabled = true,
|
||||
editEnabled = true,
|
||||
excludedProperties,
|
||||
textSearchDelegate,
|
||||
additionalColumns,
|
||||
filterableProperties,
|
||||
inlineEditing,
|
||||
onNewClick,
|
||||
extraActions,
|
||||
toolbarWidgetBuilder,
|
||||
title,
|
||||
onSelection,
|
||||
tableRowWidgetBuilder,
|
||||
onEntityClick,
|
||||
onEntityDelete,
|
||||
onMultipleEntitiesDelete,
|
||||
defaultSize = "m",
|
||||
createFormField,
|
||||
selectionEnabled = true
|
||||
createFormField
|
||||
}: CollectionTableProps<S>) {
|
||||
|
||||
const [data, setData] = React.useState<Entity<S>[]>([]);
|
||||
@@ -101,9 +79,6 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
const [dataLoadingError, setDataLoadingError] = React.useState<Error | undefined>();
|
||||
const [size, setSize] = React.useState<CollectionSize>(defaultSize);
|
||||
|
||||
const [selectedItems, setSelectedItems] = React.useState<Entity<S>[]>([]);
|
||||
|
||||
const [deleteEntityClicked, setDeleteEntityClicked] = React.useState<Entity<S> | Entity<S>[] | undefined>(undefined);
|
||||
|
||||
const [textSearchInProgress, setTextSearchInProgress] = React.useState<boolean>(false);
|
||||
const [textSearchLoading, setTextSearchLoading] = React.useState<boolean>(false);
|
||||
@@ -134,50 +109,7 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
|
||||
const clickableRows = (!editEnabled || !inlineEditing) && onEntityClick;
|
||||
|
||||
const theme = useTheme();
|
||||
const largeLayout = useMediaQuery(theme.breakpoints.up("md"));
|
||||
|
||||
function buildActions() {
|
||||
const addButton = editEnabled && onNewClick && (largeLayout ?
|
||||
<Button
|
||||
onClick={onNewClick}
|
||||
startIcon={<Add/>}
|
||||
size="large"
|
||||
variant="contained"
|
||||
color="primary">
|
||||
Add {schema.name}
|
||||
</Button>
|
||||
: <Button
|
||||
onClick={onNewClick}
|
||||
size="medium"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
>
|
||||
<Add/>
|
||||
</Button>);
|
||||
|
||||
const multipleDeleteButton = selectionEnabled && deleteEnabled &&
|
||||
<Button
|
||||
disabled={!(selectedItems?.length)}
|
||||
startIcon={<Delete/>}
|
||||
onClick={(event: MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
setDeleteEntityClicked(selectedItems);
|
||||
}}
|
||||
color={"primary"}
|
||||
>
|
||||
<p style={{ minWidth: 24 }}>({selectedItems?.length})</p>
|
||||
</Button>;
|
||||
|
||||
return (
|
||||
<>
|
||||
{multipleDeleteButton}
|
||||
{addButton}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const actions = buildActions();
|
||||
const actions = toolbarWidgetBuilder && toolbarWidgetBuilder({ size });
|
||||
|
||||
const history = useHistory();
|
||||
history.listen(() => {
|
||||
@@ -197,19 +129,6 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
setPreventOutsideClick(false);
|
||||
}, []);
|
||||
|
||||
const toggleEntitySelection = (entity: Entity<S>) => {
|
||||
let newValue;
|
||||
if (selectedItems.indexOf(entity) > -1) {
|
||||
newValue = selectedItems.filter((item: Entity<S>) => item !== entity);
|
||||
} else {
|
||||
newValue = [...selectedItems, entity];
|
||||
}
|
||||
setSelectedItems(newValue);
|
||||
if (onSelection)
|
||||
onSelection(collectionPath, newValue);
|
||||
};
|
||||
|
||||
|
||||
const additionalColumnsMap: Record<string, AdditionalColumnDelegate<S>> = useMemo(() => {
|
||||
return additionalColumns ?
|
||||
additionalColumns
|
||||
@@ -388,9 +307,9 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
|
||||
const entity: Entity<S> = rowData;
|
||||
|
||||
if (columnIndex === 0) {
|
||||
return buildTableRowButtons({
|
||||
rowIndex,
|
||||
if (columnIndex === 0 && tableRowWidgetBuilder) {
|
||||
return tableRowWidgetBuilder({
|
||||
size,
|
||||
entity
|
||||
});
|
||||
}
|
||||
@@ -495,25 +414,6 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
}
|
||||
};
|
||||
|
||||
const buildTableRowButtons = ({ entity }: any) => {
|
||||
|
||||
const isSelected = selectedItems.indexOf(entity) > -1;
|
||||
|
||||
return (
|
||||
<CollectionRowActions
|
||||
entity={entity}
|
||||
isSelected={isSelected}
|
||||
collectionPath={collectionPath}
|
||||
editEnabled={editEnabled}
|
||||
deleteEnabled={deleteEnabled}
|
||||
selectionEnabled={selectionEnabled}
|
||||
size={size}
|
||||
toggleEntitySelection={toggleEntitySelection}
|
||||
onDeleteClicked={setDeleteEntityClicked}
|
||||
/>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
const headerRenderer = ({ columnIndex }: any) => {
|
||||
|
||||
@@ -651,45 +551,22 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const internalOnEntityDelete = (collectionPath: string, entity: Entity<S>) => {
|
||||
if (onEntityDelete)
|
||||
onEntityDelete(collectionPath, entity);
|
||||
setSelectedItems(selectedItems.filter((e) => e.id !== entity.id));
|
||||
};
|
||||
|
||||
const internalOnMultipleEntitiesDelete = (collectionPath: string, entities: Entity<S>[]) => {
|
||||
if (onMultipleEntitiesDelete)
|
||||
onMultipleEntitiesDelete(collectionPath, entities);
|
||||
setSelectedItems([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<DeleteEntityDialog entityOrEntitiesToDelete={deleteEntityClicked}
|
||||
collectionPath={collectionPath}
|
||||
schema={schema}
|
||||
open={!!deleteEntityClicked}
|
||||
onEntityDelete={internalOnEntityDelete}
|
||||
onMultipleEntitiesDelete={internalOnMultipleEntitiesDelete}
|
||||
onClose={() => setDeleteEntityClicked(undefined)}/>
|
||||
|
||||
<Paper className={classes.root}>
|
||||
|
||||
{includeToolbar &&
|
||||
<CollectionTableToolbar schema={schema}
|
||||
filterValues={filter}
|
||||
onTextSearch={textSearchEnabled ? onTextSearch : undefined}
|
||||
collectionPath={collectionPath}
|
||||
filterableProperties={filterableProperties}
|
||||
actions={editEnabled && actions}
|
||||
extraActions={extraActions}
|
||||
actions={actions}
|
||||
size={size}
|
||||
onSizeChanged={setSize}
|
||||
title={title}
|
||||
loading={loading}
|
||||
onFilterUpdate={onFilterUpdate}/>}
|
||||
onFilterUpdate={onFilterUpdate}/>
|
||||
|
||||
<PopupFormField
|
||||
tableKey={tableKey}
|
||||
|
||||
@@ -4,14 +4,16 @@ import {
|
||||
Entity,
|
||||
EntitySchema,
|
||||
FilterValues,
|
||||
Properties
|
||||
Properties,
|
||||
TextSearchDelegate
|
||||
} from "../models";
|
||||
import { TextSearchDelegate } from "../models/text_search_delegate";
|
||||
import { FormFieldBuilder } from "../form";
|
||||
import React from "react";
|
||||
|
||||
export interface CollectionTableProps<S extends EntitySchema,
|
||||
Key extends string = Extract<keyof S["properties"], string>,
|
||||
P extends Properties = Properties<Key>> {
|
||||
|
||||
/**
|
||||
* Absolute collection path
|
||||
*/
|
||||
@@ -22,11 +24,6 @@ export interface CollectionTableProps<S extends EntitySchema,
|
||||
*/
|
||||
schema: S;
|
||||
|
||||
/**
|
||||
* Show the toolbar in this collection
|
||||
*/
|
||||
includeToolbar: boolean;
|
||||
|
||||
/**
|
||||
* Override the title in the toolbar
|
||||
*/
|
||||
@@ -81,17 +78,6 @@ export interface CollectionTableProps<S extends EntitySchema,
|
||||
*/
|
||||
filterableProperties?: Key[];
|
||||
|
||||
/**
|
||||
* Callback when add entity is clicked
|
||||
*/
|
||||
onNewClick?: (e: React.MouseEvent) => void;
|
||||
|
||||
/**
|
||||
* Additional components such as buttons in the
|
||||
* collection toolbar
|
||||
*/
|
||||
extraActions?: React.ReactNode;
|
||||
|
||||
/**
|
||||
* Should the table add an edit button. If set to false `inlineEditing`
|
||||
* has no effect.
|
||||
@@ -108,16 +94,6 @@ export interface CollectionTableProps<S extends EntitySchema,
|
||||
*/
|
||||
deleteEnabled?: boolean;
|
||||
|
||||
/**
|
||||
* Are the entities in this collection selectable
|
||||
*/
|
||||
selectionEnabled?: boolean;
|
||||
|
||||
/**
|
||||
* Callback when entities get selected
|
||||
*/
|
||||
onSelection?(collectionPath: string, entities?: Entity<S>[]): void;
|
||||
|
||||
/**
|
||||
* Callback when anywhere on the table is clicked
|
||||
*/
|
||||
@@ -138,4 +114,20 @@ export interface CollectionTableProps<S extends EntitySchema,
|
||||
*/
|
||||
createFormField: FormFieldBuilder;
|
||||
|
||||
/**
|
||||
* Additional components builder such as buttons in the
|
||||
* collection toolbar
|
||||
*/
|
||||
toolbarWidgetBuilder?: ({ size }: { size: CollectionSize }) => React.ReactNode;
|
||||
|
||||
/**
|
||||
* Builder for creating the buttons in each row
|
||||
* @param entity
|
||||
* @param size
|
||||
*/
|
||||
tableRowWidgetBuilder?: ({
|
||||
entity,
|
||||
size
|
||||
}: { entity: Entity<S>, size: CollectionSize }) => React.ReactNode;
|
||||
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ interface CollectionTableToolbarProps<S extends EntitySchema> {
|
||||
onTextSearch?: (searchString?: string) => void;
|
||||
filterableProperties?: (keyof S["properties"])[];
|
||||
actions?: React.ReactNode;
|
||||
extraActions?: React.ReactNode;
|
||||
loading: boolean;
|
||||
title?: React.ReactNode,
|
||||
|
||||
@@ -178,8 +177,6 @@ export function CollectionTableToolbar<S extends EntitySchema>(props: Collection
|
||||
<CircularProgress size={16} thickness={8}/>}
|
||||
</Box>
|
||||
|
||||
{props.extraActions}
|
||||
|
||||
{props.actions}
|
||||
|
||||
</div>
|
||||
|
||||
183
src/collection/EntityCollectionTable.tsx
Normal file
183
src/collection/EntityCollectionTable.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import {
|
||||
CollectionSize,
|
||||
Entity,
|
||||
EntityCollectionView,
|
||||
EntitySchema
|
||||
} from "../models";
|
||||
import { CollectionTable } from "./CollectionTable";
|
||||
import { createFormField } from "../form/form_factory";
|
||||
import { Button, Typography, useMediaQuery, useTheme } from "@material-ui/core";
|
||||
import { useSelectedEntityContext } from "../side_dialog/SelectedEntityContext";
|
||||
import React, { useState } from "react";
|
||||
import { Add, Delete } from "@material-ui/icons";
|
||||
import { CollectionRowActions } from "./CollectionRowActions";
|
||||
import DeleteEntityDialog from "./DeleteEntityDialog";
|
||||
|
||||
type EntitySubCollectionProps<S extends EntitySchema> = {
|
||||
collectionPath: string;
|
||||
view: EntityCollectionView<any>;
|
||||
}
|
||||
|
||||
export function EntityCollectionTable<S extends EntitySchema>({
|
||||
collectionPath,
|
||||
view
|
||||
}: EntitySubCollectionProps<S>
|
||||
) {
|
||||
const selectedEntityContext = useSelectedEntityContext();
|
||||
|
||||
const theme = useTheme();
|
||||
const largeLayout = useMediaQuery(theme.breakpoints.up("md"));
|
||||
|
||||
const [deleteEntityClicked, setDeleteEntityClicked] = React.useState<Entity<S> | Entity<S>[] | undefined>(undefined);
|
||||
const [selectedEntities, setSelectedEntities] = useState<Entity<S>[]>([]);
|
||||
|
||||
const deleteEnabled = view.deleteEnabled === undefined || view.deleteEnabled;
|
||||
const editEnabled = view.editEnabled === undefined || view.editEnabled;
|
||||
const inlineEditing = editEnabled && (view.inlineEditing === undefined || view.inlineEditing);
|
||||
const selectionEnabled = view.selectionEnabled === undefined || view.selectionEnabled;
|
||||
const paginationEnabled = view.pagination === undefined || view.pagination;
|
||||
|
||||
const onEntityClick = (collectionPath: string, entity: Entity<S>) => {
|
||||
selectedEntityContext.open({
|
||||
entityId: entity.id,
|
||||
collectionPath
|
||||
});
|
||||
};
|
||||
|
||||
const onNewClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
return collectionPath && selectedEntityContext.open({ collectionPath });
|
||||
};
|
||||
|
||||
const internalOnEntityDelete = (collectionPath: string, entity: Entity<S>) => {
|
||||
setSelectedEntities(selectedEntities.filter((e) => e.id !== entity.id));
|
||||
};
|
||||
|
||||
const internalOnMultipleEntitiesDelete = (collectionPath: string, entities: Entity<S>[]) => {
|
||||
setSelectedEntities([]);
|
||||
};
|
||||
|
||||
const title = (
|
||||
<>
|
||||
<Typography variant="h6">
|
||||
{`${view.schema.name} list`}
|
||||
</Typography>
|
||||
<Typography variant={"caption"} color={"textSecondary"}>
|
||||
{`/${collectionPath}`}
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
|
||||
const toggleEntitySelection = (entity: Entity<S>) => {
|
||||
let newValue;
|
||||
if (selectedEntities.indexOf(entity) > -1) {
|
||||
newValue = selectedEntities.filter((item: Entity<S>) => item !== entity);
|
||||
} else {
|
||||
newValue = [...selectedEntities, entity];
|
||||
}
|
||||
setSelectedEntities(newValue);
|
||||
};
|
||||
|
||||
const tableRowButtonsBuilder = ({
|
||||
entity,
|
||||
size
|
||||
}: { entity: Entity<any>, size: CollectionSize }) => {
|
||||
|
||||
const isSelected = selectedEntities.indexOf(entity) > -1;
|
||||
|
||||
return (
|
||||
<CollectionRowActions
|
||||
entity={entity}
|
||||
isSelected={isSelected}
|
||||
collectionPath={collectionPath}
|
||||
editEnabled={editEnabled}
|
||||
deleteEnabled={deleteEnabled}
|
||||
selectionEnabled={selectionEnabled}
|
||||
size={size}
|
||||
toggleEntitySelection={toggleEntitySelection}
|
||||
onDeleteClicked={setDeleteEntityClicked}
|
||||
/>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
function toolbarActionsBuilder({ size }: { size: CollectionSize }) {
|
||||
|
||||
const addButton = editEnabled && onNewClick && (largeLayout ?
|
||||
<Button
|
||||
onClick={onNewClick}
|
||||
startIcon={<Add/>}
|
||||
size="large"
|
||||
variant="contained"
|
||||
color="primary">
|
||||
Add {view.schema.name}
|
||||
</Button>
|
||||
: <Button
|
||||
onClick={onNewClick}
|
||||
size="medium"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
>
|
||||
<Add/>
|
||||
</Button>);
|
||||
|
||||
const multipleDeleteButton = selectionEnabled && deleteEnabled &&
|
||||
<Button
|
||||
disabled={!(selectedEntities?.length)}
|
||||
startIcon={<Delete/>}
|
||||
onClick={(event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
setDeleteEntityClicked(selectedEntities);
|
||||
}}
|
||||
color={"primary"}
|
||||
>
|
||||
<p style={{ minWidth: 24 }}>({selectedEntities?.length})</p>
|
||||
</Button>;
|
||||
|
||||
const extraActions = view.extraActions ? view.extraActions({
|
||||
view: view,
|
||||
selectedEntities
|
||||
}) : undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
{extraActions}
|
||||
{multipleDeleteButton}
|
||||
{addButton}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (<>
|
||||
|
||||
<CollectionTable
|
||||
collectionPath={collectionPath}
|
||||
schema={view.schema}
|
||||
additionalColumns={view.additionalColumns}
|
||||
defaultSize={view.defaultSize}
|
||||
properties={view.properties}
|
||||
excludedProperties={view.excludedProperties}
|
||||
filterableProperties={view.filterableProperties}
|
||||
initialFilter={view.initialFilter}
|
||||
initialSort={view.initialSort}
|
||||
editEnabled={editEnabled}
|
||||
inlineEditing={inlineEditing}
|
||||
deleteEnabled={deleteEnabled}
|
||||
onEntityClick={onEntityClick}
|
||||
tableRowWidgetBuilder={tableRowButtonsBuilder}
|
||||
paginationEnabled={paginationEnabled}
|
||||
toolbarWidgetBuilder={toolbarActionsBuilder}
|
||||
title={title}
|
||||
createFormField={createFormField}
|
||||
/>
|
||||
|
||||
<DeleteEntityDialog entityOrEntitiesToDelete={deleteEntityClicked}
|
||||
collectionPath={collectionPath}
|
||||
schema={view.schema}
|
||||
open={!!deleteEntityClicked}
|
||||
onEntityDelete={internalOnEntityDelete}
|
||||
onMultipleEntitiesDelete={internalOnMultipleEntitiesDelete}
|
||||
onClose={() => setDeleteEntityClicked(undefined)}/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
import { Entity, EntityCollectionView, EntitySchema } from "../models";
|
||||
import { removeInitialSlash } from "../routes/navigation";
|
||||
import { CollectionTable } from "./CollectionTable";
|
||||
import { createFormField } from "../form/form_factory";
|
||||
import { Box, Typography } from "@material-ui/core";
|
||||
import { useSelectedEntityContext } from "../side_dialog/SelectedEntityContext";
|
||||
import React, { useState } from "react";
|
||||
|
||||
type EntitySubCollectionProps<S extends EntitySchema> = {
|
||||
entity: Entity<S>;
|
||||
view: EntityCollectionView<any>;
|
||||
onSubcollectionEntityClick: (collectionPath: string, entity: Entity<S>) => void;
|
||||
tabsPosition: number;
|
||||
colIndex: number;
|
||||
context: "main" | "side"
|
||||
}
|
||||
|
||||
export function EntityFormSubCollection<S extends EntitySchema>({
|
||||
entity,
|
||||
view,
|
||||
onSubcollectionEntityClick,
|
||||
tabsPosition,
|
||||
colIndex,
|
||||
context
|
||||
}: EntitySubCollectionProps<S>
|
||||
) {
|
||||
const selectedEntityContext = useSelectedEntityContext();
|
||||
const collectionPath = entity ? `${entity?.reference.path}/${removeInitialSlash(view.relativePath)}` : undefined;
|
||||
const onNewClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
return collectionPath && selectedEntityContext.open({ collectionPath });
|
||||
};
|
||||
|
||||
const deleteEnabled = view.deleteEnabled === undefined || view.deleteEnabled;
|
||||
const editEnabled = view.editEnabled === undefined || view.editEnabled;
|
||||
const inlineEditing = editEnabled && (view.inlineEditing === undefined || view.inlineEditing);
|
||||
const [selectedEntities, setSelectedEntities] = useState<Entity<S>[] | undefined>();
|
||||
|
||||
const onEntityPreDelete = (collectionPath: string, entity: Entity<any>) =>
|
||||
view.schema.onDelete && view.schema.onPreDelete({
|
||||
schema: view.schema,
|
||||
collectionPath,
|
||||
id: entity.id,
|
||||
entity
|
||||
});
|
||||
|
||||
const onEntityDelete = (collectionPath: string, entity: Entity<any>) =>
|
||||
view.schema.onDelete && view.schema.onDelete({
|
||||
schema: view.schema,
|
||||
collectionPath,
|
||||
id: entity.id,
|
||||
entity
|
||||
});
|
||||
|
||||
const onMultipleEntitiesDelete = (collectionPath: string, entities: Entity<any>[]) =>
|
||||
view.schema.onDelete &&
|
||||
entities.forEach((entity) => view.schema.onDelete({
|
||||
schema: view.schema,
|
||||
collectionPath,
|
||||
id: entity.id,
|
||||
entity
|
||||
}));
|
||||
|
||||
const onEntityClick = (collectionPath: string, clickedEntity: Entity<any>) =>
|
||||
onSubcollectionEntityClick(collectionPath, clickedEntity);
|
||||
|
||||
const title = (
|
||||
<Typography variant={"caption"}
|
||||
color={"textSecondary"}>
|
||||
{`/${collectionPath}`}
|
||||
</Typography>
|
||||
);
|
||||
|
||||
const extraActions = view.extraActions ? view.extraActions({
|
||||
view: view,
|
||||
selectedEntities
|
||||
}) : undefined;
|
||||
|
||||
function onSelection(collectionPath: string, entities?: Entity<S>[]) {
|
||||
setSelectedEntities(entities);
|
||||
}
|
||||
|
||||
return <Box
|
||||
key={`entity_detail_tab_content_${view.name}`}
|
||||
role="tabpanel"
|
||||
flexGrow={1}
|
||||
height={"100%"}
|
||||
width={"100%"}
|
||||
hidden={tabsPosition !== colIndex + (context === "side" ? 1 : 0)}>
|
||||
{entity && collectionPath ?
|
||||
<CollectionTable
|
||||
collectionPath={collectionPath}
|
||||
schema={view.schema}
|
||||
additionalColumns={view.additionalColumns}
|
||||
defaultSize={view.defaultSize}
|
||||
properties={view.properties}
|
||||
excludedProperties={view.excludedProperties}
|
||||
filterableProperties={view.filterableProperties}
|
||||
initialFilter={view.initialFilter}
|
||||
initialSort={view.initialSort}
|
||||
onSelection={onSelection}
|
||||
onEntityDelete={onEntityDelete}
|
||||
onMultipleEntitiesDelete={onMultipleEntitiesDelete}
|
||||
editEnabled={editEnabled}
|
||||
inlineEditing={inlineEditing}
|
||||
deleteEnabled={deleteEnabled}
|
||||
onEntityClick={onEntityClick}
|
||||
includeToolbar={true}
|
||||
paginationEnabled={false}
|
||||
extraActions={extraActions}
|
||||
title={title}
|
||||
onNewClick={onNewClick}
|
||||
createFormField={createFormField}
|
||||
/>
|
||||
:
|
||||
<Box m={3}
|
||||
display={"flex"}
|
||||
alignItems={"center"}
|
||||
justifyContent={"center"}>
|
||||
<Box>
|
||||
You need to save your entity before
|
||||
adding
|
||||
additional collections
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
</Box>;
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { useBreadcrumbsContext } from "../contexts";
|
||||
import { CollectionTable } from "../collection/CollectionTable";
|
||||
import { useSelectedEntityContext } from "../side_dialog/SelectedEntityContext";
|
||||
import { createFormField } from "../form/form_factory";
|
||||
import { EntityCollectionTable } from "../collection/EntityCollectionTable";
|
||||
|
||||
export const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
@@ -32,9 +33,6 @@ export function CollectionRoute<S extends EntitySchema>({
|
||||
: CollectionRouteProps<S>) {
|
||||
|
||||
const { url } = useRouteMatch();
|
||||
|
||||
const [selectedEntities, setSelectedEntities] = useState<Entity<S> [] | undefined>();
|
||||
|
||||
const breadcrumbsContext = useBreadcrumbsContext();
|
||||
React.useEffect(() => {
|
||||
breadcrumbsContext.set({
|
||||
@@ -42,90 +40,13 @@ export function CollectionRoute<S extends EntitySchema>({
|
||||
});
|
||||
}, [url]);
|
||||
|
||||
const selectedEntityContext = useSelectedEntityContext();
|
||||
|
||||
const onEntityClick = (collectionPath: string, entity: Entity<S>) => {
|
||||
selectedEntityContext.open({
|
||||
entityId: entity.id,
|
||||
collectionPath
|
||||
});
|
||||
};
|
||||
|
||||
const deleteEnabled = view.deleteEnabled === undefined || view.deleteEnabled;
|
||||
const editEnabled = view.editEnabled === undefined || view.editEnabled;
|
||||
const inlineEditing = editEnabled && (view.inlineEditing === undefined || view.inlineEditing);
|
||||
const selectionEnabled = view.selectionEnabled === undefined || view.selectionEnabled;
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
const onNewClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
return selectedEntityContext.open({ collectionPath });
|
||||
};
|
||||
|
||||
const title = (
|
||||
<>
|
||||
<Typography variant="h6">
|
||||
{`${view.schema.name} list`}
|
||||
</Typography>
|
||||
<Typography variant={"caption"} color={"textSecondary"}>
|
||||
{`/${collectionPath}`}
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
|
||||
const extraActions = view.extraActions ? view.extraActions({
|
||||
view: view,
|
||||
selectedEntities
|
||||
}) : undefined;
|
||||
|
||||
function onSelection(collectionPath: string, entities?: Entity<S>[]) {
|
||||
setSelectedEntities(entities);
|
||||
}
|
||||
|
||||
const onEntityDelete = (collectionPath: string, entity: Entity<any>) =>
|
||||
view.schema.onDelete && view.schema.onDelete({
|
||||
schema: view.schema,
|
||||
collectionPath,
|
||||
id: entity.id,
|
||||
entity: entity
|
||||
});
|
||||
|
||||
const onMultipleEntitiesDelete = (collectionPath: string, entities: Entity<any>[]) =>
|
||||
entities.forEach((entity) => view.schema.onDelete && view.schema.onDelete({
|
||||
schema: view.schema,
|
||||
collectionPath,
|
||||
id: entity.id,
|
||||
entity
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
|
||||
<CollectionTable collectionPath={collectionPath}
|
||||
schema={view.schema}
|
||||
onNewClick={onNewClick}
|
||||
textSearchDelegate={view.textSearchDelegate}
|
||||
includeToolbar={true}
|
||||
editEnabled={editEnabled}
|
||||
inlineEditing={inlineEditing}
|
||||
deleteEnabled={deleteEnabled}
|
||||
selectionEnabled={selectionEnabled}
|
||||
onEntityClick={onEntityClick}
|
||||
additionalColumns={view.additionalColumns}
|
||||
defaultSize={view.defaultSize}
|
||||
paginationEnabled={view.pagination === undefined ? true : view.pagination}
|
||||
initialFilter={view.initialFilter}
|
||||
initialSort={view.initialSort}
|
||||
filterableProperties={view.filterableProperties}
|
||||
properties={view.properties}
|
||||
excludedProperties={view.excludedProperties}
|
||||
onSelection={onSelection}
|
||||
onEntityDelete={onEntityDelete}
|
||||
onMultipleEntitiesDelete={onMultipleEntitiesDelete}
|
||||
extraActions={extraActions}
|
||||
title={title}
|
||||
createFormField={createFormField}/>
|
||||
<EntityCollectionTable collectionPath={collectionPath}
|
||||
view={view}/>
|
||||
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -20,7 +20,11 @@ import {
|
||||
Theme,
|
||||
Typography
|
||||
} from "@material-ui/core";
|
||||
import { BreadcrumbEntry, getEntityPath } from "./navigation";
|
||||
import {
|
||||
BreadcrumbEntry,
|
||||
getEntityPath,
|
||||
removeInitialSlash
|
||||
} from "./navigation";
|
||||
import { CircularProgressCenter } from "../components";
|
||||
import { useSelectedEntityContext } from "../side_dialog/SelectedEntityContext";
|
||||
import { useBreadcrumbsContext, useSnackbarController } from "../contexts";
|
||||
@@ -35,7 +39,7 @@ import {
|
||||
import CloseIcon from "@material-ui/icons/Close";
|
||||
import OpenInBrowserIcon from "@material-ui/icons/OpenInBrowser";
|
||||
import { EntityPreview } from "../preview";
|
||||
import { EntityFormSubCollection } from "../collection/EntitySubcollection";
|
||||
import { EntityCollectionTable } from "../collection/EntityCollectionTable";
|
||||
|
||||
|
||||
const useStylesSide = makeStyles((theme: Theme) =>
|
||||
@@ -226,14 +230,6 @@ function EntityFormRoute<S extends EntitySchema>({
|
||||
}, [location["subcollection"]]);
|
||||
|
||||
|
||||
function onSubcollectionEntityClick(collectionPath: string,
|
||||
entity: Entity<S>) {
|
||||
selectedEntityContext.open({
|
||||
entityId: entity.id,
|
||||
collectionPath
|
||||
});
|
||||
}
|
||||
|
||||
async function onEntitySave(schema: S, collectionPath: string, id: string | undefined, values: EntityValues<S>): Promise<void> {
|
||||
|
||||
if (!status)
|
||||
@@ -342,14 +338,34 @@ function EntityFormRoute<S extends EntitySchema>({
|
||||
|
||||
const subCollectionsView = view.subcollections && view.subcollections.map(
|
||||
(subcollectionView, colIndex) => {
|
||||
return EntityFormSubCollection({
|
||||
entity: entity as Entity<S>,
|
||||
view: subcollectionView,
|
||||
onSubcollectionEntityClick,
|
||||
tabsPosition,
|
||||
colIndex,
|
||||
context
|
||||
});
|
||||
const collectionPath = entity ? `${entity?.reference.path}/${removeInitialSlash(subcollectionView.relativePath)}` : undefined;
|
||||
|
||||
return (
|
||||
<Box
|
||||
key={`entity_detail_tab_content_${view.name}`}
|
||||
role="tabpanel"
|
||||
flexGrow={1}
|
||||
height={"100%"}
|
||||
width={"100%"}
|
||||
hidden={tabsPosition !== colIndex + (context === "side" ? 1 : 0)}>
|
||||
{entity && collectionPath ?
|
||||
<EntityCollectionTable collectionPath={collectionPath}
|
||||
view={subcollectionView}
|
||||
/>
|
||||
:
|
||||
<Box m={3}
|
||||
display={"flex"}
|
||||
alignItems={"center"}
|
||||
justifyContent={"center"}>
|
||||
<Box>
|
||||
You need to save your entity before
|
||||
adding
|
||||
additional collections
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"node_modules",
|
||||
"dist",
|
||||
"example",
|
||||
"example_backend",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user