Skip to main content

AutoViews

AutoViews

AutoViews is a utility to render generic data forms given a set of components and data schema.

intro 1

  • no coupling with any components
  • based on standarts, like JSONSchema, JSONPatch and JSONPointer
  • build with TypeScript

logo

Additional Resources: GitHub, Get Started

AutoViews showcase

import React, {useCallback, useMemo, useState} from 'react';
import {applyPatch} from 'fast-json-patch';
import {
    AutoView,
    ComponentsRepo,
    RepositoryProvider,
    UISchema
} from '@autoviews/core';
import {
    Box,
    Button,
    ButtonGroup,
    Card,
    CardContent,
    FormControl,
    InputLabel,
    MenuItem,
    Select,
    SelectChangeEvent,
    Divider,
    CardHeader
} from '@mui/material';

import {availableUISchemas} from './uiSchemas';
import './styles.css';
import {dataStore, SchemaNames, schemas} from './Data';
import {MUIFormRepo, MUITableRepo} from './MUIRepos';
import {BootstrapFormRepo, BootstrapTableRepo} from './BootstrapRepos';

export default function App() {
    // data
    const [data, setData] = useState<any[]>(dataStore.user);

    // JSON Schema
    const [schemaName, setSchemaName] = useState('user');
    const schema = useMemo(() => schemas[schemaName], [schemaName]);

    // UI Schema
    const [tableUISchemaName, setTableUISchemaName] = useState('Default');
    const [formUISchemaName, setFormUISchemaName] = useState('Default');
    const [[formUISchema, tableUISchema], setUISchemas] = useState<
        [UISchema, UISchema]
    >([
        availableUISchemas['user'].form[formUISchemaName],
        availableUISchemas['user'].table[tableUISchemaName]
    ]);

    // Item to be edited in the form
    const [item, setItem] = useState<any>({});

    const onSchemaChange = useCallback((e: SelectChangeEvent<string>) => {
        const name = e.target.value as SchemaNames;
        setSchemaName(name);
        setData(dataStore[name]);
        setTableUISchemaName('Default');
        setFormUISchemaName('Default');
        setUISchemas([
            availableUISchemas[name].form['Default'],
            availableUISchemas[name].table['Default']
        ]);
    }, []);

    const onTableUISchemaChange = useCallback(
        (e: SelectChangeEvent<string>) => {
            const name = e.target.value as string;
            setTableUISchemaName(name);
            setUISchemas([
                formUISchema,
                availableUISchemas[schemaName].table[name]
            ]);
        },
        [formUISchema, schemaName]
    );

    const onFormUISchemaChange = useCallback(
        (e: SelectChangeEvent<string>) => {
            const name = e.target.value as string;
            setFormUISchemaName(name);
            setUISchemas([
                availableUISchemas[schemaName].form[name],
                tableUISchema
            ]);
        },
        [tableUISchema, schemaName]
    );

    const onFormChange = useCallback(
        (_: any, {patch}) => {
            setItem({...applyPatch(item, patch).newDocument});
        },
        [setItem, item]
    );

    const [tableRepo, setTableRepo] = useState<ComponentsRepo>(MUITableRepo);
    const [formRepo, setFormRepo] = useState<ComponentsRepo>(MUIFormRepo);

    const onSetRepo = useCallback(
        (name: 'mui' | 'bootstrap') => {
            switch (name) {
                case 'mui':
                    setTableRepo(MUITableRepo);
                    setFormRepo(MUIFormRepo);
                    break;
                case 'bootstrap':
                    setTableRepo(BootstrapTableRepo);
                    setFormRepo(BootstrapFormRepo);
                    break;
            }
        },
        [setTableRepo, setFormRepo]
    );

    const onAddItem = useCallback(
        (_, e) => {
            switch (e.data.action) {
                case 'SAVE':
                    setData([...data, item]);
                    setItem({});
                    break;
            }
        },
        [item, data]
    );
    interface DropdownProps {
        id: string;
        title: string;
        value: string;
        values: string[];
        onChange: (e: SelectChangeEvent<string>) => void;
    }
    const Dropdown = ({id, title, value, values, onChange}: DropdownProps) => {
        return (
            <FormControl sx={{width: '140px', margin: '0 10px'}}>
                <InputLabel id={`${id}-select-label`}>{title}</InputLabel>
                <Select
                    labelId={`${id}-select-label`}
                    id={`${id}-select`}
                    value={value}
                    label={title}
                    onChange={onChange}
                >
                    {values.map(key => (
                        <MenuItem
                            value={key}
                            key={key}
                        >
                            {key}
                        </MenuItem>
                    ))}
                </Select>
            </FormControl>
        );
    };

    return (
        <div className="App">
            <Box style={{margin: '0 20px'}}>
                <Card sx={{margin: '20px 0'}}>
                    <CardHeader
                        title="Controls"
                        subheader="Change UI Library, Schema or UI Schema"
                    />
                    <Divider />
                    <CardContent>
                        <ButtonGroup aria-label="outlined button group">
                            <Button
                                onClick={() => onSetRepo('mui')}
                                variant={
                                    tableRepo === MUITableRepo
                                        ? 'contained'
                                        : 'outlined'
                                }
                            >
                                Mateial UI
                            </Button>
                            <Button
                                onClick={() => onSetRepo('bootstrap')}
                                variant={
                                    tableRepo === BootstrapTableRepo
                                        ? 'contained'
                                        : 'outlined'
                                }
                            >
                                Bootstrap
                            </Button>
                            <Dropdown
                                id={'schema'}
                                title={'Schema'}
                                value={schemaName}
                                values={Object.keys(schemas)}
                                onChange={onSchemaChange}
                            />
                        </ButtonGroup>
                    </CardContent>
                </Card>

                <Card variant="outlined">
                    <CardHeader
                        title="Table"
                        subheader="First instance of AutoView"
                        action={
                            <Dropdown
                                id={'table-ui-schema'}
                                title={'Table UI Schema'}
                                value={tableUISchemaName}
                                values={Object.keys(
                                    availableUISchemas[schemaName].table
                                )}
                                onChange={onTableUISchemaChange}
                            />
                        }
                    />
                    <Divider />
                    <CardContent>
                        <RepositoryProvider components={tableRepo}>
                            <AutoView
                                schema={schema}
                                data={data}
                                uiSchema={tableUISchema}
                            />
                        </RepositoryProvider>
                    </CardContent>
                </Card>
                <Card
                    variant="outlined"
                    sx={{margin: '20px 0'}}
                >
                    <CardHeader
                        title="Form"
                        subheader="Second instance of AutoView"
                        action={
                            <Dropdown
                                id={'form-ui-schema'}
                                title={'Form UI Schema'}
                                value={formUISchemaName}
                                values={Object.keys(
                                    availableUISchemas[schemaName].form
                                )}
                                onChange={onFormUISchemaChange}
                            />
                        }
                    />
                    <Divider />
                    <CardContent>
                        <RepositoryProvider components={formRepo}>
                            <AutoView
                                data={item}
                                uiSchema={formUISchema}
                                schema={schema.items!}
                                onChange={onFormChange}
                                onClick={onAddItem}
                            />
                        </RepositoryProvider>
                    </CardContent>
                </Card>
            </Box>
        </div>
    );
}

The Elements of AutoViews

‘AutoViews’ renders UI by combining 4 elements

intro 1

  1. Your Components

    AutoViews Repository serves as a map of data types to the components to be used when rendering data of that type. The library does not include the actual components, rather it allows injecting different React component libraries such as material UI or others.

    More about the Components Repository

  2. Your Data Schema

    JSON Schema that describes your data. The schema provides nested structure, field types, titles and descriptions as well as constraints such as min, max, required.

    More about the Data JSONSchema

  3. Your Data

    AutoViews interact with data using two properties - the data property and the onChange event, which provide a unified data and events model regardless of the nesting level, data type or control used.

    More about the AutoView Data property and the Events model

  4. Your UI Schema

    The UI Schema adds another layer of hints that can be used by components to fine tune the rendered UI. UI Schema includes field ordering/layouting, grouping, component selection, field hiding and auto focus hints.

    More about the UI Schema