Explorar el Código

Merge pull request #24660 from overleaf/td-bs5-remove-react-bootstrap-0

Remove react-bootstrap 0.33.1

GitOrigin-RevId: c320a6b18c576afdc0fd49559915d3d2f3a7a1ef
Tim Down hace 1 año
padre
commit
28468e134c
Se han modificado 100 ficheros con 272 adiciones y 2727 borrados
  1. 0 128
      package-lock.json
  2. 7 31
      services/web/.storybook/preview.tsx
  3. 0 20
      services/web/.storybook/utils/with-bootstrap-switcher.tsx
  4. 0 1
      services/web/cypress/support/ct/window.ts
  5. 0 19
      services/web/frontend/js/features/file-tree/components/file-tree-context-menu.tsx
  6. 1 4
      services/web/frontend/js/features/history/components/change-list/change-list.tsx
  7. 6 16
      services/web/frontend/js/features/history/components/change-list/dropdown/actions-dropdown.tsx
  8. 0 1
      services/web/frontend/js/features/history/components/change-list/dropdown/compare-version-dropdown.tsx
  9. 0 1
      services/web/frontend/js/features/history/components/change-list/dropdown/history-dropdown.tsx
  10. 1 2
      services/web/frontend/js/features/settings/components/emails/actions/make-primary/confirmation-modal.tsx
  11. 0 3
      services/web/frontend/js/features/settings/components/emails/reconfirmation-info/reconfirmation-info-prompt-text.tsx
  12. 12 32
      services/web/frontend/js/features/subscription/components/dashboard/group-settings-button.tsx
  13. 0 5
      services/web/frontend/js/features/subscription/components/dashboard/leave-group-modal.tsx
  14. 1 5
      services/web/frontend/js/features/subscription/components/dashboard/managed-group-subscriptions.tsx
  15. 0 3
      services/web/frontend/js/features/subscription/components/dashboard/personal-subscription-recurly-sync-email.tsx
  16. 1 23
      services/web/frontend/js/features/subscription/components/dashboard/row-link.tsx
  17. 3 11
      services/web/frontend/js/features/subscription/components/dashboard/states/active/active-new.tsx
  18. 0 3
      services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/downgrade-plan-button.tsx
  19. 0 3
      services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/extend-trial-button.tsx
  20. 0 5
      services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/cancel-ai-add-on-modal.tsx
  21. 1 13
      services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx
  22. 0 5
      services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/confirm-change-plan-modal.tsx
  23. 0 5
      services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/keep-current-plan-modal.tsx
  24. 0 71
      services/web/frontend/js/features/ui/components/bootstrap-3/dropdown-menu-with-ref.tsx
  25. 0 53
      services/web/frontend/js/features/ui/components/bootstrap-3/dropdown-toggle-with-tooltip.tsx
  26. 0 21
      services/web/frontend/js/features/ui/components/bootstrap-3/form/form-control.tsx
  27. 0 14
      services/web/frontend/js/features/ui/components/bootstrap-3/toast-container.tsx
  28. 0 51
      services/web/frontend/js/features/ui/components/bootstrap-3/toast.tsx
  29. 0 99
      services/web/frontend/js/features/ui/components/bootstrap-3/toggle-button-group.tsx
  30. 0 15
      services/web/frontend/js/features/ui/components/bootstrap-5/bootstrap-version-switcher.tsx
  31. 1 8
      services/web/frontend/js/features/ui/components/ol/icons/ol-tag-icon.tsx
  32. 2 35
      services/web/frontend/js/features/ui/components/ol/ol-badge.tsx
  33. 2 25
      services/web/frontend/js/features/ui/components/ol/ol-button-group.tsx
  34. 2 26
      services/web/frontend/js/features/ui/components/ol/ol-button-toolbar.tsx
  35. 4 123
      services/web/frontend/js/features/ui/components/ol/ol-button.tsx
  36. 3 10
      services/web/frontend/js/features/ui/components/ol/ol-card.tsx
  37. 1 21
      services/web/frontend/js/features/ui/components/ol/ol-close-button.tsx
  38. 2 68
      services/web/frontend/js/features/ui/components/ol/ol-col.tsx
  39. 4 34
      services/web/frontend/js/features/ui/components/ol/ol-dropdown-menu-item.tsx
  40. 20 115
      services/web/frontend/js/features/ui/components/ol/ol-form-checkbox.tsx
  41. 6 75
      services/web/frontend/js/features/ui/components/ol/ol-form-control.tsx
  42. 2 26
      services/web/frontend/js/features/ui/components/ol/ol-form-feedback.tsx
  43. 2 36
      services/web/frontend/js/features/ui/components/ol/ol-form-group.tsx
  44. 2 23
      services/web/frontend/js/features/ui/components/ol/ol-form-label.tsx
  45. 2 49
      services/web/frontend/js/features/ui/components/ol/ol-form-select.tsx
  46. 7 41
      services/web/frontend/js/features/ui/components/ol/ol-form-switch.tsx
  47. 2 29
      services/web/frontend/js/features/ui/components/ol/ol-form-text.tsx
  48. 2 39
      services/web/frontend/js/features/ui/components/ol/ol-form.tsx
  49. 2 43
      services/web/frontend/js/features/ui/components/ol/ol-icon-button.tsx
  50. 6 33
      services/web/frontend/js/features/ui/components/ol/ol-list-group-item.tsx
  51. 3 28
      services/web/frontend/js/features/ui/components/ol/ol-list-group.tsx
  52. 13 109
      services/web/frontend/js/features/ui/components/ol/ol-modal.tsx
  53. 4 36
      services/web/frontend/js/features/ui/components/ol/ol-notification.tsx
  54. 2 56
      services/web/frontend/js/features/ui/components/ol/ol-overlay.tsx
  55. 4 10
      services/web/frontend/js/features/ui/components/ol/ol-page-content-card.tsx
  56. 5 70
      services/web/frontend/js/features/ui/components/ol/ol-popover.tsx
  57. 2 11
      services/web/frontend/js/features/ui/components/ol/ol-row.tsx
  58. 5 20
      services/web/frontend/js/features/ui/components/ol/ol-spinner.tsx
  59. 2 27
      services/web/frontend/js/features/ui/components/ol/ol-table.tsx
  60. 2 29
      services/web/frontend/js/features/ui/components/ol/ol-tag.tsx
  61. 3 15
      services/web/frontend/js/features/ui/components/ol/ol-toast-container.tsx
  62. 9 26
      services/web/frontend/js/features/ui/components/ol/ol-toast.tsx
  63. 2 37
      services/web/frontend/js/features/ui/components/ol/ol-toggle-button-group.tsx
  64. 2 43
      services/web/frontend/js/features/ui/components/ol/ol-toggle-button.tsx
  65. 2 43
      services/web/frontend/js/features/ui/components/ol/ol-tooltip.tsx
  66. 0 26
      services/web/frontend/js/features/utils/bootstrap-5.ts
  67. 0 30
      services/web/frontend/js/shared/components/accessible-modal.tsx
  68. 0 29
      services/web/frontend/js/shared/components/badge.tsx
  69. 4 19
      services/web/frontend/js/shared/components/beta-badge-icon.tsx
  70. 1 4
      services/web/frontend/js/shared/components/beta-badge.tsx
  71. 4 10
      services/web/frontend/js/shared/components/close.tsx
  72. 0 58
      services/web/frontend/js/shared/components/controlled-dropdown.tsx
  73. 1 7
      services/web/frontend/js/shared/components/copy-to-clipboard.tsx
  74. 6 21
      services/web/frontend/js/shared/components/generic-error-boundary-fallback.tsx
  75. 1 4
      services/web/frontend/js/shared/components/icon.tsx
  76. 2 6
      services/web/frontend/js/shared/components/labs/labs-experiments-widget.tsx
  77. 7 6
      services/web/frontend/js/shared/components/loading-spinner.tsx
  78. 1 4
      services/web/frontend/js/shared/components/material-icon.tsx
  79. 65 144
      services/web/frontend/js/shared/components/select.tsx
  80. 0 56
      services/web/frontend/js/shared/components/tag.tsx
  81. 0 57
      services/web/frontend/js/shared/components/tooltip.tsx
  82. 1 8
      services/web/frontend/js/shared/components/upgrade-benefits.jsx
  83. 5 55
      services/web/frontend/stories/contact-us-modal.stories.tsx
  84. 0 45
      services/web/frontend/stories/dropdown.stories.jsx
  85. 0 4
      services/web/frontend/stories/feedback-badge.stories.tsx
  86. 1 6
      services/web/frontend/stories/input-switch.stories.tsx
  87. 0 2
      services/web/frontend/stories/loading/loading.stories.tsx
  88. 0 3
      services/web/frontend/stories/menu-bar.stories.tsx
  89. 0 7
      services/web/frontend/stories/modals/unsaved-docs-locked-modal.stories.tsx
  90. 6 4
      services/web/frontend/stories/pdf-preview.stories.jsx
  91. 0 3
      services/web/frontend/stories/project-list/add-affiliation.stories.tsx
  92. 0 3
      services/web/frontend/stories/project-list/color-picker.stories.tsx
  93. 0 3
      services/web/frontend/stories/project-list/compile-and-download-project-pdf.stories.tsx
  94. 0 3
      services/web/frontend/stories/project-list/current-plan-widget.stories.tsx
  95. 0 3
      services/web/frontend/stories/project-list/inr-banner.stories.tsx
  96. 0 3
      services/web/frontend/stories/project-list/new-project-button.stories.tsx
  97. 0 3
      services/web/frontend/stories/project-list/notifications.stories.tsx
  98. 0 3
      services/web/frontend/stories/project-list/project-list.stories.tsx
  99. 0 3
      services/web/frontend/stories/project-list/project-search.stories.tsx
  100. 0 3
      services/web/frontend/stories/project-list/survey-widget.stories.tsx

+ 0 - 128
package-lock.json

@@ -3267,27 +3267,6 @@
         "node": ">=6.9.0"
         "node": ">=6.9.0"
       }
       }
     },
     },
-    "node_modules/@babel/runtime-corejs2": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.16.7.tgz",
-      "integrity": "sha512-ec0BM0J/9M5Cncha++AlgvvDlk+uM+m6f7K0t74ClcYzsE8LgX4RstRreksMSCI82o3LJS//UswmA0pUWkJpqg==",
-      "dev": true,
-      "dependencies": {
-        "core-js": "^2.6.5",
-        "regenerator-runtime": "^0.13.4"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/runtime-corejs2/node_modules/core-js": {
-      "version": "2.6.12",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
-      "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
-      "deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.",
-      "dev": true,
-      "hasInstallScript": true
-    },
     "node_modules/@babel/runtime-corejs3": {
     "node_modules/@babel/runtime-corejs3": {
       "version": "7.16.8",
       "version": "7.16.8",
       "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.8.tgz",
       "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.8.tgz",
@@ -12634,16 +12613,6 @@
         "@types/react": "*"
         "@types/react": "*"
       }
       }
     },
     },
-    "node_modules/@types/react-overlays": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/@types/react-overlays/-/react-overlays-1.1.3.tgz",
-      "integrity": "sha512-oOq5NWbyfNz2w2sKvjkHdvGQSMA+VDVfI5UOfGPR0wkik2welad1RDVnVgH15jKf58jrZNBa1Ee4SVBgCGFxCg==",
-      "dev": true,
-      "dependencies": {
-        "@types/react": "*",
-        "@types/react-transition-group": "*"
-      }
-    },
     "node_modules/@types/react-redux": {
     "node_modules/@types/react-redux": {
       "version": "7.1.33",
       "version": "7.1.33",
       "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz",
       "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.33.tgz",
@@ -19802,15 +19771,6 @@
         "utila": "~0.4"
         "utila": "~0.4"
       }
       }
     },
     },
-    "node_modules/dom-helpers": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
-      "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
-      "dev": true,
-      "dependencies": {
-        "@babel/runtime": "^7.1.2"
-      }
-    },
     "node_modules/dom-serializer": {
     "node_modules/dom-serializer": {
       "version": "1.3.2",
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
@@ -27577,12 +27537,6 @@
         "node": ">=12.0.0"
         "node": ">=12.0.0"
       }
       }
     },
     },
-    "node_modules/keycode": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz",
-      "integrity": "sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==",
-      "dev": true
-    },
     "node_modules/keyv": {
     "node_modules/keyv": {
       "version": "4.5.4",
       "version": "4.5.4",
       "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
       "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -34620,30 +34574,6 @@
         "react": ">=16.4.1"
         "react": ">=16.4.1"
       }
       }
     },
     },
-    "node_modules/react-bootstrap": {
-      "version": "0.33.1",
-      "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.33.1.tgz",
-      "integrity": "sha512-qWTRravSds87P8WC82tETy2yIso8qDqlIm0czsrduCaYAFtHuyLu0XDbUlfLXeRzqgwm5sRk2wRaTNoiVkk/YQ==",
-      "dev": true,
-      "dependencies": {
-        "@babel/runtime-corejs2": "^7.0.0",
-        "classnames": "^2.2.5",
-        "dom-helpers": "^3.2.0",
-        "invariant": "^2.2.4",
-        "keycode": "^2.2.0",
-        "prop-types": "^15.6.1",
-        "prop-types-extra": "^1.0.1",
-        "react-overlays": "^0.9.0",
-        "react-prop-types": "^0.4.0",
-        "react-transition-group": "^2.0.0",
-        "uncontrollable": "^7.0.2",
-        "warning": "^3.0.0"
-      },
-      "peerDependencies": {
-        "react": ">=16.3.0",
-        "react-dom": ">=16.3.0"
-      }
-    },
     "node_modules/react-chartjs-2": {
     "node_modules/react-chartjs-2": {
       "version": "5.0.1",
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.0.1.tgz",
       "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.0.1.tgz",
@@ -34849,36 +34779,6 @@
         "uc.micro": "^1.0.1"
         "uc.micro": "^1.0.1"
       }
       }
     },
     },
-    "node_modules/react-overlays": {
-      "version": "0.9.3",
-      "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-0.9.3.tgz",
-      "integrity": "sha512-u2T7nOLnK+Hrntho4p0Nxh+BsJl0bl4Xuwj/Y0a56xywLMetgAfyjnDVrudLXsNcKGaspoC+t3C1V80W9QQTdQ==",
-      "dev": true,
-      "dependencies": {
-        "classnames": "^2.2.5",
-        "dom-helpers": "^3.2.1",
-        "prop-types": "^15.5.10",
-        "prop-types-extra": "^1.0.1",
-        "react-transition-group": "^2.2.1",
-        "warning": "^3.0.0"
-      },
-      "peerDependencies": {
-        "react": ">=16.3.0",
-        "react-dom": ">=16.3.0"
-      }
-    },
-    "node_modules/react-prop-types": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz",
-      "integrity": "sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=",
-      "dev": true,
-      "dependencies": {
-        "warning": "^3.0.0"
-      },
-      "peerDependencies": {
-        "react": ">=0.14.0"
-      }
-    },
     "node_modules/react-proxy": {
     "node_modules/react-proxy": {
       "version": "1.1.8",
       "version": "1.1.8",
       "resolved": "https://registry.npmjs.org/react-proxy/-/react-proxy-1.1.8.tgz",
       "resolved": "https://registry.npmjs.org/react-proxy/-/react-proxy-1.1.8.tgz",
@@ -34989,22 +34889,6 @@
         "react-proxy": "^1.1.7"
         "react-proxy": "^1.1.7"
       }
       }
     },
     },
-    "node_modules/react-transition-group": {
-      "version": "2.9.0",
-      "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
-      "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
-      "dev": true,
-      "dependencies": {
-        "dom-helpers": "^3.4.0",
-        "loose-envify": "^1.4.0",
-        "prop-types": "^15.6.2",
-        "react-lifecycles-compat": "^3.0.4"
-      },
-      "peerDependencies": {
-        "react": ">=15.0.0",
-        "react-dom": ">=15.0.0"
-      }
-    },
     "node_modules/reactcss": {
     "node_modules/reactcss": {
       "version": "1.2.3",
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
       "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
@@ -40502,15 +40386,6 @@
         "node": ">=6.0.0"
         "node": ">=6.0.0"
       }
       }
     },
     },
-    "node_modules/warning": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
-      "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
-      "dev": true,
-      "dependencies": {
-        "loose-envify": "^1.0.0"
-      }
-    },
     "node_modules/watchpack": {
     "node_modules/watchpack": {
       "version": "2.4.1",
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
@@ -44482,7 +44357,6 @@
         "@types/react-dom": "^17.0.13",
         "@types/react-dom": "^17.0.13",
         "@types/react-google-recaptcha": "^2.1.5",
         "@types/react-google-recaptcha": "^2.1.5",
         "@types/react-linkify": "^1.0.0",
         "@types/react-linkify": "^1.0.0",
-        "@types/react-overlays": "^1.1.3",
         "@types/recurly__recurly-js": "^4.22.0",
         "@types/recurly__recurly-js": "^4.22.0",
         "@types/sinon-chai": "^3.2.8",
         "@types/sinon-chai": "^3.2.8",
         "@types/uuid": "^9.0.8",
         "@types/uuid": "^9.0.8",
@@ -44570,7 +44444,6 @@
         "prop-types": "^15.7.2",
         "prop-types": "^15.7.2",
         "qrcode": "^1.4.4",
         "qrcode": "^1.4.4",
         "react": "^17.0.2",
         "react": "^17.0.2",
-        "react-bootstrap": "^0.33.1",
         "react-bootstrap-5": "npm:react-bootstrap@^2.10.5",
         "react-bootstrap-5": "npm:react-bootstrap@^2.10.5",
         "react-chartjs-2": "^5.0.1",
         "react-chartjs-2": "^5.0.1",
         "react-color": "^2.19.3",
         "react-color": "^2.19.3",
@@ -44581,7 +44454,6 @@
         "react-google-recaptcha": "^3.1.0",
         "react-google-recaptcha": "^3.1.0",
         "react-i18next": "^13.3.1",
         "react-i18next": "^13.3.1",
         "react-linkify": "^1.0.0-alpha",
         "react-linkify": "^1.0.0-alpha",
-        "react-overlays": "^0.9.3",
         "react-refresh": "^0.14.0",
         "react-refresh": "^0.14.0",
         "react-resizable-panels": "^2.1.1",
         "react-resizable-panels": "^2.1.1",
         "resolve-url-loader": "^5.0.0",
         "resolve-url-loader": "^5.0.0",

+ 7 - 31
services/web/.storybook/preview.tsx

@@ -9,14 +9,10 @@ import i18n from 'i18next'
 import { initReactI18next } from 'react-i18next'
 import { initReactI18next } from 'react-i18next'
 // @ts-ignore
 // @ts-ignore
 import en from '../../../services/web/locales/en.json'
 import en from '../../../services/web/locales/en.json'
-import { bootstrapVersionArg } from './utils/with-bootstrap-switcher'
 
 
-function resetMeta(bootstrapVersion?: 3 | 5) {
+function resetMeta() {
   window.metaAttributesCache = new Map()
   window.metaAttributesCache = new Map()
   window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' })
   window.metaAttributesCache.set('ol-i18n', { currentLangCode: 'en' })
-  if (bootstrapVersion) {
-    window.metaAttributesCache.set('ol-bootstrapVersion', bootstrapVersion)
-  }
   window.metaAttributesCache.set('ol-ExposedSettings', {
   window.metaAttributesCache.set('ol-ExposedSettings', {
     adminEmail: 'placeholder@example.com',
     adminEmail: 'placeholder@example.com',
     appName: 'Overleaf',
     appName: 'Overleaf',
@@ -126,8 +122,6 @@ const preview: Preview = {
       // render stories in iframes, to isolate modals
       // render stories in iframes, to isolate modals
       inlineStories: false,
       inlineStories: false,
     },
     },
-    // Default to Bootstrap 5 styles
-    bootstrap5: true,
   },
   },
   globalTypes: {
   globalTypes: {
     theme: {
     theme: {
@@ -144,17 +138,9 @@ const preview: Preview = {
     },
     },
   },
   },
   loaders: [
   loaders: [
-    async ({ globals }) => {
-      const { theme } = globals
-
+    async () => {
       return {
       return {
-        // NOTE: this uses `${theme}style.less` rather than `${theme}.less`
-        // so that webpack only bundles files ending with "style.less"
-        bootstrap3Style: await import(
-          `!!to-string-loader!css-loader!less-loader!../../../services/web/frontend/stylesheets/${theme}style.less`
-        ),
-        // Themes are applied differently in Bootstrap 5 code
-        bootstrap5Style: await import(
+        mainStyle: await import(
           // @ts-ignore
           // @ts-ignore
           `!!to-string-loader!css-loader!resolve-url-loader!sass-loader!../../../services/web/frontend/stylesheets/bootstrap-5/main-style.scss`
           `!!to-string-loader!css-loader!resolve-url-loader!sass-loader!../../../services/web/frontend/stylesheets/bootstrap-5/main-style.scss`
         ),
         ),
@@ -163,15 +149,9 @@ const preview: Preview = {
   ],
   ],
   decorators: [
   decorators: [
     (Story, context) => {
     (Story, context) => {
-      const { bootstrap3Style, bootstrap5Style } = context.loaded
-      const bootstrapVersion = Number(
-        context.args[bootstrapVersionArg] ||
-          (context.parameters.bootstrap5 === false ? 3 : 5)
-      ) as 3 | 5
-      const activeStyle =
-        bootstrapVersion === 3 ? bootstrap3Style : bootstrap5Style
+      const { mainStyle } = context.loaded
 
 
-      resetMeta(bootstrapVersion)
+      resetMeta()
 
 
       return (
       return (
         <div
         <div
@@ -179,12 +159,8 @@ const preview: Preview = {
             context.globals.theme === 'main-light-' ? 'light' : 'default'
             context.globals.theme === 'main-light-' ? 'light' : 'default'
           }
           }
         >
         >
-          {activeStyle && <style>{activeStyle.default}</style>}
-          <Story
-            {...context}
-            // force re-renders when switching between Bootstrap versions
-            key={bootstrapVersion}
-          />
+          {mainStyle && <style>{mainStyle.default}</style>}
+          <Story {...context} />
         </div>
         </div>
       )
       )
     },
     },

+ 0 - 20
services/web/.storybook/utils/with-bootstrap-switcher.tsx

@@ -1,20 +0,0 @@
-import { Meta } from '@storybook/react'
-
-export const bootstrapVersionArg = 'bootstrapVersion'
-
-export const bsVersionDecorator: Meta = {
-  argTypes: {
-    [bootstrapVersionArg]: {
-      name: 'Bootstrap Version',
-      description: 'Bootstrap version for components',
-      control: { type: 'inline-radio' },
-      options: ['3', '5'],
-      table: {
-        defaultValue: { summary: '5' },
-      },
-    },
-  },
-  args: {
-    [bootstrapVersionArg]: '5',
-  },
-}

+ 0 - 1
services/web/cypress/support/ct/window.ts

@@ -10,7 +10,6 @@ export function resetMeta() {
     hasLinkedProjectOutputFileFeature: true,
     hasLinkedProjectOutputFileFeature: true,
     hasLinkUrlFeature: true,
     hasLinkUrlFeature: true,
   })
   })
-  window.metaAttributesCache.set('ol-bootstrapVersion', 5)
 }
 }
 
 
 // Populate meta for top-level access in modules on import
 // Populate meta for top-level access in modules on import

+ 0 - 19
services/web/frontend/js/features/file-tree/components/file-tree-context-menu.tsx

@@ -19,20 +19,11 @@ function FileTreeContextMenu() {
       toggleButtonRef.current = document.querySelector(
       toggleButtonRef.current = document.querySelector(
         '.entity-menu-toggle'
         '.entity-menu-toggle'
       ) as HTMLButtonElement | null
       ) as HTMLButtonElement | null
-      focusContextMenu()
     }
     }
   }, [contextMenuCoords])
   }, [contextMenuCoords])
 
 
   if (!contextMenuCoords || fileTreeReadOnly) return null
   if (!contextMenuCoords || fileTreeReadOnly) return null
 
 
-  // A11y - Move the focus to the context menu when it opens
-  function focusContextMenu() {
-    const BS3contextMenu = document.querySelector(
-      '[aria-labelledby="dropdown-file-tree-context-menu"]'
-    ) as HTMLElement | null
-    BS3contextMenu?.focus()
-  }
-
   function close() {
   function close() {
     setContextMenuCoords(null)
     setContextMenuCoords(null)
     if (toggleButtonRef.current) {
     if (toggleButtonRef.current) {
@@ -79,14 +70,4 @@ function FileTreeContextMenu() {
   )
   )
 }
 }
 
 
-// fake component required as Dropdowns require a Toggle, even tho we don't want
-// one for the context menu
-const FakeDropDownToggle = React.forwardRef<undefined, { bsRole: string }>(
-  ({ bsRole }, ref) => {
-    return null
-  }
-)
-
-FakeDropDownToggle.displayName = 'FakeDropDownToggle'
-
 export default FileTreeContextMenu
 export default FileTreeContextMenu

+ 1 - 4
services/web/frontend/js/features/history/components/change-list/change-list.tsx

@@ -11,10 +11,7 @@ function ChangeList() {
       <div className="history-header history-toggle-switch-container">
       <div className="history-header history-toggle-switch-container">
         <ToggleSwitch labelsOnly={labelsOnly} setLabelsOnly={setLabelsOnly} />
         <ToggleSwitch labelsOnly={labelsOnly} setLabelsOnly={setLabelsOnly} />
       </div>
       </div>
-      <div
-        className="history-version-list-container"
-        data-history-version-list-container
-      >
+      <div className="history-version-list-container">
         {labelsOnly ? <LabelsList /> : <AllHistoryList />}
         {labelsOnly ? <LabelsList /> : <AllHistoryList />}
       </div>
       </div>
     </aside>
     </aside>

+ 6 - 16
services/web/frontend/js/features/history/components/change-list/dropdown/actions-dropdown.tsx

@@ -3,26 +3,20 @@ import {
   Dropdown,
   Dropdown,
   DropdownMenu,
   DropdownMenu,
 } from '@/features/ui/components/bootstrap-5/dropdown-menu'
 } from '@/features/ui/components/bootstrap-5/dropdown-menu'
-import BS5DropdownToggleWithTooltip from '@/features/ui/components/bootstrap-5/dropdown-toggle-with-tooltip'
+import DropdownToggleWithTooltip from '@/features/ui/components/bootstrap-5/dropdown-toggle-with-tooltip'
 
 
 type ActionDropdownProps = {
 type ActionDropdownProps = {
   id: string
   id: string
   children: React.ReactNode
   children: React.ReactNode
-  parentSelector?: string
   isOpened: boolean
   isOpened: boolean
   iconTag: ReactNode
   iconTag: ReactNode
   toolTipDescription: string
   toolTipDescription: string
   setIsOpened: (isOpened: boolean) => void
   setIsOpened: (isOpened: boolean) => void
 }
 }
 
 
-function BS5ActionsDropdown({
-  id,
-  children,
-  isOpened,
-  iconTag,
-  setIsOpened,
-  toolTipDescription,
-}: Omit<ActionDropdownProps, 'parentSelector'>) {
+function ActionsDropdown(props: ActionDropdownProps) {
+  const { id, children, isOpened, iconTag, setIsOpened, toolTipDescription } =
+    props
   return (
   return (
     <Dropdown
     <Dropdown
       align="end"
       align="end"
@@ -30,7 +24,7 @@ function BS5ActionsDropdown({
       show={isOpened}
       show={isOpened}
       onToggle={open => setIsOpened(open)}
       onToggle={open => setIsOpened(open)}
     >
     >
-      <BS5DropdownToggleWithTooltip
+      <DropdownToggleWithTooltip
         id={`history-version-dropdown-${id}`}
         id={`history-version-dropdown-${id}`}
         className="history-version-dropdown-menu-btn"
         className="history-version-dropdown-menu-btn"
         aria-label={toolTipDescription}
         aria-label={toolTipDescription}
@@ -39,7 +33,7 @@ function BS5ActionsDropdown({
         tooltipProps={{ hidden: isOpened }}
         tooltipProps={{ hidden: isOpened }}
       >
       >
         {iconTag}
         {iconTag}
-      </BS5DropdownToggleWithTooltip>
+      </DropdownToggleWithTooltip>
       <DropdownMenu className="history-version-dropdown-menu">
       <DropdownMenu className="history-version-dropdown-menu">
         {children}
         {children}
       </DropdownMenu>
       </DropdownMenu>
@@ -47,8 +41,4 @@ function BS5ActionsDropdown({
   )
   )
 }
 }
 
 
-function ActionsDropdown(props: ActionDropdownProps) {
-  return <BS5ActionsDropdown {...props} />
-}
-
 export default ActionsDropdown
 export default ActionsDropdown

+ 0 - 1
services/web/frontend/js/features/history/components/change-list/dropdown/compare-version-dropdown.tsx

@@ -21,7 +21,6 @@ function CompareVersionDropdown({
       id={id}
       id={id}
       isOpened={isOpened}
       isOpened={isOpened}
       setIsOpened={setIsOpened}
       setIsOpened={setIsOpened}
-      parentSelector="[data-history-version-list-container]"
       toolTipDescription={t('compare')}
       toolTipDescription={t('compare')}
       iconTag={
       iconTag={
         <MaterialIcon
         <MaterialIcon

+ 0 - 1
services/web/frontend/js/features/history/components/change-list/dropdown/history-dropdown.tsx

@@ -25,7 +25,6 @@ function HistoryDropdown({
       iconTag={
       iconTag={
         <MaterialIcon type="more_vert" accessibilityLabel={t('more_actions')} />
         <MaterialIcon type="more_vert" accessibilityLabel={t('more_actions')} />
       }
       }
-      parentSelector="[data-history-version-list-container]"
     >
     >
       {children}
       {children}
     </ActionsDropdown>
     </ActionsDropdown>

+ 1 - 2
services/web/frontend/js/features/settings/components/emails/actions/make-primary/confirmation-modal.tsx

@@ -1,5 +1,4 @@
 import { useTranslation, Trans } from 'react-i18next'
 import { useTranslation, Trans } from 'react-i18next'
-import AccessibleModal from '../../../../../../shared/components/accessible-modal'
 import { MergeAndOverride } from '../../../../../../../../types/utils'
 import { MergeAndOverride } from '../../../../../../../../types/utils'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLModal, {
 import OLModal, {
@@ -11,7 +10,7 @@ import OLModal, {
 import { type UserEmailData } from '../../../../../../../../types/user-email'
 import { type UserEmailData } from '../../../../../../../../types/user-email'
 
 
 type ConfirmationModalProps = MergeAndOverride<
 type ConfirmationModalProps = MergeAndOverride<
-  React.ComponentProps<typeof AccessibleModal>,
+  React.ComponentProps<typeof OLModal>,
   {
   {
     email: string
     email: string
     isConfirmDisabled: boolean
     isConfirmDisabled: boolean

+ 0 - 3
services/web/frontend/js/features/settings/components/emails/reconfirmation-info/reconfirmation-info-prompt-text.tsx

@@ -4,19 +4,16 @@ import { Institution } from '../../../../../../../types/institution'
 type ReconfirmationInfoPromptTextProps = {
 type ReconfirmationInfoPromptTextProps = {
   primary: boolean
   primary: boolean
   institutionName: Institution['name']
   institutionName: Institution['name']
-  icon?: React.ReactElement // BS3 only
 }
 }
 
 
 function ReconfirmationInfoPromptText({
 function ReconfirmationInfoPromptText({
   primary,
   primary,
   institutionName,
   institutionName,
-  icon,
 }: ReconfirmationInfoPromptTextProps) {
 }: ReconfirmationInfoPromptTextProps) {
   const { t } = useTranslation()
   const { t } = useTranslation()
 
 
   return (
   return (
     <>
     <>
-      {icon}
       <Trans
       <Trans
         i18nKey="are_you_still_at"
         i18nKey="are_you_still_at"
         values={{
         values={{

+ 12 - 32
services/web/frontend/js/features/subscription/components/dashboard/group-settings-button.tsx

@@ -3,8 +3,6 @@ import { useTranslation } from 'react-i18next'
 import { useLocation } from '@/shared/hooks/use-location'
 import { useLocation } from '@/shared/hooks/use-location'
 import MaterialIcon from '@/shared/components/material-icon'
 import MaterialIcon from '@/shared/components/material-icon'
 import OLTag from '@/features/ui/components/ol/ol-tag'
 import OLTag from '@/features/ui/components/ol/ol-tag'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import { ManagedGroupSubscription } from '../../../../../../types/subscription/dashboard/subscription'
 import { ManagedGroupSubscription } from '../../../../../../types/subscription/dashboard/subscription'
 import { sendMB } from '../../../../infrastructure/event-tracking'
 import { sendMB } from '../../../../infrastructure/event-tracking'
 import starIcon from '../../images/star-gradient.svg'
 import starIcon from '../../images/star-gradient.svg'
@@ -24,7 +22,7 @@ function AvailableWithGroupProfessionalBadge() {
     <OLTag
     <OLTag
       prepend={<img aria-hidden="true" src={starIcon} alt="" />}
       prepend={<img aria-hidden="true" src={starIcon} alt="" />}
       contentProps={{
       contentProps={{
-        className: bsVersion({ bs5: 'mw-100' }),
+        className: 'mw-100',
         onClick: handleUpgradeClick,
         onClick: handleUpgradeClick,
       }}
       }}
     >
     >
@@ -82,35 +80,17 @@ export function GroupSettingsButtonWithAdBadge({
     useGroupSettingsButton(subscription)
     useGroupSettingsButton(subscription)
 
 
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <div className="row-link text-muted">
-          <div className="icon">
-            <MaterialIcon type="settings" />
-          </div>
-          <div className="text">
-            <div className="heading">{heading}</div>
-            <div className="subtext">{groupSettingRowSubText}</div>
-          </div>
-          <span>
-            <AvailableWithGroupProfessionalBadge />
-          </span>
+    <li className="list-group-item row-link">
+      <div className="row-link-inner">
+        <MaterialIcon type="settings" className="p-2 p-md-3 text-muted" />
+        <div className="flex-grow-1 text-truncate text-muted">
+          <strong>{heading}</strong>
+          <div className="text-truncate">{groupSettingRowSubText}</div>
         </div>
         </div>
-      }
-      bs5={
-        <li className="list-group-item row-link">
-          <div className="row-link-inner">
-            <MaterialIcon type="settings" className="p-2 p-md-3 text-muted" />
-            <div className="flex-grow-1 text-truncate text-muted">
-              <strong>{heading}</strong>
-              <div className="text-truncate">{groupSettingRowSubText}</div>
-            </div>
-            <span className="p-2 p-md-3">
-              <AvailableWithGroupProfessionalBadge />
-            </span>
-          </div>
-        </li>
-      }
-    />
+        <span className="p-2 p-md-3">
+          <AvailableWithGroupProfessionalBadge />
+        </span>
+      </div>
+    </li>
   )
   )
 }
 }

+ 0 - 5
services/web/frontend/js/features/subscription/components/dashboard/leave-group-modal.tsx

@@ -71,11 +71,6 @@ export default function LeaveGroupModal() {
           disabled={inflight}
           disabled={inflight}
           isLoading={inflight}
           isLoading={inflight}
           loadingLabel={t('processing_uppercase') + '…'}
           loadingLabel={t('processing_uppercase') + '…'}
-          bs3Props={{
-            loading: inflight
-              ? t('processing_uppercase') + '…'
-              : t('leave_now'),
-          }}
         >
         >
           {t('leave_now')}
           {t('leave_now')}
         </OLButton>
         </OLButton>

+ 1 - 5
services/web/frontend/js/features/subscription/components/dashboard/managed-group-subscriptions.tsx

@@ -7,8 +7,6 @@ import { Trans, useTranslation } from 'react-i18next'
 import { useSubscriptionDashboardContext } from '../../context/subscription-dashboard-context'
 import { useSubscriptionDashboardContext } from '../../context/subscription-dashboard-context'
 import { RowLink } from './row-link'
 import { RowLink } from './row-link'
 import { ManagedGroupSubscription } from '../../../../../../types/subscription/dashboard/subscription'
 import { ManagedGroupSubscription } from '../../../../../../types/subscription/dashboard/subscription'
-import { bsVersion } from '@/features/utils/bootstrap-5'
-import classnames from 'classnames'
 
 
 function ManagedGroupAdministrator({
 function ManagedGroupAdministrator({
   subscription,
   subscription,
@@ -104,9 +102,7 @@ export default function ManagedGroupSubscriptions() {
       {managedGroupSubscriptions.map(subscription => {
       {managedGroupSubscriptions.map(subscription => {
         return (
         return (
           <div key={`managed-group-${subscription._id}`}>
           <div key={`managed-group-${subscription._id}`}>
-            <h2 className={classnames('h3', bsVersion({ bs5: 'fw-bold' }))}>
-              {t('group_management')}
-            </h2>
+            <h2 className="h3 fw-bold">{t('group_management')}</h2>
             <p>
             <p>
               <ManagedGroupAdministrator subscription={subscription} />
               <ManagedGroupAdministrator subscription={subscription} />
             </p>
             </p>

+ 0 - 3
services/web/frontend/js/features/subscription/components/dashboard/personal-subscription-recurly-sync-email.tsx

@@ -51,9 +51,6 @@ function PersonalSubscriptionRecurlySyncEmail() {
                   disabled={isLoading}
                   disabled={isLoading}
                   isLoading={isLoading}
                   isLoading={isLoading}
                   loadingLabel={t('updating')}
                   loadingLabel={t('updating')}
-                  bs3Props={{
-                    loading: isLoading ? t('updating') + '…' : t('update'),
-                  }}
                 >
                 >
                   {t('update')}
                   {t('update')}
                 </OLButton>
                 </OLButton>

+ 1 - 23
services/web/frontend/js/features/subscription/components/dashboard/row-link.tsx

@@ -1,5 +1,4 @@
 import MaterialIcon from '../../../../shared/components/material-icon'
 import MaterialIcon from '../../../../shared/components/material-icon'
-import { isBootstrap5 } from '@/features/utils/bootstrap-5'
 
 
 type RowLinkProps = {
 type RowLinkProps = {
   href: string
   href: string
@@ -8,28 +7,7 @@ type RowLinkProps = {
   icon: string
   icon: string
 }
 }
 
 
-export function RowLink(props: RowLinkProps) {
-  return isBootstrap5() ? <BS5RowLink {...props} /> : <BS3RowLink {...props} />
-}
-
-function BS3RowLink({ href, heading, subtext, icon }: RowLinkProps) {
-  return (
-    <a href={href} className="row-link">
-      <div className="icon">
-        <MaterialIcon type={icon} />
-      </div>
-      <div className="text">
-        <div className="heading">{heading}</div>
-        <div className="subtext">{subtext}</div>
-      </div>
-      <div className="icon arrow">
-        <MaterialIcon type="keyboard_arrow_right" />
-      </div>
-    </a>
-  )
-}
-
-function BS5RowLink({ href, heading, subtext, icon }: RowLinkProps) {
+export function RowLink({ href, heading, subtext, icon }: RowLinkProps) {
   return (
   return (
     <li className="list-group-item row-link">
     <li className="list-group-item row-link">
       <a href={href} className="row-link-inner">
       <a href={href} className="row-link-inner">

+ 3 - 11
services/web/frontend/js/features/subscription/components/dashboard/states/active/active-new.tsx

@@ -12,7 +12,6 @@ import { ChangeToGroupModal } from './change-plan/modals/change-to-group-modal'
 import { CancelAiAddOnModal } from '@/features/subscription/components/dashboard/states/active/change-plan/modals/cancel-ai-add-on-modal'
 import { CancelAiAddOnModal } from '@/features/subscription/components/dashboard/states/active/change-plan/modals/cancel-ai-add-on-modal'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import isInFreeTrial from '../../../../util/is-in-free-trial'
 import isInFreeTrial from '../../../../util/is-in-free-trial'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import AddOns from '@/features/subscription/components/dashboard/states/active/add-ons'
 import AddOns from '@/features/subscription/components/dashboard/states/active/add-ons'
 import {
 import {
   AI_ADD_ON_CODE,
   AI_ADD_ON_CODE,
@@ -20,7 +19,6 @@ import {
   isStandaloneAiPlanCode,
   isStandaloneAiPlanCode,
 } from '@/features/subscription/data/add-on-codes'
 } from '@/features/subscription/data/add-on-codes'
 import getMeta from '@/utils/meta'
 import getMeta from '@/utils/meta'
-import classnames from 'classnames'
 import SubscriptionRemainder from '@/features/subscription/components/dashboard/states/active/subscription-remainder'
 import SubscriptionRemainder from '@/features/subscription/components/dashboard/states/active/subscription-remainder'
 import { sendMB } from '../../../../../../infrastructure/event-tracking'
 import { sendMB } from '../../../../../../infrastructure/event-tracking'
 import PauseSubscriptionModal from '@/features/subscription/components/dashboard/pause-modal'
 import PauseSubscriptionModal from '@/features/subscription/components/dashboard/pause-modal'
@@ -100,9 +98,7 @@ export function ActiveSubscriptionNew({
           />
           />
         )}
         )}
       </div>
       </div>
-      <h2 className={classnames('h3', bsVersion({ bs5: 'fw-bold' }))}>
-        {t('billing')}
-      </h2>
+      <h2 className="h3 fw-bold">{t('billing')}</h2>
       <p className="mb-1">
       <p className="mb-1">
         {subscription.plan.annual ? (
         {subscription.plan.annual ? (
           <Trans
           <Trans
@@ -169,12 +165,8 @@ export function ActiveSubscriptionNew({
         )}
         )}
       </div>
       </div>
       <hr />
       <hr />
-      <h2 className={classnames('h3', bsVersion({ bs5: 'fw-bold' }))}>
-        {t('plan')}
-      </h2>
-      <h3 className={classnames('h5 mt-0 mb-1', bsVersion({ bs5: 'fw-bold' }))}>
-        {planName}
-      </h3>
+      <h2 className="h3 fw-bold">{t('plan')}</h2>
+      <h3 className="h5 mt-0 mb-1 fw-bold">{planName}</h3>
       {subscription.pendingPlan &&
       {subscription.pendingPlan &&
         subscription.pendingPlan.name !== subscription.plan.name && (
         subscription.pendingPlan.name !== subscription.plan.name && (
           <p className="mb-1">{t('want_change_to_apply_before_plan_end')}</p>
           <p className="mb-1">{t('want_change_to_apply_before_plan_end')}</p>

+ 0 - 3
services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/downgrade-plan-button.tsx

@@ -41,9 +41,6 @@ export default function DowngradePlanButton({
       disabled={isButtonDisabled}
       disabled={isButtonDisabled}
       isLoading={isLoading}
       isLoading={isLoading}
       loadingLabel={t('processing_uppercase') + '…'}
       loadingLabel={t('processing_uppercase') + '…'}
-      bs3Props={{
-        loading: isLoading ? t('processing_uppercase') + '…' : buttonText,
-      }}
     >
     >
       {buttonText}
       {buttonText}
     </OLButton>
     </OLButton>

+ 0 - 3
services/web/frontend/js/features/subscription/components/dashboard/states/active/cancel-plan/extend-trial-button.tsx

@@ -34,9 +34,6 @@ export default function ExtendTrialButton({
       disabled={isButtonDisabled}
       disabled={isButtonDisabled}
       isLoading={isLoading}
       isLoading={isLoading}
       loadingLabel={t('processing_uppercase') + '…'}
       loadingLabel={t('processing_uppercase') + '…'}
-      bs3Props={{
-        loading: isLoading ? t('processing_uppercase') + '…' : buttonText,
-      }}
     >
     >
       {buttonText}
       {buttonText}
     </OLButton>
     </OLButton>

+ 0 - 5
services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/cancel-ai-add-on-modal.tsx

@@ -107,11 +107,6 @@ export function CancelAiAddOnModal() {
           isLoading={inflight}
           isLoading={inflight}
           loadingLabel={t('processing_uppercase') + '…'}
           loadingLabel={t('processing_uppercase') + '…'}
           onClick={handleConfirmChange}
           onClick={handleConfirmChange}
-          bs3Props={{
-            loading: inflight
-              ? t('processing_uppercase') + '…'
-              : t('cancel_add_on'),
-          }}
         >
         >
           {t('cancel_add_on')}
           {t('cancel_add_on')}
         </OLButton>
         </OLButton>

+ 1 - 13
services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/change-to-group-modal.tsx

@@ -22,9 +22,7 @@ import OLFormCheckbox from '@/features/ui/components/ol/ol-form-checkbox'
 import { useContactUsModal } from '@/shared/hooks/use-contact-us-modal'
 import { useContactUsModal } from '@/shared/hooks/use-contact-us-modal'
 import { UserProvider } from '@/shared/context/user-context'
 import { UserProvider } from '@/shared/context/user-context'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import OLNotification from '@/features/ui/components/ol/ol-notification'
 import OLNotification from '@/features/ui/components/ol/ol-notification'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 
 const educationalPercentDiscount = 40
 const educationalPercentDiscount = 40
 
 
@@ -79,8 +77,6 @@ function GroupPrice({
             })}
             })}
       </span>
       </span>
 
 
-      <BootstrapVersionSwitcher bs3={<br />} />
-
       <span className="circle-subtext">
       <span className="circle-subtext">
         <span aria-hidden>
         <span aria-hidden>
           {t('x_price_per_user', {
           {t('x_price_per_user', {
@@ -221,10 +217,7 @@ export function ChangeToGroupModal() {
                   <fieldset className="form-group">
                   <fieldset className="form-group">
                     <legend className="legend-as-label">{t('plan')}</legend>
                     <legend className="legend-as-label">{t('plan')}</legend>
                     {groupPlans.plans.map(option => (
                     {groupPlans.plans.map(option => (
-                      <div
-                        className={bsVersion({ bs3: 'radio' })}
-                        key={option.code}
-                      >
+                      <div key={option.code}>
                         <OLFormCheckbox
                         <OLFormCheckbox
                           type="radio"
                           type="radio"
                           name="plan-code"
                           name="plan-code"
@@ -333,11 +326,6 @@ export function ChangeToGroupModal() {
               onClick={upgrade}
               onClick={upgrade}
               isLoading={inflight}
               isLoading={inflight}
               loadingLabel={t('processing_uppercase') + '…'}
               loadingLabel={t('processing_uppercase') + '…'}
-              bs3Props={{
-                loading: inflight
-                  ? t('processing_uppercase') + '…'
-                  : t('upgrade_now'),
-              }}
             >
             >
               {t('upgrade_now')}
               {t('upgrade_now')}
             </OLButton>
             </OLButton>

+ 0 - 5
services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/confirm-change-plan-modal.tsx

@@ -112,11 +112,6 @@ export function ConfirmChangePlanModal() {
           isLoading={inflight}
           isLoading={inflight}
           loadingLabel={t('processing_uppercase') + '…'}
           loadingLabel={t('processing_uppercase') + '…'}
           onClick={handleConfirmChange}
           onClick={handleConfirmChange}
-          bs3Props={{
-            loading: inflight
-              ? t('processing_uppercase') + '…'
-              : t('change_plan'),
-          }}
         >
         >
           {t('change_plan')}
           {t('change_plan')}
         </OLButton>
         </OLButton>

+ 0 - 5
services/web/frontend/js/features/subscription/components/dashboard/states/active/change-plan/modals/keep-current-plan-modal.tsx

@@ -93,11 +93,6 @@ export function KeepCurrentPlanModal() {
           isLoading={inflight}
           isLoading={inflight}
           loadingLabel={t('processing_uppercase') + '…'}
           loadingLabel={t('processing_uppercase') + '…'}
           onClick={confirmCancelPendingPlanChange}
           onClick={confirmCancelPendingPlanChange}
-          bs3Props={{
-            loading: inflight
-              ? t('processing_uppercase') + '…'
-              : t('revert_pending_plan_change'),
-          }}
         >
         >
           {t('revert_pending_plan_change')}
           {t('revert_pending_plan_change')}
         </OLButton>
         </OLButton>

+ 0 - 71
services/web/frontend/js/features/ui/components/bootstrap-3/dropdown-menu-with-ref.tsx

@@ -1,71 +0,0 @@
-import { forwardRef, SyntheticEvent } from 'react'
-import classnames from 'classnames'
-import RootCloseWrapper from 'react-overlays/lib/RootCloseWrapper'
-import { DropdownProps } from 'react-bootstrap'
-import { MergeAndOverride } from '../../../../../../types/utils'
-
-type DropdownMenuWithRefProps = MergeAndOverride<
-  Pick<DropdownProps, 'bsClass' | 'open' | 'pullRight' | 'onClose'>,
-  {
-    children: React.ReactNode
-    bsRole: 'menu'
-    menuRef: React.MutableRefObject<HTMLElement | undefined>
-    className?: string
-    // The props below are passed by react-bootstrap
-    labelledBy?: string | undefined
-    rootCloseEvent?: 'click' | 'mousedown' | undefined
-    onClose?: (e: SyntheticEvent<any>) => void
-  }
->
-
-const DropdownMenuWithRef = forwardRef<
-  HTMLUListElement,
-  DropdownMenuWithRefProps
->(function (props, ref) {
-  const {
-    children,
-    bsRole,
-    bsClass,
-    className,
-    open,
-    pullRight,
-    labelledBy,
-    menuRef,
-    onClose,
-    rootCloseEvent,
-    ...rest
-  } = props
-
-  // expose the menu reference to both the `menuRef` and `ref callback` from react-bootstrap
-  const handleRefs = (node: HTMLUListElement) => {
-    if (typeof ref === 'function') {
-      ref(node)
-    }
-    menuRef.current = node
-  }
-
-  // Implementation as suggested in
-  // https://react-bootstrap-v3.netlify.app/components/dropdowns/#btn-dropdowns-props-dropdown
-  return (
-    <RootCloseWrapper
-      disabled={!open}
-      onRootClose={onClose}
-      event={rootCloseEvent}
-    >
-      <ul
-        role={bsRole}
-        className={classnames(className, bsClass, {
-          'dropdown-menu-right': pullRight,
-        })}
-        aria-labelledby={labelledBy}
-        ref={handleRefs}
-        {...rest}
-      >
-        {children}
-      </ul>
-    </RootCloseWrapper>
-  )
-})
-DropdownMenuWithRef.displayName = 'DropdownMenuWithRef'
-
-export default DropdownMenuWithRef

+ 0 - 53
services/web/frontend/js/features/ui/components/bootstrap-3/dropdown-toggle-with-tooltip.tsx

@@ -1,53 +0,0 @@
-import { forwardRef } from 'react'
-import Tooltip from '../../../../shared/components/tooltip'
-import classnames from 'classnames'
-import { DropdownProps } from 'react-bootstrap'
-import { MergeAndOverride } from '../../../../../../types/utils'
-
-type CustomToggleProps = MergeAndOverride<
-  Pick<DropdownProps, 'bsClass' | 'open'>,
-  {
-    children: React.ReactNode
-    isOpened: boolean
-    bsRole: 'toggle'
-    className?: string
-    tooltipProps: Omit<React.ComponentProps<typeof Tooltip>, 'children'>
-  }
->
-
-const DropdownToggleWithTooltip = forwardRef<
-  HTMLButtonElement,
-  CustomToggleProps
->(function (props, ref) {
-  const {
-    tooltipProps,
-    isOpened,
-    children,
-    bsClass,
-    className,
-    open,
-    bsRole: _bsRole,
-    ...rest
-  } = props
-
-  const button = (
-    <button
-      type="button"
-      ref={ref}
-      className={classnames(bsClass, 'btn', className)}
-      aria-expanded={open}
-      aria-haspopup="true"
-      {...rest}
-    >
-      {children}
-    </button>
-  )
-
-  return (
-    <>{isOpened ? button : <Tooltip {...tooltipProps}>{button}</Tooltip>}</>
-  )
-})
-
-DropdownToggleWithTooltip.displayName = 'DropdownToggleWithTooltip'
-
-export default DropdownToggleWithTooltip

+ 0 - 21
services/web/frontend/js/features/ui/components/bootstrap-3/form/form-control.tsx

@@ -1,21 +0,0 @@
-import {
-  FormControl as BS3FormControl,
-  FormControlProps as BS3FormControlProps,
-} from 'react-bootstrap'
-
-type FormControlProps = BS3FormControlProps & {
-  prepend?: React.ReactNode
-  append?: React.ReactNode
-}
-
-function FormControl({ prepend, append, ...props }: FormControlProps) {
-  return (
-    <>
-      {prepend && <div className="form-control-feedback-left">{prepend}</div>}
-      <BS3FormControl {...props} />
-      {append && <div className="form-control-feedback">{append}</div>}
-    </>
-  )
-}
-
-export default FormControl

+ 0 - 14
services/web/frontend/js/features/ui/components/bootstrap-3/toast-container.tsx

@@ -1,14 +0,0 @@
-import classNames from 'classnames'
-import { FC, HTMLProps } from 'react'
-
-export const ToastContainer: FC<HTMLProps<HTMLDivElement>> = ({
-  children,
-  className,
-  ...props
-}) => {
-  return (
-    <div className={classNames('toast-container', className)} {...props}>
-      {children}
-    </div>
-  )
-}

+ 0 - 51
services/web/frontend/js/features/ui/components/bootstrap-3/toast.tsx

@@ -1,51 +0,0 @@
-import classNames from 'classnames'
-import { FC, useCallback, useEffect, useRef } from 'react'
-
-type ToastProps = {
-  onClose?: () => void
-  onExited?: () => void
-  autohide?: boolean
-  delay?: number
-  show: boolean
-  className?: string
-}
-export const Toast: FC<ToastProps> = ({
-  children,
-  delay = 5000,
-  onClose,
-  onExited,
-  autohide,
-  show,
-  className,
-}) => {
-  const delayRef = useRef(delay)
-  const onCloseRef = useRef(onClose)
-  const onExitedRef = useRef(onExited)
-  const shouldAutoHide = Boolean(autohide && show)
-
-  const handleTimeout = useCallback(() => {
-    if (shouldAutoHide) {
-      onCloseRef.current?.()
-      onExitedRef.current?.()
-    }
-  }, [shouldAutoHide])
-
-  useEffect(() => {
-    const timeout = window.setTimeout(handleTimeout, delayRef.current)
-    return () => window.clearTimeout(timeout)
-  }, [handleTimeout])
-
-  if (!show) {
-    return null
-  }
-
-  return (
-    <div
-      className={classNames('toast', show ? 'show' : 'hide', className)}
-      aria-live="assertive"
-      role="alert"
-    >
-      {children}
-    </div>
-  )
-}

+ 0 - 99
services/web/frontend/js/features/ui/components/bootstrap-3/toggle-button-group.tsx

@@ -1,99 +0,0 @@
-import {
-  Children,
-  cloneElement,
-  isValidElement,
-  useState,
-  useEffect,
-} from 'react'
-import {
-  ToggleButtonGroup as BS3ToggleButtonGroup,
-  ToggleButtonGroupProps as BS3ToggleButtonGroupProps,
-  ToggleButtonProps as BS3ToggleButtonProps,
-} from 'react-bootstrap'
-
-function ToggleButtonGroup<T extends string | number>({
-  children,
-  value,
-  defaultValue,
-  onChange,
-  ...props
-}: BS3ToggleButtonGroupProps) {
-  const [selectedValue, setSelectedValue] = useState<T | T[] | null>(
-    defaultValue || (props.type === 'checkbox' ? [] : null)
-  )
-  const isControlled = value !== undefined
-
-  useEffect(() => {
-    if (isControlled) {
-      if (props.type === 'radio') {
-        setSelectedValue(value)
-      } else {
-        if (Array.isArray(value)) {
-          setSelectedValue(Array.from(value))
-        } else {
-          setSelectedValue([value])
-        }
-      }
-    }
-  }, [isControlled, value, props.type])
-
-  const handleButtonClick = (buttonValue: T) => {
-    if (props.type === 'radio') {
-      if (!isControlled) {
-        setSelectedValue(buttonValue)
-      }
-
-      onChange?.(buttonValue as any)
-    } else if (props.type === 'checkbox') {
-      const newValue = Array.isArray(selectedValue)
-        ? selectedValue.includes(buttonValue)
-          ? selectedValue.filter(val => val !== buttonValue) // Deselect
-          : [...selectedValue, buttonValue] // Select
-        : [buttonValue] // Initial selection if value is not array yet
-
-      if (!isControlled) {
-        setSelectedValue(newValue)
-      }
-
-      onChange?.(newValue)
-    }
-  }
-
-  // Clone children and add custom onClick handlers
-  const modifiedChildren = Children.map(children, child => {
-    if (isValidElement(child)) {
-      const childElement = child as React.ReactElement<
-        BS3ToggleButtonProps & { active?: boolean }
-      >
-
-      const isActive =
-        props.type === 'radio'
-          ? selectedValue === childElement.props.value
-          : Array.isArray(selectedValue) &&
-            selectedValue.includes(childElement.props.value as T)
-
-      return cloneElement(childElement, {
-        onClick: () => {
-          handleButtonClick(childElement.props.value as T)
-        },
-        active: isActive,
-      })
-    }
-
-    return child
-  })
-
-  return (
-    <BS3ToggleButtonGroup
-      {...props}
-      value={isControlled ? value : undefined}
-      defaultValue={defaultValue}
-      // Ignore the broken onChange handler
-      onChange={() => {}}
-    >
-      {modifiedChildren}
-    </BS3ToggleButtonGroup>
-  )
-}
-
-export default ToggleButtonGroup

+ 0 - 15
services/web/frontend/js/features/ui/components/bootstrap-5/bootstrap-version-switcher.tsx

@@ -1,15 +0,0 @@
-import { isBootstrap5 } from '@/features/utils/bootstrap-5'
-
-type BootstrapVersionSwitcherProps = {
-  bs3?: React.ReactNode
-  bs5?: React.ReactNode
-}
-
-function BootstrapVersionSwitcher({
-  bs3,
-  bs5,
-}: BootstrapVersionSwitcherProps): React.ReactElement {
-  return <>{isBootstrap5() ? bs5 : bs3}</>
-}
-
-export default BootstrapVersionSwitcher

+ 1 - 8
services/web/frontend/js/features/ui/components/ol/icons/ol-tag-icon.tsx

@@ -1,12 +1,5 @@
-import Icon from '@/shared/components/icon'
 import MaterialIcon from '@/shared/components/material-icon'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 
 export default function OLTagIcon() {
 export default function OLTagIcon() {
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<Icon type="tag" fw />}
-      bs5={<MaterialIcon type="sell" />}
-    />
-  )
+  return <MaterialIcon type="sell" />
 }
 }

+ 2 - 35
services/web/frontend/js/features/ui/components/ol/ol-badge.tsx

@@ -1,40 +1,7 @@
-import { Label } from 'react-bootstrap'
 import Badge from '@/features/ui/components/bootstrap-5/badge'
 import Badge from '@/features/ui/components/bootstrap-5/badge'
-import BS3Badge from '@/shared/components/badge'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 
-type OLBadgeProps = React.ComponentProps<typeof Badge> & {
-  bs3Props?: {
-    bsStyle?: React.ComponentProps<typeof Label>['bsStyle'] | null
-  }
-}
-
-function OLBadge(props: OLBadgeProps) {
-  const { bs3Props, ...rest } = props
-
-  let bs3BadgeProps: React.ComponentProps<typeof BS3Badge> = {
-    prepend: rest.prepend,
-    children: rest.children,
-    className: rest.className,
-    bsStyle: rest.bg,
-  }
-
-  if (bs3Props) {
-    const { bsStyle, ...restBs3Props } = bs3Props
-
-    bs3BadgeProps = {
-      ...bs3BadgeProps,
-      ...restBs3Props,
-      bsStyle: 'bsStyle' in bs3Props ? bsStyle : rest.bg,
-    }
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Badge {...bs3BadgeProps} />}
-      bs5={<Badge {...rest} />}
-    />
-  )
+function OLBadge(props: React.ComponentProps<typeof Badge>) {
+  return <Badge {...props} />
 }
 }
 
 
 export default OLBadge
 export default OLBadge

+ 2 - 25
services/web/frontend/js/features/ui/components/ol/ol-button-group.tsx

@@ -1,30 +1,7 @@
 import { ButtonGroup, ButtonGroupProps } from 'react-bootstrap-5'
 import { ButtonGroup, ButtonGroupProps } from 'react-bootstrap-5'
-import {
-  ButtonGroup as BS3ButtonGroup,
-  ButtonGroupProps as BS3ButtonGroupProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type OLButtonGroupProps = ButtonGroupProps & {
-  bs3Props?: Record<string, unknown>
-}
-
-function OLButtonGroup({ bs3Props, as, ...rest }: OLButtonGroupProps) {
-  const bs3ButtonGroupProps: BS3ButtonGroupProps = {
-    children: rest.children,
-    className: rest.className,
-    vertical: rest.vertical,
-    ...getAriaAndDataProps(rest),
-    ...bs3Props,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3ButtonGroup {...bs3ButtonGroupProps} />}
-      bs5={<ButtonGroup {...rest} as={as} />}
-    />
-  )
+function OLButtonGroup({ as, ...rest }: ButtonGroupProps) {
+  return <ButtonGroup {...rest} as={as} />
 }
 }
 
 
 export default OLButtonGroup
 export default OLButtonGroup

+ 2 - 26
services/web/frontend/js/features/ui/components/ol/ol-button-toolbar.tsx

@@ -1,31 +1,7 @@
 import { ButtonToolbar, ButtonToolbarProps } from 'react-bootstrap-5'
 import { ButtonToolbar, ButtonToolbarProps } from 'react-bootstrap-5'
-import {
-  ButtonToolbar as BS3ButtonToolbar,
-  ButtonToolbarProps as BS3ButtonToolbarProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type OLButtonToolbarProps = ButtonToolbarProps & {
-  bs3Props?: Record<string, unknown>
-}
-
-function OLButtonToolbar(props: OLButtonToolbarProps) {
-  const { bs3Props, ...rest } = props
-
-  const bs3ButtonToolbarProps: BS3ButtonToolbarProps = {
-    children: rest.children,
-    className: rest.className,
-    ...getAriaAndDataProps(rest),
-    ...bs3Props,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3ButtonToolbar {...bs3ButtonToolbarProps} />}
-      bs5={<ButtonToolbar {...rest} />}
-    />
-  )
+function OLButtonToolbar(props: ButtonToolbarProps) {
+  return <ButtonToolbar {...props} />
 }
 }
 
 
 export default OLButtonToolbar
 export default OLButtonToolbar

+ 4 - 123
services/web/frontend/js/features/ui/components/ol/ol-button.tsx

@@ -1,132 +1,13 @@
 import { forwardRef } from 'react'
 import { forwardRef } from 'react'
-import BootstrapVersionSwitcher from '../bootstrap-5/bootstrap-version-switcher'
-import { Button as BS3Button } from 'react-bootstrap'
 import type { ButtonProps } from '@/features/ui/components/types/button-props'
 import type { ButtonProps } from '@/features/ui/components/types/button-props'
-import type { ButtonProps as BS3ButtonPropsBase } from 'react-bootstrap'
 import Button from '../bootstrap-5/button'
 import Button from '../bootstrap-5/button'
-import classnames from 'classnames'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
-import { callFnsInSequence } from '@/utils/functions'
-import Icon from '@/shared/components/icon'
 
 
-export type BS3ButtonSize = 'xsmall' | 'sm' | 'medium' | 'lg'
+export type OLButtonProps = ButtonProps
 
 
-export type OLButtonProps = ButtonProps & {
-  bs3Props?: {
-    loading?: React.ReactNode
-    bsSize?: BS3ButtonSize
-    block?: boolean
-    className?: string
-    onMouseOver?: React.MouseEventHandler<HTMLButtonElement>
-    onMouseOut?: React.MouseEventHandler<HTMLButtonElement>
-    onFocus?: React.FocusEventHandler<HTMLButtonElement>
-    onBlur?: React.FocusEventHandler<HTMLButtonElement>
-  }
-}
+const OLButton = forwardRef<HTMLButtonElement, OLButtonProps>((props, ref) => {
+  return <Button {...props} ref={ref} />
+})
 
 
-// Resolve type mismatch of the onClick event handler
-export type BS3ButtonProps = Omit<BS3ButtonPropsBase, 'onClick'> & {
-  onClick?: React.MouseEventHandler<any>
-}
-
-export function bs3ButtonProps(props: ButtonProps) {
-  const bs3ButtonProps: BS3ButtonProps = {
-    bsStyle: null,
-    bsSize: props.size,
-    className: classnames(`btn-${props.variant || 'primary'}`, props.className),
-    disabled: props.isLoading || props.disabled,
-    form: props.form,
-    href: props.href,
-    id: props.id,
-    target: props.target,
-    rel: props.rel,
-    onClick: props.onClick,
-    onMouseDown: props.onMouseDown as BS3ButtonProps['onMouseDown'],
-    type: props.type,
-    draggable: props.draggable,
-    download: props.download,
-    style: props.style,
-    active: props.active,
-  }
-  return bs3ButtonProps
-}
-
-function BS3ButtonContent({
-  children,
-  leadingIcon,
-  trailingIcon,
-}: {
-  children: React.ReactNode
-  leadingIcon: OLButtonProps['leadingIcon']
-  trailingIcon: OLButtonProps['trailingIcon']
-}) {
-  const leadingIconComponent =
-    leadingIcon && typeof leadingIcon === 'string' ? (
-      <Icon type={leadingIcon} />
-    ) : (
-      leadingIcon
-    )
-
-  const trailingIconComponent =
-    trailingIcon && typeof trailingIcon === 'string' ? (
-      <Icon type={trailingIcon} />
-    ) : (
-      trailingIcon
-    )
-
-  return (
-    <>
-      {leadingIconComponent ? <>{leadingIconComponent}&nbsp;</> : null}
-      {children}
-      {trailingIconComponent ? <>&nbsp;{trailingIconComponent}</> : null}
-    </>
-  )
-}
-
-const OLButton = forwardRef<HTMLButtonElement, OLButtonProps>(
-  ({ bs3Props = {}, ...rest }, ref) => {
-    const { className: _, ...restBs3Props } = bs3Props
-
-    // BS3 OverlayTrigger automatically provides 'onMouseOver', 'onMouseOut', 'onFocus', 'onBlur' event handlers
-    const bs3FinalProps = {
-      ...restBs3Props,
-      onMouseOver: callFnsInSequence(bs3Props?.onMouseOver, rest.onMouseOver),
-      onMouseOut: callFnsInSequence(bs3Props?.onMouseOut, rest.onMouseOut),
-      onFocus: callFnsInSequence(bs3Props?.onFocus, rest.onFocus),
-      onBlur: callFnsInSequence(bs3Props?.onBlur, rest.onBlur),
-    }
-
-    // Get all `aria-*` and `data-*` attributes
-    const extraProps = getAriaAndDataProps(rest)
-
-    return (
-      <BootstrapVersionSwitcher
-        bs3={
-          <BS3Button
-            {...bs3ButtonProps({
-              ...rest,
-              // Override the `className` with bs3 specific className (if provided)
-              className: bs3Props?.className ?? rest.className,
-            })}
-            {...extraProps}
-            {...bs3FinalProps}
-            ref={ref as React.LegacyRef<any> | undefined}
-          >
-            {bs3Props?.loading || (
-              <BS3ButtonContent
-                leadingIcon={rest.leadingIcon}
-                trailingIcon={rest.trailingIcon}
-              >
-                {rest.children}
-              </BS3ButtonContent>
-            )}
-          </BS3Button>
-        }
-        bs5={<Button {...rest} ref={ref} />}
-      />
-    )
-  }
-)
 OLButton.displayName = 'OLButton'
 OLButton.displayName = 'OLButton'
 
 
 export default OLButton
 export default OLButton

+ 3 - 10
services/web/frontend/js/features/ui/components/ol/ol-card.tsx

@@ -1,18 +1,11 @@
 import { Card } from 'react-bootstrap-5'
 import { Card } from 'react-bootstrap-5'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { FC } from 'react'
 import { FC } from 'react'
-import classNames from 'classnames'
 
 
 const OLCard: FC<{ className?: string }> = ({ children, className }) => {
 const OLCard: FC<{ className?: string }> = ({ children, className }) => {
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={<div className={classNames('card', className)}>{children}</div>}
-      bs5={
-        <Card className={className}>
-          <Card.Body>{children}</Card.Body>
-        </Card>
-      }
-    />
+    <Card className={className}>
+      <Card.Body>{children}</Card.Body>
+    </Card>
   )
   )
 }
 }
 
 

+ 1 - 21
services/web/frontend/js/features/ui/components/ol/ol-close-button.tsx

@@ -1,6 +1,4 @@
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { CloseButton, CloseButtonProps } from 'react-bootstrap-5'
 import { CloseButton, CloseButtonProps } from 'react-bootstrap-5'
-import classNames from 'classnames'
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
 import { forwardRef } from 'react'
 import { forwardRef } from 'react'
 
 
@@ -8,25 +6,7 @@ const OLCloseButton = forwardRef<HTMLButtonElement, CloseButtonProps>(
   (props, ref) => {
   (props, ref) => {
     const { t } = useTranslation()
     const { t } = useTranslation()
 
 
-    const bs3CloseButtonProps: React.ButtonHTMLAttributes<HTMLButtonElement> = {
-      className: classNames('close', props.className),
-      onClick: props.onClick,
-      onMouseOver: props.onMouseOver,
-      onMouseOut: props.onMouseOut,
-
-      'aria-label': t('close'),
-    }
-
-    return (
-      <BootstrapVersionSwitcher
-        bs3={
-          <button {...bs3CloseButtonProps}>
-            <span aria-hidden="true">&times;</span>
-          </button>
-        }
-        bs5={<CloseButton ref={ref} {...props} />}
-      />
-    )
+    return <CloseButton ref={ref} aria-label={t('close')} {...props} />
   }
   }
 )
 )
 
 

+ 2 - 68
services/web/frontend/js/features/ui/components/ol/ol-col.tsx

@@ -1,73 +1,7 @@
 import { Col } from 'react-bootstrap-5'
 import { Col } from 'react-bootstrap-5'
-import { Col as BS3Col } from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 
-type OLColProps = React.ComponentProps<typeof Col> & {
-  bs3Props?: Record<string, unknown>
-}
-
-function OLCol(props: OLColProps) {
-  const { bs3Props, ...rest } = props
-
-  const getBs3Sizes = (obj: typeof rest) => {
-    const bs5ToBs3SizeMap = {
-      xs: 'xs',
-      sm: 'xs',
-      md: 'sm',
-      lg: 'md',
-      xl: 'lg',
-      xxl: undefined,
-    } as const
-
-    const isBs5ToBs3SizeMapKey = (
-      key: string
-    ): key is keyof typeof bs5ToBs3SizeMap => {
-      return key in bs5ToBs3SizeMap
-    }
-
-    const sizes = Object.entries(obj).reduce(
-      (prev, [key, value]) => {
-        if (isBs5ToBs3SizeMapKey(key)) {
-          const bs3Size = bs5ToBs3SizeMap[key]
-
-          if (bs3Size) {
-            if (typeof value === 'object') {
-              prev[bs3Size] = value.span
-              prev[`${bs3Size}Offset`] = value.offset
-            } else {
-              prev[bs3Size] = value
-            }
-          }
-        }
-
-        return prev
-      },
-      {} as Record<string, (typeof rest)['xs']>
-    )
-
-    // Add a default sizing for `col-xs-12` if no sizing is available
-    if (
-      !Object.keys(sizes).some(key => ['xs', 'sm', 'md', 'lg'].includes(key))
-    ) {
-      sizes.xs = 12
-    }
-
-    return sizes
-  }
-
-  const bs3ColProps: React.ComponentProps<typeof BS3Col> = {
-    children: rest.children,
-    className: rest.className,
-    ...getBs3Sizes(rest),
-    ...bs3Props,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Col {...bs3ColProps} />}
-      bs5={<Col {...rest} />}
-    />
-  )
+function OLCol(props: React.ComponentProps<typeof Col>) {
+  return <Col {...props} />
 }
 }
 
 
 export default OLCol
 export default OLCol

+ 4 - 34
services/web/frontend/js/features/ui/components/ol/ol-dropdown-menu-item.tsx

@@ -1,43 +1,13 @@
-import { MenuItem, MenuItemProps } from 'react-bootstrap'
 import { DropdownItem } from '@/features/ui/components/bootstrap-5/dropdown-menu'
 import { DropdownItem } from '@/features/ui/components/bootstrap-5/dropdown-menu'
 import { DropdownItemProps } from '@/features/ui/components/types/dropdown-menu-props'
 import { DropdownItemProps } from '@/features/ui/components/types/dropdown-menu-props'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import DropdownListItem from '@/features/ui/components/bootstrap-5/dropdown-list-item'
 import DropdownListItem from '@/features/ui/components/bootstrap-5/dropdown-list-item'
 
 
-type OLDropdownMenuItemProps = DropdownItemProps & {
-  bs3Props?: MenuItemProps
-}
-
 // This represents a menu item. It wraps the item within an <li> element.
 // This represents a menu item. It wraps the item within an <li> element.
-function OLDropdownMenuItem(props: OLDropdownMenuItemProps) {
-  const { bs3Props, ...rest } = props
-
-  const bs3MenuItemProps: MenuItemProps = {
-    children: rest.leadingIcon ? (
-      <>
-        {rest.leadingIcon}
-        &nbsp;
-        {rest.children}
-      </>
-    ) : (
-      rest.children
-    ),
-    onClick: rest.onClick,
-    href: rest.href,
-    download: rest.download,
-    eventKey: rest.eventKey,
-    ...bs3Props,
-  }
-
+function OLDropdownMenuItem(props: DropdownItemProps) {
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={<MenuItem {...bs3MenuItemProps} />}
-      bs5={
-        <DropdownListItem>
-          <DropdownItem {...rest} />
-        </DropdownListItem>
-      }
-    />
+    <DropdownListItem>
+      <DropdownItem {...props} />
+    </DropdownListItem>
   )
   )
 }
 }
 
 

+ 20 - 115
services/web/frontend/js/features/ui/components/ol/ol-form-checkbox.tsx

@@ -1,7 +1,4 @@
 import { Form, FormCheckProps } from 'react-bootstrap-5'
 import { Form, FormCheckProps } from 'react-bootstrap-5'
-import { Checkbox as BS3Checkbox } from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 import { MergeAndOverride } from '../../../../../../types/utils'
 import { MergeAndOverride } from '../../../../../../types/utils'
 import FormText from '../bootstrap-5/form/form-text'
 import FormText from '../bootstrap-5/form/form-text'
 
 
@@ -9,128 +6,36 @@ type OLFormCheckboxProps = MergeAndOverride<
   FormCheckProps,
   FormCheckProps,
   {
   {
     inputRef?: React.MutableRefObject<HTMLInputElement | null>
     inputRef?: React.MutableRefObject<HTMLInputElement | null>
-    bs3Props?: Record<PropertyKey, unknown>
   } & (
   } & (
     | { description: string; id: string }
     | { description: string; id: string }
     | { description?: undefined; id?: string }
     | { description?: undefined; id?: string }
   )
   )
 >
 >
 
 
-type RadioButtonProps = {
-  checked?: boolean
-  className?: string
-  description?: string
-  disabled?: boolean
-  id: string
-  name?: string
-  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
-  required?: boolean
-  label: React.ReactElement | string
-  value: string
-}
-
 function OLFormCheckbox(props: OLFormCheckboxProps) {
 function OLFormCheckbox(props: OLFormCheckboxProps) {
-  const { bs3Props, inputRef, ...rest } = props
-
-  const bs3FormCheckboxProps: React.ComponentProps<typeof BS3Checkbox> = {
-    children: rest.label,
-    checked: rest.checked,
-    value: rest.value,
-    id: rest.id,
-    name: rest.name,
-    required: rest.required,
-    readOnly: rest.readOnly,
-    disabled: rest.disabled,
-    inline: rest.inline,
-    title: rest.title,
-    autoComplete: rest.autoComplete,
-    defaultChecked: rest.defaultChecked,
-    className: rest.className,
-    onChange: rest.onChange as (e: React.ChangeEvent<unknown>) => void,
-    inputRef: node => {
-      if (inputRef) {
-        inputRef.current = node
-      }
-    },
-    ...getAriaAndDataProps(rest),
-    ...bs3Props,
-  }
+  const { inputRef, ...rest } = props
 
 
-  return (
-    <BootstrapVersionSwitcher
-      bs3={
-        rest.type === 'radio' ? (
-          <BS3Radio {...(rest as RadioButtonProps)} />
-        ) : (
-          <BS3Checkbox {...bs3FormCheckboxProps} />
-        )
-      }
-      bs5={
-        rest.type === 'radio' ? (
-          <Form.Check
-            ref={inputRef}
-            aria-describedby={
-              rest.description ? `${rest.id}-description` : undefined
-            }
-            {...rest}
-            label={
-              <>
-                {rest.label}
-                {rest.description && (
-                  <FormText
-                    id={`${rest.id}-description`}
-                    className="form-check-label-description"
-                  >
-                    {rest.description}
-                  </FormText>
-                )}
-              </>
-            }
-          />
-        ) : (
-          <Form.Check ref={inputRef} {...rest} />
-        )
+  return rest.type === 'radio' ? (
+    <Form.Check
+      ref={inputRef}
+      aria-describedby={rest.description ? `${rest.id}-description` : undefined}
+      {...rest}
+      label={
+        <>
+          {rest.label}
+          {rest.description && (
+            <FormText
+              id={`${rest.id}-description`}
+              className="form-check-label-description"
+            >
+              {rest.description}
+            </FormText>
+          )}
+        </>
       }
       }
     />
     />
-  )
-}
-
-function BS3Radio(props: RadioButtonProps) {
-  const {
-    label,
-    checked,
-    className,
-    description,
-    disabled,
-    id,
-    name,
-    onChange,
-    required,
-    value,
-  } = props
-  return (
-    <div className={className}>
-      <input
-        checked={checked}
-        className="me-1"
-        disabled={disabled}
-        id={id}
-        name={name}
-        onChange={onChange}
-        type="radio"
-        required={required}
-        value={value}
-        aria-describedby={description ? `${id}-description` : undefined}
-      />
-      <label htmlFor={id} data-disabled={disabled ? 'true' : undefined}>
-        {label}
-      </label>{' '}
-      {description && (
-        <small id={`${id}-description`} aria-hidden="true">
-          {description}
-        </small>
-      )}
-    </div>
+  ) : (
+    <Form.Check ref={inputRef} {...rest} />
   )
   )
 }
 }
 
 

+ 6 - 75
services/web/frontend/js/features/ui/components/ol/ol-form-control.tsx

@@ -1,96 +1,27 @@
-import { forwardRef, ComponentProps, useCallback } from 'react'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
+import { forwardRef } from 'react'
 import FormControl, {
 import FormControl, {
   type OLBS5FormControlProps,
   type OLBS5FormControlProps,
 } from '@/features/ui/components/bootstrap-5/form/form-control'
 } from '@/features/ui/components/bootstrap-5/form/form-control'
-import BS3FormControl from '@/features/ui/components/bootstrap-3/form/form-control'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import OLSpinner from '@/features/ui/components/ol/ol-spinner'
 import OLSpinner from '@/features/ui/components/ol/ol-spinner'
-import Icon from '@/shared/components/icon'
 import type { BsPrefixRefForwardingComponent } from 'react-bootstrap-5/helpers'
 import type { BsPrefixRefForwardingComponent } from 'react-bootstrap-5/helpers'
 
 
 type OLFormControlProps = OLBS5FormControlProps & {
 type OLFormControlProps = OLBS5FormControlProps & {
-  bs3Props?: Record<string, unknown>
   'data-ol-dirty'?: unknown
   'data-ol-dirty'?: unknown
   'main-field'?: any // For the CM6's benefit in the editor search panel
   'main-field'?: any // For the CM6's benefit in the editor search panel
   loading?: boolean
   loading?: boolean
 }
 }
 
 
-type BS3FormControlProps = ComponentProps<typeof BS3FormControl> & {
-  'main-field'?: any
-}
-
 const OLFormControl: BsPrefixRefForwardingComponent<
 const OLFormControl: BsPrefixRefForwardingComponent<
   'input',
   'input',
   OLFormControlProps
   OLFormControlProps
 > = forwardRef<HTMLInputElement, OLFormControlProps>((props, ref) => {
 > = forwardRef<HTMLInputElement, OLFormControlProps>((props, ref) => {
-  const { bs3Props, append, ...rest } = props
-
-  // Use a callback so that the ref passed to the BS3 FormControl is stable
-  const bs3InputRef = useCallback(
-    (inputElement: HTMLInputElement) => {
-      if (typeof ref === 'function') {
-        ref(inputElement)
-      } else if (ref) {
-        ref.current = inputElement
-      }
-    },
-    [ref]
-  )
-
-  let bs3FormControlProps: BS3FormControlProps = {
-    inputRef: bs3InputRef,
-    componentClass: rest.as,
-    bsSize: rest.size,
-    id: rest.id,
-    name: rest.name,
-    className: rest.className,
-    style: rest.style,
-    type: rest.type,
-    value: rest.value,
-    defaultValue: rest.defaultValue,
-    required: rest.required,
-    disabled: rest.disabled,
-    placeholder: rest.placeholder,
-    readOnly: rest.readOnly,
-    autoComplete: rest.autoComplete,
-    autoFocus: rest.autoFocus,
-    minLength: rest.minLength,
-    maxLength: rest.maxLength,
-    onChange: rest.onChange as BS3FormControlProps['onChange'],
-    onKeyDown: rest.onKeyDown as BS3FormControlProps['onKeyDown'],
-    onFocus: rest.onFocus as BS3FormControlProps['onFocus'],
-    onBlur: rest.onBlur as BS3FormControlProps['onBlur'],
-    onInvalid: rest.onInvalid as BS3FormControlProps['onInvalid'],
-    onPaste: rest.onPaste as BS3FormControlProps['onPaste'],
-    prepend: rest.prepend,
-    size: rest.htmlSize,
-    'main-field': rest['main-field'],
-    children: rest.children,
-    ...bs3Props,
-  }
-
-  bs3FormControlProps = {
-    ...bs3FormControlProps,
-    ...getAriaAndDataProps(rest),
-    'data-ol-dirty': rest['data-ol-dirty'],
-  } as typeof bs3FormControlProps & Record<string, unknown>
+  const { append, ...rest } = props
 
 
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <BS3FormControl
-          {...bs3FormControlProps}
-          append={rest.loading ? <Icon type="spinner" spin /> : append}
-        />
-      }
-      bs5={
-        <FormControl
-          ref={ref}
-          {...rest}
-          append={rest.loading ? <OLSpinner size="sm" /> : append}
-        />
-      }
+    <FormControl
+      ref={ref}
+      {...rest}
+      append={rest.loading ? <OLSpinner size="sm" /> : append}
     />
     />
   )
   )
 })
 })

+ 2 - 26
services/web/frontend/js/features/ui/components/ol/ol-form-feedback.tsx

@@ -1,38 +1,14 @@
 import { Form } from 'react-bootstrap-5'
 import { Form } from 'react-bootstrap-5'
-import {
-  HelpBlock as BS3HelpBlock,
-  HelpBlockProps as BS3HelpBlockProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { ComponentProps } from 'react'
 import { ComponentProps } from 'react'
-import classnames from 'classnames'
 import FormFeedback from '@/features/ui/components/bootstrap-5/form/form-feedback'
 import FormFeedback from '@/features/ui/components/bootstrap-5/form/form-feedback'
 
 
 type OLFormFeedbackProps = Pick<
 type OLFormFeedbackProps = Pick<
   ComponentProps<typeof Form.Control.Feedback>,
   ComponentProps<typeof Form.Control.Feedback>,
   'type' | 'className' | 'children'
   'type' | 'className' | 'children'
-> & {
-  bs3Props?: Record<string, unknown>
-}
+>
 
 
 function OLFormFeedback(props: OLFormFeedbackProps) {
 function OLFormFeedback(props: OLFormFeedbackProps) {
-  const { bs3Props, children, ...bs5Props } = props
-
-  const bs3HelpBlockProps: BS3HelpBlockProps = {
-    className: classnames(
-      bs5Props.className,
-      bs5Props.type === 'invalid' ? 'invalid-only' : null
-    ),
-    children,
-    ...bs3Props,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3HelpBlock {...bs3HelpBlockProps} />}
-      bs5={<FormFeedback {...bs5Props}>{children}</FormFeedback>}
-    />
-  )
+  return <FormFeedback {...props} />
 }
 }
 
 
 export default OLFormFeedback
 export default OLFormFeedback

+ 2 - 36
services/web/frontend/js/features/ui/components/ol/ol-form-group.tsx

@@ -1,42 +1,8 @@
 import { FormGroupProps } from 'react-bootstrap-5'
 import { FormGroupProps } from 'react-bootstrap-5'
-import {
-  FormGroup as BS3FormGroup,
-  FormGroupProps as BS3FormGroupProps,
-  FormControl,
-} from 'react-bootstrap'
 import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
 import FormGroup from '@/features/ui/components/bootstrap-5/form/form-group'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import classNames from 'classnames'
 
 
-type OLFormGroupProps = FormGroupProps & {
-  bs3Props?: {
-    withFeedback?: boolean
-    hiddenLabel?: boolean
-    validationState?: BS3FormGroupProps['validationState']
-  }
-}
-
-function OLFormGroup(props: OLFormGroupProps) {
-  const { bs3Props, className, ...rest } = props
-  const { withFeedback, hiddenLabel, ...bs3PropsRest } = bs3Props || {}
-
-  const bs3FormGroupProps: BS3FormGroupProps = {
-    controlId: rest.controlId,
-    className: classNames(className, { 'hidden-label': hiddenLabel }),
-    ...bs3PropsRest,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <BS3FormGroup {...bs3FormGroupProps}>
-          {rest.children}
-          {withFeedback ? <FormControl.Feedback /> : null}
-        </BS3FormGroup>
-      }
-      bs5={<FormGroup className={className} {...rest} />}
-    />
-  )
+function OLFormGroup(props: FormGroupProps) {
+  return <FormGroup {...props} />
 }
 }
 
 
 export default OLFormGroup
 export default OLFormGroup

+ 2 - 23
services/web/frontend/js/features/ui/components/ol/ol-form-label.tsx

@@ -1,28 +1,7 @@
 import { Form } from 'react-bootstrap-5'
 import { Form } from 'react-bootstrap-5'
-import { ControlLabel as BS3FormLabel } from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 
-type OLFormLabelProps = React.ComponentProps<(typeof Form)['Label']> & {
-  bs3Props?: Record<string, unknown>
-}
-
-function OLFormLabel(props: OLFormLabelProps) {
-  const { bs3Props, ...rest } = props
-
-  const bs3FormLabelProps: React.ComponentProps<typeof BS3FormLabel> = {
-    children: rest.children,
-    htmlFor: rest.htmlFor,
-    srOnly: rest.visuallyHidden,
-    className: rest.className,
-    ...bs3Props,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3FormLabel {...bs3FormLabelProps} />}
-      bs5={<Form.Label {...rest} />}
-    />
-  )
+function OLFormLabel(props: React.ComponentProps<(typeof Form)['Label']>) {
+  return <Form.Label {...props} />
 }
 }
 
 
 export default OLFormLabel
 export default OLFormLabel

+ 2 - 49
services/web/frontend/js/features/ui/components/ol/ol-form-select.tsx

@@ -1,56 +1,9 @@
 import { forwardRef } from 'react'
 import { forwardRef } from 'react'
 import { Form, FormSelectProps } from 'react-bootstrap-5'
 import { Form, FormSelectProps } from 'react-bootstrap-5'
-import {
-  FormControl as BS3FormControl,
-  FormControlProps as BS3FormControlProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type OLFormSelectProps = FormSelectProps & {
-  bs3Props?: Record<string, unknown>
-}
-
-const OLFormSelect = forwardRef<HTMLSelectElement, OLFormSelectProps>(
+const OLFormSelect = forwardRef<HTMLSelectElement, FormSelectProps>(
   (props, ref) => {
   (props, ref) => {
-    const { bs3Props, ...bs5Props } = props
-
-    const bs3FormSelectProps: BS3FormControlProps = {
-      children: bs5Props.children,
-      bsSize: bs5Props.size,
-      name: bs5Props.name,
-      value: bs5Props.value,
-      defaultValue: bs5Props.defaultValue,
-      disabled: bs5Props.disabled,
-      onChange: bs5Props.onChange as BS3FormControlProps['onChange'],
-      required: bs5Props.required,
-      placeholder: bs5Props.placeholder,
-      className: bs5Props.className,
-      inputRef: (inputElement: HTMLInputElement) => {
-        if (typeof ref === 'function') {
-          ref(inputElement as unknown as HTMLSelectElement)
-        } else if (ref) {
-          ref.current = inputElement as unknown as HTMLSelectElement
-        }
-      },
-      ...bs3Props,
-    }
-
-    // Get all `aria-*` and `data-*` attributes
-    const extraProps = getAriaAndDataProps(bs5Props)
-
-    return (
-      <BootstrapVersionSwitcher
-        bs3={
-          <BS3FormControl
-            componentClass="select"
-            {...bs3FormSelectProps}
-            {...extraProps}
-          />
-        }
-        bs5={<Form.Select ref={ref} {...bs5Props} />}
-      />
-    )
+    return <Form.Select ref={ref} {...props} />
   }
   }
 )
 )
 OLFormSelect.displayName = 'OLFormSelect'
 OLFormSelect.displayName = 'OLFormSelect'

+ 7 - 41
services/web/frontend/js/features/ui/components/ol/ol-form-switch.tsx

@@ -1,53 +1,19 @@
 import { FormCheck, FormCheckProps, FormLabel } from 'react-bootstrap-5'
 import { FormCheck, FormCheckProps, FormLabel } from 'react-bootstrap-5'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
 type OLFormSwitchProps = FormCheckProps & {
 type OLFormSwitchProps = FormCheckProps & {
   inputRef?: React.MutableRefObject<HTMLInputElement | null>
   inputRef?: React.MutableRefObject<HTMLInputElement | null>
-  bs3Props?: React.InputHTMLAttributes<HTMLInputElement>
 }
 }
 
 
 function OLFormSwitch(props: OLFormSwitchProps) {
 function OLFormSwitch(props: OLFormSwitchProps) {
-  const { bs3Props, inputRef, label, id, ...rest } = props
-
-  const bs3FormSwitchProps: React.InputHTMLAttributes<HTMLInputElement> = {
-    id,
-    checked: rest.checked,
-    required: rest.required,
-    readOnly: rest.readOnly,
-    disabled: rest.disabled,
-    autoComplete: rest.autoComplete,
-    defaultChecked: rest.defaultChecked,
-    onChange: rest.onChange as (e: React.ChangeEvent<unknown>) => void,
-    ...getAriaAndDataProps(rest),
-    ...bs3Props,
-  }
+  const { inputRef, label, id, ...rest } = props
 
 
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <div className="input-switch">
-          <input
-            id={id}
-            type="checkbox"
-            className="input-switch-hidden-input"
-            ref={inputRef}
-            {...bs3FormSwitchProps}
-          />
-          <label htmlFor={id} className="input-switch-btn">
-            <span className="sr-only">{label}</span>
-          </label>
-        </div>
-      }
-      bs5={
-        <>
-          <FormCheck type="switch" ref={inputRef} id={id} {...rest} />
-          <FormLabel htmlFor={id} visuallyHidden>
-            {label}
-          </FormLabel>
-        </>
-      }
-    />
+    <>
+      <FormCheck type="switch" ref={inputRef} id={id} {...rest} />
+      <FormLabel htmlFor={id} visuallyHidden>
+        {label}
+      </FormLabel>
+    </>
   )
   )
 }
 }
 
 

+ 2 - 29
services/web/frontend/js/features/ui/components/ol/ol-form-text.tsx

@@ -1,36 +1,9 @@
 import FormText, {
 import FormText, {
   FormTextProps,
   FormTextProps,
-  getFormTextClass,
 } from '@/features/ui/components/bootstrap-5/form/form-text'
 } from '@/features/ui/components/bootstrap-5/form/form-text'
-import PolymorphicComponent from '@/shared/components/polymorphic-component'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import classnames from 'classnames'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type OLFormTextProps = FormTextProps & {
-  bs3Props?: Record<string, unknown>
-}
-
-function OLFormText({ as = 'div', ...props }: OLFormTextProps) {
-  const { bs3Props, ...rest } = props
-
-  const bs3HelpBlockProps = {
-    children: rest.children,
-    className: classnames('small', rest.className, getFormTextClass(rest.type)),
-    ...bs3Props,
-  } as const satisfies React.ComponentProps<typeof PolymorphicComponent>
-
-  // Get all `aria-*` and `data-*` attributes
-  const extraProps = getAriaAndDataProps(rest)
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <PolymorphicComponent {...bs3HelpBlockProps} {...extraProps} as={as} />
-      }
-      bs5={<FormText {...rest} as={as} />}
-    />
-  )
+function OLFormText({ as = 'div', ...rest }: FormTextProps) {
+  return <FormText {...rest} as={as} />
 }
 }
 
 
 export default OLFormText
 export default OLFormText

+ 2 - 39
services/web/frontend/js/features/ui/components/ol/ol-form.tsx

@@ -1,45 +1,8 @@
 import { Form } from 'react-bootstrap-5'
 import { Form } from 'react-bootstrap-5'
-import { Form as BS3Form, FormProps as BS3FormProps } from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { ComponentProps } from 'react'
 import { ComponentProps } from 'react'
-import classnames from 'classnames'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type OLFormProps = ComponentProps<typeof Form> & {
-  bs3Props?: ComponentProps<typeof BS3Form>
-}
-
-function OLForm(props: OLFormProps) {
-  const { bs3Props, ...rest } = props
-
-  const bs3FormProps: BS3FormProps = {
-    componentClass: rest.as,
-    children: rest.children,
-    id: rest.id,
-    onSubmit: rest.onSubmit as BS3FormProps['onSubmit'],
-    onClick: rest.onClick as BS3FormProps['onClick'],
-    name: rest.name,
-    noValidate: rest.noValidate,
-    role: rest.role,
-    ...bs3Props,
-  }
-
-  const bs3ClassName = classnames(
-    rest.className,
-    rest.validated ? 'was-validated' : null
-  )
-
-  // Get all `aria-*` and `data-*` attributes
-  const extraProps = getAriaAndDataProps(rest)
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <BS3Form className={bs3ClassName} {...bs3FormProps} {...extraProps} />
-      }
-      bs5={<Form {...rest} />}
-    />
-  )
+function OLForm(props: ComponentProps<typeof Form>) {
+  return <Form {...props} />
 }
 }
 
 
 export default OLForm
 export default OLForm

+ 2 - 43
services/web/frontend/js/features/ui/components/ol/ol-icon-button.tsx

@@ -1,54 +1,13 @@
 import { forwardRef } from 'react'
 import { forwardRef } from 'react'
-import { bs3ButtonProps, BS3ButtonSize } from './ol-button'
-import { Button as BS3Button } from 'react-bootstrap'
 import type { IconButtonProps } from '@/features/ui/components/types/icon-button-props'
 import type { IconButtonProps } from '@/features/ui/components/types/icon-button-props'
-import BootstrapVersionSwitcher from '../bootstrap-5/bootstrap-version-switcher'
-import Icon, { IconProps } from '@/shared/components/icon'
 import IconButton from '../bootstrap-5/icon-button'
 import IconButton from '../bootstrap-5/icon-button'
-import { callFnsInSequence } from '@/utils/functions'
 
 
-export type OLIconButtonProps = IconButtonProps & {
-  bs3Props?: {
-    loading?: React.ReactNode
-    fw?: IconProps['fw']
-    className?: string
-    bsSize?: BS3ButtonSize
-    onMouseOver?: React.MouseEventHandler<HTMLButtonElement>
-    onMouseOut?: React.MouseEventHandler<HTMLButtonElement>
-    onFocus?: React.FocusEventHandler<HTMLButtonElement>
-    onBlur?: React.FocusEventHandler<HTMLButtonElement>
-  }
-}
+export type OLIconButtonProps = IconButtonProps
 
 
 const OLIconButton = forwardRef<HTMLButtonElement, OLIconButtonProps>(
 const OLIconButton = forwardRef<HTMLButtonElement, OLIconButtonProps>(
   (props, ref) => {
   (props, ref) => {
-    const { bs3Props, ...rest } = props
-
-    const { fw, loading, ...bs3Rest } = bs3Props || {}
-
-    // BS3 OverlayTrigger automatically provides 'onMouseOver', 'onMouseOut', 'onFocus', 'onBlur' event handlers
-    const bs3FinalProps = {
-      'aria-label': rest.accessibilityLabel,
-      ...bs3ButtonProps(rest),
-      ...bs3Rest,
-      onMouseOver: callFnsInSequence(bs3Props?.onMouseOver, rest.onMouseOver),
-      onMouseOut: callFnsInSequence(bs3Props?.onMouseOut, rest.onMouseOut),
-      onFocus: callFnsInSequence(bs3Props?.onFocus, rest.onFocus),
-      onBlur: callFnsInSequence(bs3Props?.onBlur, rest.onBlur),
-    }
-
-    // BS3 tooltip relies on the 'onMouseOver', 'onMouseOut', 'onFocus', 'onBlur' props
     // BS5 tooltip relies on the ref
     // BS5 tooltip relies on the ref
-    return (
-      <BootstrapVersionSwitcher
-        bs3={
-          <BS3Button {...bs3FinalProps}>
-            {loading || <Icon type={rest.icon} fw={fw} />}
-          </BS3Button>
-        }
-        bs5={<IconButton {...rest} ref={ref} />}
-      />
-    )
+    return <IconButton {...props} ref={ref} />
   }
   }
 )
 )
 OLIconButton.displayName = 'OLIconButton'
 OLIconButton.displayName = 'OLIconButton'

+ 6 - 33
services/web/frontend/js/features/ui/components/ol/ol-list-group-item.tsx

@@ -1,40 +1,13 @@
 import { ListGroupItem, ListGroupItemProps } from 'react-bootstrap-5'
 import { ListGroupItem, ListGroupItemProps } from 'react-bootstrap-5'
-import {
-  ListGroupItem as BS3ListGroupItem,
-  ListGroupItemProps as BS3ListGroupItemProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type OLListGroupItemProps = ListGroupItemProps & {
-  bs3Props?: BS3ListGroupItemProps
-}
-
-function OLListGroupItem(props: OLListGroupItemProps) {
-  const { bs3Props, ...rest } = props
-
-  const bs3ListGroupItemProps: BS3ListGroupItemProps = {
-    children: rest.children,
-    active: rest.active,
-    disabled: rest.disabled,
-    href: rest.href,
-    onClick: rest.onClick as BS3ListGroupItemProps['onClick'],
-    ...bs3Props,
-  }
-
-  const extraProps = getAriaAndDataProps(rest)
-  const as = rest.as ?? 'button'
+function OLListGroupItem(props: ListGroupItemProps) {
+  const as = props.as ?? 'button'
 
 
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3ListGroupItem {...bs3ListGroupItemProps} {...extraProps} />}
-      bs5={
-        <ListGroupItem
-          {...rest}
-          as={as}
-          type={as === 'button' ? 'button' : undefined}
-        />
-      }
+    <ListGroupItem
+      {...props}
+      as={as}
+      type={as === 'button' ? 'button' : undefined}
     />
     />
   )
   )
 }
 }

+ 3 - 28
services/web/frontend/js/features/ui/components/ol/ol-list-group.tsx

@@ -1,34 +1,9 @@
 import { ListGroup, ListGroupProps } from 'react-bootstrap-5'
 import { ListGroup, ListGroupProps } from 'react-bootstrap-5'
-import {
-  ListGroup as BS3ListGroup,
-  ListGroupProps as BS3ListGroupProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type OLListGroupProps = ListGroupProps & {
-  bs3Props?: BS3ListGroupProps
-}
-
-function OLListGroup(props: OLListGroupProps) {
-  const { bs3Props, ...rest } = props
-
-  const bs3ListGroupProps: BS3ListGroupProps = {
-    children: rest.children,
-    role: rest.role,
-    componentClass: rest.as,
-    ...bs3Props,
-  }
-
-  const extraProps = getAriaAndDataProps(rest)
-  const as = rest.as ?? 'div'
+function OLListGroup(props: ListGroupProps) {
+  const as = props.as ?? 'div'
 
 
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3ListGroup {...bs3ListGroupProps} {...extraProps} />}
-      bs5={<ListGroup {...rest} as={as} />}
-    />
-  )
+  return <ListGroup {...props} as={as} />
 }
 }
 
 
 export default OLListGroup
 export default OLListGroup

+ 13 - 109
services/web/frontend/js/features/ui/components/ol/ol-modal.tsx

@@ -1,133 +1,37 @@
 import {
 import {
-  Modal as BS5Modal,
+  Modal,
   ModalProps,
   ModalProps,
   ModalHeaderProps,
   ModalHeaderProps,
   ModalTitleProps,
   ModalTitleProps,
-  ModalBody,
   ModalFooterProps,
   ModalFooterProps,
 } from 'react-bootstrap-5'
 } from 'react-bootstrap-5'
-import {
-  Modal as BS3Modal,
-  ModalProps as BS3ModalProps,
-  ModalHeaderProps as BS3ModalHeaderProps,
-  ModalTitleProps as BS3ModalTitleProps,
-  ModalBodyProps as BS3ModalBodyProps,
-  ModalFooterProps as BS3ModalFooterProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import AccessibleModal from '@/shared/components/accessible-modal'
+import { ModalBodyProps } from 'react-bootstrap-5/ModalBody'
 
 
 type OLModalProps = ModalProps & {
 type OLModalProps = ModalProps & {
-  bs3Props?: Record<string, unknown>
   size?: 'sm' | 'lg'
   size?: 'sm' | 'lg'
   onHide: () => void
   onHide: () => void
 }
 }
 
 
-type OLModalHeaderProps = ModalHeaderProps & {
-  bs3Props?: Record<string, unknown>
-}
-
-type OLModalTitleProps = ModalTitleProps & {
-  bs3Props?: Record<string, unknown>
-}
-
-type OLModalBodyProps = React.ComponentProps<typeof ModalBody> & {
-  bs3Props?: Record<string, unknown>
-}
-
-type OLModalFooterProps = ModalFooterProps & {
-  bs3Props?: Record<string, unknown>
-}
-
 export default function OLModal({ children, ...props }: OLModalProps) {
 export default function OLModal({ children, ...props }: OLModalProps) {
-  const { bs3Props, ...bs5Props } = props
-
-  const bs3ModalProps: BS3ModalProps = {
-    bsClass: bs5Props.bsPrefix,
-    bsSize: bs5Props.size,
-    show: bs5Props.show,
-    onHide: bs5Props.onHide,
-    onExited: bs5Props.onExited,
-    backdrop: bs5Props.backdrop,
-    animation: bs5Props.animation,
-    id: bs5Props.id,
-    className: bs5Props.className,
-    backdropClassName: bs5Props.backdropClassName,
-    ...bs3Props,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<AccessibleModal {...bs3ModalProps}>{children}</AccessibleModal>}
-      bs5={<BS5Modal {...bs5Props}>{children}</BS5Modal>}
-    />
-  )
+  return <Modal {...props}>{children}</Modal>
 }
 }
 
 
-export function OLModalHeader({ children, ...props }: OLModalHeaderProps) {
-  const { bs3Props, ...bs5Props } = props
-
-  const bs3ModalProps: BS3ModalHeaderProps = {
-    bsClass: bs5Props.bsPrefix,
-    onHide: bs5Props.onHide,
-    closeButton: bs5Props.closeButton,
-    closeLabel: bs5Props.closeLabel,
-  }
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Modal.Header {...bs3ModalProps}>{children}</BS3Modal.Header>}
-      bs5={<BS5Modal.Header {...bs5Props}>{children}</BS5Modal.Header>}
-    />
-  )
+export function OLModalHeader({ children, ...props }: ModalHeaderProps) {
+  return <Modal.Header {...props}>{children}</Modal.Header>
 }
 }
 
 
-export function OLModalTitle({ children, ...props }: OLModalTitleProps) {
-  const { bs3Props, ...bs5Props } = props
-
-  const bs3ModalProps: BS3ModalTitleProps = {
-    componentClass: bs5Props.as,
-  }
-
+export function OLModalTitle({ children, ...props }: ModalTitleProps) {
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Modal.Title {...bs3ModalProps}>{children}</BS3Modal.Title>}
-      bs5={
-        <BS5Modal.Title as="h2" {...bs5Props}>
-          {children}
-        </BS5Modal.Title>
-      }
-    />
+    <Modal.Title as="h2" {...props}>
+      {children}
+    </Modal.Title>
   )
   )
 }
 }
 
 
-export function OLModalBody({ children, ...props }: OLModalBodyProps) {
-  const { bs3Props, ...bs5Props } = props
-
-  const bs3ModalProps: BS3ModalBodyProps = {
-    componentClass: bs5Props.as,
-    className: bs5Props.className,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Modal.Body {...bs3ModalProps}>{children}</BS3Modal.Body>}
-      bs5={<BS5Modal.Body {...bs5Props}>{children}</BS5Modal.Body>}
-    />
-  )
+export function OLModalBody({ children, ...props }: ModalBodyProps) {
+  return <Modal.Body {...props}>{children}</Modal.Body>
 }
 }
 
 
-export function OLModalFooter({ children, ...props }: OLModalFooterProps) {
-  const { bs3Props, ...bs5Props } = props
-
-  const bs3ModalProps: BS3ModalFooterProps = {
-    componentClass: bs5Props.as,
-    className: bs5Props.className,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Modal.Footer {...bs3ModalProps}>{children}</BS3Modal.Footer>}
-      bs5={<BS5Modal.Footer {...bs5Props}>{children}</BS5Modal.Footer>}
-    />
-  )
+export function OLModalFooter({ children, ...props }: ModalFooterProps) {
+  return <Modal.Footer {...props}>{children}</Modal.Footer>
 }
 }

+ 4 - 36
services/web/frontend/js/features/ui/components/ol/ol-notification.tsx

@@ -1,42 +1,10 @@
 import Notification from '@/shared/components/notification'
 import Notification from '@/shared/components/notification'
-import { Alert, AlertProps } from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import classnames from 'classnames'
-
-type OLNotificationProps = React.ComponentProps<typeof Notification> & {
-  bs3Props?: {
-    icon?: React.ReactElement
-    className?: string
-  }
-}
-
-function OLNotification(props: OLNotificationProps) {
-  const { bs3Props, ...notificationProps } = props
-
-  const alertProps = {
-    // Map `error` to `danger`
-    bsStyle:
-      notificationProps.type === 'error' ? 'danger' : notificationProps.type,
-    className: classnames(notificationProps.className, bs3Props?.className),
-    onDismiss: notificationProps.onDismiss,
-  } as const satisfies AlertProps
 
 
+function OLNotification(props: React.ComponentProps<typeof Notification>) {
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <Alert {...alertProps}>
-          {bs3Props?.icon}
-          {bs3Props?.icon && ' '}
-          {notificationProps.content}
-          {notificationProps.action}
-        </Alert>
-      }
-      bs5={
-        <div className="notification-list">
-          <Notification {...notificationProps} />
-        </div>
-      }
-    />
+    <div className="notification-list">
+      <Notification {...props} />
+    </div>
   )
   )
 }
 }
 
 

+ 2 - 56
services/web/frontend/js/features/ui/components/ol/ol-overlay.tsx

@@ -1,61 +1,7 @@
 import { Overlay, OverlayProps } from 'react-bootstrap-5'
 import { Overlay, OverlayProps } from 'react-bootstrap-5'
-import {
-  Overlay as BS3Overlay,
-  OverlayProps as BS3OverlayProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 
-type OLOverlayProps = OverlayProps & {
-  bs3Props?: BS3OverlayProps
-}
-
-function OLOverlay(props: OLOverlayProps) {
-  const { bs3Props, ...bs5Props } = props
-
-  let bs3OverlayProps: BS3OverlayProps = {
-    children: bs5Props.children,
-    target: bs5Props.target as BS3OverlayProps['target'],
-    container: bs5Props.container,
-    containerPadding: bs5Props.containerPadding,
-    show: bs5Props.show,
-    rootClose: bs5Props.rootClose,
-    animation: bs5Props.transition,
-    onHide: bs5Props.onHide as BS3OverlayProps['onHide'],
-    onEnter: bs5Props.onEnter as BS3OverlayProps['onEnter'],
-    onEntering: bs5Props.onEntering as BS3OverlayProps['onEntering'],
-    onEntered: bs5Props.onEntered as BS3OverlayProps['onEntered'],
-    onExit: bs5Props.onExit as BS3OverlayProps['onExit'],
-    onExiting: bs5Props.onExiting as BS3OverlayProps['onExiting'],
-    onExited: bs5Props.onExited as BS3OverlayProps['onExited'],
-  }
-
-  if (bs5Props.placement) {
-    const bs3PlacementOptions = [
-      'top',
-      'right',
-      'bottom',
-      'left',
-    ] satisfies Array<
-      Extract<OverlayProps['placement'], BS3OverlayProps['placement']>
-    >
-
-    for (const placement of bs3PlacementOptions) {
-      // BS5 has more placement options than BS3, such as "left-start", so these are mapped to "left" etc.
-      if (bs5Props.placement.startsWith(placement)) {
-        bs3OverlayProps.placement = placement
-        break
-      }
-    }
-  }
-
-  bs3OverlayProps = { ...bs3OverlayProps, ...bs3Props }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Overlay {...bs3OverlayProps} />}
-      bs5={<Overlay {...bs5Props} />}
-    />
-  )
+function OLOverlay(props: OverlayProps) {
+  return <Overlay {...props} />
 }
 }
 
 
 export default OLOverlay
 export default OLOverlay

+ 4 - 10
services/web/frontend/js/features/ui/components/ol/ol-page-content-card.tsx

@@ -1,24 +1,18 @@
 import { Card, CardBody } from 'react-bootstrap-5'
 import { Card, CardBody } from 'react-bootstrap-5'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { FC } from 'react'
 import { FC } from 'react'
 import classNames from 'classnames'
 import classNames from 'classnames'
 
 
 // This wraps the Bootstrap 5 Card component but is restricted to the very
 // This wraps the Bootstrap 5 Card component but is restricted to the very
 // basic way we're using it, which is as a container for page content. The
 // basic way we're using it, which is as a container for page content. The
-// Bootstrap 3 equivalent in our codebase is a div with class "card"
+// Bootstrap 3 equivalent previously in our codebase is a div with class "card"
 const OLPageContentCard: FC<{ className?: string }> = ({
 const OLPageContentCard: FC<{ className?: string }> = ({
   children,
   children,
   className,
   className,
 }) => {
 }) => {
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={<div className={classNames('card', className)}>{children}</div>}
-      bs5={
-        <Card className={classNames('page-content-card', className)}>
-          <CardBody>{children}</CardBody>
-        </Card>
-      }
-    />
+    <Card className={classNames('page-content-card', className)}>
+      <CardBody>{children}</CardBody>
+    </Card>
   )
   )
 }
 }
 
 

+ 5 - 70
services/web/frontend/js/features/ui/components/ol/ol-popover.tsx

@@ -1,83 +1,18 @@
 import { forwardRef } from 'react'
 import { forwardRef } from 'react'
 import { Popover, PopoverProps } from 'react-bootstrap-5'
 import { Popover, PopoverProps } from 'react-bootstrap-5'
-import {
-  Popover as BS3Popover,
-  PopoverProps as BS3PopoverProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 
 type OLPopoverProps = Omit<PopoverProps, 'title'> & {
 type OLPopoverProps = Omit<PopoverProps, 'title'> & {
   title?: React.ReactNode
   title?: React.ReactNode
-  bs3Props?: BS3PopoverProps
 }
 }
 
 
 const OLPopover = forwardRef<HTMLDivElement, OLPopoverProps>((props, ref) => {
 const OLPopover = forwardRef<HTMLDivElement, OLPopoverProps>((props, ref) => {
-  // BS3 passes in some props automatically so the `props`
-  // type should be adjusted to reflect the actual received object
-  const propsCombinedWithAutoInjectedBs3Props = props as OLPopoverProps &
-    Pick<
-      BS3PopoverProps,
-      'arrowOffsetLeft' | 'arrowOffsetTop' | 'positionLeft' | 'positionTop'
-    >
-
-  const {
-    bs3Props,
-    title,
-    children,
-    arrowOffsetLeft,
-    arrowOffsetTop,
-    positionLeft,
-    positionTop,
-    ...bs5Props
-  } = propsCombinedWithAutoInjectedBs3Props
-
-  let bs3PopoverProps: BS3PopoverProps = {
-    children,
-    arrowOffsetLeft,
-    arrowOffsetTop,
-    positionLeft,
-    positionTop,
-    title,
-    id: bs5Props.id,
-    className: bs5Props.className,
-    style: bs5Props.style,
-  }
-
-  if (bs5Props.placement) {
-    const bs3PlacementOptions = [
-      'top',
-      'right',
-      'bottom',
-      'left',
-    ] satisfies Array<
-      Extract<PopoverProps['placement'], BS3PopoverProps['placement']>
-    >
-
-    for (const placement of bs3PlacementOptions) {
-      if (placement === bs5Props.placement) {
-        bs3PopoverProps.placement = bs5Props.placement
-        break
-      }
-    }
-  }
-
-  bs3PopoverProps = { ...bs3PopoverProps, ...bs3Props }
+  const { title, children, ...bs5Props } = props
 
 
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <BS3Popover
-          {...bs3PopoverProps}
-          ref={ref as React.LegacyRef<BS3Popover>}
-        />
-      }
-      bs5={
-        <Popover {...bs5Props} ref={ref}>
-          {title && <Popover.Header>{title}</Popover.Header>}
-          <Popover.Body>{children}</Popover.Body>
-        </Popover>
-      }
-    />
+    <Popover {...bs5Props} ref={ref}>
+      {title && <Popover.Header>{title}</Popover.Header>}
+      <Popover.Body>{children}</Popover.Body>
+    </Popover>
   )
   )
 })
 })
 OLPopover.displayName = 'OLPopover'
 OLPopover.displayName = 'OLPopover'

+ 2 - 11
services/web/frontend/js/features/ui/components/ol/ol-row.tsx

@@ -1,16 +1,7 @@
 import { Row } from 'react-bootstrap-5'
 import { Row } from 'react-bootstrap-5'
-import { Row as BS3Row } from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 
-type OLRowProps = React.ComponentProps<typeof Row>
-
-function OLRow(props: OLRowProps) {
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Row className={props.className}>{props.children}</BS3Row>}
-      bs5={<Row {...props} />}
-    />
-  )
+function OLRow(props: React.ComponentProps<typeof Row>) {
+  return <Row {...props} />
 }
 }
 
 
 export default OLRow
 export default OLRow

+ 5 - 20
services/web/frontend/js/features/ui/components/ol/ol-spinner.tsx

@@ -1,29 +1,14 @@
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import Icon from '@/shared/components/icon'
 import { Spinner } from 'react-bootstrap-5'
 import { Spinner } from 'react-bootstrap-5'
-import classNames from 'classnames'
 
 
 export type OLSpinnerSize = 'sm' | 'lg'
 export type OLSpinnerSize = 'sm' | 'lg'
 
 
 function OLSpinner({ size = 'sm' }: { size: OLSpinnerSize }) {
 function OLSpinner({ size = 'sm' }: { size: OLSpinnerSize }) {
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <Icon
-          type="refresh"
-          fw
-          spin
-          className={classNames({ 'fa-2x': size === 'lg' })}
-        />
-      }
-      bs5={
-        <Spinner
-          size={size === 'sm' ? 'sm' : undefined}
-          animation="border"
-          aria-hidden="true"
-          role="status"
-        />
-      }
+    <Spinner
+      size={size === 'sm' ? 'sm' : undefined}
+      animation="border"
+      aria-hidden="true"
+      role="status"
     />
     />
   )
   )
 }
 }

+ 2 - 27
services/web/frontend/js/features/ui/components/ol/ol-table.tsx

@@ -1,32 +1,7 @@
 import Table from '@/features/ui/components/bootstrap-5/table'
 import Table from '@/features/ui/components/bootstrap-5/table'
-import { Table as BS3Table } from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type OLFormProps = React.ComponentProps<typeof Table> & {
-  bs3Props?: React.ComponentProps<typeof BS3Table>
-}
-
-function OLTable(props: OLFormProps) {
-  const { bs3Props, container, ...rest } = props
-
-  const bs3FormProps: React.ComponentProps<typeof BS3Table> = {
-    bsClass: rest.className,
-    id: rest.id,
-    condensed: rest.size === 'sm',
-    children: rest.children,
-    responsive:
-      typeof rest.responsive !== 'string' ? rest.responsive : undefined,
-    ...getAriaAndDataProps(rest),
-    ...bs3Props,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Table {...bs3FormProps} />}
-      bs5={<Table container={container} {...rest} />}
-    />
-  )
+function OLTable(props: React.ComponentProps<typeof Table>) {
+  return <Table {...props} />
 }
 }
 
 
 export default OLTable
 export default OLTable

+ 2 - 29
services/web/frontend/js/features/ui/components/ol/ol-tag.tsx

@@ -1,37 +1,10 @@
 import Tag from '@/features/ui/components/bootstrap-5/tag'
 import Tag from '@/features/ui/components/bootstrap-5/tag'
-import BS3Tag from '@/shared/components/tag'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { forwardRef } from 'react'
 import { forwardRef } from 'react'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type OLTagProps = React.ComponentProps<typeof Tag> & {
-  bs3Props?: React.ComponentProps<typeof BS3Tag>
-}
+type OLTagProps = React.ComponentProps<typeof Tag>
 
 
 const OLTag = forwardRef<HTMLElement, OLTagProps>((props: OLTagProps, ref) => {
 const OLTag = forwardRef<HTMLElement, OLTagProps>((props: OLTagProps, ref) => {
-  const { bs3Props, ...rest } = props
-
-  const bs3TagProps: React.ComponentProps<typeof BS3Tag> = {
-    children: rest.children,
-    prepend: rest.prepend,
-    closeBtnProps: rest.closeBtnProps,
-    className: rest.className,
-    onClick: rest.onClick,
-    onFocus: rest.onFocus,
-    onBlur: rest.onBlur,
-    onMouseOver: rest.onMouseOver,
-    onMouseOut: rest.onMouseOut,
-    contentProps: rest.contentProps,
-    ...getAriaAndDataProps(rest),
-    ...bs3Props,
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Tag {...bs3TagProps} />}
-      bs5={<Tag ref={ref} {...rest} />}
-    />
-  )
+  return <Tag ref={ref} {...props} />
 })
 })
 
 
 OLTag.displayName = 'OLTag'
 OLTag.displayName = 'OLTag'

+ 3 - 15
services/web/frontend/js/features/ui/components/ol/ol-toast-container.tsx

@@ -1,8 +1,5 @@
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-
 import { CSSProperties, FC } from 'react'
 import { CSSProperties, FC } from 'react'
 import { ToastContainer as BS5ToastContainer } from 'react-bootstrap-5'
 import { ToastContainer as BS5ToastContainer } from 'react-bootstrap-5'
-import { ToastContainer as BS3ToastContainer } from '../bootstrap-3/toast-container'
 
 
 type OLToastContainerProps = {
 type OLToastContainerProps = {
   style?: CSSProperties
   style?: CSSProperties
@@ -15,17 +12,8 @@ export const OLToastContainer: FC<OLToastContainerProps> = ({
   style,
   style,
 }) => {
 }) => {
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs5={
-        <BS5ToastContainer className={className} style={style}>
-          {children}
-        </BS5ToastContainer>
-      }
-      bs3={
-        <BS3ToastContainer className={className} style={style}>
-          {children}
-        </BS3ToastContainer>
-      }
-    />
+    <BS5ToastContainer className={className} style={style}>
+      {children}
+    </BS5ToastContainer>
   )
   )
 }
 }

+ 9 - 26
services/web/frontend/js/features/ui/components/ol/ol-toast.tsx

@@ -7,8 +7,6 @@ import {
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
 import MaterialIcon from '../../../../shared/components/material-icon'
 import MaterialIcon from '../../../../shared/components/material-icon'
 import { ReactNode, useCallback, useState } from 'react'
 import { ReactNode, useCallback, useState } from 'react'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { Toast as BS3Toast } from '../bootstrap-3/toast'
 
 
 export type OLToastProps = {
 export type OLToastProps = {
   type: NotificationType
   type: NotificationType
@@ -78,29 +76,14 @@ export const OLToast = ({
     </div>
     </div>
   )
   )
   return (
   return (
-    <BootstrapVersionSwitcher
-      bs5={
-        <BS5Toast
-          onClose={handleClose}
-          autohide={autoHide}
-          onExited={handleOnHidden}
-          delay={delay}
-          show={show}
-        >
-          {toastElement}
-        </BS5Toast>
-      }
-      bs3={
-        <BS3Toast
-          onClose={handleClose}
-          autohide={autoHide}
-          delay={delay}
-          onExited={handleOnHidden}
-          show={show}
-        >
-          {toastElement}
-        </BS3Toast>
-      }
-    />
+    <BS5Toast
+      onClose={handleClose}
+      autohide={autoHide}
+      onExited={handleOnHidden}
+      delay={delay}
+      show={show}
+    >
+      {toastElement}
+    </BS5Toast>
   )
   )
 }
 }

+ 2 - 37
services/web/frontend/js/features/ui/components/ol/ol-toggle-button-group.tsx

@@ -1,42 +1,7 @@
 import { ToggleButtonGroup, ToggleButtonGroupProps } from 'react-bootstrap-5'
 import { ToggleButtonGroup, ToggleButtonGroupProps } from 'react-bootstrap-5'
-import BS3ToggleButtonGroup from '@/features/ui/components/bootstrap-3/toggle-button-group'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
 
 
-type BS3ToggleButtonGroupProps = React.ComponentProps<
-  typeof BS3ToggleButtonGroup
->
-
-type OLToggleButtonGroupProps<T> = ToggleButtonGroupProps<T> & {
-  bs3Props?: BS3ToggleButtonGroupProps
-}
-
-function OLToggleButtonGroup<T>(props: OLToggleButtonGroupProps<T>) {
-  const { bs3Props, ...rest } = props
-
-  const bs3ToggleButtonGroupProps = {
-    name: rest.name,
-    type: rest.type,
-    value: rest.value,
-    onChange: rest.onChange,
-    children: rest.children,
-    className: rest.className,
-    defaultValue: rest.defaultValue,
-    defaultChecked: rest.defaultChecked,
-    ...bs3Props,
-  } as BS3ToggleButtonGroupProps
-
-  // Get all `aria-*` and `data-*` attributes
-  const extraProps = getAriaAndDataProps(rest)
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <BS3ToggleButtonGroup {...extraProps} {...bs3ToggleButtonGroupProps} />
-      }
-      bs5={<ToggleButtonGroup {...rest} />}
-    />
-  )
+function OLToggleButtonGroup<T>(props: ToggleButtonGroupProps<T>) {
+  return <ToggleButtonGroup {...props} />
 }
 }
 
 
 export default OLToggleButtonGroup
 export default OLToggleButtonGroup

+ 2 - 43
services/web/frontend/js/features/ui/components/ol/ol-toggle-button.tsx

@@ -1,48 +1,7 @@
 import { ToggleButton, ToggleButtonProps } from 'react-bootstrap-5'
 import { ToggleButton, ToggleButtonProps } from 'react-bootstrap-5'
-import {
-  ToggleButton as BS3ToggleButton,
-  ToggleButtonProps as BS3ToggleButtonProps,
-} from 'react-bootstrap'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
-import { getAriaAndDataProps } from '@/features/utils/bootstrap-5'
-import classnames from 'classnames'
 
 
-type OLToggleButtonProps = ToggleButtonProps & {
-  bs3Props?: BS3ToggleButtonProps
-}
-
-function OLToggleButton(props: OLToggleButtonProps) {
-  const { bs3Props, ...rest } = props
-
-  const bs3ToggleButtonProps: BS3ToggleButtonProps & { active?: boolean } = {
-    type: rest.type,
-    name: rest.name,
-    active: rest.active,
-    checked: rest.checked,
-    disabled: rest.disabled,
-    onChange: rest.onChange as BS3ToggleButtonProps['onChange'],
-    onClick: rest.onClick as BS3ToggleButtonProps['onClick'],
-    value: rest.value as BS3ToggleButtonProps['value'],
-    children: rest.children,
-    className: classnames(`btn-${props.variant || 'primary'}`, rest.className),
-    ...bs3Props,
-  }
-
-  // Get all `aria-*` and `data-*` attributes
-  const extraProps = getAriaAndDataProps(rest)
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <BS3ToggleButton
-          {...extraProps}
-          {...bs3ToggleButtonProps}
-          bsStyle={null}
-        />
-      }
-      bs5={<ToggleButton {...rest} />}
-    />
-  )
+function OLToggleButton(props: ToggleButtonProps) {
+  return <ToggleButton {...props} />
 }
 }
 
 
 export default OLToggleButton
 export default OLToggleButton

+ 2 - 43
services/web/frontend/js/features/ui/components/ol/ol-tooltip.tsx

@@ -1,48 +1,7 @@
 import Tooltip from '@/features/ui/components/bootstrap-5/tooltip'
 import Tooltip from '@/features/ui/components/bootstrap-5/tooltip'
-import BS3Tooltip from '@/shared/components/tooltip'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 
-type OLTooltipProps = React.ComponentProps<typeof Tooltip> & {
-  bs3Props?: Record<string, unknown>
-}
-
-function OLTooltip(props: OLTooltipProps) {
-  const { bs3Props, ...bs5Props } = props
-
-  type BS3TooltipProps = React.ComponentProps<typeof BS3Tooltip>
-
-  const bs3TooltipProps: BS3TooltipProps = {
-    children: bs5Props.children,
-    id: bs5Props.id,
-    description: bs5Props.description,
-    tooltipProps: bs5Props.tooltipProps as BS3TooltipProps,
-    overlayProps: {
-      placement: bs5Props.overlayProps?.placement,
-      rootClose: bs5Props.overlayProps?.rootClose,
-      trigger: bs5Props.overlayProps?.trigger,
-    },
-    ...bs3Props,
-  }
-
-  if ('hidden' in bs5Props) {
-    bs3TooltipProps.hidden = bs5Props.hidden
-  }
-
-  const delay = bs5Props.overlayProps?.delay
-  if (delay && typeof delay !== 'number') {
-    bs3TooltipProps.overlayProps = {
-      ...bs3TooltipProps.overlayProps,
-      delayShow: delay.show,
-      delayHide: delay.hide,
-    }
-  }
-
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<BS3Tooltip {...bs3TooltipProps} />}
-      bs5={<Tooltip {...bs5Props} />}
-    />
-  )
+function OLTooltip(props: React.ComponentProps<typeof Tooltip>) {
+  return <Tooltip {...props} />
 }
 }
 
 
 export default OLTooltip
 export default OLTooltip

+ 0 - 26
services/web/frontend/js/features/utils/bootstrap-5.ts

@@ -1,26 +0,0 @@
-import getMeta from '@/utils/meta'
-
-// The reason this is a function is to ensure that the meta tag is read before
-// any isBootstrap5 check is performed
-export const isBootstrap5 = () => getMeta('ol-bootstrapVersion') === 5
-
-/* eslint-disable no-redeclare */
-export function bsVersion<A>({ bs5 }: { bs5: A }): A | undefined
-export function bsVersion<B>({ bs3 }: { bs3: B }): B | undefined
-export function bsVersion<A, B>({ bs5, bs3 }: { bs5: A; bs3: B }): A | B
-export function bsVersion({ bs5, bs3 }: { bs5?: unknown; bs3?: unknown }) {
-  return isBootstrap5() ? bs5 : bs3
-}
-
-// get all `aria-*` and `data-*` attributes
-export const getAriaAndDataProps = (obj: Record<string, unknown>) => {
-  return Object.entries(obj).reduce(
-    (acc, [key, value]) => {
-      if (key.startsWith('aria-') || key.startsWith('data-')) {
-        acc[key] = value
-      }
-      return acc
-    },
-    {} as Record<string, unknown>
-  )
-}

+ 0 - 30
services/web/frontend/js/shared/components/accessible-modal.tsx

@@ -1,30 +0,0 @@
-import { useCallback } from 'react'
-import { Modal, ModalProps } from 'react-bootstrap'
-
-// A wrapper for the v0.33 React Bootstrap Modal component,
-// which ensures that the `aria-hidden` attribute is not set on the modal when it's visible,
-// and that role="dialog" is not duplicated.
-// https://github.com/react-bootstrap/react-bootstrap/issues/4790
-// There are other ARIA attributes on these modals which could be improved,
-// but this at least makes them accessible for tests.
-function AccessibleModal(props: ModalProps) {
-  const modalRef = useCallback(
-    element => {
-      const modalNode = element?._modal?.modalNode
-      if (modalNode) {
-        if (props.show) {
-          modalNode.removeAttribute('role')
-          modalNode.removeAttribute('aria-hidden')
-        } else {
-          // NOTE: possibly not ever used, as the modal is only rendered when shown
-          modalNode.setAttribute('aria-hidden', 'true')
-        }
-      }
-    },
-    [props.show]
-  )
-
-  return <Modal {...props} ref={modalRef} />
-}
-
-export default AccessibleModal

+ 0 - 29
services/web/frontend/js/shared/components/badge.tsx

@@ -1,29 +0,0 @@
-import { Label } from 'react-bootstrap'
-import classnames from 'classnames'
-import { MergeAndOverride } from '../../../../types/utils'
-
-type BadgeProps = MergeAndOverride<
-  React.ComponentProps<'span'>,
-  {
-    prepend?: React.ReactNode
-    children: React.ReactNode
-    className?: string
-    bsStyle?: React.ComponentProps<typeof Label>['bsStyle'] | null
-  }
->
-
-function Badge({ prepend, children, bsStyle, className, ...rest }: BadgeProps) {
-  const classNames =
-    bsStyle === null
-      ? className
-      : classnames('label', `label-${bsStyle}`, className)
-
-  return (
-    <span className={classNames} {...rest}>
-      {prepend && <span className="badge-tag-bs3-prepend">{prepend}</span>}
-      <span className="badge-tag-bs3-content">{children}</span>
-    </span>
-  )
-}
-
-export default Badge

+ 4 - 19
services/web/frontend/js/shared/components/beta-badge-icon.tsx

@@ -1,14 +1,11 @@
 import type { FC } from 'react'
 import type { FC } from 'react'
-import classnames from 'classnames'
 import MaterialIcon from '@/shared/components/material-icon'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import OLBadge from '@/features/ui/components/ol/ol-badge'
 import OLBadge from '@/features/ui/components/ol/ol-badge'
 
 
-function BS5BetaBadgeIcon({
-  badgeClass,
-}: {
-  badgeClass: ReturnType<typeof chooseBadgeClass>
-}) {
+const BetaBadgeIcon: FC<{
+  phase?: string
+}> = ({ phase = 'beta' }) => {
+  const badgeClass = chooseBadgeClass(phase)
   if (badgeClass === 'info-badge') {
   if (badgeClass === 'info-badge') {
     return <MaterialIcon type="info" className="align-middle info-badge" />
     return <MaterialIcon type="info" className="align-middle info-badge" />
   } else if (badgeClass === 'alpha-badge') {
   } else if (badgeClass === 'alpha-badge') {
@@ -26,18 +23,6 @@ function BS5BetaBadgeIcon({
   }
   }
 }
 }
 
 
-const BetaBadgeIcon: FC<{
-  phase?: string
-}> = ({ phase = 'beta' }) => {
-  const badgeClass = chooseBadgeClass(phase)
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<span className={classnames('badge', badgeClass)} />}
-      bs5={<BS5BetaBadgeIcon badgeClass={badgeClass} />}
-    />
-  )
-}
-
 function chooseBadgeClass(phase?: string) {
 function chooseBadgeClass(phase?: string) {
   switch (phase) {
   switch (phase) {
     case 'release':
     case 'release':

+ 1 - 4
services/web/frontend/js/shared/components/beta-badge.tsx

@@ -1,6 +1,5 @@
 import type { FC, MouseEventHandler, ReactNode } from 'react'
 import type { FC, MouseEventHandler, ReactNode } from 'react'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import BetaBadgeIcon from '@/shared/components/beta-badge-icon'
 import BetaBadgeIcon from '@/shared/components/beta-badge-icon'
 
 
 type TooltipProps = {
 type TooltipProps = {
@@ -40,9 +39,7 @@ const BetaBadge: FC<{
       href={href || defaultHref}
       href={href || defaultHref}
       {...linkProps}
       {...linkProps}
     >
     >
-      <span className={bsVersion({ bs5: 'visually-hidden', bs3: 'sr-only' })}>
-        {description || tooltip?.text}
-      </span>
+      <span className="visually-hidden">{description || tooltip?.text}</span>
       <BetaBadgeIcon phase={phase} />
       <BetaBadgeIcon phase={phase} />
     </a>
     </a>
   )
   )

+ 4 - 10
services/web/frontend/js/shared/components/close.tsx

@@ -1,6 +1,5 @@
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
 import MaterialIcon from '@/shared/components/material-icon'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 
 
 type CloseProps = {
 type CloseProps = {
   onDismiss: React.MouseEventHandler<HTMLButtonElement>
   onDismiss: React.MouseEventHandler<HTMLButtonElement>
@@ -16,15 +15,10 @@ function Close({ onDismiss, variant = 'light' }: CloseProps) {
       className={`close pull-right ${variant}`}
       className={`close pull-right ${variant}`}
       onClick={onDismiss}
       onClick={onDismiss}
     >
     >
-      <BootstrapVersionSwitcher
-        bs3={<span aria-hidden="true">&times;</span>}
-        bs5={
-          <MaterialIcon
-            type="close"
-            className="align-text-bottom"
-            accessibilityLabel={t('close')}
-          />
-        }
+      <MaterialIcon
+        type="close"
+        className="align-text-bottom"
+        accessibilityLabel={t('close')}
       />
       />
       <span className="sr-only">{t('close')}</span>
       <span className="sr-only">{t('close')}</span>
     </button>
     </button>

+ 0 - 58
services/web/frontend/js/shared/components/controlled-dropdown.tsx

@@ -1,58 +0,0 @@
-import React, {
-  Children,
-  cloneElement,
-  type FC,
-  isValidElement,
-  useCallback,
-} from 'react'
-import { Dropdown, DropdownProps } from 'react-bootstrap'
-import useDropdown from '../hooks/use-dropdown'
-
-type ControlledDropdownProps = DropdownProps & {
-  defaultOpen?: boolean
-  onMainButtonClick?: (dropdownOpen: boolean) => void
-}
-
-const ControlledDropdown: FC<ControlledDropdownProps> = ({
-  defaultOpen,
-  onMainButtonClick,
-  ...props
-}) => {
-  const { onClick, ...dropdownProps } = useDropdown(Boolean(defaultOpen))
-
-  const handleClick = useCallback(
-    (e: React.MouseEvent<Dropdown, MouseEvent>) => {
-      onClick(e)
-
-      if (onMainButtonClick) {
-        onMainButtonClick(dropdownProps.open)
-      }
-    },
-    [onClick, onMainButtonClick, dropdownProps.open]
-  )
-
-  return (
-    <Dropdown {...props} {...dropdownProps} onClick={handleClick}>
-      {Children.map(props.children, child => {
-        if (!isValidElement(child)) {
-          return child
-        }
-
-        // Dropdown.Menu
-        if ('open' in child.props) {
-          return cloneElement<any>(child, { open: dropdownProps.open })
-        }
-
-        // Overlay
-        if ('show' in child.props) {
-          return cloneElement<any>(child, { show: dropdownProps.open })
-        }
-
-        // anything else
-        return cloneElement(child)
-      })}
-    </Dropdown>
-  )
-}
-
-export default ControlledDropdown

+ 1 - 7
services/web/frontend/js/shared/components/copy-to-clipboard.tsx

@@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import OLIconButton from '@/features/ui/components/ol/ol-icon-button'
 import OLIconButton from '@/features/ui/components/ol/ol-icon-button'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 
 export const CopyToClipboard = memo<{
 export const CopyToClipboard = memo<{
   content: string
   content: string
@@ -39,7 +38,6 @@ export const CopyToClipboard = memo<{
           size="sm"
           size="sm"
           variant="secondary"
           variant="secondary"
           className="copy-button"
           className="copy-button"
-          bs3Props={{ bsSize: 'xsmall' }}
         >
         >
           {t('copy')}
           {t('copy')}
         </OLButton>
         </OLButton>
@@ -50,11 +48,7 @@ export const CopyToClipboard = memo<{
           size="sm"
           size="sm"
           accessibilityLabel={t('copy')}
           accessibilityLabel={t('copy')}
           className="copy-button"
           className="copy-button"
-          bs3Props={{ bsSize: 'xsmall' }}
-          icon={bsVersion({
-            bs5: copied ? 'check' : 'content_copy',
-            bs3: copied ? 'check' : 'clipboard',
-          })}
+          icon={copied ? 'check' : 'content_copy'}
         />
         />
       )}
       )}
     </OLTooltip>
     </OLTooltip>

+ 6 - 21
services/web/frontend/js/shared/components/generic-error-boundary-fallback.tsx

@@ -1,9 +1,7 @@
 import { FC } from 'react'
 import { FC } from 'react'
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
-import Icon from './icon'
 import { useLocation } from '../hooks/use-location'
 import { useLocation } from '../hooks/use-location'
 import { DefaultMessage } from './default-message'
 import { DefaultMessage } from './default-message'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import MaterialIcon from './material-icon'
 import MaterialIcon from './material-icon'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButton from '@/features/ui/components/ol/ol-button'
 
 
@@ -13,25 +11,12 @@ export const GenericErrorBoundaryFallback: FC = ({ children }) => {
 
 
   return (
   return (
     <div className="error-boundary-container">
     <div className="error-boundary-container">
-      <BootstrapVersionSwitcher
-        bs3={
-          <Icon
-            accessibilityLabel={`${t('generic_something_went_wrong')} ${t(
-              'please_refresh'
-            )}`}
-            type="exclamation-triangle fa-2x"
-            fw
-          />
-        }
-        bs5={
-          <MaterialIcon
-            accessibilityLabel={`${t('generic_something_went_wrong')} ${t(
-              'please_refresh'
-            )}`}
-            type="warning"
-            size="2x"
-          />
-        }
+      <MaterialIcon
+        accessibilityLabel={`${t('generic_something_went_wrong')} ${t(
+          'please_refresh'
+        )}`}
+        type="warning"
+        size="2x"
       />
       />
       {children || (
       {children || (
         <div className="error-message">
         <div className="error-message">

+ 1 - 4
services/web/frontend/js/shared/components/icon.tsx

@@ -1,5 +1,4 @@
 import classNames from 'classnames'
 import classNames from 'classnames'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 
 
 type IconOwnProps = {
 type IconOwnProps = {
   type: string
   type: string
@@ -36,9 +35,7 @@ function Icon({
     <>
     <>
       <i className={iconClassName} aria-hidden="true" {...rest} />
       <i className={iconClassName} aria-hidden="true" {...rest} />
       {accessibilityLabel && (
       {accessibilityLabel && (
-        <span className={bsVersion({ bs5: 'visually-hidden', bs3: 'sr-only' })}>
-          {accessibilityLabel}
-        </span>
+        <span className="visually-hidden">{accessibilityLabel}</span>
       )}
       )}
     </>
     </>
   )
   )

+ 2 - 6
services/web/frontend/js/shared/components/labs/labs-experiments-widget.tsx

@@ -5,7 +5,6 @@ import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
 import { postJSON } from '@/infrastructure/fetch-json'
 import { postJSON } from '@/infrastructure/fetch-json'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import getMeta from '@/utils/meta'
 import getMeta from '@/utils/meta'
-import { isBootstrap5 } from '@/features/utils/bootstrap-5'
 
 
 type IntegrationLinkingWidgetProps = {
 type IntegrationLinkingWidgetProps = {
   logo: ReactNode
   logo: ReactNode
@@ -117,17 +116,14 @@ function ActionButton({
       </OLButton>
       </OLButton>
     )
     )
   } else if (disabled) {
   } else if (disabled) {
-    const tooltipableButton = isBootstrap5() ? (
+    const tooltipableButton = (
       <div className="d-inline-block">
       <div className="d-inline-block">
         <OLButton variant="primary" disabled>
         <OLButton variant="primary" disabled>
           {t('turn_on')}
           {t('turn_on')}
         </OLButton>
         </OLButton>
       </div>
       </div>
-    ) : (
-      <OLButton variant="primary" disabled>
-        {t('turn_on')}
-      </OLButton>
     )
     )
+
     return (
     return (
       <OLTooltip
       <OLTooltip
         id="experiment-disabled"
         id="experiment-disabled"

+ 7 - 6
services/web/frontend/js/shared/components/loading-spinner.tsx

@@ -3,7 +3,6 @@ import { useEffect, useState } from 'react'
 import OLSpinner, {
 import OLSpinner, {
   OLSpinnerSize,
   OLSpinnerSize,
 } from '@/features/ui/components/ol/ol-spinner'
 } from '@/features/ui/components/ol/ol-spinner'
-import { isBootstrap5 } from '@/features/utils/bootstrap-5'
 import classNames from 'classnames'
 import classNames from 'classnames'
 
 
 function LoadingSpinner({
 function LoadingSpinner({
@@ -43,12 +42,14 @@ function LoadingSpinner({
     return null
     return null
   }
   }
 
 
-  const extraClasses = isBootstrap5()
-    ? [align === 'left' ? 'align-items-start' : 'align-items-center']
-    : null
-
   return (
   return (
-    <div className={classNames('loading', className, extraClasses)}>
+    <div
+      className={classNames(
+        'loading',
+        className,
+        align === 'left' ? 'align-items-start' : 'align-items-center'
+      )}
+    >
       <OLSpinner size={size} />
       <OLSpinner size={size} />
       &nbsp;
       &nbsp;
       {loadingText || `${t('loading')}…`}
       {loadingText || `${t('loading')}…`}

+ 1 - 4
services/web/frontend/js/shared/components/material-icon.tsx

@@ -1,6 +1,5 @@
 import classNames from 'classnames'
 import classNames from 'classnames'
 import React from 'react'
 import React from 'react'
-import { bsVersion } from '@/features/utils/bootstrap-5'
 import unfilledIconTypes from '../../../fonts/material-symbols/unfilled-symbols.mjs'
 import unfilledIconTypes from '../../../fonts/material-symbols/unfilled-symbols.mjs'
 
 
 export type AvailableUnfilledIcon = (typeof unfilledIconTypes)[number]
 export type AvailableUnfilledIcon = (typeof unfilledIconTypes)[number]
@@ -43,9 +42,7 @@ function MaterialIcon({
         {type}
         {type}
       </span>
       </span>
       {accessibilityLabel && (
       {accessibilityLabel && (
-        <span className={bsVersion({ bs5: 'visually-hidden', bs3: 'sr-only' })}>
-          {accessibilityLabel}
-        </span>
+        <span className="visually-hidden">{accessibilityLabel}</span>
       )}
       )}
     </>
     </>
   )
   )

+ 65 - 144
services/web/frontend/js/shared/components/select.tsx

@@ -10,9 +10,7 @@ import {
 } from 'react'
 } from 'react'
 import classNames from 'classnames'
 import classNames from 'classnames'
 import { useSelect } from 'downshift'
 import { useSelect } from 'downshift'
-import Icon from './icon'
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { Form, Spinner } from 'react-bootstrap-5'
 import { Form, Spinner } from 'react-bootstrap-5'
 import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
 import FormControl from '@/features/ui/components/bootstrap-5/form/form-control'
 import MaterialIcon from '@/shared/components/material-icon'
 import MaterialIcon from '@/shared/components/material-icon'
@@ -150,150 +148,73 @@ export const Select = <T,>({
   } else {
   } else {
     value = defaultText
     value = defaultText
   }
   }
-  return (
-    <BootstrapVersionSwitcher
-      bs3={
-        <div className="select-wrapper" ref={rootRef}>
-          <div>
-            {label ? (
-              <label {...getLabelProps()}>
-                {label}{' '}
-                {optionalLabel && (
-                  <span className="select-optional-label text-muted">
-                    ({t('optional')})
-                  </span>
-                )}{' '}
-                {loading && (
-                  <Icon data-testid="spinner" fw type="spinner" spin />
-                )}
-              </label>
-            ) : null}
-            <div
-              className={classNames({ disabled }, 'select-trigger')}
-              // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
-              tabIndex={0}
-              {...getToggleButtonProps({
-                disabled,
-                onKeyDown,
-              })}
-            >
-              <div>{value}</div>
-              <div>
-                {isOpen ? (
-                  <Icon type="chevron-up" fw />
-                ) : (
-                  <Icon type="chevron-down" fw />
-                )}
-              </div>
-            </div>
-          </div>
-          <ul
-            className={classNames({ hidden: !isOpen }, 'select-items')}
-            {...getMenuProps({ disabled, onKeyDown: handleMenuKeyDown })}
-          >
-            {isOpen &&
-              items?.map((item, index) => {
-                const isDisabled = itemToDisabled && itemToDisabled(item)
-                return (
-                  <li
-                    className={classNames({
-                      'select-highlighted': highlightedIndex === index,
-                      'selected-active': selectedItem === item,
-                      'select-icon': selectedIcon,
-                      'select-disabled': isDisabled,
-                    })}
-                    key={itemToKey(item)}
-                    {...getItemProps({ item, index, disabled: isDisabled })}
-                  >
-                    <span className="select-item-title">
-                      {selectedIcon && (
-                        <div className="select-item-icon">
-                          {(selectedItem === item ||
-                            (!selectedItem && defaultItem === item)) && (
-                            <Icon type="check" fw />
-                          )}
-                        </div>
-                      )}
-                      {itemToString(item)}
-                    </span>
 
 
-                    {itemToSubtitle ? (
-                      <span className="text-muted select-item-subtitle">
-                        {itemToSubtitle(item)}
-                      </span>
-                    ) : null}
-                  </li>
-                )
-              })}
-          </ul>
-        </div>
-      }
-      bs5={
-        <div className="select-wrapper" ref={rootRef}>
-          {label ? (
-            <Form.Label {...getLabelProps()}>
-              {label}{' '}
-              {optionalLabel && (
-                <span className="fw-normal">({t('optional')})</span>
-              )}{' '}
-              {loading && (
-                <span data-testid="spinner">
-                  <Spinner
-                    animation="border"
-                    aria-hidden="true"
-                    as="span"
-                    role="status"
-                    size="sm"
-                  />
-                </span>
-              )}
-            </Form.Label>
-          ) : null}
-          <FormControl
-            data-testid={dataTestId}
-            {...getToggleButtonProps({
-              disabled,
-              onKeyDown,
-              className: 'select-trigger',
-            })}
-            value={value}
-            readOnly
-            append={
-              <MaterialIcon
-                type={isOpen ? 'keyboard_arrow_up' : 'keyboard_arrow_down'}
-                className="align-text-bottom"
+  return (
+    <div className="select-wrapper" ref={rootRef}>
+      {label ? (
+        <Form.Label {...getLabelProps()}>
+          {label}{' '}
+          {optionalLabel && (
+            <span className="fw-normal">({t('optional')})</span>
+          )}{' '}
+          {loading && (
+            <span data-testid="spinner">
+              <Spinner
+                animation="border"
+                aria-hidden="true"
+                as="span"
+                role="status"
+                size="sm"
               />
               />
-            }
+            </span>
+          )}
+        </Form.Label>
+      ) : null}
+      <FormControl
+        data-testid={dataTestId}
+        {...getToggleButtonProps({
+          disabled,
+          onKeyDown,
+          className: 'select-trigger',
+        })}
+        value={value}
+        readOnly
+        append={
+          <MaterialIcon
+            type={isOpen ? 'keyboard_arrow_up' : 'keyboard_arrow_down'}
+            className="align-text-bottom"
           />
           />
-          <ul
-            {...getMenuProps({ disabled, onKeyDown: handleMenuKeyDown })}
-            className={classNames('dropdown-menu w-100', { show: isOpen })}
-          >
-            {isOpen &&
-              items?.map((item, index) => {
-                const isDisabled = itemToDisabled && itemToDisabled(item)
-                return (
-                  <li role="none" key={itemToKey(item)}>
-                    <DropdownItem
-                      as="button"
-                      className={classNames({
-                        'select-highlighted': highlightedIndex === index,
-                      })}
-                      active={selectedItem === item}
-                      trailingIcon={selectedItem === item ? 'check' : undefined}
-                      description={
-                        itemToSubtitle ? itemToSubtitle(item) : undefined
-                      }
-                      {...getItemProps({ item, index, disabled: isDisabled })}
-                    >
-                      {itemToString(item)}
-                    </DropdownItem>
-                  </li>
-                )
-              })}
-          </ul>
-        </div>
-      }
-    />
+        }
+      />
+      <ul
+        {...getMenuProps({ disabled, onKeyDown: handleMenuKeyDown })}
+        className={classNames('dropdown-menu w-100', { show: isOpen })}
+      >
+        {isOpen &&
+          items?.map((item, index) => {
+            const isDisabled = itemToDisabled && itemToDisabled(item)
+            return (
+              <li role="none" key={itemToKey(item)}>
+                <DropdownItem
+                  as="button"
+                  className={classNames({
+                    'select-highlighted': highlightedIndex === index,
+                  })}
+                  active={selectedItem === item}
+                  trailingIcon={
+                    selectedIcon && selectedItem === item ? 'check' : undefined
+                  }
+                  description={
+                    itemToSubtitle ? itemToSubtitle(item) : undefined
+                  }
+                  {...getItemProps({ item, index, disabled: isDisabled })}
+                >
+                  {itemToString(item)}
+                </DropdownItem>
+              </li>
+            )
+          })}
+      </ul>
+    </div>
   )
   )
 }
 }

+ 0 - 56
services/web/frontend/js/shared/components/tag.tsx

@@ -1,56 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { Label } from 'react-bootstrap'
-import { MergeAndOverride } from '../../../../types/utils'
-import classnames from 'classnames'
-
-type TagProps = MergeAndOverride<
-  React.ComponentProps<'span'>,
-  {
-    prepend?: React.ReactNode
-    children: React.ReactNode
-    contentProps?: React.ComponentProps<'button'>
-    closeBtnProps?: React.ComponentProps<'button'>
-    className?: string
-    bsStyle?: React.ComponentProps<typeof Label>['bsStyle'] | null
-  }
->
-
-function Tag({
-  prepend,
-  children,
-  contentProps,
-  closeBtnProps,
-  bsStyle,
-  className,
-  ...rest
-}: TagProps) {
-  const { t } = useTranslation()
-
-  return (
-    <span className={classnames('badge-tag-bs3', className)} {...rest}>
-      <span
-        {...contentProps}
-        className={classnames(
-          'badge-tag-bs3-content-wrapper',
-          { clickable: Boolean(contentProps?.onClick) },
-          contentProps?.className
-        )}
-      >
-        {prepend && <span className="badge-tag-bs3-prepend">{prepend}</span>}
-        <span className="badge-tag-bs3-content">{children}</span>
-      </span>
-      {closeBtnProps && (
-        <button
-          type="button"
-          className="badge-tag-bs3-close"
-          aria-label={t('remove_tag', { tagName: children })}
-          {...closeBtnProps}
-        >
-          <span aria-hidden="true">&times;</span>
-        </button>
-      )}
-    </span>
-  )
-}
-
-export default Tag

+ 0 - 57
services/web/frontend/js/shared/components/tooltip.tsx

@@ -1,57 +0,0 @@
-import { cloneElement } from 'react'
-import {
-  OverlayTrigger,
-  OverlayTriggerProps,
-  Tooltip as BSTooltip,
-} from 'react-bootstrap'
-import { callFnsInSequence } from '../../utils/functions'
-
-type OverlayProps = Omit<OverlayTriggerProps, 'overlay'> & {
-  shouldUpdatePosition?: boolean // Not officially documented https://stackoverflow.com/a/43138470
-}
-
-export type TooltipProps = {
-  description: React.ReactNode
-  id: string
-  overlayProps?: OverlayProps
-  tooltipProps?: BSTooltip.TooltipProps
-  hidden?: boolean
-  children: React.ReactElement
-}
-
-function Tooltip({
-  id,
-  description,
-  children,
-  tooltipProps,
-  overlayProps,
-  hidden,
-}: TooltipProps) {
-  const hideTooltip = (e: React.MouseEvent) => {
-    if (e.currentTarget instanceof HTMLElement) {
-      e.currentTarget.blur()
-    }
-  }
-
-  return (
-    <OverlayTrigger
-      overlay={
-        <BSTooltip
-          id={`${id}-tooltip`}
-          {...tooltipProps}
-          style={{ display: hidden ? 'none' : 'block' }}
-        >
-          {description}
-        </BSTooltip>
-      }
-      {...overlayProps}
-      placement={overlayProps?.placement || 'top'}
-    >
-      {cloneElement(children, {
-        onClick: callFnsInSequence(children.props.onClick, hideTooltip),
-      })}
-    </OverlayTrigger>
-  )
-}
-
-export default Tooltip

+ 1 - 8
services/web/frontend/js/shared/components/upgrade-benefits.jsx

@@ -1,16 +1,9 @@
-import Icon from './icon'
 import MaterialIcon from '@/shared/components/material-icon'
 import MaterialIcon from '@/shared/components/material-icon'
-import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
 import { useTranslation } from 'react-i18next'
 import { useTranslation } from 'react-i18next'
 import { memo } from 'react'
 import { memo } from 'react'
 
 
 function Check() {
 function Check() {
-  return (
-    <BootstrapVersionSwitcher
-      bs3={<Icon type="check" />}
-      bs5={<MaterialIcon type="check" />}
-    />
-  )
+  return <MaterialIcon type="check" />
 }
 }
 
 
 function UpgradeBenefits() {
 function UpgradeBenefits() {

+ 5 - 55
services/web/frontend/stories/contact-us-modal.stories.tsx

@@ -3,40 +3,10 @@ import useFetchMock from './hooks/use-fetch-mock'
 import ContactUsModal from '../../modules/support/frontend/js/components/contact-us-modal'
 import ContactUsModal from '../../modules/support/frontend/js/components/contact-us-modal'
 import fixedHelpSuggestionSearch from '../../modules/support/test/frontend/util/fixed-help-suggestion-search'
 import fixedHelpSuggestionSearch from '../../modules/support/test/frontend/util/fixed-help-suggestion-search'
 import { ScopeDecorator } from './decorators/scope'
 import { ScopeDecorator } from './decorators/scope'
-import { StoryObj } from '@storybook/react'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import OLButton from '@/features/ui/components/ol/ol-button'
-import { bsVersionDecorator } from '../../.storybook/utils/with-bootstrap-switcher'
 
 
-type Story = StoryObj<typeof ContactUsModal>
 type ContactUsModalProps = ComponentProps<typeof ContactUsModal>
 type ContactUsModalProps = ComponentProps<typeof ContactUsModal>
 
 
-function bootstrap3Story(render: Story['render']): Story {
-  return {
-    render,
-    decorators: [
-      story => {
-        return ScopeDecorator(story)
-      },
-    ],
-  }
-}
-
-function bootstrap5Story(render: Story['render']): Story {
-  return {
-    render,
-    decorators: [
-      story => {
-        return ScopeDecorator(story, undefined, {
-          'ol-bootstrapVersion': 5,
-        })
-      },
-    ],
-    parameters: {
-      bootstrap5: true,
-    },
-  }
-}
-
 function GenericContactUsModal(args: ContactUsModalProps) {
 function GenericContactUsModal(args: ContactUsModalProps) {
   useFetchMock(fetchMock => {
   useFetchMock(fetchMock => {
     fetchMock.post('/support', { status: 200 }, { delay: 1000 })
     fetchMock.post('/support', { status: 200 }, { delay: 1000 })
@@ -50,13 +20,9 @@ function GenericContactUsModal(args: ContactUsModalProps) {
   )
   )
 }
 }
 
 
-export const Generic: Story = bootstrap3Story(args => (
+export const Generic = (args: ContactUsModalProps) => (
   <GenericContactUsModal {...args} />
   <GenericContactUsModal {...args} />
-))
-
-export const GenericBootstrap5: Story = bootstrap5Story(args => (
-  <GenericContactUsModal {...args} />
-))
+)
 
 
 const ContactUsModalWithRequestError = (args: ContactUsModalProps) => {
 const ContactUsModalWithRequestError = (args: ContactUsModalProps) => {
   useFetchMock(fetchMock => {
   useFetchMock(fetchMock => {
@@ -71,18 +37,10 @@ const ContactUsModalWithRequestError = (args: ContactUsModalProps) => {
   )
   )
 }
 }
 
 
-const renderContactUsModalWithRequestError = (args: ContactUsModalProps) => (
+export const RequestError = (args: ContactUsModalProps) => (
   <ContactUsModalWithRequestError {...args} />
   <ContactUsModalWithRequestError {...args} />
 )
 )
 
 
-export const RequestError: Story = bootstrap3Story(
-  renderContactUsModalWithRequestError
-)
-
-export const RequestErrorBootstrap5: Story = bootstrap5Story(
-  renderContactUsModalWithRequestError
-)
-
 const ContactUsModalWithAcknowledgement = (
 const ContactUsModalWithAcknowledgement = (
   args: Omit<ContactUsModalProps, 'show' | 'handleHide'>
   args: Omit<ContactUsModalProps, 'show' | 'handleHide'>
 ) => {
 ) => {
@@ -110,19 +68,11 @@ const ContactUsModalWithAcknowledgement = (
   )
   )
 }
 }
 
 
-const renderContactUsModalWithAcknowledgement = (args: ContactUsModalProps) => {
+export const WithAcknowledgement = (args: ContactUsModalProps) => {
   const { show, handleHide, ...rest } = args
   const { show, handleHide, ...rest } = args
   return <ContactUsModalWithAcknowledgement {...rest} />
   return <ContactUsModalWithAcknowledgement {...rest} />
 }
 }
 
 
-export const WithAcknowledgement: Story = bootstrap3Story(
-  renderContactUsModalWithAcknowledgement
-)
-
-export const WithAcknowledgementBootstrap5: Story = bootstrap5Story(
-  renderContactUsModalWithAcknowledgement
-)
-
 export default {
 export default {
   title: 'Shared / Modals / Contact Us',
   title: 'Shared / Modals / Contact Us',
   component: ContactUsModal,
   component: ContactUsModal,
@@ -133,6 +83,6 @@ export default {
   },
   },
   argTypes: {
   argTypes: {
     handleHide: { action: 'close modal' },
     handleHide: { action: 'close modal' },
-    ...bsVersionDecorator.argTypes,
   },
   },
+  decorators: [ScopeDecorator],
 }
 }

+ 0 - 45
services/web/frontend/stories/dropdown.stories.jsx

@@ -1,45 +0,0 @@
-import { Dropdown, MenuItem } from 'react-bootstrap'
-import ControlledDropdown from '../js/shared/components/controlled-dropdown'
-
-export const Customized = args => {
-  return (
-    <ControlledDropdown
-      pullRight={args.pullRight}
-      defaultOpen={args.defaultOpen}
-      id="dropdown-story"
-    >
-      <Dropdown.Toggle
-        noCaret={args.noCaret}
-        className={args.className}
-        bsStyle={args.bsStyle}
-      >
-        {args.title}
-      </Dropdown.Toggle>
-      <Dropdown.Menu>
-        <MenuItem eventKey="1">Action</MenuItem>
-        <MenuItem eventKey="2">Another action</MenuItem>
-        <MenuItem eventKey="3" active>
-          Active Item
-        </MenuItem>
-        <MenuItem divider />
-        <MenuItem eventKey="4">Separated link</MenuItem>
-      </Dropdown.Menu>
-    </ControlledDropdown>
-  )
-}
-Customized.args = {
-  title: 'Toggle & Menu used separately',
-}
-
-export default {
-  title: 'Shared / Components / Dropdown',
-  component: ControlledDropdown,
-  args: {
-    bsStyle: 'default',
-    title: 'Dropdown',
-    pullRight: false,
-    noCaret: false,
-    className: '',
-    defaultOpen: true,
-  },
-}

+ 0 - 4
services/web/frontend/stories/feedback-badge.stories.tsx

@@ -1,6 +1,5 @@
 import { ScopeDecorator } from './decorators/scope'
 import { ScopeDecorator } from './decorators/scope'
 import { FeedbackBadge } from '@/shared/components/feedback-badge'
 import { FeedbackBadge } from '@/shared/components/feedback-badge'
-import { bsVersionDecorator } from '../../.storybook/utils/with-bootstrap-switcher'
 
 
 export const WithDefaultText = () => {
 export const WithDefaultText = () => {
   return (
   return (
@@ -33,7 +32,4 @@ export default {
   title: 'Shared / Components / Feedback Badge',
   title: 'Shared / Components / Feedback Badge',
   component: FeedbackBadge,
   component: FeedbackBadge,
   decorators: [ScopeDecorator],
   decorators: [ScopeDecorator],
-  argTypes: {
-    ...bsVersionDecorator.argTypes,
-  },
 }
 }

+ 1 - 6
services/web/frontend/stories/input-switch.stories.tsx

@@ -1,5 +1,4 @@
 import OLFormSwitch from '@/features/ui/components/ol/ol-form-switch'
 import OLFormSwitch from '@/features/ui/components/ol/ol-form-switch'
-import { bsVersionDecorator } from '../../.storybook/utils/with-bootstrap-switcher'
 import { disableControlsOf } from './utils/arg-types'
 import { disableControlsOf } from './utils/arg-types'
 
 
 export const Unchecked = () => {
 export const Unchecked = () => {
@@ -22,10 +21,6 @@ export default {
   title: 'Shared / Components / Input Switch',
   title: 'Shared / Components / Input Switch',
   component: OLFormSwitch,
   component: OLFormSwitch,
   argTypes: {
   argTypes: {
-    ...bsVersionDecorator.argTypes,
-    ...disableControlsOf('inputRef', 'bs3Props'),
-  },
-  args: {
-    ...bsVersionDecorator.args,
+    ...disableControlsOf('inputRef'),
   },
   },
 }
 }

+ 0 - 2
services/web/frontend/stories/loading/loading.stories.tsx

@@ -1,7 +1,6 @@
 import type { Meta, StoryObj } from '@storybook/react'
 import type { Meta, StoryObj } from '@storybook/react'
 import { LoadingUI } from '@/features/ide-react/components/loading'
 import { LoadingUI } from '@/features/ide-react/components/loading'
 import { EditorProviders } from '../../../test/frontend/helpers/editor-providers'
 import { EditorProviders } from '../../../test/frontend/helpers/editor-providers'
-import { bsVersionDecorator } from '../../../.storybook/utils/with-bootstrap-switcher'
 import { PartialMeta } from '@/utils/meta'
 import { PartialMeta } from '@/utils/meta'
 
 
 const meta: Meta<typeof LoadingUI> = {
 const meta: Meta<typeof LoadingUI> = {
@@ -19,7 +18,6 @@ const meta: Meta<typeof LoadingUI> = {
       ],
       ],
     },
     },
     progress: { control: { type: 'range', min: 0, max: 100 } },
     progress: { control: { type: 'range', min: 0, max: 100 } },
-    ...bsVersionDecorator.argTypes,
   },
   },
 }
 }
 
 

+ 0 - 3
services/web/frontend/stories/menu-bar.stories.tsx

@@ -30,9 +30,6 @@ const meta: Meta<typeof MenuBar> = {
   title: 'Shared / Components / MenuBar',
   title: 'Shared / Components / MenuBar',
   component: MenuBar,
   component: MenuBar,
   argTypes: {},
   argTypes: {},
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }
 
 
 export default meta
 export default meta

+ 0 - 7
services/web/frontend/stories/modals/unsaved-docs-locked-modal.stories.tsx

@@ -1,18 +1,11 @@
 import { Meta, StoryObj } from '@storybook/react'
 import { Meta, StoryObj } from '@storybook/react'
 import { UnsavedDocsLockedAlert } from '@/features/ide-react/components/unsaved-docs/unsaved-docs-locked-alert'
 import { UnsavedDocsLockedAlert } from '@/features/ide-react/components/unsaved-docs/unsaved-docs-locked-alert'
 import { ScopeDecorator } from '../decorators/scope'
 import { ScopeDecorator } from '../decorators/scope'
-import { bsVersionDecorator } from '../../../.storybook/utils/with-bootstrap-switcher'
 
 
 export default {
 export default {
   title: 'Editor / Modals / Unsaved Docs Locked',
   title: 'Editor / Modals / Unsaved Docs Locked',
   component: UnsavedDocsLockedAlert,
   component: UnsavedDocsLockedAlert,
   decorators: [Story => ScopeDecorator(Story)],
   decorators: [Story => ScopeDecorator(Story)],
-  argTypes: {
-    ...bsVersionDecorator.argTypes,
-  },
-  parameters: {
-    bootstrap5: true,
-  },
 } satisfies Meta
 } satisfies Meta
 
 
 type Story = StoryObj<typeof UnsavedDocsLockedAlert>
 type Story = StoryObj<typeof UnsavedDocsLockedAlert>

+ 6 - 4
services/web/frontend/stories/pdf-preview.stories.jsx

@@ -1,6 +1,6 @@
 import { useCallback, useMemo, useState } from 'react'
 import { useCallback, useMemo, useState } from 'react'
 import useFetchMock from './hooks/use-fetch-mock'
 import useFetchMock from './hooks/use-fetch-mock'
-import { Button } from 'react-bootstrap'
+import OLButton from '@/features/ui/components/ol/ol-button'
 import PdfPreviewPane from '../js/features/pdf-preview/components/pdf-preview-pane'
 import PdfPreviewPane from '../js/features/pdf-preview/components/pdf-preview-pane'
 import PdfPreview from '../js/features/pdf-preview/components/pdf-preview'
 import PdfPreview from '../js/features/pdf-preview/components/pdf-preview'
 import PdfFileList from '../js/features/pdf-preview/components/pdf-file-list'
 import PdfFileList from '../js/features/pdf-preview/components/pdf-file-list'
@@ -123,10 +123,12 @@ export const Interactive = () => {
                   margin: '10px 0',
                   margin: '10px 0',
                 }}
                 }}
               >
               >
-                <Button onClick={dispatchDocChanged}>trigger doc change</Button>
-                <Button onClick={toggleLintingError}>
+                <OLButton onClick={dispatchDocChanged}>
+                  trigger doc change
+                </OLButton>
+                <OLButton onClick={toggleLintingError}>
                   toggle linting error
                   toggle linting error
-                </Button>
+                </OLButton>
               </div>
               </div>
             </div>
             </div>
           </div>
           </div>

+ 0 - 3
services/web/frontend/stories/project-list/add-affiliation.stories.tsx

@@ -26,7 +26,4 @@ export const Add = (args: any) => {
 export default {
 export default {
   title: 'Project List / Affiliation',
   title: 'Project List / Affiliation',
   component: AddAffiliation,
   component: AddAffiliation,
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

+ 0 - 3
services/web/frontend/stories/project-list/color-picker.stories.tsx

@@ -12,7 +12,4 @@ export const Select = (args: any) => {
 export default {
 export default {
   title: 'Project List / Color Picker',
   title: 'Project List / Color Picker',
   component: ColorPicker,
   component: ColorPicker,
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

+ 0 - 3
services/web/frontend/stories/project-list/compile-and-download-project-pdf.stories.tsx

@@ -62,7 +62,4 @@ export default {
       </div>
       </div>
     ),
     ),
   ],
   ],
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

+ 0 - 3
services/web/frontend/stories/project-list/current-plan-widget.stories.tsx

@@ -72,7 +72,4 @@ export const PausedPlan = (args: any) => {
 export default {
 export default {
   title: 'Project List / Current Plan Widget',
   title: 'Project List / Current Plan Widget',
   component: CurrentPlanWidget,
   component: CurrentPlanWidget,
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

+ 0 - 3
services/web/frontend/stories/project-list/inr-banner.stories.tsx

@@ -7,7 +7,4 @@ export const Default = () => {
 export default {
 export default {
   title: 'Project List / INR Banner',
   title: 'Project List / INR Banner',
   component: INRBanner,
   component: INRBanner,
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

+ 0 - 3
services/web/frontend/stories/project-list/new-project-button.stories.tsx

@@ -104,7 +104,4 @@ export const Error = () => {
 export default {
 export default {
   title: 'Project List / New Project Button',
   title: 'Project List / New Project Button',
   component: NewProjectButton,
   component: NewProjectButton,
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

+ 0 - 3
services/web/frontend/stories/project-list/notifications.stories.tsx

@@ -343,7 +343,4 @@ export const ReconfirmedAffiliationSuccess = (args: any) => {
 export default {
 export default {
   title: 'Project List / Notifications',
   title: 'Project List / Notifications',
   component: UserNotifications,
   component: UserNotifications,
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

+ 0 - 3
services/web/frontend/stories/project-list/project-list.stories.tsx

@@ -57,7 +57,4 @@ export default {
       </div>
       </div>
     ),
     ),
   ],
   ],
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

+ 0 - 3
services/web/frontend/stories/project-list/project-search.stories.tsx

@@ -24,7 +24,4 @@ export default {
   args: {
   args: {
     inputValue: '',
     inputValue: '',
   },
   },
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

+ 0 - 3
services/web/frontend/stories/project-list/survey-widget.stories.tsx

@@ -28,7 +28,4 @@ export const EmptySurvey = (args: any) => {
 export default {
 export default {
   title: 'Project List / Survey Widget',
   title: 'Project List / Survey Widget',
   component: SurveyWidget,
   component: SurveyWidget,
-  parameters: {
-    bootstrap5: true,
-  },
 }
 }

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio