mirror of
https://github.com/zhigang1992/firecms.git
synced 2026-06-14 09:38:59 +08:00
Styles and keys refactor for enhanced performance.
Version 0.21.1
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
# Change Log
|
||||
|
||||
## [0.21.0] - 2020-12-15
|
||||
## [0.21.1] - 2020-12-30
|
||||
### Changed
|
||||
- Table performance improvements
|
||||
|
||||
## [0.21.0] - 2020-12-29
|
||||
### Added
|
||||
- Inline editing of tables. Tables are now editable by default. There are two new
|
||||
parameters you can set in entity collection views.
|
||||
@@ -8,7 +12,6 @@ parameters you can set in entity collection views.
|
||||
edit or create new entities.
|
||||
- `inlineEditing` defaults to true. If false, the users can still edit the
|
||||
content, but the inline editing is disabled. The side panel is still enabled.
|
||||
|
||||
### Changed
|
||||
- [BREAKING] The custom fields API has been refactored and simplified. The Formik
|
||||
props have been abstracted away and only the relevant fields are exposed.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@camberi/firecms",
|
||||
"version": "0.21.0",
|
||||
"version": "0.21.1",
|
||||
"description": "Awesome Firestore based CMS",
|
||||
"author": "camberi",
|
||||
"license": "GPL-3.0",
|
||||
|
||||
@@ -32,7 +32,7 @@ import { getIconForProperty } from "../util/property_icons";
|
||||
import { CollectionTableToolbar } from "./CollectionTableToolbar";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import KeyboardTabIcon from "@material-ui/icons/KeyboardTab";
|
||||
import SkeletonComponent, { renderSkeletonText } from "../preview/SkeletonComponent";
|
||||
import SkeletonComponent, { renderSkeletonText } from "../preview/components/SkeletonComponent";
|
||||
import ErrorBoundary from "../components/ErrorBoundary";
|
||||
import { getPreviewSizeFrom } from "../preview/PreviewComponentProps";
|
||||
import DeleteEntityDialog from "./DeleteEntityDialog";
|
||||
@@ -388,20 +388,24 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
|
||||
if (column.type === "property") {
|
||||
if (!editEnabled || !inlineEditing) {
|
||||
return <PreviewTableCell
|
||||
size={size}
|
||||
align={column.align}>
|
||||
<PreviewComponent
|
||||
name={propertyKey}
|
||||
value={entity.values[propertyKey]}
|
||||
property={property}
|
||||
size={getPreviewSizeFrom(size)}
|
||||
entitySchema={schema}
|
||||
/>
|
||||
</PreviewTableCell>;
|
||||
return (
|
||||
<PreviewTableCell
|
||||
key={`preview_cell_${propertyKey}_${rowIndex}_${columnIndex}`}
|
||||
size={size}
|
||||
align={column.align}>
|
||||
<PreviewComponent
|
||||
name={`preview_${propertyKey}_${rowIndex}_${columnIndex}`}
|
||||
value={entity.values[propertyKey]}
|
||||
property={property}
|
||||
size={getPreviewSizeFrom(size)}
|
||||
entitySchema={schema}
|
||||
/>
|
||||
</PreviewTableCell>
|
||||
);
|
||||
} else if (property.disabled || !editEnabled) {
|
||||
return (
|
||||
<DisabledTableCell
|
||||
key={`disabled_cell_${propertyKey}_${rowIndex}_${columnIndex}`}
|
||||
size={size}
|
||||
align={column.align}>
|
||||
<PreviewComponent
|
||||
@@ -438,25 +442,27 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
const isFocused = selected && focused;
|
||||
|
||||
return entity ?
|
||||
<TableCell tableKey={tableKey}
|
||||
size={size}
|
||||
align={column.align}
|
||||
name={propertyKey}
|
||||
path={collectionPath}
|
||||
entity={entity}
|
||||
schema={schema}
|
||||
selected={selected}
|
||||
focused={isFocused}
|
||||
setPreventOutsideClick={setPreventOutsideClick}
|
||||
setFocused={setFocused}
|
||||
value={entity.values[propertyKey]}
|
||||
columnIndex={columnIndex}
|
||||
rowIndex={rowIndex}
|
||||
CollectionTable={CollectionTable}
|
||||
property={property}
|
||||
openPopup={openPopup}
|
||||
select={onSelect}
|
||||
createFormField={createFormField}/>
|
||||
<TableCell
|
||||
key={`table_cell_${propertyKey}_${rowIndex}_${columnIndex}`}
|
||||
tableKey={tableKey}
|
||||
size={size}
|
||||
align={column.align}
|
||||
name={propertyKey}
|
||||
path={collectionPath}
|
||||
entity={entity}
|
||||
schema={schema}
|
||||
selected={selected}
|
||||
focused={isFocused}
|
||||
setPreventOutsideClick={setPreventOutsideClick}
|
||||
setFocused={setFocused}
|
||||
value={entity.values[propertyKey]}
|
||||
columnIndex={columnIndex}
|
||||
rowIndex={rowIndex}
|
||||
CollectionTable={CollectionTable}
|
||||
property={property}
|
||||
openPopup={openPopup}
|
||||
select={onSelect}
|
||||
createFormField={createFormField}/>
|
||||
:
|
||||
<SkeletonComponent property={property}
|
||||
size={getPreviewSizeFrom(size)}/>;
|
||||
@@ -608,7 +614,7 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
key: orderByProperty,
|
||||
order: currentOrder
|
||||
} : undefined}
|
||||
overscanRowCount={6}
|
||||
overscanRowCount={2}
|
||||
onColumnSort={onColumnSort}
|
||||
onEndReachedThreshold={PIXEL_NEXT_PAGE_OFFSET}
|
||||
onEndReached={loadNextPage}
|
||||
@@ -632,7 +638,7 @@ export function CollectionTable<S extends EntitySchema<Key, P>,
|
||||
|
||||
{columns.map((column) =>
|
||||
<Column
|
||||
key={column.id}
|
||||
key={`column_${tableKey}_${column.id}`}
|
||||
type={column.type}
|
||||
title={column.label}
|
||||
className={classes.column}
|
||||
|
||||
@@ -48,6 +48,7 @@ export function TableSelect(props: {
|
||||
<Select
|
||||
// TODO: related to prev. replace autofocus with ref, it makes the scroll jump when rendered
|
||||
autoFocus
|
||||
key={`table_select_${name}`}
|
||||
// inputRef={ref}
|
||||
className={classes.select}
|
||||
classes={{ root: classes.selectRoot }}
|
||||
@@ -88,7 +89,7 @@ export function TableSelect(props: {
|
||||
small={true}/>;
|
||||
if (multiple) {
|
||||
return (
|
||||
<MenuItem key={`select-${key}`}
|
||||
<MenuItem key={`select-${name}-${key}`}
|
||||
value={key}
|
||||
dense={true}>
|
||||
<Checkbox
|
||||
@@ -98,7 +99,7 @@ export function TableSelect(props: {
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<MenuItem key={`select-${key}`} value={key}
|
||||
<MenuItem key={`select-${name}-${key}`} value={key}
|
||||
dense={true}>
|
||||
{chip}
|
||||
</MenuItem>
|
||||
|
||||
@@ -105,7 +105,7 @@ export default function StringNumberFilterField({ name, property }: StringNumber
|
||||
}}>
|
||||
{possibleOperations.map((op) =>
|
||||
<MenuItem
|
||||
key={`filter_op_${op}`}
|
||||
key={`filter_op_${name}_${op}`}
|
||||
value={op}>{operationLabels[op]}</MenuItem>
|
||||
)}
|
||||
|
||||
@@ -116,7 +116,7 @@ export default function StringNumberFilterField({ name, property }: StringNumber
|
||||
|
||||
{!enumValues && <Input
|
||||
fullWidth
|
||||
key={`filter-${name}`}
|
||||
key={`filter_${name}`}
|
||||
type={dataType === "number" ? "number" : undefined}
|
||||
value={internalValue ? internalValue : ""}
|
||||
onChange={(evt) => {
|
||||
@@ -147,7 +147,7 @@ export default function StringNumberFilterField({ name, property }: StringNumber
|
||||
</div>
|
||||
) : undefined}>
|
||||
{Object.entries(enumValues).map(([key, value]) => (
|
||||
<MenuItem key={`select-${key}`}
|
||||
<MenuItem key={`select_${name}_${key}`}
|
||||
value={key}>
|
||||
<CustomChip
|
||||
colorKey={key as string}
|
||||
|
||||
@@ -149,7 +149,7 @@ function PopupFormField<S extends EntitySchema>({
|
||||
|
||||
const form = entity && (
|
||||
<div
|
||||
key={`${tableKey}_${entity.id}_${rowIndex}`}
|
||||
key={`popup_form_${tableKey}_${entity.id}_${rowIndex}`}
|
||||
style={{
|
||||
width: 470,
|
||||
maxWidth: "100vw",
|
||||
@@ -194,6 +194,7 @@ function PopupFormField<S extends EntitySchema>({
|
||||
return (
|
||||
<Portal container={document.body}>
|
||||
<Draggable
|
||||
key={`draggable_${name}_${rowIndex}`}
|
||||
x={popupLocation?.x}
|
||||
y={popupLocation?.y}
|
||||
open={formPopupOpen}
|
||||
|
||||
@@ -19,7 +19,8 @@ import { ErrorFocus } from "./ErrorFocus";
|
||||
export const useStyles = makeStyles(theme => createStyles({
|
||||
stickyButtons: {
|
||||
marginTop: theme.spacing(2),
|
||||
backgroundColor: "#ffffffb8",
|
||||
background: "rgba(255,255,255,0.6)",
|
||||
backdropFilter: "blur(3px)",
|
||||
borderTop: "solid 1px #f9f9f9",
|
||||
position: "sticky",
|
||||
bottom: 0,
|
||||
@@ -213,7 +214,7 @@ function EntityForm<S extends EntitySchema>({
|
||||
Object.entries(underlyingChanges).forEach(([key, value]) => {
|
||||
const formValue = values[key];
|
||||
if (!deepEqual(value, formValue) && !touched[key]) {
|
||||
console.debug("Updated value from Firestore:", key, value)
|
||||
console.debug("Updated value from Firestore:", key, value);
|
||||
setFieldValue(key, !!value ? value : null);
|
||||
setFieldTouched(key, false);
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ export default function ReferenceField<S extends EntitySchema>({
|
||||
{listProperties && listProperties.map((key, index) => {
|
||||
const propertyKey = schema.properties[key as string];
|
||||
return (
|
||||
<Box key={"ref_prev_" + key + index}
|
||||
<Box
|
||||
mt={0.5}
|
||||
mb={0.5}>
|
||||
<ErrorBoundary>{
|
||||
@@ -221,7 +221,7 @@ export default function ReferenceField<S extends EntitySchema>({
|
||||
</Box>
|
||||
|
||||
{entity &&
|
||||
<Box key={"ref_prev_id"}
|
||||
<Box
|
||||
alignSelf={"center"}
|
||||
m={1}>
|
||||
<Tooltip title={value && value.path}>
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function Select<T extends EnumType>({
|
||||
}>
|
||||
|
||||
{Object.entries(enumValues).map(([key, value]) => (
|
||||
<MenuItem key={`select-${key}`} value={key}>
|
||||
<MenuItem key={`select_${name}_${key}`} value={key}>
|
||||
<CustomChip
|
||||
colorKey={typeof key === "number" ? `${name}_${key}` : key as string}
|
||||
label={value as string}
|
||||
|
||||
@@ -398,16 +398,18 @@ export function StorageUpload({
|
||||
);
|
||||
}
|
||||
|
||||
return <StorageEntry
|
||||
key={`storage_entry_${index}`}
|
||||
entry={entry}
|
||||
index={index}
|
||||
dragType={"storage_card_" + name}
|
||||
moveItem={moveItem}
|
||||
onHover={setHoveredIndex}
|
||||
hovered={hoveredIndex === index}>
|
||||
{child}
|
||||
</StorageEntry>;
|
||||
return (
|
||||
<StorageEntry
|
||||
key={`storage_entry_${name}_${index}`}
|
||||
entry={entry}
|
||||
index={index}
|
||||
dragType={"storage_card_" + name}
|
||||
moveItem={moveItem}
|
||||
onHover={setHoveredIndex}
|
||||
hovered={hoveredIndex === index}>
|
||||
{child}
|
||||
</StorageEntry>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { EntitySchema } from "../models";
|
||||
import { renderSkeletonText } from "./SkeletonComponent";
|
||||
import { renderSkeletonText } from "./components/SkeletonComponent";
|
||||
|
||||
|
||||
export interface AsyncPreviewComponentProps<S extends EntitySchema> {
|
||||
|
||||
@@ -58,7 +58,7 @@ export default function EntityPreview<S extends EntitySchema>(
|
||||
<TableContainer>
|
||||
<Table aria-label="entity table">
|
||||
<TableBody>
|
||||
<TableRow key={"entity_prev_id"}>
|
||||
<TableRow >
|
||||
<TableCell align="right"
|
||||
component="td"
|
||||
scope="row"
|
||||
|
||||
@@ -32,6 +32,8 @@ import ErrorIcon from "@material-ui/icons/Error";
|
||||
|
||||
import firebase from "firebase/app";
|
||||
import { Box } from "@material-ui/core";
|
||||
import { useStyles } from "./components/styles";
|
||||
import clsx from "clsx";
|
||||
|
||||
export function PreviewComponent<T>(props: PreviewComponentProps<T>) {
|
||||
let content: JSX.Element | any;
|
||||
@@ -171,14 +173,14 @@ export function PreviewComponent<T>(props: PreviewComponentProps<T>) {
|
||||
}
|
||||
|
||||
function buildWrongValueType() {
|
||||
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<Box
|
||||
display={"flex"}
|
||||
alignItems={"center"}
|
||||
m={1}>
|
||||
<div
|
||||
className={clsx(classes.flexCenter, classes.smallMargin)}>
|
||||
<ErrorIcon fontSize={"small"} color={"error"}/>
|
||||
<Box marginLeft={1}>Unexpected value</Box>
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { getDownloadURL } from "../firebase";
|
||||
import { renderSkeletonImageThumbnail } from "./SkeletonComponent";
|
||||
import { renderSkeletonImageThumbnail } from "./components/SkeletonComponent";
|
||||
import {
|
||||
PreviewComponentFactoryProps,
|
||||
PreviewComponentProps
|
||||
|
||||
@@ -5,22 +5,11 @@ import {
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Box, createStyles, makeStyles, Theme } from "@material-ui/core";
|
||||
import ErrorBoundary from "../../components/ErrorBoundary";
|
||||
import { EnumValues, NumberProperty, StringProperty } from "../../models";
|
||||
import { CustomChip } from "./CustomChip";
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
display: "flex",
|
||||
flexWrap: "wrap"
|
||||
},
|
||||
item: {
|
||||
m: 0.2,
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
export function buildArrayEnumPreview(value: string[] | number[],
|
||||
name: string,
|
||||
@@ -30,10 +19,10 @@ export function buildArrayEnumPreview(value: string[] | number[],
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<div className={classes.arrayRoot}>
|
||||
{value &&
|
||||
(value as any[]).map((v, index) => (
|
||||
<div className={classes.item} key={`preview_array_ref_${name}_${index}`}>
|
||||
<div className={classes.arrayItem} key={`preview_array_ref_${name}_${index}`}>
|
||||
<ErrorBoundary>
|
||||
<CustomChip
|
||||
colorKey={typeof v == "number" ? `${name}_${v}` : v as string}
|
||||
|
||||
@@ -16,16 +16,7 @@ import {
|
||||
TableRow,
|
||||
Theme
|
||||
} from "@material-ui/core";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
tableNoBottomBorder: {
|
||||
"&:last-child th, &:last-child td": {
|
||||
borderBottom: 0
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export function ArrayOfMapsPreview({
|
||||
name,
|
||||
|
||||
@@ -9,14 +9,7 @@ import React from "react";
|
||||
|
||||
import { createStyles, makeStyles, Theme } from "@material-ui/core";
|
||||
import { default as ReferencePreview } from "./ReferencePreview";
|
||||
|
||||
export const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
margin: 0.2,
|
||||
}
|
||||
})
|
||||
);
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export function ArrayOfReferencesPreview({
|
||||
name,
|
||||
@@ -37,7 +30,7 @@ export function ArrayOfReferencesPreview({
|
||||
<>
|
||||
{value &&
|
||||
value.map((v, index) =>
|
||||
<div className={classes.root} key={`preview_array_ref_${name}_${index}`}>
|
||||
<div className={classes.arrayItem} key={`preview_array_ref_${name}_${index}`}>
|
||||
<ReferencePreview
|
||||
name={`${name}[${index}]`}
|
||||
entitySchema={entitySchema}
|
||||
|
||||
@@ -9,6 +9,7 @@ import React from "react";
|
||||
import { Box } from "@material-ui/core";
|
||||
import ErrorBoundary from "../../components/ErrorBoundary";
|
||||
import { PreviewComponent } from "../PreviewComponent";
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
|
||||
export function ArrayOfStorageComponentsPreview({
|
||||
@@ -24,14 +25,13 @@ export function ArrayOfStorageComponentsPreview({
|
||||
throw Error("Picked wrong preview component ArrayOfStorageComponentsPreview");
|
||||
|
||||
const childSize: PreviewSize = size === "regular" ? "small" : "tiny";
|
||||
const classes = useStyles();
|
||||
|
||||
return <Box
|
||||
display={"flex"}
|
||||
flexWrap="wrap">
|
||||
return <div className={classes.arrayRoot}>
|
||||
{value &&
|
||||
value.map((v, index) =>
|
||||
<Box m={0.2}
|
||||
key={"preview_array_storage_" + name + v + index}>
|
||||
<div className={classes.arrayItem}
|
||||
key={`preview_array_storage_${name}_${index}`}>
|
||||
<ErrorBoundary>
|
||||
<PreviewComponent
|
||||
name={name}
|
||||
@@ -40,7 +40,7 @@ export function ArrayOfStorageComponentsPreview({
|
||||
size={childSize}
|
||||
entitySchema={entitySchema}/>
|
||||
</ErrorBoundary>
|
||||
</Box>
|
||||
</div>
|
||||
)}
|
||||
</Box>;
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,9 @@ import {
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Box } from "@material-ui/core";
|
||||
import ErrorBoundary from "../../components/ErrorBoundary";
|
||||
import { StringPreview } from "./StringPreview";
|
||||
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export function ArrayOfStringsPreview({
|
||||
name,
|
||||
@@ -19,6 +18,8 @@ export function ArrayOfStringsPreview({
|
||||
entitySchema
|
||||
}: PreviewComponentProps<string[]> & PreviewComponentFactoryProps) {
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
if (property.dataType !== "array" || property.of.dataType !== "string")
|
||||
throw Error("Picked wrong preview component ArrayOfStringsPreview");
|
||||
|
||||
@@ -28,11 +29,10 @@ export function ArrayOfStringsPreview({
|
||||
const stringProperty = property.of as StringProperty;
|
||||
|
||||
return (
|
||||
<Box display={stringProperty.config?.previewAsTag ? "flex" : "block"}
|
||||
flexWrap={"wrap"}>
|
||||
<div className={classes.arrayRoot}>
|
||||
{value &&
|
||||
value.map((v, index) =>
|
||||
<Box m={stringProperty.config?.previewAsTag ? 0.2 : 0.5}
|
||||
<div className={classes.arrayItem}
|
||||
key={`preview_array_strings_${name}_${index}`}>
|
||||
<ErrorBoundary>
|
||||
<StringPreview name={name}
|
||||
@@ -41,8 +41,8 @@ export function ArrayOfStringsPreview({
|
||||
size={size}
|
||||
entitySchema={entitySchema}/>
|
||||
</ErrorBoundary>
|
||||
</Box>
|
||||
</div>
|
||||
)}
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,17 +16,7 @@ import {
|
||||
Theme
|
||||
} from "@material-ui/core";
|
||||
import { PreviewComponent } from "../PreviewComponent";
|
||||
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
tableNoBottomBorder: {
|
||||
"&:last-child th, &:last-child td": {
|
||||
borderBottom: 0
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export function ArrayPreview({
|
||||
name,
|
||||
@@ -37,6 +27,8 @@ export function ArrayPreview({
|
||||
PreviewComponent
|
||||
}: PreviewComponentProps<any[]> & PreviewComponentFactoryProps) {
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
if (property.dataType !== "array")
|
||||
throw Error("Picked wrong preview component ArrayPreview");
|
||||
|
||||
@@ -47,11 +39,11 @@ export function ArrayPreview({
|
||||
const childSize: PreviewSize = size === "regular" ? "small" : "tiny";
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<>
|
||||
{values &&
|
||||
values.map((value, index) =>
|
||||
<React.Fragment key={"preview_array_" + value + "_" + index}>
|
||||
<Box p={1}>
|
||||
<div className={classes.arrayItemBig} >
|
||||
<ErrorBoundary>
|
||||
<PreviewComponent
|
||||
name={name}
|
||||
@@ -60,10 +52,10 @@ export function ArrayPreview({
|
||||
size={childSize}
|
||||
entitySchema={entitySchema}/>
|
||||
</ErrorBoundary>
|
||||
</Box>
|
||||
</div>
|
||||
{index < values.length - 1 && <Divider/>}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ export function CustomChip({ colorKey, label, error, outlined, small }: EnumChip
|
||||
label: classes.label
|
||||
}}
|
||||
size={small ? "small" : "medium"}
|
||||
key={"preview_chip_" + colorKey}
|
||||
variant={outlined ? "outlined" : "default"}
|
||||
label={label}
|
||||
/>
|
||||
|
||||
@@ -13,7 +13,7 @@ export function EnumChipsPreview({
|
||||
}: PreviewComponentProps<string>):React.ReactElement {
|
||||
|
||||
if (property.config?.enumValues) {
|
||||
return <React.Fragment>{property.config?.enumValues[value]}</React.Fragment>;
|
||||
return <>{property.config?.enumValues[value]}</>;
|
||||
} else if (property.config?.previewAsTag) {
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
@@ -24,6 +24,6 @@ export function EnumChipsPreview({
|
||||
/>
|
||||
</ErrorBoundary>);
|
||||
} else {
|
||||
return <React.Fragment>{value}</React.Fragment>;
|
||||
return <>{value}</>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import React, { CSSProperties, useState } from "react";
|
||||
import { Box, IconButton } from "@material-ui/core";
|
||||
import React, { CSSProperties, useMemo, useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import { IconButton } from "@material-ui/core";
|
||||
import OpenInNewIcon from "@material-ui/icons/OpenInNew";
|
||||
import { getThumbnailMeasure, PreviewSize } from "./PreviewComponentProps";
|
||||
import { getThumbnailMeasure, PreviewSize } from "../PreviewComponentProps";
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
type ImagePreviewProps = { size: PreviewSize, url: string };
|
||||
|
||||
function ImagePreview({ size, url }: ImagePreviewProps) {
|
||||
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
const [onHover, setOnHover] = useState(false);
|
||||
|
||||
const imageSize = getThumbnailMeasure(size);
|
||||
const imageSize = useMemo(() => getThumbnailMeasure(size), [size]);
|
||||
|
||||
if (size === "tiny") {
|
||||
return (
|
||||
@@ -34,22 +39,16 @@ function ImagePreview({ size, url }: ImagePreviewProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
<div
|
||||
className={clsx(classes.flexCenter, classes.imageWrap)}
|
||||
key={"image_preview_" + url}
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
style={{
|
||||
position: "relative",
|
||||
maxWidth: "100%",
|
||||
maxHeight: "100%"
|
||||
width: imageSize,
|
||||
height: imageSize
|
||||
}}
|
||||
|
||||
onMouseEnter={() => setOnHover(true)}
|
||||
onMouseMove={() => setOnHover(true)}
|
||||
onMouseLeave={() => setOnHover(false)}
|
||||
width={imageSize}
|
||||
height={imageSize}>
|
||||
onMouseLeave={() => setOnHover(false)}>
|
||||
|
||||
<img src={url}
|
||||
style={imageStyle}/>
|
||||
@@ -71,7 +70,7 @@ function ImagePreview({ size, url }: ImagePreviewProps) {
|
||||
</IconButton>
|
||||
</a>
|
||||
)}
|
||||
</Box>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
@@ -59,7 +59,7 @@ export function MapPreview<T>({
|
||||
|
||||
if (size !== "regular")
|
||||
return (
|
||||
<React.Fragment>
|
||||
<>
|
||||
{mapProperties.map((key, index) => (
|
||||
<ListItem
|
||||
key={"map_preview_" + mapProperty.title + key + index}>
|
||||
@@ -72,7 +72,7 @@ export function MapPreview<T>({
|
||||
</ErrorBoundary>
|
||||
</ListItem>
|
||||
))}
|
||||
</React.Fragment>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -82,16 +82,16 @@ export function MapPreview<T>({
|
||||
mapProperties.map((key, index) => {
|
||||
return (
|
||||
<TableRow
|
||||
key={`map_preview_table_${mapProperty.title}_${index}`}
|
||||
key={`map_preview_table_${name}_${index}`}
|
||||
className={classes.tableNoBottomBorder}>
|
||||
<TableCell key={`table-cell-title-${key}`}
|
||||
<TableCell key={`table-cell-title-${name}-${key}`}
|
||||
component="th">
|
||||
<Typography variant={"caption"}
|
||||
color={"textSecondary"}>
|
||||
{mapProperty.properties[key].title}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell key={`table-cell-${key}`} component="th">
|
||||
<TableCell key={`table-cell-${name}-${key}`} component="th">
|
||||
<ErrorBoundary>
|
||||
<PreviewComponent
|
||||
name={key}
|
||||
|
||||
@@ -19,6 +19,6 @@ export function NumberPreview({
|
||||
outlined={false}
|
||||
small={size !== "regular"}/>;
|
||||
} else {
|
||||
return <React.Fragment>{value}</React.Fragment>;
|
||||
return <>{value}</>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { useEffect } from "react";
|
||||
import clsx from "clsx";
|
||||
|
||||
import {
|
||||
Box,
|
||||
createStyles,
|
||||
IconButton,
|
||||
makeStyles,
|
||||
@@ -20,7 +19,7 @@ import {
|
||||
PreviewComponentProps,
|
||||
PreviewSize
|
||||
} from "../PreviewComponentProps";
|
||||
import SkeletonComponent from "../SkeletonComponent";
|
||||
import SkeletonComponent from "./SkeletonComponent";
|
||||
import KeyboardTabIcon from "@material-ui/icons/KeyboardTab";
|
||||
import { useSelectedEntityContext } from "../../side_dialog/SelectedEntityContext";
|
||||
import ErrorIcon from "@material-ui/icons/Error";
|
||||
@@ -31,8 +30,9 @@ import { useAppConfigContext } from "../../contexts/AppConfigContext";
|
||||
import firebase from "firebase/app";
|
||||
import "firebase/firestore";
|
||||
import { PreviewComponent } from "../PreviewComponent";
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
const useStyles = makeStyles<Theme, { size: PreviewSize }>((theme: Theme) =>
|
||||
const useReferenceStyles = makeStyles<Theme, { size: PreviewSize }>((theme: Theme) =>
|
||||
createStyles({
|
||||
paper: {
|
||||
display: "flex",
|
||||
@@ -95,7 +95,8 @@ export default React.memo<PreviewComponentProps<firebase.firestore.DocumentRefer
|
||||
entitySchema
|
||||
}: PreviewComponentProps<firebase.firestore.DocumentReference> & PreviewComponentFactoryProps) {
|
||||
|
||||
const classes = useStyles({ size });
|
||||
const referenceClasses = useReferenceStyles({ size });
|
||||
const classes = useStyles();
|
||||
|
||||
// TODO: remove when https://github.com/firebase/firebase-js-sdk/issues/4125 is fixed and replace with instance check of DocumentReference
|
||||
const isFirestoreReference = value
|
||||
@@ -135,13 +136,13 @@ export default React.memo<PreviewComponentProps<firebase.firestore.DocumentRefer
|
||||
let body: JSX.Element;
|
||||
|
||||
function buildError(error: string) {
|
||||
return <Box
|
||||
display={"flex"}
|
||||
alignItems={"center"}
|
||||
m={1}>
|
||||
return <div
|
||||
className={clsx(classes.flexCenter, classes.smallMargin)}>
|
||||
<ErrorIcon fontSize={"small"} color={"error"}/>
|
||||
<Box marginLeft={1}>{error}</Box>
|
||||
</Box>;
|
||||
<div style={{
|
||||
marginLeft: 1
|
||||
}}>{error}</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
@@ -160,11 +161,10 @@ export default React.memo<PreviewComponentProps<firebase.firestore.DocumentRefer
|
||||
|
||||
body = (
|
||||
<>
|
||||
<div className={classes.root}>
|
||||
<div className={referenceClasses.root}>
|
||||
|
||||
{size !== "tiny" && entity &&
|
||||
<div key={"ref_prev_id"}
|
||||
className={classes.inner}>
|
||||
<div className={referenceClasses.inner}>
|
||||
<Typography variant={"caption"} className={"mono"}>
|
||||
{entity.id}
|
||||
</Typography>
|
||||
@@ -175,7 +175,7 @@ export default React.memo<PreviewComponentProps<firebase.firestore.DocumentRefer
|
||||
|
||||
return (
|
||||
<div key={"ref_prev" + property.title + key}
|
||||
className={classes.inner}>
|
||||
className={referenceClasses.inner}>
|
||||
{entity && PreviewComponent ?
|
||||
<PreviewComponent name={key as string}
|
||||
value={entity.values[key as string]}
|
||||
@@ -191,7 +191,7 @@ export default React.memo<PreviewComponentProps<firebase.firestore.DocumentRefer
|
||||
})}
|
||||
|
||||
</div>
|
||||
<div className={classes.marginAuto}>
|
||||
<div className={referenceClasses.marginAuto}>
|
||||
{entity &&
|
||||
<Tooltip title={`See details for ${entity.id}`}>
|
||||
<IconButton
|
||||
@@ -212,12 +212,12 @@ export default React.memo<PreviewComponentProps<firebase.firestore.DocumentRefer
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper elevation={0} className={clsx(classes.paper,
|
||||
<Paper elevation={0} className={clsx(referenceClasses.paper,
|
||||
{
|
||||
[classes.regular]: size === "regular",
|
||||
[classes.small]: size === "small",
|
||||
[classes.tiny]: size === "tiny",
|
||||
[classes.clickable]: !!onClick
|
||||
[referenceClasses.regular]: size === "regular",
|
||||
[referenceClasses.small]: size === "small",
|
||||
[referenceClasses.tiny]: size === "tiny",
|
||||
[referenceClasses.clickable]: !!onClick
|
||||
})}
|
||||
onClick={onClick}>
|
||||
|
||||
|
||||
@@ -5,41 +5,27 @@ import {
|
||||
Properties,
|
||||
Property,
|
||||
StringProperty
|
||||
} from "../models";
|
||||
} from "../../models";
|
||||
import React from "react";
|
||||
import {
|
||||
Box,
|
||||
createStyles,
|
||||
Divider,
|
||||
Grid,
|
||||
List,
|
||||
ListItem,
|
||||
makeStyles,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableRow,
|
||||
Theme
|
||||
TableRow
|
||||
} from "@material-ui/core";
|
||||
import { Skeleton } from "@material-ui/lab";
|
||||
import { getThumbnailMeasure, PreviewSize } from "./PreviewComponentProps";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
tableNoBottomBorder: {
|
||||
"&:last-child th, &:last-child td": {
|
||||
borderBottom: 0
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
import { getThumbnailMeasure, PreviewSize } from "../PreviewComponentProps";
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export interface SkeletonComponentProps<T> {
|
||||
property: Property,
|
||||
size: PreviewSize
|
||||
}
|
||||
|
||||
|
||||
export default function SkeletonComponent<T>({
|
||||
property,
|
||||
size
|
||||
@@ -188,9 +174,9 @@ function renderArrayOfStrings() {
|
||||
<Grid>
|
||||
{
|
||||
[0, 1].map((value, index) => (
|
||||
<React.Fragment key={"skeleton_array_strings_" + value}>
|
||||
<>
|
||||
{renderSkeletonText(index)}
|
||||
</React.Fragment>
|
||||
</>
|
||||
))}
|
||||
</Grid>
|
||||
);
|
||||
@@ -201,9 +187,9 @@ function renderArrayEnumTableCell<T extends EnumType>() {
|
||||
<Grid>
|
||||
{
|
||||
[0, 1].map((value, index) =>
|
||||
<React.Fragment key={"skeleton_array_enum_" + value}>
|
||||
<>
|
||||
{renderSkeletonText(index)}
|
||||
</React.Fragment>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
@@ -217,10 +203,10 @@ function renderGenericArrayCell(
|
||||
|
||||
{
|
||||
[0, 1].map((value, index) =>
|
||||
<React.Fragment key={"skeleton_array_" + value}>
|
||||
<>
|
||||
<SkeletonComponent property={property}
|
||||
size={"small"}/>
|
||||
</React.Fragment>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
@@ -230,17 +216,21 @@ function renderShapedArray<T extends EnumType>(
|
||||
properties: Property[]
|
||||
) {
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
{properties &&
|
||||
properties.map((property, index) =>
|
||||
<React.Fragment
|
||||
key={"preview_array_" + properties[index] + "_" + index}>
|
||||
{properties[index] && <Box m={1}>
|
||||
<SkeletonComponent
|
||||
property={property}
|
||||
size={"small"}/>
|
||||
</Box>}
|
||||
{properties[index] && (
|
||||
<div className={classes.smallMargin}>
|
||||
<SkeletonComponent
|
||||
property={property}
|
||||
size={"small"}/>
|
||||
</div>
|
||||
)}
|
||||
{properties[index] && index < properties.length - 1 &&
|
||||
<Divider/>}
|
||||
</React.Fragment>
|
||||
@@ -300,26 +290,29 @@ function renderUrlComponent(property: StringProperty, size: PreviewSize = "regul
|
||||
}
|
||||
|
||||
function renderUrlFile(size: PreviewSize) {
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
width={getThumbnailMeasure(size)}
|
||||
height={getThumbnailMeasure(size)}>
|
||||
<div
|
||||
className={(classes as any)}
|
||||
style={{
|
||||
width: getThumbnailMeasure(size),
|
||||
height: getThumbnailMeasure(size)
|
||||
}}>
|
||||
{renderSkeletonIcon()}
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function renderSkeletonText(index?: number) {
|
||||
return <Skeleton key={"skeleton_text_" + index} variant="text"/>;
|
||||
return <Skeleton variant="text"/>;
|
||||
}
|
||||
|
||||
export function renderSkeletonCaptionText(index?: number) {
|
||||
return <Skeleton key={"skeleton_text_" + index}
|
||||
height={20}
|
||||
variant="text"/>;
|
||||
return <Skeleton
|
||||
height={20}
|
||||
variant="text"/>;
|
||||
}
|
||||
|
||||
export function renderSkeletonIcon() {
|
||||
@@ -29,6 +29,6 @@ export function StringPreview({
|
||||
/>
|
||||
</ErrorBoundary>);
|
||||
} else {
|
||||
return <React.Fragment>{value}</React.Fragment>;
|
||||
return <>{value}</>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,20 +4,23 @@ import {
|
||||
} from "../PreviewComponentProps";
|
||||
import React from "react";
|
||||
import { MediaType } from "../../models";
|
||||
import ImagePreview from "../ImagePreview";
|
||||
import ImagePreview from "./ImagePreview";
|
||||
|
||||
|
||||
import { Box, CardMedia, Link } from "@material-ui/core";
|
||||
import { CardMedia, Link } from "@material-ui/core";
|
||||
import DescriptionOutlinedIcon from "@material-ui/icons/DescriptionOutlined";
|
||||
import OpenInNewIcon from "@material-ui/icons/OpenInNew";
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export function UrlComponentPreview({
|
||||
name,
|
||||
value,
|
||||
property,
|
||||
size,
|
||||
entitySchema
|
||||
}: PreviewComponentProps<string>):React.ReactElement {
|
||||
name,
|
||||
value,
|
||||
property,
|
||||
size,
|
||||
entitySchema
|
||||
}: PreviewComponentProps<string>): React.ReactElement {
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
if (!value) return <div/>;
|
||||
const url = value;
|
||||
@@ -60,14 +63,13 @@ export function UrlComponentPreview({
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
onClick={(e) => e.stopPropagation()}>
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
width={getThumbnailMeasure(size)}
|
||||
height={getThumbnailMeasure(size)}>
|
||||
<div className={classes.flexCenter}
|
||||
style={{
|
||||
width: getThumbnailMeasure(size),
|
||||
height: getThumbnailMeasure(size)
|
||||
}}>
|
||||
<DescriptionOutlinedIcon/>
|
||||
</Box>
|
||||
</div>
|
||||
</a>;
|
||||
}
|
||||
}
|
||||
|
||||
36
src/preview/components/styles.tsx
Normal file
36
src/preview/components/styles.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { createStyles, makeStyles, Theme } from "@material-ui/core";
|
||||
|
||||
export const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
flexCenter: {
|
||||
display:"flex",
|
||||
alignItems:"center",
|
||||
justifyContent:"center"
|
||||
},
|
||||
smallMargin: {
|
||||
margin: theme.spacing(1)
|
||||
},
|
||||
arrayRoot: {
|
||||
display: "flex",
|
||||
flexWrap: "wrap"
|
||||
},
|
||||
arrayItem: {
|
||||
m: 0.2,
|
||||
},
|
||||
arrayItemBig: {
|
||||
m: theme.spacing(1),
|
||||
},
|
||||
tableNoBottomBorder: {
|
||||
"&:last-child th, &:last-child td": {
|
||||
borderBottom: 0
|
||||
}
|
||||
},
|
||||
imageWrap:{
|
||||
position: "relative",
|
||||
maxWidth: "100%",
|
||||
maxHeight: "100%"
|
||||
}
|
||||
})
|
||||
);
|
||||
@@ -6,7 +6,7 @@ import StorageThumbnail from "./StorageThumbnail";
|
||||
import AsyncPreviewComponent from "./AsyncPreviewComponent";
|
||||
import EntityPreview from "./EntityPreview";
|
||||
import PreviewComponent from "./PreviewComponent";
|
||||
import SkeletonComponent from "./SkeletonComponent";
|
||||
import SkeletonComponent from "./components/SkeletonComponent";
|
||||
|
||||
export {
|
||||
PreviewComponent,
|
||||
|
||||
@@ -26,7 +26,7 @@ function AdditionalViewRoute({
|
||||
breadcrumbsContext.set({
|
||||
breadcrumbs: [breadcrumb]
|
||||
});
|
||||
}, [url]);
|
||||
}, []);
|
||||
|
||||
return <React.Fragment>
|
||||
{additionalView.view}
|
||||
|
||||
Reference in New Issue
Block a user