form style refactor + charts

This commit is contained in:
Jan Prochazka
2020-12-06 10:23:57 +01:00
parent 0c4d5b5356
commit 3bb22ddc36
10 changed files with 131 additions and 140 deletions

View File

@@ -12,6 +12,8 @@ import { loadChartData, loadChartStructure } from './chartDataLoader';
import useExtensions from '../utility/useExtensions'; import useExtensions from '../utility/useExtensions';
import { getConnectionInfo } from '../utility/metadataLoaders'; import { getConnectionInfo } from '../utility/metadataLoaders';
import { findEngineDriver } from 'dbgate-tools'; import { findEngineDriver } from 'dbgate-tools';
import { FormFieldTemplateTiny } from '../utility/formStyle';
import { ManagerInnerContainer } from '../datagrid/ManagerStyles';
const LeftContainer = styled.div` const LeftContainer = styled.div`
background-color: ${(props) => props.theme.manager_background}; background-color: ${(props) => props.theme.manager_background};
@@ -72,11 +74,12 @@ export default function ChartEditor({ data, config, setConfig, sql, conid, datab
}, [config, sql, conid, database]); }, [config, sql, conid, database]);
return ( return (
<FormProviderCore values={config} setValues={setConfig}> <FormProviderCore values={config} setValues={setConfig} template={FormFieldTemplateTiny}>
<HorizontalSplitter initialValue="300px" size={managerSize} setSize={setManagerSize}> <HorizontalSplitter initialValue="300px" size={managerSize} setSize={setManagerSize}>
<LeftContainer theme={theme}> <LeftContainer theme={theme}>
<WidgetColumnBar> <WidgetColumnBar>
<WidgetColumnBarItem title="Style" name="style" height="40%"> <WidgetColumnBarItem title="Style" name="style" height="40%">
<ManagerInnerContainer style={{ maxWidth: managerSize }}>
<FormSelectField label="Chart type" name="chartType"> <FormSelectField label="Chart type" name="chartType">
<option value="bar">Bar</option> <option value="bar">Bar</option>
<option value="line">Line</option> <option value="line">Line</option>
@@ -86,9 +89,17 @@ export default function ChartEditor({ data, config, setConfig, sql, conid, datab
{/* <option value="bubble">Bubble</option> {/* <option value="bubble">Bubble</option>
<option value="scatter">Scatter</option> */} <option value="scatter">Scatter</option> */}
</FormSelectField> </FormSelectField>
<FormTextField label="Color seed" name="colorSeed" /> <FormSelectField label="Color set" name="colorSeed">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</FormSelectField>
</ManagerInnerContainer>
</WidgetColumnBarItem> </WidgetColumnBarItem>
<WidgetColumnBarItem title="Data" name="data"> <WidgetColumnBarItem title="Data" name="data">
<ManagerInnerContainer style={{ maxWidth: managerSize }}>
{availableColumnNames.length > 0 && ( {availableColumnNames.length > 0 && (
<FormSelectField label="Label column" name="labelColumn"> <FormSelectField label="Label column" name="labelColumn">
<option value=""></option> <option value=""></option>
@@ -102,6 +113,7 @@ export default function ChartEditor({ data, config, setConfig, sql, conid, datab
{availableColumnNames.map((col) => ( {availableColumnNames.map((col) => (
<FormCheckboxField label={col} name={`dataColumn_${col}`} key={col} /> <FormCheckboxField label={col} name={`dataColumn_${col}`} key={col} />
))} ))}
</ManagerInnerContainer>
</WidgetColumnBarItem> </WidgetColumnBarItem>
</WidgetColumnBar> </WidgetColumnBar>
</LeftContainer> </LeftContainer>

View File

@@ -1,82 +1,28 @@
import React from 'react'; import React from 'react';
import _ from 'lodash';
import Chart from 'react-chartjs-2'; import Chart from 'react-chartjs-2';
import randomcolor from 'randomcolor'; import randomcolor from 'randomcolor';
import styled from 'styled-components'; import styled from 'styled-components';
import useTheme from '../theme/useTheme';
import useDimensions from '../utility/useDimensions'; import useDimensions from '../utility/useDimensions';
import { HorizontalSplitter } from '../widgets/Splitter';
import WidgetColumnBar, { WidgetColumnBarItem } from '../widgets/WidgetColumnBar';
import { FormSelectField } from '../utility/forms';
import { useForm } from '../utility/FormProvider'; import { useForm } from '../utility/FormProvider';
import { saturateByTenth } from '../theme/colorUtil';
const ChartWrapper = styled.div` const ChartWrapper = styled.div`
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
`; `;
// const chartData = {
// labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
// datasets: [
// {
// label: '# of Votes',
// data: [12, 19, 3, 5, 2, 3],
// backgroundColor: [
// 'rgba(255, 99, 132, 0.2)',
// 'rgba(54, 162, 235, 0.2)',
// 'rgba(255, 206, 86, 0.2)',
// 'rgba(75, 192, 192, 0.2)',
// 'rgba(153, 102, 255, 0.2)',
// 'rgba(255, 159, 64, 0.2)',
// ],
// borderColor: [
// 'rgba(255, 99, 132, 1)',
// 'rgba(54, 162, 235, 1)',
// 'rgba(255, 206, 86, 1)',
// 'rgba(75, 192, 192, 1)',
// 'rgba(153, 102, 255, 1)',
// 'rgba(255, 159, 64, 1)',
// ],
// borderWidth: 1,
// },
// ],
// };
function createChartData(freeData, labelColumn, dataColumns, colorSeed, chartType) { function createChartData(freeData, labelColumn, dataColumns, colorSeed, chartType) {
if (!freeData || !labelColumn || !dataColumns || dataColumns.length == 0) return {}; if (!freeData || !labelColumn || !dataColumns || dataColumns.length == 0) return {};
const labels = _.uniq(freeData.rows.map((x) => x[labelColumn]));
const colors = randomcolor({ const colors = randomcolor({
count: labels.length, count: freeData.rows.length,
seed: colorSeed, seed: colorSeed,
}); });
const res = { const res = {
labels: freeData.rows.map((x) => x[labelColumn]), labels: freeData.rows.map((x) => x[labelColumn]),
datasets: dataColumns.map((dataColumn) => ({ datasets: dataColumns.map((dataColumn) => ({
label: dataColumn, label: dataColumn,
// data: [12, 19, 3, 5, 2, 3], data: freeData.rows.map((row) => row[dataColumn]),
data: labels.map((label) =>
_.sum(freeData.rows.filter((row) => row[labelColumn] == label).map((row) => row[dataColumn]))
),
backgroundColor: chartType != 'line' ? colors : null, backgroundColor: chartType != 'line' ? colors : null,
borderColor: chartType == 'line' ? colors : null, borderColor: chartType == 'line' ? colors : null,
// borderColor: colors, // .map(saturateByTenth),
// backgroundColor: [
// 'rgba(255, 99, 132, 0.2)',
// 'rgba(54, 162, 235, 0.2)',
// 'rgba(255, 206, 86, 0.2)',
// 'rgba(75, 192, 192, 0.2)',
// 'rgba(153, 102, 255, 0.2)',
// 'rgba(255, 159, 64, 0.2)',
// ],
// borderColor: [
// 'rgba(255, 99, 132, 1)',
// 'rgba(54, 162, 235, 1)',
// 'rgba(255, 206, 86, 1)',
// 'rgba(75, 192, 192, 1)',
// 'rgba(153, 102, 255, 1)',
// 'rgba(255, 159, 64, 1)',
// ],
borderWidth: 1, borderWidth: 1,
})), })),
}; };

View File

@@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import ModalBase from './ModalBase'; import ModalBase from './ModalBase';
import { FormButtonRow } from '../utility/forms';
import FormStyledButton from '../widgets/FormStyledButton'; import FormStyledButton from '../widgets/FormStyledButton';
import SqlEditor from '../sqleditor/SqlEditor'; import SqlEditor from '../sqleditor/SqlEditor';
import styled from 'styled-components'; import styled from 'styled-components';

View File

@@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import ModalBase from './ModalBase'; import ModalBase from './ModalBase';
import { FormButtonRow } from '../utility/forms';
import FormStyledButton from '../widgets/FormStyledButton'; import FormStyledButton from '../widgets/FormStyledButton';
import SqlEditor from '../sqleditor/SqlEditor'; import SqlEditor from '../sqleditor/SqlEditor';
import styled from 'styled-components'; import styled from 'styled-components';

View File

@@ -1,11 +1,12 @@
import React from 'react'; import React from 'react';
import ModalBase from './ModalBase'; import ModalBase from './ModalBase';
import { FormTextField, FormSubmit, FormArchiveFolderSelect, FormRow, FormLabel } from '../utility/forms'; import { FormTextField, FormSubmit, FormArchiveFolderSelect } from '../utility/forms';
import styled from 'styled-components'; import styled from 'styled-components';
import ModalHeader from './ModalHeader'; import ModalHeader from './ModalHeader';
import ModalContent from './ModalContent'; import ModalContent from './ModalContent';
import ModalFooter from './ModalFooter'; import ModalFooter from './ModalFooter';
import { FormProvider } from '../utility/FormProvider'; import { FormProvider } from '../utility/FormProvider';
import { FormFieldTemplateDefault } from '../utility/formStyle';
const SelectWrapper = styled.div` const SelectWrapper = styled.div`
width: 150px; width: 150px;
@@ -24,13 +25,11 @@ export default function SaveArchiveModal({ file = 'new-table', folder = 'default
<ModalHeader modalState={modalState}>Save to archive</ModalHeader> <ModalHeader modalState={modalState}>Save to archive</ModalHeader>
<FormProvider initialValues={{ file, folder }}> <FormProvider initialValues={{ file, folder }}>
<ModalContent> <ModalContent>
{/* <Label>Archive folder</Label> */} <FormFieldTemplateDefault label="Folder" type="select">
<FormRow>
<FormLabel>Folder</FormLabel>
<SelectWrapper> <SelectWrapper>
<FormArchiveFolderSelect name="folder" /> <FormArchiveFolderSelect name="folder" />
</SelectWrapper> </SelectWrapper>
</FormRow> </FormFieldTemplateDefault>
<FormTextField label="File name" name="file" /> <FormTextField label="File name" name="file" />
</ModalContent> </ModalContent>
<ModalFooter> <ModalFooter>

View File

@@ -1,13 +1,11 @@
import React from 'react'; import React from 'react';
import axios from '../utility/axios'; import axios from '../utility/axios';
import ModalBase from './ModalBase'; import ModalBase from './ModalBase';
import { FormButtonRow, FormButton, FormTextField, FormSelectField, FormSubmit } from '../utility/forms'; import { FormTextField, FormSubmit } from '../utility/forms';
import { TextField } from '../utility/inputs';
import ModalHeader from './ModalHeader'; import ModalHeader from './ModalHeader';
import ModalContent from './ModalContent'; import ModalContent from './ModalContent';
import ModalFooter from './ModalFooter'; import ModalFooter from './ModalFooter';
import { FormProvider } from '../utility/FormProvider'; import { FormProvider } from '../utility/FormProvider';
// import FormikForm from '../utility/FormikForm';
export default function SaveFileModal({ data, folder, format, modalState, name, onSave = undefined }) { export default function SaveFileModal({ data, folder, format, modalState, name, onSave = undefined }) {
const handleSubmit = async (values) => { const handleSubmit = async (values) => {

View File

@@ -2,19 +2,13 @@ import React from 'react';
import ModalBase from './ModalBase'; import ModalBase from './ModalBase';
import FormStyledButton from '../widgets/FormStyledButton'; import FormStyledButton from '../widgets/FormStyledButton';
import styled from 'styled-components'; import styled from 'styled-components';
import { import { FormSubmit, FormSelectFieldRaw, FormRadioGroupItem, FormTextFieldRaw } from '../utility/forms';
FormButtonRow,
FormSubmit,
FormSelectFieldRaw,
FormRow,
FormRadioGroupItem,
FormTextFieldRaw,
} from '../utility/forms';
import ModalHeader from './ModalHeader'; import ModalHeader from './ModalHeader';
import ModalFooter from './ModalFooter'; import ModalFooter from './ModalFooter';
import ModalContent from './ModalContent'; import ModalContent from './ModalContent';
import { TextField } from '../utility/inputs'; import { TextField } from '../utility/inputs';
import { FormProvider } from '../utility/FormProvider'; import { FormProvider } from '../utility/FormProvider';
import { FormRow } from '../utility/formStyle';
const Wrapper = styled.div` const Wrapper = styled.div`
display: flex; display: flex;

View File

@@ -1,18 +1,20 @@
import React from 'react'; import React from 'react';
import { FormFieldTemplateDefault } from './formStyle';
import keycodes from './keycodes'; import keycodes from './keycodes';
const FormContext = React.createContext(null); const FormContext = React.createContext(null);
const FormFieldTemplateContext = React.createContext(null);
export function FormProvider({ children, initialValues = {} }) { export function FormProvider({ children, initialValues = {}, template = FormFieldTemplateDefault }) {
const [values, setValues] = React.useState(initialValues); const [values, setValues] = React.useState(initialValues);
return ( return (
<FormProviderCore values={values} setValues={setValues}> <FormProviderCore values={values} setValues={setValues} template={template}>
{children} {children}
</FormProviderCore> </FormProviderCore>
); );
} }
export function FormProviderCore({ children, values, setValues }) { export function FormProviderCore({ children, values, setValues, template = FormFieldTemplateDefault }) {
const [submitAction, setSubmitAction] = React.useState(null); const [submitAction, setSubmitAction] = React.useState(null);
const handleEnter = React.useCallback( const handleEnter = React.useCallback(
(e) => { (e) => {
@@ -43,9 +45,21 @@ export function FormProviderCore({ children, values, setValues }) {
setFieldValue, setFieldValue,
setSubmitAction, setSubmitAction,
}; };
return <FormContext.Provider value={provider}>{children}</FormContext.Provider>; return (
<FormContext.Provider value={provider}>
<FormFieldTemplateProvider template={template}>{children}</FormFieldTemplateProvider>
</FormContext.Provider>
);
} }
export function useForm() { export function useForm() {
return React.useContext(FormContext); return React.useContext(FormContext);
} }
export function FormFieldTemplateProvider({ children, template = FormFieldTemplateDefault }) {
return <FormFieldTemplateContext.Provider value={template}>{children}</FormFieldTemplateContext.Provider>;
}
export function useFormFieldTemplate() {
return React.useContext(FormFieldTemplateContext);
}

View File

@@ -0,0 +1,54 @@
import styled from 'styled-components';
import React from 'react';
import useTheme from '../theme/useTheme';
export const FormRow = styled.div`
display: flex;
margin: 10px;
`;
export const FormLabel = styled.div`
width: 10vw;
font-weight: bold;
`;
export const FormValue = styled.div``;
export function FormFieldTemplateDefault({ label, children, type }) {
return (
<FormRow>
<FormLabel>{label}</FormLabel>
<FormValue>{children}</FormValue>
</FormRow>
);
}
export const FormRowTiny = styled.div`
margin: 5px;
`;
export const FormLabelTiny = styled.div`
color: ${(props) => props.theme.manager_font3};
`;
export const FormValueTiny = styled.div`
margin-left: 15px;
margin-top: 3px;
`;
export function FormFieldTemplateTiny({ label, children, type }) {
const theme = useTheme();
if (type == 'checkbox') {
return (
<FormRowTiny>
{children} {label}
</FormRowTiny>
);
}
return (
<FormRowTiny>
<FormLabelTiny theme={theme}>{label}</FormLabelTiny>
<FormValueTiny>{children}</FormValueTiny>
</FormRowTiny>
);
}

View File

@@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import styled from 'styled-components';
import Select from 'react-select'; import Select from 'react-select';
import Creatable from 'react-select/creatable'; import Creatable from 'react-select/creatable';
import { TextField, SelectField, CheckboxField } from './inputs'; import { TextField, SelectField, CheckboxField } from './inputs';
@@ -14,25 +13,8 @@ import {
import getAsArray from './getAsArray'; import getAsArray from './getAsArray';
import axios from './axios'; import axios from './axios';
import useTheme from '../theme/useTheme'; import useTheme from '../theme/useTheme';
import { useForm } from './FormProvider'; import { useForm, useFormFieldTemplate } from './FormProvider';
export const FormRow = styled.div`
display: flex;
margin: 10px;
`;
export const FormButtonRow = styled.div`
display: flex;
// justify-content: flex-end;
margin: 10px;
`;
export const FormLabel = styled.div`
width: 10vw;
font-weight: bold;
`;
export const FormValue = styled.div``;
export function FormTextFieldRaw({ name, focused = false, ...other }) { export function FormTextFieldRaw({ name, focused = false, ...other }) {
const { values, setFieldValue } = useForm(); const { values, setFieldValue } = useForm();
@@ -48,13 +30,11 @@ export function FormTextFieldRaw({ name, focused = false, ...other }) {
} }
export function FormTextField({ name, label, focused = false, ...other }) { export function FormTextField({ name, label, focused = false, ...other }) {
const FieldTemplate = useFormFieldTemplate();
return ( return (
<FormRow> <FieldTemplate label={label} type="text">
<FormLabel>{label}</FormLabel>
<FormValue>
<FormTextFieldRaw name={name} focused={focused} {...other} /> <FormTextFieldRaw name={name} focused={focused} {...other} />
</FormValue> </FieldTemplate>
</FormRow>
); );
} }
@@ -70,13 +50,11 @@ export function FormCheckboxFieldRaw({ name = undefined, defaultValue = undefine
} }
export function FormCheckboxField({ label, ...other }) { export function FormCheckboxField({ label, ...other }) {
const FieldTemplate = useFormFieldTemplate();
return ( return (
<FormRow> <FieldTemplate label={label} type="checkbox">
<FormLabel>{label}</FormLabel>
<FormValue>
<FormCheckboxFieldRaw {...other} /> <FormCheckboxFieldRaw {...other} />
</FormValue> </FieldTemplate>
</FormRow>
); );
} }
@@ -93,15 +71,13 @@ export function FormSelectFieldRaw({ children, name, ...other }) {
} }
export function FormSelectField({ label, name, children = null, ...other }) { export function FormSelectField({ label, name, children = null, ...other }) {
const FieldTemplate = useFormFieldTemplate();
return ( return (
<FormRow> <FieldTemplate label={label} type="select">
<FormLabel>{label}</FormLabel>
<FormValue>
<FormSelectFieldRaw name={name} {...other}> <FormSelectFieldRaw name={name} {...other}>
{children} {children}
</FormSelectFieldRaw> </FormSelectFieldRaw>
</FormValue> </FieldTemplate>
</FormRow>
); );
} }