10a0547be1ebed99a14397adf60a7e91fff0f45e
[ccsdk/features.git] / sdnr / wt / odlux / framework / src / components / objectDump / index.tsx
1 /**
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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
15  * the License.
16  * ============LICENSE_END==========================================================================
17  */
18
19 import * as React from "react";
20 import makeStyles from '@mui/styles/makeStyles';
21
22 export const getTypeName = (obj: any): string => {
23   if (obj == null) {
24     return obj === undefined ? "Undefined" : "Null";
25   }
26   return Object.prototype.toString.call(obj).slice(8, -1);
27 };
28
29 const isObjectLike = (obj: any) => {
30   return typeof obj === "object" && obj !== null;
31 };
32
33 const isBoolean = (obj: any) => {
34   return obj === true || obj === false ||
35     (isObjectLike(obj) && getTypeName(obj) === "Boolean");
36 };
37
38 const isNumber = (obj: any) => {
39   return typeof obj === "number" ||
40     (isObjectLike(obj) && getTypeName(obj) === "Number");
41 };
42
43 const isString = (obj: any) => {
44   return typeof obj === "string" ||
45     (isObjectLike(obj) && getTypeName(obj) === "String");
46 };
47
48 const isNull = (obj: any) => {
49   return obj === null;
50 };
51
52 const isDate = (obj: any): boolean => {
53   return isObjectLike(obj) && (obj instanceof Date);
54 };
55
56 const useSimpleTableStyles = makeStyles({
57   root: {
58   },
59   table: {
60     fontFamily: "verdana, arial, helvetica, sans-serif",
61     borderSpacing: "3px",
62     borderCollapse: "separate",
63     marginLeft: "30px"
64   },
65   label: {
66     cursor: "pointer",
67   },
68   th: {
69     textAlign: "left",
70     color: "white",
71     padding: "5px",
72     backgroundColor: "#cccccc",
73
74   },
75   td: {
76     verticalAlign: "top",
77     padding: "0.5rem 1rem",
78     border: "2px solid #DDD"
79   },
80   object: {
81   },
82   objectTh: {
83     backgroundColor: "#cccccc",
84   },
85   objectTd: {
86     padding: "0.5rem 1rem",
87     border: "2px solid #DDD"
88   },
89   chevron: {
90     '&:before': {
91       borderStyle: 'solid',
92       borderWidth: '0.25em 0.25em 0 0',
93       content: '\'\'',
94       display: 'inline-block',
95       height: '0.45em',
96       left: '0.15em',
97       position: 'relative',
98       top: '0.15em',
99       transform: 'rotate(-45deg)',
100       transition: 'all 0.3s',
101       verticalAlign: 'top',
102       width: '0.45em',
103     }
104
105   },
106     right: {
107     '&:before': {
108       left: '0',
109       transform: 'rotate(45deg)',
110     }
111   },
112   bottom: {
113     '&:before': {
114       left: '0',
115       transform: 'rotate(135deg)',
116     }
117   },
118 });
119
120
121 type SimpleTableProps = {
122   classNameTh?: string;
123   label?: JSX.Element | string | null;
124   cols?: number;
125   expand?: boolean;
126   ariaLabel?: string;
127 }
128
129 const SimpleTable: React.FC<SimpleTableProps> = (props) => {
130   const { label = '', cols = 2, expand = true, classNameTh, children } = props;
131   const [isExpanded, setIsExpanded] = React.useState(expand);
132
133   const classes = useSimpleTableStyles();
134
135   React.useEffect(() => {
136     setIsExpanded(expand);
137   }, [expand]);
138
139   const handleClick = () => {
140     setIsExpanded(!isExpanded);
141   };
142
143   return (
144     <table className={`${classes.root} ${classes.table}`} aria-label={props.ariaLabel? props.ariaLabel+'-table' : 'table'}>
145       {label && (<thead>
146         <tr aria-label={props.ariaLabel? props.ariaLabel+'-title-row' : 'title row'}>
147           <th className={`${classes.th} ${classes.label} ${classNameTh ? classNameTh : ''}`} colSpan={cols} onClick={handleClick}>
148             <span className={`${classes.chevron} ${isExpanded ? classes.bottom : classes.right }`}></span> { label }
149           </th>
150         </tr>
151       </thead>) || null
152       }
153       {isExpanded && <tbody >{children}</tbody> || null}
154     </table>
155   );
156 };
157
158
159 type ObjectRendererProps = {
160   className?: string;
161   label?: JSX.Element | string | null;
162   expand?: boolean;
163   object: { [key: string]: any };
164   ariaLabel?: string;
165 };
166
167 const ObjectRenderer: React.FC<ObjectRendererProps> = (props) => {
168   const { object, className, label = 'Object', expand = true } = props;
169   const classes = useSimpleTableStyles();
170
171   return (
172     <SimpleTable ariaLabel={props.ariaLabel} classNameTh={classes.objectTh} label={getTypeName(object) || label} expand={expand}>
173       {
174         Object.keys(object).map(key => {
175           return (
176             <tr key={String(key)} aria-label={props.ariaLabel? props.ariaLabel+'-row': 'row'}>
177               <td className={`${classes.td} ${classes.objectTd}`} aria-label="object-title">{String(key)} </td>
178               <td className={`${classes.td}`} aria-label="object-details">{renderObject(object[key], "sub-element")}</td>
179             </tr>
180           );
181         })
182       }
183     </SimpleTable>
184   );
185 };
186
187
188 type ArrayRendererProps = {
189   label?: JSX.Element | string | null;
190   extraRenderer?: { [label: string]: React.ComponentType<{ label?: JSX.Element | string | null; object: any; }> };
191   description?: string;
192   object: any;
193 };
194
195 const ArrayRenderer: React.FC<ArrayRendererProps> = (props) => {
196
197   return null;
198 };
199
200 export const renderObject = (object: any, ariaLabel?: string): JSX.Element | string => {
201   if (isString(object) || isNumber(object) || isBoolean(object)) {
202     return String(object);
203   }
204   return <ObjectRenderer object={object} ariaLabel={ariaLabel} />;
205 };