remove functions page

This commit is contained in:
shamsmosowi
2023-06-11 14:25:49 +02:00
parent ed047f7925
commit b260b5c126
14 changed files with 1 additions and 757 deletions

View File

@@ -84,7 +84,7 @@
"startWithEmulators": "VITE_APP_FIREBASE_EMULATORS=true vite --port 7699",
"emulators": "firebase emulators:start --only firestore,auth --import ./emulators/ --export-on-exit",
"test": "vitest",
"build": "tsc && vite build",
"build": "tsc && cross-env NODE_OPTIONS=--max-old-space-size=8192 vite build",
"preview": "vite preview --port 7699",
"analyze": "source-map-explorer ./build/static/js/*.js",
"prepare": "husky install",

View File

@@ -1,55 +0,0 @@
import { AutoTypings, LocalStorageCache } from "monaco-editor-auto-typings";
import Editor, { OnMount } from "@monaco-editor/react";
const defaultCode = `import React from "react";
function App() {
return (
<div>
<h1>Hello World!</h1>
</div>
);
}
`;
const handleEditorMount: OnMount = (monacoEditor, monaco) => {
console.log("handleEditorMount");
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
target: monaco.languages.typescript.ScriptTarget.ES2016,
allowNonTsExtensions: true,
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
module: monaco.languages.typescript.ModuleKind.CommonJS,
noEmit: true,
typeRoots: ["node_modules/@types"],
});
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
noSemanticValidation: false,
noSyntaxValidation: false,
});
const autoTypings = AutoTypings.create(monacoEditor, {
sourceCache: new LocalStorageCache(), // Cache loaded sources in localStorage. May be omitted
monaco: monaco,
onError: (error) => {
console.log(error);
},
onUpdate: (update, textual) => {
console.log(textual);
},
});
};
export default function Function() {
const onChange = (value: string | undefined, ev: any) => {
//console.log(value)
};
return (
<Editor
height="100vh"
theme="vs-dark"
defaultPath="app.tsx"
defaultLanguage="typescript"
defaultValue={defaultCode}
onChange={onChange}
onMount={handleEditorMount}
/>
);
}

View File

@@ -1,2 +0,0 @@
//export * from "./Function";
export { default } from "./Function";

View File

@@ -1,79 +0,0 @@
import { Link } from "react-router-dom";
import {
Card,
CardActionArea,
CardContent,
Typography,
CardActions,
Button,
} from "@mui/material";
import { Go as GoIcon } from "@src/assets/icons";
import RenderedMarkdown from "@src/components/RenderedMarkdown";
import { TableSettings } from "@src/types/table";
export interface ITableCardProps extends TableSettings {
link: string;
actions?: React.ReactNode;
}
export default function TableCard({
section,
name,
description,
link,
actions,
}: ITableCardProps) {
return (
<Card style={{ height: "100%", display: "flex", flexDirection: "column" }}>
<CardActionArea component={Link} to={link}>
<CardContent style={{ paddingBottom: 0 }}>
<Typography variant="overline" component="p">
{section}
</Typography>
<Typography variant="h6" component="h3" gutterBottom>
{name}
</Typography>
</CardContent>
</CardActionArea>
<CardContent style={{ flexGrow: 1, paddingTop: 0 }}>
<Typography
color="textSecondary"
sx={{
minHeight: (theme) =>
(theme.typography.body2.lineHeight as number) * 2 + "em",
display: "flex",
flexDirection: "column",
gap: 1,
}}
component="div"
>
{description && (
<RenderedMarkdown
children={description}
//restrictionPreset="singleLine"
/>
)}
</Typography>
</CardContent>
<CardActions>
<Button
variant="text"
color="primary"
endIcon={<GoIcon />}
component={Link}
to={link}
>
Open
</Button>
<div style={{ flexGrow: 1 }} />
{actions}
</CardActions>
</Card>
);
}

View File

@@ -1,42 +0,0 @@
import {
Card,
CardContent,
Typography,
CardActions,
Skeleton,
} from "@mui/material";
export default function TableCardSkeleton() {
return (
<Card style={{ height: "100%", display: "flex", flexDirection: "column" }}>
<CardContent style={{ flexGrow: 1 }}>
<Typography variant="overline">
<Skeleton width={80} />
</Typography>
<Typography variant="h6" gutterBottom>
<Skeleton width={180} />
</Typography>
<Typography
color="textSecondary"
sx={{
minHeight: (theme) =>
(theme.typography.body2.lineHeight as number) * 2 + "em",
}}
>
<Skeleton width={120} />
</Typography>
</CardContent>
<CardActions sx={{ mb: 1, mx: 1 }}>
<Skeleton
width={60}
height={20}
variant="rectangular"
sx={{ borderRadius: 1, mr: "auto" }}
/>
<Skeleton variant="circular" width={24} height={24} />
</CardActions>
</Card>
);
}

View File

@@ -1,73 +0,0 @@
import { TransitionGroup } from "react-transition-group";
import { Box, Grid, Collapse } from "@mui/material";
import SectionHeading from "@src/components/SectionHeading";
import TableCard from "./TableCard";
import SlideTransition from "@src/components/Modal/SlideTransition";
import { TableSettings } from "@src/types/table";
export interface ITableGridProps {
sections: Record<string, TableSettings[]>;
getLink: (table: TableSettings) => string;
getActions?: (table: TableSettings) => React.ReactNode;
}
export default function TableGrid({
sections,
getLink,
getActions,
}: ITableGridProps) {
return (
<TransitionGroup>
{Object.entries(sections).map(
([sectionName, sectionTables], sectionIndex) => {
const tableItems = sectionTables
.map((table, tableIndex) => {
if (!table) return null;
return (
<SlideTransition
key={table.id}
appear
timeout={(sectionIndex + 1) * 100 + tableIndex * 50}
>
<Grid item xs={12} sm={6} md={4} lg={3}>
<TableCard
{...table}
link={getLink(table)}
actions={getActions ? getActions(table) : null}
/>
</Grid>
</SlideTransition>
);
})
.filter((item) => item !== null);
if (tableItems.length === 0) return null;
return (
<Collapse key={sectionName}>
<Box component="section" sx={{ mt: 4 }}>
<SlideTransition
key={"grid-section-" + sectionName}
in
timeout={(sectionIndex + 1) * 100}
>
<SectionHeading sx={{ pl: 2, pr: 1.5 }}>
{sectionName}
</SectionHeading>
</SlideTransition>
<Grid component={TransitionGroup} container spacing={2}>
{tableItems}
</Grid>
</Box>
</Collapse>
);
}
)}
</TransitionGroup>
);
}

View File

@@ -1,2 +0,0 @@
export * from "./TableGrid";
export { default } from "./TableGrid";

View File

@@ -1,71 +0,0 @@
import { TransitionGroup } from "react-transition-group";
import { Box, Paper, Collapse, List } from "@mui/material";
import SectionHeading from "@src/components/SectionHeading";
import TableListItem from "./TableListItem";
import SlideTransition from "@src/components/Modal/SlideTransition";
import { TableSettings } from "@src/types/table";
export interface ITableListProps {
sections: Record<string, TableSettings[]>;
getLink: (table: TableSettings) => string;
getActions?: (table: TableSettings) => React.ReactNode;
}
export default function TableList({
sections,
getLink,
getActions,
}: ITableListProps) {
return (
<TransitionGroup>
{Object.entries(sections).map(
([sectionName, sectionTables], sectionIndex) => {
const tableItems = sectionTables
.map((table) => {
if (!table) return null;
return (
<Collapse key={table.id}>
<TableListItem
{...table}
link={getLink(table)}
actions={getActions ? getActions(table) : null}
/>
</Collapse>
);
})
.filter((item) => item !== null);
if (tableItems.length === 0) return null;
return (
<Collapse key={sectionName}>
<Box component="section" sx={{ mt: 4 }}>
<SlideTransition
key={"list-section-" + sectionName}
in
timeout={(sectionIndex + 1) * 100}
>
<SectionHeading sx={{ pl: 2, pr: 1 }}>
{sectionName}
</SectionHeading>
</SlideTransition>
<SlideTransition in timeout={(sectionIndex + 1) * 100}>
<Paper>
<List disablePadding>
<TransitionGroup>{tableItems}</TransitionGroup>
</List>
</Paper>
</SlideTransition>
</Box>
</Collapse>
);
}
)}
</TransitionGroup>
);
}

View File

@@ -1,81 +0,0 @@
import { Link } from "react-router-dom";
import {
ListItem,
ListItemButton,
Typography,
IconButton,
} from "@mui/material";
import GoIcon from "@mui/icons-material/ArrowForward";
import RenderedMarkdown from "@src/components/RenderedMarkdown";
import { TableSettings } from "@src/types/table";
export interface ITableListItemProps extends TableSettings {
link: string;
actions?: React.ReactNode;
}
export default function TableListItem({
// section,
name,
description,
link,
actions,
}: ITableListItemProps) {
return (
<ListItem disableGutters disablePadding>
<ListItemButton
component={Link}
to={link}
sx={{
alignItems: "baseline",
height: 48,
py: 0,
pr: 0,
borderRadius: 2,
"& > *": { lineHeight: "48px !important" },
flexWrap: "nowrap",
overflow: "hidden",
flexBasis: 160 + 16,
flexGrow: 0,
flexShrink: 0,
mr: 2,
}}
>
<Typography component="h3" variant="button" noWrap>
{name}
</Typography>
</ListItemButton>
<Typography
color="textSecondary"
component="div"
noWrap
sx={{ flexGrow: 1, "& *": { display: "inline" } }}
>
{description && (
<RenderedMarkdown
children={description}
restrictionPreset="singleLine"
/>
)}
</Typography>
<div style={{ flexShrink: 0 }}>
{actions}
<IconButton
size="large"
color="primary"
component={Link}
to={link}
sx={{ display: { xs: "none", sm: "inline-flex" } }}
>
<GoIcon />
</IconButton>
</div>
</ListItem>
);
}

View File

@@ -1,23 +0,0 @@
import { ListItem, Skeleton } from "@mui/material";
export default function TableListItemSkeleton() {
return (
<ListItem disableGutters disablePadding style={{ height: 48 }}>
<Skeleton width={160} sx={{ mx: 2, flexShrink: 0 }} />
<Skeleton sx={{ mr: 2, flexBasis: 240, flexShrink: 1 }} />
<Skeleton
variant="circular"
width={24}
height={24}
sx={{ ml: "auto", mr: 3, flexShrink: 0 }}
/>
<Skeleton
variant="circular"
width={24}
height={24}
sx={{ mr: 1.5, flexShrink: 0 }}
/>
</ListItem>
);
}

View File

@@ -1,2 +0,0 @@
export * from "./TableList";
export { default } from "./TableList";

View File

@@ -1,33 +0,0 @@
import { Zoom, Stack, Typography } from "@mui/material";
export default function HomeWelcomePrompt() {
return (
<Zoom in style={{ transformOrigin: `${320 - 52}px ${320 - 52}px` }}>
<Stack
justifyContent="center"
sx={{
bgcolor: "primary.main",
color: "primary.contrastText",
boxShadow: 24,
width: 320,
height: 320,
p: 5,
borderRadius: "50% 50% 0 50%",
position: "fixed",
bottom: 0,
right: 0,
}}
>
<Typography variant="overline" component="h1" gutterBottom>
Get started
</Typography>
<Typography variant="h5" component="p">
Create a function
</Typography>
</Stack>
</Zoom>
);
}

View File

@@ -1,67 +0,0 @@
import { Suspense } from "react";
import { useAtom, Provider } from "jotai";
import { useParams } from "react-router-dom";
import { isEmpty } from "lodash-es";
import { Fade } from "@mui/material";
//import TableHeaderSkeleton from "@src/components/Table/Skeleton/TableHeaderSkeleton";
//import TableSkeleton from "@src/components/Table/Skeleton/TableSkeleton";
//import EmptyTable from "@src/components/Table/EmptyTable";
import Function from "@src/components/Function";
import { currentUserAtom, projectScope } from "@src/atoms/projectScope";
// import TableSourceFirestore from "@src/sources/TableSourceFirestore";
// import {
// tableScope,
// tableIdAtom,
// tableSettingsAtom,
// tableSchemaAtom,
// } from "@src/atoms/tableScope";
export default function FunctionPage() {
// const [tableId] = useAtom(tableIdAtom, tableScope);
// const [tableSettings] = useAtom(tableSettingsAtom, tableScope);
// const [tableSchema] = useAtom(tableSchemaAtom, tableScope);
// console.log(tableSchema);
// if (isEmpty(tableSchema.columns))
// return (
// <Fade style={{ transitionDelay: "500ms" }}>
// <div>
// <EmptyTable />
// </div>
// </Fade>
// );
return <Function key="function" />;
}
function ProvidedFunctionPage() {
const { id } = useParams();
const [currentUser] = useAtom(currentUserAtom, projectScope);
return (
<Suspense
fallback={
<>
{/* <TableHeaderSkeleton />
<TableSkeleton /> */}
</>
}
>
{/* <Provider
key={id}
scope={tableScope}
initialValues={[
[tableIdAtom, id],
[currentUserAtom, currentUser],
]}
> */}
{/* <TableSourceFirestore /> */}
<FunctionPage />
{/* </Provider> */}
</Suspense>
);
}

View File

@@ -1,226 +0,0 @@
import { useAtom, useSetAtom } from "jotai";
import { find, groupBy } from "lodash-es";
import {
Container,
Stack,
Typography,
ToggleButtonGroup,
ToggleButton,
Tooltip,
Fab,
Checkbox,
IconButton,
Zoom,
} from "@mui/material";
import ViewListIcon from "@mui/icons-material/ViewListOutlined";
import ViewGridIcon from "@mui/icons-material/ViewModuleOutlined";
import FavoriteBorderIcon from "@mui/icons-material/FavoriteBorder";
import FavoriteIcon from "@mui/icons-material/Favorite";
import EditIcon from "@mui/icons-material/EditOutlined";
import AddIcon from "@mui/icons-material/Add";
import FloatingSearch from "@src/components/FloatingSearch";
import SlideTransition from "@src/components/Modal/SlideTransition";
import FunctionGrid from "@src/components/Functions/FunctionGrid";
import FunctionList from "@src/components/Functions/FunctionList";
import HomeWelcomePrompt from "@src/components/Functions/HomeWelcomePrompt";
import EmptyState from "@src/components/EmptyState";
import {
projectScope,
userRolesAtom,
userSettingsAtom,
updateUserSettingsAtom,
tablesAtom,
tablesViewAtom,
tableSettingsDialogAtom,
} from "@src/atoms/projectScope";
import { TableSettings } from "@src/types/table";
import { ROUTES } from "@src/constants/routes";
import useBasicSearch from "@src/hooks/useBasicSearch";
import { TOP_BAR_HEIGHT } from "@src/layouts/Navigation/TopBar";
const SEARCH_KEYS = ["id", "name", "section", "description"];
export default function HomePage() {
const [userRoles] = useAtom(userRolesAtom, projectScope);
const [userSettings] = useAtom(userSettingsAtom, projectScope);
const [updateUserSettings] = useAtom(updateUserSettingsAtom, projectScope);
const [tables] = useAtom(tablesAtom, projectScope);
const [view, setView] = useAtom(tablesViewAtom, projectScope);
const openTableSettingsDialog = useSetAtom(
tableSettingsDialogAtom,
projectScope
);
const [results, query, handleQuery] = useBasicSearch(
tables ?? [],
SEARCH_KEYS
);
const favorites = Array.isArray(userSettings.favoriteTables)
? userSettings.favoriteTables
: [];
const sections: Record<string, TableSettings[]> = {
Favorites: favorites.map((id) => find(results, { id })) as TableSettings[],
...groupBy(results, "section"),
};
if (!Array.isArray(tables))
throw new Error(
"Project settings are not configured correctly. `tables` is not an array."
);
const createFunctionFab = (
<Tooltip title="Create function">
<Zoom in>
<Fab
color="secondary"
aria-label="Create table"
onClick={() => openTableSettingsDialog({ mode: "create" })}
sx={{
zIndex: "speedDial",
position: "fixed",
bottom: (theme) => ({
xs: `max(${theme.spacing(2)}, env(safe-area-inset-bottom))`,
sm: `max(${theme.spacing(3)}, env(safe-area-inset-bottom))`,
}),
right: (theme) => ({
xs: `max(${theme.spacing(2)}, env(safe-area-inset-right))`,
sm: `max(${theme.spacing(3)}, env(safe-area-inset-right))`,
}),
}}
>
<AddIcon />
</Fab>
</Zoom>
</Tooltip>
);
if (tables.length === 0) {
if (userRoles.includes("ADMIN"))
return (
<>
<HomeWelcomePrompt />
{createFunctionFab}
</>
);
return (
<EmptyState
message="No tables"
description="There are no tables in this project. Sign in with an ADMIN account to create tables."
fullScreen
style={{ marginTop: -TOP_BAR_HEIGHT }}
/>
);
}
const getLink = (table: TableSettings) =>
`${ROUTES.table}/${table.id.replace(/\//g, "~2F")}`;
const handleFavorite =
(id: string) => (e: React.ChangeEvent<HTMLInputElement>) => {
const favoriteTables = e.target.checked
? [...favorites, id]
: favorites.filter((f) => f !== id);
if (updateUserSettings) updateUserSettings({ favoriteTables });
};
const getActions = (table: TableSettings) => (
<>
{userRoles.includes("ADMIN") && (
<IconButton
aria-label="Edit table"
onClick={() =>
openTableSettingsDialog({ mode: "update", data: table })
}
size={view === "list" ? "large" : undefined}
>
<EditIcon />
</IconButton>
)}
<Checkbox
onChange={handleFavorite(table.id)}
checked={favorites.includes(table.id)}
icon={<FavoriteBorderIcon />}
checkedIcon={
<Zoom in>
<FavoriteIcon />
</Zoom>
}
name={`favorite-${table.id}`}
inputProps={{ "aria-label": "Favorite" }}
sx={view === "list" ? { p: 1.5 } : undefined}
color="secondary"
/>
</>
);
return (
<Container component="main" sx={{ px: 1, pt: 1, pb: 7 + 3 + 3 }}>
<FloatingSearch
label="Search tables"
onChange={(e) => handleQuery(e.target.value)}
paperSx={{
maxWidth: (theme) => ({ md: theme.breakpoints.values.sm - 48 }),
mb: { xs: 2, md: -6 },
}}
/>
<SlideTransition in timeout={50}>
<Stack
direction="row"
spacing={2}
alignItems="center"
justifyContent="space-between"
>
<Typography
variant="h6"
component="h1"
sx={{ pl: 2, cursor: "default" }}
>
{query ? `${results.length} of ${tables.length}` : tables.length}{" "}
tables
</Typography>
<ToggleButtonGroup
value={view}
size="large"
exclusive
onChange={(_, v) => {
if (v !== null) setView(v);
}}
aria-label="Table view"
sx={{ "& .MuiToggleButton-root": { borderRadius: 2 } }}
>
<ToggleButton value="list" aria-label="List view">
<ViewListIcon style={{ transform: "rotate(180deg)" }} />
</ToggleButton>
<ToggleButton value="grid" aria-label="Grid view">
<ViewGridIcon />
</ToggleButton>
</ToggleButtonGroup>
</Stack>
</SlideTransition>
{view === "list" ? (
<FunctionList
sections={sections}
getLink={getLink}
getActions={getActions}
/>
) : (
<FunctionGrid
sections={sections}
getLink={getLink}
getActions={getActions}
/>
)}
{userRoles.includes("ADMIN") && createFunctionFab}
</Container>
);
}