From 7cdf8ec3c2ca4651b611e47b3fc2c6dbc0f2705e Mon Sep 17 00:00:00 2001
From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Mon, 2 Nov 2026 21:25:35 -0800
Subject: [PATCH] Chore: ditch the abandoned ngx-bootstrap-icons, roll our own
(#14665)
---
src-ui/angular.json | 3 +
.../e2e/document-list/document-list.spec.ts | 2 +-
src-ui/jest.config.js | 2 +-
src-ui/package.json | 2 +-
src-ui/pnpm-lock.yaml | 24 +-
src-ui/src/app/app.component.spec.ts | 2 -
.../admin/config/config.component.html | 6 +-
.../admin/config/config.component.spec.ts | 2 -
.../admin/config/config.component.ts | 4 +-
.../admin/logs/logs.component.spec.ts | 2 -
.../admin/settings/settings.component.html | 18 +-
.../admin/settings/settings.component.spec.ts | 2 -
.../admin/settings/settings.component.ts | 4 +-
.../admin/tasks/tasks.component.html | 22 +-
.../admin/tasks/tasks.component.spec.ts | 2 -
.../components/admin/tasks/tasks.component.ts | 4 +-
.../admin/trash/trash.component.html | 16 +-
.../admin/trash/trash.component.spec.ts | 2 -
.../components/admin/trash/trash.component.ts | 4 +-
.../users-groups/users-groups.component.html | 12 +-
.../users-groups.component.spec.ts | 2 -
.../users-groups/users-groups.component.ts | 4 +-
.../app-frame/app-frame.component.html | 72 ++--
.../app-frame/app-frame.component.scss | 16 +-
.../app-frame/app-frame.component.spec.ts | 2 -
.../app-frame/app-frame.component.ts | 4 +-
.../global-search.component.html | 18 +-
.../global-search.component.scss | 6 +-
.../global-search.component.spec.ts | 2 -
.../global-search/global-search.component.ts | 4 +-
.../toasts-dropdown.component.html | 6 +-
.../toasts-dropdown.component.spec.ts | 6 +-
.../toasts-dropdown.component.ts | 4 +-
.../components/chat/chat/chat.component.html | 12 +-
.../chat/chat/chat.component.spec.ts | 7 +-
.../components/chat/chat/chat.component.ts | 4 +-
.../bootstrap-icon.component.spec.ts | 61 ++++
.../bootstrap-icon.component.ts | 54 +++
.../components/common/bootstrap-icon/icons.ts | 317 ++++++++++++++++++
.../clearable-badge.component.html | 4 +-
.../clearable-badge.component.spec.ts | 6 +-
.../clearable-badge.component.ts | 4 +-
.../confirm-button.component.html | 2 +-
.../confirm-button.component.spec.ts | 7 +-
.../confirm-button.component.ts | 4 +-
...-as-versions-confirm-dialog.component.html | 2 +-
...-versions-confirm-dialog.component.spec.ts | 6 +-
...ge-as-versions-confirm-dialog.component.ts | 4 +-
.../merge-confirm-dialog.component.html | 2 +-
.../merge-confirm-dialog.component.spec.ts | 8 +-
.../merge-confirm-dialog.component.ts | 4 +-
...word-removal-confirm-dialog.component.html | 4 +-
...d-removal-confirm-dialog.component.spec.ts | 6 +-
...ssword-removal-confirm-dialog.component.ts | 4 +-
.../rotate-confirm-dialog.component.html | 4 +-
.../rotate-confirm-dialog.component.spec.ts | 6 +-
.../rotate-confirm-dialog.component.ts | 4 +-
.../custom-field-display.component.html | 2 +-
.../custom-fields-dropdown.component.html | 4 +-
.../custom-fields-dropdown.component.spec.ts | 2 -
.../custom-fields-dropdown.component.ts | 4 +-
...ustom-fields-query-dropdown.component.html | 16 +-
...om-fields-query-dropdown.component.spec.ts | 2 -
.../custom-fields-query-dropdown.component.ts | 4 +-
.../dates-dropdown.component.html | 34 +-
.../dates-dropdown.component.spec.ts | 2 -
.../dates-dropdown.component.ts | 6 +-
.../custom-field-edit-dialog.component.html | 2 +-
...custom-field-edit-dialog.component.spec.ts | 2 -
.../custom-field-edit-dialog.component.ts | 4 +-
.../group-edit-dialog.component.spec.ts | 2 -
.../tag-edit-dialog.component.spec.ts | 2 -
.../user-edit-dialog.component.spec.ts | 2 -
.../workflow-edit-dialog.component.html | 10 +-
.../workflow-edit-dialog.component.ts | 4 +-
.../email-document-dialog.component.spec.ts | 7 +-
.../email-document-dialog.component.ts | 3 +-
.../filterable-dropdown.component.html | 8 +-
.../filterable-dropdown.component.spec.ts | 3 +-
.../filterable-dropdown.component.ts | 4 +-
.../toggleable-dropdown-button.component.html | 6 +-
.../toggleable-dropdown-button.component.ts | 4 +-
.../common/input/check/check.component.html | 2 +-
.../common/input/check/check.component.ts | 4 +-
.../common/input/color/color.component.html | 2 +-
.../input/color/color.component.spec.ts | 2 -
.../common/input/color/color.component.ts | 4 +-
.../custom-fields-values.component.html | 2 +-
.../custom-fields-values.component.ts | 4 +-
.../common/input/date/date.component.html | 6 +-
.../common/input/date/date.component.spec.ts | 6 +-
.../common/input/date/date.component.ts | 4 +-
.../document-link.component.html | 8 +-
.../document-link.component.scss | 2 +-
.../document-link.component.spec.ts | 3 +-
.../document-link/document-link.component.ts | 4 +-
.../input/entries/entries.component.html | 4 +-
.../input/entries/entries.component.spec.ts | 8 +-
.../common/input/entries/entries.component.ts | 4 +-
.../common/input/file/file.component.html | 4 +-
.../input/monetary/monetary.component.html | 2 +-
.../input/monetary/monetary.component.ts | 4 +-
.../common/input/number/number.component.html | 2 +-
.../common/input/number/number.component.ts | 4 +-
.../input/password/password.component.html | 2 +-
.../input/password/password.component.spec.ts | 8 +-
.../input/password/password.component.ts | 4 +-
.../common/input/select/select.component.html | 10 +-
.../common/input/select/select.component.ts | 4 +-
.../common/input/switch/switch.component.html | 6 +-
.../common/input/tags/tags.component.html | 10 +-
.../common/input/tags/tags.component.spec.ts | 2 -
.../common/input/tags/tags.component.ts | 4 +-
.../common/input/text/text.component.html | 2 +-
.../common/input/text/text.component.ts | 4 +-
.../input/textarea/textarea.component.html | 2 +-
.../input/textarea/textarea.component.ts | 4 +-
.../common/input/url/url.component.html | 4 +-
.../common/input/url/url.component.spec.ts | 8 +-
.../common/input/url/url.component.ts | 4 +-
.../page-header/page-header.component.html | 6 +-
.../page-header/page-header.component.spec.ts | 3 +-
.../page-header/page-header.component.ts | 4 +-
.../pdf-editor/pdf-editor.component.html | 22 +-
.../pdf-editor/pdf-editor.component.spec.ts | 3 +-
.../common/pdf-editor/pdf-editor.component.ts | 4 +-
...permissions-filter-dropdown.component.html | 16 +-
...missions-filter-dropdown.component.spec.ts | 2 -
.../permissions-filter-dropdown.component.ts | 4 +-
.../permissions-select.component.html | 4 +-
.../permissions-select.component.spec.ts | 6 +-
.../permissions-select.component.ts | 4 +-
.../preview-popup.component.html | 2 +-
.../preview-popup.component.spec.ts | 4 +-
.../preview-popup/preview-popup.component.ts | 4 +-
.../profile-edit-dialog.component.html | 12 +-
.../profile-edit-dialog.component.spec.ts | 2 -
.../profile-edit-dialog.component.ts | 4 +-
.../share-link-bundle-dialog.component.html | 4 +-
...share-link-bundle-dialog.component.spec.ts | 6 +-
.../share-link-bundle-dialog.component.ts | 4 +-
.../share-links-dialog.component.html | 10 +-
.../share-links-dialog.component.spec.ts | 8 +-
.../share-links-dialog.component.ts | 4 +-
.../suggestions-dropdown.component.html | 16 +-
.../suggestions-dropdown.component.spec.ts | 7 +-
.../suggestions-dropdown.component.ts | 4 +-
.../system-status-dialog.component.html | 62 ++--
.../system-status-dialog.component.spec.ts | 6 +-
.../system-status-dialog.component.ts | 4 +-
.../common/toast/toast.component.html | 10 +-
.../common/toast/toast.component.spec.ts | 9 +-
.../common/toast/toast.component.ts | 4 +-
.../common/toasts/toasts.component.spec.ts | 3 +-
.../common/toasts/toasts.component.ts | 8 +-
.../upload-status-tray.component.html | 6 +-
.../upload-status-tray.component.scss | 4 +-
.../upload-status-tray.component.spec.ts | 2 -
.../upload-status-tray.component.ts | 4 +-
.../dashboard/dashboard.component.html | 4 +-
.../dashboard/dashboard.component.spec.ts | 2 -
.../dashboard/dashboard.component.ts | 4 +-
.../saved-view-widget.component.html | 6 +-
.../saved-view-widget.component.spec.ts | 2 -
.../saved-view-widget.component.ts | 4 +-
.../upload-file-widget.component.html | 2 +-
.../upload-file-widget.component.scss | 2 +-
.../upload-file-widget.component.spec.ts | 2 -
.../upload-file-widget.component.ts | 4 +-
.../widget-frame/widget-frame.component.html | 4 +-
.../widget-frame/widget-frame.component.scss | 2 +-
.../widget-frame/widget-frame.component.ts | 4 +-
.../document-barcodes.component.html | 4 +-
.../document-barcodes.component.spec.ts | 18 +-
.../document-barcodes.component.ts | 4 +-
.../document-detail.component.html | 36 +-
.../document-detail.component.spec.ts | 7 +-
.../document-detail.component.ts | 4 +-
.../document-history.component.spec.ts | 7 +-
.../document-history.component.ts | 2 -
.../document-version-dropdown.component.html | 14 +-
...ocument-version-dropdown.component.spec.ts | 8 +-
.../document-version-dropdown.component.ts | 4 +-
.../metadata-collapse.component.html | 4 +-
.../metadata-collapse.component.spec.ts | 6 +-
.../metadata-collapse.component.ts | 4 +-
.../bulk-editor/bulk-editor.component.html | 24 +-
.../bulk-editor/bulk-editor.component.spec.ts | 3 +-
.../bulk-editor/bulk-editor.component.ts | 4 +-
...tom-fields-bulk-edit-dialog.component.html | 2 +-
...ustom-fields-bulk-edit-dialog.component.ts | 4 +-
.../document-card-large.component.html | 30 +-
.../document-card-large.component.spec.ts | 2 -
.../document-card-large.component.ts | 4 +-
.../document-card-small.component.html | 26 +-
.../document-card-small.component.spec.ts | 7 +-
.../document-card-small.component.ts | 4 +-
.../document-list.component.html | 34 +-
.../document-list.component.spec.ts | 7 +-
.../document-list/document-list.component.ts | 4 +-
.../filter-editor.component.html | 4 +-
.../filter-editor.component.spec.ts | 2 -
.../filter-editor/filter-editor.component.ts | 4 +-
.../document-notes.component.html | 2 +-
.../document-notes.component.spec.ts | 2 -
.../document-notes.component.ts | 4 +-
.../custom-fields.component.html | 8 +-
.../custom-fields.component.spec.ts | 2 -
.../custom-fields/custom-fields.component.ts | 4 +-
.../document-attributes.component.html | 18 +-
.../document-attributes.component.spec.ts | 4 +-
.../document-attributes.component.ts | 4 +-
.../correspondent-list.component.spec.ts | 2 -
.../correspondent-list.component.ts | 4 +-
.../document-type-list.component.spec.ts | 2 -
.../document-type-list.component.ts | 4 +-
.../management-list.component.html | 8 +-
.../management-list.component.spec.ts | 2 -
.../storage-path-list.component.spec.ts | 2 -
.../storage-path-list.component.ts | 4 +-
.../tag-list/tag-list.component.spec.ts | 2 -
.../tag-list/tag-list.component.ts | 4 +-
.../manage/mail/mail.component.html | 36 +-
.../manage/mail/mail.component.spec.ts | 2 -
.../components/manage/mail/mail.component.ts | 4 +-
.../processed-mail-dialog.component.html | 10 +-
.../processed-mail-dialog.component.spec.ts | 7 +-
.../processed-mail-dialog.component.ts | 4 +-
.../saved-views/saved-views.component.html | 2 +-
.../saved-views/saved-views.component.spec.ts | 2 -
.../saved-views/saved-views.component.ts | 8 +-
.../share-link-bundle-list.component.html | 8 +-
.../share-link-bundle-list.component.spec.ts | 6 +-
.../share-link-bundle-list.component.ts | 8 +-
.../share-link-list.component.html | 6 +-
.../share-link-list.component.spec.ts | 7 +-
.../share-link-list.component.ts | 4 +-
.../share-links/share-links.component.spec.ts | 8 +-
.../manage/workflows/workflows.component.html | 10 +-
.../workflows/workflows.component.spec.ts | 2 -
.../manage/workflows/workflows.component.ts | 4 +-
.../not-found/not-found.component.html | 2 +-
.../not-found/not-found.component.spec.ts | 8 +-
.../not-found/not-found.component.ts | 4 +-
.../app/guards/dirty-saved-view.guard.spec.ts | 7 +-
src-ui/src/main.ts | 317 +-----------------
src-ui/src/styles.scss | 4 +-
src-ui/src/theme.scss | 2 +-
src-ui/src/typings.d.ts | 5 +
249 files changed, 1092 insertions(+), 1216 deletions(-)
create mode 100644 src-ui/src/app/components/common/bootstrap-icon/bootstrap-icon.component.spec.ts
create mode 100644 src-ui/src/app/components/common/bootstrap-icon/bootstrap-icon.component.ts
create mode 100644 src-ui/src/app/components/common/bootstrap-icon/icons.ts
create mode 100644 src-ui/src/typings.d.ts
diff --git a/src-ui/angular.json b/src-ui/angular.json
index 633be88c5f..c3faf73f26 100644
--- a/src-ui/angular.json
+++ b/src-ui/angular.json
@@ -69,6 +69,9 @@
"src/polyfills.ts"
],
"tsConfig": "tsconfig.app.json",
+ "loader": {
+ ".svg": "text"
+ },
"localize": true,
"assets": [
"src/apple-touch-icon.png",
diff --git a/src-ui/e2e/document-list/document-list.spec.ts b/src-ui/e2e/document-list/document-list.spec.ts
index 5365b48268..b86ffa873f 100644
--- a/src-ui/e2e/document-list/document-list.spec.ts
+++ b/src-ui/e2e/document-list/document-list.spec.ts
@@ -123,7 +123,7 @@ test('sorting', async ({ page }) => {
await page.getByRole('button', { name: 'Notes' }).click()
await expect(page).toHaveURL(/sort=num_notes/)
await page.getByRole('button', { name: 'Sort' }).click()
- await page.locator('.w-100 > label > i-bs').first().click()
+ await page.locator('.w-100 > label > pngx-bs-icon').first().click()
await expect(page).not.toHaveURL(/reverse=1/)
})
diff --git a/src-ui/jest.config.js b/src-ui/jest.config.js
index 89a3341307..ffea6ccc21 100644
--- a/src-ui/jest.config.js
+++ b/src-ui/jest.config.js
@@ -28,7 +28,7 @@ module.exports = {
'abstract-paperless-service',
],
transformIgnorePatterns: [
- 'node_modules/(?!.*(\\.mjs$|tslib|lodash-es|normalize-diacritics|marked|@angular/common/locales/.*\\.js$))',
+ 'node_modules/(?!.*(\\.mjs$|tslib|lodash-es|normalize-diacritics|marked|@angular/common/locales/.*\\.js$|bootstrap-icons/icons/.*\\.svg$))',
],
moduleNameMapper: {
...esmPreset.moduleNameMapper,
diff --git a/src-ui/package.json b/src-ui/package.json
index a1ce49eed4..9255ff139e 100644
--- a/src-ui/package.json
+++ b/src-ui/package.json
@@ -28,11 +28,11 @@
"@ngneat/dirty-check-forms": "^3.0.3",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.8",
+ "bootstrap-icons": "^1.13.2",
"file-saver": "^2.0.5",
"lodash-es": "^4.18.1",
"marked": "~18.1.1",
"mime-names": "^1.0.0",
- "ngx-bootstrap-icons": "^1.9.3",
"ngx-color": "^10.1.0",
"ngx-cookie-service": "^22.0.0",
"ngx-device-detector": "^12.0.0",
diff --git a/src-ui/pnpm-lock.yaml b/src-ui/pnpm-lock.yaml
index bcbc11d953..3e743b69ef 100644
--- a/src-ui/pnpm-lock.yaml
+++ b/src-ui/pnpm-lock.yaml
@@ -51,6 +51,9 @@ importers:
bootstrap:
specifier: ^5.3.8
version: 5.3.8(@popperjs/core@2.11.8)
+ bootstrap-icons:
+ specifier: ^1.13.2
+ version: 1.13.2
file-saver:
specifier: ^2.0.5
version: 2.0.5
@@ -63,9 +66,6 @@ importers:
mime-names:
specifier: ^1.0.0
version: 1.0.0
- ngx-bootstrap-icons:
- specifier: ^1.9.3
- version: 1.9.3(@angular/common@22.2.3(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2))
ngx-color:
specifier: ^10.1.0
version: 10.1.0(@angular/common@22.2.3(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2))
@@ -2391,6 +2391,9 @@ packages:
resolution: {integrity: sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA==}
engines: {node: '>=20.19.0'}
+ bootstrap-icons@1.13.2:
+ resolution: {integrity: sha512-fAU1Ly3dH7hwRg+CB8EZ0Vl0fF80zgXHeUVJyfUOKzoURr+TbwISbCW5tKUoQLERaWYG2emTCybcPbD96hdD1A==}
+
bootstrap@5.3.8:
resolution: {integrity: sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==}
peerDependencies:
@@ -3421,13 +3424,6 @@ packages:
neo-async@2.6.2:
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
- ngx-bootstrap-icons@1.9.3:
- resolution: {integrity: sha512-UsFqJ/cn0u5W39hVMIDbm+ze1dCF9fDV839scqeimi70Efcmg41zOx6GgR6i2gWAVFR0OBso1cdqb4E75XhTSw==}
- engines: {node: '>= 16.18.1', npm: '>= 8.11.0'}
- peerDependencies:
- '@angular/common': '>= 13.3.8'
- '@angular/core': '>= 13.3.8'
-
ngx-color@10.1.0:
resolution: {integrity: sha512-yuxlE1LfN+PABIO4hv0Gw5ksq8g9XkMJKrGPn2SWbrre/gsH+kkyyn3rwSCurinnLCnw7czqenwQUtnBJm8yww==}
peerDependencies:
@@ -6411,6 +6407,8 @@ snapshots:
boolbase@2.0.0: {}
+ bootstrap-icons@1.13.2: {}
+
bootstrap@5.3.8(@popperjs/core@2.11.8):
dependencies:
'@popperjs/core': 2.11.8
@@ -7648,12 +7646,6 @@ snapshots:
neo-async@2.6.2: {}
- ngx-bootstrap-icons@1.9.3(@angular/common@22.2.3(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2)):
- dependencies:
- '@angular/common': 22.2.3(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2))(rxjs@7.8.2)
- '@angular/core': 22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2)
- tslib: 2.8.1
-
ngx-color@10.1.0(@angular/common@22.2.3(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2))(rxjs@7.8.2))(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2)):
dependencies:
'@angular/common': 22.2.3(@angular/core@22.2.3(@angular/compiler@22.2.3)(rxjs@7.8.2))(rxjs@7.8.2)
diff --git a/src-ui/src/app/app.component.spec.ts b/src-ui/src/app/app.component.spec.ts
index d93534d80f..bd81eebaeb 100644
--- a/src-ui/src/app/app.component.spec.ts
+++ b/src-ui/src/app/app.component.spec.ts
@@ -3,7 +3,6 @@ import { provideHttpClientTesting } from '@angular/common/http/testing'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { Router, RouterModule } from '@angular/router'
import { NgbModalModule } from '@ng-bootstrap/ng-bootstrap'
-import { allIcons, NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
import {
provideUiTour,
TourNgBootstrap,
@@ -47,7 +46,6 @@ describe('AppComponent', () => {
ToastsComponent,
FileDropComponent,
TourNgBootstrap,
- NgxBootstrapIconsModule.pick(allIcons),
],
providers: [
PermissionsGuard,
diff --git a/src-ui/src/app/components/admin/config/config.component.html b/src-ui/src/app/components/admin/config/config.component.html
index 31e9aecfa6..50ecb8ef03 100644
--- a/src-ui/src/app/components/admin/config/config.component.html
+++ b/src-ui/src/app/components/admin/config/config.component.html
@@ -28,7 +28,7 @@
{{option.title}}
-