@eeacms/volto-eea-website-theme 4.3.0 → 4.3.2
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/CHANGELOG.md +37 -3
- package/package.json +1 -1
- package/src/customizations/volto/components/manage/Contents/ContentsItem.jsx +425 -0
- package/src/customizations/volto/components/manage/Contents/ContentsItem.jsx.diff +73 -0
- package/src/customizations/volto/components/manage/Contents/ContentsItem.jsx.md +19 -0
- package/src/customizations/volto/components/theme/Header/Header.jsx +157 -120
package/CHANGELOG.md
CHANGED
|
@@ -4,11 +4,19 @@ 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
|
-
### [4.3.
|
|
7
|
+
### [4.3.2](https://github.com/eea/volto-eea-website-theme/compare/4.3.1...4.3.2) - 15 May 2026
|
|
8
8
|
|
|
9
|
-
#### :
|
|
9
|
+
#### :bug: Bug Fixes
|
|
10
|
+
|
|
11
|
+
- fix(Header): use navroot language to fetch navigation, fix subsite case - refs #303244 [Miu Razvan - [`c25711e`](https://github.com/eea/volto-eea-website-theme/commit/c25711ec3f8492d442c9a130e5e4cb9feb1e80ad)]
|
|
12
|
+
|
|
13
|
+
### [4.3.1](https://github.com/eea/volto-eea-website-theme/compare/4.3.0...4.3.1) - 14 May 2026
|
|
14
|
+
|
|
15
|
+
#### :bug: Bug Fixes
|
|
16
|
+
|
|
17
|
+
- fix: Scheduled label in contents - refs #303325 [Teodor Voicu - [`7c7d4d4`](https://github.com/eea/volto-eea-website-theme/commit/7c7d4d43ced32570f2ea1dd104992f5da4164594)]
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
### [4.3.0](https://github.com/eea/volto-eea-website-theme/compare/4.2.0...4.3.0) - 24 April 2026
|
|
12
20
|
|
|
13
21
|
#### :hammer_and_wrench: Others
|
|
14
22
|
|
|
@@ -77,6 +85,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
77
85
|
|
|
78
86
|
#### :house: Internal changes
|
|
79
87
|
|
|
88
|
+
- chore: [JENKINSFILE] add package version in sonarqube [valentinab25 - [`b15b302`](https://github.com/eea/volto-eea-website-theme/commit/b15b302ff88ec6afa6901ee7e1726cc4e04a8739)]
|
|
89
|
+
- chore: [JENKINSFILE] use sonarqube branches [EEA Jenkins - [`36f2e1e`](https://github.com/eea/volto-eea-website-theme/commit/36f2e1e176471b3753d77ab8aaf0cba577b43b36)]
|
|
80
90
|
|
|
81
91
|
### [3.19.0](https://github.com/eea/volto-eea-website-theme/compare/3.18.1...3.19.0) - 11 February 2026
|
|
82
92
|
|
|
@@ -139,6 +149,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
139
149
|
#### :hammer_and_wrench: Others
|
|
140
150
|
|
|
141
151
|
- Release 3.12.0 [Alin Voinea - [`ea1e961`](https://github.com/eea/volto-eea-website-theme/commit/ea1e96144684b2a8238ae476fd8d47de82ff42b4)]
|
|
152
|
+
- Add Sonarqube tag using bise-frontend addons list [EEA Jenkins - [`2cac56e`](https://github.com/eea/volto-eea-website-theme/commit/2cac56e22e580e042d368b69254172539ed33b65)]
|
|
142
153
|
### [3.11.0](https://github.com/eea/volto-eea-website-theme/compare/3.10.1...3.11.0) - 29 September 2025
|
|
143
154
|
|
|
144
155
|
#### :bug: Bug Fixes
|
|
@@ -232,6 +243,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
232
243
|
|
|
233
244
|
#### :hammer_and_wrench: Others
|
|
234
245
|
|
|
246
|
+
- Add Sonarqube tag using fise-frontend addons list [EEA Jenkins - [`3d50874`](https://github.com/eea/volto-eea-website-theme/commit/3d50874281ebcb91a1ae3727248f656a6f26c603)]
|
|
247
|
+
- Add Sonarqube tag using ied-frontend addons list [EEA Jenkins - [`a3f7676`](https://github.com/eea/volto-eea-website-theme/commit/a3f76767d99cb6dd93cc7fa0eafdea57e9000b2c)]
|
|
235
248
|
### [3.5.4](https://github.com/eea/volto-eea-website-theme/compare/3.5.3...3.5.4) - 30 January 2025
|
|
236
249
|
|
|
237
250
|
#### :bug: Bug Fixes
|
|
@@ -332,6 +345,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
332
345
|
|
|
333
346
|
#### :hammer_and_wrench: Others
|
|
334
347
|
|
|
348
|
+
- Add Sonarqube tag using bise-frontend addons list [EEA Jenkins - [`e417f83`](https://github.com/eea/volto-eea-website-theme/commit/e417f839312045c56b67ab8134fe5b0622b3e2c3)]
|
|
335
349
|
## [3.0.0](https://github.com/eea/volto-eea-website-theme/compare/2.4.0...3.0.0) - 21 October 2024
|
|
336
350
|
|
|
337
351
|
#### :nail_care: Enhancements
|
|
@@ -417,6 +431,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
417
431
|
- Refs #269520 - other_organisation test [Tripon Eugen - [`7558b27`](https://github.com/eea/volto-eea-website-theme/commit/7558b27a9d1cd6d3480a32b296c7325c796006c9)]
|
|
418
432
|
- Refs #269520 - other_organisation token widget edit mode [Tripon Eugen - [`b6df127`](https://github.com/eea/volto-eea-website-theme/commit/b6df127bd91b6f55dda8f468e1107037d43752ff)]
|
|
419
433
|
- Refs #269520 - other_organisation token widget [Tripon Eugen - [`6fd7543`](https://github.com/eea/volto-eea-website-theme/commit/6fd7543894bd2c593a1729116befd95c82ea3c8f)]
|
|
434
|
+
- Add Sonarqube tag using marine-frontend addons list [EEA Jenkins - [`cbc36c7`](https://github.com/eea/volto-eea-website-theme/commit/cbc36c74dfcd5f7cb1013a4c673d9c02e0023766)]
|
|
420
435
|
### [2.1.1](https://github.com/eea/volto-eea-website-theme/compare/2.1.0...2.1.1) - 28 May 2024
|
|
421
436
|
|
|
422
437
|
#### :bug: Bug Fixes
|
|
@@ -501,6 +516,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
501
516
|
|
|
502
517
|
#### :hammer_and_wrench: Others
|
|
503
518
|
|
|
519
|
+
- Add Sonarqube tag using insitu-frontend addons list [EEA Jenkins - [`adc6730`](https://github.com/eea/volto-eea-website-theme/commit/adc6730e21a37afb865b842182624401de6a29f5)]
|
|
504
520
|
### [1.33.1](https://github.com/eea/volto-eea-website-theme/compare/1.33.0...1.33.1) - 4 April 2024
|
|
505
521
|
|
|
506
522
|
#### :bug: Bug Fixes
|
|
@@ -634,6 +650,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
634
650
|
|
|
635
651
|
- bump version [Razvan - [`721e939`](https://github.com/eea/volto-eea-website-theme/commit/721e939d12e324b459ebfa78a2e656ee7142a3d6)]
|
|
636
652
|
- merge master into this branch [Razvan - [`586c8f9`](https://github.com/eea/volto-eea-website-theme/commit/586c8f910bac55a043bd8dda60e9444bd2ae1663)]
|
|
653
|
+
- Add Sonarqube tag using freshwater-frontend addons list [EEA Jenkins - [`fd90044`](https://github.com/eea/volto-eea-website-theme/commit/fd9004442a9d1d465f7601ecdefe3e23c61e6a9c)]
|
|
654
|
+
- Add Sonarqube tag using insitu-frontend addons list [EEA Jenkins - [`4bc3dd3`](https://github.com/eea/volto-eea-website-theme/commit/4bc3dd3ae412a66befd04b5b80fab3716c929240)]
|
|
637
655
|
- test: Update jest,Jenkinsfile,lint to volto-addons-template PR30 [valentinab25 - [`c4dbd28`](https://github.com/eea/volto-eea-website-theme/commit/c4dbd289358205bc2d849aab7edb11ccf3b89cee)]
|
|
638
656
|
- fix tests [Razvan - [`042330b`](https://github.com/eea/volto-eea-website-theme/commit/042330bc97d32ffe7ba769b4f2453f71cffed706)]
|
|
639
657
|
- remove RemoveSchema logic [Razvan - [`08d10f8`](https://github.com/eea/volto-eea-website-theme/commit/08d10f8bf6f75478260e4e4c66d7316ba87b907a)]
|
|
@@ -728,6 +746,11 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
728
746
|
- test: Add real image to cypress test [Alin Voinea - [`4ff591a`](https://github.com/eea/volto-eea-website-theme/commit/4ff591ae3318c9588b4e2114582c0fa6cfdf31ae)]
|
|
729
747
|
- test: Add cypress tests for Image block styling position and align [Alin Voinea - [`7341ef7`](https://github.com/eea/volto-eea-website-theme/commit/7341ef7b92714fc0cc3ab0c31c39033e7b3e19e7)]
|
|
730
748
|
- Revert "change(tests): commented out rss test since title block config is missing" [Alin Voinea - [`fb61191`](https://github.com/eea/volto-eea-website-theme/commit/fb611918d6ca380b89b594f283dcf9f685a4b294)]
|
|
749
|
+
- test: [JENKINS] Use java17 for sonarqube scanner [valentinab25 - [`6a3be30`](https://github.com/eea/volto-eea-website-theme/commit/6a3be3092589411af7808a235f76de5222fd3868)]
|
|
750
|
+
- test: [JENKINS] Run cypress in started frontend container [valentinab25 - [`c3978f2`](https://github.com/eea/volto-eea-website-theme/commit/c3978f23375ef066e9fd6f6c2e34ba6c1c058f69)]
|
|
751
|
+
- test: [JENKINS] Add cpu limit on cypress docker [valentinab25 - [`f672779`](https://github.com/eea/volto-eea-website-theme/commit/f672779e845bec9240ccc901e9f53ec80c5a1819)]
|
|
752
|
+
- test: [JENKINS] Increase shm-size to cypress docker [valentinab25 - [`ae5d8e3`](https://github.com/eea/volto-eea-website-theme/commit/ae5d8e3f4e04dc2808d47ce2ee886e1b23b528da)]
|
|
753
|
+
- test: [JENKINS] Improve cypress time [valentinab25 - [`170ff0c`](https://github.com/eea/volto-eea-website-theme/commit/170ff0c8e3b30e69479bdf1117e811fea94f1027)]
|
|
731
754
|
### [1.23.0](https://github.com/eea/volto-eea-website-theme/compare/1.22.1...1.23.0) - 2 November 2023
|
|
732
755
|
|
|
733
756
|
#### :rocket: New Features
|
|
@@ -740,6 +763,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
740
763
|
|
|
741
764
|
#### :house: Internal changes
|
|
742
765
|
|
|
766
|
+
- chore: [JENKINS] Refactor automated testing [valentinab25 - [`f28fce3`](https://github.com/eea/volto-eea-website-theme/commit/f28fce3d1eb815f95fb9aa40de42b10b7e8e30c5)]
|
|
743
767
|
- chore: husky, lint-staged use fixed versions [valentinab25 - [`6d15088`](https://github.com/eea/volto-eea-website-theme/commit/6d150886c5aeb2ca0b569270486e60f7cc274e2c)]
|
|
744
768
|
- chore:volto 16 in tests, update docs, fix stylelint overrides [valentinab25 - [`20c0323`](https://github.com/eea/volto-eea-website-theme/commit/20c032380b33c0077c869a05136f93e2fb68e5d4)]
|
|
745
769
|
|
|
@@ -925,6 +949,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
925
949
|
|
|
926
950
|
#### :house: Internal changes
|
|
927
951
|
|
|
952
|
+
- chore: [JENKINS] Deprecate circularity website [valentinab25 - [`370dcbf`](https://github.com/eea/volto-eea-website-theme/commit/370dcbfbf1a8135ce7b1b3b271b004552a631837)]
|
|
928
953
|
|
|
929
954
|
#### :hammer_and_wrench: Others
|
|
930
955
|
|
|
@@ -1080,6 +1105,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
1080
1105
|
|
|
1081
1106
|
#### :hammer_and_wrench: Others
|
|
1082
1107
|
|
|
1108
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`6c5e2f8`](https://github.com/eea/volto-eea-website-theme/commit/6c5e2f80456e2061d9e9c15fd0a0b91b9ac70568)]
|
|
1083
1109
|
### [1.9.1](https://github.com/eea/volto-eea-website-theme/compare/1.9.0...1.9.1) - 28 February 2023
|
|
1084
1110
|
|
|
1085
1111
|
#### :bug: Bug Fixes
|
|
@@ -1226,6 +1252,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
1226
1252
|
|
|
1227
1253
|
- For some reasons types is a string [Alin Voinea - [`3769a09`](https://github.com/eea/volto-eea-website-theme/commit/3769a0981181d5b633f3498daebbe96be8b4b833)]
|
|
1228
1254
|
- Fix(redirect): o.filter - refs #157627 [Alin Voinea - [`deb23da`](https://github.com/eea/volto-eea-website-theme/commit/deb23da846444cc96539697fd798429ae0abe89e)]
|
|
1255
|
+
- Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`f1fffc5`](https://github.com/eea/volto-eea-website-theme/commit/f1fffc5db96725440863d545580b4e76cce4b796)]
|
|
1229
1256
|
### [1.5.0](https://github.com/eea/volto-eea-website-theme/compare/1.4.2...1.5.0) - 9 January 2023
|
|
1230
1257
|
|
|
1231
1258
|
#### :hammer_and_wrench: Others
|
|
@@ -1259,6 +1286,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
1259
1286
|
|
|
1260
1287
|
- Release 1.4.0 [Alin Voinea - [`bd42a0d`](https://github.com/eea/volto-eea-website-theme/commit/bd42a0d26e928cac5d99933194755da3db06b341)]
|
|
1261
1288
|
- bump version to use as volto-eea-design-system [David Ichim - [`f4be047`](https://github.com/eea/volto-eea-website-theme/commit/f4be047328b46399b03b612d378b18aaf82e7dc1)]
|
|
1289
|
+
- Add Sonarqube tag using advisory-board-frontend addons list [EEA Jenkins - [`9b7cfef`](https://github.com/eea/volto-eea-website-theme/commit/9b7cfefb4d34fc1c948015e491feb370f9795bd8)]
|
|
1262
1290
|
- test(Jenkins): Run tests and cypress with latest canary @plone/volto [Alin Voinea - [`df252a9`](https://github.com/eea/volto-eea-website-theme/commit/df252a9bfed0bb86cadf53c59dd1603b1e2cd822)]
|
|
1263
1291
|
### [1.3.2](https://github.com/eea/volto-eea-website-theme/compare/1.3.1...1.3.2) - 16 December 2022
|
|
1264
1292
|
|
|
@@ -1268,6 +1296,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
1268
1296
|
|
|
1269
1297
|
#### :hammer_and_wrench: Others
|
|
1270
1298
|
|
|
1299
|
+
- Add Sonarqube tag using cca-frontend addons list [EEA Jenkins - [`a43c658`](https://github.com/eea/volto-eea-website-theme/commit/a43c658a7920c8df95e763b9a637f38ce77eba2c)]
|
|
1271
1300
|
- Better razzle.config [Tiberiu Ichim - [`81dbf48`](https://github.com/eea/volto-eea-website-theme/commit/81dbf48815fb27facb4f82c9b764540fdf188b2e)]
|
|
1272
1301
|
- Better razzle.config [Tiberiu Ichim - [`7bc9da2`](https://github.com/eea/volto-eea-website-theme/commit/7bc9da2cd837ab62a95cd29979cdd9b0055b7d67)]
|
|
1273
1302
|
### [1.3.1](https://github.com/eea/volto-eea-website-theme/compare/1.3.0...1.3.1) - 28 November 2022
|
|
@@ -1278,6 +1307,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
1278
1307
|
|
|
1279
1308
|
#### :hammer_and_wrench: Others
|
|
1280
1309
|
|
|
1310
|
+
- yarn 3 [Alin Voinea - [`ea7a709`](https://github.com/eea/volto-eea-website-theme/commit/ea7a7094945312776e9b6f44e371178603e92139)]
|
|
1281
1311
|
### [1.3.0](https://github.com/eea/volto-eea-website-theme/compare/1.2.0...1.3.0) - 22 November 2022
|
|
1282
1312
|
|
|
1283
1313
|
#### :rocket: New Features
|
|
@@ -1318,6 +1348,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
1318
1348
|
- Add subsite class to body [Tiberiu Ichim - [`74d700f`](https://github.com/eea/volto-eea-website-theme/commit/74d700fbfd6249a8604762a7e4e49cce857db0f3)]
|
|
1319
1349
|
- Add subsite info to header [Tiberiu Ichim - [`47daf8b`](https://github.com/eea/volto-eea-website-theme/commit/47daf8bb6374a1222040626b19d4154df7ba1b83)]
|
|
1320
1350
|
- fix eslint [Miu Razvan - [`eb8d0a7`](https://github.com/eea/volto-eea-website-theme/commit/eb8d0a790bc70c0aae256c6ff35f63c4885f338e)]
|
|
1351
|
+
- Add Sonarqube tag using circularity-frontend addons list [EEA Jenkins - [`cc578a4`](https://github.com/eea/volto-eea-website-theme/commit/cc578a413b205a8e61e091fab3a88f94cedefc89)]
|
|
1321
1352
|
### [1.1.0](https://github.com/eea/volto-eea-website-theme/compare/1.0.0...1.1.0) - 28 October 2022
|
|
1322
1353
|
|
|
1323
1354
|
#### :nail_care: Enhancements
|
|
@@ -1365,6 +1396,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
1365
1396
|
|
|
1366
1397
|
#### :hammer_and_wrench: Others
|
|
1367
1398
|
|
|
1399
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`33b56ac`](https://github.com/eea/volto-eea-website-theme/commit/33b56acb13fbaf0c5b79e8fc6e13c4b699c79c90)]
|
|
1368
1400
|
### [0.7.3](https://github.com/eea/volto-eea-website-theme/compare/0.7.2...0.7.3) - 22 September 2022
|
|
1369
1401
|
|
|
1370
1402
|
#### :hammer_and_wrench: Others
|
|
@@ -1632,6 +1664,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
1632
1664
|
- Header refactor, add custom logo #5 [ichim-david - [`4950235`](https://github.com/eea/volto-eea-website-theme/commit/49502358105437cfeac3b144e6d301cb59aa2346)]
|
|
1633
1665
|
- Update footer.config with new publication card component [ichim-david - [`2e38e9a`](https://github.com/eea/volto-eea-website-theme/commit/2e38e9a417f835009d60c80d4eb4b30229f55e45)]
|
|
1634
1666
|
- feature(breadcrumbs): implement eea-design-system breadcrumb as Volto component #32 #7 [ichim-david - [`181af41`](https://github.com/eea/volto-eea-website-theme/commit/181af4125ce2b9ddac56dab4723cb11c26633221)]
|
|
1667
|
+
- Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`da8ceb6`](https://github.com/eea/volto-eea-website-theme/commit/da8ceb68ea68bfbc9504e48ccd4d68277f11ab9a)]
|
|
1635
1668
|
- use breadcrumbs from eea-design-system [nileshgulia1 - [`db2f9e9`](https://github.com/eea/volto-eea-website-theme/commit/db2f9e9a4327420a3cce9a9903cd88549b129eab)]
|
|
1636
1669
|
- Update theme.config [ichim-david - [`8eca4f4`](https://github.com/eea/volto-eea-website-theme/commit/8eca4f40397a4aeca6d39029c92db78968d37064)]
|
|
1637
1670
|
- Added keyContent component to theme.config [ichim-david - [`d86f202`](https://github.com/eea/volto-eea-website-theme/commit/d86f202d0274d839487a88b51cae9a0e899beb23)]
|
|
@@ -1673,4 +1706,5 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
|
1673
1706
|
|
|
1674
1707
|
#### :hammer_and_wrench: Others
|
|
1675
1708
|
|
|
1709
|
+
- yarn bootstrap [Alin Voinea - [`6995e9e`](https://github.com/eea/volto-eea-website-theme/commit/6995e9e091f21fdbbdffa8a44fc0e2c626f6d46a)]
|
|
1676
1710
|
- Initial commit [Alin Voinea - [`6a9c03a`](https://github.com/eea/volto-eea-website-theme/commit/6a9c03a7cebe71ca87e82cf58c42904063e9d8d3)]
|
package/package.json
CHANGED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contents item component.
|
|
3
|
+
* @module components/manage/Contents/ContentsItem
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { Button, Table, Menu, Divider } from 'semantic-ui-react';
|
|
8
|
+
import { Link } from 'react-router-dom';
|
|
9
|
+
import PropTypes from 'prop-types';
|
|
10
|
+
import map from 'lodash/map';
|
|
11
|
+
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
|
12
|
+
import Circle from '@plone/volto/components/manage/Contents/circle';
|
|
13
|
+
import FormattedDate from '@plone/volto/components/theme/FormattedDate/FormattedDate';
|
|
14
|
+
import Icon from '@plone/volto/components/theme/Icon/Icon';
|
|
15
|
+
import Popup from '@plone/volto/components/theme/Popup/Popup';
|
|
16
|
+
import { getContentIcon } from '@plone/volto/helpers/Content/Content';
|
|
17
|
+
import moreSVG from '@plone/volto/icons/more.svg';
|
|
18
|
+
import checkboxUncheckedSVG from '@plone/volto/icons/checkbox-unchecked.svg';
|
|
19
|
+
import checkboxCheckedSVG from '@plone/volto/icons/checkbox-checked.svg';
|
|
20
|
+
import cutSVG from '@plone/volto/icons/cut.svg';
|
|
21
|
+
import deleteSVG from '@plone/volto/icons/delete.svg';
|
|
22
|
+
import copySVG from '@plone/volto/icons/copy.svg';
|
|
23
|
+
import showSVG from '@plone/volto/icons/show.svg';
|
|
24
|
+
import moveUpSVG from '@plone/volto/icons/move-up.svg';
|
|
25
|
+
import moveDownSVG from '@plone/volto/icons/move-down.svg';
|
|
26
|
+
import editingSVG from '@plone/volto/icons/editing.svg';
|
|
27
|
+
import dragSVG from '@plone/volto/icons/drag.svg';
|
|
28
|
+
import cx from 'classnames';
|
|
29
|
+
|
|
30
|
+
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
31
|
+
|
|
32
|
+
const messages = defineMessages({
|
|
33
|
+
private: {
|
|
34
|
+
id: 'private',
|
|
35
|
+
defaultMessage: 'Private',
|
|
36
|
+
},
|
|
37
|
+
pending: {
|
|
38
|
+
id: 'pending',
|
|
39
|
+
defaultMessage: 'Pending',
|
|
40
|
+
},
|
|
41
|
+
published: {
|
|
42
|
+
id: 'published',
|
|
43
|
+
defaultMessage: 'Published',
|
|
44
|
+
},
|
|
45
|
+
intranet: {
|
|
46
|
+
id: 'intranet',
|
|
47
|
+
defaultMessage: 'Intranet',
|
|
48
|
+
},
|
|
49
|
+
draft: {
|
|
50
|
+
id: 'draft',
|
|
51
|
+
defaultMessage: 'Draft',
|
|
52
|
+
},
|
|
53
|
+
no_workflow_state: {
|
|
54
|
+
id: 'no workflow state',
|
|
55
|
+
defaultMessage: 'No workflow state',
|
|
56
|
+
},
|
|
57
|
+
none: {
|
|
58
|
+
id: 'Not available',
|
|
59
|
+
defaultMessage: 'None',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
function getColor(string) {
|
|
64
|
+
switch (string) {
|
|
65
|
+
case 'private':
|
|
66
|
+
return '#ed4033';
|
|
67
|
+
case 'published':
|
|
68
|
+
return '#007bc1';
|
|
69
|
+
case 'intranet':
|
|
70
|
+
return '#51aa55';
|
|
71
|
+
case 'draft':
|
|
72
|
+
return '#f6a808';
|
|
73
|
+
default:
|
|
74
|
+
return 'grey';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Contents item component class.
|
|
80
|
+
* @function ContentsItemComponent
|
|
81
|
+
* @returns {string} Markup of the component.
|
|
82
|
+
*/
|
|
83
|
+
export const ContentsItemComponent = ({
|
|
84
|
+
item,
|
|
85
|
+
selected,
|
|
86
|
+
onClick,
|
|
87
|
+
indexes,
|
|
88
|
+
onCut,
|
|
89
|
+
onCopy,
|
|
90
|
+
onDelete,
|
|
91
|
+
onMoveToTop,
|
|
92
|
+
onMoveToBottom,
|
|
93
|
+
connectDragPreview,
|
|
94
|
+
connectDragSource,
|
|
95
|
+
connectDropTarget,
|
|
96
|
+
isDragging,
|
|
97
|
+
order,
|
|
98
|
+
}) => {
|
|
99
|
+
const intl = useIntl();
|
|
100
|
+
const now = Date.now();
|
|
101
|
+
const expirationTime = new Date(item.ExpirationDate).getTime();
|
|
102
|
+
const effectiveTime = new Date(item.EffectiveDate).getTime();
|
|
103
|
+
const isExpired = item.ExpirationDate !== 'None' && expirationTime < now;
|
|
104
|
+
const isScheduled = item.EffectiveDate !== 'None' && effectiveTime > now;
|
|
105
|
+
|
|
106
|
+
return connectDropTarget(
|
|
107
|
+
connectDragPreview(
|
|
108
|
+
<tr
|
|
109
|
+
key={item['@id']}
|
|
110
|
+
className={cx('', { 'dragging-row': isDragging })}
|
|
111
|
+
aria-label={item['@id']}
|
|
112
|
+
>
|
|
113
|
+
<Table.Cell className={cx('', { 'dragging-cell': isDragging })}>
|
|
114
|
+
{connectDragSource(
|
|
115
|
+
<div style={{ display: 'inline-block' }}>
|
|
116
|
+
<Button icon basic>
|
|
117
|
+
<Icon
|
|
118
|
+
name={dragSVG}
|
|
119
|
+
size="20px"
|
|
120
|
+
color="#878f93"
|
|
121
|
+
className="content drag handle"
|
|
122
|
+
/>
|
|
123
|
+
</Button>
|
|
124
|
+
</div>,
|
|
125
|
+
)}
|
|
126
|
+
</Table.Cell>
|
|
127
|
+
<Table.Cell className={cx('', { 'dragging-cell': isDragging })}>
|
|
128
|
+
{selected ? (
|
|
129
|
+
<Button
|
|
130
|
+
icon
|
|
131
|
+
basic
|
|
132
|
+
aria-label="Unchecked"
|
|
133
|
+
onClick={(e) => onClick(e, item['@id'])}
|
|
134
|
+
>
|
|
135
|
+
<Icon
|
|
136
|
+
name={checkboxCheckedSVG}
|
|
137
|
+
color="#007eb1"
|
|
138
|
+
size="24px"
|
|
139
|
+
className="checked"
|
|
140
|
+
/>
|
|
141
|
+
</Button>
|
|
142
|
+
) : (
|
|
143
|
+
<Button
|
|
144
|
+
icon
|
|
145
|
+
basic
|
|
146
|
+
aria-label="Checked"
|
|
147
|
+
onClick={(e) => onClick(e, item['@id'])}
|
|
148
|
+
>
|
|
149
|
+
<Icon
|
|
150
|
+
name={checkboxUncheckedSVG}
|
|
151
|
+
color="#826a6a"
|
|
152
|
+
size="24px"
|
|
153
|
+
className="unchecked"
|
|
154
|
+
/>
|
|
155
|
+
</Button>
|
|
156
|
+
)}
|
|
157
|
+
</Table.Cell>
|
|
158
|
+
<Table.Cell className={cx('', { 'dragging-cell': isDragging })}>
|
|
159
|
+
<Link
|
|
160
|
+
className="icon-align-name"
|
|
161
|
+
to={`${item['@id']}${item.is_folderish ? '/contents' : ''}`}
|
|
162
|
+
>
|
|
163
|
+
<div
|
|
164
|
+
className="expire-align"
|
|
165
|
+
style={{ flex: '1 1 auto', minWidth: 0 }}
|
|
166
|
+
>
|
|
167
|
+
<Icon
|
|
168
|
+
name={getContentIcon(item['@type'], item.is_folderish)}
|
|
169
|
+
size="20px"
|
|
170
|
+
className="icon-margin"
|
|
171
|
+
color="#878f93"
|
|
172
|
+
title={item['Type'] || item['@type']}
|
|
173
|
+
/>{' '}
|
|
174
|
+
<span
|
|
175
|
+
title={item.title}
|
|
176
|
+
style={{ flex: '1 1 auto', minWidth: 0 }}
|
|
177
|
+
>
|
|
178
|
+
{' '}
|
|
179
|
+
{item.title}
|
|
180
|
+
</span>
|
|
181
|
+
</div>
|
|
182
|
+
{isExpired && (
|
|
183
|
+
<Button
|
|
184
|
+
className="button-margin"
|
|
185
|
+
size="mini"
|
|
186
|
+
style={{ flexShrink: 0 }}
|
|
187
|
+
>
|
|
188
|
+
<FormattedMessage id="Expired" defaultMessage="Expired" />
|
|
189
|
+
</Button>
|
|
190
|
+
)}
|
|
191
|
+
{isScheduled && (
|
|
192
|
+
<Button
|
|
193
|
+
className="button-margin effective-future"
|
|
194
|
+
size="mini"
|
|
195
|
+
style={{ flexShrink: 0 }}
|
|
196
|
+
>
|
|
197
|
+
<FormattedMessage id="Scheduled" defaultMessage="Scheduled" />
|
|
198
|
+
</Button>
|
|
199
|
+
)}
|
|
200
|
+
</Link>
|
|
201
|
+
</Table.Cell>
|
|
202
|
+
{map(indexes, (index) => (
|
|
203
|
+
<Table.Cell
|
|
204
|
+
className={cx('', { 'dragging-cell': isDragging })}
|
|
205
|
+
key={index.id}
|
|
206
|
+
>
|
|
207
|
+
{index.type === 'boolean' &&
|
|
208
|
+
(item[index.id] ? (
|
|
209
|
+
<FormattedMessage id="Yes" defaultMessage="Yes" />
|
|
210
|
+
) : (
|
|
211
|
+
<FormattedMessage id="No" defaultMessage="No" />
|
|
212
|
+
))}
|
|
213
|
+
{index.type === 'string' &&
|
|
214
|
+
index.id !== 'review_state' &&
|
|
215
|
+
item[index.id]}
|
|
216
|
+
{index.id === 'review_state' && (
|
|
217
|
+
<div>
|
|
218
|
+
<span>
|
|
219
|
+
<Circle color={getColor(item[index.id])} size="15px" />
|
|
220
|
+
</span>
|
|
221
|
+
{messages[item[index.id]]
|
|
222
|
+
? intl.formatMessage(messages[item[index.id]])
|
|
223
|
+
: item['review_title'] ||
|
|
224
|
+
item['review_state'] ||
|
|
225
|
+
intl.formatMessage(messages.no_workflow_state)}
|
|
226
|
+
</div>
|
|
227
|
+
)}
|
|
228
|
+
{index.type === 'date' && (
|
|
229
|
+
<>
|
|
230
|
+
{item[index?.id] && item[index.id] !== 'None' ? (
|
|
231
|
+
<FormattedDate date={item[index.id]} />
|
|
232
|
+
) : (
|
|
233
|
+
intl.formatMessage(messages.none)
|
|
234
|
+
)}
|
|
235
|
+
</>
|
|
236
|
+
)}
|
|
237
|
+
{index.type === 'array' && (
|
|
238
|
+
<span>{item[index.id]?.join(', ')}</span>
|
|
239
|
+
)}
|
|
240
|
+
</Table.Cell>
|
|
241
|
+
))}
|
|
242
|
+
<Table.Cell
|
|
243
|
+
className={cx('', { 'dragging-cell': isDragging })}
|
|
244
|
+
textAlign="right"
|
|
245
|
+
>
|
|
246
|
+
<Popup
|
|
247
|
+
menu={true}
|
|
248
|
+
position="bottom right"
|
|
249
|
+
flowing={true}
|
|
250
|
+
basic={true}
|
|
251
|
+
on="click"
|
|
252
|
+
popper={{
|
|
253
|
+
className: 'dropdown-popup',
|
|
254
|
+
}}
|
|
255
|
+
trigger={
|
|
256
|
+
<Icon
|
|
257
|
+
name={moreSVG}
|
|
258
|
+
className="dropdown-popup-trigger"
|
|
259
|
+
size="24px"
|
|
260
|
+
color="#007eb1"
|
|
261
|
+
/>
|
|
262
|
+
}
|
|
263
|
+
>
|
|
264
|
+
<Menu vertical borderless fluid>
|
|
265
|
+
<Link className="item icon-align" to={`${item['@id']}/edit`}>
|
|
266
|
+
<Icon name={editingSVG} color="#007eb1" size="24px" />{' '}
|
|
267
|
+
<FormattedMessage id="Edit" defaultMessage="Edit" />
|
|
268
|
+
</Link>
|
|
269
|
+
<Link className="item right-dropdown icon-align" to={item['@id']}>
|
|
270
|
+
<Icon name={showSVG} color="#007eb1" size="24px" />{' '}
|
|
271
|
+
<FormattedMessage id="View" defaultMessage="View" />
|
|
272
|
+
</Link>
|
|
273
|
+
<Divider />
|
|
274
|
+
<Menu.Item
|
|
275
|
+
onClick={onCut}
|
|
276
|
+
value={item['@id']}
|
|
277
|
+
className="right-dropdown icon-align"
|
|
278
|
+
>
|
|
279
|
+
<Icon name={cutSVG} color="#007eb1" size="24px" />{' '}
|
|
280
|
+
<FormattedMessage id="Cut" defaultMessage="Cut" />
|
|
281
|
+
</Menu.Item>
|
|
282
|
+
<Menu.Item
|
|
283
|
+
onClick={onCopy}
|
|
284
|
+
value={item['@id']}
|
|
285
|
+
className="right-dropdown icon-align"
|
|
286
|
+
>
|
|
287
|
+
<Icon name={copySVG} color="#007eb1" size="24px" />{' '}
|
|
288
|
+
<FormattedMessage id="Copy" defaultMessage="Copy" />
|
|
289
|
+
</Menu.Item>
|
|
290
|
+
<Menu.Item
|
|
291
|
+
onClick={onDelete}
|
|
292
|
+
value={item['@id']}
|
|
293
|
+
className="right-dropdown icon-align"
|
|
294
|
+
>
|
|
295
|
+
<Icon name={deleteSVG} color="#e40166" size="24px" />{' '}
|
|
296
|
+
<FormattedMessage id="Delete" defaultMessage="Delete" />
|
|
297
|
+
</Menu.Item>
|
|
298
|
+
<Divider />
|
|
299
|
+
<Menu.Item
|
|
300
|
+
onClick={onMoveToTop}
|
|
301
|
+
value={order}
|
|
302
|
+
className="right-dropdown icon-align"
|
|
303
|
+
>
|
|
304
|
+
<Icon name={moveUpSVG} color="#007eb1" size="24px" />{' '}
|
|
305
|
+
<FormattedMessage
|
|
306
|
+
id="Move to top of folder"
|
|
307
|
+
defaultMessage="Move to top of folder"
|
|
308
|
+
/>
|
|
309
|
+
</Menu.Item>
|
|
310
|
+
<Menu.Item
|
|
311
|
+
onClick={onMoveToBottom}
|
|
312
|
+
value={order}
|
|
313
|
+
className="right-dropdown icon-align"
|
|
314
|
+
>
|
|
315
|
+
<Icon name={moveDownSVG} color="#007eb1" size="24px" />{' '}
|
|
316
|
+
<FormattedMessage
|
|
317
|
+
id="Move to bottom of folder"
|
|
318
|
+
defaultMessage="Move to bottom of folder"
|
|
319
|
+
/>
|
|
320
|
+
</Menu.Item>
|
|
321
|
+
</Menu>
|
|
322
|
+
</Popup>
|
|
323
|
+
</Table.Cell>
|
|
324
|
+
</tr>,
|
|
325
|
+
),
|
|
326
|
+
);
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Property types.
|
|
331
|
+
* @property {Object} propTypes Property types.
|
|
332
|
+
* @static
|
|
333
|
+
*/
|
|
334
|
+
ContentsItemComponent.propTypes = {
|
|
335
|
+
item: PropTypes.shape({
|
|
336
|
+
'@id': PropTypes.string,
|
|
337
|
+
title: PropTypes.string,
|
|
338
|
+
is_folderish: PropTypes.bool,
|
|
339
|
+
'@type': PropTypes.string,
|
|
340
|
+
}).isRequired,
|
|
341
|
+
selected: PropTypes.bool.isRequired,
|
|
342
|
+
onClick: PropTypes.func.isRequired,
|
|
343
|
+
indexes: PropTypes.arrayOf(
|
|
344
|
+
PropTypes.shape({
|
|
345
|
+
id: PropTypes.string,
|
|
346
|
+
type: PropTypes.string,
|
|
347
|
+
}),
|
|
348
|
+
).isRequired,
|
|
349
|
+
onCut: PropTypes.func.isRequired,
|
|
350
|
+
onCopy: PropTypes.func.isRequired,
|
|
351
|
+
onDelete: PropTypes.func.isRequired,
|
|
352
|
+
onMoveToTop: PropTypes.func.isRequired,
|
|
353
|
+
onMoveToBottom: PropTypes.func.isRequired,
|
|
354
|
+
connectDragPreview: PropTypes.func.isRequired,
|
|
355
|
+
connectDragSource: PropTypes.func.isRequired,
|
|
356
|
+
connectDropTarget: PropTypes.func.isRequired,
|
|
357
|
+
isDragging: PropTypes.bool.isRequired,
|
|
358
|
+
order: PropTypes.number.isRequired,
|
|
359
|
+
onOrderItem: PropTypes.func.isRequired,
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const DragDropConnector = (props) => {
|
|
363
|
+
const { DropTarget, DragSource } = props.reactDnd;
|
|
364
|
+
|
|
365
|
+
const DndConnectedContentsItem = React.useMemo(
|
|
366
|
+
() =>
|
|
367
|
+
DropTarget(
|
|
368
|
+
'item',
|
|
369
|
+
{
|
|
370
|
+
hover(props, monitor) {
|
|
371
|
+
const id = monitor.getItem().id;
|
|
372
|
+
const dragOrder = monitor.getItem().order;
|
|
373
|
+
const hoverOrder = props.order;
|
|
374
|
+
|
|
375
|
+
if (dragOrder === hoverOrder) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
props.onOrderItem(id, dragOrder, hoverOrder - dragOrder, false);
|
|
380
|
+
|
|
381
|
+
monitor.getItem().order = hoverOrder;
|
|
382
|
+
},
|
|
383
|
+
drop(props, monitor) {
|
|
384
|
+
const id = monitor.getItem().id;
|
|
385
|
+
const dragOrder = monitor.getItem().startOrder;
|
|
386
|
+
const dropOrder = props.order;
|
|
387
|
+
|
|
388
|
+
if (dragOrder === dropOrder) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
props.onOrderItem(id, dragOrder, dropOrder - dragOrder, true);
|
|
393
|
+
|
|
394
|
+
monitor.getItem().order = dropOrder;
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
(connect) => ({
|
|
398
|
+
connectDropTarget: connect.dropTarget(),
|
|
399
|
+
}),
|
|
400
|
+
)(
|
|
401
|
+
DragSource(
|
|
402
|
+
'item',
|
|
403
|
+
{
|
|
404
|
+
beginDrag(props) {
|
|
405
|
+
return {
|
|
406
|
+
id: props.item['@id'],
|
|
407
|
+
order: props.order,
|
|
408
|
+
startOrder: props.order,
|
|
409
|
+
};
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
(connect, monitor) => ({
|
|
413
|
+
connectDragSource: connect.dragSource(),
|
|
414
|
+
connectDragPreview: connect.dragPreview(),
|
|
415
|
+
isDragging: monitor.isDragging(),
|
|
416
|
+
}),
|
|
417
|
+
)(ContentsItemComponent),
|
|
418
|
+
),
|
|
419
|
+
[DragSource, DropTarget],
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
return <DndConnectedContentsItem {...props} />;
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
export default injectLazyLibs('reactDnd')(DragDropConnector);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
--- node_modules/@plone/volto/src/components/manage/Contents/ContentsItem.jsx
|
|
2
|
+
+++ src/customizations/volto/components/manage/Contents/ContentsItem.jsx
|
|
3
|
+
@@ -97,6 +97,11 @@
|
|
4
|
+
order,
|
|
5
|
+
}) => {
|
|
6
|
+
const intl = useIntl();
|
|
7
|
+
+ const now = Date.now();
|
|
8
|
+
+ const expirationTime = new Date(item.ExpirationDate).getTime();
|
|
9
|
+
+ const effectiveTime = new Date(item.EffectiveDate).getTime();
|
|
10
|
+
+ const isExpired = item.ExpirationDate !== 'None' && expirationTime < now;
|
|
11
|
+
+ const isScheduled = item.EffectiveDate !== 'None' && effectiveTime > now;
|
|
12
|
+
|
|
13
|
+
return connectDropTarget(
|
|
14
|
+
connectDragPreview(
|
|
15
|
+
@@ -155,7 +160,10 @@
|
|
16
|
+
className="icon-align-name"
|
|
17
|
+
to={`${item['@id']}${item.is_folderish ? '/contents' : ''}`}
|
|
18
|
+
>
|
|
19
|
+
- <div className="expire-align">
|
|
20
|
+
+ <div
|
|
21
|
+
+ className="expire-align"
|
|
22
|
+
+ style={{ flex: '1 1 auto', minWidth: 0 }}
|
|
23
|
+
+ >
|
|
24
|
+
<Icon
|
|
25
|
+
name={getContentIcon(item['@type'], item.is_folderish)}
|
|
26
|
+
size="20px"
|
|
27
|
+
@@ -163,21 +171,32 @@
|
|
28
|
+
color="#878f93"
|
|
29
|
+
title={item['Type'] || item['@type']}
|
|
30
|
+
/>{' '}
|
|
31
|
+
- <span title={item.title}> {item.title}</span>
|
|
32
|
+
+ <span
|
|
33
|
+
+ title={item.title}
|
|
34
|
+
+ style={{ flex: '1 1 auto', minWidth: 0 }}
|
|
35
|
+
+ >
|
|
36
|
+
+ {' '}
|
|
37
|
+
+ {item.title}
|
|
38
|
+
+ </span>
|
|
39
|
+
</div>
|
|
40
|
+
- {item.ExpirationDate !== 'None' &&
|
|
41
|
+
- new Date(item.ExpirationDate).getTime() <
|
|
42
|
+
- new Date().getTime() && (
|
|
43
|
+
- <Button className="button-margin" size="mini">
|
|
44
|
+
- <FormattedMessage id="Expired" defaultMessage="Expired" />
|
|
45
|
+
- </Button>
|
|
46
|
+
- )}
|
|
47
|
+
- {item.EffectiveDate !== 'None' &&
|
|
48
|
+
- new Date(item.EffectiveDate).getTime() > new Date().getTime() && (
|
|
49
|
+
- <Button className="button-margin effective-future" size="mini">
|
|
50
|
+
- <FormattedMessage id="Scheduled" defaultMessage="Scheduled" />
|
|
51
|
+
- </Button>
|
|
52
|
+
- )}
|
|
53
|
+
+ {isExpired && (
|
|
54
|
+
+ <Button
|
|
55
|
+
+ className="button-margin"
|
|
56
|
+
+ size="mini"
|
|
57
|
+
+ style={{ flexShrink: 0 }}
|
|
58
|
+
+ >
|
|
59
|
+
+ <FormattedMessage id="Expired" defaultMessage="Expired" />
|
|
60
|
+
+ </Button>
|
|
61
|
+
+ )}
|
|
62
|
+
+ {isScheduled && (
|
|
63
|
+
+ <Button
|
|
64
|
+
+ className="button-margin effective-future"
|
|
65
|
+
+ size="mini"
|
|
66
|
+
+ style={{ flexShrink: 0 }}
|
|
67
|
+
+ >
|
|
68
|
+
+ <FormattedMessage id="Scheduled" defaultMessage="Scheduled" />
|
|
69
|
+
+ </Button>
|
|
70
|
+
+ )}
|
|
71
|
+
</Link>
|
|
72
|
+
</Table.Cell>
|
|
73
|
+
{map(indexes, (index) => (
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# ContentsItem.jsx customization
|
|
2
|
+
|
|
3
|
+
This customization shadows Volto core's
|
|
4
|
+
`src/components/manage/Contents/ContentsItem.jsx` from `@plone/volto` 18.33.1.
|
|
5
|
+
|
|
6
|
+
The functional changes are limited to the contents table item link:
|
|
7
|
+
|
|
8
|
+
- The expired and scheduled date checks are computed once per render as
|
|
9
|
+
`isExpired` and `isScheduled`, then reused by the badge rendering.
|
|
10
|
+
- The title wrapper and title text are allowed to shrink with flexbox
|
|
11
|
+
(`flex: '1 1 auto'` and `minWidth: 0`), while the status badges keep their
|
|
12
|
+
intrinsic width with `flexShrink: 0`.
|
|
13
|
+
|
|
14
|
+
The goal is to avoid title text colliding with the `Expired` or `Scheduled`
|
|
15
|
+
badges without hardcoding a pixel width for the title.
|
|
16
|
+
|
|
17
|
+
When upgrading Volto, compare the new core component with this override and
|
|
18
|
+
refresh `ContentsItem.jsx.diff` if upstream changed around the contents item
|
|
19
|
+
title or badge rendering.
|
|
@@ -3,26 +3,24 @@
|
|
|
3
3
|
* @module components/theme/Header/Header
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import loadable from '@loadable/component';
|
|
7
|
+
import cx from 'classnames';
|
|
8
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
8
9
|
import { connect, useDispatch, useSelector } from 'react-redux';
|
|
9
|
-
|
|
10
10
|
import { withRouter } from 'react-router-dom';
|
|
11
|
+
import { compose } from 'redux';
|
|
12
|
+
import { Dropdown, Image } from 'semantic-ui-react';
|
|
13
|
+
|
|
14
|
+
import { getNavigation } from '@plone/volto/actions/navigation/navigation';
|
|
11
15
|
import UniversalLink from '@plone/volto/components/manage/UniversalLink/UniversalLink';
|
|
12
16
|
import { getBaseUrl } from '@plone/volto/helpers/Url/Url';
|
|
13
17
|
import { hasApiExpander } from '@plone/volto/helpers/Utils/Utils';
|
|
14
|
-
import { getNavigation } from '@plone/volto/actions/navigation/navigation';
|
|
15
|
-
import { getNavigationSettings } from '@eeacms/volto-eea-website-theme/actions';
|
|
16
|
-
import Header from '@eeacms/volto-eea-design-system/ui/Header/Header';
|
|
17
|
-
import EEALogo from '@eeacms/volto-eea-website-theme/components/theme/Logo';
|
|
18
|
-
import { usePrevious } from '@eeacms/volto-eea-design-system/helpers';
|
|
19
|
-
import eeaFlag from '@eeacms/volto-eea-design-system/../theme/themes/eea/assets/images/Header/eea.png';
|
|
20
|
-
|
|
21
18
|
import config from '@plone/volto/registry';
|
|
22
|
-
import { compose } from 'redux';
|
|
23
19
|
|
|
24
|
-
import
|
|
25
|
-
import
|
|
20
|
+
import eeaFlag from '@eeacms/volto-eea-design-system/../theme/themes/eea/assets/images/Header/eea.png';
|
|
21
|
+
import Header from '@eeacms/volto-eea-design-system/ui/Header/Header';
|
|
22
|
+
import { getNavigationSettings } from '@eeacms/volto-eea-website-theme/actions';
|
|
23
|
+
import EEALogo from '@eeacms/volto-eea-website-theme/components/theme/Logo';
|
|
26
24
|
|
|
27
25
|
const LazyLanguageSwitcher = loadable(() => import('./LanguageSwitcher'));
|
|
28
26
|
const EMPTY_NAVIGATION_SETTINGS = {};
|
|
@@ -32,15 +30,79 @@ function removeTrailingSlash(path) {
|
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
/**
|
|
35
|
-
*
|
|
33
|
+
* Merge backend navigation settings into the config-level menu layouts.
|
|
36
34
|
*/
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
35
|
+
function buildEnhancedLayouts(items, navigationSettings) {
|
|
36
|
+
const configLayouts = config.settings?.menuItemsLayouts || {};
|
|
37
|
+
const enhancedLayouts = { ...configLayouts };
|
|
38
|
+
|
|
39
|
+
if (!items) return enhancedLayouts;
|
|
40
|
+
|
|
41
|
+
items.forEach(() => {
|
|
42
|
+
Object.keys(navigationSettings).forEach((routeId) => {
|
|
43
|
+
const route = navigationSettings[routeId];
|
|
44
|
+
const backendSettings = {};
|
|
45
|
+
|
|
46
|
+
if (route.hideChildrenFromNavigation !== undefined) {
|
|
47
|
+
backendSettings.hideChildrenFromNavigation =
|
|
48
|
+
route.hideChildrenFromNavigation;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (route.menuItemChildrenListColumns !== undefined) {
|
|
52
|
+
backendSettings.menuItemChildrenListColumns = Array.isArray(
|
|
53
|
+
route.menuItemChildrenListColumns,
|
|
54
|
+
)
|
|
55
|
+
? route.menuItemChildrenListColumns
|
|
56
|
+
.map((val) => (typeof val === 'string' ? parseInt(val, 10) : val))
|
|
57
|
+
.filter((val) => !isNaN(val))
|
|
58
|
+
: route.menuItemChildrenListColumns;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (route.menuItemColumns !== undefined) {
|
|
62
|
+
backendSettings.menuItemColumns = route.menuItemColumns;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (Object.keys(backendSettings).length > 0) {
|
|
66
|
+
enhancedLayouts[routeId] = {
|
|
67
|
+
...enhancedLayouts[routeId],
|
|
68
|
+
...backendSettings,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
});
|
|
40
72
|
});
|
|
41
73
|
|
|
74
|
+
return enhancedLayouts;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* EEA Specific Header component.
|
|
79
|
+
*/
|
|
80
|
+
const EEAHeader = ({ pathname, token, items, history, navroot, subsite }) => {
|
|
81
|
+
// Config / static derived values
|
|
82
|
+
const { eea } = config.settings;
|
|
83
|
+
const headerOpts = eea.headerOpts || {};
|
|
84
|
+
const { logo, logoWhite } = headerOpts;
|
|
85
|
+
|
|
42
86
|
const isSubsite = subsite?.['@type'] === 'Subsite';
|
|
43
87
|
|
|
88
|
+
// Redux state
|
|
89
|
+
const dispatch = useDispatch();
|
|
90
|
+
const width = useSelector((state) => state.screen?.width);
|
|
91
|
+
|
|
92
|
+
const router_pathname = useSelector(
|
|
93
|
+
(state) => removeTrailingSlash(state.router?.location?.pathname) || '',
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const headerSettings = useSelector(
|
|
97
|
+
(state) => state.reduxAsyncConnect?.headerSettings,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const navigationSettings =
|
|
101
|
+
useSelector((state) => state.navigationSettings?.settings) ||
|
|
102
|
+
EMPTY_NAVIGATION_SETTINGS;
|
|
103
|
+
|
|
104
|
+
const updateRequest = useSelector((state) => state.content.update);
|
|
105
|
+
|
|
44
106
|
const isHomePageInverse = useSelector((state) => {
|
|
45
107
|
const layout = state.content?.data?.layout;
|
|
46
108
|
const has_home_layout =
|
|
@@ -55,85 +117,69 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
|
|
|
55
117
|
);
|
|
56
118
|
});
|
|
57
119
|
|
|
58
|
-
const
|
|
59
|
-
const headerOpts = eea.headerOpts || {};
|
|
60
|
-
const { logo, logoWhite } = headerOpts;
|
|
61
|
-
const width = useSelector((state) => state.screen?.width);
|
|
62
|
-
const dispatch = useDispatch();
|
|
63
|
-
|
|
64
|
-
const headerSettings = useSelector(
|
|
65
|
-
(state) => state.reduxAsyncConnect?.headerSettings,
|
|
66
|
-
);
|
|
120
|
+
const prevTokenRef = useRef(undefined);
|
|
67
121
|
|
|
122
|
+
// Derived / memoized values
|
|
68
123
|
const headerSearchBox =
|
|
69
124
|
headerSettings?.searchBox || eea.headerSearchBox || [];
|
|
70
|
-
const previousToken = usePrevious(token);
|
|
71
|
-
const navigationSettings =
|
|
72
|
-
useSelector((state) => state.navigationSettings?.settings) ||
|
|
73
|
-
EMPTY_NAVIGATION_SETTINGS;
|
|
74
|
-
const updateRequest = useSelector((state) => state.content.update);
|
|
75
|
-
|
|
76
|
-
// Combine navigation settings from backend with config fallback
|
|
77
|
-
const configLayouts = config.settings?.menuItemsLayouts || {};
|
|
78
|
-
const enhancedLayouts = { ...configLayouts };
|
|
79
125
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
126
|
+
const enhancedLayouts = buildEnhancedLayouts(items, navigationSettings);
|
|
127
|
+
|
|
128
|
+
// Prefer navroot.language; fall back to extracting language from pathname
|
|
129
|
+
// (validated against supportedLanguages) when navroot is not yet loaded.
|
|
130
|
+
const navrootLang = useMemo(() => {
|
|
131
|
+
const { supportedLanguages, navigationLanguage } = config.settings;
|
|
132
|
+
if (navroot?.language?.token) return navroot.language.token;
|
|
133
|
+
const supported = supportedLanguages || [];
|
|
134
|
+
const first = pathname.split('/').filter(Boolean)[0];
|
|
135
|
+
if (first === undefined) return navigationLanguage || null;
|
|
136
|
+
return supported.includes(first) ? first : null;
|
|
137
|
+
}, [navroot, pathname]);
|
|
138
|
+
|
|
139
|
+
// Normalize pathname for menu active-item matching when using
|
|
140
|
+
// navigationLanguage. Menu items come from the configured language; rewrite
|
|
141
|
+
// the current language prefix to match. E.g. navLang='en' on /fr/topics ->
|
|
142
|
+
// /en/topics. Uses navroot.language as source of truth instead of parsing
|
|
143
|
+
// the first path segment.
|
|
144
|
+
const normalizedPathname = useMemo(() => {
|
|
145
|
+
const navLang = config.settings.navigationLanguage;
|
|
146
|
+
if (!navLang || !navrootLang || navrootLang === navLang) return pathname;
|
|
92
147
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
typeof val === 'string' ? parseInt(val, 10) : val,
|
|
101
|
-
)
|
|
102
|
-
.filter((val) => !isNaN(val))
|
|
103
|
-
: route.menuItemChildrenListColumns;
|
|
104
|
-
}
|
|
148
|
+
const prefix = `/${navrootLang}`;
|
|
149
|
+
if (pathname === prefix) return `/${navLang}`;
|
|
150
|
+
if (pathname.startsWith(`${prefix}/`)) {
|
|
151
|
+
return `/${navLang}${pathname.slice(prefix.length)}`;
|
|
152
|
+
}
|
|
153
|
+
return pathname;
|
|
154
|
+
}, [pathname, navrootLang]);
|
|
105
155
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
156
|
+
const baseUrl = useMemo(() => {
|
|
157
|
+
const { settings } = config;
|
|
158
|
+
const navLang = settings.navigationLanguage;
|
|
159
|
+
let url = getBaseUrl(pathname);
|
|
110
160
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
...enhancedLayouts[routeId],
|
|
115
|
-
...backendSettings,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
}
|
|
161
|
+
if (isSubsite || !navLang || !navrootLang) {
|
|
162
|
+
return url;
|
|
163
|
+
}
|
|
121
164
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
165
|
+
// When the current navroot's language differs from the configured
|
|
166
|
+
// navigationLanguage, override the base url so navigation is fetched from
|
|
167
|
+
// the configured language root instead of the current navroot.
|
|
168
|
+
if (navLang !== navrootLang) {
|
|
169
|
+
url = `/${settings.navigationLanguage}`;
|
|
170
|
+
} else if (!url && navLang === navrootLang) {
|
|
171
|
+
url = `/${navLang}`;
|
|
172
|
+
}
|
|
173
|
+
return url;
|
|
174
|
+
}, [pathname, navrootLang, isSubsite]);
|
|
130
175
|
|
|
131
|
-
|
|
176
|
+
// Fetch navigation settings on pathname change.
|
|
177
|
+
useEffect(() => {
|
|
132
178
|
dispatch(getNavigationSettings(pathname));
|
|
133
179
|
}, [dispatch, pathname]);
|
|
134
180
|
|
|
135
|
-
//
|
|
136
|
-
|
|
181
|
+
// Re-fetch navigation settings after a content update for the current page.
|
|
182
|
+
useEffect(() => {
|
|
137
183
|
if (
|
|
138
184
|
updateRequest?.loaded &&
|
|
139
185
|
removeTrailingSlash(updateRequest?.content?.['@id'] || '') ===
|
|
@@ -143,46 +189,36 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
|
|
|
143
189
|
}
|
|
144
190
|
}, [updateRequest, dispatch, pathname]);
|
|
145
191
|
|
|
146
|
-
|
|
192
|
+
// Fetch the main navigation tree.
|
|
193
|
+
// Cases that force a fetch:
|
|
194
|
+
// 1. Language mismatch — the current navroot's language differs from the
|
|
195
|
+
// configured navigationLanguage, so the API expander's navigation (if
|
|
196
|
+
// any) is in the wrong language and must be replaced.
|
|
197
|
+
// 2. Token change — auth state affects which nav items are visible, so
|
|
198
|
+
// expander data loaded under the previous token may be stale.
|
|
199
|
+
// 3. No expander available — backend did not pre-supply navigation for
|
|
200
|
+
// this base url, so we fetch it explicitly.
|
|
201
|
+
// Otherwise the expander already supplied correct navigation; no fetch.
|
|
202
|
+
useEffect(() => {
|
|
147
203
|
const { settings } = config;
|
|
204
|
+
const navLang = settings.navigationLanguage;
|
|
205
|
+
const langMismatch = navLang && navrootLang && navrootLang !== navLang;
|
|
206
|
+
const tokenChanged = prevTokenRef.current !== token;
|
|
148
207
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
// When navigationLanguage is not configured, fetch navigation for current page language
|
|
156
|
-
// Check if navigation data needs to be fetched based on the API expander availability
|
|
157
|
-
if (!hasApiExpander('navigation', navigationBaseUrl)) {
|
|
158
|
-
dispatch(getNavigation(navigationBaseUrl, settings.navDepth));
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Additional check for token changes
|
|
162
|
-
if (token !== previousToken) {
|
|
163
|
-
dispatch(getNavigation(navigationBaseUrl, settings.navDepth));
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}, [navigationBaseUrl, token, dispatch, previousToken]);
|
|
167
|
-
|
|
168
|
-
// Normalize pathname for menu matching when using navigationLanguage
|
|
169
|
-
// This ensures menu items from the configured language match correctly even when on other language pages
|
|
170
|
-
const normalizedPathname = React.useMemo(() => {
|
|
171
|
-
const navLang = config.settings.navigationLanguage;
|
|
172
|
-
if (!navLang) {
|
|
173
|
-
return pathname;
|
|
208
|
+
if (
|
|
209
|
+
langMismatch ||
|
|
210
|
+
tokenChanged ||
|
|
211
|
+
!hasApiExpander('navigation', baseUrl)
|
|
212
|
+
) {
|
|
213
|
+
dispatch(getNavigation(baseUrl, settings.navDepth));
|
|
174
214
|
}
|
|
215
|
+
}, [dispatch, baseUrl, navrootLang, token]);
|
|
175
216
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const rest = pathParts.slice(1).join('/');
|
|
182
|
-
return rest ? `/${navLang}/${rest}` : `/${navLang}`;
|
|
183
|
-
}
|
|
184
|
-
return pathname;
|
|
185
|
-
}, [pathname]);
|
|
217
|
+
// Track the previous token value. Runs after the fetch effect so the
|
|
218
|
+
// comparison above sees the value from the prior render.
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
prevTokenRef.current = token;
|
|
221
|
+
}, [token]);
|
|
186
222
|
|
|
187
223
|
return (
|
|
188
224
|
<Header menuItems={items}>
|
|
@@ -327,6 +363,7 @@ export default compose(
|
|
|
327
363
|
(state) => ({
|
|
328
364
|
token: state.userSession.token,
|
|
329
365
|
items: state.navigation.items,
|
|
366
|
+
navroot: state.content.data?.['@components']?.navroot?.navroot,
|
|
330
367
|
subsite: state.content.data?.['@components']?.subsite,
|
|
331
368
|
}),
|
|
332
369
|
{ getNavigation },
|