diff --git a/.eslintrc b/.eslintrc
index f5c858df..89d062e7 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -53,8 +53,8 @@
"./src/develop/volto-embed/src"
],
[
- "volto-sidebar",
- "./src/develop/volto-sidebar/src"
+ "volto-tabsview",
+ "./src/develop/volto-tabsview/src"
]
]
}
diff --git a/jsconfig.json b/jsconfig.json
index a6393519..c5ba58c7 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -7,6 +7,7 @@
"volto-datablocks",
"volto-drafteditor",
"volto-mosaic",
+ "volto-tabsview",
"volto-plotlycharts"
],
"compilerOptions": {
@@ -15,6 +16,9 @@
"volto-mosaic": [
"develop/volto-mosaic/src"
],
+ "volto-tabsview": [
+ "develop/volto-tabsview/src"
+ ],
"volto-datablocks": [
"develop/volto-datablocks/src"
],
diff --git a/mrs.developer.json b/mrs.developer.json
index 799ee242..856e0773 100644
--- a/mrs.developer.json
+++ b/mrs.developer.json
@@ -39,5 +39,9 @@
"volto-gridlayout": {
"url": "https://github.com/eea/volto-gridlayout.git",
"path": "src"
+ },
+ "volto-tabsview": {
+ "url": "https://github.com/eea/volto-tabsview.git",
+ "path": "src"
}
}
diff --git a/src/components/manage/Blocks/SidebarBlock/Edit.jsx b/src/components/manage/Blocks/SidebarBlock/Edit.jsx
new file mode 100644
index 00000000..9f7063bf
--- /dev/null
+++ b/src/components/manage/Blocks/SidebarBlock/Edit.jsx
@@ -0,0 +1,84 @@
+import React, { useState, useEffect } from 'react';
+import { connect } from 'react-redux';
+import { compose } from 'redux';
+import _uniqueId from 'lodash/uniqueId';
+import RenderFields from 'volto-addons/Widgets/RenderFields';
+import View from './View';
+
+const makeChoices = keys => keys && keys.map(k => [k, k]);
+
+const getSchema = props => {
+ const { search, key, resourceKey } = props.discodata_query.data;
+ const discodataResources = Object.keys(props.discodata_resources.data) || [];
+ const selectedDiscodataResource =
+ props.discodata_resources.data?.[resourceKey]?.[search?.[key]] || null;
+ return {
+ parent: {
+ type: 'link',
+ title: 'Parent page',
+ },
+ multiply_second_level: {
+ type: 'boolean',
+ title: 'Multiply second level',
+ },
+ discodata_resource: {
+ type: 'array',
+ title: 'Discodata resource',
+ choices: makeChoices(discodataResources),
+ },
+ discodata_resource_property: {
+ type: 'array',
+ title: 'Source',
+ // items: {
+ choices: selectedDiscodataResource
+ ? makeChoices(Object.keys(selectedDiscodataResource))
+ : [],
+ // },
+ },
+ query_parameter: {
+ type: 'text',
+ title: 'Query to set',
+ },
+ };
+};
+
+const Edit = props => {
+ const [state, setState] = useState({
+ schema: getSchema({ ...props }),
+ id: _uniqueId('block_'),
+ });
+ useEffect(() => {
+ props.onChangeBlock(props.block, {
+ ...props.data,
+ hide_block: {
+ selector: '.sidebar-block-container .sidebar',
+ hiddenClassName: 'hidden',
+ event: 'sidebarToggle',
+ },
+ });
+ /* eslint-disable-next-line */
+ }, [])
+ useEffect(() => {
+ setState({
+ ...state,
+ schema: getSchema({
+ ...props,
+ }),
+ });
+ /* eslint-disable-next-line */
+ }, [state.item, props.data, props.discodata_resources, props.discodata_query])
+ return (
+
+
+
+
+ );
+};
+
+export default compose(
+ connect((state, props) => ({
+ pathname: state.router.location.pathname,
+ discodata_resources: state.discodata_resources,
+ discodata_query: state.discodata_query,
+ })),
+)(Edit);
diff --git a/src/components/manage/Blocks/SidebarBlock/View.jsx b/src/components/manage/Blocks/SidebarBlock/View.jsx
new file mode 100644
index 00000000..114245d9
--- /dev/null
+++ b/src/components/manage/Blocks/SidebarBlock/View.jsx
@@ -0,0 +1,206 @@
+/* REACT */
+import React, { useState, useEffect } from 'react';
+import { useHistory } from 'react-router-dom';
+import { compose } from 'redux';
+import { connect } from 'react-redux';
+import { NavLink } from 'react-router-dom';
+/* ROOT */
+import { settings } from '~/config';
+/* HELPERS */
+import { getNavigationByParent } from 'volto-tabsview/helpers';
+import {
+ getDiscodataResource,
+ setDiscodataQuery,
+} from 'volto-datablocks/actions';
+
+import './style.css';
+const sidebarRef = React.createRef();
+let unlisten;
+const View = ({ content, ...props }) => {
+ const { data } = props;
+ const [state, setState] = useState({
+ sidebar: [],
+ sidebarOpened: true,
+ });
+ const history = useHistory();
+ const { search, key, resourceKey } = props.discodata_query.data;
+ const parent = data.parent?.value;
+ const activeItem = search?.[props.data.discodata_resource_property?.value];
+
+ // useEffect(() => {
+ // unlisten = this.props.history.listen((location, action) => {
+ // if (action === 'PUSH') {
+ // const nextPathname = location.pathname.split('/');
+ // const prevPathname = props.location.pathname.split('/');
+ // // if (
+ // // props.location.search &&
+ // // props.location.search !== location.search &&
+ // // (location.pathname.includes(props.location.pathname) ||
+ // // nextPathname[1] === prevPathname[1])
+ // // ) {
+ // // props.history.push(
+ // // `${location.pathname}${this.props.location.search}`,
+ // // );
+ // // }
+ // }
+ // });
+ // return () => {
+ // unlisten();
+ // };
+ // /* eslint-disable-next-line */
+ // }, [])
+
+ useEffect(() => {
+ if (props.navigation) {
+ const sidebar = [];
+ sidebar.push(...getSidebar(props.navigation, 1));
+ setState({
+ ...state,
+ sidebar,
+ });
+ }
+ /* eslint-disable-next-line */
+ }, [ props.data, props.navigation, props.discodata_resources, props.discodata_query?.search]);
+
+ const getSidebar = (item, depth) => {
+ const sidebar = [];
+ if (depth === 2 && props.data?.multiply_second_level?.value === true) {
+ const selectedDiscodataResource =
+ props.discodata_resources.data?.[resourceKey]?.[search?.[key]] || null;
+ const selectedDiscodataResourceProperty =
+ selectedDiscodataResource?.[
+ props.data.discodata_resource_property?.value
+ ];
+ selectedDiscodataResourceProperty &&
+ item?.items?.length &&
+ Object.entries(selectedDiscodataResourceProperty).forEach(
+ ([key, value]) => {
+ sidebar.push(
+ ,
+ );
+ item?.items?.length &&
+ item.items.forEach(nextItem => {
+ sidebar.push(
+
+ {nextItem.title}
+ ,
+ );
+ sidebar.push(...getSidebar(nextItem, depth + 2));
+ });
+ },
+ );
+ } else {
+ item?.items?.length &&
+ item.items.forEach(nextItem => {
+ sidebar.push(
+
+ {nextItem.title}
+ ,
+ );
+ sidebar.push(...getSidebar(nextItem, depth + 1));
+ });
+ }
+ return sidebar;
+ };
+ return (
+
+ {/*
*/}
+
+ {props.navigation?.items?.length && parent ? (
+
+ ) : (
+ ''
+ )}
+
+
+ );
+};
+
+export default compose(
+ connect(
+ (state, props) => ({
+ router: state.router,
+ query: state.router.location.search,
+ location: state.router.location,
+ content:
+ state.prefetch?.[state.router.location.pathname] || state.content.data,
+ pathname: state.router.location.pathname,
+ lang: state.intl.locale,
+ navigation: getNavigationByParent(
+ state.navigation.items,
+ props.data?.parent?.value,
+ ),
+ discodata_resources: state.discodata_resources,
+ discodata_query: state.discodata_query,
+ }),
+ { getDiscodataResource, setDiscodataQuery },
+ ),
+)(View);
diff --git a/src/components/manage/Blocks/SidebarBlock/style.css b/src/components/manage/Blocks/SidebarBlock/style.css
new file mode 100644
index 00000000..4f149c02
--- /dev/null
+++ b/src/components/manage/Blocks/SidebarBlock/style.css
@@ -0,0 +1,83 @@
+.react-grid-item .block-container,
+.react-grid-item .block-container .block-wrapper,
+.sidebar-block-container,
+.sidebar-block-container .sidebar {
+ height: 100%;
+}
+
+.sidebar-block-container .sidebar {
+ background-color: #f3efee;
+ display: flex;
+ transition: width 0.2s;
+}
+
+.sidebar-block-container .sidebar .tabs {
+ display: flex;
+ flex-flow: column;
+ max-width: 220px;
+}
+
+.sidebar-block-container .sidebar.hidden {
+ width: 0;
+ overflow: hidden;
+}
+
+.sidebar-block-container .sidebar.show {
+ width: 100%;
+}
+
+.sidebar-block-container .sidebar .tabs {
+ flex-direction: column;
+ display: inline-flex;
+ position: relative;
+ margin: 2em auto;
+ padding: 0 1em;
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item,
+.sidebar-block-container .sidebar .tabs .tabs__item_active {
+ background-color: transparent;
+ border: none;
+ text-align: left;
+ color: #333333;
+ padding-bottom: 1rem;
+ cursor: pointer;
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item:focus,
+.sidebar-block-container .sidebar .tabs .tabs__item_active:focus {
+ outline: none;
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item.hidden {
+ display: none;
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item.show {
+ display: block;
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item.depth__2 {
+ padding-left: 1em;
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item.depth__3 {
+ padding-left: 2em;
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item.depth__4 {
+ padding-left: 3em;
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item_active {
+ color: #ED776A
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item_active.depth__2 {
+ color: #ED776A
+}
+
+.sidebar-block-container .sidebar .tabs .tabs__item_active.depth__3 {
+ color: #333333;
+ font-weight: bold;;
+}
diff --git a/src/components/theme/View/DiscodataView.jsx b/src/components/theme/View/DiscodataView.jsx
new file mode 100644
index 00000000..b2d0c506
--- /dev/null
+++ b/src/components/theme/View/DiscodataView.jsx
@@ -0,0 +1,78 @@
+/* REACT IMPORTS */
+import React, { useState, useEffect } from 'react';
+import { connect } from 'react-redux';
+import qs from 'query-string';
+/* ROOT IMPORTS */
+import MosaicView from 'volto-mosaic/components/theme/View';
+import DB from 'volto-datablocks/DataBase/DB';
+// SVGS
+/* LOCAL IMPORTS */
+import {
+ getDiscodataResource,
+ setDiscodataQuery,
+} from 'volto-datablocks/actions';
+/* =================================================== */
+
+const DiscodataView = props => {
+ const query = qs.parse(props.location.search);
+
+ useEffect(() => {
+ const { sql_query, endpoint_url } = props.content;
+ const {
+ search,
+ key,
+ resourceKey,
+ where,
+ groupBy,
+ } = props.discodata_query.data;
+ const whereStatements =
+ where?.length > 0 &&
+ where.map(param => {
+ return {
+ discodataKey: param,
+ value: props.discodata_query.data.search?.[param],
+ };
+ });
+ const url = DB.table(sql_query, endpoint_url, {
+ p: query.p,
+ nrOfHits: query.nrOfHits,
+ })
+ .where(whereStatements)
+ .encode()
+ .get();
+ if (!props.discodata_resources.loading) {
+ const request = {
+ url,
+ search: search || {},
+ resourceKey: resourceKey || '',
+ key: key || '',
+ groupBy: groupBy || [],
+ };
+ if (
+ request.url &&
+ !props.discodata_resources.data?.[key]?.[
+ props.discodata_query.data.search?.[key]
+ ]
+ ) {
+ props.getDiscodataResource(request);
+ }
+ }
+ /* eslint-disable-next-line */
+ }, [props.discodata_query.data])
+
+ return (
+
+
+
+ );
+};
+
+export default connect(
+ (state, props) => ({
+ discodata_query: state.discodata_query,
+ discodata_resources: state.discodata_resources,
+ content:
+ state.prefetch?.[state.router.location.pathname] || state.content.data,
+ }),
+ { getDiscodataResource, setDiscodataQuery },
+)(DiscodataView);
diff --git a/src/config.js b/src/config.js
index 6f0c913c..fa80660e 100644
--- a/src/config.js
+++ b/src/config.js
@@ -12,6 +12,7 @@ import { applyConfig as mosaicConfig } from 'volto-mosaic/config';
import { applyConfig as plotlyConfig } from 'volto-plotlycharts/config';
// import { applyConfig as installEPRTRFrontend } from './localconfig';
import { applyConfig as gridLayoutConfig } from 'volto-gridlayout/config';
+import { applyConfig as tabsViewConfig } from 'volto-tabsview/config';
// import { applyConfig as installEPRTRFrontend } from './localconfig';
import installEPRTR from './localconfig';
@@ -22,6 +23,7 @@ const config = [
installTableau,
plotlyConfig,
// ckeditorConfig,
+ tabsViewConfig,
mosaicConfig,
blocksConfig,
dataBlocksConfig,
diff --git a/src/customizations/volto/helpers/Api/Api.js b/src/customizations/volto/helpers/Api/Api.js
new file mode 100644
index 00000000..0fcd7412
--- /dev/null
+++ b/src/customizations/volto/helpers/Api/Api.js
@@ -0,0 +1,81 @@
+/**
+ * Api helper.
+ * @module helpers/Api
+ */
+
+import superagent from 'superagent';
+import cookie from 'react-cookie';
+
+import { settings } from '~/config';
+
+const methods = ['get', 'post', 'put', 'patch', 'del'];
+
+/**
+ * Format the url.
+ * @function formatUrl
+ * @param {string} path Path (or URL) to be formatted.
+ * @returns {string} Formatted path.
+ */
+function formatUrl(path) {
+ if (path.startsWith('http://') || path.startsWith('https://')) return path;
+
+ const adjustedPath = path[0] !== '/' ? `/${path}` : path;
+ let apiPath = '';
+ if (settings.internalApiPath && __SERVER__) {
+ apiPath = settings.internalApiPath;
+ } else {
+ apiPath = settings.apiPath;
+ }
+ return `${apiPath}${adjustedPath}`;
+}
+
+/**
+ * Api class.
+ * @class Api
+ */
+class Api {
+ /**
+ * Constructor
+ * @method constructor
+ * @constructs Api
+ */
+ constructor() {
+ methods.forEach(method => {
+ this[method] = (path, { params, data, type, headers = {} } = {}) => {
+ let request;
+ let promise = new Promise((resolve, reject) => {
+ request = superagent[method](formatUrl(path));
+
+ if (params) {
+ request.query(params);
+ }
+
+ const authToken = cookie.load('auth_token');
+ if (authToken) {
+ request.set('Authorization', `Bearer ${authToken}`);
+ }
+
+ request.set('Accept', 'application/json');
+
+ if (type) {
+ request.type(type);
+ }
+
+ Object.keys(headers).forEach(key => request.set(key, headers[key]));
+
+ if (data) {
+ request.send(data);
+ }
+
+ request.end((err, { body } = {}) =>
+ err ? reject(err) : resolve(body),
+ );
+ });
+ promise.request = request;
+ return promise;
+ };
+ });
+ }
+}
+
+export default Api;
diff --git a/src/localconfig.js b/src/localconfig.js
index ab8af831..eb74ae4a 100644
--- a/src/localconfig.js
+++ b/src/localconfig.js
@@ -3,6 +3,9 @@ import TabsView from '~/components/theme/View/TabsView';
import RedirectView from '~/components/theme/View/RedirectView';
import TabsChildView from '~/components/theme/View/TabsChildView';
import BrowseView from '~/components/theme/View/BrowseView/BrowseView';
+import DiscodataView from '~/components/theme/View/DiscodataView';
+
+import MosaicForm from 'volto-mosaic/components/manage/Form';
import DetailedLinkView from '~/components/manage/Blocks/DetailedLink/View';
import DetailedLinkEdit from '~/components/manage/Blocks/DetailedLink/Edit';
@@ -25,8 +28,10 @@ import RegulatoryInformationBlockView from '~/components/manage/Blocks/Regulator
import CompanyHeaderEdit from '~/components/manage/Blocks/CompanyHeader/Edit';
import CompanyHeaderView from '~/components/manage/Blocks/CompanyHeader/View';
+import EprtrSidebarBlockEdit from '~/components/manage/Blocks/SidebarBlock/Edit';
+import EprtrSidebarBlockView from '~/components/manage/Blocks/SidebarBlock/View';
+
const applyConfig = config => {
- console.log('config', config);
config.views = {
...config.views,
layoutViews: {
@@ -35,6 +40,15 @@ const applyConfig = config => {
glossaryview: TabsChildView,
redirect_view: RedirectView,
browse_view: BrowseView,
+ discodata_view: DiscodataView,
+ },
+ };
+
+ config.editForms = {
+ ...config.editForms,
+ byLayout: {
+ ...config.editForms?.byLayout,
+ discodata_view: MosaicForm,
},
};
@@ -101,6 +115,15 @@ const applyConfig = config => {
group: 'data_blocks',
};
+ config.blocks.blocksConfig.eprtr_sidebar_block = {
+ id: 'eprtr_sidebar_block',
+ title: 'Eprtr sidebar block',
+ view: EprtrSidebarBlockView,
+ edit: EprtrSidebarBlockEdit,
+ icon: chartIcon,
+ group: 'data_blocks',
+ };
+
return config;
};
diff --git a/theme/site/globals/site.overrides b/theme/site/globals/site.overrides
index e8dc3635..8e87227c 100644
--- a/theme/site/globals/site.overrides
+++ b/theme/site/globals/site.overrides
@@ -831,11 +831,13 @@ space-around {
top: auto;
}
}
-
.sidebar-container {
z-index: 9999;
}
+}
+.sidebar-container .ui.raised.segments {
+ height: fit-content !important;
}
.block.maps iframe {
@@ -1002,4 +1004,127 @@ body.has-sidebar {
left: auto !important;
transform: none !important;
top: auto;
+}
+
+/* Tabs view nav */
+.tabs-view-menu {
+ padding-bottom: 0;
+ height: 100%;
+ .scroll-container {
+ height: 100%;
+ .ui.menu {
+ height: 100%;
+ }
+ }
+ .ui.menu {
+ border: none;
+ box-shadow: none;
+ &.item {
+ text-align: left !important;
+ justify-content: start !important;
+ margin-left: auto !important;
+ margin-right: auto !important;
+ &::-webkit-scrollbar {
+ height: 6px;
+ }
+ &::-webkit-scrollbar-track {
+ border-radius: 10em;
+ }
+ &::-webkit-scrollbar-thumb {
+ background-color: darkgrey;
+ outline: 1px solid slategrey;
+ }
+ .item {
+ width: fit-content !important;
+ margin-right: 1em !important;
+ margin-left: 1em !important;
+ }
+ }
+ .item {
+ font-size: 18px;
+ &:before {
+ background: #fff;
+ }
+ }
+ .active.item {
+ background: #fff;
+ color: #4296B3;
+ font-weight: bold;
+ border-bottom: 2px solid #4296B3;
+ &:hover {
+ background: transparent;
+ color: #3b849e;
+ }
+ }
+ }
+
+ // @media(min-width: 1300px) {
+ // .ui.item.menu {
+ // width: 1200px !important;
+ // }
+ // }
+
+ // @media(min-width: 1000px) {
+ // .ui.item.menu {
+ // width: 900px !important;
+ // }
+ // }
+
+ // @media(max-width: 999px) {
+ // .ui.item.menu {
+ // width: fit-content !important;
+ // }
+ // }
+}
+
+.react-grid-item {
+ .block-container {
+ .block-wrapper {
+ &.grey {
+ background-color: #F6F6F6;
+ }
+ .sidebar {
+ .tabs {
+
+ }
+ }
+ }
+ }
+}
+
+
+.view-navgation-container {
+ height: 100%;
+ .tabs-view-menu {
+ padding-bottom: 0;
+ }
+ .view-sidebar-container {
+ display: grid;
+ grid-template-columns: 300px 1fr;
+ height: calc(100% - 40px);
+ .sidebar {
+ background: #F3EFEE;
+ padding: 20px 0;
+ }
+ .view {
+ padding: 20px;
+ }
+ }
+}
+
+
+.section-industrial-site main {
+ height: 100%;
+}
+
+h2 {
+ color: #4296B3;
+}
+
+h3 {
+ color: #EC776A;
+}
+
+.blocks-chooser {
+ top: -500px !important;
}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 4f583f22..cc953dc3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -32,6 +32,9 @@
],
"volto-embed": [
"develop/volto-embed"
+ ],
+ "volto-tabsview": [
+ "develop/volto-tabsview"
]
},
"baseUrl": "src"