@eeacms/volto-tableau 8.1.5 → 9.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc.js CHANGED
@@ -16,16 +16,16 @@ if (configFile) {
16
16
  voltoPath = `./${jsConfig.baseUrl}/${pathsConfig['@plone/volto'][0]}`;
17
17
  }
18
18
 
19
- const AddonConfigurationRegistry = require(`${voltoPath}/addon-registry.js`);
20
- const reg = new AddonConfigurationRegistry(projectRootPath);
19
+ const { AddonRegistry } = require('@plone/registry/addon-registry');
20
+ const { registry } = AddonRegistry.init(projectRootPath);
21
21
 
22
22
  // Extends ESlint configuration for adding the aliases to `src` directories in Volto addons
23
- const addonAliases = Object.keys(reg.packages).map((o) => [
23
+ const addonAliases = Object.keys(registry.packages).map((o) => [
24
24
  o,
25
- reg.packages[o].modulePath,
25
+ registry.packages[o].modulePath,
26
26
  ]);
27
27
 
28
- const addonExtenders = reg.getEslintExtenders().map((m) => require(m));
28
+ const addonExtenders = registry.getEslintExtenders().map((m) => require(m));
29
29
 
30
30
  const defaultConfig = {
31
31
  extends: `${voltoPath}/.eslintrc`,
@@ -34,7 +34,7 @@ const defaultConfig = {
34
34
  alias: {
35
35
  map: [
36
36
  ['@plone/volto', '@plone/volto/src'],
37
- ['@plone/volto-slate', '@plone/volto/packages/volto-slate/src'],
37
+ ['@plone/volto-slate', '@plone/volto-slate/src'],
38
38
  ...addonAliases,
39
39
  ['@package', `${__dirname}/src`],
40
40
  ['@root', `${__dirname}/src`],
package/CHANGELOG.md CHANGED
@@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ ### [9.0.1](https://github.com/eea/volto-tableau/compare/9.0.0...9.0.1) - 8 April 2026
8
+
9
+ #### :hammer_and_wrench: Others
10
+
11
+ - test: Fix make test [Alin V. (Claudiu) - [`34446a7`](https://github.com/eea/volto-tableau/commit/34446a71fa6f5715cf797c4c0ca80bed33181d71)]
12
+ ## [9.0.0](https://github.com/eea/volto-tableau/compare/8.1.5...9.0.0) - 25 March 2026
13
+
14
+ #### :rocket: New Features
15
+
16
+ - feat: Volto 18 support - refs #287700 [Alin Voinea - [`9b3e664`](https://github.com/eea/volto-tableau/commit/9b3e664c40418e950816242f95f306399dc527c4)]
17
+
18
+ #### :house: Internal changes
19
+
20
+ - chore: [JENKINSFILE] add package version in sonarqube [valentinab25 - [`929dd7c`](https://github.com/eea/volto-tableau/commit/929dd7cb27faaecf96f133377acf4efcc8e0ca78)]
21
+ - chore: [JENKINSFILE] use sonarqube branches [EEA Jenkins - [`ce94213`](https://github.com/eea/volto-tableau/commit/ce9421395395abfc6ddab7950f9a2c9ffadbfbbe)]
22
+
23
+ #### :hammer_and_wrench: Others
24
+
25
+ - tests: Fix Sonar Qube tags - refs #297339 [Alin Voinea - [`cfbd646`](https://github.com/eea/volto-tableau/commit/cfbd646a9c09cb90f6ffa6a886822e7a4759ba4d)]
7
26
  ### [8.1.5](https://github.com/eea/volto-tableau/compare/8.1.4...8.1.5) - 4 August 2025
8
27
 
9
28
  #### :hammer_and_wrench: Others
package/DEVELOP.md CHANGED
@@ -26,21 +26,20 @@
26
26
 
27
27
  ### Or add @eeacms/volto-tableau to your Volto project
28
28
 
29
- Before starting make sure your development environment is properly set. See [Volto Developer Documentation](https://docs.voltocms.com/getting-started/install/)
29
+ Before starting make sure your development environment is properly set. See the official Plone documentation for [creating a project with Cookieplone](https://6.docs.plone.org/install/create-project-cookieplone.html) and [installing an add-on in development mode in Volto 18 and 19](https://6.docs.plone.org/volto/development/add-ons/install-an-add-on-dev-18.html).
30
30
 
31
- 1. Make sure you have installed `yo`, `@plone/generator-volto` and `mrs-developer`
31
+ For new Volto 18+ projects, use Cookieplone. It includes `mrs-developer` by default.
32
32
 
33
- npm install -g yo @plone/generator-volto mrs-developer
33
+ 1. Create a new Volto project with Cookieplone
34
34
 
35
- 1. Create new volto app
36
-
37
- yo @plone/volto my-volto-project --addon @eeacms/volto-tableau --skip-install
38
- cd my-volto-project
35
+ uvx cookieplone project
36
+ cd project-title
39
37
 
40
38
  1. Add the following to `mrs.developer.json`:
41
39
 
42
40
  {
43
41
  "volto-tableau": {
42
+ "output": "packages",
44
43
  "url": "https://github.com/eea/volto-tableau.git",
45
44
  "package": "@eeacms/volto-tableau",
46
45
  "branch": "develop",
@@ -48,28 +47,31 @@ Before starting make sure your development environment is properly set. See [Vol
48
47
  }
49
48
  }
50
49
 
51
- 1. Install
50
+ 1. Add `@eeacms/volto-tableau` to the `addons` key in your project `volto.config.js`
51
+
52
+ 1. Install or refresh the project setup
52
53
 
53
- make develop
54
- yarn
54
+ make install
55
55
 
56
- 1. Start backend
56
+ 1. Start backend in one terminal
57
57
 
58
- docker run --pull always -it --rm --name plone -p 8080:8080 -e SITE=Plone plone/plone-backend
58
+ make backend-start
59
59
 
60
- ...wait for backend to setup and start - `Ready to handle requests`:
60
+ ...wait for backend to setup and start, ending with `Ready to handle requests`
61
61
 
62
62
  ...you can also check http://localhost:8080/Plone
63
63
 
64
- 1. Start frontend
64
+ 1. Start frontend in a second terminal
65
65
 
66
- yarn start
66
+ make frontend-start
67
67
 
68
68
  1. Go to http://localhost:3000
69
69
 
70
70
  1. Happy hacking!
71
71
 
72
- cd src/addons/volto-tableau/
72
+ cd packages/volto-tableau
73
+
74
+ For legacy Volto 17 projects, keep using the yarn-based workflow from the Volto 17 documentation.
73
75
 
74
76
  ## Cypress
75
77
 
@@ -81,7 +83,7 @@ project where you added `volto-tableau` to `mrs.developer.json`
81
83
  Go to:
82
84
 
83
85
  ```BASH
84
- cd src/addons/volto-tableau/
86
+ cd packages/volto-tableau/
85
87
  ```
86
88
 
87
89
  Start:
package/Dockerfile CHANGED
@@ -1,13 +1,22 @@
1
1
  # syntax=docker/dockerfile:1
2
2
  ARG VOLTO_VERSION
3
- FROM eeacms/frontend-builder:${VOLTO_VERSION}
3
+ FROM plone/frontend-builder:${VOLTO_VERSION}
4
4
 
5
5
  ARG ADDON_NAME
6
6
  ARG ADDON_PATH
7
+ ENV HOST="0.0.0.0"
8
+
9
+ USER root
10
+ RUN apt-get update -q \
11
+ && apt-get install -qy --no-install-recommends \
12
+ chromium libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb \
13
+ && rm -rf /var/lib/apt/lists/*
14
+ USER node
7
15
 
8
16
  COPY --chown=node:node ./ /app/src/addons/${ADDON_PATH}/
9
17
 
10
18
  RUN /setupAddon
19
+ RUN yarn add jest-junit
11
20
  RUN yarn install
12
21
 
13
22
  ENTRYPOINT ["yarn"]
package/Jenkinsfile CHANGED
@@ -1,7 +1,4 @@
1
1
  pipeline {
2
- tools {
3
- jdk 'Java17'
4
- }
5
2
  agent {
6
3
  node { label 'docker-host' }
7
4
  }
@@ -9,12 +6,12 @@ pipeline {
9
6
  environment {
10
7
  GIT_NAME = "volto-tableau"
11
8
  NAMESPACE = "@eeacms"
12
- SONARQUBE_TAGS = "volto.eea.europa.eu,climate-energy.eea.europa.eu,forest.eea.europa.eu,biodiversity.europa.eu,water.europa.eu-freshwater,water.europa.eu-marine,industry.eea.europa.eu,demo-www.eea.europa.eu,www.eea.europa.eu-en,insitu.copernicus.eu"
9
+ SONARQUBE_TAGS = "volto.eea.europa.eu,climate-energy.eea.europa.eu,forest.eea.europa.eu,biodiversity.europa.eu,water.europa.eu-freshwater,water.europa.eu-marine,industry.eea.europa.eu,demo-www.eea.europa.eu,www.eea.europa.eu-en,www.eea.europa.eu,insitu.copernicus.eu"
13
10
  DEPENDENCIES = ""
14
11
  BACKEND_PROFILES = "eea.kitkat:testing"
15
12
  BACKEND_ADDONS = ""
16
- VOLTO = "17"
17
- VOLTO16_BREAKING_CHANGES = "yes"
13
+ CURRENT_VOLTO = "18-yarn"
14
+ PREVIOUS_VOLTO = "17"
18
15
  IMAGE_NAME = BUILD_TAG.toLowerCase()
19
16
  }
20
17
 
@@ -75,12 +72,13 @@ pipeline {
75
72
  }
76
73
  parallel {
77
74
 
78
- stage('Volto 17') {
75
+ // Declarative stage names must stay string literals.
76
+ stage('Volto 18-yarn') {
79
77
  agent { node { label 'docker-1.13'} }
80
78
  stages {
81
79
  stage('Build test image') {
82
80
  steps {
83
- sh '''docker build --pull --build-arg="VOLTO_VERSION=$VOLTO" --build-arg="ADDON_NAME=$NAMESPACE/$GIT_NAME" --build-arg="ADDON_PATH=$GIT_NAME" . -t $IMAGE_NAME-frontend'''
81
+ sh '''docker build --pull --build-arg="VOLTO_VERSION=$CURRENT_VOLTO" --build-arg="ADDON_NAME=$NAMESPACE/$GIT_NAME" --build-arg="ADDON_PATH=$GIT_NAME" . -t $IMAGE_NAME-frontend-current'''
84
82
  }
85
83
  }
86
84
 
@@ -91,9 +89,9 @@ pipeline {
91
89
  }
92
90
  steps {
93
91
  script {
94
- fix_result = sh(script: '''docker run --name="$IMAGE_NAME-fix" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend ci-fix''', returnStatus: true)
95
- sh '''docker cp $IMAGE_NAME-fix:/app/src/addons/$GIT_NAME/src .'''
96
- sh '''docker rm -v $IMAGE_NAME-fix'''
92
+ fix_result = sh(script: '''docker run --name="$IMAGE_NAME-fix-current" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend-current ci-fix''', returnStatus: true)
93
+ sh '''docker cp $IMAGE_NAME-fix-current:/app/src/addons/$GIT_NAME/src .'''
94
+ sh '''docker rm -v $IMAGE_NAME-fix-current'''
97
95
  FOUND_FIX = sh(script: '''git diff | wc -l''', returnStdout: true).trim()
98
96
 
99
97
  if (FOUND_FIX != '0') {
@@ -114,21 +112,21 @@ pipeline {
114
112
  stage('ES lint') {
115
113
  when { environment name: 'SKIP_TESTS', value: '' }
116
114
  steps {
117
- sh '''docker run --rm --name="$IMAGE_NAME-eslint" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend lint'''
115
+ sh '''docker run --rm --name="$IMAGE_NAME-eslint-current" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend-current lint'''
118
116
  }
119
117
  }
120
118
 
121
119
  stage('Style lint') {
122
120
  when { environment name: 'SKIP_TESTS', value: '' }
123
121
  steps {
124
- sh '''docker run --rm --name="$IMAGE_NAME-stylelint" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend stylelint'''
122
+ sh '''docker run --rm --name="$IMAGE_NAME-stylelint-current" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend-current stylelint'''
125
123
  }
126
124
  }
127
125
 
128
126
  stage('Prettier') {
129
127
  when { environment name: 'SKIP_TESTS', value: '' }
130
128
  steps {
131
- sh '''docker run --rm --name="$IMAGE_NAME-prettier" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend prettier'''
129
+ sh '''docker run --rm --name="$IMAGE_NAME-prettier-current" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend-current prettier'''
132
130
  }
133
131
  }
134
132
  stage('Unit tests') {
@@ -136,25 +134,25 @@ pipeline {
136
134
  steps {
137
135
  script {
138
136
  try {
139
- sh '''docker run --name="$IMAGE_NAME-volto" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend test-ci'''
140
- sh '''rm -rf xunit-reports'''
141
- sh '''mkdir -p xunit-reports'''
142
- sh '''docker cp $IMAGE_NAME-volto:/app/coverage xunit-reports/'''
143
- sh '''docker cp $IMAGE_NAME-volto:/app/junit.xml xunit-reports/'''
137
+ sh '''docker run --name="$IMAGE_NAME-volto-current" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend-current test-ci'''
138
+ sh '''rm -rf xunit-reports-current'''
139
+ sh '''mkdir -p xunit-reports-current'''
140
+ sh '''docker cp $IMAGE_NAME-volto-current:/app/coverage xunit-reports-current/'''
141
+ sh '''docker cp $IMAGE_NAME-volto-current:/app/junit.xml xunit-reports-current/'''
144
142
  publishHTML(target : [
145
143
  allowMissing: false,
146
144
  alwaysLinkToLastBuild: true,
147
145
  keepAll: true,
148
- reportDir: 'xunit-reports/coverage/lcov-report',
146
+ reportDir: 'xunit-reports-current/coverage/lcov-report',
149
147
  reportFiles: 'index.html',
150
148
  reportName: 'UTCoverage',
151
149
  reportTitles: 'Unit Tests Code Coverage'
152
150
  ])
153
151
  } finally {
154
152
  catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') {
155
- junit testResults: 'xunit-reports/junit.xml', allowEmptyResults: true
153
+ junit testResults: 'xunit-reports-current/junit.xml', allowEmptyResults: true
156
154
  }
157
- sh script: '''docker rm -v $IMAGE_NAME-volto''', returnStatus: true
155
+ sh script: '''docker rm -v $IMAGE_NAME-volto-current''', returnStatus: true
158
156
  }
159
157
  }
160
158
  }
@@ -165,52 +163,52 @@ pipeline {
165
163
  steps {
166
164
  script {
167
165
  try {
168
- sh '''docker run --pull always --rm -d --name="$IMAGE_NAME-plone" -e SITE="Plone" -e PROFILES="$BACKEND_PROFILES" -e ADDONS="$BACKEND_ADDONS" eeacms/plone-backend'''
169
- sh '''docker run -d --shm-size=4g --link $IMAGE_NAME-plone:plone --name="$IMAGE_NAME-cypress" -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend start-ci'''
170
- frontend = sh script:'''docker exec --workdir=/app/src/addons/${GIT_NAME} $IMAGE_NAME-cypress make check-ci''', returnStatus: true
166
+ sh '''docker run --pull always --rm -d --name="$IMAGE_NAME-plone-current" -e SITE="Plone" -e PROFILES="$BACKEND_PROFILES" -e ADDONS="$BACKEND_ADDONS" eeacms/plone-backend'''
167
+ sh '''docker run -d --shm-size=4g --link $IMAGE_NAME-plone-current:plone --name="$IMAGE_NAME-cypress-current" -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend-current start-ci'''
168
+ frontend = sh script:'''docker exec --workdir=/app/src/addons/${GIT_NAME} $IMAGE_NAME-cypress-current make check-ci''', returnStatus: true
171
169
  if ( frontend != 0 ) {
172
- sh '''docker logs $IMAGE_NAME-cypress; exit 1'''
170
+ sh '''docker logs $IMAGE_NAME-cypress-current; exit 1'''
173
171
  }
174
172
 
175
- sh '''timeout -s 9 1800 docker exec --workdir=/app/src/addons/${GIT_NAME} $IMAGE_NAME-cypress make cypress-ci'''
173
+ sh '''timeout -s 9 1800 docker exec --workdir=/app/src/addons/${GIT_NAME} $IMAGE_NAME-cypress-current make cypress-ci'''
176
174
  } finally {
177
175
  try {
178
176
  if ( frontend == 0 ) {
179
- sh '''rm -rf cypress-videos cypress-results cypress-coverage cypress-screenshots'''
180
- sh '''mkdir -p cypress-videos cypress-results cypress-coverage cypress-screenshots'''
181
- videos = sh script: '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/videos cypress-videos/''', returnStatus: true
182
- sh '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/reports cypress-results/'''
183
- screenshots = sh script: '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/cypress/screenshots cypress-screenshots''', returnStatus: true
177
+ sh '''rm -rf cypress-videos-current cypress-results-current cypress-coverage-current cypress-screenshots-current'''
178
+ sh '''mkdir -p cypress-videos-current cypress-results-current cypress-coverage-current cypress-screenshots-current'''
179
+ videos = sh script: '''docker cp $IMAGE_NAME-cypress-current:/app/src/addons/$GIT_NAME/cypress/videos cypress-videos-current/''', returnStatus: true
180
+ sh '''docker cp $IMAGE_NAME-cypress-current:/app/src/addons/$GIT_NAME/cypress/reports cypress-results-current/'''
181
+ screenshots = sh script: '''docker cp $IMAGE_NAME-cypress-current:/app/src/addons/$GIT_NAME/cypress/screenshots cypress-screenshots-current''', returnStatus: true
184
182
 
185
- archiveArtifacts artifacts: 'cypress-screenshots/**', fingerprint: true, allowEmptyArchive: true
183
+ archiveArtifacts artifacts: 'cypress-screenshots-current/**', fingerprint: true, allowEmptyArchive: true
186
184
 
187
- coverage = sh script: '''docker cp $IMAGE_NAME-cypress:/app/src/addons/$GIT_NAME/coverage cypress-coverage''', returnStatus: true
185
+ coverage = sh script: '''docker cp $IMAGE_NAME-cypress-current:/app/src/addons/$GIT_NAME/coverage cypress-coverage-current''', returnStatus: true
188
186
 
189
187
  if ( coverage == 0 ) {
190
188
  publishHTML(target : [allowMissing: false,
191
189
  alwaysLinkToLastBuild: true,
192
190
  keepAll: true,
193
- reportDir: 'cypress-coverage/coverage/lcov-report',
191
+ reportDir: 'cypress-coverage-current/coverage/lcov-report',
194
192
  reportFiles: 'index.html',
195
193
  reportName: 'CypressCoverage',
196
194
  reportTitles: 'Integration Tests Code Coverage'])
197
195
  }
198
196
  if ( videos == 0 ) {
199
- sh '''for file in $(find cypress-results -name *.xml); do if [ $(grep -E 'failures="[1-9].*"' $file | wc -l) -eq 0 ]; then testname=$(grep -E 'file=.*failures="0"' $file | sed 's#.* file=".*\\/\\(.*\\.[jsxt]\\+\\)" time.*#\\1#' ); rm -f cypress-videos/videos/$testname.mp4; fi; done'''
200
- archiveArtifacts artifacts: 'cypress-videos/**/*.mp4', fingerprint: true, allowEmptyArchive: true
197
+ sh '''for file in $(find cypress-results-current -name *.xml); do if [ $(grep -E 'failures="[1-9].*"' $file | wc -l) -eq 0 ]; then testname=$(grep -E 'file=.*failures="0"' $file | sed 's#.* file=".*\\/\\(.*\\.[jsxt]\\+\\)" time.*#\\1#' ); rm -f cypress-videos-current/videos/$testname.mp4; fi; done'''
198
+ archiveArtifacts artifacts: 'cypress-videos-current/**/*.mp4', fingerprint: true, allowEmptyArchive: true
201
199
  }
202
200
  }
203
201
  } finally {
204
202
  catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') {
205
- junit testResults: 'cypress-results/**/*.xml', allowEmptyResults: true
203
+ junit testResults: 'cypress-results-current/**/*.xml', allowEmptyResults: true
206
204
  }
207
205
  catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') {
208
- sh '''docker logs $IMAGE_NAME-cypress'''
206
+ sh '''docker logs $IMAGE_NAME-cypress-current'''
209
207
  }
210
- sh script: "docker stop $IMAGE_NAME-cypress", returnStatus: true
211
- sh script: "docker stop $IMAGE_NAME-plone", returnStatus: true
212
- sh script: "docker rm -v $IMAGE_NAME-plone", returnStatus: true
213
- sh script: "docker rm -v $IMAGE_NAME-cypress", returnStatus: true
208
+ sh script: "docker stop $IMAGE_NAME-cypress-current", returnStatus: true
209
+ sh script: "docker stop $IMAGE_NAME-plone-current", returnStatus: true
210
+ sh script: "docker rm -v $IMAGE_NAME-plone-current", returnStatus: true
211
+ sh script: "docker rm -v $IMAGE_NAME-cypress-current", returnStatus: true
214
212
  }
215
213
  }
216
214
  }
@@ -242,11 +240,17 @@ pipeline {
242
240
  script {
243
241
  def scannerHome = tool 'SonarQubeScanner'
244
242
  def nodeJS = tool 'NodeJS'
243
+ if (env.CHANGE_ID) {
244
+ env.sonarParams = " -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.key=${env.CHANGE_ID} "
245
+ }
246
+ else {
247
+ env.sonarParams = " -Dsonar.branch.name=${env.BRANCH_NAME}"
248
+ }
245
249
  withSonarQubeEnv('Sonarqube') {
246
- sh '''sed -i "s#/app/src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info'''
247
- sh '''sed -i "s#src/addons/${GIT_NAME}/##g" xunit-reports/coverage/lcov.info'''
248
- sh "export PATH=${scannerHome}/bin:${nodeJS}/bin:$PATH; sonar-scanner -Dsonar.javascript.lcov.reportPaths=./xunit-reports/coverage/lcov.info,./cypress-coverage/coverage/lcov.info -Dsonar.sources=./src -Dsonar.projectKey=$GIT_NAME-$BRANCH_NAME -Dsonar.projectVersion=$BRANCH_NAME-$BUILD_NUMBER"
249
- sh '''try=5; while [ \$try -gt 0 ]; do curl -s -XPOST -u "${SONAR_AUTH_TOKEN}:" "${SONAR_HOST_URL}api/project_tags/set?project=${GIT_NAME}-${BRANCH_NAME}&tags=${SONARQUBE_TAGS},${BRANCH_NAME}" > set_tags_result; if [ \$(grep -ic error set_tags_result ) -eq 0 ]; then try=0; else cat set_tags_result; echo "... Will retry"; sleep 15; try=\$(( \$try - 1 )); fi; done'''
250
+ sh '''sed -i "s#/app/src/addons/${GIT_NAME}/##g" xunit-reports-current/coverage/lcov.info'''
251
+ sh '''sed -i "s#src/addons/${GIT_NAME}/##g" xunit-reports-current/coverage/lcov.info'''
252
+ sh "export PATH=${scannerHome}/bin:${nodeJS}/bin:$PATH; sonar-scanner -Dsonar.javascript.lcov.reportPaths=./xunit-reports-current/coverage/lcov.info,./cypress-coverage-current/coverage/lcov.info -Dsonar.sources=./src -Dsonar.projectKey=$GIT_NAME -Dsonar.projectName=$GIT_NAME -Dsonar.projectVersion=\$(jq -r '.version' package.json) ${env.sonarParams}"
253
+ sh '''try=5; while [ \$try -gt 0 ]; do curl -s -XPOST -u "${SONAR_AUTH_TOKEN}:" "${SONAR_HOST_URL}api/project_tags/set?project=${GIT_NAME}&tags=${SONARQUBE_TAGS}" > set_tags_result; if [ \$(grep -ic error set_tags_result ) -eq 0 ]; then try=0; else cat set_tags_result; echo "... Will retry"; sleep 15; try=\$(( \$try - 1 )); fi; done'''
250
254
  }
251
255
  }
252
256
  }
@@ -256,75 +260,77 @@ pipeline {
256
260
  }
257
261
  }
258
262
 
259
- stage('Volto 16') {
263
+ stage('Volto 17') {
260
264
  agent { node { label 'integration'} }
261
- when {
262
- environment name: 'SKIP_TESTS', value: ''
263
- not { environment name: 'VOLTO16_BREAKING_CHANGES', value: 'yes' }
265
+ when {
266
+ allOf {
267
+ environment name: 'SKIP_TESTS', value: ''
268
+ expression { return !!env.PREVIOUS_VOLTO?.trim() }
269
+ }
264
270
  }
265
271
  stages {
266
272
  stage('Build test image') {
267
273
  steps {
268
- sh '''docker build --pull --build-arg="VOLTO_VERSION=16" --build-arg="ADDON_NAME=$NAMESPACE/$GIT_NAME" --build-arg="ADDON_PATH=$GIT_NAME" . -t $IMAGE_NAME-frontend16'''
274
+ sh '''docker build --pull --build-arg="VOLTO_VERSION=$PREVIOUS_VOLTO" --build-arg="ADDON_NAME=$NAMESPACE/$GIT_NAME" --build-arg="ADDON_PATH=$GIT_NAME" . -t $IMAGE_NAME-frontend-previous'''
269
275
  }
270
276
  }
271
277
 
272
- stage('Unit tests Volto 16') {
278
+ stage('Unit tests') {
273
279
  steps {
274
280
  script {
275
281
  try {
276
- sh '''docker run --name="$IMAGE_NAME-volto16" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend16 test-ci'''
277
- sh '''rm -rf xunit-reports16'''
278
- sh '''mkdir -p xunit-reports16'''
279
- sh '''docker cp $IMAGE_NAME-volto16:/app/junit.xml xunit-reports16/'''
282
+ sh '''docker run --name="$IMAGE_NAME-volto-previous" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend-previous test-ci'''
283
+ sh '''rm -rf xunit-reports-previous'''
284
+ sh '''mkdir -p xunit-reports-previous'''
285
+ sh '''docker cp $IMAGE_NAME-volto-previous:/app/junit.xml xunit-reports-previous/'''
280
286
  } finally {
281
287
  catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') {
282
- junit testResults: 'xunit-reports16/junit.xml', allowEmptyResults: true
288
+ junit testResults: 'xunit-reports-previous/junit.xml', allowEmptyResults: true
283
289
  }
284
- sh script: '''docker rm -v $IMAGE_NAME-volto16''', returnStatus: true
290
+ sh script: '''docker rm -v $IMAGE_NAME-volto-previous''', returnStatus: true
285
291
  }
286
292
  }
287
293
  }
288
294
  }
289
295
 
290
- stage('Integration tests Volto 16') {
296
+ stage('Integration tests') {
291
297
  steps {
292
298
  script {
293
299
  try {
294
- sh '''docker run --pull always --rm -d --name="$IMAGE_NAME-plone16" -e SITE="Plone" -e PROFILES="$BACKEND_PROFILES" -e ADDONS="$BACKEND_ADDONS" eeacms/plone-backend'''
295
- sh '''docker run -d --shm-size=4g --link $IMAGE_NAME-plone16:plone --name="$IMAGE_NAME-cypress16" -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend16 start-ci'''
296
- frontend = sh script:'''docker exec --workdir=/app/src/addons/${GIT_NAME} $IMAGE_NAME-cypress16 make check-ci''', returnStatus: true
300
+ sh '''docker run --pull always --rm -d --name="$IMAGE_NAME-plone-previous" -e SITE="Plone" -e PROFILES="$BACKEND_PROFILES" -e ADDONS="$BACKEND_ADDONS" eeacms/plone-backend'''
301
+ sh '''docker run -d --shm-size=4g --link $IMAGE_NAME-plone-previous:plone --name="$IMAGE_NAME-cypress-previous" -e "RAZZLE_INTERNAL_API_PATH=http://plone:8080/Plone" --entrypoint=make --workdir=/app/src/addons/$GIT_NAME $IMAGE_NAME-frontend-previous start-ci'''
302
+ frontend = sh script:'''docker exec --workdir=/app/src/addons/${GIT_NAME} $IMAGE_NAME-cypress-previous make check-ci''', returnStatus: true
297
303
  if ( frontend != 0 ) {
298
- sh '''docker logs $IMAGE_NAME-cypress16; exit 1'''
304
+ sh '''docker logs $IMAGE_NAME-cypress-previous; exit 1'''
299
305
  }
300
- sh '''timeout -s 9 1800 docker exec --workdir=/app/src/addons/${GIT_NAME} $IMAGE_NAME-cypress16 make cypress-ci'''
306
+ sh '''timeout -s 9 1800 docker exec --workdir=/app/src/addons/${GIT_NAME} $IMAGE_NAME-cypress-previous make cypress-ci'''
301
307
  } finally {
302
308
  try {
303
309
  if ( frontend == 0 ) {
304
- sh '''rm -rf cypress-videos16 cypress-results16 cypress-coverage16 cypress-screenshots16'''
305
- sh '''mkdir -p cypress-videos16 cypress-results16 cypress-coverage16 cypress-screenshots16'''
306
- videos = sh script: '''docker cp $IMAGE_NAME-cypress16:/app/src/addons/$GIT_NAME/cypress/videos cypress-videos16/''', returnStatus: true
307
- sh '''docker cp $IMAGE_NAME-cypress16:/app/src/addons/$GIT_NAME/cypress/reports cypress-results16/'''
308
- screenshots = sh script: '''docker cp $IMAGE_NAME-cypress16:/app/src/addons/$GIT_NAME/cypress/screenshots cypress-screenshots16''', returnStatus: true
310
+ sh '''rm -rf cypress-videos-previous cypress-results-previous cypress-coverage-previous cypress-screenshots-previous'''
311
+ sh '''mkdir -p cypress-videos-previous cypress-results-previous cypress-coverage-previous cypress-screenshots-previous'''
312
+ videos = sh script: '''docker cp $IMAGE_NAME-cypress-previous:/app/src/addons/$GIT_NAME/cypress/videos cypress-videos-previous/''', returnStatus: true
313
+ sh '''docker cp $IMAGE_NAME-cypress-previous:/app/src/addons/$GIT_NAME/cypress/reports cypress-results-previous/'''
314
+ screenshots = sh script: '''docker cp $IMAGE_NAME-cypress-previous:/app/src/addons/$GIT_NAME/cypress/screenshots cypress-screenshots-previous''', returnStatus: true
309
315
 
310
- archiveArtifacts artifacts: 'cypress-screenshots16/**', fingerprint: true, allowEmptyArchive: true
316
+ archiveArtifacts artifacts: 'cypress-screenshots-previous/**', fingerprint: true, allowEmptyArchive: true
311
317
 
312
318
  if ( videos == 0 ) {
313
- sh '''for file in $(find cypress-results16 -name *.xml); do if [ $(grep -E 'failures="[1-9].*"' $file | wc -l) -eq 0 ]; then testname=$(grep -E 'file=.*failures="0"' $file | sed 's#.* file=".*\\/\\(.*\\.[jsxt]\\+\\)" time.*#\\1#' ); rm -f cypress-videos16/videos/$testname.mp4; fi; done'''
314
- archiveArtifacts artifacts: 'cypress-videos16/**/*.mp4', fingerprint: true, allowEmptyArchive: true
319
+ sh '''for file in $(find cypress-results-previous -name *.xml); do if [ $(grep -E 'failures="[1-9].*"' $file | wc -l) -eq 0 ]; then testname=$(grep -E 'file=.*failures="0"' $file | sed 's#.* file=".*\\/\\(.*\\.[jsxt]\\+\\)" time.*#\\1#' ); rm -f cypress-videos-previous/videos/$testname.mp4; fi; done'''
320
+ archiveArtifacts artifacts: 'cypress-videos-previous/**/*.mp4', fingerprint: true, allowEmptyArchive: true
315
321
  }
316
322
  }
317
323
  } finally {
318
324
  catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') {
319
- junit testResults: 'cypress-results16/**/*.xml', allowEmptyResults: true
325
+ junit testResults: 'cypress-results-previous/**/*.xml', allowEmptyResults: true
320
326
  }
321
327
  catchError(buildResult: 'SUCCESS', stageResult: 'SUCCESS') {
322
- sh '''docker logs $IMAGE_NAME-cypress16'''
328
+ sh '''docker logs $IMAGE_NAME-cypress-previous'''
323
329
  }
324
- sh script: "docker stop $IMAGE_NAME-cypress16", returnStatus: true
325
- sh script: "docker stop $IMAGE_NAME-plone16", returnStatus: true
326
- sh script: "docker rm -v $IMAGE_NAME-plone16", returnStatus: true
327
- sh script: "docker rm -v $IMAGE_NAME-cypress16", returnStatus: true
330
+ sh script: "docker stop $IMAGE_NAME-cypress-previous", returnStatus: true
331
+ sh script: "docker stop $IMAGE_NAME-plone-previous", returnStatus: true
332
+ sh script: "docker rm -v $IMAGE_NAME-plone-previous", returnStatus: true
333
+ sh script: "docker rm -v $IMAGE_NAME-cypress-previous", returnStatus: true
328
334
  }
329
335
  }
330
336
  }
@@ -336,8 +342,8 @@ pipeline {
336
342
  }
337
343
  post {
338
344
  always {
339
- sh script: "docker rmi $IMAGE_NAME-frontend", returnStatus: true
340
- sh script: "docker rmi $IMAGE_NAME-frontend16", returnStatus: true
345
+ sh script: "docker rmi $IMAGE_NAME-frontend-current", returnStatus: true
346
+ sh script: "docker rmi $IMAGE_NAME-frontend-previous", returnStatus: true
341
347
  }
342
348
  }
343
349
  }
@@ -363,7 +369,7 @@ pipeline {
363
369
  script {
364
370
  sh '''echo "Error" > checkresult.txt'''
365
371
  catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
366
- sh '''set -o pipefail; docker run -i --rm --pull always --name="$IMAGE_NAME-gitflow-sn" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_NAME="$GIT_NAME" eeacms/gitflow /checkSonarqubemaster.sh | grep -v "Found script" | tee checkresult.txt'''
372
+ sh '''set -o pipefail; docker run -i --rm --pull always --name="$IMAGE_NAME-gitflow-sn" -e GIT_BRANCH="$BRANCH_NAME" -e GIT_NAME="$GIT_NAME" eeacms/gitflow /checkSonarqubemasterV2.sh | grep -v "Found script" | tee checkresult.txt'''
367
373
  }
368
374
 
369
375
  publishChecks name: 'SonarQube', title: 'Sonarqube Code Quality Check', summary: 'Quality check on the SonarQube metrics from branch develop, comparing it with the ones from master branch. No bugs are allowed',
package/Makefile CHANGED
@@ -46,7 +46,7 @@ endif
46
46
  DIR=$(shell basename $$(pwd))
47
47
  NODE_MODULES?="../../../node_modules"
48
48
  PLONE_VERSION?=6
49
- VOLTO_VERSION?=17
49
+ VOLTO_VERSION?=18-yarn
50
50
  ADDON_PATH="${DIR}"
51
51
  ADDON_NAME="@eeacms/${ADDON_PATH}"
52
52
  DOCKER_COMPOSE=PLONE_VERSION=${PLONE_VERSION} VOLTO_VERSION=${VOLTO_VERSION} ADDON_NAME=${ADDON_NAME} ADDON_PATH=${ADDON_PATH} docker compose
@@ -90,11 +90,11 @@ cypress-run: ## Run cypress integration tests
90
90
 
91
91
  .PHONY: test
92
92
  test: ## Run jest tests
93
- ${DOCKER_COMPOSE} run -e CI=1 frontend test
93
+ ${DOCKER_COMPOSE} run --no-deps -e CI=1 frontend test
94
94
 
95
95
  .PHONY: test-update
96
96
  test-update: ## Update jest tests snapshots
97
- ${DOCKER_COMPOSE} run -e CI=1 frontend test -u
97
+ ${DOCKER_COMPOSE} run --no-deps -e CI=1 frontend test -u
98
98
 
99
99
  .PHONY: stylelint
100
100
  stylelint: ## Stylelint
package/README.md CHANGED
@@ -3,16 +3,16 @@
3
3
  [![Releases](https://img.shields.io/github/v/release/eea/volto-tableau)](https://github.com/eea/volto-tableau/releases)
4
4
 
5
5
  [![Pipeline](https://ci.eionet.europa.eu/buildStatus/icon?job=volto-addons%2Fvolto-tableau%2Fmaster&subject=master)](https://ci.eionet.europa.eu/view/Github/job/volto-addons/job/volto-tableau/job/master/display/redirect)
6
- [![Lines of Code](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau-master&metric=ncloc)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau-master)
7
- [![Coverage](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau-master&metric=coverage)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau-master)
8
- [![Bugs](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau-master&metric=bugs)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau-master)
9
- [![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau-master&metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau-master)
6
+ [![Lines of Code](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau&metric=ncloc)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau)
7
+ [![Coverage](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau&metric=coverage)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau)
8
+ [![Bugs](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau&metric=bugs)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau)
9
+ [![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau&metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau)
10
10
 
11
11
  [![Pipeline](https://ci.eionet.europa.eu/buildStatus/icon?job=volto-addons%2Fvolto-tableau%2Fdevelop&subject=develop)](https://ci.eionet.europa.eu/view/Github/job/volto-addons/job/volto-tableau/job/develop/display/redirect)
12
- [![Lines of Code](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau-develop&metric=ncloc)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau-develop)
13
- [![Coverage](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau-develop&metric=coverage)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau-develop)
14
- [![Bugs](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau-develop&metric=bugs)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau-develop)
15
- [![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau-develop&metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau-develop)
12
+ [![Lines of Code](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau&branch=develop&metric=ncloc)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau&branch=develop)
13
+ [![Coverage](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau&branch=develop&metric=coverage)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau&branch=develop)
14
+ [![Bugs](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau&branch=develop&metric=bugs)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau&branch=develop)
15
+ [![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-tableau&branch=develop&metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-tableau&branch=develop)
16
16
 
17
17
  [Volto](https://github.com/plone/volto) add-on
18
18
 
@@ -37,6 +37,11 @@ Registers a VisualizationView component for a content type named 'tableau_visual
37
37
 
38
38
  Go to http://localhost:3000
39
39
 
40
+ `make start` now defaults to Volto 18. To run the same setup against Volto 17, use:
41
+
42
+ VOLTO_VERSION=17 make
43
+ VOLTO_VERSION=17 make start
44
+
40
45
  ### Add volto-tableau to your Volto project
41
46
 
42
47
  1. Make sure you have a [Plone backend](https://plone.org/download) up-and-running at http://localhost:8080/Plone
@@ -50,30 +55,39 @@ Go to http://localhost:3000
50
55
  - If you already have a volto project, just update `package.json`:
51
56
 
52
57
  ```JSON
53
- "addons": [
54
- "@eeacms/volto-tableau"
55
- ],
56
-
57
58
  "dependencies": {
58
59
  "@eeacms/volto-tableau": "*"
59
60
  }
60
61
  ```
61
62
 
62
- - If not, create one:
63
+ and `volto.config.js`:
64
+
65
+ ```JavaScript
66
+ const addons = ['@eeacms/volto-tableau'];
67
+ ```
68
+
69
+ - If not, create one with Cookieplone, as recommended by the official Plone documentation for Volto 18+:
63
70
 
64
71
  ```
65
- npm install -g yo @plone/generator-volto
66
- yo @plone/volto my-volto-project --canary --addon @eeacms/volto-tableau
67
- cd my-volto-project
72
+ uvx cookieplone project
73
+ cd project-title
68
74
  ```
69
75
 
70
- 1. Install new add-ons and restart Volto:
76
+ 1. Install or update dependencies, then start the project:
71
77
 
72
78
  ```
73
- yarn
74
- yarn start
79
+ make install
75
80
  ```
76
81
 
82
+ For a Cookieplone project, start the backend and frontend in separate terminals:
83
+
84
+ ```
85
+ make backend-start
86
+ make frontend-start
87
+ ```
88
+
89
+ For a legacy Volto 17 project, install the package with `yarn` and restart the frontend as usual.
90
+
77
91
  1. Go to http://localhost:3000
78
92
 
79
93
  1. Happy editing!
@@ -5,22 +5,24 @@ describe('Blocks Tests', () => {
5
5
  afterEach(slateAfterEach);
6
6
 
7
7
  it('Add Block: Empty', () => {
8
+ const titleSelector = '.block.inner.title [contenteditable="true"]';
9
+
8
10
  // Change page title
9
- cy.clearSlateTitle();
10
- cy.getSlateTitle().type('My Add-on Page');
11
+ cy.get(titleSelector).clear();
12
+ cy.get(titleSelector).type('My Add-on Page');
11
13
 
12
14
  cy.get('.documentFirstHeading').contains('My Add-on Page');
13
15
 
14
- cy.getSlate().click({ force: true });
16
+ cy.get(titleSelector).type('{enter}');
15
17
 
16
18
  // Add block
17
19
  cy.get('.ui.basic.icon.button.block-add-button')
18
20
  .first()
19
21
  .click({ force: true });
20
- cy.get('.blocks-chooser .title').contains('Media').click({ force: true });
21
- cy.get('.content.active.media .button.image')
22
- .contains('Image')
23
- .click({ force: true });
22
+ cy.get(".blocks-chooser .ui.form .field.searchbox input[type='text']").type(
23
+ 'image',
24
+ );
25
+ cy.get('.button.image').contains('Image').click({ force: true });
24
26
 
25
27
  // Save
26
28
  cy.get('#toolbar-save').click({ force: true });
@@ -27,15 +27,22 @@ describe('Blocks Tests', () => {
27
27
  afterEach(slateAfterEach);
28
28
 
29
29
  it('Add Tableau block', () => {
30
- cy.intercept('GET', `/**/*?expand*`, {
31
- statusCode: 200,
32
- }).as('content');
30
+ cy.on('uncaught:exception', (err) => {
31
+ if (err.message?.includes('Not Found')) {
32
+ return false;
33
+ }
34
+ });
35
+
36
+ cy.intercept('GET', `/**/*?expand*`).as('content');
33
37
  // when I add a maps block
34
- cy.addNewBlock('tableau');
38
+ cy.addNewBlock('tableau', true);
35
39
 
36
40
  cy.get(
37
41
  `.sidebar-container .field-wrapper-tableau_vis_url #field-tableau_vis_url`,
38
- ).type('/path/to/dashboard', { force: true });
42
+ ).clear({ force: true });
43
+ cy.get(
44
+ `.sidebar-container .field-wrapper-tableau_vis_url #field-tableau_vis_url`,
45
+ ).type('/cypress/my-page', { force: true });
39
46
  cy.wait('@content');
40
47
  cy.get('#toolbar-save').click({ force: true });
41
48
  cy.intercept('GET', `/**/*?expand*`).as('content');
@@ -387,8 +387,9 @@ Cypress.Commands.add('getSlate', ({ createNewSlate = true } = {}) => {
387
387
  },
388
388
  () => {
389
389
  if (createNewSlate) {
390
- cy.get('.block.inner')
391
- .last()
390
+ cy.get(SLATE_TITLE_SELECTOR)
391
+ .focus()
392
+ .click({ force: true })
392
393
  .type('{moveToEnd}{enter}', { force: true });
393
394
  }
394
395
  slate = cy.get(SLATE_SELECTOR, { timeout: 10000 }).last();
@@ -548,7 +549,10 @@ Cypress.Commands.add('addNewBlock', (blockName, createNewSlate = false) => {
548
549
  Cypress.Commands.add('getSlate', (createNewSlate = false) => {
549
550
  let slate;
550
551
  if (createNewSlate) {
551
- cy.get('.block.inner').last().type('{moveToEnd}{enter}', { force: true });
552
+ cy.get(SLATE_TITLE_SELECTOR)
553
+ .focus()
554
+ .click({ force: true })
555
+ .type('{moveToEnd}{enter}', { force: true });
552
556
  }
553
557
  cy.getIfExists(
554
558
  SLATE_SELECTOR,
@@ -15,7 +15,7 @@ services:
15
15
  args:
16
16
  ADDON_NAME: "${ADDON_NAME}"
17
17
  ADDON_PATH: "${ADDON_PATH}"
18
- VOLTO_VERSION: ${VOLTO_VERSION:-16}
18
+ VOLTO_VERSION: ${VOLTO_VERSION:-18-yarn}
19
19
  ports:
20
20
  - "3000:3000"
21
21
  - "3001:3001"
@@ -1,5 +1,18 @@
1
1
  require('dotenv').config({ path: __dirname + '/.env' })
2
2
 
3
+ const fs = require('fs')
4
+ const path = require('path')
5
+
6
+ const voltoSlatePath = fs.existsSync(
7
+ path.join(__dirname, '../../../node_modules/@plone/volto-slate/src'),
8
+ )
9
+ ? '<rootDir>/node_modules/@plone/volto-slate/src'
10
+ : '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src'
11
+
12
+ const countupPath = fs.existsSync(path.join(__dirname, '../countup/src'))
13
+ ? '<rootDir>/src/addons/countup/src'
14
+ : '<rootDir>/node_modules/@eeacms/countup'
15
+
3
16
  module.exports = {
4
17
  testMatch: ['**/src/addons/**/?(*.)+(spec|test).[jt]s?(x)'],
5
18
  collectCoverageFrom: [
@@ -16,11 +29,10 @@ module.exports = {
16
29
  '@plone/volto-quanta/(.*)$': '<rootDir>/src/addons/volto-quanta/src/$1',
17
30
  '@eeacms/search/(.*)$': '<rootDir>/src/addons/volto-searchlib/searchlib/$1',
18
31
  '@eeacms/search': '<rootDir>/src/addons/volto-searchlib/searchlib',
32
+ '@eeacms/countup$': countupPath,
19
33
  '@eeacms/(.*?)/(.*)$': '<rootDir>/node_modules/@eeacms/$1/src/$2',
20
- '@plone/volto-slate$':
21
- '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src',
22
- '@plone/volto-slate/(.*)$':
23
- '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src/$1',
34
+ '@plone/volto-slate$': voltoSlatePath,
35
+ '@plone/volto-slate/(.*)$': `${voltoSlatePath}/$1`,
24
36
  '~/(.*)$': '<rootDir>/src/$1',
25
37
  'load-volto-addons':
26
38
  '<rootDir>/node_modules/@plone/volto/jest-addons-loader.js',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-tableau",
3
- "version": "8.1.5",
3
+ "version": "9.0.1",
4
4
  "description": "@eeacms/volto-tableau: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { compose } from 'redux';
3
3
  import { injectIntl } from 'react-intl';
4
4
  import BlockDataForm from '@plone/volto/components/manage/Form/BlockDataForm';
5
- import { SidebarPortal } from '@plone/volto/components';
5
+ import SidebarPortal from '@plone/volto/components/manage/Sidebar/SidebarPortal';
6
6
  import getSchema from './schema';
7
7
 
8
8
  import View from './View';
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
- import { render, screen } from '@testing-library/react';
2
+ import { render } from '@testing-library/react';
3
3
  import { Provider } from 'react-intl-redux';
4
4
  import config from '@plone/volto/registry';
5
- import '@testing-library/jest-dom/extend-expect';
5
+ import '@testing-library/jest-dom';
6
6
 
7
7
  import Edit from './Edit';
8
8
  import installEmbedTableau from '.';
@@ -22,14 +22,18 @@ describe('Edit', () => {
22
22
  with_share: true,
23
23
  };
24
24
 
25
- it('should render the component', () => {
25
+ it('should render the component', async () => {
26
+ const sidebar = document.createElement('div');
27
+ sidebar.id = 'sidebar';
28
+ document.body.appendChild(sidebar);
29
+
26
30
  const { container } = render(
27
31
  <Provider store={global.store}>
28
32
  <Edit
29
33
  id="my-tableau"
30
34
  data={data}
31
35
  pathname="/news"
32
- selected={false}
36
+ selected={true}
33
37
  block="1234"
34
38
  index={1}
35
39
  onChangeBlock={() => {}}
@@ -55,60 +59,7 @@ describe('Edit', () => {
55
59
  position: 'relative',
56
60
  });
57
61
  expect(container.querySelector('.tableau-wrapper')).toBeInTheDocument();
58
- expect(container.querySelector('#sidebar')).toBeInTheDocument();
59
- expect(container.querySelector('#sidebar .ui.form')).toBeInTheDocument();
60
- expect(
61
- container.querySelector('#sidebar .ui.form .header.pulled'),
62
- ).toBeInTheDocument();
63
- expect(screen.getByText('Embed Dashboard (Tableau)')).toBeInTheDocument();
64
- expect(
65
- container.querySelector('#blockform-fieldset-default'),
66
- ).toBeInTheDocument();
67
- expect(
68
- container.querySelector(
69
- '#blockform-fieldset-default .ui.segment.form.attached',
70
- ),
71
- ).toBeInTheDocument();
72
- expect(
73
- container.querySelector(
74
- '#mocked-field-tableau_vis_url.mocked-default-widget',
75
- ),
76
- ).toBeInTheDocument();
77
- expect(screen.getByText(/Tableau visualization/)).toBeInTheDocument();
78
- expect(
79
- screen.getByText(
80
- 'When using context query parameters please use the corresponding field name from the Tableau service.',
81
- ),
82
- ).toBeInTheDocument();
83
- expect(
84
- screen.getByText(
85
- 'When using context query parameters please use the corresponding field name from the Tableau service.',
86
- ),
87
- ).toBeInTheDocument();
88
- expect(
89
- container.querySelector(
90
- '#mocked-field-tableau_height.mocked-default-widget',
91
- ),
92
- ).toBeInTheDocument();
93
- expect(
94
- container.querySelector(
95
- 'a[href="https://developer.mozilla.org/en-US/docs/Web/CSS/height"]',
96
- ),
97
- ).toBeInTheDocument();
98
- expect(
99
- container.querySelector('.accordion.ui.fluid.styled.form'),
100
- ).toBeInTheDocument();
101
- expect(
102
- container.querySelector('#blockform-fieldset-toolbar'),
103
- ).toBeInTheDocument();
104
- expect(
105
- container.querySelector('#blockform-fieldset-toolbar .active.title'),
106
- ).toBeInTheDocument();
107
- expect(screen.getByText('Toolbar')).toBeInTheDocument();
108
- expect(screen.getByText(/Show note/)).toBeInTheDocument();
109
- expect(screen.getByText(/Show more info/)).toBeInTheDocument();
110
- expect(screen.getByText(/Show download button/)).toBeInTheDocument();
111
- expect(screen.getByText(/Show share button/)).toBeInTheDocument();
112
- expect(screen.getByText(/Show enlarge button/)).toBeInTheDocument();
62
+ expect(document.querySelector('#sidebar')).toBeInTheDocument();
63
+ sidebar.remove();
113
64
  });
114
65
  });
@@ -2,10 +2,10 @@ import React, { useEffect, useState } from 'react';
2
2
  import { withRouter } from 'react-router';
3
3
  import { connect } from 'react-redux';
4
4
  import { compose } from 'redux';
5
- import { isFunction } from 'lodash';
5
+ import isFunction from 'lodash/isFunction';
6
6
  import { Message } from 'semantic-ui-react';
7
- import { flattenToAppURL } from '@plone/volto/helpers';
8
- import { getContent } from '@plone/volto/actions';
7
+ import { flattenToAppURL } from '@plone/volto/helpers/Url/Url';
8
+ import { getContent } from '@plone/volto/actions/content/content';
9
9
  import PrivacyProtection from '@eeacms/volto-embed/PrivacyProtection/PrivacyProtection';
10
10
  import Tableau from '@eeacms/volto-tableau/Tableau/Tableau';
11
11
  import {
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { render } from '@testing-library/react';
3
3
  import { Provider } from 'react-intl-redux';
4
- import '@testing-library/jest-dom/extend-expect';
4
+ import '@testing-library/jest-dom';
5
5
 
6
6
  import View from './View';
7
7
 
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { SidebarPortal } from '@plone/volto/components';
2
+ import SidebarPortal from '@plone/volto/components/manage/Sidebar/SidebarPortal';
3
3
  import BlockDataForm from '@plone/volto/components/manage/Form/InlineForm';
4
4
  import config from '@plone/volto/registry';
5
5
  import getSchema from './schema';
@@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react';
3
3
  import { Provider } from 'react-redux';
4
4
  import configureStore from 'redux-mock-store';
5
5
  import View from './View';
6
- import '@testing-library/jest-dom/extend-expect';
6
+ import '@testing-library/jest-dom';
7
7
  import Tableau from '@eeacms/volto-tableau/Tableau/Tableau';
8
8
 
9
9
  jest.mock('@eeacms/volto-tableau/Tableau/Tableau', () =>
@@ -1,4 +1,4 @@
1
- import { uniqBy } from 'lodash';
1
+ import uniqBy from 'lodash/uniqBy';
2
2
  import installEmbedTableauVisualization from './EmbedTableauVisualization';
3
3
  import installTableauBlock from './TableauBlock';
4
4
 
@@ -9,26 +9,25 @@ import React, {
9
9
  } from 'react';
10
10
  import { connect } from 'react-redux';
11
11
  import { toast } from 'react-toastify';
12
- import {
13
- isEqual,
14
- isUndefined,
15
- isNaN,
16
- isNumber,
17
- forOwn,
18
- find,
19
- includes,
20
- isArray,
21
- isString,
22
- isInteger,
23
- isBoolean,
24
- toString,
25
- toInteger,
26
- toNumber,
27
- } from 'lodash';
12
+ import isEqual from 'lodash/isEqual';
13
+ import isUndefined from 'lodash/isUndefined';
14
+ import isNaN from 'lodash/isNaN';
15
+ import isNumber from 'lodash/isNumber';
16
+ import forOwn from 'lodash/forOwn';
17
+ import find from 'lodash/find';
18
+ import includes from 'lodash/includes';
19
+ import isArray from 'lodash/isArray';
20
+ import isString from 'lodash/isString';
21
+ import isInteger from 'lodash/isInteger';
22
+ import isBoolean from 'lodash/isBoolean';
23
+ import toString from 'lodash/toString';
24
+ import toInteger from 'lodash/toInteger';
25
+ import toNumber from 'lodash/toNumber';
28
26
  import qs from 'qs';
29
27
  import cx from 'classnames';
30
28
  import { Button } from 'semantic-ui-react';
31
- import { Toast, Icon } from '@plone/volto/components';
29
+ import Toast from '@plone/volto/components/manage/Toast/Toast';
30
+ import Icon from '@plone/volto/components/theme/Icon/Icon';
32
31
  import {
33
32
  FigureNote,
34
33
  Sources,
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { render } from '@testing-library/react';
3
- import '@testing-library/jest-dom/extend-expect';
3
+ import '@testing-library/jest-dom';
4
4
  import { Provider } from 'react-redux';
5
5
  import Tableau from './Tableau';
6
6
 
@@ -1,4 +1,6 @@
1
- import { reduce, isUndefined, isString } from 'lodash';
1
+ import reduce from 'lodash/reduce';
2
+ import isUndefined from 'lodash/isUndefined';
3
+ import isString from 'lodash/isString';
2
4
  import qs from 'query-string';
3
5
  import { pickMetadata } from '@eeacms/volto-embed/helpers';
4
6
 
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from 'react';
2
2
  import { withRouter } from 'react-router';
3
3
  import { Container } from 'semantic-ui-react';
4
- import { hasBlocksData } from '@plone/volto/helpers';
4
+ import { hasBlocksData } from '@plone/volto/helpers/Blocks/Blocks';
5
5
  import config from '@plone/volto/registry';
6
6
  import RenderBlocks from '@plone/volto/components/theme/View/RenderBlocks';
7
7
  import Tableau from '@eeacms/volto-tableau/Tableau/Tableau';
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { render } from '@testing-library/react';
3
- import '@testing-library/jest-dom/extend-expect';
3
+ import '@testing-library/jest-dom';
4
4
  import { Provider } from 'react-redux';
5
5
 
6
6
  import VisualizationView from './VisualizationView';
@@ -7,15 +7,18 @@ import React, { Component } from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import { connect } from 'react-redux';
9
9
  import { compose } from 'redux';
10
- import { map } from 'lodash';
10
+ import map from 'lodash/map';
11
11
  import { defineMessages, injectIntl } from 'react-intl';
12
12
  import {
13
13
  getVocabFromHint,
14
14
  getVocabFromField,
15
15
  getVocabFromItems,
16
- } from '@plone/volto/helpers';
17
- import { FormFieldWrapper } from '@plone/volto/components';
18
- import { getVocabulary, getVocabularyTokenTitle } from '@plone/volto/actions';
16
+ } from '@plone/volto/helpers/Vocabularies/Vocabularies';
17
+ import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
18
+ import {
19
+ getVocabulary,
20
+ getVocabularyTokenTitle,
21
+ } from '@plone/volto/actions/vocabularies/vocabularies';
19
22
  import { normalizeValue } from '@plone/volto/components/manage/Widgets/SelectUtils';
20
23
 
21
24
  import {
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { render } from '@testing-library/react';
3
- import '@testing-library/jest-dom/extend-expect';
3
+ import '@testing-library/jest-dom';
4
4
  import { Provider } from 'react-redux';
5
5
 
6
6
  import VisualizationViewWidget from './VisualizationViewWidget';
@@ -3,10 +3,11 @@ import { withRouter } from 'react-router';
3
3
  import { connect } from 'react-redux';
4
4
  import { injectIntl } from 'react-intl';
5
5
  import { compose } from 'redux';
6
- import { isEqual } from 'lodash';
6
+ import isEqual from 'lodash/isEqual';
7
7
  import { Modal, Button, Grid } from 'semantic-ui-react';
8
8
  import config from '@plone/volto/registry';
9
- import { FormFieldWrapper, InlineForm } from '@plone/volto/components';
9
+ import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
10
+ import InlineForm from '@plone/volto/components/manage/Form/InlineForm';
10
11
  import Tableau from '@eeacms/volto-tableau/Tableau/Tableau';
11
12
  import getSchema from './schema';
12
13
  import {
@@ -17,7 +18,7 @@ import {
17
18
  } from '@eeacms/volto-tableau/Tableau/helpers';
18
19
 
19
20
  import '@eeacms/volto-tableau/less/tableau.less';
20
- import { getBaseUrl } from '@plone/volto/helpers';
21
+ import { getBaseUrl } from '@plone/volto/helpers/Url/Url';
21
22
 
22
23
  function blobToBase64(blob) {
23
24
  return new Promise((resolve, reject) => {
@@ -1,11 +1,11 @@
1
1
  import React from 'react';
2
- import { render } from '@testing-library/react';
3
- import '@testing-library/jest-dom/extend-expect';
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
4
  import { Provider } from 'react-intl-redux';
5
5
  import VisualizationWidget from './VisualizationWidget';
6
6
 
7
7
  describe('VisualizationWidget', () => {
8
- it('should render the component', () => {
8
+ it('should render the component', async () => {
9
9
  const data = {
10
10
  value: {
11
11
  url: 'http://localhost:3000/tableau-ct',
@@ -29,6 +29,11 @@ describe('VisualizationWidget', () => {
29
29
  <VisualizationWidget {...data} id={'1234'} title="Title" />
30
30
  </Provider>,
31
31
  );
32
- expect(container.querySelector('.tableau-wrapper')).toBeInTheDocument();
32
+ expect(
33
+ await screen.findByRole('button', { name: /open tableau editor/i }),
34
+ ).toBeInTheDocument();
35
+ await waitFor(() => {
36
+ expect(container.querySelector('.tableau-wrapper')).toBeInTheDocument();
37
+ });
33
38
  });
34
39
  });
@@ -1,5 +1,7 @@
1
1
  import { defineMessages } from 'react-intl';
2
- import { find, includes, uniq } from 'lodash';
2
+ import find from 'lodash/find';
3
+ import includes from 'lodash/includes';
4
+ import uniq from 'lodash/uniq';
3
5
  import { canChangeVizData } from '@eeacms/volto-tableau/Tableau/helpers';
4
6
 
5
7
  const messages = defineMessages({