mirror of
https://github.com/rowyio/rowy.git
synced 2026-07-12 21:39:28 +02:00
import csv step 1
This commit is contained in:
@@ -15,7 +15,7 @@ import { APP_BAR_HEIGHT } from "components/Navigation";
|
||||
import { useFiretableContext } from "contexts/firetableContext";
|
||||
import ColumnMenu from "./ColumnMenu";
|
||||
import ImportWizard from "components/Wizards/ImportWizard";
|
||||
import ImportCSV from "./TableHeader/ImportCSV";
|
||||
import ImportCSV from "./TableHeader/ImportCsv";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
|
||||
@@ -7,7 +7,7 @@ import VisibilityOffIcon from "@material-ui/icons/VisibilityOff";
|
||||
|
||||
import MultiSelect from "@antlerengineering/multiselect";
|
||||
import ButtonWithStatus from "components/ButtonWithStatus";
|
||||
import Column from "components/Wizards/ImportWizard/Column";
|
||||
import Column from "components/Wizards/Column";
|
||||
|
||||
import { useFiretableContext } from "contexts/firetableContext";
|
||||
import { useAppContext } from "contexts/appContext";
|
||||
|
||||
@@ -96,7 +96,7 @@ const selectedColumnsReducer = (doc: any) => (
|
||||
}
|
||||
};
|
||||
|
||||
export default function ExportCSV() {
|
||||
export default function ExportCsv() {
|
||||
const classes = useStyles();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
|
||||
@@ -24,9 +24,13 @@ import TabPanel from "@material-ui/lab/TabPanel";
|
||||
|
||||
import ImportIcon from "assets/icons/Import";
|
||||
import FileUploadIcon from "assets/icons/FileUpload";
|
||||
import AttachmentIcon from "@material-ui/icons/AttachFile";
|
||||
import CheckIcon from "@material-ui/icons/CheckCircle";
|
||||
import GoIcon from "assets/icons/Go";
|
||||
|
||||
import ImportCsvWizard, {
|
||||
IImportCsvWizardProps,
|
||||
} from "components/Wizards/ImportCsvWizard";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
button: {
|
||||
@@ -76,22 +80,23 @@ const useStyles = makeStyles((theme) =>
|
||||
})
|
||||
);
|
||||
|
||||
export interface IImportCSVProps {
|
||||
export interface IImportCsvProps {
|
||||
render?: (
|
||||
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void
|
||||
) => React.ReactNode;
|
||||
}
|
||||
|
||||
export default function ImportCSV({ render }: IImportCSVProps) {
|
||||
export default function ImportCsv({ render }: IImportCsvProps) {
|
||||
const classes = useStyles();
|
||||
|
||||
const [open, setOpen] = useState<HTMLButtonElement | null>(null);
|
||||
const [tab, setTab] = useState("upload");
|
||||
const [csvData, setCsvData] = useState<{
|
||||
columns: string[];
|
||||
rows: string[][];
|
||||
} | null>(null);
|
||||
const [csvData, setCsvData] = useState<IImportCsvWizardProps["csvData"]>(
|
||||
null
|
||||
);
|
||||
const [error, setError] = useState("");
|
||||
const validCsv =
|
||||
csvData !== null && csvData?.columns.length > 0 && csvData?.rows.length > 0;
|
||||
|
||||
const handleOpen = (event: React.MouseEvent<HTMLButtonElement>) =>
|
||||
setOpen(event.currentTarget);
|
||||
@@ -152,6 +157,8 @@ export default function ImportCSV({ render }: IImportCSVProps) {
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
const [openWizard, setOpenWizard] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
{render ? (
|
||||
@@ -218,11 +225,17 @@ export default function ImportCSV({ render }: IImportCSVProps) {
|
||||
) : (
|
||||
<>
|
||||
<Grid item>
|
||||
<FileUploadIcon color="inherit" />
|
||||
{validCsv ? (
|
||||
<CheckIcon color="inherit" />
|
||||
) : (
|
||||
<FileUploadIcon color="inherit" />
|
||||
)}
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="overline" color="inherit">
|
||||
Click to upload or drop CSV file here
|
||||
{validCsv
|
||||
? "Valid CSV"
|
||||
: "Click to upload or drop CSV file here"}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</>
|
||||
@@ -277,16 +290,49 @@ export default function ImportCSV({ render }: IImportCSVProps) {
|
||||
|
||||
<Button
|
||||
endIcon={<GoIcon />}
|
||||
disabled={
|
||||
csvData === null ||
|
||||
csvData?.columns.length === 0 ||
|
||||
csvData?.rows.length === 0
|
||||
}
|
||||
disabled={!validCsv}
|
||||
className={classes.continueButton}
|
||||
onClick={() => setOpenWizard(true)}
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</Popover>
|
||||
|
||||
<ImportCsvWizard
|
||||
// open={openWizard}
|
||||
setOpen={setOpenWizard}
|
||||
// csvData={csvData}
|
||||
open
|
||||
csvData={{
|
||||
columns: [
|
||||
"Title",
|
||||
"Show On Fusion",
|
||||
"Datastudio Link",
|
||||
"Fusion Section",
|
||||
],
|
||||
rows: [
|
||||
["Events Data", "NO", "", "/events/global"],
|
||||
[
|
||||
"Antler Global Key Statistics",
|
||||
"NO",
|
||||
"https://datastudio.google.com/embed/reporting/14x4t3K_8pwhsdPN27gQlgykMBOJtsm16/page/sq7VB",
|
||||
"/employees",
|
||||
],
|
||||
[
|
||||
"Program Resource Usage Stats",
|
||||
"YES",
|
||||
"https://datastudio.google.com/embed/reporting/709aea8c-db5a-451f-88c5-51485b8ece63/page/p6veB",
|
||||
"/resources/program",
|
||||
],
|
||||
[
|
||||
"Founder Stats",
|
||||
"YES",
|
||||
"https://datastudio.google.com/embed/reporting/1Ka1xm1OhrZU6BtfMQB0hGtLdgfZeH-nQ/page/oXEBB",
|
||||
"/cohort/founders",
|
||||
],
|
||||
],
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ import { isCollectionGroup } from "util/fns";
|
||||
import AddRowIcon from "assets/icons/AddRow";
|
||||
|
||||
import Filters from "../Filters";
|
||||
import ImportCSV from "./ImportCSV";
|
||||
import ExportCSV from "./ExportCSV";
|
||||
import ImportCSV from "./ImportCsv";
|
||||
import ExportCSV from "./ExportCsv";
|
||||
import TableSettings from "./TableSettings";
|
||||
|
||||
import { DRAWER_COLLAPSED_WIDTH } from "components/SideDrawer";
|
||||
|
||||
154
www/src/components/Wizards/ImportCsvWizard/Step1Columns.tsx
Normal file
154
www/src/components/Wizards/ImportCsvWizard/Step1Columns.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import MultiSelect from "@antlerengineering/multiselect";
|
||||
import _find from "lodash/find";
|
||||
|
||||
import {
|
||||
makeStyles,
|
||||
createStyles,
|
||||
Grid,
|
||||
Typography,
|
||||
Divider,
|
||||
FormControlLabel,
|
||||
Checkbox,
|
||||
} from "@material-ui/core";
|
||||
import ArrowIcon from "@material-ui/icons/ArrowForward";
|
||||
|
||||
import { IStepProps } from ".";
|
||||
import FadeList from "../FadeList";
|
||||
import Column from "../Column";
|
||||
import EmptyState from "components/EmptyState";
|
||||
import AddColumnIcon from "assets/icons/AddColumn";
|
||||
|
||||
import { useFiretableContext } from "contexts/firetableContext";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
csvListItem: { display: "flex" },
|
||||
csvColumn: {},
|
||||
|
||||
formControlLabel: {
|
||||
marginRight: 0,
|
||||
flex: 1,
|
||||
},
|
||||
columnLabel: { flex: 1 },
|
||||
|
||||
arrowGridItem: {
|
||||
width: theme.spacing(7),
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default function Step1Columns({
|
||||
csvData,
|
||||
config,
|
||||
updateConfig,
|
||||
isXs,
|
||||
}: IStepProps) {
|
||||
const classes = useStyles();
|
||||
|
||||
const { tableState } = useFiretableContext();
|
||||
const tableColumns = Object.values(
|
||||
tableState?.columns ?? {}
|
||||
).map((column) => ({ label: column.name, value: column.key }));
|
||||
|
||||
const [selectedFields, setSelectedFields] = useState(
|
||||
config.pairs.map((pair) => pair.csvKey)
|
||||
);
|
||||
|
||||
const handleSelect = (field: string) => (_, checked: boolean) => {
|
||||
if (checked) {
|
||||
setSelectedFields((x) => [...x, field]);
|
||||
} else {
|
||||
const newValue = [...selectedFields];
|
||||
newValue.splice(newValue.indexOf(field), 1);
|
||||
setSelectedFields(newValue);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (csvKey: string) => (columnKey: string) =>
|
||||
updateConfig({ pairs: [{ csvKey, columnKey }] });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid container spacing={7}>
|
||||
{!isXs && (
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Typography variant="overline" gutterBottom component="h2">
|
||||
Select Columns ({config.pairs.length} of {csvData.columns.length})
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Typography variant="overline" gutterBottom component="h2">
|
||||
Firetable Columns
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Divider />
|
||||
|
||||
<FadeList>
|
||||
{csvData.columns.map((field) => {
|
||||
const selected = selectedFields.indexOf(field) > -1;
|
||||
const ftColumnKey =
|
||||
_find(config.pairs, { csvKey: field })?.columnKey ?? null;
|
||||
const matchingColumn = ftColumnKey
|
||||
? tableState?.columns[ftColumnKey]
|
||||
: null;
|
||||
|
||||
return (
|
||||
<Grid container key={field} component="li" wrap="nowrap">
|
||||
<Grid item xs>
|
||||
<FormControlLabel
|
||||
key={field}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={selected}
|
||||
aria-label={`Select column ${field}`}
|
||||
onChange={handleSelect(field)}
|
||||
color="default"
|
||||
/>
|
||||
}
|
||||
label={<Column label={field} className={classes.csvColumn} />}
|
||||
classes={{
|
||||
root: classes.formControlLabel,
|
||||
label: classes.columnLabel,
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item className={classes.arrowGridItem}>
|
||||
<ArrowIcon color={selected ? "action" : "disabled"} />
|
||||
</Grid>
|
||||
|
||||
<Grid item xs>
|
||||
{selected && (
|
||||
<MultiSelect
|
||||
multiple={false}
|
||||
options={tableColumns}
|
||||
value={ftColumnKey}
|
||||
onChange={handleChange(field) as any}
|
||||
TextFieldProps={{
|
||||
hiddenLabel: true,
|
||||
SelectProps: {
|
||||
renderValue: (_) => {
|
||||
if (!ftColumnKey) return "Select or add column";
|
||||
else return matchingColumn.name;
|
||||
},
|
||||
},
|
||||
}}
|
||||
clearable={false}
|
||||
displayEmpty
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</FadeList>
|
||||
</>
|
||||
);
|
||||
}
|
||||
113
www/src/components/Wizards/ImportCsvWizard/index.tsx
Normal file
113
www/src/components/Wizards/ImportCsvWizard/index.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import _merge from "lodash/merge";
|
||||
|
||||
import { useTheme, useMediaQuery, Typography } from "@material-ui/core";
|
||||
|
||||
import WizardDialog from "../WizardDialog";
|
||||
import Step1Columns from "./Step1Columns";
|
||||
|
||||
import { ColumnConfig } from "hooks/useFiretable/useTableConfig";
|
||||
import { useFiretableContext } from "contexts/firetableContext";
|
||||
|
||||
export type CsvConfig = {
|
||||
pairs: { csvKey: string; columnKey: string }[];
|
||||
newColumns: string[];
|
||||
};
|
||||
|
||||
export interface IStepProps {
|
||||
csvData: NonNullable<IImportCsvWizardProps["csvData"]>;
|
||||
config: CsvConfig;
|
||||
setConfig: React.Dispatch<React.SetStateAction<CsvConfig>>;
|
||||
updateConfig: (value: Partial<ColumnConfig>) => void;
|
||||
isXs: boolean;
|
||||
}
|
||||
|
||||
export interface IImportCsvWizardProps {
|
||||
open: boolean;
|
||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
csvData: {
|
||||
columns: string[];
|
||||
rows: string[][];
|
||||
} | null;
|
||||
}
|
||||
|
||||
export default function ImportCsvWizard({
|
||||
open,
|
||||
setOpen,
|
||||
csvData,
|
||||
}: IImportCsvWizardProps) {
|
||||
const theme = useTheme();
|
||||
const isXs = useMediaQuery(theme.breakpoints.down("xs"));
|
||||
|
||||
const { tableState, tableActions } = useFiretableContext();
|
||||
|
||||
const [config, setConfig] = useState<CsvConfig>({
|
||||
pairs: [],
|
||||
newColumns: [],
|
||||
});
|
||||
const updateConfig: IStepProps["updateConfig"] = (value) => {
|
||||
setConfig((prev) => ({ ..._merge(prev, value) }));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!tableState || !open) return;
|
||||
|
||||
if (Array.isArray(tableState.filters) && tableState.filters?.length > 0)
|
||||
tableActions!.table.filter([]);
|
||||
|
||||
if (Array.isArray(tableState.orderBy) && tableState.orderBy?.length > 0)
|
||||
tableActions!.table.orderBy([]);
|
||||
}, [open, tableState]);
|
||||
|
||||
if (tableState?.rows.length === 0) return null;
|
||||
|
||||
const handleFinish = () => {
|
||||
tableActions?.table.updateConfig("columns", config);
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
if (!csvData) return null;
|
||||
|
||||
return (
|
||||
<WizardDialog
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
title="Import CSV"
|
||||
steps={[
|
||||
{
|
||||
title: "choose columns",
|
||||
description: "Select which columns to import to your table.",
|
||||
content: (
|
||||
<Step1Columns
|
||||
csvData={csvData}
|
||||
config={config}
|
||||
setConfig={setConfig}
|
||||
updateConfig={updateConfig}
|
||||
isXs={isXs}
|
||||
/>
|
||||
),
|
||||
disableNext: Object.keys(config).length === 0,
|
||||
},
|
||||
{
|
||||
title: "rename columns",
|
||||
description:
|
||||
"Rename your Firetable columns with user-friendly names. These changes will not update the field names in your database.",
|
||||
content: <div>Step2Rename</div>,
|
||||
},
|
||||
{
|
||||
title: "set column types",
|
||||
description:
|
||||
"Set the type of each column to display your data correctly. Some column types have been suggested based off your data.",
|
||||
content: <div>Step3Types</div>,
|
||||
},
|
||||
{
|
||||
title: "preview",
|
||||
description:
|
||||
"Preview your data with your configured columns. You can change column types by clicking “Edit Type” from the column menu at any time.",
|
||||
content: <div>Step4Preview</div>,
|
||||
},
|
||||
]}
|
||||
onFinish={handleFinish}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -21,8 +21,8 @@ import {
|
||||
import DragHandleIcon from "@material-ui/icons/DragHandle";
|
||||
|
||||
import { IStepProps } from ".";
|
||||
import FadeList from "./FadeList";
|
||||
import Column from "./Column";
|
||||
import FadeList from "../FadeList";
|
||||
import Column from "../Column";
|
||||
import EmptyState from "components/EmptyState";
|
||||
import AddColumnIcon from "assets/icons/AddColumn";
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ import EditIcon from "@material-ui/icons/Edit";
|
||||
import DoneIcon from "@material-ui/icons/Done";
|
||||
|
||||
import { IStepProps } from ".";
|
||||
import FadeList from "./FadeList";
|
||||
import Column from "./Column";
|
||||
import FadeList from "../FadeList";
|
||||
import Column from "../Column";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
|
||||
|
||||
import { IStepProps } from ".";
|
||||
import FadeList from "./FadeList";
|
||||
import Column from "./Column";
|
||||
import Cell from "./Cell";
|
||||
import FadeList from "../FadeList";
|
||||
import Column from "../Column";
|
||||
import Cell from "../Cell";
|
||||
import FieldsDropdown from "components/Table/ColumnMenu/FieldsDropdown";
|
||||
|
||||
import { useFiretableContext } from "contexts/firetableContext";
|
||||
|
||||
@@ -4,8 +4,8 @@ import { ScrollSync, ScrollSyncPane } from "react-scroll-sync";
|
||||
import { makeStyles, createStyles, Grid } from "@material-ui/core";
|
||||
|
||||
import { IStepProps } from ".";
|
||||
import Column from "./Column";
|
||||
import Cell from "./Cell";
|
||||
import Column from "../Column";
|
||||
import Cell from "../Cell";
|
||||
|
||||
import { useFiretableContext } from "contexts/firetableContext";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user