Skip to content

Commit

Permalink
feat(form): add published version of fields
Browse files Browse the repository at this point in the history
- Adds published version of some fields
- Uses the default version with disabled=true for the rest
- FormuleForm now shows the preview version by default
- FormuleForm can show the editable version with isEditable=true
- Updates the README with related information and adds new badges
- Reorganizes the current fields and widgets in base/published folders
- Adds a toggle to switch between editable and published in the demo
- Now shows form data in the schema json viewer modal
  • Loading branch information
miguelgrc committed Jun 12, 2024
1 parent 79108ac commit 4668817
Show file tree
Hide file tree
Showing 45 changed files with 313 additions and 174 deletions.
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
<p align="center"><img src="https://raw.githubusercontent.com/cern-sis/react-formule/master/docs/logo.png" width="350px"/></p>
<div align="center">

<h3 align="center"> 🕹️ <a href="https://cern-sis.github.io/react-formule/">DEMO</a> 🕹️</h3>
<img src="https://raw.githubusercontent.com/cern-sis/react-formule/master/docs/logo_horizontal.png" width="800px" />

[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
[![Try our demo](https://img.shields.io/badge/try_our-🕹️_demo_🕹️-deepskyblue.svg?style=for-the-badge)](https://cern-sis.github.io/react-formule/)

</div>

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
[![NPM Version](https://img.shields.io/npm/v/react-formule?style=flat-square&color=orchid)](https://www.npmjs.com/package/react-formule?activeTab=readme)
[![GitHub commits since tagged version](https://img.shields.io/github/commits-since/cern-sis/react-formule/latest?style=flat-square&color=orange)](https://github.com/cern-sis/react-formule/commits/master/)
[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/cern-sis/react-formule?style=flat-square)](https://github.com/cern-sis/react-formule/pulls)
[![Contributions welcome](https://img.shields.io/badge/contributions-welcome-blue.svg?style=flat-square)](https://github.com/cern-sis/react-formule/issues)
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-blue.svg?style=flat-square)](http://commitizen.github.io/cz-cli/)
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/cern-sis/react-formule/cypress.yml?style=flat-square&label=cypress)](https://github.com/cern-sis/react-formule/actions/workflows/cypress.yml)
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/cern-sis/react-formule/deploy-demo.yml?style=flat-square&label=deploy-demo)](https://github.com/cern-sis/react-formule/actions/workflows/commit-lint.yml)

## :horse: What is Formule?

Expand All @@ -27,8 +38,8 @@ Formule consists of the following main components:
- The form editor, which has been split into three different components that work together for more flexibility:
- **`SelectOrEdit`** (or, separately, **`SelectFieldType`** and **`PropertyEditor`**): You can select fields to add to the form and customize their properties.
- **`SchemaPreview`**: A tree view of the fields where you can rearrange or select fields to be edited.
- **`FormPreview`**: A live, iteractive preview of the form.
- **`FormuleForm`**: You can use it to display a form (JSON Schema) generated by Formule.
- **`FormPreview`**: A live, iteractive preview of the form which lets you toggle between the editable and the published version. If you only want to show the editable version, use **`EditablePreview`** instead.
- **`FormuleForm`**: You can use it to display a form (JSON Schema) generated by Formule. If you want to display the editable version, pass `isEditable`.

It also exports the following functions:

Expand Down
Binary file added docs/logo_horizontal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 20 additions & 5 deletions formule-demo/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ function App() {
width={1000}
footer={null}
>
<Row gutter={10}>
<Row gutter={[10, 10]}>
<Col
xs={12}
xs={24}
style={{
overflowX: "hidden",
height: "100%",
Expand All @@ -49,7 +49,7 @@ function App() {
<CodeViewer
value={JSON.stringify(formuleState?.current.schema, null, 2)}
lang="json"
height="50vh"
height="45vh"
reset
/>
</Col>
Expand All @@ -64,7 +64,22 @@ function App() {
<CodeViewer
value={JSON.stringify(formuleState?.current.uiSchema, null, 2)}
lang="json"
height="50vh"
height="25vh"
reset
/>
</Col>
<Col
xs={12}
style={{
overflowX: "hidden",
height: "100%",
}}
>
<Typography.Text strong>Form data</Typography.Text>
<CodeViewer
value={JSON.stringify(formuleState?.formData, null, 2)}
lang="json"
height="25vh"
reset
/>
</Col>
Expand Down Expand Up @@ -107,7 +122,7 @@ function App() {
style={{
overflowX: "hidden",
height: "100%",
padding: "0px 15px",
padding: "0px 25px",
}}
className="tour-form-preview"
>
Expand Down
5 changes: 5 additions & 0 deletions formule-demo/src/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ export const theme = {
colorBgLayout: "#f0f2f5",
fontFamily: "Titillium Web",
},
components: {
Segmented: {
trackBg: "#E4E8EC",
},
},
};
59 changes: 59 additions & 0 deletions src/admin/components/EditablePreview.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useContext } from "react";
import Form from "../../forms/Form";
import { shoudDisplayGuideLinePopUp } from "../utils";
import { Row, Empty, Space, Typography } from "antd";
import { useSelector } from "react-redux";
import CustomizationContext from "../../contexts/CustomizationContext";

const EditablePreview = ({ hideTitle, liveValidate }) => {
const schema = useSelector((state) => state.schemaWizard.current.schema);
const uiSchema = useSelector((state) => state.schemaWizard.current.uiSchema);
const formData = useSelector((state) => state.schemaWizard.formData);

const customizationContext = useContext(CustomizationContext);

return (
<>
{!hideTitle && (
<Typography.Title
level={4}
style={{ textAlign: "center", margin: "15px 0" }}
>
Editable Preview
</Typography.Title>
)}
{shoudDisplayGuideLinePopUp(schema) ? (
<Row
justify="center"
align="middle"
style={{ height: "100%", flex: 1 }}
>
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description={
<Space direction="vertical">
<Typography.Title level={5}>
Your form is empty
</Typography.Title>
<Typography.Text type="secondary">
Add fields to the drop area to initialize your form
</Typography.Text>
</Space>
}
/>
</Row>
) : (
<Form
schema={customizationContext.transformSchema(schema)}
uiSchema={uiSchema}
formData={formData || {}}
onChange={() => {}}
liveValidate={liveValidate}
isEditable
/>
)}
</>
);
};

export default EditablePreview;
73 changes: 27 additions & 46 deletions src/admin/components/FormPreview.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { useContext } from "react";
import { useState } from "react";
import Form from "../../forms/Form";
import { shoudDisplayGuideLinePopUp } from "../utils";
import { Row, Empty, Space, Typography, Col } from "antd";
import { Segmented, Row } from "antd";
import { useSelector } from "react-redux";
import CustomizationContext from "../../contexts/CustomizationContext";
import EditablePreview from "./EditablePreview";
import { EditOutlined, EyeOutlined } from "@ant-design/icons";

const FormPreview = ({liveValidate}) => {
const schema = useSelector((state) => state.schemaWizard.current.schema)
const uiSchema = useSelector((state) => state.schemaWizard.current.uiSchema)
const formData = useSelector((state) => state.schemaWizard.formData)
const FormPreview = ({ liveValidate }) => {
const schema = useSelector((state) => state.schemaWizard.current.schema);
const uiSchema = useSelector((state) => state.schemaWizard.current.uiSchema);
const formData = useSelector((state) => state.schemaWizard.formData);

const customizationContext = useContext(CustomizationContext)
const [segment, setSegment] = useState("editable");

const handleSegmentChange = (value) => {
setSegment(value);
};

return (
<div
Expand All @@ -21,44 +25,21 @@ const FormPreview = ({liveValidate}) => {
}}
data-cy="formPreview"
>
<Typography.Title
level={4}
style={{ textAlign: "center", margin: "15px 0" }}
>
Preview
</Typography.Title>
{shoudDisplayGuideLinePopUp(schema) ? (
<Row
justify="center"
align="middle"
style={{ height: "100%", flex: 1 }}
>
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description={
<Space direction="vertical">
<Typography.Title level={5}>
Your form is empty
</Typography.Title>
<Typography.Text type="secondary">
Add fields to the drop area to initialize your form
</Typography.Text>
</Space>
}
/>
</Row>
<Row justify="center" style={{ margin: "15px" }}>
<Segmented
options={[
{ label: "Editable", value: "editable", icon: <EditOutlined /> },
{ label: "Published", value: "published", icon: <EyeOutlined /> },
]}
style={{ fontWeight: "bold" }}
value={segment}
onChange={handleSegmentChange}
/>
</Row>
{segment === "editable" ? (
<EditablePreview hideTitle liveValidate={liveValidate} />
) : (
<Row justify="center">
<Col xs={22} sm={20}>
<Form
schema={customizationContext.transformSchema(schema)}
uiSchema={uiSchema}
formData={formData || {}}
onChange={() => {}}
liveValidate={liveValidate}
/>
</Col>
</Row>
<Form schema={schema} uiSchema={uiSchema} formData={formData} />
)}
</div>
);
Expand Down
7 changes: 5 additions & 2 deletions src/admin/components/PropKeyEditorForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ const PropertyKeyEditorForm = ({
}) => {
const customizationContext = useContext(CustomizationContext);

const updatedFormData = {...formData}
const updatedFormData = { ...formData };

let type;

const cleanupSelect = () =>
schema.type === "array" ? delete updatedFormData.enum : delete updatedFormData.items;
schema.type === "array"
? delete updatedFormData.enum
: delete updatedFormData.items;

// in case we can not define the type of the element from the uiSchema,
// extract the type from the schema
Expand Down Expand Up @@ -61,6 +63,7 @@ const PropertyKeyEditorForm = ({
formData={updatedFormData}
onChange={onChange}
liveValidate
isEditable
/>
);
};
Expand Down
8 changes: 4 additions & 4 deletions src/admin/components/SchemaTree.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import CustomizationContext from "../../contexts/CustomizationContext";
import { useContext } from "react";

const SchemaTree = () => {
const schema = useSelector((state) => state.schemaWizard.current.schema);
const uiSchema = useSelector((state) => state.schemaWizard.current.uiSchema);

const schema = useSelector((state) => state.schemaWizard.current.schema)
const uiSchema = useSelector((state) => state.schemaWizard.current.uiSchema)

const customizationContext = useContext(CustomizationContext)
const customizationContext = useContext(CustomizationContext);

return (
<Form
Expand All @@ -27,6 +26,7 @@ const SchemaTree = () => {
liveValidate
formContext={{ schema: [], uiSchema: [] }}
className="schemaTree"
isEditable
/>
);
};
Expand Down
7 changes: 4 additions & 3 deletions src/admin/formComponents/ArrayFieldTemplate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import FieldTemplate from "./FieldTemplate";
import { _validate } from "../utils";
import DropArea from "./DropArea";

const ArrayFieldTemplate = props => {
const ArrayFieldTemplate = (props) => {
const [display, setDisplay] = useState(false);

let schemaPath = [];
let uiSchemaPath = [];
if (props.rawErrors) {
let _rawErrors = props.rawErrors.filter(i => (i.schema ? i : false));
let _rawErrors = props.rawErrors.filter((i) => (i.schema ? i : false));
let { schema, uiSchema } = _rawErrors[0];
schemaPath = schema;
uiSchemaPath = uiSchema;
Expand Down Expand Up @@ -58,6 +58,7 @@ const ArrayFieldTemplate = props => {
noHtml5Validate={true}
onChange={() => {}}
formContext={{ ..._path, nestedForm: true }}
isEditable
>
<span />
</Form>
Expand All @@ -77,4 +78,4 @@ ArrayFieldTemplate.propTypes = {
id: PropTypes.string,
};

export default ArrayFieldTemplate
export default ArrayFieldTemplate;
17 changes: 9 additions & 8 deletions src/admin/formComponents/FieldTemplate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { isItTheArrayField, _validate } from "../utils/index";
import DropArea from "./DropArea";
import { addByPath } from "../../store/schemaWizard";

const FieldTemplate = props => {
const FieldTemplate = (props) => {
const {
schema,
uiSchema = {},
Expand All @@ -20,22 +20,22 @@ const FieldTemplate = props => {
id,
} = props;

const dispatch = useDispatch()
const dispatch = useDispatch();

const [display, setDisplay] = useState(false);

let path = {
schema: [
...formContext.schema,
...(rawErrors.find(e => typeof e === "object").schema || []),
...(rawErrors.find((e) => typeof e === "object").schema || []),
],
uiSchema: [
...formContext.uiSchema,
...(rawErrors.find(e => typeof e === "object").uiSchema || []),
...(rawErrors.find((e) => typeof e === "object").uiSchema || []),
],
};

const shouldBoxHideChildren = uiSchema => {
const shouldBoxHideChildren = (uiSchema) => {
return uiSchema["ui:field"] !== undefined;
};

Expand All @@ -55,7 +55,7 @@ const FieldTemplate = props => {
return (
<HoverBox
allowsChildren
addProperty={(path, value) => dispatch(addByPath({path, value}))}
addProperty={(path, value) => dispatch(addByPath({ path, value }))}
key={id}
path={path}
shouldHideChildren={shouldBoxHideChildren(uiSchema)}
Expand Down Expand Up @@ -94,6 +94,7 @@ const FieldTemplate = props => {
validate={_validate}
formContext={path}
onChange={() => {}}
isEditable
>
<span />
</Form>
Expand All @@ -108,7 +109,7 @@ const FieldTemplate = props => {
// The HoverBox wrapper here is needed to allow dropping items into objects
// or arrays directly without having to expand them first
<HoverBox
addProperty={(path, value) => dispatch(addByPath({path, value}))}
addProperty={(path, value) => dispatch(addByPath({ path, value }))}
key={id}
path={path}
shouldHideChildren={shouldBoxHideChildren(uiSchema)}
Expand All @@ -130,4 +131,4 @@ FieldTemplate.propTypes = {
schema: PropTypes.object,
};

export default FieldTemplate
export default FieldTemplate;
1 change: 0 additions & 1 deletion src/assets/react.svg

This file was deleted.

Loading

0 comments on commit 4668817

Please sign in to comment.