{"id":13568042,"url":"https://github.com/eea/volto-datablocks","last_synced_at":"2026-03-07T18:04:30.057Z","repository":{"id":36137934,"uuid":"221726728","full_name":"eea/volto-datablocks","owner":"eea","description":"Volto extension to provide remote data powered blocks. Depends on eea.restapi","archived":false,"fork":false,"pushed_at":"2026-03-03T12:13:32.000Z","size":7870,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":35,"default_branch":"master","last_synced_at":"2026-03-03T13:41:40.353Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eea.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-11-14T15:16:32.000Z","updated_at":"2026-03-03T12:12:10.000Z","dependencies_parsed_at":"2024-02-06T14:12:49.517Z","dependency_job_id":"1c1ca489-1b28-4143-964a-955a9bd81de4","html_url":"https://github.com/eea/volto-datablocks","commit_stats":{"total_commits":744,"total_committers":28,"mean_commits":"26.571428571428573","dds":0.7163978494623655,"last_synced_commit":"36732da736ad54a8d6bf14b9c7c45eee67558574"},"previous_names":[],"tags_count":102,"template":false,"template_full_name":null,"purl":"pkg:github/eea/volto-datablocks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eea%2Fvolto-datablocks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eea%2Fvolto-datablocks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eea%2Fvolto-datablocks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eea%2Fvolto-datablocks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eea","download_url":"https://codeload.github.com/eea/volto-datablocks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eea%2Fvolto-datablocks/sbom","scorecard":{"id":367796,"data":{"date":"2025-08-11","repo":{"name":"github.com/eea/volto-datablocks","commit":"00c96beeee6ea01eb51dc464ad167a4a4ce206eb"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":5.5,"checks":[{"name":"Code-Review","score":7,"reason":"Found 6/8 approved changesets -- score normalized to 7","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:3","Info:   0 out of   1 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T12:16:38.018Z","repository_id":36137934,"created_at":"2025-08-18T12:16:38.018Z","updated_at":"2025-08-18T12:16:38.018Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30225462,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T17:00:40.062Z","status":"ssl_error","status_checked_at":"2026-03-07T17:00:39.026Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T14:00:19.293Z","updated_at":"2026-03-07T18:04:30.051Z","avatar_url":"https://github.com/eea.png","language":"JavaScript","funding_links":[],"categories":["Add-ons"],"sub_categories":[],"readme":"# Data-connected Volto components\n\n[![Releases](https://img.shields.io/github/v/release/eea/volto-datablocks)](https://github.com/eea/volto-datablocks/releases)\n\n[![Pipeline](https://ci.eionet.europa.eu/buildStatus/icon?job=volto-addons%2Fvolto-datablocks%2Fmaster\u0026subject=master)](https://ci.eionet.europa.eu/view/Github/job/volto-addons/job/volto-datablocks/job/master/display/redirect)\n[![Lines of Code](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-datablocks\u0026metric=ncloc)](https://sonarqube.eea.europa.eu/dashboard?id=volto-datablocks)\n[![Coverage](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-datablocks\u0026metric=coverage)](https://sonarqube.eea.europa.eu/dashboard?id=volto-datablocks)\n[![Bugs](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-datablocks\u0026metric=bugs)](https://sonarqube.eea.europa.eu/dashboard?id=volto-datablocks)\n[![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-datablocks\u0026metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-datablocks)\n\n[![Pipeline](https://ci.eionet.europa.eu/buildStatus/icon?job=volto-addons%2Fvolto-datablocks%2Fdevelop\u0026subject=develop)](https://ci.eionet.europa.eu/view/Github/job/volto-addons/job/volto-datablocks/job/develop/display/redirect)\n[![Lines of Code](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-datablocks\u0026branch=develop\u0026metric=ncloc)](https://sonarqube.eea.europa.eu/dashboard?id=volto-datablocks\u0026branch=develop)\n[![Coverage](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-datablocks\u0026branch=develop\u0026metric=coverage)](https://sonarqube.eea.europa.eu/dashboard?id=volto-datablocks\u0026branch=develop)\n[![Bugs](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-datablocks\u0026branch=develop\u0026metric=bugs)](https://sonarqube.eea.europa.eu/dashboard?id=volto-datablocks\u0026branch=develop)\n[![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-datablocks\u0026branch=develop\u0026metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-datablocks\u0026branch=develop)\n\n[Volto](https://github.com/plone/volto) add-on\n\nVolto-datablocks is an addon that has various blocks and utilities to provide \"data-connected\" components in volto websites.\n\n**This add-on requires `eea.docker.plonesaas@5.2.4-66`.**\n\n## Concepts and terminology\n\n- data-connected component: is a component or a block that displays information coming from outside sources; For example a table would get its data from a REST api server (discodata.eea.europa.eu) and show it as desired\n- connector / provider: is a dexterity content type characterized by:\n  - title: acts as the name of the connector and it used by plone to compose the short-name or route through which we can query the connector\n  - endpoint_url: the url to the REST api server (ex. discodata.eea.europa.eu)\n  - sql_query: the sql that will be executed on the REST api server\n  - parameters (optional): a list of parameters (keys) through which we can filter the data fetched by the connector\n  - required_parameters (optional): a list of required parameters which if not satisfed the connector will return empty data\n  - collate (optional)\n  - readme (optional)\n- query string parameters or parameters from url; Ex. `https://frontend/home?db_version=latest\u0026p=1\u0026nrOfHits=10`\n- data query are another type of parameters that are composed internally using redux\n- connected data parameters is the global object that stores data queries; we will get more into this later\n\n## Workflow\n\nA data-connected component will use a connector through which it gets its data.\n\n[eea.api.dataconnector](https://github.com/eea/eea.api.dataconnector) is a plone add-on that expose an api through which a connector will run a query and fetch some data.\n\n### How to use eea.api.dataconnector\n\neea.api.dataconnector expose `/@connector-data` through which we can make `POST` requests to get the data of a connector. We can pass some data to the request:\n\n- `form` - parameters from url\n- `data_query` - parameters from connected data parameters\n\nYou can use this api only over connectors.\n\nExample:\n\nLet's say that we have the following connector added into connectors folder:\n\n```\ntitle: Forests per capita\nendpoint_url: https://discodata.eea.europa.eu/sql\nsql_query: SELECT * FROM [FISE].[latest].[v_cnct_forest_per_capita]\nparameters: ['NUTS_CODE']\n```\n\nThe route to the connector will be `https://frontend/connectors/forests-per-capita`\n\nBy making the following request:\n\n```\n\u003e curl --location --request POST 'http://backend/Plone/++api++/connectors/forests-per-capita/@connector-data'\n```\n\nthe sql_query will be executed on specified endpoint_url (discodata) and after data is fetched the response will look like:\n\n```JSON\n{\n   \"@id\": \"https://backend/Plone/connectors/forests-per-capita\",\n   \"data\": {\n      \"metadata\": {...},\n      \"results\": {\n         \"COUNTRY\": [\"Albania\", ...],\n         \"Forest per capita\": [0.39, ...],\n         \"NUTS_CODE\": [\"AL\", ...],\n      }\n   }\n}\n```\n\nWe can filter the data in two ways:\n\n- By updating the sql before it is executed on discodata by adding where statements - this requires parameters property to be specified on the connector\n- By filtering the data after it is fetched from discodata through for loops\n\nObs: both filtering are done on the backend. The response will always contain the filtered data.\n\nIn this case we can filter by `NUTS_CODE`. The request will look like:\n\n```\n\u003e curl --location --request POST 'http://backend/Plone/++api++/connectors/forests-per-capita/@connector-data' \\\n--header 'Content-Type: application/json' \\\n--data '{\n    \"form\": {\n        \"NUTS_CODE\": \"FR\"\n    }\n}'\n```\n\nBecause `NUTS_CODE` is specified in the parameters list of the connector the query will be modified and will look like this:\n\n```sql\nSELECT * FROM FISE.latest.v_cnct_forest_per_capita WHERE NUTS_CODE = 'FR'\n```\n\nSo we get the data from discodata already filtered and the response will look like:\n\n```JSON\n{\n   \"@id\": \"https://backend/Plone/connectors/forests-per-capita\",\n   \"data\": {\n      \"metadata\": {...},\n      \"results\": {\n         \"COUNTRY\": [\"France\"],\n         \"Forest per capita\": [0.23],\n         \"NUTS_CODE\": [\"FR\"],\n      }\n   }\n}\n```\n\nIf we don't have `NUTS_CODE` specified in the parameters list we will still get the data filtered by `NUTS_CODE` but after it is fetched from discodata. So by adding keys to parameters list can dramatically decrease the data usage.\n\nIf we want to set the same parameter but through data_query the request will look like this:\n\n```\n\u003e curl --location --request POST 'http://backend/Plone/++api++/connectors/forests-per-capita/@connector-data' \\\n--header 'Content-Type: application/json' \\\n--data '{\n   \"data_query\": [\n      \"i\": \"NUTS_CODE\"\n      \"o\": \"plone.app.querystring.operation.selection.any\"\n      \"v\": [\"FR\"]\n   ]\n}'\n```\n\nVolto-datablocks offers 4 hooks through which a data-connected component can make requests to a connector:\n\n```\nconnectToProviderData\nconnectToProviderDataUnfiltered\nconnectToMultipleProviders\nconnectToMultipleProvidersUnfiltered\n```\n\nObs: a data-connected component needs to specify a provider_url (the path to the connector) to the hook used to fetch the data. We will get more into this later.\n\n## Operators\n\n### Parameters from url - `form`\n\nAvailable operators:\n\n```\neq          - equal\nne          - not equal\nlike\nnot like\nin\nnin         - not in\ngt          - greater than\ngte         - greater than equal\nlt          - lower than\nlte         - lower than equal\n```\n\nTo specify an operator to a parameter from url you need to use this structure:\n\n```\nsome/path?parameter[operation]=value\n```\n\nFor example if on the homepage we have a data-connected component that uses `/connectors/forests-per-capita` as provider and we want to filter it by multiple `NUTS_CODE` we can set a url parameter using the 'in' operator like:\n\n```\nhttps://frontend/?NUTS_CODE[in]=RO,FR\n```\n\n### Parameters from data_query - `connected_data_parameters`\n\nTo be continued...\n\n## Pagination\n\nTo be continued...\n\n## Features\n\nThere are a few data-connected blocks in this add-on:\n\n### SimpleDataTable\n\nA data-connected table which allows pagination and filtering. It can be customized by implementing a template.\n\n`TODO: tutorial on how to customize and demo`\n\n### DataQueryFilter\n\nA dropdown data-connected component that uses a provider to create a filter for it by a parameter selected from block configuration.\n\n`TODO: demo`\n\n### DottedTableChart\n\n### CustomConnectedBlock\n\n## Usage (for developers)\n\n### How to connect a block to a provider?\n\nAs we said we have 4 hooks, 2 that uses filters and 2 that doesn't use filters. They require you to pass a getConfig function that returns an object. That object needs to have some specific data.\n\nHere is the configuration needed to be passed to each hook:\n\n1. `connectToProviderData`\n\n```javascript\n{\n   provider_url: 'path/to/provider', // mandatory\n   pagination: { // optional\n      enabled: true,\n      itemsPerPage: 5\n   }\n}\n// Obs: provider_url is mandatory and pagination is optional. If pagination is not configured then connectToProviderData will run as if pagination is disabled.\n```\n\n2. `connectToProviderDataUnfiltered`\n\n```javascript\n{\n  provider_url: 'path/to/provider'; // mandatory\n}\n```\n\n3. `connectToMultipleProviders`\n\n```javascript\n{\n   provider: [ // mandatory\n      {\n         provider_url: 'path/to/provider', // mandatory\n         name: 'some name', // optional\n         title: 'some title', // optional\n         data_query: [...some_data_query] // optional\n         has_data_query_by_context: true // optional\n         has_data_query_by_provider: true // optional\n      }\n   ]\n}\n```\n\n4. `connectToMultipleProvidersUnfiltered`\n\n```javascript\n{\n  provider: [\n    // mandatory\n    {\n      provider_url: 'path/to/provider', // mandatory\n      name: 'some name', // optional\n      title: 'some title', // optional\n    },\n  ];\n}\n```\n\nConnecting to multiple providers doesn't allow pagination.\n\nHere is an example on how to use `connectToProviderData`:\n\n```javascript\nimport React from 'react';\nimport { compose } from 'redux';\nimport { connectToProviderData } from '@eeacms/volto-datablocks/hocs';\n\n...\n\nconst View = props =\u003e {\n   ...\n   return \u003cYourComponents /\u003e\n}\n\nexport default compose(\n  connectToProviderData((props) =\u003e {\n    return {\n      provider_url: props.data?.provider_url,\n    };\n  }),\n)(View);\n\n```\n\n## Getting started\n\n### Try volto-datablocks with Docker\n\n      git clone https://github.com/eea/volto-datablocks.git\n      cd volto-datablocks\n      make\n      make start\n\nGo to http://localhost:3000\n\n### Add volto-datablocks to your Volto project\n\n1. Make sure you have a [Plone backend](https://plone.org/download) up-and-running at http://localhost:8080/Plone\n\n   ```Bash\n   docker compose up backend\n   ```\n\n1. Start Volto frontend\n\n* If you already have a volto project, just update `package.json`:\n\n   ```JSON\n   \"addons\": [\n       \"@eeacms/volto-datablocks\"\n   ],\n\n   \"dependencies\": {\n       \"@eeacms/volto-datablocks\": \"*\"\n   }\n   ```\n\n* If not, create one:\n\n   ```\n   npm install -g yo @plone/generator-volto\n   yo @plone/volto my-volto-project --canary --addon @eeacms/volto-datablocks\n   cd my-volto-project\n   ```\n\n1. Install new add-ons and restart Volto:\n\n   ```\n   yarn\n   yarn start\n   ```\n\n1. Go to http://localhost:3000\n\n1. Happy editing!\n\n## Release\n\nSee [RELEASE.md](https://github.com/eea/volto-datablocks/blob/master/RELEASE.md).\n\n## How to contribute\n\nSee [DEVELOP.md](https://github.com/eea/volto-datablocks/blob/master/DEVELOP.md).\n\n## Copyright and license\n\nThe Initial Owner of the Original Code is European Environment Agency (EEA).\nAll Rights Reserved.\n\nSee [LICENSE.md](https://github.com/eea/volto-datablocks/blob/master/LICENSE.md) for details.\n\n## Funding\n\n[European Environment Agency (EU)](http://eea.europa.eu)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feea%2Fvolto-datablocks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feea%2Fvolto-datablocks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feea%2Fvolto-datablocks/lists"}