{"_id":"@eeacms/volto-redirector","_rev":"4-2323cd1994e4872e191903c97cb9302f","name":"@eeacms/volto-redirector","dist-tags":{"latest":"1.0.1"},"versions":{"0.2.0":{"name":"@eeacms/volto-redirector","version":"0.2.0","keywords":["volto-addon","volto","plone","react"],"author":{"name":"European Environment Agency: IDM2 A-Team"},"license":"MIT","_id":"@eeacms/volto-redirector@0.2.0","maintainers":[{"name":"demarant","email":"eeacms@gmail.com"},{"name":"avoinea","email":"contact@avoinea.com"},{"name":"tiberiuichim","email":"tiberiu.ichim@eaudeweb.ro"},{"name":"zotya","email":"zoltan.szabo@eaudeweb.ro"},{"name":"alecghica","email":"alecghica@gmail.com"},{"name":"eea-jenkins","email":"eea-jenkins-npm@roles.eea.eionet.europa.eu"},{"name":"razvan.miu","email":"miu.razvan28@gmail.com"},{"name":"ichimdav","email":"ichim.david@gmail.com"},{"name":"valentinab25","email":"valentina.balan@gmail.com"},{"name":"nileshgulia1","email":"nileshgulia@gmail.com"}],"homepage":"https://github.com/eea/volto-redirector","bugs":{"url":"https://github.com/eea/volto-redirector/issues"},"dist":{"shasum":"411f6ce79d5e903b8e31c6f3e1097023a19d2f24","tarball":"https://registry.npmjs.org/@eeacms/volto-redirector/-/volto-redirector-0.2.0.tgz","fileCount":30,"integrity":"sha512-hmlCXOL4NA5xQZPSSbADvyN2cKKWP2P9zCBCmsIqYiCFfIZNDxixADq9tuMZ/yt+qH/1yj+m8akjypCms4jnRQ==","signatures":[{"sig":"MEUCIHjsxp2xYAhp0LrsiQhhHLNbEENfOZczj+vVAqQCVOd7AiEAvxD8HZfdGvKfI+jyOcQaQz489JxTWYpKK+HyrJOQ10U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":92702},"main":"src/index.js","gitHead":"3090bccd64b03b4b235c02bbad7e29865d3e3dc0","scripts":{"i18n":"make i18n","lint":"make lint","test":"make test","prepare":"husky install","release":"release-it","lint:fix":"make lint-fix","prettier":"make prettier","test:fix":"make test-update","bootstrap":"npm install -g ejs; npm link ejs; node bootstrap","stylelint":"make stylelint","pre-commit":"yarn stylelint:fix && yarn prettier:fix && yarn lint:fix","cypress:run":"make cypress-run","cypress:open":"make cypress-open","prettier:fix":"make prettier-fix","release-beta":"release-it --preRelease=beta","stylelint:fix":"make stylelint-fix","release-major-beta":"release-it major --preRelease=beta","stylelint:overrides":"make stylelint-overrides"},"_npmUser":{"name":"eea-jenkins","email":"eea-jenkins-npm@roles.eea.eionet.europa.eu"},"repository":{"url":"git+ssh://git@github.com/eea/volto-redirector.git","type":"git"},"_npmVersion":"8.19.4","description":"@eeacms/volto-redirector: Volto add-on","directories":{},"lint-staged":{"src/**/*.{jsx}":["make i18n"],"src/**/*.overrides":["make stylelint-fix"],"src/**/*.{css,less}":["make stylelint-fix"],"theme/**/*.overrides":["make stylelint-fix"],"theme/**/*.{css,less}":["make stylelint-fix"],"src/**/*.{js,jsx,ts,tsx,json}":["make lint-fix","make prettier-fix"]},"_nodeVersion":"16.20.2","_hasShrinkwrap":false,"devDependencies":{"md5":"^2.3.0","husky":"^8.0.3","cypress":"13.1.0","lint-staged":"^14.0.1","@plone/scripts":"*","cypress-fail-fast":"^5.0.1","@cypress/code-coverage":"^3.10.0","babel-plugin-transform-class-properties":"^6.24.1"},"_npmOperationalInternal":{"tmp":"tmp/volto-redirector_0.2.0_1764364342837_0.6012408310475956","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@eeacms/volto-redirector","version":"0.3.0","keywords":["volto-addon","volto","plone","react"],"author":{"name":"European Environment Agency: IDM2 A-Team"},"license":"MIT","_id":"@eeacms/volto-redirector@0.3.0","maintainers":[{"name":"demarant","email":"eeacms@gmail.com"},{"name":"avoinea","email":"contact@avoinea.com"},{"name":"tiberiuichim","email":"tiberiu.ichim@eaudeweb.ro"},{"name":"zotya","email":"zoltan.szabo@eaudeweb.ro"},{"name":"alecghica","email":"alecghica@gmail.com"},{"name":"eea-jenkins","email":"eea-jenkins-npm@roles.eea.eionet.europa.eu"},{"name":"razvan.miu","email":"miu.razvan28@gmail.com"},{"name":"ichimdav","email":"ichim.david@gmail.com"},{"name":"valentinab25","email":"valentina.balan@gmail.com"},{"name":"nileshgulia1","email":"nileshgulia@gmail.com"}],"homepage":"https://github.com/eea/volto-redirector","bugs":{"url":"https://github.com/eea/volto-redirector/issues"},"dist":{"shasum":"f22b9a74caea2b7e3a37db54ac521d8e12ca3135","tarball":"https://registry.npmjs.org/@eeacms/volto-redirector/-/volto-redirector-0.3.0.tgz","fileCount":30,"integrity":"sha512-CdYebiI/DXNFO2ziKusXp3/jeVKwIq3Az0Xy/J1/BWiWHdC/1MI6GPuc3Rrn7ijUUg/eG6Mi6CWqOj/oMwKQ1g==","signatures":[{"sig":"MEUCIAia4M3f4h6NkXi0YLkB7BOZP0SBsHQ2hZeQgP3Zs8y2AiEA0Je00R3QvLDHg3DJZvX+gR/InfDFcnTmp8CjMNpn6dg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":125108},"main":"src/index.js","gitHead":"848fb6ec445f1ec17102ffc8bc812221215b3e09","scripts":{"i18n":"make i18n","lint":"make lint","test":"make test","prepare":"husky install","release":"release-it","lint:fix":"make lint-fix","prettier":"make prettier","test:fix":"make test-update","bootstrap":"npm install -g ejs; npm link ejs; node bootstrap","stylelint":"make stylelint","pre-commit":"yarn stylelint:fix && yarn prettier:fix && yarn lint:fix","cypress:run":"make cypress-run","cypress:open":"make cypress-open","prettier:fix":"make prettier-fix","release-beta":"release-it --preRelease=beta","stylelint:fix":"make stylelint-fix","release-major-beta":"release-it major --preRelease=beta","stylelint:overrides":"make stylelint-overrides"},"_npmUser":{"name":"eea-jenkins","email":"eea-jenkins-npm@roles.eea.eionet.europa.eu"},"repository":{"url":"git+ssh://git@github.com/eea/volto-redirector.git","type":"git"},"_npmVersion":"8.19.4","description":"@eeacms/volto-redirector: Volto add-on","directories":{},"lint-staged":{"src/**/*.{jsx}":["make i18n"],"src/**/*.overrides":["make stylelint-fix"],"src/**/*.{css,less}":["make stylelint-fix"],"theme/**/*.overrides":["make stylelint-fix"],"theme/**/*.{css,less}":["make stylelint-fix"],"src/**/*.{js,jsx,ts,tsx,json}":["make lint-fix","make prettier-fix"]},"_nodeVersion":"16.20.2","_hasShrinkwrap":false,"devDependencies":{"md5":"^2.3.0","husky":"^8.0.3","cypress":"13.1.0","lint-staged":"^14.0.1","@plone/scripts":"*","cypress-fail-fast":"^5.0.1","@cypress/code-coverage":"^3.10.0","babel-plugin-transform-class-properties":"^6.24.1"},"_npmOperationalInternal":{"tmp":"tmp/volto-redirector_0.3.0_1766186545036_0.2434367422929513","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@eeacms/volto-redirector","version":"1.0.0","keywords":["volto-addon","volto","plone","react"],"author":{"name":"European Environment Agency: IDM2 A-Team"},"license":"MIT","_id":"@eeacms/volto-redirector@1.0.0","maintainers":[{"name":"demarant","email":"eeacms@gmail.com"},{"name":"avoinea","email":"contact@avoinea.com"},{"name":"tiberiuichim","email":"tiberiu.ichim@eaudeweb.ro"},{"name":"zotya","email":"zoltan.szabo@eaudeweb.ro"},{"name":"alecghica","email":"alecghica@gmail.com"},{"name":"eea-jenkins","email":"eea-jenkins-npm@roles.eea.eionet.europa.eu"},{"name":"razvan.miu","email":"miu.razvan28@gmail.com"},{"name":"ichimdav","email":"ichim.david@gmail.com"},{"name":"valentinab25","email":"valentina.balan@gmail.com"},{"name":"nileshgulia1","email":"nileshgulia@gmail.com"}],"homepage":"https://github.com/eea/volto-redirector","bugs":{"url":"https://github.com/eea/volto-redirector/issues"},"dist":{"shasum":"70f221e21e7816fe447bd12aa58d9794db0827e9","tarball":"https://registry.npmjs.org/@eeacms/volto-redirector/-/volto-redirector-1.0.0.tgz","fileCount":30,"integrity":"sha512-aPTAe7KlUkUCQLdTvGz6/a3Gcan4zpOeP/1O9g1lcQVQCrkZA1A3dUKv/LdmoM4ULcRlyuWrh5Pr6vTVlmCZ2w==","signatures":[{"sig":"MEYCIQD0hO5if4mEFvQPjlr6O1pmgTX8Zld2gQdbACCFFGtSzQIhAKahQJmtYGA14d83Gnon7W6QVQgt8h+aqYcAj44jggWz","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":126561},"main":"src/index.js","gitHead":"8caacb4267d5456945dec26f456a2e3641b30363","scripts":{"i18n":"make i18n","lint":"make lint","test":"make test","prepare":"husky install","release":"release-it","lint:fix":"make lint-fix","prettier":"make prettier","test:fix":"make test-update","bootstrap":"npm install -g ejs; npm link ejs; node bootstrap","stylelint":"make stylelint","pre-commit":"yarn stylelint:fix && yarn prettier:fix && yarn lint:fix","cypress:run":"make cypress-run","cypress:open":"make cypress-open","prettier:fix":"make prettier-fix","release-beta":"release-it --preRelease=beta","stylelint:fix":"make stylelint-fix","release-major-beta":"release-it major --preRelease=beta","stylelint:overrides":"make stylelint-overrides"},"_npmUser":{"name":"eea-jenkins","email":"eea-jenkins-npm@roles.eea.eionet.europa.eu"},"repository":{"url":"git+ssh://git@github.com/eea/volto-redirector.git","type":"git"},"_npmVersion":"8.19.4","description":"@eeacms/volto-redirector: Volto add-on","directories":{},"lint-staged":{"src/**/*.{jsx}":["make i18n"],"src/**/*.overrides":["make stylelint-fix"],"src/**/*.{css,less}":["make stylelint-fix"],"theme/**/*.overrides":["make stylelint-fix"],"theme/**/*.{css,less}":["make stylelint-fix"],"src/**/*.{js,jsx,ts,tsx,json}":["make lint-fix","make prettier-fix"]},"_nodeVersion":"16.20.2","_hasShrinkwrap":false,"devDependencies":{"md5":"^2.3.0","husky":"^8.0.3","cypress":"13.1.0","lint-staged":"^14.0.1","@plone/scripts":"*","cypress-fail-fast":"^5.0.1","@cypress/code-coverage":"^3.10.0","babel-plugin-transform-class-properties":"^6.24.1"},"_npmOperationalInternal":{"tmp":"tmp/volto-redirector_1.0.0_1774455099123_0.940065659337068","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@eeacms/volto-redirector","version":"1.0.1","description":"@eeacms/volto-redirector: Volto add-on","main":"src/index.js","author":{"name":"European Environment Agency: IDM2 A-Team"},"license":"MIT","homepage":"https://github.com/eea/volto-redirector","keywords":["volto-addon","volto","plone","react"],"repository":{"type":"git","url":"git+ssh://git@github.com/eea/volto-redirector.git"},"devDependencies":{"@cypress/code-coverage":"^3.10.0","@plone/scripts":"*","babel-plugin-transform-class-properties":"^6.24.1","cypress":"13.1.0","cypress-fail-fast":"^5.0.1","husky":"^8.0.3","lint-staged":"^14.0.1","md5":"^2.3.0"},"lint-staged":{"src/**/*.{js,jsx,ts,tsx,json}":["make lint-fix","make prettier-fix"],"src/**/*.{jsx}":["make i18n"],"theme/**/*.{css,less}":["make stylelint-fix"],"src/**/*.{css,less}":["make stylelint-fix"],"theme/**/*.overrides":["make stylelint-fix"],"src/**/*.overrides":["make stylelint-fix"]},"scripts":{"prepare":"husky install","release":"release-it","release-major-beta":"release-it major --preRelease=beta","release-beta":"release-it --preRelease=beta","bootstrap":"npm install -g ejs; npm link ejs; node bootstrap","test":"make test","test:fix":"make test-update","pre-commit":"yarn stylelint:fix && yarn prettier:fix && yarn lint:fix","stylelint":"make stylelint","stylelint:overrides":"make stylelint-overrides","stylelint:fix":"make stylelint-fix","prettier":"make prettier","prettier:fix":"make prettier-fix","lint":"make lint","lint:fix":"make lint-fix","i18n":"make i18n","cypress:run":"make cypress-run","cypress:open":"make cypress-open"},"_id":"@eeacms/volto-redirector@1.0.1","gitHead":"145aa5e056b1b6cfe416cb5f12f9d6c830538caa","bugs":{"url":"https://github.com/eea/volto-redirector/issues"},"_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-Pe1YabSQYEJTQEli+uSs0nTgMYCY5HNlLcc4iRFVrwg7yz3JcRxPtJ3Zx2boHYlwOAQbuvYj/cHu2sEN7Y/qSg==","shasum":"09f1cfc4fa8c991b17acd9087f407b9b2313dfca","tarball":"https://registry.npmjs.org/@eeacms/volto-redirector/-/volto-redirector-1.0.1.tgz","fileCount":30,"unpackedSize":128005,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDO+JQhirwkpVJaS724pP1IHbwgujiILAWxDKLVSxP5mQIgV0KfCeIC6YdTet/nRLdg/nuHnbQmZx2R+AopQMvZl8k="}]},"_npmUser":{"name":"eea-jenkins","email":"eea-jenkins-npm@roles.eea.eionet.europa.eu"},"directories":{},"maintainers":[{"name":"demarant","email":"eeacms@gmail.com"},{"name":"avoinea","email":"contact@avoinea.com"},{"name":"tiberiuichim","email":"tiberiu.ichim@eaudeweb.ro"},{"name":"zotya","email":"zoltan.szabo@eaudeweb.ro"},{"name":"alecghica","email":"alecghica@gmail.com"},{"name":"eea-jenkins","email":"eea-jenkins-npm@roles.eea.eionet.europa.eu"},{"name":"razvan.miu","email":"miu.razvan28@gmail.com"},{"name":"ichimdav","email":"ichim.david@gmail.com"},{"name":"valentinab25","email":"valentina.balan@gmail.com"},{"name":"nileshgulia1","email":"nileshgulia@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/volto-redirector_1.0.1_1775725190906_0.9475603320802202"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-28T21:12:22.770Z","modified":"2026-04-09T08:59:51.350Z","0.2.0":"2025-11-28T21:12:23.108Z","0.3.0":"2025-12-19T23:22:25.187Z","1.0.0":"2026-03-25T16:11:39.334Z","1.0.1":"2026-04-09T08:59:51.043Z"},"bugs":{"url":"https://github.com/eea/volto-redirector/issues"},"author":{"name":"European Environment Agency: IDM2 A-Team"},"license":"MIT","homepage":"https://github.com/eea/volto-redirector","keywords":["volto-addon","volto","plone","react"],"repository":{"type":"git","url":"git+ssh://git@github.com/eea/volto-redirector.git"},"description":"@eeacms/volto-redirector: Volto add-on","maintainers":[{"name":"demarant","email":"eeacms@gmail.com"},{"name":"avoinea","email":"contact@avoinea.com"},{"name":"tiberiuichim","email":"tiberiu.ichim@eaudeweb.ro"},{"name":"zotya","email":"zoltan.szabo@eaudeweb.ro"},{"name":"alecghica","email":"alecghica@gmail.com"},{"name":"eea-jenkins","email":"eea-jenkins-npm@roles.eea.eionet.europa.eu"},{"name":"razvan.miu","email":"miu.razvan28@gmail.com"},{"name":"ichimdav","email":"ichim.david@gmail.com"},{"name":"valentinab25","email":"valentina.balan@gmail.com"},{"name":"nileshgulia1","email":"nileshgulia@gmail.com"}],"readme":"# volto-redirector\n\n[![Releases](https://img.shields.io/github/v/release/eea/volto-redirector)](https://github.com/eea/volto-redirector/releases)\n\n[![Pipeline](https://ci.eionet.europa.eu/buildStatus/icon?job=volto-addons%2Fvolto-redirector%2Fmaster&subject=master)](https://ci.eionet.europa.eu/view/Github/job/volto-addons/job/volto-redirector/job/master/display/redirect)\n[![Lines of Code](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-redirector&metric=ncloc)](https://sonarqube.eea.europa.eu/dashboard?id=volto-redirector)\n[![Coverage](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-redirector&metric=coverage)](https://sonarqube.eea.europa.eu/dashboard?id=volto-redirector)\n[![Bugs](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-redirector&metric=bugs)](https://sonarqube.eea.europa.eu/dashboard?id=volto-redirector)\n[![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-redirector&metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-redirector)\n\n[![Pipeline](https://ci.eionet.europa.eu/buildStatus/icon?job=volto-addons%2Fvolto-redirector%2Fdevelop&subject=develop)](https://ci.eionet.europa.eu/view/Github/job/volto-addons/job/volto-redirector/job/develop/display/redirect)\n[![Lines of Code](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-redirector&branch=develop&metric=ncloc)](https://sonarqube.eea.europa.eu/dashboard?id=volto-redirector&branch=develop)\n[![Coverage](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-redirector&branch=develop&metric=coverage)](https://sonarqube.eea.europa.eu/dashboard?id=volto-redirector&branch=develop)\n[![Bugs](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-redirector&branch=develop&metric=bugs)](https://sonarqube.eea.europa.eu/dashboard?id=volto-redirector&branch=develop)\n[![Duplicated Lines (%)](https://sonarqube.eea.europa.eu/api/project_badges/measure?project=volto-redirector&branch=develop&metric=duplicated_lines_density)](https://sonarqube.eea.europa.eu/dashboard?id=volto-redirector&branch=develop)\n\n\n[Volto](https://github.com/plone/volto) add-on\n\n## Demo\n\n<video src=\"https://github.com/user-attachments/assets/d8778ada-785e-43b7-a56d-1cfdda8a8cb3\" controls width=\"100%\"></video>\n\n## Features\n\n### Control Panel Features\n\n- **Redirects Management**: Full CRUD interface for managing URL redirects stored in Redis\n- **Real-time Statistics**: Animated statistics boxes showing:\n  - Total redirects / search results\n  - Internal redirects (paths starting with `/`)\n  - External redirects (full URLs with `http://` or `https://`)\n  - Gone redirects (HTTP 410 - permanently deleted content)\n- **Add Redirects**: Create new redirects with validation:\n  - Old URL must start with `/`\n  - New URL can be relative (`/path`), absolute (`https://example.com`), or empty (HTTP 410)\n  - Automatic whitespace trimming\n  - Prevention of self-redirects\n- **Remove Redirects**: Bulk delete multiple redirects at once with \"Select All\" checkbox\n- **CSV Import/Export**:\n  - Import redirects from CSV files via drag-and-drop or file browser\n  - Export selected redirects to CSV for backup or migration\n  - Automatic validation and error reporting\n- **Advanced Search**: Search by old or new URL path with regex support and search scope selector:\n  - Search scope: Old URL, New URL, or Both URLs\n  - Simple search: `/themes` (finds in both old and new URLs)\n  - External URLs: `example.com` (finds redirects to external sites)\n  - Starts with: `^/publications`\n  - Ends with: `.*\\.pdf$`\n  - Complex patterns: `.*/[0-9]{4}/.*`\n- **Pagination**: Browse through large datasets with configurable page sizes (10, 25, 50, 100, 500, 1000)\n- **Performance**: Handles 100,000+ redirects with ~2 second statistics load time\n- **Responsive UI**: Compact table design with tooltips for long URLs\n\n### HTTP 410 Gone Support\n\n- **Custom 410 Page**: Beautiful error page for permanently deleted content\n- **Wayback Machine Integration**: Link to archived versions via Internet Archive\n- **User-friendly Messages**: Clear communication about deleted resources\n\n### Technical Features\n\n- **Redis Storage**: High-performance Redis backend for fast lookups\n- **REST API Integration**: Uses `@redirects` and `@redirects-statistics` endpoints\n- **Progressive Loading**: Statistics load asynchronously without blocking the UI\n- **Countup Animations**: Engaging number animations while loading statistics\n- **Error Handling**: Graceful handling of failed operations with user feedback\n\n## Backend Requirements\n\nThis addon requires the `eea.api.redirector` Plone backend package to be installed and configured:\n\n1. Install `eea.api.redirector` in your Plone backend\n2. Configure Redis connection via environment variables:\n   - `REDIS_SERVER`: Redis server address (default: localhost)\n   - `REDIS_PORT`: Redis server port (default: 6379)\n   - `REDIS_DB`: Redis database index (default: 0)\n   - `REDIS_TIMEOUT`: Connection timeout in seconds (default: 5)\n\n## Usage\n\nAfter installation, the EEA Redirects control panel will be available at:\n\n**Site Setup → EEA Redirects** (`/controlpanel/eea-redirects`)\n\n### Adding a Redirect\n\n1. Navigate to the EEA Redirects control panel\n2. Enter the **Old URL Path**:\n   - Must start with `/`\n   - Example: `/old-page` or `/news/2023/article`\n3. Enter the **New URL Path** (optional - leave empty for HTTP 410):\n   - Relative path: `/new-page`\n   - Absolute URL: `https://example.com/page`\n   - Empty: Leave blank to mark as permanently deleted (HTTP 410 Gone)\n4. Click **Add**\n\nThe redirect will be immediately added to Redis and appear in the list.\n\n### Marking Content as Deleted (HTTP 410)\n\nTo indicate that a page has been permanently deleted:\n\n1. Enter the old URL path\n2. Leave the new URL path **empty**\n3. Click **Add**\n\nWhen users visit this URL, they'll see a custom 410 Gone page with:\n- Explanation that the content no longer exists\n- Link to view archived versions via Wayback Machine\n- Helpful navigation options\n\n### Searching Redirects\n\nUse the search box to filter redirects by old or new URL path. Supports both simple and regex patterns:\n\n**Simple search (searches both old and new URLs):**\n- `/themes` - Find all redirects with \"/themes\" in old or new URL\n- `/publications` - Find all redirects with \"/publications\"\n- `example.com` - Find all redirects to example.com\n- `https://` - Find all external redirects\n\n**Regex patterns:**\n- `^/publications` - Old URLs starting with \"/publications\"\n- `.*\\.pdf$` - URLs ending with \".pdf\"\n- `^/news/[0-9]{4}/` - News items from specific years\n- `/environmental-.*` - URLs containing \"environmental-\"\n\nClick **Search** to filter results. Statistics will update to reflect the filtered results.\n\n**Use cases:**\n- Find all redirects pointing to a specific domain: `example.com`\n- Find all internal redirects to archive: `/archive`\n- Find all broken external redirects: `http://old-domain.com`\n\n### Removing Redirects\n\n1. Check the checkboxes next to the redirects you want to remove (or use \"Select All\" checkbox in table header)\n2. Click **Remove selected**\n3. Confirm the deletion\n\nMultiple redirects can be deleted at once. The \"Select All\" checkbox in the table header allows you to quickly select all redirects on the current page.\n\n### Importing Redirects from CSV\n\nBulk import redirects from a CSV file:\n\n1. Navigate to the \"Add a new redirect\" section\n2. **Drag and drop** a CSV file onto the drop zone, OR click to browse and select a file\n3. The file will be automatically imported on drop, or click **Import CSV** after selecting\n\n**CSV Format:**\n```csv\nOld URL,New URL\n/old-page,/new-page\n/deleted-content,\n/external-redirect,https://example.com/page\n```\n\n- First row (header) is skipped automatically\n- Old URL must start with `/`\n- New URL can be relative, absolute, or empty (for HTTP 410)\n- Properly handles quoted fields with commas\n\n### Exporting Redirects to CSV\n\nExport redirects for backup or migration:\n\n1. Select the redirects you want to export using checkboxes\n2. Click **Export selected**\n3. CSV file will be downloaded with format: `redirects-selected-YYYY-MM-DD.csv`\n\nThe exported CSV can be imported back into any instance of the redirector.\n\n### Pagination\n\n- Use the pagination controls at the bottom to navigate through pages\n- Change items per page: Select 10, 25, 50, 100, 500, or 1000 from the dropdown\n- Page numbers show your current position in the full dataset\n- Pagination shows first page, current page range, and last page for easy navigation\n\n### Statistics\n\nThe control panel displays real-time statistics with animated counters:\n\n- **Total Redirects** - Total count (changes to \"Search Results\" when filtering)\n- **Internal** - Redirects to internal paths (starting with `/`)\n- **External** - Redirects to external URLs (starting with `http://` or `https://`)\n- **Gone** - Empty redirects for permanently deleted content (HTTP 410)\n\nStatistics update automatically when you search or modify redirects.\n\n## Architecture\n\nThis addon is structured with the following key components:\n\n### Redux State Management\n\n- **Actions** (`src/actions/redirects.js`):\n  - `getRedirects(url, options)` - Fetch redirects list with pagination\n  - `getRedirectsStatistics(url, options)` - Fetch statistics separately for async loading\n  - `addRedirects(url, data)` - Add new redirects\n  - `removeRedirects(url, data)` - Delete redirects\n\n- **Reducer** (`src/reducers/redirects.js`):\n  - Manages loading states for list and statistics separately\n  - Clears old statistics when new request starts to prevent stale data\n  - Tracks items, total count, and statistics\n\n### UI Components\n\n- **Redirects** (`src/components/Controlpanels/Redirects.jsx`):\n  - Main control panel component\n  - Handles add/remove/search operations\n  - Manages pagination and statistics reset\n  - Form validation (old URL must start with `/`, new URL allows empty for HTTP 410)\n\n- **StatisticsBox** (`src/components/Controlpanels/StatisticsBox.jsx`):\n  - Animated counter component\n  - Counts up infinitely while loading (~1000-1500 increments every 100ms)\n  - Smoothly transitions to real value when data arrives\n  - Resets to 0 on new searches\n\n- **GoneView** (`src/components/GoneView/GoneView.jsx`):\n  - Custom 410 Gone error page\n  - Accordion with Wayback Machine integration\n  - Uses `withServerErrorCode(410)` HOC to set proper status\n\n### Routes and Registration\n\n- Control panel route auto-discovered from backend `@controlpanels` endpoint\n- 410 error view registered in `config.views.errorViews`\n- No manual control panel registration needed (handled by backend)\n\n## Performance Optimization\n\nThe addon implements several performance optimizations:\n\n1. **Separate Statistics Endpoint**: Statistics load via `@redirects-statistics` instead of blocking the main list\n2. **Progressive Loading**: List appears immediately, statistics load in background with animated counters\n3. **Reset on Search**: Statistics counters reset to 0 and start counting when new search initiated\n4. **Backend Pipelining**: Backend uses Redis pipelining for 42x faster statistics (see eea.api.redirector docs)\n\n## Getting started\n\n### Quick Start with Docker\n\nThe easiest way to try this addon is using Docker Compose, which will start:\n- **Redis** - For storing redirects\n- **Plone Backend** - Plone 6.0 with eea.api.redirector pre-installed and activated\n- **Volto Frontend** - With volto-redirector addon\n\n1. **Clone and start services:**\n\n   ```bash\n   git clone https://github.com/eea/volto-redirector.git\n   cd volto-redirector\n   docker-compose up\n   ```\n\n2. **Wait for services to start** (first time takes ~5 minutes to build):\n   - Redis: `localhost:6379`\n   - Backend: `http://localhost:8080/Plone` (Plone site auto-created with eea.api.redirector)\n   - Frontend: `http://localhost:3000`\n\n3. **Access the control panel:**\n   - Visit `http://localhost:3000/controlpanel/eea-redirects`\n   - Start managing redirects!\n\n### Try it out\n\nOnce the control panel is open, you can:\n\n1. **Add a test redirect:**\n   - Old URL: `/old-page`\n   - New URL: `/new-page`\n   - Click \"Add\"\n\n2. **Test the redirect:**\n   - Visit `http://localhost:3000/old-page`\n   - You'll be redirected to `/new-page`\n\n3. **Try HTTP 410 (Gone):**\n   - Old URL: `/deleted-content`\n   - New URL: _(leave empty)_\n   - Click \"Add\"\n   - Visit `http://localhost:3000/deleted-content`\n   - See the custom 410 Gone page\n\n4. **Import bulk redirects:**\n   - Create a CSV file with sample redirects\n   - Drag and drop it onto the import area\n   - Watch it import automatically\n\n### Stopping and Data Persistence\n\n- **Stop services:** `docker-compose down`\n- **Stop and remove data:** `docker-compose down -v` (removes Redis data)\n- **Redis data is persistent** in the `redis-data` volume, so redirects survive container restarts\n\n### Troubleshooting\n\n**Backend addon not showing in control panel:**\n- Make sure you activated `eea.api.redirector` in Site Setup → Add-ons\n- Check backend logs: `docker-compose logs backend`\n- Restart the backend: `docker-compose restart backend`\n\n**Control panel shows \"No redirects found\":**\n- This is normal on first start - Redis is empty\n- Try adding a test redirect to verify it's working\n\n**Redis connection errors:**\n- Check Redis is running: `docker-compose ps redis`\n- Check backend can reach Redis: `docker-compose logs backend`\n\n### Development Setup\n\nIf you want to develop the addon:\n\n```bash\ncd volto-redirector\nmake\nmake start\n```\n\nGo to http://localhost:3000\n\n`make start` now defaults to Volto 18. To run the same setup against Volto 17, use:\n\n      VOLTO_VERSION=17 make\n      VOLTO_VERSION=17 make start\n\n### Add volto-redirector to your Volto project\n\n1. Make sure you have a [Plone backend](https://plone.org/download) up-and-running at http://localhost:8080/Plone\n\n   ```Bash\n   docker compose up backend\n   ```\n\n1. Start Volto frontend\n\n* If you already have a volto project, just update `package.json`:\n\n   ```JSON\n   \"dependencies\": {\n       \"@eeacms/volto-redirector\": \"*\"\n   }\n   ```\n\n   and `volto.config.js`:\n\n   ```JavaScript\n   const addons = ['@eeacms/volto-redirector'];\n   ```\n\n* If not, create one with Cookieplone, as recommended by the official Plone documentation for Volto 18+:\n\n   ```\n   uvx cookieplone project\n   cd project-title\n   ```\n\n1. Install or update dependencies, then start the project:\n\n   ```\n   make install\n   ```\n\n   For a Cookieplone project, start the backend and frontend in separate terminals:\n\n   ```\n   make backend-start\n   make frontend-start\n   ```\n\n   For a legacy Volto 17 project, install the package with `yarn` and restart the frontend as usual.\n\n1. Go to http://localhost:3000\n\n1. Happy editing!\n\n## Release\n\nSee [RELEASE.md](https://github.com/eea/volto-redirector/blob/master/RELEASE.md).\n\n## How to contribute\n\nSee [DEVELOP.md](https://github.com/eea/volto-redirector/blob/master/DEVELOP.md).\n\n## Copyright and license\n\nThe Initial Owner of the Original Code is European Environment Agency (EEA).\nAll Rights Reserved.\n\nSee [LICENSE.md](https://github.com/eea/volto-redirector/blob/master/LICENSE.md) for details.\n\n## Funding\n\n[European Environment Agency (EU)](http://eea.europa.eu)\n","readmeFilename":"README.md"}