Refactor of collection table internal API

This commit is contained in:
francesco
2021-01-28 22:19:18 +01:00
parent 8494764173
commit ea2fadb61c
8 changed files with 252 additions and 393 deletions

View File

@@ -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}

View File

@@ -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;
}

View File

@@ -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>

View 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)}/>
</>
);
}

View File

@@ -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>;
}

View File

@@ -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>
);

View File

@@ -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>
);
}
);

View File

@@ -36,6 +36,7 @@
"node_modules",
"dist",
"example",
"example_backend",
"test"
]
}