volto-searchblocks 0.1.8

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.
@@ -0,0 +1,3 @@
1
+ ## 0.1.8 (2026-02-05)
2
+
3
+
@@ -0,0 +1,34 @@
1
+ {
2
+ "plugins": {
3
+ "../../core/packages/scripts/prepublish.js": {}
4
+ },
5
+ "hooks": {
6
+ "after:bump": [
7
+ "pipx run towncrier build --draft --yes --version ${version} > .changelog.draft",
8
+ "pipx run towncrier build --yes --version ${version}",
9
+ "cp ../../README.md ./ && cp CHANGELOG.md ../../CHANGELOG.md",
10
+ "python3 -c 'import json; data = json.load(open(\"../../package.json\")); data[\"version\"] = \"${version}\"; json.dump(data, open(\"../../package.json\", \"w\"), indent=2)'",
11
+ "git add ../../CHANGELOG.md ../../package.json"
12
+ ],
13
+ "after:release": "rm .changelog.draft README.md"
14
+ },
15
+ "npm": {
16
+ "publish": true
17
+ },
18
+ "plonePrePublish": {
19
+ "publish": false
20
+ },
21
+ "git": {
22
+ "changelog": "pipx run towncrier build --draft --yes --version 0.0.0",
23
+ "requireUpstream": false,
24
+ "requireCleanWorkingDir": false,
25
+ "commitMessage": "Release ${version}",
26
+ "tagName": "${version}",
27
+ "tagAnnotation": "Release ${version}"
28
+ },
29
+ "github": {
30
+ "release": false,
31
+ "releaseName": "${version}",
32
+ "releaseNotes": "cat .changelog.draft"
33
+ }
34
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ <!-- You should *NOT* be adding new change log entries to this file.
4
+ You should create a file in the news directory instead.
5
+ For helpful instructions, please see:
6
+ https://6.docs.plone.org/contributing/index.html#contributing-change-log-label
7
+ -->
8
+
9
+ <!-- towncrier release notes start -->
10
+
11
+ ## 0.1.8 (2026-02-05)
12
+
13
+ ## 0.1.5 (2026-02-03)
14
+
15
+ ## 0.1.4 (2026-02-03)
16
+
17
+ ## 0.1.3 (2026-02-03)
18
+
19
+ ## 0.1.2 (2026-02-03)
20
+
21
+ ## 0.1.1 (2026-02-03)
22
+
23
+ ## 0.1.0 (2026-02-03)
package/README.md ADDED
@@ -0,0 +1,201 @@
1
+ # Search blocks (volto-searchblocks)
2
+
3
+ A Volto add-on that provides a control panel for searching and managing content that uses specific blocks.
4
+
5
+ [![npm](https://img.shields.io/npm/v/volto-searchblocks)](https://www.npmjs.com/package/volto-searchblocks)
6
+ [![](https://img.shields.io/badge/-Storybook-ff4785?logo=Storybook&logoColor=white&style=flat-square)](https://collective.github.io/volto-searchblocks/)
7
+ [![CI](https://github.com/collective/collective-searchblocks/actions/workflows/main.yml/badge.svg)](https://github.com/collective/collective-searchblocks/actions/workflows/main.yml)
8
+
9
+
10
+ ## Features ✨
11
+
12
+ - **Search Blocks Control Panel**: Dedicated control panel view for searching content by block types
13
+ - **Table Display**: Results displayed in a sortable table with key metadata
14
+ - **Pagination**: Navigate through results with configurable page sizes (default, 50, or all)
15
+ - **Block Type Selection**: Dropdown selector for choosing which block type to search for
16
+ - **Multilingual Support**: Full i18n support with Italian translation included
17
+ - **Error Handling**: Comprehensive error displays for API failures
18
+ - **Semantic UI Integration**: Uses Volto's standard Semantic UI components for consistent styling
19
+
20
+ ## Installation
21
+
22
+ To install your project, you must choose the method appropriate to your version of Volto.
23
+
24
+
25
+ ### Volto 18 and later
26
+
27
+ Add `volto-searchblocks` to your `package.json`.
28
+
29
+ ```json
30
+ "dependencies": {
31
+ "volto-searchblocks": "*"
32
+ }
33
+ ```
34
+
35
+ Add `volto-searchblocks` to your `volto.config.js`.
36
+
37
+ ```javascript
38
+ const addons = ['volto-searchblocks'];
39
+ ```
40
+
41
+ If this package provides a Volto theme, and you want to activate it, then add the following to your `volto.config.js`.
42
+
43
+ ```javascript
44
+ const theme = 'volto-searchblocks';
45
+ ```
46
+
47
+ ### Volto 17 and earlier
48
+
49
+ Create a new Volto project.
50
+ You can skip this step if you already have one.
51
+
52
+ ```
53
+ npm install -g yo @plone/generator-volto
54
+ yo @plone/volto my-volto-project --addon volto-searchblocks
55
+ cd my-volto-project
56
+ ```
57
+
58
+ Add `volto-searchblocks` to your `package.json`.
59
+
60
+ ```JSON
61
+ "addons": [
62
+ "volto-searchblocks"
63
+ ],
64
+
65
+ "dependencies": {
66
+ "volto-searchblocks": "*"
67
+ }
68
+ ```
69
+
70
+ Download and install the new add-on.
71
+
72
+ ```
73
+ yarn install
74
+ ```
75
+
76
+ Start Volto.
77
+
78
+ ```
79
+ yarn start
80
+ ```
81
+
82
+ ## Test installation
83
+
84
+ Visit http://localhost:3000/ in a browser, login, and check the awesome new features.
85
+
86
+
87
+ ## Development
88
+
89
+ The development of this add-on is done in isolation using pnpm workspaces, the latest `mrs-developer`, and other Volto core improvements.
90
+ For these reasons, it only works with pnpm and Volto 18.
91
+
92
+
93
+ ### Prerequisites ✅
94
+
95
+ - An [operating system](https://6.docs.plone.org/install/create-project-cookieplone.html#prerequisites-for-installation) that runs all the requirements mentioned.
96
+ - [nvm](https://6.docs.plone.org/install/create-project-cookieplone.html#nvm)
97
+ - [Node.js and pnpm](https://6.docs.plone.org/install/create-project.html#node-js) 22
98
+ - [Make](https://6.docs.plone.org/install/create-project-cookieplone.html#make)
99
+ - [Git](https://6.docs.plone.org/install/create-project-cookieplone.html#git)
100
+ - [Docker](https://docs.docker.com/get-started/get-docker/) (optional)
101
+
102
+ ### Installation 🔧
103
+
104
+ 1. Clone this repository, then change your working directory.
105
+
106
+ ```shell
107
+ git clone git@github.com:collective/collective-searchblocks.git
108
+ cd collective-searchblocks/frontend
109
+ ```
110
+
111
+ 2. Install this code base.
112
+
113
+ ```shell
114
+ make install
115
+ ```
116
+
117
+
118
+ ### Make convenience commands
119
+
120
+ Run `make help` to list the available Make commands.
121
+
122
+
123
+ ### Set up development environment
124
+
125
+ Install package requirements.
126
+
127
+ ```shell
128
+ make install
129
+ ```
130
+
131
+ ### Start developing
132
+
133
+ Start the backend.
134
+
135
+ ```shell
136
+ make backend-docker-start
137
+ ```
138
+
139
+ In a separate terminal session, start the frontend.
140
+
141
+ ```shell
142
+ make start
143
+ ```
144
+
145
+ ### Lint code
146
+
147
+ Run ESlint, Prettier, and Stylelint in analyze mode.
148
+
149
+ ```shell
150
+ make lint
151
+ ```
152
+
153
+ ### Format code
154
+
155
+ Run ESlint, Prettier, and Stylelint in fix mode.
156
+
157
+ ```shell
158
+ make format
159
+ ```
160
+
161
+ ### i18n
162
+
163
+ Extract the i18n messages to locales.
164
+
165
+ ```shell
166
+ make i18n
167
+ ```
168
+
169
+ ### Unit tests
170
+
171
+ Run unit tests.
172
+
173
+ ```shell
174
+ make test
175
+ ```
176
+
177
+ ### Run Cypress tests
178
+
179
+ Run each of these steps in separate terminal sessions.
180
+
181
+ In the first session, start the frontend in development mode.
182
+
183
+ ```shell
184
+ make acceptance-frontend-dev-start
185
+ ```
186
+
187
+ In the second session, start the backend acceptance server.
188
+
189
+ ```shell
190
+ make acceptance-backend-start
191
+ ```
192
+
193
+ In the third session, start the Cypress interactive test runner.
194
+
195
+ ```shell
196
+ make acceptance-test
197
+ ```
198
+
199
+ ## License
200
+
201
+ The project is licensed under the MIT license.
@@ -0,0 +1,17 @@
1
+ module.exports = function (api) {
2
+ api.cache(true);
3
+ const presets = ['razzle'];
4
+ const plugins = [
5
+ [
6
+ 'react-intl', // React Intl extractor, required for the whole i18n infrastructure to work
7
+ {
8
+ messagesDir: './build/messages/',
9
+ },
10
+ ],
11
+ ];
12
+
13
+ return {
14
+ plugins,
15
+ presets,
16
+ };
17
+ };
@@ -0,0 +1,83 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: \n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: \n"
8
+ "Language: de\n"
9
+ "Language-Team: \n"
10
+ "Content-Type: \n"
11
+ "Content-Transfer-Encoding: \n"
12
+ "Plural-Forms: \n"
13
+
14
+ #. Default: "Back to Control Panel"
15
+ #: components/SearchBlocks/SearchBlocks
16
+ msgid "Back to Control Panel"
17
+ msgstr ""
18
+
19
+ #. Default: "Block Type"
20
+ #: components/SearchBlocks/SearchBlocks
21
+ msgid "Block Type"
22
+ msgstr ""
23
+
24
+ #. Default: "Choose a block type"
25
+ #: components/SearchBlocks/SearchBlocks
26
+ msgid "Choose a block type"
27
+ msgstr ""
28
+
29
+ #. Default: "Created"
30
+ #: components/SearchBlocks/SearchBlocks
31
+ msgid "Created"
32
+ msgstr ""
33
+
34
+ #. Default: "Loading..."
35
+ #: components/SearchBlocks/SearchBlocks
36
+ msgid "Loading"
37
+ msgstr ""
38
+
39
+ #. Default: "Modified"
40
+ #: components/SearchBlocks/SearchBlocks
41
+ msgid "Modified"
42
+ msgstr ""
43
+
44
+ #. Default: "No results found for"
45
+ #: components/SearchBlocks/SearchBlocks
46
+ msgid "No results found for"
47
+ msgstr ""
48
+
49
+ #. Default: "On this page you can see which contents on the site use a specific block"
50
+ #: components/SearchBlocks/SearchBlocks
51
+ msgid "On this page you can see which contents on the site use a specific block"
52
+ msgstr ""
53
+
54
+ #. Default: "Results"
55
+ #: components/SearchBlocks/SearchBlocks
56
+ msgid "Results"
57
+ msgstr ""
58
+
59
+ #. Default: "Review State"
60
+ #: components/SearchBlocks/SearchBlocks
61
+ msgid "Review State"
62
+ msgstr ""
63
+
64
+ #. Default: "Search blocks"
65
+ #: components/SearchBlocks/SearchBlocks
66
+ #: config/settings
67
+ msgid "Search blocks"
68
+ msgstr ""
69
+
70
+ #. Default: "Select Block Type:"
71
+ #: components/SearchBlocks/SearchBlocks
72
+ msgid "Select Block Type"
73
+ msgstr ""
74
+
75
+ #. Default: "Title"
76
+ #: components/SearchBlocks/SearchBlocks
77
+ msgid "Title"
78
+ msgstr ""
79
+
80
+ #. Default: "Type"
81
+ #: components/SearchBlocks/SearchBlocks
82
+ msgid "Type"
83
+ msgstr ""
@@ -0,0 +1,83 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: \n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: \n"
8
+ "Language: en\n"
9
+ "Language-Team: \n"
10
+ "Content-Type: \n"
11
+ "Content-Transfer-Encoding: \n"
12
+ "Plural-Forms: \n"
13
+
14
+ #. Default: "Back to Control Panel"
15
+ #: components/SearchBlocks/SearchBlocks
16
+ msgid "Back to Control Panel"
17
+ msgstr ""
18
+
19
+ #. Default: "Block Type"
20
+ #: components/SearchBlocks/SearchBlocks
21
+ msgid "Block Type"
22
+ msgstr ""
23
+
24
+ #. Default: "Choose a block type"
25
+ #: components/SearchBlocks/SearchBlocks
26
+ msgid "Choose a block type"
27
+ msgstr ""
28
+
29
+ #. Default: "Created"
30
+ #: components/SearchBlocks/SearchBlocks
31
+ msgid "Created"
32
+ msgstr ""
33
+
34
+ #. Default: "Loading..."
35
+ #: components/SearchBlocks/SearchBlocks
36
+ msgid "Loading"
37
+ msgstr ""
38
+
39
+ #. Default: "Modified"
40
+ #: components/SearchBlocks/SearchBlocks
41
+ msgid "Modified"
42
+ msgstr ""
43
+
44
+ #. Default: "No results found for"
45
+ #: components/SearchBlocks/SearchBlocks
46
+ msgid "No results found for"
47
+ msgstr ""
48
+
49
+ #. Default: "On this page you can see which contents on the site use a specific block"
50
+ #: components/SearchBlocks/SearchBlocks
51
+ msgid "On this page you can see which contents on the site use a specific block"
52
+ msgstr ""
53
+
54
+ #. Default: "Results"
55
+ #: components/SearchBlocks/SearchBlocks
56
+ msgid "Results"
57
+ msgstr ""
58
+
59
+ #. Default: "Review State"
60
+ #: components/SearchBlocks/SearchBlocks
61
+ msgid "Review State"
62
+ msgstr ""
63
+
64
+ #. Default: "Search blocks"
65
+ #: components/SearchBlocks/SearchBlocks
66
+ #: config/settings
67
+ msgid "Search blocks"
68
+ msgstr ""
69
+
70
+ #. Default: "Select Block Type:"
71
+ #: components/SearchBlocks/SearchBlocks
72
+ msgid "Select Block Type"
73
+ msgstr ""
74
+
75
+ #. Default: "Title"
76
+ #: components/SearchBlocks/SearchBlocks
77
+ msgid "Title"
78
+ msgstr ""
79
+
80
+ #. Default: "Type"
81
+ #: components/SearchBlocks/SearchBlocks
82
+ msgid "Type"
83
+ msgstr ""
@@ -0,0 +1,90 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: Plone\n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2023-05-09 11:45-0400\n"
6
+ "PO-Revision-Date: 2023-05-10 11:34-0400\n"
7
+ "Last-Translator: Leonardo J. Caballero G. <leonardocaballero@gmail.com>\n"
8
+ "Language: es\n"
9
+ "Language-Team: ES <LL@li.org>\n"
10
+ "Content-Type: text/plain; charset=utf-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
13
+ "Preferred-Encodings: utf-8\n"
14
+ "MIME-Version: 1.0\n"
15
+ "Language-Code: es\n"
16
+ "Language-Name: Español\n"
17
+ "Domain: volto\n"
18
+ "X-Is-Fallback-For: es-ar es-bo es-cl es-co es-cr es-do es-ec es-es es-sv es-gt es-hn es-mx es-ni es-pa es-py es-pe es-pr es-us es-uy es-ve\n"
19
+ "X-Generator: Poedit 2.2.1\n"
20
+
21
+ #. Default: "Back to Control Panel"
22
+ #: components/SearchBlocks/SearchBlocks
23
+ msgid "Back to Control Panel"
24
+ msgstr ""
25
+
26
+ #. Default: "Block Type"
27
+ #: components/SearchBlocks/SearchBlocks
28
+ msgid "Block Type"
29
+ msgstr ""
30
+
31
+ #. Default: "Choose a block type"
32
+ #: components/SearchBlocks/SearchBlocks
33
+ msgid "Choose a block type"
34
+ msgstr ""
35
+
36
+ #. Default: "Created"
37
+ #: components/SearchBlocks/SearchBlocks
38
+ msgid "Created"
39
+ msgstr ""
40
+
41
+ #. Default: "Loading..."
42
+ #: components/SearchBlocks/SearchBlocks
43
+ msgid "Loading"
44
+ msgstr ""
45
+
46
+ #. Default: "Modified"
47
+ #: components/SearchBlocks/SearchBlocks
48
+ msgid "Modified"
49
+ msgstr ""
50
+
51
+ #. Default: "No results found for"
52
+ #: components/SearchBlocks/SearchBlocks
53
+ msgid "No results found for"
54
+ msgstr ""
55
+
56
+ #. Default: "On this page you can see which contents on the site use a specific block"
57
+ #: components/SearchBlocks/SearchBlocks
58
+ msgid "On this page you can see which contents on the site use a specific block"
59
+ msgstr ""
60
+
61
+ #. Default: "Results"
62
+ #: components/SearchBlocks/SearchBlocks
63
+ msgid "Results"
64
+ msgstr ""
65
+
66
+ #. Default: "Review State"
67
+ #: components/SearchBlocks/SearchBlocks
68
+ msgid "Review State"
69
+ msgstr ""
70
+
71
+ #. Default: "Search blocks"
72
+ #: components/SearchBlocks/SearchBlocks
73
+ #: config/settings
74
+ msgid "Search blocks"
75
+ msgstr ""
76
+
77
+ #. Default: "Select Block Type:"
78
+ #: components/SearchBlocks/SearchBlocks
79
+ msgid "Select Block Type"
80
+ msgstr ""
81
+
82
+ #. Default: "Title"
83
+ #: components/SearchBlocks/SearchBlocks
84
+ msgid "Title"
85
+ msgstr ""
86
+
87
+ #. Default: "Type"
88
+ #: components/SearchBlocks/SearchBlocks
89
+ msgid "Type"
90
+ msgstr ""
@@ -0,0 +1,84 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: Plone\n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2025-01-16T00:00:00.000Z\n"
6
+ "PO-Revision-Date: 2025-01-16\n"
7
+ "Last-Translator: \n"
8
+ "Language: it\n"
9
+ "Language-Team: Italian\n"
10
+ "Content-Type: text/plain; charset=utf-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
13
+ "MIME-Version: 1.0\n"
14
+
15
+ #. Default: "Back to Control Panel"
16
+ #: components/SearchBlocks/SearchBlocks
17
+ msgid "Back to Control Panel"
18
+ msgstr "Torna al Pannello di Controllo"
19
+
20
+ #. Default: "Block Type"
21
+ #: components/SearchBlocks/SearchBlocks
22
+ msgid "Block Type"
23
+ msgstr "Tipo di Blocco"
24
+
25
+ #. Default: "Choose a block type"
26
+ #: components/SearchBlocks/SearchBlocks
27
+ msgid "Choose a block type"
28
+ msgstr "Scegli un tipo di blocco"
29
+
30
+ #. Default: "Created"
31
+ #: components/SearchBlocks/SearchBlocks
32
+ msgid "Created"
33
+ msgstr "Creato"
34
+
35
+ #. Default: "Loading..."
36
+ #: components/SearchBlocks/SearchBlocks
37
+ msgid "Loading"
38
+ msgstr "Caricamento in corso..."
39
+
40
+ #. Default: "Modified"
41
+ #: components/SearchBlocks/SearchBlocks
42
+ msgid "Modified"
43
+ msgstr "Modificato"
44
+
45
+ #. Default: "No results found for"
46
+ #: components/SearchBlocks/SearchBlocks
47
+ msgid "No results found for"
48
+ msgstr "Nessun risultato trovato per"
49
+
50
+ #. Default: "On this page you can see which contents on the site use a specific block"
51
+ #: components/SearchBlocks/SearchBlocks
52
+ msgid "On this page you can see which contents on the site use a specific block"
53
+ msgstr "In questa pagina puoi vedere quali contenuti del sito utilizzano un determinato blocco"
54
+
55
+ #. Default: "Results"
56
+ #: components/SearchBlocks/SearchBlocks
57
+ msgid "Results"
58
+ msgstr "Risultati"
59
+
60
+ #. Default: "Review State"
61
+ #: components/SearchBlocks/SearchBlocks
62
+ msgid "Review State"
63
+ msgstr "Stato di Revisione"
64
+
65
+ #. Default: "Search blocks"
66
+ #: components/SearchBlocks/SearchBlocks
67
+ #: config/settings
68
+ msgid "Search blocks"
69
+ msgstr "Ricerca blocchi"
70
+
71
+ #. Default: "Select Block Type:"
72
+ #: components/SearchBlocks/SearchBlocks
73
+ msgid "Select Block Type"
74
+ msgstr "Seleziona Tipo di Blocco"
75
+
76
+ #. Default: "Title"
77
+ #: components/SearchBlocks/SearchBlocks
78
+ msgid "Title"
79
+ msgstr "Titolo"
80
+
81
+ #. Default: "Type"
82
+ #: components/SearchBlocks/SearchBlocks
83
+ msgid "Type"
84
+ msgstr "Tipo"
@@ -0,0 +1,88 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: Plone\n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2023-04-06T16:01:32.969Z\n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
8
+ "Language: \n"
9
+ "Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
10
+ "Content-Type: text/plain; charset=utf-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "Plural-Forms: nplurals=1; plural=0;\n"
13
+ "MIME-Version: 1.0\n"
14
+ "Language-Code: pt_BR\n"
15
+ "Language-Name: Português do Brasil\n"
16
+ "Preferred-Encodings: utf-8\n"
17
+ "Domain: volto\n"
18
+
19
+ #. Default: "Back to Control Panel"
20
+ #: components/SearchBlocks/SearchBlocks
21
+ msgid "Back to Control Panel"
22
+ msgstr ""
23
+
24
+ #. Default: "Block Type"
25
+ #: components/SearchBlocks/SearchBlocks
26
+ msgid "Block Type"
27
+ msgstr ""
28
+
29
+ #. Default: "Choose a block type"
30
+ #: components/SearchBlocks/SearchBlocks
31
+ msgid "Choose a block type"
32
+ msgstr ""
33
+
34
+ #. Default: "Created"
35
+ #: components/SearchBlocks/SearchBlocks
36
+ msgid "Created"
37
+ msgstr ""
38
+
39
+ #. Default: "Loading..."
40
+ #: components/SearchBlocks/SearchBlocks
41
+ msgid "Loading"
42
+ msgstr ""
43
+
44
+ #. Default: "Modified"
45
+ #: components/SearchBlocks/SearchBlocks
46
+ msgid "Modified"
47
+ msgstr ""
48
+
49
+ #. Default: "No results found for"
50
+ #: components/SearchBlocks/SearchBlocks
51
+ msgid "No results found for"
52
+ msgstr ""
53
+
54
+ #. Default: "On this page you can see which contents on the site use a specific block"
55
+ #: components/SearchBlocks/SearchBlocks
56
+ msgid "On this page you can see which contents on the site use a specific block"
57
+ msgstr ""
58
+
59
+ #. Default: "Results"
60
+ #: components/SearchBlocks/SearchBlocks
61
+ msgid "Results"
62
+ msgstr ""
63
+
64
+ #. Default: "Review State"
65
+ #: components/SearchBlocks/SearchBlocks
66
+ msgid "Review State"
67
+ msgstr ""
68
+
69
+ #. Default: "Search blocks"
70
+ #: components/SearchBlocks/SearchBlocks
71
+ #: config/settings
72
+ msgid "Search blocks"
73
+ msgstr ""
74
+
75
+ #. Default: "Select Block Type:"
76
+ #: components/SearchBlocks/SearchBlocks
77
+ msgid "Select Block Type"
78
+ msgstr ""
79
+
80
+ #. Default: "Title"
81
+ #: components/SearchBlocks/SearchBlocks
82
+ msgid "Title"
83
+ msgstr ""
84
+
85
+ #. Default: "Type"
86
+ #: components/SearchBlocks/SearchBlocks
87
+ msgid "Type"
88
+ msgstr ""
@@ -0,0 +1,85 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: Plone\n"
4
+ "POT-Creation-Date: 2026-01-27T12:21:38.702Z\n"
5
+ "Last-Translator: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
6
+ "Language-Team: Plone i18n <plone-i18n@lists.sourceforge.net>\n"
7
+ "Content-Type: text/plain; charset=utf-8\n"
8
+ "Content-Transfer-Encoding: 8bit\n"
9
+ "Plural-Forms: nplurals=1; plural=0;\n"
10
+ "MIME-Version: 1.0\n"
11
+ "Language-Code: en\n"
12
+ "Language-Name: English\n"
13
+ "Preferred-Encodings: utf-8\n"
14
+ "Domain: volto\n"
15
+
16
+ #. Default: "Back to Control Panel"
17
+ #: components/SearchBlocks/SearchBlocks
18
+ msgid "Back to Control Panel"
19
+ msgstr ""
20
+
21
+ #. Default: "Block Type"
22
+ #: components/SearchBlocks/SearchBlocks
23
+ msgid "Block Type"
24
+ msgstr ""
25
+
26
+ #. Default: "Choose a block type"
27
+ #: components/SearchBlocks/SearchBlocks
28
+ msgid "Choose a block type"
29
+ msgstr ""
30
+
31
+ #. Default: "Created"
32
+ #: components/SearchBlocks/SearchBlocks
33
+ msgid "Created"
34
+ msgstr ""
35
+
36
+ #. Default: "Loading..."
37
+ #: components/SearchBlocks/SearchBlocks
38
+ msgid "Loading"
39
+ msgstr ""
40
+
41
+ #. Default: "Modified"
42
+ #: components/SearchBlocks/SearchBlocks
43
+ msgid "Modified"
44
+ msgstr ""
45
+
46
+ #. Default: "No results found for"
47
+ #: components/SearchBlocks/SearchBlocks
48
+ msgid "No results found for"
49
+ msgstr ""
50
+
51
+ #. Default: "On this page you can see which contents on the site use a specific block"
52
+ #: components/SearchBlocks/SearchBlocks
53
+ msgid "On this page you can see which contents on the site use a specific block"
54
+ msgstr ""
55
+
56
+ #. Default: "Results"
57
+ #: components/SearchBlocks/SearchBlocks
58
+ msgid "Results"
59
+ msgstr ""
60
+
61
+ #. Default: "Review State"
62
+ #: components/SearchBlocks/SearchBlocks
63
+ msgid "Review State"
64
+ msgstr ""
65
+
66
+ #. Default: "Search blocks"
67
+ #: components/SearchBlocks/SearchBlocks
68
+ #: config/settings
69
+ msgid "Search blocks"
70
+ msgstr ""
71
+
72
+ #. Default: "Select Block Type:"
73
+ #: components/SearchBlocks/SearchBlocks
74
+ msgid "Select Block Type"
75
+ msgstr ""
76
+
77
+ #. Default: "Title"
78
+ #: components/SearchBlocks/SearchBlocks
79
+ msgid "Title"
80
+ msgstr ""
81
+
82
+ #. Default: "Type"
83
+ #: components/SearchBlocks/SearchBlocks
84
+ msgid "Type"
85
+ msgstr ""
package/news/.gitkeep ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "volto-searchblocks",
3
+ "version": "0.1.8",
4
+ "description": "Additional control-panel that allow users to search which contents using a specific block",
5
+ "main": "src/index.ts",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "volto-addon",
9
+ "volto",
10
+ "plone",
11
+ "react"
12
+ ],
13
+ "author": "RedTurtle Technology",
14
+ "homepage": "https://github.com/collective/collective-searchblocks#readme",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git@github.com:collective/collective-searchblocks"
18
+ },
19
+ "publishConfig": {
20
+ "access": "public",
21
+ "registry": "https://registry.npmjs.org/"
22
+ },
23
+ "addons": [],
24
+ "theme": "",
25
+ "peerDependencies": {
26
+ "react": "^18.2.0",
27
+ "react-dom": "^18.2.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/react": "^18.3.1",
31
+ "@types/react-dom": "^18.3.1",
32
+ "release-it": "^19.0.5",
33
+ "typescript": "^5.7.3",
34
+ "@plone/scripts": "^3.10.3"
35
+ },
36
+ "scripts": {
37
+ "i18n": "rm -rf build/messages && NODE_ENV=production i18n --addon",
38
+ "dry-release": "release-it --dry-run",
39
+ "release": "release-it",
40
+ "release-major-alpha": "release-it major --preRelease=alpha",
41
+ "release-alpha": "release-it --preRelease=alpha"
42
+ }
43
+ }
File without changes
@@ -0,0 +1,27 @@
1
+ import { SEARCH_BLOCKS } from '../constants/ActionTypes';
2
+
3
+ export function searchBlocks(options = {}) {
4
+ const params = {
5
+ sort_on: 'sortable_title',
6
+ metadata_fields: ['modified', 'created'],
7
+ };
8
+
9
+ if (options.block_types) {
10
+ params.block_types = options.block_types;
11
+ }
12
+ if (options.b_size) {
13
+ params.b_size = options.b_size;
14
+ }
15
+ if (options.b_start) {
16
+ params.b_start = options.b_start;
17
+ }
18
+
19
+ return {
20
+ type: SEARCH_BLOCKS,
21
+ request: {
22
+ op: 'get',
23
+ path: '/@search-blocks',
24
+ params,
25
+ },
26
+ };
27
+ }
File without changes
@@ -0,0 +1,288 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { useDispatch, useSelector } from 'react-redux';
3
+ import { createPortal } from 'react-dom';
4
+ import { Link } from 'react-router-dom';
5
+ import { Container, Segment, Header, Table } from 'semantic-ui-react';
6
+ import { Helmet } from '@plone/volto/helpers';
7
+ import { SelectWidget } from '@plone/volto/components';
8
+ import Toolbar from '@plone/volto/components/manage/Toolbar/Toolbar';
9
+ import Icon from '@plone/volto/components/theme/Icon/Icon';
10
+ import Pagination from '@plone/volto/components/theme/Pagination/Pagination';
11
+ import Error from '@plone/volto/components/theme/Error/Error';
12
+ import backSVG from '@plone/volto/icons/back.svg';
13
+ import { useClient } from '@plone/volto/hooks';
14
+ import { useIntl, FormattedMessage, defineMessages } from 'react-intl';
15
+ import config from '@plone/volto/registry';
16
+ import { searchBlocks } from '../../actions/searchBlocks';
17
+
18
+ const messages = defineMessages({
19
+ pageTitle: {
20
+ id: 'Search blocks',
21
+ defaultMessage: 'Search blocks',
22
+ },
23
+ pageDescription: {
24
+ id: 'On this page you can see which contents on the site use a specific block',
25
+ defaultMessage:
26
+ 'On this page you can see which contents on the site use a specific block',
27
+ },
28
+ selectBlockType: {
29
+ id: 'Select Block Type',
30
+ defaultMessage: 'Select Block Type:',
31
+ },
32
+ blockTypeLabel: {
33
+ id: 'Block Type',
34
+ defaultMessage: 'Block Type',
35
+ },
36
+ chooseBlockType: {
37
+ id: 'Choose a block type',
38
+ defaultMessage: 'Choose a block type',
39
+ },
40
+ title: {
41
+ id: 'Title',
42
+ defaultMessage: 'Title',
43
+ },
44
+ type: {
45
+ id: 'Type',
46
+ defaultMessage: 'Type',
47
+ },
48
+ reviewState: {
49
+ id: 'Review State',
50
+ defaultMessage: 'Review State',
51
+ },
52
+ created: {
53
+ id: 'Created',
54
+ defaultMessage: 'Created',
55
+ },
56
+ modified: {
57
+ id: 'Modified',
58
+ defaultMessage: 'Modified',
59
+ },
60
+ results: {
61
+ id: 'Results',
62
+ defaultMessage: 'Results',
63
+ },
64
+ loading: {
65
+ id: 'Loading',
66
+ defaultMessage: 'Loading...',
67
+ },
68
+ noResults: {
69
+ id: 'No results found for',
70
+ defaultMessage: 'No results found for',
71
+ },
72
+ backToControlPanel: {
73
+ id: 'Back to Control Panel',
74
+ defaultMessage: 'Back to Control Panel',
75
+ },
76
+ });
77
+
78
+ const SearchBlocks = (props) => {
79
+ const dispatch = useDispatch();
80
+ const isClient = useClient();
81
+ const intl = useIntl();
82
+ const pathname = props.location?.pathname || '/controlpanel/blocks-search';
83
+ const [selectedBlockType, setSelectedBlockType] = useState(null);
84
+ const [currentPage, setCurrentPage] = useState(0);
85
+ const [currentPageSize, setCurrentPageSize] = useState(
86
+ config.settings.defaultPageSize,
87
+ );
88
+
89
+ const searchResults = useSelector((state) => state.searchBlocks);
90
+ const { block_types, items, total, loading, batching, b_start, error } =
91
+ searchResults;
92
+
93
+ useEffect(() => {
94
+ // Initial fetch to get block types
95
+ dispatch(
96
+ searchBlocks({
97
+ b_start: b_start * currentPageSize,
98
+ }),
99
+ );
100
+ // eslint-disable-next-line react-hooks/exhaustive-deps
101
+ }, [dispatch]);
102
+
103
+ if (error) {
104
+ return <Error error={error} />;
105
+ }
106
+
107
+ const handleSelect = (key) => {
108
+ setSelectedBlockType(key);
109
+ setCurrentPage(0);
110
+ dispatch(searchBlocks({ block_types: key }));
111
+ };
112
+
113
+ const handlePageChange = (e, { value }) => {
114
+ setCurrentPage(value);
115
+ dispatch(
116
+ searchBlocks({
117
+ block_types: selectedBlockType,
118
+ b_size: currentPageSize,
119
+ b_start: value * currentPageSize,
120
+ }),
121
+ );
122
+ };
123
+
124
+ const handlePageSizeChange = (e, { value }) => {
125
+ setCurrentPageSize(
126
+ value === intl.formatMessage({ id: 'All', defaultMessage: 'All' })
127
+ ? total
128
+ : value,
129
+ );
130
+ setCurrentPage(0);
131
+ dispatch(
132
+ searchBlocks({
133
+ block_types: selectedBlockType,
134
+ b_size:
135
+ value === intl.formatMessage({ id: 'All', defaultMessage: 'All' })
136
+ ? total
137
+ : value,
138
+ }),
139
+ );
140
+ };
141
+
142
+ return (
143
+ <Container className="view-wrapper controlpanel-blocks-search cms-ui">
144
+ <Helmet title={intl.formatMessage(messages.pageTitle)} />
145
+ <Segment.Group raised>
146
+ <Segment className="primary">
147
+ <Header as="h1">
148
+ <FormattedMessage {...messages.pageTitle} />
149
+ </Header>
150
+ <p>
151
+ <FormattedMessage {...messages.pageDescription} />
152
+ </p>
153
+ </Segment>
154
+
155
+ <Segment>
156
+ <div className="blocks-search-controls ui form">
157
+ <label style={{ display: 'block', marginBottom: '0.5rem' }}>
158
+ <FormattedMessage {...messages.selectBlockType} />
159
+ </label>
160
+ <SelectWidget
161
+ id="block_type"
162
+ title={intl.formatMessage(messages.blockTypeLabel)}
163
+ required={false}
164
+ value={selectedBlockType || ''}
165
+ onChange={(id, value) => handleSelect(value)}
166
+ choices={block_types?.map((type) => [type, type]) || []}
167
+ wrapped={false}
168
+ isClearable={false}
169
+ />
170
+ </div>
171
+ </Segment>
172
+
173
+ <Segment>
174
+ <div className="blocks-search-results">
175
+ {loading && (
176
+ <div className="loader">
177
+ <FormattedMessage {...messages.loading} />
178
+ </div>
179
+ )}
180
+
181
+ {!loading && items && items.length > 0 && (
182
+ <>
183
+ <Header as="h2">
184
+ <FormattedMessage
185
+ {...messages.results}
186
+ values={{ count: total }}
187
+ />{' '}
188
+ ({total})
189
+ </Header>
190
+ <Table celled striped>
191
+ <Table.Header>
192
+ <Table.Row>
193
+ <Table.HeaderCell>
194
+ <FormattedMessage {...messages.title} />
195
+ </Table.HeaderCell>
196
+ <Table.HeaderCell>
197
+ <FormattedMessage {...messages.type} />
198
+ </Table.HeaderCell>
199
+ <Table.HeaderCell>
200
+ <FormattedMessage {...messages.reviewState} />
201
+ </Table.HeaderCell>
202
+ <Table.HeaderCell>
203
+ <FormattedMessage {...messages.created} />
204
+ </Table.HeaderCell>
205
+ <Table.HeaderCell>
206
+ <FormattedMessage {...messages.modified} />
207
+ </Table.HeaderCell>
208
+ </Table.Row>
209
+ </Table.Header>
210
+ <Table.Body>
211
+ {items.map((item) => (
212
+ <Table.Row key={item['@id']}>
213
+ <Table.Cell>
214
+ <a href={item['@id']}>{item.title}</a>
215
+ </Table.Cell>
216
+ <Table.Cell>{item['@type']}</Table.Cell>
217
+ <Table.Cell>{item.review_state}</Table.Cell>
218
+ <Table.Cell>
219
+ {item.created
220
+ ? new Date(item.created).toLocaleDateString()
221
+ : '-'}
222
+ </Table.Cell>
223
+ <Table.Cell>
224
+ {item.modified
225
+ ? new Date(item.modified).toLocaleDateString()
226
+ : '-'}
227
+ </Table.Cell>
228
+ </Table.Row>
229
+ ))}
230
+ </Table.Body>
231
+ </Table>
232
+
233
+ {/* Pagination using Volto component */}
234
+ {batching && (
235
+ <Pagination
236
+ current={currentPage}
237
+ total={Math.ceil(total / currentPageSize)}
238
+ pageSize={currentPageSize}
239
+ pageSizes={[
240
+ config.settings.defaultPageSize,
241
+ 50,
242
+ intl.formatMessage({ id: 'All', defaultMessage: 'All' }),
243
+ ]}
244
+ onChangePage={handlePageChange}
245
+ onChangePageSize={handlePageSizeChange}
246
+ />
247
+ )}
248
+ </>
249
+ )}
250
+
251
+ {!loading && selectedBlockType && items.length === 0 && (
252
+ <p>
253
+ <FormattedMessage
254
+ {...messages.noResults}
255
+ values={{ blockType: selectedBlockType }}
256
+ />{' '}
257
+ {selectedBlockType}.
258
+ </p>
259
+ )}
260
+ </div>
261
+ </Segment>
262
+ </Segment.Group>
263
+
264
+ {isClient &&
265
+ createPortal(
266
+ <Toolbar
267
+ pathname={pathname}
268
+ hideDefaultViewButtons
269
+ inner={
270
+ <>
271
+ <Link to="/controlpanel" className="item">
272
+ <Icon
273
+ name={backSVG}
274
+ className="contents circled"
275
+ size="30px"
276
+ title={intl.formatMessage(messages.backToControlPanel)}
277
+ />
278
+ </Link>
279
+ </>
280
+ }
281
+ />,
282
+ document.getElementById('toolbar'),
283
+ )}
284
+ </Container>
285
+ );
286
+ };
287
+
288
+ export default SearchBlocks;
@@ -0,0 +1,26 @@
1
+ import type { ConfigType } from '@plone/registry';
2
+ import { defineMessages } from 'react-intl';
3
+ import cardsSVG from '@plone/volto/icons/cards.svg';
4
+
5
+ const messages = defineMessages({
6
+ controlPanelTitle: {
7
+ id: 'Search blocks',
8
+ defaultMessage: 'Search blocks',
9
+ },
10
+ });
11
+
12
+ export default function install(config: ConfigType) {
13
+ config.settings.controlpanels = [
14
+ ...config.settings.controlpanels,
15
+ {
16
+ '@id': '/search-blocks',
17
+ group: 'General',
18
+ title: messages.controlPanelTitle.defaultMessage,
19
+ },
20
+ ];
21
+ config.settings.controlPanelsIcons = {
22
+ ...config.settings.controlPanelsIcons,
23
+ 'blocks-search': cardsSVG,
24
+ };
25
+ return config;
26
+ }
@@ -0,0 +1,3 @@
1
+ export const SEARCH_BLOCKS = 'SEARCH_BLOCKS';
2
+ export const SEARCH_BLOCKS_SUCCESS = 'SEARCH_BLOCKS_SUCCESS';
3
+ export const SEARCH_BLOCKS_FAIL = 'SEARCH_BLOCKS_FAIL';
package/src/index.ts ADDED
@@ -0,0 +1,28 @@
1
+ import type { ConfigType } from '@plone/registry';
2
+ import installSettings from './config/settings';
3
+
4
+ import { searchBlocks } from './actions/searchBlocks';
5
+ import searchBlocksReducer from './reducers/searchBlocks';
6
+ import SearchBlocks from './components/SearchBlocks/SearchBlocks';
7
+
8
+ function applyConfig(config: ConfigType) {
9
+ installSettings(config);
10
+
11
+ config.addonReducers = {
12
+ ...config.addonReducers,
13
+ searchBlocks: searchBlocksReducer,
14
+ };
15
+
16
+ config.addonRoutes = [
17
+ ...(config.addonRoutes || []),
18
+ {
19
+ path: '/controlpanel/search-blocks',
20
+ component: SearchBlocks,
21
+ },
22
+ ];
23
+
24
+ return config;
25
+ }
26
+
27
+ export default applyConfig;
28
+ export { searchBlocks };
@@ -0,0 +1,51 @@
1
+ import {
2
+ SEARCH_BLOCKS,
3
+ SEARCH_BLOCKS_SUCCESS,
4
+ SEARCH_BLOCKS_FAIL,
5
+ } from '../constants/ActionTypes';
6
+
7
+ const initialState = {
8
+ error: null,
9
+ items: [],
10
+ total: 0,
11
+ block_types: [],
12
+ batching: null,
13
+ b_start: 0,
14
+ loaded: false,
15
+ loading: false,
16
+ };
17
+
18
+ export default function searchBlocks(state = initialState, action = {}) {
19
+ switch (action.type) {
20
+ case SEARCH_BLOCKS:
21
+ return {
22
+ ...state,
23
+ error: null,
24
+ loading: true,
25
+ loaded: false,
26
+ };
27
+ case SEARCH_BLOCKS_SUCCESS:
28
+ return {
29
+ ...state,
30
+ error: null,
31
+ items: action.result.items || [],
32
+ total: action.result.items_total || 0,
33
+ block_types: action.result.block_types || [],
34
+ batching: action.result.batching || null,
35
+ b_start: action.result.b_start || 0,
36
+ loaded: true,
37
+ loading: false,
38
+ };
39
+ case SEARCH_BLOCKS_FAIL:
40
+ return {
41
+ ...state,
42
+ error: action.error,
43
+ items: [],
44
+ total: 0,
45
+ loaded: false,
46
+ loading: false,
47
+ };
48
+ default:
49
+ return state;
50
+ }
51
+ }
package/towncrier.toml ADDED
@@ -0,0 +1,33 @@
1
+ [tool.towncrier]
2
+ filename = "CHANGELOG.md"
3
+ directory = "news/"
4
+ title_format = "## {version} ({project_date})"
5
+ underlines = ["", "", ""]
6
+ template = "./node_modules/@plone/scripts/templates/towncrier_template.jinja"
7
+ start_string = "<!-- towncrier release notes start -->\n"
8
+ issue_format = "[#{issue}](https://github.com/collective/collective-searchblocks/issue/{issue})"
9
+
10
+ [[tool.towncrier.type]]
11
+ directory = "breaking"
12
+ name = "Breaking"
13
+ showcontent = true
14
+
15
+ [[tool.towncrier.type]]
16
+ directory = "feature"
17
+ name = "Feature"
18
+ showcontent = true
19
+
20
+ [[tool.towncrier.type]]
21
+ directory = "bugfix"
22
+ name = "Bugfix"
23
+ showcontent = true
24
+
25
+ [[tool.towncrier.type]]
26
+ directory = "internal"
27
+ name = "Internal"
28
+ showcontent = true
29
+
30
+ [[tool.towncrier.type]]
31
+ directory = "documentation"
32
+ name = "Documentation"
33
+ showcontent = true
package/tsconfig.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ "esModuleInterop": true,
4
+ "skipLibCheck": true,
5
+ "target": "es2022",
6
+ "allowJs": true,
7
+ "resolveJsonModule": true,
8
+ "moduleDetection": "force",
9
+ "isolatedModules": true,
10
+ "verbatimModuleSyntax": true,
11
+ "module": "preserve",
12
+ "noEmit": true,
13
+ "lib": ["es2022", "dom", "dom.iterable"],
14
+ "jsx": "react-jsx",
15
+ "paths": {
16
+ "@plone/volto/*": ["../../core/packages/volto/src/*"],
17
+ "volto-searchblocks/*": ["./src/*"]
18
+ }
19
+ },
20
+ "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"],
21
+ "exclude": [
22
+ "node_modules",
23
+ "build",
24
+ "public",
25
+ "coverage",
26
+ "**/*.test.{js,jsx,ts,tsx}",
27
+ "**/*.spec.{js,jsx,ts,tsx}",
28
+ "**/*.stories.{js,jsx,ts,tsx}"
29
+ ]
30
+ }