2 * ============LICENSE_START========================================================================
3 * ONAP : ccsdk feature sdnr wt odlux
4 * =================================================================================================
5 * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
6 * =================================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
8 * in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software distributed under the License
13 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14 * or implied. See the License for the specific language governing permissions and limitations under
16 * ============LICENSE_END==========================================================================
19 import React from 'react';
20 import { RouteComponentProps, withRouter } from 'react-router-dom';
22 import { WithStyles, withStyles, createStyles, Theme } from '@material-ui/core/styles';
24 import connect, { IDispatcher, Connect } from "../../../../framework/src/flux/connect";
25 import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore";
26 import MaterialTable, { ColumnModel, ColumnType, MaterialTableCtorType } from "../../../../framework/src/components/material-table";
27 import { Loader } from "../../../../framework/src/components/material-ui/loader";
28 import { renderObject } from '../../../../framework/src/components/objectDump';
30 import { DisplayModeType } from '../handlers/viewDescriptionHandler';
31 import { SetSelectedValue, splitVPath, updateDataActionAsyncCreator, updateViewActionAsyncCreator, removeElementActionAsyncCreator, executeRpcActionAsyncCreator } from "../actions/deviceActions";
32 import { ViewSpecification, isViewElementString, isViewElementNumber, isViewElementBoolean, isViewElementObjectOrList, isViewElementSelection, isViewElementChoise, ViewElement, ViewElementChoise, isViewElementUnion, isViewElementRpc, ViewElementRpc, isViewElementEmpty } from "../models/uiModels";
34 import Fab from '@material-ui/core/Fab';
35 import AddIcon from '@material-ui/icons/Add';
36 import ArrowBack from '@material-ui/icons/ArrowBack';
37 import RemoveIcon from '@material-ui/icons/RemoveCircleOutline';
38 import SaveIcon from '@material-ui/icons/Save';
39 import EditIcon from '@material-ui/icons/Edit';
40 import Tooltip from "@material-ui/core/Tooltip";
41 import FormControl from "@material-ui/core/FormControl";
42 import IconButton from "@material-ui/core/IconButton";
44 import InputLabel from "@material-ui/core/InputLabel";
45 import Select from "@material-ui/core/Select";
46 import MenuItem from "@material-ui/core/MenuItem";
47 import Breadcrumbs from "@material-ui/core/Breadcrumbs";
48 import { Button } from '@material-ui/core';
49 import Link from "@material-ui/core/Link";
51 import { BaseProps } from '../components/baseProps';
52 import { UIElementReference } from '../components/uiElementReference';
53 import { UiElementNumber } from '../components/uiElementNumber';
54 import { UiElementString } from '../components/uiElementString';
55 import { UiElementBoolean } from '../components/uiElementBoolean';
56 import { UiElementSelection } from '../components/uiElementSelection';
57 import { UIElementUnion } from '../components/uiElementUnion';
58 import { UiElementLeafList } from '../components/uiElementLeafList';
60 import { useConfirm } from 'material-ui-confirm';
62 const styles = (theme: Theme) => createStyles({
65 "justifyContent": "space-between",
68 "justifyContent": "left"
74 "alignItems": "center",
75 "justifyContent": "center",
83 "flexDirection": "column",
86 "marginRight": theme.spacing(0.5),
91 "margin": theme.spacing(1),
99 '& label.Mui-focused': {
102 '& .MuiInput-underline:after': {
103 borderBottomColor: 'green',
105 '& .MuiOutlinedInput-root': {
109 '&:hover fieldset': {
110 borderColor: 'yellow',
112 '&.Mui-focused fieldset': {
113 borderColor: 'green',
122 borderBottom: `2px solid ${theme.palette.divider}`,
125 width: 485, marginLeft: 20, marginRight: 20
127 verificationElements: {
128 width: 485, marginLeft: 20, marginRight: 20
132 const mapProps = (state: IApplicationStoreState) => ({
133 collectingData: state.configuration.valueSelector.collectingData,
134 listKeyProperty: state.configuration.valueSelector.keyProperty,
135 listSpecification: state.configuration.valueSelector.listSpecification,
136 listData: state.configuration.valueSelector.listData,
137 vPath: state.configuration.viewDescription.vPath,
138 nodeId: state.configuration.deviceDescription.nodeId,
139 viewData: state.configuration.viewDescription.viewData,
140 outputData: state.configuration.viewDescription.outputData,
141 displaySpecification: state.configuration.viewDescription.displaySpecification,
144 const mapDispatch = (dispatcher: IDispatcher) => ({
145 onValueSelected: (value: any) => dispatcher.dispatch(new SetSelectedValue(value)),
146 onUpdateData: (vPath: string, data: any) => dispatcher.dispatch(updateDataActionAsyncCreator(vPath, data)),
147 reloadView: (vPath: string) => dispatcher.dispatch(updateViewActionAsyncCreator(vPath)),
148 removeElement: (vPath: string) => dispatcher.dispatch(removeElementActionAsyncCreator(vPath)),
149 executeRpc: (vPath: string, data: any) => dispatcher.dispatch(executeRpcActionAsyncCreator(vPath, data)),
152 const SelectElementTable = MaterialTable as MaterialTableCtorType<{ [key: string]: any }>;
154 type ConfigurationApplicationComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDispatch> & WithStyles<typeof styles>;
156 type ConfigurationApplicationComponentState = {
160 viewData: { [key: string]: any } | null;
161 choises: { [path: string]: { selectedCase: string, data: { [property: string]: any } } };
164 const OldProps = Symbol("OldProps");
165 class ConfigurationApplicationComponent extends React.Component<ConfigurationApplicationComponentProps, ConfigurationApplicationComponentState> {
170 constructor(props: ConfigurationApplicationComponentProps) {
182 private static getChoisesFromElements = (elements: { [name: string]: ViewElement }, viewData: any) => {
183 return Object.keys(elements).reduce((acc, cur) => {
184 const elm = elements[cur];
185 if (isViewElementChoise(elm)) {
186 const caseKeys = Object.keys(elm.cases);
188 // find the right case for this choise, use the first one with data, at least use index 0
189 const selectedCase = caseKeys.find(key => {
190 const caseElm = elm.cases[key];
191 return Object.keys(caseElm.elements).some(caseElmKey => {
192 const caseElmElm = caseElm.elements[caseElmKey];
193 return viewData[caseElmElm.label] !== undefined || viewData[caseElmElm.id] != undefined;
197 // extract all data of the active case
198 const caseElements = elm.cases[selectedCase].elements;
199 const data = Object.keys(caseElements).reduce((dataAcc, dataCur) => {
200 const dataElm = caseElements[dataCur];
201 if (isViewElementEmpty(dataElm)) {
202 dataAcc[dataElm.label] = null;
203 } else if (viewData[dataElm.label] !== undefined) {
204 dataAcc[dataElm.label] = viewData[dataElm.label];
205 } else if (viewData[dataElm.id] !== undefined) {
206 dataAcc[dataElm.id] = viewData[dataElm.id];
209 }, {} as { [name: string]: any });
217 }, {} as { [path: string]: { selectedCase: string, data: { [property: string]: any } } }) || {}
220 static getDerivedStateFromProps(nextProps: ConfigurationApplicationComponentProps, prevState: ConfigurationApplicationComponentState & { [OldProps]: ConfigurationApplicationComponentProps }) {
222 if (!prevState || !prevState[OldProps] || (prevState[OldProps].viewData !== nextProps.viewData)) {
223 const isNew: boolean = nextProps.vPath?.endsWith("[]") || false;
228 viewData: nextProps.viewData || null,
229 [OldProps]: nextProps,
230 choises: nextProps.displaySpecification.displayMode === DisplayModeType.doNotDisplay
232 : nextProps.displaySpecification.displayMode === DisplayModeType.displayAsRPC
233 ? nextProps.displaySpecification.inputViewSpecification && ConfigurationApplicationComponent.getChoisesFromElements(nextProps.displaySpecification.inputViewSpecification.elements, nextProps.viewData) || []
234 : ConfigurationApplicationComponent.getChoisesFromElements(nextProps.displaySpecification.viewSpecification.elements, nextProps.viewData)
241 private navigate = (path: string) => {
242 this.props.history.push(`${this.props.match.url}${path}`);
245 private changeValueFor = (property: string, value: any) => {
248 ...this.state.viewData,
254 private collectData = (elements: { [name: string]: ViewElement }) => {
255 // ensure only active choises will be contained
256 const viewData : { [key: string]: any }= { ...this.state.viewData };
257 const choiseKeys = Object.keys(elements).filter(elmKey => isViewElementChoise(elements[elmKey]));
258 const elementsToRemove = choiseKeys.reduce((acc, curChoiceKey) => {
259 const currentChoice = elements[curChoiceKey] as ViewElementChoise;
260 const selectedCase = this.state.choises[curChoiceKey].selectedCase;
261 Object.keys(currentChoice.cases).forEach(caseKey => {
262 const caseElements = currentChoice.cases[caseKey].elements;
263 if (caseKey === selectedCase) {
264 Object.keys(caseElements).forEach(caseElementKey => {
265 const elm = caseElements[caseElementKey];
266 if (isViewElementEmpty(elm)) {
267 // insert null for all empty elements
268 viewData[elm.id] = null;
273 Object.keys(caseElements).forEach(caseElementKey => {
274 acc.push(caseElements[caseElementKey]);
278 }, [] as ViewElement[]);
280 return viewData && Object.keys(viewData).reduce((acc, cur) => {
281 if (!elementsToRemove.some(elm => elm.label === cur || elm.id === cur)) {
282 acc[cur] = viewData[cur];
285 }, {} as { [key: string]: any });
288 private getEditorForViewElement = (uiElement: ViewElement) : (null | React.ComponentType<BaseProps<any>>) => {
289 if (isViewElementEmpty(uiElement)) {
291 } else if (isViewElementSelection(uiElement)) {
292 return UiElementSelection;
293 } else if (isViewElementBoolean(uiElement)) {
294 return UiElementBoolean;
295 } else if (isViewElementString(uiElement)) {
296 return UiElementString;
297 } else if (isViewElementNumber(uiElement)) {
298 return UiElementNumber;
299 } else if (isViewElementUnion(uiElement)) {
300 return UIElementUnion;
302 if (process.env.NODE_ENV !== "production") {
303 console.error(`Unknown element type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`)
309 private renderUIElement = (uiElement: ViewElement, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
310 const isKey = (uiElement.label === keyProperty);
311 const canEdit = editMode && (isNew || (uiElement.config && !isKey));
313 // do not show elements w/o any value from the backend
314 if (viewData[uiElement.id] == null && !editMode) {
316 } else if (isViewElementEmpty(uiElement)) {
318 } else if (uiElement.isList) {
319 /* element is a leaf-list */
320 return <UiElementLeafList
322 inputValue={viewData[uiElement.id] == null ? [] : viewData[uiElement.id]}
325 disabled={editMode && !canEdit}
326 onChange={(e) => { this.changeValueFor(uiElement.id, e) }}
327 getEditorForViewElement = { this.getEditorForViewElement }
330 const Element = this.getEditorForViewElement(uiElement);
331 return Element != null
336 inputValue={viewData[uiElement.id] == null ? '' : viewData[uiElement.id]}
339 disabled={editMode && !canEdit}
340 onChange={(e) => { this.changeValueFor(uiElement.id, e) }}
346 // private renderUIReference = (uiElement: ViewElement, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
347 // const isKey = (uiElement.label === keyProperty);
348 // const canEdit = editMode && (isNew || (uiElement.config && !isKey));
349 // if (isViewElementObjectOrList(uiElement)) {
351 // <FormControl key={uiElement.id} style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
352 // <Tooltip title={uiElement.description || ''}>
353 // <Button className={this.props.classes.leftButton} color="secondary" disabled={this.state.editMode} onClick={() => {
354 // this.navigate(`/${uiElement.id}`);
355 // }}>{uiElement.label}</Button>
360 // if (process.env.NODE_ENV !== "production") {
361 // console.error(`Unknown reference type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`)
367 private renderUIChoise = (uiElement: ViewElementChoise, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
368 const isKey = (uiElement.label === keyProperty);
370 const currentChoise = this.state.choises[uiElement.id];
371 const currentCase = currentChoise && uiElement.cases[currentChoise.selectedCase];
373 const canEdit = editMode && (isNew || (uiElement.config && !isKey));
374 if (isViewElementChoise(uiElement)) {
375 const subElements = currentCase ?.elements;
378 <FormControl key={uiElement.id} style={{ width: 485, marginLeft: 20, marginRight: 20 }}>
379 <InputLabel htmlFor={`select-${uiElement.id}`} >{uiElement.label}</InputLabel>
381 required={!!uiElement.mandatory}
383 if (currentChoise.selectedCase === e.target.value) {
384 return; // nothing changed
386 this.setState({ choises: { ...this.state.choises, [uiElement.id]: { ...this.state.choises[uiElement.id], selectedCase: e.target.value as string } } });
389 disabled={editMode && !canEdit}
390 value={this.state.choises[uiElement.id].selectedCase}
393 id: `select-${uiElement.id}`,
397 Object.keys(uiElement.cases).map(caseKey => {
398 const caseElm = uiElement.cases[caseKey];
400 <MenuItem key={caseElm.id} value={caseKey}><Tooltip title={caseElm.description || ''}><div style={{width:"100%"}}>{caseElm.label}</div></Tooltip></MenuItem>
407 ? Object.keys(subElements).map(elmKey => {
408 const elm = subElements[elmKey];
409 return this.renderUIElement(elm, viewData, keyProperty, editMode, isNew);
411 : <h3>Invalid Choise</h3>
416 if (process.env.NODE_ENV !== "production") {
417 console.error(`Unknown type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`)
423 private renderUIView = (viewSpecification: ViewSpecification, viewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) => {
424 const { classes } = this.props;
426 const orderFunc = (vsA: ViewElement, vsB: ViewElement) => {
428 // if (vsA.label === vsB.label) return 0;
429 if (vsA.label === keyProperty) return -1;
430 if (vsB.label === keyProperty) return +1;
433 // if (vsA.uiType === vsB.uiType) return 0;
434 // if (vsA.uiType !== "object" && vsB.uiType !== "object") return 0;
435 // if (vsA.uiType === "object") return +1;
439 const sections = Object.keys(viewSpecification.elements).reduce((acc, cur) => {
440 const elm = viewSpecification.elements[cur];
441 if (isViewElementObjectOrList(elm)) {
442 acc.references.push(elm);
443 } else if (isViewElementChoise(elm)) {
444 acc.choises.push(elm);
445 } else if (isViewElementRpc(elm)) {
448 acc.elements.push(elm);
451 }, { elements: [] as ViewElement[], references: [] as ViewElement[], choises: [] as ViewElementChoise[], rpcs: [] as ViewElementRpc[] });
453 sections.elements = sections.elements.sort(orderFunc);
456 <div className={classes.uiView}>
457 <div className={classes.section} />
458 {sections.elements.length > 0
460 <div className={classes.section}>
461 {sections.elements.map(element => this.renderUIElement(element, viewData, keyProperty, editMode, isNew))}
465 {sections.references.length > 0
467 <div className={classes.section}>
468 {sections.references.map(element => (
469 <UIElementReference key={element.id} element={element} disabled={editMode} onOpenReference={(elm) => { this.navigate(`/${elm.id}`) }} />
474 {sections.choises.length > 0
476 <div className={classes.section}>
477 {sections.choises.map(element => this.renderUIChoise(element, viewData, keyProperty, editMode, isNew))}
481 {sections.rpcs.length > 0
483 <div className={classes.section}>
484 {sections.rpcs.map(element => (
485 <UIElementReference key={element.id} element={element} disabled={editMode} onOpenReference={(elm) => { this.navigate(`/${elm.id}`) }} />
494 private renderUIViewList(listSpecification: ViewSpecification, listKeyProperty: string, listData: { [key: string]: any }[]) {
495 const listElements = listSpecification.elements;
497 const navigate = (path: string) => {
498 this.props.history.push(`${this.props.match.url}${path}`);
501 const addNewElementAction = {
502 icon: AddIcon, tooltip: 'Add', onClick: () => {
503 navigate("[]"); // empty key means new element
507 const { classes, removeElement } = this.props;
509 const DeleteIconWithConfirmation : React.FC<{rowData: {[key:string]:any}, onReload: () => void} > = (props) => {
510 const confirm = useConfirm();
513 <Tooltip title={"Remove"} >
514 <IconButton className={classes.button} onClick={async (e) => {
517 confirm({title: "Do you really want to delete this element ?", description: "This action is permanent!", confirmationButtonProps: { color: "secondary" }})
518 .then(() => removeElement(`${this.props.vPath}[${props.rowData[listKeyProperty]}]`))
519 .then( props.onReload );
528 <SelectElementTable stickyHeader idProperty={listKeyProperty} rows={listData} customActionButtons={[addNewElementAction]} columns={
529 Object.keys(listElements).reduce<ColumnModel<{ [key: string]: any }>[]>((acc, cur) => {
530 const elm = listElements[cur];
531 if (elm.uiType !== "object" && listData.every(entry => entry[elm.label] != null)) {
532 if (elm.label !== listKeyProperty) {
533 acc.push(elm.uiType === "boolean" ? { property: elm.label, type: ColumnType.boolean } : { property: elm.label, type: elm.uiType === "number" ? ColumnType.numeric : ColumnType.text });
535 acc.unshift(elm.uiType === "boolean" ? { property: elm.label, type: ColumnType.boolean } : { property: elm.label, type: elm.uiType === "number" ? ColumnType.numeric : ColumnType.text });
540 property: "Actions", disableFilter: true, disableSorting: true, type: ColumnType.custom, customControl: ( ({ rowData })=> {
542 <DeleteIconWithConfirmation rowData={rowData} onReload={() => this.props.vPath && this.props.reloadView(this.props.vPath) } />
546 } onHandleClick={(ev, row) => {
548 navigate(`[${row[listKeyProperty]}]`);
549 }} ></SelectElementTable>
553 private renderUIViewRPC(inputViewSpecification: ViewSpecification | undefined, inputViewData: { [key: string]: any }, outputViewData: { [key: string]: any }, keyProperty: string | undefined, editMode: boolean, isNew: boolean) {
554 const { classes } = this.props;
556 const orderFunc = (vsA: ViewElement, vsB: ViewElement) => {
558 // if (vsA.label === vsB.label) return 0;
559 if (vsA.label === keyProperty) return -1;
560 if (vsB.label === keyProperty) return +1;
563 // if (vsA.uiType === vsB.uiType) return 0;
564 // if (vsA.uiType !== "object" && vsB.uiType !== "object") return 0;
565 // if (vsA.uiType === "object") return +1;
569 const sections = inputViewSpecification && Object.keys(inputViewSpecification.elements).reduce((acc, cur) => {
570 const elm = inputViewSpecification.elements[cur];
571 if (isViewElementObjectOrList(elm)) {
572 console.error("Object should not appear in RPC view !");
573 } else if (isViewElementChoise(elm)) {
574 acc.choises.push(elm);
575 } else if (isViewElementRpc(elm)) {
576 console.error("RPC should not appear in RPC view !");
578 acc.elements.push(elm);
581 }, { elements: [] as ViewElement[], references: [] as ViewElement[], choises: [] as ViewElementChoise[], rpcs: [] as ViewElementRpc[] })
582 || { elements: [] as ViewElement[], references: [] as ViewElement[], choises: [] as ViewElementChoise[], rpcs: [] as ViewElementRpc[] };
584 sections.elements = sections.elements.sort(orderFunc);
588 <div className={classes.section} />
589 {sections.elements.length > 0
591 <div className={classes.section}>
592 {sections.elements.map(element => this.renderUIElement(element, inputViewData, keyProperty, editMode, isNew))}
596 {sections.choises.length > 0
598 <div className={classes.section}>
599 {sections.choises.map(element => this.renderUIChoise(element, inputViewData, keyProperty, editMode, isNew))}
603 <Button onClick={() => {
604 const resultingViewData = inputViewSpecification && this.collectData(inputViewSpecification.elements);
605 this.props.executeRpc(this.props.vPath!, resultingViewData);
607 {outputViewData !== undefined
609 renderObject(outputViewData) )
616 private renderBreadCrumps() {
617 const { editMode } = this.state;
618 const { displaySpecification } = this.props;
619 const { vPath, nodeId } = this.props;
620 const pathParts = splitVPath(vPath!, /(?:([^\/\["]+)(?:\[([^\]]*)\])?)/g); // 1 = property / 2 = optional key
621 let lastPath = `/configuration`;
622 let basePath = `/configuration/${nodeId}`;
624 <div className={this.props.classes.header}>
626 <Breadcrumbs aria-label="breadcrumb">
627 <Link color="inherit" href="#" onClick={(ev: React.MouseEvent<HTMLElement>) => {
629 this.props.history.push(lastPath);
631 <Link color="inherit" href="#" onClick={(ev: React.MouseEvent<HTMLElement>) => {
633 this.props.history.push(`/configuration/${nodeId}`);
634 }}><span>{nodeId}</span></Link>
636 pathParts.map(([prop, key], ind) => {
637 const path = `${basePath}/${prop}`;
638 const keyPath = key && `${basePath}/${prop}[${key}]`;
641 <Link color="inherit" href="#" onClick={(ev: React.MouseEvent<HTMLElement>) => {
643 this.props.history.push(path);
644 }}><span>{prop.replace(/^[^:]+:/, "")}</span></Link>
646 keyPath && <Link color="inherit" href="#" onClick={(ev: React.MouseEvent<HTMLElement>) => {
648 this.props.history.push(keyPath);
649 }}>{`[${key}]`}</Link> || null
654 basePath = keyPath || path;
660 {this.state.editMode && (
661 <Fab color="secondary" aria-label="edit" className={this.props.classes.fab} onClick={async () => {
662 this.props.vPath && await this.props.reloadView(this.props.vPath);
663 this.setState({ editMode: false });
664 }} ><ArrowBack /></Fab>
666 { /* do not show edit if this is a list or it can't be edited */
667 displaySpecification.displayMode === DisplayModeType.displayAsObject && displaySpecification.viewSpecification.canEdit && (<div>
668 <Fab color="secondary" aria-label="edit" className={this.props.classes.fab} onClick={() => {
669 if (this.state.editMode) {
670 // ensure only active choises will be contained
671 const resultingViewData = this.collectData(displaySpecification.viewSpecification.elements);
672 this.props.onUpdateData(this.props.vPath!, resultingViewData);
674 this.setState({ editMode: !editMode });
687 private renderValueSelector() {
688 const { listKeyProperty, listSpecification, listData, onValueSelected } = this.props;
689 if (!listKeyProperty || !listSpecification) {
690 throw new Error("ListKex ot view not specified.");
694 <div className={this.props.classes.container}>
695 <SelectElementTable stickyHeader idProperty={listKeyProperty} rows={listData} columns={
696 Object.keys(listSpecification.elements).reduce<ColumnModel<{ [key: string]: any }>[]>((acc, cur) => {
697 const elm = listSpecification.elements[cur];
698 if (elm.uiType !== "object" && listData.every(entry => entry[elm.label] != null)) {
699 if (elm.label !== listKeyProperty) {
700 acc.push({ property: elm.label, type: elm.uiType === "number" ? ColumnType.numeric : ColumnType.text });
702 acc.unshift({ property: elm.label, type: elm.uiType === "number" ? ColumnType.numeric : ColumnType.text });
707 } onHandleClick={(ev, row) => { ev.preventDefault(); onValueSelected(row); }} ></SelectElementTable>
712 private renderValueEditor() {
713 const { displaySpecification: ds, outputData } = this.props;
714 const { viewData, editMode, isNew } = this.state;
717 <div className={this.props.classes.container}>
718 {this.renderBreadCrumps()}
719 {ds.displayMode === DisplayModeType.doNotDisplay
721 : ds.displayMode === DisplayModeType.displayAsList && viewData instanceof Array
722 ? this.renderUIViewList(ds.viewSpecification, ds.keyProperty!, viewData)
723 : ds.displayMode === DisplayModeType.displayAsRPC
724 ? this.renderUIViewRPC(ds.inputViewSpecification, viewData!, outputData, undefined, true, false)
725 : this.renderUIView(ds.viewSpecification, viewData!, ds.keyProperty, editMode, isNew)
731 private renderCollectingData() {
733 <div className={this.props.classes.outer}>
734 <div className={this.props.classes.inner}>
736 <h3>Processing ...</h3>
743 return this.props.collectingData || !this.state.viewData
744 ? this.renderCollectingData()
745 : this.props.listSpecification
746 ? this.renderValueSelector()
747 : this.renderValueEditor();
751 export const ConfigurationApplication = withStyles(styles)(withRouter(connect(mapProps, mapDispatch)(ConfigurationApplicationComponent)));
752 export default ConfigurationApplication;