mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
Merge branch 'develop' of https://github.com/rowyio/rowy into multi-file-upload
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { atom } from "jotai";
|
||||
import { findIndex } from "lodash-es";
|
||||
import { FieldType } from "@src/constants/fields";
|
||||
|
||||
import {
|
||||
tableColumnsOrderedAtom,
|
||||
tableColumnsReducer,
|
||||
updateTableSchemaAtom,
|
||||
tableSchemaAtom,
|
||||
} from "./table";
|
||||
import { ColumnConfig } from "@src/types/table";
|
||||
|
||||
@@ -14,6 +16,7 @@ export interface IAddColumnOptions {
|
||||
/** Index to add column at. If undefined, adds to end */
|
||||
index?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set function adds a column to tableSchema, to the end or by index.
|
||||
* Also fixes any issues with column indexes, so they go from 0 to length - 1
|
||||
@@ -52,6 +55,7 @@ export interface IUpdateColumnOptions {
|
||||
/** If passed, reorders the column to the index */
|
||||
index?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set function updates a column in tableSchema
|
||||
* @throws Error if column not found
|
||||
@@ -112,13 +116,50 @@ export const updateColumnAtom = atom(
|
||||
* ```
|
||||
*/
|
||||
export const deleteColumnAtom = atom(null, async (get, _set, key: string) => {
|
||||
const tableSchema = get(tableSchemaAtom);
|
||||
const tableColumnsOrdered = [...get(tableColumnsOrderedAtom)];
|
||||
const updateTableSchema = get(updateTableSchemaAtom);
|
||||
if (!updateTableSchema) throw new Error("Cannot update table schema");
|
||||
|
||||
const updatedColumns = tableColumnsOrdered
|
||||
.filter((c) => c.key !== key)
|
||||
.map((c) => {
|
||||
// remove column from derivatives listener fields
|
||||
if (c.type === FieldType.derivative) {
|
||||
return {
|
||||
...c,
|
||||
config: {
|
||||
...c.config,
|
||||
listenerFields:
|
||||
c.config?.listenerFields?.filter((f) => f !== key) ?? [],
|
||||
},
|
||||
};
|
||||
} else if (c.type === FieldType.action) {
|
||||
return {
|
||||
...c,
|
||||
config: {
|
||||
...c.config,
|
||||
requiredFields:
|
||||
c.config?.requiredFields?.filter((f) => f !== key) ?? [],
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
})
|
||||
.reduce(tableColumnsReducer, {});
|
||||
|
||||
await updateTableSchema({ columns: updatedColumns }, [`columns.${key}`]);
|
||||
const updatedExtensionObjects = tableSchema?.extensionObjects?.map(
|
||||
(extension) => {
|
||||
return {
|
||||
...extension,
|
||||
requiredFields: extension.requiredFields.filter((f) => f !== key),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
await updateTableSchema(
|
||||
{ columns: updatedColumns, extensionObjects: updatedExtensionObjects },
|
||||
[`columns.${key}`]
|
||||
);
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Typography,
|
||||
Divider,
|
||||
} from "@mui/material";
|
||||
import FilterIcon from "@mui/icons-material/FilterList";
|
||||
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
||||
@@ -50,12 +51,18 @@ import {
|
||||
columnModalAtom,
|
||||
tableFiltersPopoverAtom,
|
||||
tableNextPageAtom,
|
||||
tableSchemaAtom,
|
||||
} from "@src/atoms/tableScope";
|
||||
import { FieldType } from "@src/constants/fields";
|
||||
import { getFieldProp } from "@src/components/fields";
|
||||
import { analytics, logEvent } from "@src/analytics";
|
||||
import { formatSubTableName, getTableSchemaPath } from "@src/utils/table";
|
||||
import {
|
||||
formatSubTableName,
|
||||
getTableBuildFunctionPathname,
|
||||
getTableSchemaPath,
|
||||
} from "@src/utils/table";
|
||||
import { runRoutes } from "@src/constants/runRoutes";
|
||||
import { useSnackLogContext } from "@src/contexts/SnackLogContext";
|
||||
|
||||
export interface IMenuModalProps {
|
||||
name: string;
|
||||
@@ -91,6 +98,8 @@ export default function ColumnMenu() {
|
||||
tableScope
|
||||
);
|
||||
const [tableNextPage] = useAtom(tableNextPageAtom, tableScope);
|
||||
const [tableSchema] = useAtom(tableSchemaAtom, tableScope);
|
||||
const snackLogContext = useSnackLogContext();
|
||||
|
||||
const [altPress] = useAtom(altPressAtom, projectScope);
|
||||
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
|
||||
@@ -117,8 +126,42 @@ export default function ColumnMenu() {
|
||||
const userDocHiddenFields =
|
||||
userSettings.tables?.[formatSubTableName(tableId)]?.hiddenFields ?? [];
|
||||
|
||||
let referencedColumns: string[] = [];
|
||||
let referencedExtensions: string[] = [];
|
||||
Object.entries(tableSchema?.columns ?? {}).forEach(([key, c], index) => {
|
||||
if (
|
||||
c.config?.listenerFields?.includes(column.key) ||
|
||||
c.config?.requiredFields?.includes(column.key)
|
||||
) {
|
||||
referencedColumns.push(c.name);
|
||||
}
|
||||
});
|
||||
tableSchema?.extensionObjects?.forEach((extension) => {
|
||||
if (extension.requiredFields.includes(column.key)) {
|
||||
referencedExtensions.push(extension.name);
|
||||
}
|
||||
});
|
||||
const requireRebuild =
|
||||
referencedColumns.length || referencedExtensions.length;
|
||||
|
||||
const handleDeleteColumn = () => {
|
||||
deleteColumn(column.key);
|
||||
if (requireRebuild) {
|
||||
snackLogContext.requestSnackLog();
|
||||
rowyRun({
|
||||
route: runRoutes.buildFunction,
|
||||
body: {
|
||||
tablePath: tableSettings.collection,
|
||||
// pathname must match old URL format
|
||||
pathname: getTableBuildFunctionPathname(
|
||||
tableSettings.id,
|
||||
tableSettings.tableType
|
||||
),
|
||||
tableConfigPath: getTableSchemaPath(tableSettings),
|
||||
},
|
||||
});
|
||||
logEvent(analytics, "deployed_extensions");
|
||||
}
|
||||
logEvent(analytics, "delete_column", { type: column.type });
|
||||
handleClose();
|
||||
};
|
||||
@@ -360,8 +403,8 @@ export default function ColumnMenu() {
|
||||
icon: <ColumnRemoveIcon />,
|
||||
onClick: altPress
|
||||
? handleDeleteColumn
|
||||
: () =>
|
||||
confirm({
|
||||
: () => {
|
||||
return confirm({
|
||||
title: "Delete column?",
|
||||
body: (
|
||||
<>
|
||||
@@ -373,12 +416,39 @@ export default function ColumnMenu() {
|
||||
<Typography sx={{ mt: 1 }}>
|
||||
Key: <code style={{ userSelect: "all" }}>{column.key}</code>
|
||||
</Typography>
|
||||
{requireRebuild ? (
|
||||
<>
|
||||
<Divider sx={{ my: 2 }} />
|
||||
{referencedColumns.length ? (
|
||||
<Typography sx={{ mt: 1 }}>
|
||||
This column will be removed as a dependency of the
|
||||
following columns:{" "}
|
||||
<Typography fontWeight="bold" component="span">
|
||||
{referencedColumns.join(", ")}
|
||||
</Typography>
|
||||
</Typography>
|
||||
) : null}
|
||||
{referencedExtensions.length ? (
|
||||
<Typography sx={{ mt: 1 }}>
|
||||
This column will be removed as a dependency from the
|
||||
following Extensions:{" "}
|
||||
<Typography fontWeight="bold" component="span">
|
||||
{referencedExtensions.join(", ")}
|
||||
</Typography>
|
||||
</Typography>
|
||||
) : null}
|
||||
<Typography sx={{ mt: 1, fontWeight: "bold" }}>
|
||||
You need to re-deploy this table’s cloud function.
|
||||
</Typography>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
),
|
||||
confirm: "Delete",
|
||||
confirm: requireRebuild ? "Delete & re-deploy" : "Delete",
|
||||
confirmColor: "error",
|
||||
handleConfirm: handleDeleteColumn,
|
||||
}),
|
||||
});
|
||||
},
|
||||
color: "error" as "error",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { FallbackProps } from "react-error-boundary";
|
||||
import { useLocation, Link } from "react-router-dom";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import useOffline from "@src/hooks/useOffline";
|
||||
|
||||
import { Typography, Button } from "@mui/material";
|
||||
import ReloadIcon from "@mui/icons-material/Refresh";
|
||||
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
|
||||
import OfflineIcon from "@mui/icons-material/CloudOff";
|
||||
import { Tables as TablesIcon } from "@src/assets/icons";
|
||||
|
||||
import EmptyState, { IEmptyStateProps } from "@src/components/EmptyState";
|
||||
import AccessDenied from "@src/components/AccessDenied";
|
||||
|
||||
import { ROUTES } from "@src/constants/routes";
|
||||
import { EXTERNAL_LINKS } from "@src/constants/externalLinks";
|
||||
|
||||
export const ERROR_TABLE_NOT_FOUND = "Table not found";
|
||||
|
||||
export interface IErrorFallbackProps extends FallbackProps, IEmptyStateProps {}
|
||||
|
||||
export function ErrorFallbackContents({
|
||||
@@ -57,7 +53,7 @@ export function ErrorFallbackContents({
|
||||
.filter(Boolean)
|
||||
.join(": ")
|
||||
.replace(/\n/g, " "),
|
||||
body: "👉 **Please describe how to reproduce this bug here.**",
|
||||
body: "👉 **Please describe the steps that you took that led to this bug.**",
|
||||
}).toString()
|
||||
}
|
||||
target="_blank"
|
||||
@@ -70,37 +66,6 @@ export function ErrorFallbackContents({
|
||||
),
|
||||
};
|
||||
|
||||
if (error.message.startsWith(ERROR_TABLE_NOT_FOUND)) {
|
||||
if (isOffline) {
|
||||
renderProps = { Icon: OfflineIcon, message: "You’re offline" };
|
||||
} else {
|
||||
renderProps = {
|
||||
message: ERROR_TABLE_NOT_FOUND,
|
||||
description: (
|
||||
<>
|
||||
<Typography variant="inherit">
|
||||
Make sure you have the right ID
|
||||
</Typography>
|
||||
<code>
|
||||
{error.message.replace(ERROR_TABLE_NOT_FOUND + ": ", "")}
|
||||
</code>
|
||||
<Button
|
||||
size={props.basic ? "small" : "medium"}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
component={Link}
|
||||
to={ROUTES.tables}
|
||||
startIcon={<TablesIcon />}
|
||||
onClick={() => resetErrorBoundary()}
|
||||
>
|
||||
All tables
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (error.message.startsWith("Loading chunk")) {
|
||||
if (isOffline) {
|
||||
renderProps = { Icon: OfflineIcon, message: "You’re offline" };
|
||||
|
||||
@@ -111,7 +111,7 @@ export default function MenuContents({ onClose }: IMenuContentsProps) {
|
||||
disabled:
|
||||
selectedColumn.editable === false ||
|
||||
!row ||
|
||||
cellValue ||
|
||||
cellValue === undefined ||
|
||||
getFieldProp("group", selectedColumn.type) === "Auditing",
|
||||
onClick: altPress
|
||||
? handleClearValue
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useAtom, useSetAtom } from "jotai";
|
||||
import { isEqual } from "lodash-es";
|
||||
import { isEqual, isUndefined } from "lodash-es";
|
||||
import { ITableModalProps } from "@src/components/TableModals";
|
||||
|
||||
import Modal from "@src/components/Modal";
|
||||
@@ -56,11 +56,12 @@ export default function ExtensionsModal({ onClose }: ITableModalProps) {
|
||||
|
||||
const errors = {
|
||||
runtimeOptions: {
|
||||
timeoutSeconds: !(
|
||||
!!localRuntimeOptions.timeoutSeconds &&
|
||||
localRuntimeOptions.timeoutSeconds > 0 &&
|
||||
localRuntimeOptions.timeoutSeconds <= 540
|
||||
),
|
||||
timeoutSeconds:
|
||||
!isUndefined(localRuntimeOptions.timeoutSeconds) &&
|
||||
!(
|
||||
localRuntimeOptions.timeoutSeconds! > 0 &&
|
||||
localRuntimeOptions.timeoutSeconds! <= 540
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
21
src/components/fields/Color/filters.ts
Normal file
21
src/components/fields/Color/filters.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { IFilterOperator } from "@src/components/fields/types";
|
||||
|
||||
export const filterOperators: IFilterOperator[] = [
|
||||
{
|
||||
label: "is",
|
||||
secondaryLabel: "==",
|
||||
value: "color-equal"
|
||||
},
|
||||
{
|
||||
label: "is not",
|
||||
secondaryLabel: "!=",
|
||||
value: "color-not-equal"
|
||||
}
|
||||
];
|
||||
|
||||
export const valueFormatter = (value: any) => {
|
||||
if (value && value.hex) {
|
||||
return value.hex.toString()
|
||||
}
|
||||
return "";
|
||||
};
|
||||
@@ -7,6 +7,7 @@ import ColorIcon from "@mui/icons-material/Colorize";
|
||||
import BasicCell from "@src/components/fields/_BasicCell/BasicCellNull";
|
||||
import InlineCell from "./InlineCell";
|
||||
import NullEditor from "@src/components/Table/editors/NullEditor";
|
||||
import { filterOperators, valueFormatter } from "./filters";
|
||||
|
||||
const PopoverCell = lazy(
|
||||
() => import("./PopoverCell" /* webpackChunkName: "PopoverCell-Color" */)
|
||||
@@ -31,6 +32,10 @@ export const config: IFieldConfig = {
|
||||
}),
|
||||
TableEditor: NullEditor as any,
|
||||
SideDrawerField,
|
||||
filter: {
|
||||
operators: filterOperators,
|
||||
valueFormatter
|
||||
},
|
||||
csvImportParser: (value: string) => {
|
||||
try {
|
||||
const obj = JSON.parse(value);
|
||||
|
||||
28
src/components/fields/Rating/Icon.tsx
Normal file
28
src/components/fields/Rating/Icon.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import RatingIcon from "@mui/icons-material/Star";
|
||||
import RatingOutlineIcon from "@mui/icons-material/StarBorder"
|
||||
import { get } from "lodash-es";
|
||||
|
||||
|
||||
export interface IIconProps{
|
||||
config: any,
|
||||
isEmpty: boolean
|
||||
}
|
||||
|
||||
export default function Icon({config, isEmpty} : IIconProps) {
|
||||
if (isEmpty) {
|
||||
return getStateOutline(config)
|
||||
} else {
|
||||
return getStateIcon(config)
|
||||
}
|
||||
}
|
||||
|
||||
const getStateIcon = (config: any) => {
|
||||
// only use the config to get the custom rating icon if enabled via toggle
|
||||
if (!get(config, "customIcons.enabled")) { return <RatingIcon /> }
|
||||
console.log(get(config, "customIcons.rating"))
|
||||
return get(config, "customIcons.rating") || <RatingIcon />;
|
||||
};
|
||||
const getStateOutline = (config: any) => {
|
||||
if (!get(config, "customIcons.enabled")) { return <RatingOutlineIcon /> }
|
||||
return get(config, "customIcons.rating") || <RatingOutlineIcon />;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ISettingsProps } from "@src/components/fields/types";
|
||||
import RatingIcon from "@mui/icons-material/Star";
|
||||
import RatingOutlineIcon from "@mui/icons-material/StarBorder"
|
||||
import { InputLabel, TextField, Grid, FormControlLabel, Checkbox, Stack } from "@mui/material";
|
||||
import ToggleButton from "@mui/material/ToggleButton";
|
||||
import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
|
||||
import MuiRating from "@mui/material/Rating";
|
||||
import { get } from "lodash-es";
|
||||
import Icon from "./Icon"
|
||||
|
||||
|
||||
export default function Settings({ onChange, config }: ISettingsProps) {
|
||||
return (
|
||||
@@ -80,9 +80,9 @@ export default function Settings({ onChange, config }: ISettingsProps) {
|
||||
<MuiRating aria-label="Preview of the rating field with custom icon"
|
||||
name="Preview"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
icon={get(config, "customIcons.rating") || <RatingIcon />}
|
||||
icon={<Icon config={config} isEmpty={false} />}
|
||||
size="small"
|
||||
emptyIcon={get(config, "customIcons.rating") || <RatingOutlineIcon />}
|
||||
emptyIcon={<Icon config={config} isEmpty={true} />}
|
||||
max={get(config, "max")}
|
||||
precision={get(config, "precision")}
|
||||
sx={{ pt: 0.5 }}
|
||||
|
||||
@@ -3,8 +3,9 @@ import { ISideDrawerFieldProps } from "@src/components/fields/types";
|
||||
import { Grid } from "@mui/material";
|
||||
import { Rating as MuiRating } from "@mui/material";
|
||||
import "@mui/lab";
|
||||
import { getStateIcon, getStateOutline } from "./TableCell";
|
||||
import { fieldSx } from "@src/components/SideDrawer/utils";
|
||||
import Icon from "./Icon"
|
||||
|
||||
|
||||
export default function Rating({
|
||||
column,
|
||||
@@ -28,8 +29,8 @@ export default function Rating({
|
||||
onChange(newValue);
|
||||
onSubmit();
|
||||
}}
|
||||
icon={getStateIcon(column.config)}
|
||||
emptyIcon={getStateOutline(column.config)}
|
||||
icon={<Icon config={column.config} isEmpty={false}/>}
|
||||
emptyIcon={<Icon config={column.config} isEmpty={true} />}
|
||||
size="small"
|
||||
max={max}
|
||||
precision={precision}
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
import { IHeavyCellProps } from "@src/components/fields/types";
|
||||
|
||||
import MuiRating from "@mui/material/Rating";
|
||||
import RatingIcon from "@mui/icons-material/Star";
|
||||
import RatingOutlineIcon from "@mui/icons-material/StarBorder"
|
||||
import { get } from "lodash-es";
|
||||
import Icon from "./Icon"
|
||||
|
||||
|
||||
export const getStateIcon = (config: any) => {
|
||||
// only use the config to get the custom rating icon if enabled via toggle
|
||||
if (!get(config, "customIcons.enabled")) { return <RatingIcon /> }
|
||||
return get(config, "customIcons.rating") || <RatingIcon />;
|
||||
};
|
||||
|
||||
export const getStateOutline = (config: any) => {
|
||||
if (!get(config, "customIcons.enabled")) { return <RatingOutlineIcon /> }
|
||||
return get(config, "customIcons.rating") || <RatingOutlineIcon />;
|
||||
}
|
||||
|
||||
export default function Rating({
|
||||
row,
|
||||
column,
|
||||
@@ -42,11 +29,11 @@ export default function Rating({
|
||||
name={`${row.id}-${column.key}`}
|
||||
value={typeof value === "number" ? value : 0}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
icon={getStateIcon(column.config)}
|
||||
icon={<Icon config={column.config} isEmpty={false} />}
|
||||
size="small"
|
||||
disabled={disabled}
|
||||
onChange={(_, newValue) => onSubmit(newValue)}
|
||||
emptyIcon={getStateOutline(column.config)}
|
||||
emptyIcon={<Icon config={column.config} isEmpty={true} />}
|
||||
max={max}
|
||||
precision={precision}
|
||||
sx={{ mx: -0.25 }}
|
||||
|
||||
@@ -376,12 +376,16 @@ export const tableFiltersToFirestoreFilters = (filters: TableFilter[]) => {
|
||||
} else if (filter.operator === "id-equal") {
|
||||
firestoreFilters.push(where(documentId(), "==", filter.value));
|
||||
continue;
|
||||
} else if (filter.operator === "color-equal") {
|
||||
firestoreFilters.push(where(filter.key.concat(".hex"), "==", filter.value.hex.toString()))
|
||||
continue
|
||||
} else if (filter.operator === "color-not-equal") {
|
||||
firestoreFilters.push(where(filter.key.concat(".hex"), "!=", filter.value.hex.toString()))
|
||||
continue
|
||||
}
|
||||
|
||||
firestoreFilters.push(
|
||||
where(filter.key, filter.operator as WhereFilterOp, filter.value)
|
||||
);
|
||||
}
|
||||
|
||||
return firestoreFilters;
|
||||
};
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import { Suspense } from "react";
|
||||
import { useAtom, Provider } from "jotai";
|
||||
import { DebugAtoms } from "@src/atoms/utils";
|
||||
import { useParams, useOutlet } from "react-router-dom";
|
||||
import { useParams, useOutlet, Link } from "react-router-dom";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
import { find, isEmpty } from "lodash-es";
|
||||
import useOffline from "@src/hooks/useOffline";
|
||||
|
||||
import ErrorFallback, {
|
||||
ERROR_TABLE_NOT_FOUND,
|
||||
} from "@src/components/ErrorFallback";
|
||||
import { Typography, Button } from "@mui/material";
|
||||
|
||||
import ErrorFallback from "@src/components/ErrorFallback";
|
||||
import TableSourceFirestore from "@src/sources/TableSourceFirestore";
|
||||
import TablePage from "./TablePage";
|
||||
import TableToolbarSkeleton from "@src/components/TableToolbar/TableToolbarSkeleton";
|
||||
import TableSkeleton from "@src/components/Table/TableSkeleton";
|
||||
import EmptyState from "@src/components/EmptyState";
|
||||
import OfflineIcon from "@mui/icons-material/CloudOff";
|
||||
import { Tables as TablesIcon } from "@src/assets/icons";
|
||||
|
||||
import {
|
||||
projectScope,
|
||||
@@ -26,6 +30,7 @@ import {
|
||||
tableSettingsAtom,
|
||||
} from "@src/atoms/tableScope";
|
||||
import { SyncAtomValue } from "@src/atoms/utils";
|
||||
import { ROUTES } from "@src/constants/routes";
|
||||
import useDocumentTitle from "@src/hooks/useDocumentTitle";
|
||||
|
||||
/**
|
||||
@@ -39,6 +44,7 @@ export default function ProvidedTablePage() {
|
||||
const [currentUser] = useAtom(currentUserAtom, projectScope);
|
||||
const [projectSettings] = useAtom(projectSettingsAtom, projectScope);
|
||||
const [tables] = useAtom(tablesAtom, projectScope);
|
||||
const isOffline = useOffline();
|
||||
|
||||
const tableSettings = find(tables, ["id", id]);
|
||||
useDocumentTitle(projectId, tableSettings ? tableSettings.name : "Not found");
|
||||
@@ -52,7 +58,41 @@ export default function ProvidedTablePage() {
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
throw new Error(ERROR_TABLE_NOT_FOUND + ": " + id);
|
||||
if (isOffline) {
|
||||
return (
|
||||
<EmptyState
|
||||
role="alert"
|
||||
fullScreen
|
||||
Icon={OfflineIcon}
|
||||
message="You’re offline"
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<EmptyState
|
||||
role="alert"
|
||||
fullScreen
|
||||
message="Table not found"
|
||||
description={
|
||||
<>
|
||||
<Typography variant="inherit">
|
||||
Make sure you have the right ID
|
||||
</Typography>
|
||||
<code>{id}</code>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
component={Link}
|
||||
to={ROUTES.tables}
|
||||
startIcon={<TablesIcon />}
|
||||
>
|
||||
All tables
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1375,11 +1375,12 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
|
||||
MuiRating: {
|
||||
styleOverrides: {
|
||||
iconFilled: { color: theme.palette.text.secondary },
|
||||
icon: {
|
||||
// https://github.com/mui/material-ui/issues/32557
|
||||
"& .MuiSvgIcon-root": { pointerEvents: "auto" },
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
iconEmpty: { opacity: 0.38 },
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
8
src/types/table.d.ts
vendored
8
src/types/table.d.ts
vendored
@@ -149,6 +149,10 @@ export type ColumnConfig = {
|
||||
};
|
||||
/** FieldType to render for Derivative fields */
|
||||
renderFieldType?: FieldType;
|
||||
/** Used in Derivative fields */
|
||||
listenerFields?: string[];
|
||||
/** Used in Derivative and Action fields */
|
||||
requiredFields?: string[];
|
||||
/** For sub-table fields */
|
||||
parentLabel?: string[];
|
||||
|
||||
@@ -169,7 +173,9 @@ export type TableFilter = {
|
||||
| "date-before-equal"
|
||||
| "date-after-equal"
|
||||
| "time-minute-equal"
|
||||
| "id-equal";
|
||||
| "id-equal"
|
||||
| "color-equal"
|
||||
| "color-not-equal";
|
||||
value: any;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user