Skip to content

Commit

Permalink
feat: widget yaml viewer
Browse files Browse the repository at this point in the history
* feat: 118 input number instead slider in form

* feat: 118 yaml viewer and form fixes

* feat: 118 yaml png and readme entry
  • Loading branch information
codev99 authored Oct 10, 2024
1 parent 8e7a4a1 commit 40ce1e6
Show file tree
Hide file tree
Showing 11 changed files with 1,019 additions and 1,082 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -636,4 +636,16 @@ Copy content of _/build_ folder in your web server
}[]
}[]
}
```

### YamlViewer

![YamlViewer](/widgets-samples/yamlviewer.png)

#### Properties

```
{
yaml: string
}
```
1,905 changes: 878 additions & 1,027 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"react-markdown": "^9.0.1",
"react-redux": "^8.1.2",
"react-router-dom": "^6.16.0",
"react-syntax-highlighter": "^15.5.0",
"react-terminal-ui": "^1.3.0",
"reactflow": "^11.11.2",
"remark-gfm": "^4.0.0",
Expand Down
8 changes: 4 additions & 4 deletions public/config/config.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"api": {
"AUTHN_API_BASE_URL": "http://48.209.182.145:8082",
"BFF_API_BASE_URL": "http://48.209.182.59:8081",
"EVENTS_API_BASE_URL": "http://48.209.180.171:8083",
"EVENTS_PUSH_API_BASE_URL": "http://48.209.180.171:8083",
"AUTHN_API_BASE_URL": "http://4.207.39.182:8082",
"BFF_API_BASE_URL": "http://4.207.39.183:8081",
"EVENTS_API_BASE_URL": "http://172.205.78.36:8083",
"EVENTS_PUSH_API_BASE_URL": "http://172.205.78.36:8083",
"TERMINAL_SOCKET_URL": "http://localhost:8084"
},
"params": {
Expand Down
5 changes: 4 additions & 1 deletion src/components/DrawerPanel/DrawerPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import widgets from "../Widgets/index";
// import { selectFilters } from "../../features/dataList/dataListSlice";
// import dayjs from "dayjs";
import styles from "./styles.module.scss";
import { useState } from "react";

type DrawerPanelType = {
panel: {
Expand Down Expand Up @@ -35,10 +36,12 @@ const DrawerPanel = ({panel, isOpen, onClose}: DrawerPanelType) => {
// const filters = useSelector(selectFilters);
const [form] = Form.useForm();
const panelProps = {...panel.content.props};
const [disableButtons, setDisableButtons] = useState<boolean>(false);

if (panel.type === "form") {
// add form object to panel
panelProps["form"] = form;
panelProps["disableButtons"] = setDisableButtons
}

// const generateInitialValues = () => {
Expand Down Expand Up @@ -77,7 +80,7 @@ const DrawerPanel = ({panel, isOpen, onClose}: DrawerPanelType) => {
panel.type === "form" &&
<Space>
{
panel.buttons?.map((but, i) => <Button key={`btn_${i}`} type={but.type} onClick={() => onClickButton(but.action)}>{but.label}</Button>)
panel.buttons?.map((but, i) => <Button key={`btn_${i}`} type={but.type} onClick={() => onClickButton(but.action)} disabled={disableButtons}>{but.label}</Button>)
}
</Space>
}
Expand Down
94 changes: 45 additions & 49 deletions src/components/Widgets/FormGenerator/FormGenerator.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import { useEffect, useState } from "react";
import { Anchor, App, Col, Form, FormInstance, Input, Radio, Result, Row, Select, Slider, Space, Switch, Typography } from "antd";
import { Anchor, App, Col, Form, FormInstance, Input, InputNumber, Radio, Result, Row, Select, Slider, Space, Switch, Typography } from "antd";
import dayjs, { Dayjs } from "dayjs";
import { useGetContentQuery, useLazyGetContentQuery, usePostContentMutation } from "../../../features/common/commonApiSlice";
import { useGetContentQuery, usePostContentMutation } from "../../../features/common/commonApiSlice";
import { useAppDispatch } from "../../../redux/hooks";
import { DataListFilterType, setFilters } from "../../../features/dataList/dataListSlice";
import ListEditor from "../ListEditor/ListEditor";
import styles from "./styles.module.scss";
import Skeleton from "../../Skeleton/Skeleton";
import useCatchError from "../../../utils/useCatchError";
import SelectWithFilters from "./SelectWithFilters";

type FormGeneratorType = {
title?: string,
description?: string,
fieldsEndpoint?: string,
form: FormInstance<any>,
prefix?: string,
onClose: () => void
onClose: () => void,
disableButtons: (value: boolean) => void
}

const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClose }: FormGeneratorType) => {
const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClose, disableButtons }: FormGeneratorType) => {

const [postContent, { data: postData, isLoading: postLoading, isSuccess: isPostSuccess, isError: isPostError, error: postError }] = usePostContentMutation();
const { message } = App.useApp();
Expand All @@ -28,11 +30,9 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos

// get fields
const {data, isLoading, isFetching, isSuccess, isError, error} = useGetContentQuery({endpoint: fieldsEndpoint?.replace("/form/", "/forms/")});
const [getContent] = useLazyGetContentQuery();
const [formData, setFormData] = useState<any>("idle");
const [formEndpoint, setFormEndpoint] = useState<string>();
const fieldsData: {type: string, name: string}[] = [];
const [loadingFields, setLoadingFields] = useState({});

useEffect(() => {
if (isSuccess) {
Expand Down Expand Up @@ -120,13 +120,7 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos
)
}

const setLoading = (key: string, value: boolean) => {
const loadingObj = {...loadingFields}
loadingObj[key] = value
setLoadingFields(loadingObj)
}

const renderField = async (label: string, name: string, node: any, required: boolean) => {
const renderField = (label: string, name: string, node: any, required: boolean) => {
const rules: any[] = [];
if (required) {
rules.push({required: true, message: "Insert a value"})
Expand Down Expand Up @@ -198,6 +192,8 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos

case "integer":
form.setFieldValue(name.split("."), (node.minimum || 0));
const min = node.minimum
const max = node.maximum
return (
<div id={name} className={styles.formField}>
<Form.Item
Expand All @@ -206,26 +202,17 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos
name={name.split(".")}
rules={rules}
>
<Slider step={1} min={node.minimum ? node.minimum : 0} max={node.maximum ? node.maximum : 100} />
{
min && max && (max - min < 100) ?
<Slider step={1} min={min} max={max} />
:
<InputNumber min={min ? min : 0} max={max ? max : undefined} step={1} style={{width: '100%'}} />
}
</Form.Item>
</div>
)

case "selectWithFilters":
let options;
if (node.source) {
options = node.source.map(opt => ({value: opt, label: opt}))
}
if (node.endpoint) {
try {
setLoading(name, true)
const result = await getContent({endpoint: node.endpoint}).unwrap()
options = result.map(opt => ({value: opt, label: opt}))
setLoading(name, false)
} catch(error) {
catchError({ message: "Unable to retrieve field data"})
}
}
return (
<div id={name} className={styles.formField}>
<Form.Item
Expand All @@ -234,14 +221,7 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos
name={name.split(".")}
rules={rules}
>
<Select
placeholder={node.description ? node.description : undefined}
loading={loadingFields[name]}
options={options}
allowClear
showSearch
optionFilterProp="label"
/>
<SelectWithFilters node={node} />
</Form.Item>
</div>
)
Expand Down Expand Up @@ -295,7 +275,7 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos
arrEndPoint.push(name);

const postEndpoint = arrEndPoint.join("/");

// remove metadata from values
delete values['metadata']

Expand All @@ -312,10 +292,17 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos

// submit values
if (!postLoading && !isPostError && !isPostSuccess) {
await postContent({
endpoint: postEndpoint,
body: payload,
});
try {
await postContent({
endpoint: postEndpoint,
body: payload,
});
// close panel
onClose()
} catch(error) {
catchError({ message: "Unable to send data"})
// keep panel opened
}
}
}

Expand All @@ -329,10 +316,9 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos
}
})
dispatch(setFilters({filters, prefix}))
// close panel
onClose()
}

// close panel
onClose()
}

useEffect(() => {
Expand All @@ -345,16 +331,24 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos
if (isPostSuccess) {
message.success('Operation successful');
// go to created element page if a specific props is true
console.log("postData", postData);
// navigate("");
}
}, [message, isPostSuccess, postData]);

useEffect(() => {
if (isLoading || postLoading) {
if (isLoading) {
message.loading('Receiving data...');
}
}, [isLoading, postLoading, message]);
}, [isLoading, message]);

useEffect(() => {
if (postLoading) {
disableButtons(true)
message.loading('Sending data...');
} else {
disableButtons(false)
}
}, [postLoading, message]);

return (
isLoading || isFetching ?
Expand All @@ -378,8 +372,10 @@ const FormGenerator = ({title, description, fieldsEndpoint, form, prefix, onClos
<div className={styles.metadataFields}>
{ renderMetadataFields() }
</div>
{ renderFields() }
{ generateInitialValues() }
<>
{ renderFields() }
{ generateInitialValues() }
</>
</Form>
</div>
</Col>
Expand Down
46 changes: 46 additions & 0 deletions src/components/Widgets/FormGenerator/SelectWithFilters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useEffect, useState } from "react";
import { useLazyGetContentQuery } from "../../../features/common/commonApiSlice";
import useCatchError from "../../../utils/useCatchError";
import { Select } from "antd";

const SelectWithFilters = ({node}) => {
const [getContent] = useLazyGetContentQuery();
const { catchError } = useCatchError();

const [loading, setLoading] = useState(false);

let options;

useEffect(() => {
const getOptions = async () => {
try {
setLoading(true)
const result = await getContent({endpoint: node.endpoint}).unwrap()
options = result.map(opt => ({value: opt, label: opt}))
setLoading(false)
} catch(error) {
catchError({ message: "Unable to retrieve field data"})
}
}

if (node.source) {
options = node.source.map(opt => ({value: opt, label: opt}))
}
if (node.endpoint) {
getOptions()
}
})

return (
<Select
placeholder={node.description ? node.description : undefined}
loading={loading}
options={options}
allowClear
showSearch
optionFilterProp="label"
/>
)
}

export default SelectWithFilters
9 changes: 8 additions & 1 deletion src/components/Widgets/Panel/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import useParseData from "../../../hooks/useParseData";
import styles from "./styles.module.scss";
import { QuestionCircleOutlined } from "@ant-design/icons";

const Panel = ({title, tooltip, buttons, content}) => {
type PanelType = {
title?: string,
tooltip?: string,
buttons?: React.ReactElement[],
content: React.ReactElement
}

const Panel = ({title, tooltip, buttons, content}: PanelType) => {
const [parseContent] = useParseData()

// let panelContent;
Expand Down
1 change: 1 addition & 0 deletions src/components/Widgets/Panel/styles.module.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import '../../../theme/global.scss';

.card {
background-color: $light-color;

:global .ant-card-head {
border: none;
Expand Down
20 changes: 20 additions & 0 deletions src/components/Widgets/YamlViewer/YamlViewer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import SyntaxHighlighter from 'react-syntax-highlighter';
import { lightfair } from 'react-syntax-highlighter/dist/esm/styles/hljs';

const YamlViewer = ({yaml}: {yaml: string}) => {
return (
<div style={{maxHeight: '600px', overflowY: 'auto'}}>
<SyntaxHighlighter
language="yaml"
style={lightfair}
showLineNumbers
wrapLines
wrapLongLines
>
{yaml}
</SyntaxHighlighter>
</div>
)
}

export default YamlViewer
Binary file added widgets-samples/yamlviewer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 40ce1e6

Please sign in to comment.