diff --git a/package.json b/package.json index 2046fd478..8d723bbc3 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "react-dom": "^16.13.1", "react-helmet": "^6.1.0", "react-json-view": "^1.20.0", + "react-markdown": "^6.0.2", "react-redux": "^7.2.0", "react-router-dom": "^5.1.2", "reactstrap": "^8.4.1", diff --git a/src/abc/Module.js b/src/abc/Module.js index b0519eaec..06370107d 100644 --- a/src/abc/Module.js +++ b/src/abc/Module.js @@ -1,6 +1,10 @@ export default class Module { constructor(app, name) { this.App = app; + this.Name = name; + this.Config = app?.config; + this.Navigation = app?.Navigation; + this.Router = app?.Router; } initialize() { diff --git a/src/modules/wizard/Wizard.js b/src/modules/wizard/Wizard.js new file mode 100644 index 000000000..0edc8ecb7 --- /dev/null +++ b/src/modules/wizard/Wizard.js @@ -0,0 +1,166 @@ +import React, { useState, useEffect } from "react"; +import { useForm } from "react-hook-form"; +import ReactMarkdown from 'react-markdown' +import { Card, CardHeader, CardBody, CardFooter, FormGroup, FormText, Input, Label, Pagination, PaginationItem, PaginationLink } from "reactstrap"; + + +export function Wizard({ + name, wizardPages +}) { + + const [rows, setRows] = useState(); + const [page, setPage] = useState(1); + const [totalCount, setTotalCount] = useState(0); //TODO: calculate + const [progressStep, setProgressStep] = useState(20); + const [pageTitle, setPageTitle] = useState(""); + const { register, handleSubmit, setValue, getValues, errors, reset } = useForm(); + + useEffect(() => { + setTotalCount(wizardPages.length); + }, []); + + useEffect(() => { + getRows(); + setPageTitle(wizardPages[page - 1].title ? wizardPages[page - 1].title : page - 1); // pagination counts index from 1, not 0 + }, [page]); + + const getRows = () => { + var view = [] + if (wizardPages != undefined) { + var pageView = wizardPages[page - 1] + if (pageView.rows != undefined) { + pageView.rows.forEach(row => { + if (row.type == "markdown") { + view.push( + + {row.contents} + + ) + } else if (row.type == "object") { + var line = row.properties + Object.keys(line).map((key, idx) => { + view.push() + }) + }; + }); + }; + setRows(view) + }; + }; + + + return ( + + + {pageTitle} + + + + {rows} + + + + {/* Here should be some progress indicator */} + + + ); +} + + + + +function ListPagination(props) { + + const slots = Math.min(5, props.max); + + var start = props.page - Math.floor(slots / 2); + var end = props.page + Math.floor(slots / 2); + + if (start < 1) { + start = 1; + end = Math.min(slots, props.max); + } + + else if (end > props.max) { + start = Math.max(props.max - slots + 1, 1); + end = props.max; + } + + let pages = []; + var i; + for (i = start; i <= end; i++) { + pages.push(i); + } + + return ( + + + props.onPageChange(Math.max(1, props.page - 1))} + > + + + + {pages.map((i, x) => + + { + props.onPageChange(i); + }} + > + {i} + + + )} + + + = props.max} + onClick={(e) => { + props.onPageChange(props.page + 1) + }} + > + + + + ); +} + + +// TODO: Different types of Item to cover formats such as "number", "boolean", checkbox, radiobox +export function InputStringItem(props) { + return ( + + + + + {props.description} + + + ); +} diff --git a/src/modules/wizard/WizardContainer.js b/src/modules/wizard/WizardContainer.js new file mode 100644 index 000000000..9cc81d391 --- /dev/null +++ b/src/modules/wizard/WizardContainer.js @@ -0,0 +1,23 @@ +import React from 'react'; + +import { Wizard } from './Wizard'; +import { Container } from 'reactstrap'; + +import json from './mock-data.json'; + +const WizardContainer = (props) => { + console.log(json) + + return ( + + + + ) +} + +export default WizardContainer; + diff --git a/src/modules/wizard/index.js b/src/modules/wizard/index.js new file mode 100644 index 000000000..6c16ab8ac --- /dev/null +++ b/src/modules/wizard/index.js @@ -0,0 +1,23 @@ +import Module from 'asab-webui/abc/Module'; +import WizardContainer from './WizardContainer'; + +export default class WizardModule extends Module { + constructor (app) { + super(app, "WizardModule"); + + console.log("WizardModule: ", this); + + this.Router.addRoute({ + path: "/wizard/", + exact: true, + name: "Wizard", + component: WizardContainer + }) + + this.Navigation.addItem({ + name: "Wizard", + icon: "cil-gem", + url: "/wizard/" + }) + } +} \ No newline at end of file diff --git a/src/modules/wizard/mock-data.json b/src/modules/wizard/mock-data.json new file mode 100644 index 000000000..806efd026 --- /dev/null +++ b/src/modules/wizard/mock-data.json @@ -0,0 +1,119 @@ +{ + "name": "Wizard Name", + "wizardPages": [ + { + "title": "a 1", + "rows": + [ + { + "type": "markdown", + "contents": "# headline \n ## second line \n normal text \n\n second line of normal text" + }, + { + "$id": "some_id", + "type": "object", + "description": "description", + "examples": [ + { + "servers": "lm1:12181,lm2:22181,lm3:32181", + "path": "/lmio" + } + ], + "required": [ + "servers", + "path" + ], + "properties": { + "servers": { + "$id": "#/properties/asab%3Azookeeper/properties/servers", + "type": "text", + "title": "The servers schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "lm1:12181,lm2:22181,lm3:32181" + ] + }, + "path": { + "$id": "#/properties/asab%3Azookeeper/properties/path", + "type": "text", + "title": "The path schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "/lmio" + ] + } + } + }, + { + "type": "markdown", + "contents": "## headline 2" + } + ] + }, + { + "title": "b 2", + "rows": + [ + { + "type": "markdown", + "contents": "# headline \n ## second line \n normal text \n\n second line of normal text" + }, + { + "type": "markdown", + "contents": "## headline 2" + }, + { + "type": "markdown", + "contents": "### headline 3" + }, + { + "type": "markdown", + "contents": "#### headline 4" + }, + { + "$id": "some_id2", + "type": "object", + "description": "description", + "examples": [ + { + "servers": "lm1:12181,lm2:22181,lm3:32181", + "path": "/lmio" + } + ], + "required": [ + "servers", + "path" + ], + "properties": { + "servers2": { + "$id": "#/properties/asab%3Azookeeper/properties/servers2", + "type": "string", + "title": "The servers schema2", + "description": "An explanation about the purpose of servers2.", + "default": "", + "examples": [ + "lm1:12181,lm2:22181,lm3:32181" + ] + }, + "path2": { + "$id": "#/properties/asab%3Azookeeper/properties/path2", + "type": "string", + "title": "The path schema2", + "description": "An explanation about the purpose of path2.", + "default": "some default value", + "examples": [ + "/lmio" + ] + } + } + }, + { + "type": "markdown", + "contents": "last markdown under input" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/style.scss b/src/style.scss index 0a2bdbca9..f1a53eb92 100644 --- a/src/style.scss +++ b/src/style.scss @@ -26,3 +26,7 @@ main > .container-fluid, main > .container { .breadcrumb { margin: 0 !important; } + +.height-100 { + height: 100% !important; +}