Reverts `Remove sidebars`
diff --git a/frontend/src/components/sidebar/containers/Sidebar.js b/frontend/src/components/sidebar/containers/Sidebar.js
new file mode 100644
index 0000000..c3547cb
--- /dev/null
+++ b/frontend/src/components/sidebar/containers/Sidebar.js
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { connect } from 'react-redux';
+import Sidebar from '../presentations/Sidebar';
+
+const mapStateToProps = (state) => ({
+ activeMenuName: state.navigator.activeMenu,
+ isActive: state.navigator.isActive,
+});
+
+/*
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onThemeChange: function(e) {
+ const selectedTheme = e.target.value
+ dispatch({type: 'CHANGE_THEME', theme : selectedTheme})
+ }
+ }
+}
+*/
+
+const mapDispatchToProps = {};
+
+export default connect(mapStateToProps, mapDispatchToProps)(Sidebar);
+
+/*
+import React, {Component} from 'react'
+import store from '../../../app/store'
+class SidebarContainer extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {navigator : store.getState().navigator}
+ }
+
+ componentDidMount() {
+ store.subscribe(function() {
+ this.setState({navigator : store.getState().navigator});
+ }.bind(this));
+ }
+
+ changeTheme = (e) => {
+ console.log(e);
+ const selectedTheme = e.target.value
+ store.dispatch({type: 'CHANGE_THEME', theme : selectedTheme})
+ }
+
+ render() {
+ const activeMenu = this.state.navigator.activeMenu
+ return (
+ <Sidebar activeMenuName={activeMenu} onThemeChange={this.changeTheme} />
+ );
+ }
+
+}
+
+export default SidebarContainer
+*/
diff --git a/frontend/src/components/sidebar/containers/SidebarHome.js b/frontend/src/components/sidebar/containers/SidebarHome.js
new file mode 100644
index 0000000..860495b
--- /dev/null
+++ b/frontend/src/components/sidebar/containers/SidebarHome.js
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { connect } from 'react-redux';
+import SidebarHome from '../presentations/SidebarHome';
+import { setCommand } from '../../../features/editor/EditorSlice';
+import { addFrame, trimFrame } from '../../../features/frame/FrameSlice';
+import { getMetaData } from '../../../features/database/MetadataSlice';
+
+const mapStateToProps = (state) => ({
+ edges: state.metadata.edges,
+ nodes: state.metadata.nodes,
+ propertyKeys: state.metadata.propertyKeys,
+ dbname: state.metadata.dbname,
+ graph: state.metadata.graph,
+ role: state.metadata.role,
+ command: state.editor.command,
+});
+
+const mapDispatchToProps = {
+ setCommand, addFrame, trimFrame, getMetaData,
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(SidebarHome);
diff --git a/frontend/src/components/sidebar/containers/SidebarSetting.js b/frontend/src/components/sidebar/containers/SidebarSetting.js
new file mode 100644
index 0000000..4dd0009
--- /dev/null
+++ b/frontend/src/components/sidebar/containers/SidebarSetting.js
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { connect } from 'react-redux';
+import {
+ changeMaxDataOfGraph,
+ changeMaxDataOfTable,
+ changeMaxNumOfFrames,
+ changeMaxNumOfHistories,
+ changeTheme,
+ resetSetting,
+} from '../../../features/setting/SettingSlice';
+import SidebarSetting from '../presentations/SidebarSetting';
+
+const mapStateToProps = (state) => ({
+ theme: state.setting.theme,
+ maxNumOfFrames: state.setting.maxNumOfFrames,
+ maxNumOfHistories: state.setting.maxNumOfHistories,
+ maxDataOfGraph: state.setting.maxDataOfGraph,
+ maxDataOfTable: state.setting.maxDataOfTable,
+});
+
+const mapDispatchToProps = {
+ changeTheme,
+ changeMaxNumOfFrames,
+ changeMaxNumOfHistories,
+ changeMaxDataOfGraph,
+ changeMaxDataOfTable,
+ resetSetting,
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(SidebarSetting);
diff --git a/frontend/src/components/sidebar/presentations/Sidebar.jsx b/frontend/src/components/sidebar/presentations/Sidebar.jsx
new file mode 100644
index 0000000..ccb6d02
--- /dev/null
+++ b/frontend/src/components/sidebar/presentations/Sidebar.jsx
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import SidebarHome from '../containers/SidebarHome';
+import SidebarSetting from '../containers/SidebarSetting';
+
+const Sidebar = ({ activeMenuName, isActive }) => (
+ <div id="sidebar" className={isActive ? ' active ' : 'inactive'}>
+ <div className="tab-content">
+ <div className={`tab-pane fade${activeMenuName === 'home' ? ' active show ' : ''}`} role="tabpanel" aria-labelledby="side-home-tab">
+ <SidebarHome />
+ </div>
+ <div className={`tab-pane fade${activeMenuName === 'setting' ? ' active show ' : ''}`} role="tabpanel" aria-labelledby="side-setting-tab">
+ <SidebarSetting />
+ </div>
+ </div>
+ </div>
+);
+
+Sidebar.propTypes = {
+ activeMenuName: PropTypes.string.isRequired,
+ isActive: PropTypes.bool.isRequired,
+};
+
+export default Sidebar;
diff --git a/frontend/src/components/sidebar/presentations/SidebarComponents.jsx b/frontend/src/components/sidebar/presentations/SidebarComponents.jsx
new file mode 100644
index 0000000..fcc34a0
--- /dev/null
+++ b/frontend/src/components/sidebar/presentations/SidebarComponents.jsx
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+
+const StyleTextRight = {
+ marginBottom: '10px', textAlign: 'right', fontSize: '13px', fontWeight: 'bold',
+};
+const StyleTextLeft = { fontSize: '13px', fontWeight: 'bold' };
+
+export const ColoredLine = () => (
+ <hr
+ style={{
+ color: '#B0B0B0',
+ backgroundColor: '#B0B0B0',
+ marginTop: 0,
+ height: 0.3,
+ }}
+ />
+);
+
+export const VerticalLine = () => (
+ <div
+ style={{
+ backgroundColor: '#C4C4C4',
+ width: '1px',
+ height: '120px',
+ marginTop: '37px',
+ marginBottom: '37px',
+ }}
+ />
+);
+
+const SubLabelRight = ({ label, classes }) => (
+ <div className={classes} style={StyleTextRight}>{label}</div>
+);
+SubLabelRight.propTypes = {
+ classes: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+};
+
+const SubLabelLeft = ({ label, classes }) => (
+ <div className={classes} style={StyleTextLeft}>{label}</div>
+);
+SubLabelLeft.propTypes = {
+ classes: PropTypes.string.isRequired,
+ label: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.element,
+ ]).isRequired,
+};
+
+const SubLabelLeftWithLink = ({ label, classes }) => (
+ <div className={classes} style={StyleTextLeft}><pre>{label}</pre></div>
+);
+SubLabelLeftWithLink.propTypes = {
+ classes: PropTypes.string.isRequired,
+ label: PropTypes.string.isRequired,
+};
+
+export { SubLabelRight, SubLabelLeft, SubLabelLeftWithLink };
diff --git a/frontend/src/components/sidebar/presentations/SidebarHome.jsx b/frontend/src/components/sidebar/presentations/SidebarHome.jsx
new file mode 100644
index 0000000..6521585
--- /dev/null
+++ b/frontend/src/components/sidebar/presentations/SidebarHome.jsx
@@ -0,0 +1,427 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { Modal } from 'antd';
+import uuid from 'react-uuid';
+import { connect, useDispatch } from 'react-redux';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faRedo, faTimes } from '@fortawesome/free-solid-svg-icons';
+import { VerticalLine, SubLabelLeft, SubLabelRight } from './SidebarComponents';
+
+const genLabelQuery = (eleType, labelName, database) => {
+ function age() {
+ if (eleType === 'node') {
+ if (labelName === '*') {
+ return `SELECT * from cypher('${database.graph}', $$
+ MATCH (V)
+ RETURN V
+$$) as (V agtype);`;
+ }
+ return `SELECT * from cypher('${database.graph}', $$
+ MATCH (V:${labelName})
+ RETURN V
+$$) as (V agtype);`;
+ }
+ if (eleType === 'edge') {
+ if (labelName === '*') {
+ return `SELECT * from cypher('${database.graph}', $$
+ MATCH (V)-[R]-(V2)
+ RETURN V,R,V2
+$$) as (V agtype, R agtype, V2 agtype);`;
+ }
+ return `SELECT * from cypher('${database.graph}', $$
+ MATCH (V)-[R:${labelName}]-(V2)
+ RETURN V,R,V2
+$$) as (V agtype, R agtype, V2 agtype);`;
+ }
+ return '';
+ }
+ function agens() {
+ if (eleType === 'node') {
+ if (labelName === '*') {
+ return 'MATCH (V) RETURN V';
+ }
+ return `MATCH (V) WHERE LABEL(V) = '${labelName}' RETURN V`;
+ }
+ if (eleType === 'edge') {
+ if (labelName === '*') {
+ return 'MATCH (V)-[R]->(V2) RETURN *';
+ }
+ return `MATCH (V)-[R]->(V2) WHERE LABEL(R) = '${labelName}' RETURN *`;
+ }
+ return '';
+ }
+ if (database.flavor === 'AGE') {
+ return age();
+ }
+ if (database.flavor === 'AGENS') {
+ return agens();
+ }
+ return '';
+};
+
+const genPropQuery = (eleType, propertyName) => {
+ if (eleType === 'v') {
+ return `MATCH (V) WHERE V.${propertyName} IS NOT NULL RETURN V`;
+ }
+ if (eleType === 'e') {
+ return `MATCH (V)-[R]->(V2) WHERE R.${propertyName} IS NOT NULL RETURN *`;
+ }
+ return '';
+};
+
+const NodeList = ({ nodes, setCommand }) => {
+ let list;
+ if (nodes) {
+ list = nodes.map((item) => (
+ <NodeItems
+ key={uuid()}
+ label={item.label}
+ cnt={item.cnt}
+ setCommand={setCommand}
+ />
+ ));
+ return (
+ <div style={{
+ display: 'flex',
+ flexWrap: 'wrap',
+ height: '80px',
+ overflowY: 'auto',
+ marginTop: '12px',
+ }}
+ >
+ {list}
+ </div>
+ );
+ }
+
+ return null;
+};
+NodeList.propTypes = {
+ nodes: PropTypes.arrayOf(PropTypes.shape({
+ label: PropTypes.string,
+ cnt: PropTypes.number,
+ })).isRequired,
+ setCommand: PropTypes.func.isRequired,
+};
+
+const NodeItems = connect((state) => ({
+ database: state.database,
+}), {})(
+ ({
+ label, cnt, setCommand, database,
+ }) => (
+ <button
+ type="button"
+ className="node-item"
+ onClick={() => setCommand(genLabelQuery('node', label, database))}
+ >
+ {label}
+ (
+ {cnt}
+ )
+ </button>
+ ),
+);
+NodeItems.propTypes = {
+ database: PropTypes.shape({
+ flavor: PropTypes.string,
+ }).isRequired,
+ label: PropTypes.string.isRequired,
+ cnt: PropTypes.number.isRequired,
+ setCommand: PropTypes.func.isRequired,
+};
+
+const EdgeList = ({ edges, setCommand }) => {
+ let list;
+ if (edges) {
+ list = edges.map((item) => (
+ <EdgeItems
+ key={uuid()}
+ label={item.label}
+ cnt={item.cnt}
+ setCommand={setCommand}
+ />
+ ));
+ return (
+ <div style={{
+ display: 'flex',
+ flexWrap: 'wrap',
+ height: '80px',
+ overflowY: 'auto',
+ marginTop: '12px',
+ }}
+ >
+ {list}
+ </div>
+ );
+ }
+
+ return null;
+};
+EdgeList.propTypes = {
+ edges: PropTypes.arrayOf(PropTypes.shape({
+ label: PropTypes.string,
+ cnt: PropTypes.number,
+ })).isRequired,
+ setCommand: PropTypes.func.isRequired,
+};
+
+const EdgeItems = connect((state) => ({
+ database: state.database,
+}), {})(({
+ label, cnt, setCommand, database,
+}) => (
+ <button
+ type="button"
+ className="edge-item"
+ onClick={() => setCommand(genLabelQuery('edge', label, database))}
+ >
+ {label}
+ (
+ {cnt}
+ )
+ </button>
+));
+EdgeItems.propTypes = {
+ database: PropTypes.shape({
+ flavor: PropTypes.string,
+ }).isRequired,
+ label: PropTypes.string.isRequired,
+ cnt: PropTypes.number.isRequired,
+ setCommand: PropTypes.func.isRequired,
+};
+
+const PropertyList = ({ propertyKeys, setCommand }) => {
+ let list;
+ if (propertyKeys) {
+ list = propertyKeys.map((item) => (
+ <PropertyItems
+ key={uuid()}
+ propertyName={item.key}
+ keyType={item.key_type}
+ setCommand={setCommand}
+ />
+ ));
+ return (
+ <div style={{
+ display: 'flex',
+ flexWrap: 'wrap',
+ height: '80px',
+ overflowY: 'auto',
+ marginTop: '12px',
+ }}
+ >
+ {list}
+ </div>
+ );
+ }
+
+ return null;
+};
+PropertyList.propTypes = {
+ propertyKeys: PropTypes.arrayOf(PropTypes.shape({
+ key: PropTypes.string,
+ key_type: PropTypes.string,
+ })).isRequired,
+ setCommand: PropTypes.func.isRequired,
+};
+
+const PropertyItems = ({ propertyName, keyType, setCommand }) => (
+ <button
+ type="button"
+ className={`${keyType === 'v' ? 'propertie-item' : 'propertie-item'} propertie-item`}
+ onClick={() => setCommand(genPropQuery(keyType, propertyName))}
+ >
+ {propertyName}
+ </button>
+);
+PropertyItems.propTypes = {
+ propertyName: PropTypes.string.isRequired,
+ keyType: PropTypes.string.isRequired,
+ setCommand: PropTypes.func.isRequired,
+};
+
+const ConnectedText = ({ userName, roleName }) => (
+ <div>
+ <h6>
+ <div style={{ display: 'flex', flexWrap: 'wrap' }}>
+ <SubLabelRight label="Username :" classes="col-sm-6" />
+ <SubLabelLeft label={userName} classes="col-sm-6" />
+ </div>
+ <div style={{ display: 'flex', flexWrap: 'wrap' }}>
+ <SubLabelRight label="Roles :" classes="col-sm-6" />
+ <SubLabelLeft label={roleName} classes="col-sm-6" />
+ </div>
+ </h6>
+ </div>
+);
+
+ConnectedText.propTypes = {
+ userName: PropTypes.string.isRequired,
+ roleName: PropTypes.string.isRequired,
+};
+
+const DBMSText = ({ dbname, graph }) => (
+ <div>
+ <h6>
+ <div style={{ display: 'flex', flexWrap: 'wrap' }}>
+ <SubLabelRight label="Databases :" classes="col-sm-6" />
+ <SubLabelLeft label={dbname} classes="col-sm-6" />
+ </div>
+ <div style={{ display: 'flex', flexWrap: 'wrap' }}>
+ <SubLabelRight label="Graph Path :" classes="col-sm-6" />
+ <SubLabelLeft label={graph} classes="col-sm-6" />
+ </div>
+ <div style={{ display: 'flex', flexWrap: 'wrap' }}>
+ <SubLabelRight label="Information :" classes="col-sm-6" />
+ <SubLabelLeft label="-" classes="col-sm-6" />
+ </div>
+ <div style={{ display: 'flex', flexWrap: 'wrap' }}>
+ <SubLabelRight label="Query List :" classes="col-sm-6" />
+ <SubLabelLeft label="-" classes="col-sm-6" />
+ </div>
+ </h6>
+ </div>
+);
+
+DBMSText.propTypes = {
+ dbname: PropTypes.string.isRequired,
+ graph: PropTypes.string.isRequired,
+};
+
+const SidebarHome = ({
+ edges,
+ nodes,
+ propertyKeys,
+ setCommand,
+ command,
+ trimFrame,
+ addFrame,
+ getMetaData,
+}) => {
+ const dispatch = useDispatch();
+ const { confirm } = Modal;
+
+ const requestDisconnect = () => {
+ const refKey = uuid();
+ dispatch(() => trimFrame('ServerDisconnect'));
+ dispatch(() => addFrame(command, 'ServerDisconnect', refKey));
+ };
+
+ const refreshSidebarHome = () => {
+ getMetaData();
+ };
+
+ return (
+ <div className="sidebar-home">
+ <div className="sidebar sidebar-body">
+ <div className="form-group sidebar-item">
+ <b>Node Label</b>
+ <br />
+ <NodeList nodes={nodes} setCommand={setCommand} />
+ </div>
+ <VerticalLine />
+ <div className="form-group sidebar-item">
+ <b>Edge Label</b>
+ <br />
+ <EdgeList edges={edges} setCommand={setCommand} />
+ </div>
+ <VerticalLine />
+ <div className="form-group sidebar-item">
+ <b>Properties</b>
+ <br />
+ <PropertyList propertyKeys={propertyKeys} setCommand={setCommand} />
+ </div>
+ <VerticalLine />
+ <div className="form-group sidebar-item-disconnect">
+ <button
+ className="frame-head-button refresh_button btn btn-link"
+ type="button"
+ onClick={() => refreshSidebarHome()}
+ >
+ <FontAwesomeIcon
+ icon={faRedo}
+ size="1x"
+ color="white"
+ flip="horizontal"
+ />
+ </button>
+ <br />
+ <b>Refresh</b>
+ <div style={{
+ border: '1px solid #C4C4C4',
+ opacity: '1',
+ width: '80%',
+ height: '0',
+ margin: '3px auto',
+ }}
+ />
+ <button
+ className="frame-head-button close_session btn btn-link"
+ type="button"
+ color="#142B80"
+ onClick={() => confirm({
+ title: 'Are you sure you want to close this window?',
+ onOk() {
+ requestDisconnect();
+ },
+ onCancel() {
+ return false;
+ },
+ })}
+ >
+ <FontAwesomeIcon
+ icon={faTimes}
+ size="1x"
+ color="white"
+ />
+ </button>
+ <br />
+ <b>Close Session</b>
+ </div>
+ </div>
+ </div>
+ );
+};
+
+SidebarHome.propTypes = {
+ edges: PropTypes.arrayOf(PropTypes.shape({
+ label: PropTypes.string,
+ cnt: PropTypes.number,
+ })).isRequired,
+ nodes: PropTypes.arrayOf(PropTypes.shape({
+ label: PropTypes.string,
+ cnt: PropTypes.number,
+ })).isRequired,
+ propertyKeys: PropTypes.arrayOf(PropTypes.shape({
+ key: PropTypes.string,
+ key_type: PropTypes.string,
+ })).isRequired,
+ setCommand: PropTypes.func.isRequired,
+ command: PropTypes.string.isRequired,
+ trimFrame: PropTypes.func.isRequired,
+ addFrame: PropTypes.func.isRequired,
+ getMetaData: PropTypes.func.isRequired,
+};
+
+export default SidebarHome;
diff --git a/frontend/src/components/sidebar/presentations/SidebarSetting.jsx b/frontend/src/components/sidebar/presentations/SidebarSetting.jsx
new file mode 100644
index 0000000..382b39f
--- /dev/null
+++ b/frontend/src/components/sidebar/presentations/SidebarSetting.jsx
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import { ColoredLine, SubLabelLeft } from './SidebarComponents';
+import { saveToCookie } from '../../../features/cookie/CookieUtil';
+
+const SidebarSetting = ({
+ theme,
+ maxNumOfFrames,
+ maxNumOfHistories,
+ maxDataOfGraph,
+ maxDataOfTable,
+ changeTheme,
+ changeMaxNumOfFrames,
+ changeMaxNumOfHistories,
+ changeMaxDataOfGraph,
+ changeMaxDataOfTable,
+ resetSetting,
+}) => (
+ <div className="sidebar-setting">
+ <div className="sidebar sidebar-header">
+ <h4>Configuration</h4>
+ </div>
+ <div className="sidebar sidebar-body">
+ <div className="form-group">
+ <b>Themes</b>
+ <ColoredLine />
+ <select
+ className="form-control theme-switcher"
+ value={theme}
+ onChange={(e) => [saveToCookie('theme', e.target.value), changeTheme(e)]}
+ >
+ <option value="default">Default</option>
+ <option value="dark">Dark</option>
+ </select>
+ </div>
+ <div className="form-group pt-4">
+ <b>Frames</b>
+ <ColoredLine />
+ <fieldset className="form-group">
+ <SubLabelLeft label="Maximum Number of Frames:" classes="py-1" />
+ <input
+ type="number"
+ className="form-control"
+ id="maxFrames"
+ name="maxFrames"
+ min="0"
+ value={maxNumOfFrames}
+ onChange={(e) => [saveToCookie('maxNumOfFrames', e.target.value), changeMaxNumOfFrames(parseInt(e.target.value, 10))]}
+ />
+ </fieldset>
+ <fieldset className="form-group">
+ <SubLabelLeft label="Max Number of Histories:" classes="py-1" />
+ <input
+ type="number"
+ className="form-control"
+ id="maxHistories"
+ name="maxHistories"
+ value={maxNumOfHistories}
+ min="0"
+ onChange={(e) => [saveToCookie('maxNumOfHistories', e.target.value), changeMaxNumOfHistories(parseInt(e.target.value, 10))]}
+ />
+ </fieldset>
+ </div>
+ <div className="form-group pt-4">
+ <b>Data Display</b>
+ <ColoredLine />
+ <fieldset className="form-group">
+ <SubLabelLeft label="Maximum Data of Graph Visualization" classes="py-1" />
+ <input
+ type="number"
+ className="form-control"
+ id="maxGraphData"
+ name="maxGraphData"
+ value={maxDataOfGraph.toString()}
+ min="0"
+ onChange={(e) => [saveToCookie('maxDataOfGraph', e.target.value), changeMaxDataOfGraph(parseInt(e.target.value, 10))]}
+ />
+ </fieldset>
+ <fieldset className="form-group">
+ <SubLabelLeft label="Maximum Data of Table Display" classes="py-1" />
+ <input
+ type="number"
+ className="form-control"
+ id="maxTableData"
+ name="maxTableData"
+ value={maxDataOfTable}
+ min="0"
+ onChange={(e) => [saveToCookie('maxDataOfTable', e.target.value), changeMaxDataOfTable(parseInt(e.target.value, 10))]}
+ />
+ </fieldset>
+ </div>
+ <div className="form-group pt-4">
+ <fieldset className="form-group">
+ <button
+ type="button"
+ className="btn btn-info btn-sm btn-block"
+ onClick={() => [
+ resetSetting(),
+ ]}
+ >
+ Reset Configuration
+ </button>
+ </fieldset>
+ </div>
+ </div>
+ </div>
+);
+
+SidebarSetting.propTypes = {
+ theme: PropTypes.string.isRequired,
+ maxNumOfFrames: PropTypes.number.isRequired,
+ maxNumOfHistories: PropTypes.number.isRequired,
+ maxDataOfGraph: PropTypes.number.isRequired,
+ maxDataOfTable: PropTypes.number.isRequired,
+ changeTheme: PropTypes.func.isRequired,
+ changeMaxNumOfFrames: PropTypes.func.isRequired,
+ changeMaxNumOfHistories: PropTypes.func.isRequired,
+ changeMaxDataOfGraph: PropTypes.func.isRequired,
+ changeMaxDataOfTable: PropTypes.func.isRequired,
+ resetSetting: PropTypes.func.isRequired,
+};
+
+export default SidebarSetting;