diff --git a/src/components/manage/Blocks/ArticlesSparql/style.css b/src/components/manage/Blocks/ArticlesSparql/style.css
index 5a1b64f..a992662 100644
--- a/src/components/manage/Blocks/ArticlesSparql/style.css
+++ b/src/components/manage/Blocks/ArticlesSparql/style.css
@@ -9,7 +9,10 @@
}
.articles .article {
- display: block;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 100%;
}
.articles .articles-row.can-be-half:last-child {
@@ -25,6 +28,9 @@
.articles .article.hero img {
border-radius: 2em;
+ max-height: 200px;
+ width: auto;
+ height: auto;
}
.articles .article-header,
diff --git a/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx
index 9928903..0dd4d4c 100644
--- a/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx
+++ b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx
@@ -942,6 +942,11 @@ const OpenlayersMapView = (props) => {
}
currentZoom = newZoom;
}
+ props.setQueryParam({
+ queryParam: {
+ extent: map.getView().calculateExtent(map.getSize()),
+ },
+ });
}
});
setState({
diff --git a/src/components/manage/Blocks/DiscodataTableBlock/Edit.jsx b/src/components/manage/Blocks/DiscodataTableBlock/Edit.jsx
new file mode 100644
index 0000000..12f09fe
--- /dev/null
+++ b/src/components/manage/Blocks/DiscodataTableBlock/Edit.jsx
@@ -0,0 +1,173 @@
+import React, { useEffect } from 'react';
+import { connect } from 'react-redux';
+import { compose } from 'redux';
+import { injectIntl } from 'react-intl';
+import View from './View';
+import DiscodataSqlBuilderEdit from 'volto-datablocks/DiscodataSqlBuilder/Edit';
+
+const schema = {
+ itemsCountKey: {
+ title: 'Items count key',
+ type: 'text',
+ },
+ hiddenRowTypes: {
+ title: 'Hidden row columns types',
+ type: 'array',
+ },
+ metadata: {
+ title: 'Metadata',
+ type: 'schema',
+ fieldSetTitle: 'Table metadata',
+ fieldSetId: 'table-metadata',
+ fieldSetSchema: {
+ fieldsets: [
+ {
+ id: 'default',
+ title: 'title',
+ fields: [
+ 'tableType',
+ 'title',
+ 'id',
+ 'dataType',
+ 'show',
+ 'urlFieldId',
+ 'queriesToSet',
+ 'discodataQueriesKeys',
+ 'hiddenRowType',
+ 'className',
+ ],
+ },
+ ],
+ properties: {
+ tableType: {
+ type: 'string',
+ title: 'Table type',
+ description: 'Used for data table fieldset',
+ choices: [
+ ['Table header', 'Table header'],
+ ['Hidden row', 'Hidden row'],
+ ['Invisible', 'Invisible'],
+ ],
+ },
+ id: {
+ type: 'string',
+ title: 'Field id',
+ description: 'Description',
+ },
+ title: {
+ type: 'string',
+ title: 'Title',
+ },
+ dataType: {
+ type: 'string',
+ title: 'Data type',
+ choices: [
+ ['string', 'String'],
+ ['textarea', 'Text area'],
+ ['array', 'Array'],
+ ['object', 'Object'],
+ ['button', 'Button'],
+ ],
+ },
+ show: {
+ type: 'string',
+ title: 'Display option',
+ choices: formData => {
+ if (['string', 'textarea'].includes(formData.dataType))
+ return [['value', 'Value'], ['link_value', 'Link value']];
+ if (['button'].includes(formData.dataType))
+ return [['link_value', 'Link value']];
+ if (['array', 'object'].includes(formData.dataType))
+ return [
+ ['length', 'Length'],
+ ['keys', 'Keys'],
+ ['link_length', 'Link length'],
+ ['link_keys', 'Link keys'],
+ ];
+ return [];
+ },
+ },
+ urlFieldId: {
+ disabled: formData =>
+ !['link_value', 'link_length', 'link_keys'].includes(
+ formData?.show,
+ ),
+ type: 'string',
+ title: 'Url field id or url',
+ description: 'Add only if "Display option" is set to "Link*"',
+ },
+ queriesToSet: {
+ disabled: formData =>
+ !['link_value', 'link_length', 'link_keys'].includes(
+ formData?.show,
+ ),
+ type: 'array',
+ title: 'Queries to set',
+ items: {
+ choices: [],
+ },
+ },
+ discodataQueriesKeys: {
+ disabled: formData =>
+ !['link_value', 'link_length', 'link_keys'].includes(
+ formData?.show,
+ ),
+ type: 'array',
+ title: 'Discodata queries keys',
+ items: {
+ choices: [],
+ },
+ },
+ hiddenRowType: {
+ disabled: formData => formData?.tableType !== 'Hidden row',
+ type: 'string',
+ title: 'Hidden row type',
+ description: "Add only if 'Table type' is set to 'Hidden row'",
+ choices: [],
+ },
+ className: {
+ disabled: formData => formData?.dataType !== 'button',
+ type: 'string',
+ title: 'Add a classname',
+ description: "Add only if 'button' data type is selected",
+ },
+ },
+ required: ['tableType', 'id', 'title', 'dataType', 'show'],
+ },
+ editFieldset: false,
+ deleteFieldset: false,
+ },
+};
+
+const Edit = React.forwardRef(props => {
+ useEffect(() => {
+ if (schema.metadata?.fieldSetSchema?.properties?.hiddenRowType) {
+ schema.metadata.fieldSetSchema.properties.hiddenRowType.choices = props
+ .data?.hiddenRowTypes?.value
+ ? props.data.hiddenRowTypes.value.map(type => [type, type])
+ : [];
+ }
+ /* eslint-disable-next-line */
+ }, [props.data?.hiddenRowTypes?.value]);
+
+ if (__SERVER__) {
+ return
;
+ }
+
+ return (
+
+
+
+ );
+});
+
+export default compose(
+ injectIntl,
+ connect(state => ({
+ content: state.content.data,
+ })),
+)(Edit);
diff --git a/src/components/manage/Blocks/DiscodataTableBlock/View.jsx b/src/components/manage/Blocks/DiscodataTableBlock/View.jsx
new file mode 100644
index 0000000..b8c1b37
--- /dev/null
+++ b/src/components/manage/Blocks/DiscodataTableBlock/View.jsx
@@ -0,0 +1,461 @@
+import React, { useState, useEffect } from 'react';
+import { connect } from 'react-redux';
+import { compose } from 'redux';
+import { isString } from 'lodash';
+import { Link } from 'react-router-dom';
+import qs from 'query-string';
+import { Table, Pagination } from 'semantic-ui-react';
+import downSVG from '@plone/volto/icons/down-key.svg';
+import upSVG from '@plone/volto/icons/up-key.svg';
+import { Icon } from '@plone/volto/components';
+import DiscodataSqlBuilderView from 'volto-datablocks/DiscodataSqlBuilder/View';
+import { setQueryParam } from 'volto-datablocks/actions';
+import { Dimmer, Loader } from 'semantic-ui-react';
+
+const components = {
+ object_link_length: (schemaMetadata, itemMetadata, item) => {
+ return (
+
+ {item[itemMetadata] && Object.keys(item[itemMetadata]).length}{' '}
+ {schemaMetadata.title}
+
+ );
+ },
+ object_link_keys: (schemaMetadata, itemMetadata, item) => {
+ return (
+ <>
+ {item[itemMetadata] &&
+ Object.keys(item[itemMetadata])?.map(
+ (key, index) =>
+ index < 3 && {key},
+ )}
+ {item[itemMetadata] && Object.keys(item[itemMetadata]).length > 3 && (
+
+ {Object.keys(item[itemMetadata]).length - 3} {schemaMetadata.title}
+
+ )}
+ >
+ );
+ },
+ textarea_link_value: (schemaMetadata, itemMetadata, item) => {
+ return (
+ <>
+
+
+ {schemaMetadata.title}
+
+ >
+ );
+ },
+ button_link_value: (schemaMetadata, itemMetadata, item, props) => {
+ const { search } = props.discodata_query;
+ let newSearch = { ...search };
+ let updatedSearch = false;
+ schemaMetadata.queriesToSet.forEach((key, index) => {
+ if (
+ schemaMetadata.discodataQueriesKeys[index] &&
+ (!newSearch[key] ||
+ (newSearch[key] &&
+ newSearch[key] !==
+ item[schemaMetadata.discodataQueriesKeys[index]]))
+ ) {
+ updatedSearch = true;
+ newSearch[key] = item[schemaMetadata.discodataQueriesKeys[index]];
+ }
+ });
+ return (
+
+ {
+ if (updatedSearch) props.setQueryParam({ queryParam: newSearch });
+ }}
+ to={
+ schemaMetadata.urlFieldId + ''
+ // (newSearch ? `?${qs.stringify(newSearch)}` : '')
+ }
+ >
+ {schemaMetadata.title}
+
+
+ );
+ },
+ default: (schemaMetadata, itemMetadata, item) => {
+ if (Array.isArray(item[itemMetadata])) return item[itemMetadata].join(', ');
+ if (typeof item[itemMetadata] === 'object' && item[itemMetadata] !== null)
+ return Object.keys(item[itemMetadata]).join(', ');
+ return item[itemMetadata];
+ },
+};
+
+const View = (props) => {
+ const [state, setState] = useState({
+ metadata: {},
+ tableHeaders: 0,
+ pagination: {
+ activePage: 1,
+ itemsPerPage: 25,
+ },
+ selectedItemIndex: -1,
+ });
+ const [collection, set_collection] = useState('');
+ const [collection_count, set_collection_count] = useState('');
+ const extent = props.discodata_query.search.extent || [
+ -10686671.0000035,
+ -2430148.00000588,
+ 6199975.99999531,
+ 10421410.9999871,
+ ];
+ const sqls = props.data?.sql?.value
+ ? JSON.parse(props.data.sql.value).properties
+ : {};
+ const { activePage, itemsPerPage } = state.pagination;
+ let items = [],
+ totalItems = 0;
+ if (
+ (sqls && Object.keys(sqls).length >= 2 && items,
+ props.data.itemsCountKey?.value)
+ ) {
+ const local_collection = Object.keys(sqls).filter(
+ (key) => !key.includes('collection_count'),
+ )[0];
+ const local_collection_count = Object.keys(sqls).filter((key) =>
+ key.includes('collection_count'),
+ )[0];
+ if (collection !== local_collection) {
+ set_collection(local_collection);
+ }
+ if (collection_count !== local_collection_count) {
+ set_collection_count(local_collection_count);
+ }
+ items = props.discodata_resources.data[local_collection] || [];
+ totalItems =
+ props.data.itemsCountKey?.value &&
+ props.discodata_resources.data[local_collection_count] &&
+ Array.isArray(props.discodata_resources.data[local_collection_count]) &&
+ props.discodata_resources.data[local_collection_count].length > 0
+ ? props.discodata_resources.data[local_collection_count].reduce(
+ (acc, el) =>
+ acc[props.data.itemsCountKey.value] +
+ el[props.data.itemsCountKey.value],
+ )[props.data.itemsCountKey.value]
+ : 0;
+ }
+ useEffect(() => {
+ const metadata = props.data?.metadata
+ ? isString(props.data.metadata.value)
+ ? JSON.parse(props.data.metadata.value)
+ : props.data.metadata.value
+ : {};
+ setState({
+ ...state,
+ metadata,
+ tableHeaders: metadata?.fieldsets?.[0]?.fields?.length,
+ });
+ /* eslint-disable-next-line */
+ }, [props.data?.metadata?.value])
+
+ const loader =
+ props.discodata_resources.pendingRequests[collection] ||
+ props.discodata_resources.pendingRequests[collection_count];
+
+ const additionalWhereStatements = [
+ `x_3857 >= ${extent[0]} AND x_3857 <= ${extent[2]}`,
+ `y_3857 >= ${extent[1]} AND y_3857 <= ${extent[3]}`,
+ ];
+
+ return (
+
+
+ {items?.length ? (
+
+
+ {/* ==== TABLE HEADER ==== */}
+
+
+ {state.metadata?.fieldsets?.[0]?.fields?.map(
+ (meta) =>
+ state.metadata.properties[meta].tableType ===
+ 'Table header' && (
+
+ {state.metadata.properties[meta].title}
+
+ ),
+ )}
+
+
+
+ {/* ==== TABLE BODY ==== */}
+
+ {items?.map((item, trIndex) => (
+
+ {/* ==== TABLE ROW ====*/}
+
+ {state.metadata?.fieldsets?.[0]?.fields?.map(
+ (meta, cellIndex) => {
+ if (
+ state.metadata.properties[meta].tableType ===
+ 'Table header'
+ ) {
+ const dataType =
+ state.metadata.properties[meta].dataType;
+ const show = state.metadata.properties[meta].show;
+
+ return (
+
+ {components[`${dataType}_${show}`]
+ ? components[`${dataType}_${show}`](
+ state.metadata.properties[meta],
+ meta,
+ item,
+ props,
+ )
+ : components.default(
+ state.metadata.properties[meta],
+ meta,
+ item,
+ props,
+ )}
+
+ );
+ }
+ return null;
+ },
+ )}
+
+
+
+
+ {/* ==== TABLE HIDDEN ROW ==== */}
+
+
+
+
+ {props.data?.hiddenRowTypes?.value
+ ?.filter((type) => type !== 'Action')
+ .map((type) => (
+
+ {type !== 'Action' && (
+
{type}
+ )}
+
+ {state.metadata?.fieldsets?.[0]?.fields?.map(
+ (meta) => {
+ if (
+ state.metadata.properties[meta]
+ .tableType === 'Hidden row' &&
+ state.metadata.properties[meta]
+ .hiddenRowType === type
+ ) {
+ const dataType =
+ state.metadata.properties[meta]
+ .dataType;
+ const show =
+ state.metadata.properties[meta]
+ .show;
+
+ return (
+
+ {components[`${dataType}_${show}`]
+ ? components[
+ `${dataType}_${show}`
+ ](
+ state.metadata.properties[
+ meta
+ ],
+ meta,
+ item,
+ props,
+ )
+ : components.default(
+ state.metadata.properties[
+ meta
+ ],
+ meta,
+ item,
+ props,
+ )}
+
+ );
+ }
+ return null;
+ },
+ )}
+
+
+ ))}
+
+
+ {props.data?.hiddenRowTypes?.value
+ ?.filter((type) => type === 'Action')
+ .map((type) => (
+
+
+ {state.metadata?.fieldsets?.[0]?.fields?.map(
+ (meta) => {
+ if (
+ state.metadata.properties[meta]
+ .tableType === 'Hidden row' &&
+ state.metadata.properties[meta]
+ .hiddenRowType === type
+ ) {
+ const dataType =
+ state.metadata.properties[meta]
+ .dataType;
+ const show =
+ state.metadata.properties[meta]
+ .show;
+
+ return (
+
+ {components[`${dataType}_${show}`]
+ ? components[
+ `${dataType}_${show}`
+ ](
+ state.metadata.properties[
+ meta
+ ],
+ meta,
+ item,
+ props,
+ )
+ : components.default(
+ state.metadata.properties[
+ meta
+ ],
+ meta,
+ item,
+ props,
+ )}
+
+ );
+ }
+ return null;
+ },
+ )}
+
+
+ ))}
+
+
+
+
+
+ ))}
+
+ {/* ==== TABLE FOOTER ==== */}
+
+
+
+ {
+ setState({
+ ...state,
+ pagination: {
+ ...state.pagination,
+ activePage: pagination.activePage,
+ },
+ selectedItemIndex: -1,
+ });
+ }}
+ totalPages={Math.ceil(totalItems / itemsPerPage)}
+ firstItem={null}
+ lastItem={null}
+ />
+
+
+
+
+
+ ) : (
+
+ )}
+
+
+ European Environment Agency
+
+
+ );
+};
+
+export default compose(
+ connect(
+ (state, props) => ({
+ discodata_query: state.discodata_query,
+ discodata_resources: state.discodata_resources,
+ }),
+ { setQueryParam },
+ ),
+)(View);
diff --git a/src/localconfig.js b/src/localconfig.js
index 2a26dc5..663fbc4 100644
--- a/src/localconfig.js
+++ b/src/localconfig.js
@@ -44,6 +44,9 @@ import DummyBlockEdit from '~/components/manage/Blocks/DummyBlock/Edit';
import DummyBlockView from '~/components/manage/Blocks/DummyBlock/View';
// Discodata components
+import DiscodataTableBlockEdit from '~/components/manage/Blocks/DiscodataTableBlock/Edit';
+import DiscodataTableBlockView from '~/components/manage/Blocks/DiscodataTableBlock/View';
+
import DiscodataComponentsBlockEdit from '~/components/manage/Blocks/DiscodataComponentsBlock/Edit';
import DiscodataComponentsBlockView from '~/components/manage/Blocks/DiscodataComponentsBlock/View';
@@ -224,6 +227,15 @@ export function applyConfig(voltoConfig) {
// DISCODATA COMPONENTS
+ config.blocks.blocksConfig.discodata_components_table_block = {
+ id: 'discodata_components_table_block',
+ title: 'Table block',
+ group: 'discodata_components',
+ view: DiscodataTableBlockView,
+ edit: DiscodataTableBlockEdit,
+ icon: packSVG,
+ };
+
config.blocks.blocksConfig.discodata_components_text = {
id: 'discodata_components_text',
title: 'Text',