diff --git a/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/alert_user.js b/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/alert_user.js index b63241c36e7b..228a62a76224 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/alert_user.js +++ b/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/alert_user.js @@ -16,7 +16,7 @@ hqDefine("hqwebapp/js/bootstrap5/alert_user", [ "jquery", "knockout", - "hqwebapp/js/bootstrap3/hq.helpers", + "hqwebapp/js/bootstrap5/hq.helpers", ], function ( $, diff --git a/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/hq-bug-report.js b/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/hq-bug-report.js index a803cafda6ee..778d7485c6d9 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/hq-bug-report.js +++ b/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/hq-bug-report.js @@ -1,49 +1,58 @@ hqDefine('hqwebapp/js/bootstrap5/hq-bug-report', [ - "jquery", "jquery-form/dist/jquery.form.min", "hqwebapp/js/bootstrap5/hq.helpers", -], function ($) { + "jquery", + "hqwebapp/js/bootstrap5_loader", + "jquery-form/dist/jquery.form.min", + "hqwebapp/js/bootstrap5/hq.helpers", +], function ($, bootstrap) { + 'use strict'; $(function () { - var $hqwebappBugReportModal = $('#modalReportIssue'), - $hqwebappBugReportForm = $('#hqwebapp-bugReportForm'), - $hqwebappBugReportSubmit = $('#bug-report-submit'), - $hqwebappBugReportCancel = $('#bug-report-cancel'), - $ccFormGroup = $("#bug-report-cc-form-group"), - $emailFormGroup = $("#bug-report-email-form-group"), - $issueSubjectFormGroup = $("#bug-report-subject-form-group"), - isBugReportSubmitting = false; + let self = {}; - var resetForm = function () { - $hqwebappBugReportForm.find("button[type='submit']").button('reset'); - $hqwebappBugReportForm.resetForm(); - $hqwebappBugReportCancel.enableButton(); - $hqwebappBugReportSubmit.button('reset'); - $ccFormGroup.removeClass('has-error has-feedback'); - $ccFormGroup.find(".label-danger").addClass('hide'); - $emailFormGroup.removeClass('has-error has-feedback'); - $emailFormGroup.find(".label-danger").addClass('hide'); + self.$bugReportModalElement = $('#modalReportIssue'); + self.bugReportModal = new bootstrap.Modal(self.$bugReportModalElement); + self.$hqwebappBugReportForm = $('#hqwebapp-bugReportForm'); + self.$hqwebappBugReportSubmit = $('#bug-report-submit'); + self.$hqwebappBugReportCancel = $('#bug-report-cancel'); + self.$ccFormGroup = $("#bug-report-cc-form-group"); + self.$emailFormGroup = $("#bug-report-email-form-group"); + self.$issueSubjectFormGroup = $("#bug-report-subject-form-group"); + self.isBugReportSubmitting = false; + + self.resetForm = function () { + self.$hqwebappBugReportForm.find("button[type='submit']").changeButtonState('reset'); + self.$hqwebappBugReportForm.resetForm(); + self.$hqwebappBugReportCancel.enableButton(); + self.$hqwebappBugReportSubmit.changeButtonState('reset'); + self.$ccFormGroup.removeClass('has-error has-feedback'); + self.$ccFormGroup.find(".label-danger").addClass('hide'); + self.$emailFormGroup.removeClass('has-error has-feedback'); + self.$emailFormGroup.find(".label-danger").addClass('hide'); }; - $hqwebappBugReportModal.on('shown.bs.modal', function () { + self.$bugReportModalElement.on('shown.bs.modal', function () { $("input#bug-report-subject").focus(); }); - $hqwebappBugReportForm.submit(function () { - var isDescriptionEmpty = !$("#bug-report-subject").val() && !$("#bug-report-message").val(); + self.$hqwebappBugReportForm.submit(function (e) { + e.preventDefault(); + + let isDescriptionEmpty = !$("#bug-report-subject").val() && !$("#bug-report-message").val(); if (isDescriptionEmpty) { - highlightInvalidField($issueSubjectFormGroup); + self.highlightInvalidField(self.$issueSubjectFormGroup); } - var emailAddress = $(this).find("input[name='email']").val(); - if (emailAddress && !IsValidEmail(emailAddress)) { - highlightInvalidField($emailFormGroup); + let emailAddress = $(this).find("input[name='email']").val(); + if (emailAddress && !self.isValidEmail(emailAddress)) { + self.highlightInvalidField(self.$emailFormGroup); return false; } - var emailAddresses = $(this).find("input[name='cc']").val(); + let emailAddresses = $(this).find("input[name='cc']").val(); emailAddresses = emailAddresses.replace(/ /g, "").split(","); - for (var index in emailAddresses) { - var email = emailAddresses[index]; - if (email && !IsValidEmail(email)) { - highlightInvalidField($ccFormGroup); + for (let index in emailAddresses) { + let email = emailAddresses[index]; + if (email && !self.isValidEmail(email)) { + self.highlightInvalidField(self.$ccFormGroup); return false; } } @@ -51,57 +60,61 @@ hqDefine('hqwebapp/js/bootstrap5/hq-bug-report', [ return false; } - if (!isBugReportSubmitting && $hqwebappBugReportSubmit.text() === $hqwebappBugReportSubmit.data("success-text")) { - $hqwebappBugReportModal.modal("hide"); - } else if (!isBugReportSubmitting) { - $hqwebappBugReportCancel.disableButtonNoSpinner(); - $hqwebappBugReportSubmit.button('loading'); + if (!self.isBugReportSubmitting && self.$hqwebappBugReportSubmit.text() === + self.$hqwebappBugReportSubmit.data("success-text")) { + self.bugReportModal.hide(); + } else if (!self.isBugReportSubmitting) { + self.$hqwebappBugReportCancel.disableButtonNoSpinner(); + self.$hqwebappBugReportSubmit.changeButtonState('loading'); $(this).ajaxSubmit({ type: "POST", url: $(this).attr('action'), - beforeSerialize: hqwebappBugReportBeforeSerialize, - beforeSubmit: hqwebappBugReportBeforeSubmit, - success: hqwebappBugReportSucccess, - error: hqwebappBugReportError, + beforeSerialize: self.hqwebappBugReportBeforeSerialize, + beforeSubmit: self.hqwebappBugReportBeforeSubmit, + success: self.hqwebappBugReportSuccess, + error: self.hqwebappBugReportError, }); } return false; }); - function IsValidEmail(email) { - var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/; + self.isValidEmail = function (email) { + let regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/; return regex.test(email); - } + }; - function hqwebappBugReportBeforeSerialize($form) { + self.hqwebappBugReportBeforeSerialize = function ($form) { $form.find("#bug-report-url").val(location.href); - } + }; - function hqwebappBugReportBeforeSubmit() { - isBugReportSubmitting = true; - } + self.hqwebappBugReportBeforeSubmit = function () { + self.isBugReportSubmitting = true; + }; - function hqwebappBugReportSucccess() { - isBugReportSubmitting = false; - $hqwebappBugReportForm.find("button[type='submit']").button('success').removeClass('btn-danger').addClass('btn-primary'); - $hqwebappBugReportModal.one('hidden.bs.modal', function () { - resetForm(); + self.hqwebappBugReportSuccess = function () { + self.isBugReportSubmitting = false; + self.$bugReportModalElement.one('hidden.bs.modal', function () { + self.resetForm(); }); - } + self.$hqwebappBugReportForm.find("button[type='submit']") + .changeButtonState('success') + .removeClass('btn-danger').addClass('btn-primary'); + }; - function hqwebappBugReportError() { - isBugReportSubmitting = false; - $hqwebappBugReportForm.find("button[type='submit']").button('error').removeClass('btn-primary').addClass('btn-danger'); - $hqwebappBugReportCancel.enableButton(); - } + self.hqwebappBugReportError = function () { + self.isBugReportSubmitting = false; + self.$hqwebappBugReportForm.find("button[type='submit']").changeButtonState('error') + .removeClass('btn-primary').addClass('btn-danger'); + self.$hqwebappBugReportCancel.enableButton(); + }; - function highlightInvalidField($element) { + self.highlightInvalidField = function ($element) { $element.addClass('has-error has-feedback'); $element.find(".label-danger").removeClass('hide'); $element.find("input").focus(function () { $element.removeClass("has-error has-feedback"); $element.find(".label-danger").addClass('hide'); }); - } + }; }); }); diff --git a/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/hq.helpers.js b/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/hq.helpers.js index c5efcee20af2..245af1df0ce8 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/hq.helpers.js +++ b/corehq/apps/hqwebapp/static/hqwebapp/js/bootstrap5/hq.helpers.js @@ -59,19 +59,6 @@ hqDefine("hqwebapp/js/bootstrap5/hq.helpers", [ return false; // let default handler run }; - var oldHide = $.fn.popover.Constructor.prototype.hide; - - $.fn.popover.Constructor.prototype.hide = function () { - if (this.options.trigger === "hover" && this.tip().is(":hover")) { - var that = this; - setTimeout(function () { - return that.hide.apply(that, arguments); - }, that.options.delay.hide); - return; - } - oldHide.apply(this, arguments); - }; - $.fn.hqHelp = function () { var self = this; self.each(function (i) { @@ -103,6 +90,11 @@ hqDefine("hqwebapp/js/bootstrap5/hq.helpers", [ }); }; + $.fn.changeButtonState = function (state) { + $(this).text($(this).data(state + '-text')); + return this; + }; + $.fn.addSpinnerToButton = function () { $(this).find("i").addClass("hide"); $(this).prepend(' '); diff --git a/corehq/apps/hqwebapp/static/hqwebapp/js/hqModules.js b/corehq/apps/hqwebapp/static/hqwebapp/js/hqModules.js index b918a6e1bbb2..ce45af74f2d7 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/js/hqModules.js +++ b/corehq/apps/hqwebapp/static/hqwebapp/js/hqModules.js @@ -69,6 +69,9 @@ function hqDefine(path, dependencies, moduleAccessor) { 'hqwebapp/js/lib/modernizr': 'Modernizr', 'sinon/pkg/sinon': 'sinon', }; + if (window.USE_BOOTSTRAP5) { + thirdPartyGlobals['hqwebapp/js/bootstrap5_loader'] = 'bootstrap'; + } var args = []; for (var i = 0; i < dependencies.length; i++) { var dependency = dependencies[i]; diff --git a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq.scss b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq.scss index b2917bf269c2..e10e55aa5819 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq.scss +++ b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq.scss @@ -3,6 +3,7 @@ @import "functions"; @import "commcarehq/variables"; // This comes before Bootstrap 5 variables to override the defaults @import "variables"; +@import "variables-dark"; @import "commcarehq/variables_bootstrap3"; // Variables specific to B3-era Stylesheet @import "maps"; @import "mixins"; diff --git a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_containers.scss b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_containers.scss index 590f2710cfe6..af4272472f0f 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_containers.scss +++ b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_containers.scss @@ -1,3 +1,7 @@ +html, body { + height: 100%; +} + .hq-container { min-height: 100%; height: auto !important; diff --git a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_dropdown.scss b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_dropdown.scss index 2a731ff34179..3f88bd53d541 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_dropdown.scss +++ b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_dropdown.scss @@ -24,7 +24,7 @@ border-color: transparent; border-style: solid; border-width: 5px 0 5px 5px; - border-left-color: darken($dropdown-bg, 20%); + border-left-color: darken($body-bg, 20%); margin-right: -5px; margin-top: 3.3px; color: $dropdown-link-color; @@ -72,14 +72,19 @@ margin-top: 5px; } - .dropdown-menu .dropdown-divider { - margin-top: 0px; - margin-bottom: 0px; + .navbar-nav > li > a.dropdown-toggle-with-icon { + padding-top: 22px !important; + padding-bottom: 17px !important; } .nav-settings-bar .dropdown-toggle-with-icon.nav-link::after { display: none; } + + .dropdown-toggle::after { + vertical-align: 2.48px; + margin-left: 2px; + } } @media (max-width: map-get($grid-breakpoints, "lg")) { diff --git a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_nav.scss b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_nav.scss index 8365af7fad40..ee48ecfccf07 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_nav.scss +++ b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_nav.scss @@ -54,6 +54,7 @@ .nav-main-icon { font-size: 1.7em; line-height: 0.7em; + color: $gray-light; } .text-hq-nav-header { diff --git a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_navbar.scss b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_navbar.scss index 9ab13848b2c2..66f0da7d7297 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_navbar.scss +++ b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_navbar.scss @@ -6,9 +6,12 @@ min-height: $navbar-height; .navbar-brand { + padding-top: 11px; line-height: 17px; - height: $navbar-height - 4px; + height: $navbar-height - 6px; display: inline-block; + margin-left: -1px; + margin-right: 3px; // Standard HQ logo // Custom domain logos use an actual image @@ -30,8 +33,9 @@ } &.navbar-expand-lg .navbar-nav .nav-link { - padding: 21px 15px; + padding: 21px 15px 20px; line-height: 19.5px; + color: $gray-light; } &.navbar-expand-lg .navbar-nav li:not(.active) > .nav-link:focus, @@ -64,6 +68,7 @@ .nav-settings-bar { margin-left: auto; order: 2; + padding-right: 8px; } @media(max-width: 1057px) { @@ -131,7 +136,7 @@ .dimagi-logo svg { height: 22px; width: 50px; - top: 3px; + top: 2px; position: relative; display: inline-block; } diff --git a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_type.scss b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_type.scss index ecd1d6fbab2d..3e07104eeabc 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_type.scss +++ b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_type.scss @@ -90,3 +90,10 @@ code { a { cursor: pointer; } + +// we should eventually get rid of this as bootstrap5+ doesn't natively support +.page-header { + padding-bottom: 7.5px; + margin: 34px 0 17px; + border-bottom: 1px solid #eeeeee; +} \ No newline at end of file diff --git a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_variables.scss b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_variables.scss index b92f181c310c..aa2607b71bf8 100644 --- a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_variables.scss +++ b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_variables.scss @@ -1,3 +1,14 @@ +// Grid Containers +// we will want to adapt the defaults in a full redesign +$container-max-widths: ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px, + xxl: 1160px +); + + // Typography Overrides $font-family-sans-serif: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; $font-size-base: .75rem; // approx 12px diff --git a/corehq/apps/hqwebapp/templates/hqwebapp/base.html b/corehq/apps/hqwebapp/templates/hqwebapp/base.html index 069734eef272..663e8d346d56 100644 --- a/corehq/apps/hqwebapp/templates/hqwebapp/base.html +++ b/corehq/apps/hqwebapp/templates/hqwebapp/base.html @@ -184,7 +184,11 @@ {% block modals %}{% endblock %} {% if show_mobile_ux_warning %} - {% include "hqwebapp/partials/bootstrap3/mobile_ux_warning.html" %} + {% if use_bootstrap5 %} + {% include "hqwebapp/partials/bootstrap5/mobile_ux_warning.html" %} + {% else %} + {% include "hqwebapp/partials/bootstrap3/mobile_ux_warning.html" %} + {% endif %} {% endif %} {# Report Issue #} @@ -208,7 +212,11 @@ {% if EULA_COMPLIANCE %} {% if request.couch_user and not request.couch_user.is_eula_signed %} {% registerurl 'agree_to_eula' %} - {% include 'hqwebapp/includes/bootstrap3/modal_eula.html' %} + {% if use_bootstrap5 %} + {% include 'hqwebapp/includes/bootstrap5/modal_eula.html' %} + {% else %} + {% include 'hqwebapp/includes/bootstrap3/modal_eula.html' %} + {% endif %} {% endif %} {% endif %} @@ -219,7 +227,11 @@ {% registerurl 'submit_hubspot_cta_form' %} {# 30 Day Trial #} - {% include 'hqwebapp/includes/bootstrap3/modal_30_day_trial.html' %} + {% if use_bootstrap5 %} + {% include 'hqwebapp/includes/bootstrap5/modal_30_day_trial.html' %} + {% else %} + {% include 'hqwebapp/includes/bootstrap3/modal_30_day_trial.html' %} + {% endif %} {% block additional_initial_page_data %} {% comment %} @@ -281,26 +293,35 @@ {# javascript below this line #} - {% if use_bootstrap5 %} - - {% else %} - {% include "hqwebapp/partials/requirejs.html" with BASE_MAIN=True %} - {% endif %} + {% include "hqwebapp/partials/requirejs.html" with BASE_MAIN=True %} {# DO NOT COMPRESS #} {# HQ Specific Libraries #} {% if not requirejs_main %} - {% compress js %} - - - - - - - - - {% endcompress %} + {% if use_bootstrap5 %} + {% compress js %} + + + + + + + + + {% endcompress %} + {% else %} + {% compress js %} + + + + + + + + + {% endcompress %} + {% endif %} {% endif %} {# JavaScript Display Logic Libaries #} @@ -387,22 +408,42 @@ {% endif %} {% if is_demo_visible %} - {% include "hqwebapp/partials/bootstrap3/get_demo_modals.html" %} + {% if use_bootstrap5 %} + {% include "hqwebapp/partials/bootstrap5/get_demo_modals.html" %} + {% else %} + {% include "hqwebapp/partials/bootstrap3/get_demo_modals.html" %} + {% endif %} {% endif %} {# Knockout component templates #} - {% include 'hqwebapp/partials/bootstrap3/ko_pagination.html' %} - {% include 'hqwebapp/partials/bootstrap3/ko_inline_edit.html' %} - {% include 'hqwebapp/partials/bootstrap3/ko_search_box.html' %} - {% include 'hqwebapp/partials/bootstrap3/ko_select_toggle.html' %} - {% include 'hqwebapp/partials/bootstrap3/ko_feedback.html' %} + {% if use_bootstrap5 %} + {% include 'hqwebapp/partials/bootstrap5/ko_pagination.html' %} + {% include 'hqwebapp/partials/bootstrap5/ko_inline_edit.html' %} + {% include 'hqwebapp/partials/bootstrap5/ko_search_box.html' %} + {% include 'hqwebapp/partials/bootstrap5/ko_select_toggle.html' %} + {% include 'hqwebapp/partials/bootstrap5/ko_feedback.html' %} + {% else %} + {% include 'hqwebapp/partials/bootstrap3/ko_pagination.html' %} + {% include 'hqwebapp/partials/bootstrap3/ko_inline_edit.html' %} + {% include 'hqwebapp/partials/bootstrap3/ko_search_box.html' %} + {% include 'hqwebapp/partials/bootstrap3/ko_select_toggle.html' %} + {% include 'hqwebapp/partials/bootstrap3/ko_feedback.html' %} + {% endif %} {% if show_overdue_invoice_modal and not requirejs_main %} - + {% if use_bootstrap5 %} + + {% else %} + + {% endif %} {% endif %} {% if show_prepaid_modal and not requirejs_main %} - + {% if use_bootstrap5 %} + + {% else %} + + {% endif %} {% endif %} {% if show_status_page %} diff --git a/corehq/apps/hqwebapp/templates/hqwebapp/includes/core_libraries.html b/corehq/apps/hqwebapp/templates/hqwebapp/includes/core_libraries.html index 3660ddb7f883..3fe88adccc5f 100644 --- a/corehq/apps/hqwebapp/templates/hqwebapp/includes/core_libraries.html +++ b/corehq/apps/hqwebapp/templates/hqwebapp/includes/core_libraries.html @@ -68,7 +68,7 @@ otherwise the two tooltip widgets and two button widgets conflict. {% endcomment %} {% if use_bootstrap5 %} - + {% else %} {% endif %} @@ -103,29 +103,48 @@ {# already minified #} {% if hq %} + {% if use_bootstrap5 %} {% compress js %} - - - - - - - - - + + + + + + + + + {% endcompress %} + {% else %} + {% compress js %} + + + + + + + + + + {% endcompress %} + {% endif %} {% endif %} {% endif %} {% if hq %} - {% if use_bootstrap5 %} + {% if use_bootstrap5 %} + {% compress js %} - {% else %} - - {% endif %} + + + + {% endcompress %} + {% else %} {% compress js %} + {% endcompress %} + {% endif %} {% endif %} diff --git a/corehq/apps/hqwebapp/templatetags/tests/rendered/javascript_libraries_hq_bootstrap5.html b/corehq/apps/hqwebapp/templatetags/tests/rendered/javascript_libraries_hq_bootstrap5.html index 27c9e69e8fb2..af54c8c15cee 100644 --- a/corehq/apps/hqwebapp/templatetags/tests/rendered/javascript_libraries_hq_bootstrap5.html +++ b/corehq/apps/hqwebapp/templatetags/tests/rendered/javascript_libraries_hq_bootstrap5.html @@ -8,7 +8,7 @@ - + @@ -27,16 +27,16 @@ - + - - + + - - + + diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/alert_user.js.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/alert_user.js.diff.txt index 564ea8a604fb..522b85780c7b 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/alert_user.js.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/alert_user.js.diff.txt @@ -1,6 +1,6 @@ --- +++ -@@ -13,7 +13,7 @@ +@@ -13,10 +13,10 @@ (success < info < warning < danger). fadeOut: Set to 'true' to have the message automatically removed from the UI after 5s. */ @@ -8,4 +8,8 @@ +hqDefine("hqwebapp/js/bootstrap5/alert_user", [ "jquery", "knockout", - "hqwebapp/js/bootstrap3/hq.helpers", +- "hqwebapp/js/bootstrap3/hq.helpers", ++ "hqwebapp/js/bootstrap5/hq.helpers", + ], + function ( + $, diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/hq-bug-report.js.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/hq-bug-report.js.diff.txt index c31613200580..1754533dd38c 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/hq-bug-report.js.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/hq-bug-report.js.diff.txt @@ -1,10 +1,185 @@ --- +++ -@@ -1,5 +1,5 @@ +@@ -1,49 +1,58 @@ -hqDefine('hqwebapp/js/bootstrap3/hq-bug-report', [ - "jquery", "jquery-form/dist/jquery.form.min", "hqwebapp/js/bootstrap3/hq.helpers", +-], function ($) { +hqDefine('hqwebapp/js/bootstrap5/hq-bug-report', [ -+ "jquery", "jquery-form/dist/jquery.form.min", "hqwebapp/js/bootstrap5/hq.helpers", - ], function ($) { ++ "jquery", ++ "hqwebapp/js/bootstrap5_loader", ++ "jquery-form/dist/jquery.form.min", ++ "hqwebapp/js/bootstrap5/hq.helpers", ++], function ($, bootstrap) { ++ 'use strict'; $(function () { - var $hqwebappBugReportModal = $('#modalReportIssue'), +- var $hqwebappBugReportModal = $('#modalReportIssue'), +- $hqwebappBugReportForm = $('#hqwebapp-bugReportForm'), +- $hqwebappBugReportSubmit = $('#bug-report-submit'), +- $hqwebappBugReportCancel = $('#bug-report-cancel'), +- $ccFormGroup = $("#bug-report-cc-form-group"), +- $emailFormGroup = $("#bug-report-email-form-group"), +- $issueSubjectFormGroup = $("#bug-report-subject-form-group"), +- isBugReportSubmitting = false; ++ let self = {}; + +- var resetForm = function () { +- $hqwebappBugReportForm.find("button[type='submit']").button('reset'); +- $hqwebappBugReportForm.resetForm(); +- $hqwebappBugReportCancel.enableButton(); +- $hqwebappBugReportSubmit.button('reset'); +- $ccFormGroup.removeClass('has-error has-feedback'); +- $ccFormGroup.find(".label-danger").addClass('hide'); +- $emailFormGroup.removeClass('has-error has-feedback'); +- $emailFormGroup.find(".label-danger").addClass('hide'); ++ self.$bugReportModalElement = $('#modalReportIssue'); ++ self.bugReportModal = new bootstrap.Modal(self.$bugReportModalElement); ++ self.$hqwebappBugReportForm = $('#hqwebapp-bugReportForm'); ++ self.$hqwebappBugReportSubmit = $('#bug-report-submit'); ++ self.$hqwebappBugReportCancel = $('#bug-report-cancel'); ++ self.$ccFormGroup = $("#bug-report-cc-form-group"); ++ self.$emailFormGroup = $("#bug-report-email-form-group"); ++ self.$issueSubjectFormGroup = $("#bug-report-subject-form-group"); ++ self.isBugReportSubmitting = false; ++ ++ self.resetForm = function () { ++ self.$hqwebappBugReportForm.find("button[type='submit']").changeButtonState('reset'); ++ self.$hqwebappBugReportForm.resetForm(); ++ self.$hqwebappBugReportCancel.enableButton(); ++ self.$hqwebappBugReportSubmit.changeButtonState('reset'); ++ self.$ccFormGroup.removeClass('has-error has-feedback'); ++ self.$ccFormGroup.find(".label-danger").addClass('hide'); ++ self.$emailFormGroup.removeClass('has-error has-feedback'); ++ self.$emailFormGroup.find(".label-danger").addClass('hide'); + }; + +- $hqwebappBugReportModal.on('shown.bs.modal', function () { ++ self.$bugReportModalElement.on('shown.bs.modal', function () { + $("input#bug-report-subject").focus(); + }); + +- $hqwebappBugReportForm.submit(function () { +- var isDescriptionEmpty = !$("#bug-report-subject").val() && !$("#bug-report-message").val(); ++ self.$hqwebappBugReportForm.submit(function (e) { ++ e.preventDefault(); ++ ++ let isDescriptionEmpty = !$("#bug-report-subject").val() && !$("#bug-report-message").val(); + if (isDescriptionEmpty) { +- highlightInvalidField($issueSubjectFormGroup); ++ self.highlightInvalidField(self.$issueSubjectFormGroup); + } + +- var emailAddress = $(this).find("input[name='email']").val(); +- if (emailAddress && !IsValidEmail(emailAddress)) { +- highlightInvalidField($emailFormGroup); ++ let emailAddress = $(this).find("input[name='email']").val(); ++ if (emailAddress && !self.isValidEmail(emailAddress)) { ++ self.highlightInvalidField(self.$emailFormGroup); + return false; + } + +- var emailAddresses = $(this).find("input[name='cc']").val(); ++ let emailAddresses = $(this).find("input[name='cc']").val(); + emailAddresses = emailAddresses.replace(/ /g, "").split(","); +- for (var index in emailAddresses) { +- var email = emailAddresses[index]; +- if (email && !IsValidEmail(email)) { +- highlightInvalidField($ccFormGroup); ++ for (let index in emailAddresses) { ++ let email = emailAddresses[index]; ++ if (email && !self.isValidEmail(email)) { ++ self.highlightInvalidField(self.$ccFormGroup); + return false; + } + } +@@ -51,57 +60,61 @@ + return false; + } + +- if (!isBugReportSubmitting && $hqwebappBugReportSubmit.text() === $hqwebappBugReportSubmit.data("success-text")) { +- $hqwebappBugReportModal.modal("hide"); +- } else if (!isBugReportSubmitting) { +- $hqwebappBugReportCancel.disableButtonNoSpinner(); +- $hqwebappBugReportSubmit.button('loading'); ++ if (!self.isBugReportSubmitting && self.$hqwebappBugReportSubmit.text() === ++ self.$hqwebappBugReportSubmit.data("success-text")) { ++ self.bugReportModal.hide(); ++ } else if (!self.isBugReportSubmitting) { ++ self.$hqwebappBugReportCancel.disableButtonNoSpinner(); ++ self.$hqwebappBugReportSubmit.changeButtonState('loading'); + $(this).ajaxSubmit({ + type: "POST", + url: $(this).attr('action'), +- beforeSerialize: hqwebappBugReportBeforeSerialize, +- beforeSubmit: hqwebappBugReportBeforeSubmit, +- success: hqwebappBugReportSucccess, +- error: hqwebappBugReportError, ++ beforeSerialize: self.hqwebappBugReportBeforeSerialize, ++ beforeSubmit: self.hqwebappBugReportBeforeSubmit, ++ success: self.hqwebappBugReportSuccess, ++ error: self.hqwebappBugReportError, + }); + } + return false; + }); + +- function IsValidEmail(email) { +- var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/; ++ self.isValidEmail = function (email) { ++ let regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/; + return regex.test(email); +- } ++ }; + +- function hqwebappBugReportBeforeSerialize($form) { ++ self.hqwebappBugReportBeforeSerialize = function ($form) { + $form.find("#bug-report-url").val(location.href); +- } ++ }; + +- function hqwebappBugReportBeforeSubmit() { +- isBugReportSubmitting = true; +- } ++ self.hqwebappBugReportBeforeSubmit = function () { ++ self.isBugReportSubmitting = true; ++ }; + +- function hqwebappBugReportSucccess() { +- isBugReportSubmitting = false; +- $hqwebappBugReportForm.find("button[type='submit']").button('success').removeClass('btn-danger').addClass('btn-primary'); +- $hqwebappBugReportModal.one('hidden.bs.modal', function () { +- resetForm(); ++ self.hqwebappBugReportSuccess = function () { ++ self.isBugReportSubmitting = false; ++ self.$bugReportModalElement.one('hidden.bs.modal', function () { ++ self.resetForm(); + }); +- } ++ self.$hqwebappBugReportForm.find("button[type='submit']") ++ .changeButtonState('success') ++ .removeClass('btn-danger').addClass('btn-primary'); ++ }; + +- function hqwebappBugReportError() { +- isBugReportSubmitting = false; +- $hqwebappBugReportForm.find("button[type='submit']").button('error').removeClass('btn-primary').addClass('btn-danger'); +- $hqwebappBugReportCancel.enableButton(); +- } ++ self.hqwebappBugReportError = function () { ++ self.isBugReportSubmitting = false; ++ self.$hqwebappBugReportForm.find("button[type='submit']").changeButtonState('error') ++ .removeClass('btn-primary').addClass('btn-danger'); ++ self.$hqwebappBugReportCancel.enableButton(); ++ }; + +- function highlightInvalidField($element) { ++ self.highlightInvalidField = function ($element) { + $element.addClass('has-error has-feedback'); + $element.find(".label-danger").removeClass('hide'); + $element.find("input").focus(function () { + $element.removeClass("has-error has-feedback"); + $element.find(".label-danger").addClass('hide'); + }); +- } ++ }; + }); + }); diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/hq.helpers.js.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/hq.helpers.js.diff.txt index 28b7decbbf5d..709ba772458e 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/hq.helpers.js.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/javascript/hqwebapp/hq.helpers.js.diff.txt @@ -6,3 +6,35 @@ 'jquery', 'knockout', 'underscore', +@@ -59,19 +59,6 @@ + return false; // let default handler run + }; + +- var oldHide = $.fn.popover.Constructor.prototype.hide; +- +- $.fn.popover.Constructor.prototype.hide = function () { +- if (this.options.trigger === "hover" && this.tip().is(":hover")) { +- var that = this; +- setTimeout(function () { +- return that.hide.apply(that, arguments); +- }, that.options.delay.hide); +- return; +- } +- oldHide.apply(this, arguments); +- }; +- + $.fn.hqHelp = function () { + var self = this; + self.each(function (i) { +@@ -101,6 +88,11 @@ + event.preventDefault(); + }); + }); ++ }; ++ ++ $.fn.changeButtonState = function (state) { ++ $(this).text($(this).data(state + '-text')); ++ return this; + }; + + $.fn.addSpinnerToButton = function () { diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/dropdowns._dropdown.style.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/dropdowns._dropdown.style.diff.txt index de9c8d33f5a6..58a1f6dc6658 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/dropdowns._dropdown.style.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/dropdowns._dropdown.style.diff.txt @@ -1,6 +1,6 @@ --- +++ -@@ -24,97 +24,69 @@ +@@ -24,97 +24,74 @@ border-color: transparent; border-style: solid; border-width: 5px 0 5px 5px; @@ -9,7 +9,7 @@ - margin-top: 3px; - color: @dropdown-link-color; - line-height: @line-height-base; -+ border-left-color: darken($dropdown-bg, 20%); ++ border-left-color: darken($body-bg, 20%); + margin-right: -5px; + margin-top: 3.3px; + color: $dropdown-link-color; @@ -96,14 +96,19 @@ + margin-top: 5px; + } + -+ .dropdown-menu .dropdown-divider { -+ margin-top: 0px; -+ margin-bottom: 0px; ++ .navbar-nav > li > a.dropdown-toggle-with-icon { ++ padding-top: 22px !important; ++ padding-bottom: 17px !important; + } + + .nav-settings-bar .dropdown-toggle-with-icon.nav-link::after { + display: none; + } ++ ++ .dropdown-toggle::after { ++ vertical-align: 2.48px; ++ margin-left: 2px; ++ } +} + +@media (max-width: map-get($grid-breakpoints, "lg")) { diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/includes_variables._variables.style.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/includes_variables._variables.style.diff.txt index 8ca48ddd6439..e5c1030bbe39 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/includes_variables._variables.style.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/includes_variables._variables.style.diff.txt @@ -1,18 +1,29 @@ --- +++ -@@ -1,119 +1,111 @@ +@@ -1,119 +1,122 @@ -@import "@{b3-import-variables}"; -+// Typography Overrides -+$font-family-sans-serif: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; -+$font-size-base: .75rem; // approx 12px ++// Grid Containers ++// we will want to adapt the defaults in a full redesign ++$container-max-widths: ( ++ sm: 540px, ++ md: 720px, ++ lg: 960px, ++ xl: 1140px, ++ xxl: 1160px ++); -// Nunito Sans is used on dimagi.com and embedded in hqwebapp/base.html -@font-family-sans-serif: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; -+// Links -+$link-decoration: none; -@font-size-base: 12px; -@icon-font-path: "../../bootstrap/fonts/"; ++// Typography Overrides ++$font-family-sans-serif: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; ++$font-size-base: .75rem; // approx 12px ++ ++// Links ++$link-decoration: none; ++ +// Form Overrides +$input-border-radius-lg: 5px; + diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/layouts._containers.style.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/layouts._containers.style.diff.txt index 955db4aff434..931797da4f89 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/layouts._containers.style.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/layouts._containers.style.diff.txt @@ -1,10 +1,12 @@ --- +++ -@@ -1,32 +1,11 @@ +@@ -1,32 +1,15 @@ -body, html { - height: 100%; --} -- ++html, body { ++ height: 100%; + } + .hq-container { min-height: 100%; height: auto !important; diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/navs._nav.style.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/navs._nav.style.diff.txt index e7d3dc762f45..befd5207acde 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/navs._nav.style.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/navs._nav.style.diff.txt @@ -36,7 +36,15 @@ } .nav-input { padding: 3px 20px; -@@ -68,7 +68,7 @@ +@@ -54,6 +54,7 @@ + .nav-main-icon { + font-size: 1.7em; + line-height: 0.7em; ++ color: $gray-light; + } + + .text-hq-nav-header { +@@ -68,7 +69,7 @@ } .nav > li > a { diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/typography._type.style.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/typography._type.style.diff.txt index 18d3c742bfa4..011dab19e956 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/typography._type.style.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/imports/typography._type.style.diff.txt @@ -28,3 +28,14 @@ } .no-border { +@@ -89,3 +90,10 @@ + a { + cursor: pointer; + } ++ ++// we should eventually get rid of this as bootstrap5+ doesn't natively support ++.page-header { ++ padding-bottom: 7.5px; ++ margin: 34px 0 17px; ++ border-bottom: 1px solid #eeeeee; ++} \ No newline at end of file diff --git a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/style-imports.commcarehq.style.diff.txt b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/style-imports.commcarehq.style.diff.txt index 6b4ac2ab3b82..a6e9e037cb48 100644 --- a/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/style-imports.commcarehq.style.diff.txt +++ b/corehq/apps/hqwebapp/tests/data/bootstrap5_diffs/stylesheets/style-imports.commcarehq.style.diff.txt @@ -1,6 +1,6 @@ --- +++ -@@ -1,43 +1,93 @@ +@@ -1,43 +1,94 @@ -@import "_hq/includes/variables.less"; -@import "_hq/includes/mixins.less"; @@ -48,6 +48,7 @@ +@import "functions"; +@import "commcarehq/variables"; // This comes before Bootstrap 5 variables to override the defaults +@import "variables"; ++@import "variables-dark"; +@import "commcarehq/variables_bootstrap3"; // Variables specific to B3-era Stylesheet +@import "maps"; +@import "mixins"; diff --git a/corehq/apps/hqwebapp/tests/utils/test_bootstrap_changes.py b/corehq/apps/hqwebapp/tests/utils/test_bootstrap_changes.py index 1eac08a7cfa5..6eb781272804 100644 --- a/corehq/apps/hqwebapp/tests/utils/test_bootstrap_changes.py +++ b/corehq/apps/hqwebapp/tests/utils/test_bootstrap_changes.py @@ -64,12 +64,16 @@ def test_flag_changed_javascript_plugins_bootstrap5(): flags = flag_changed_javascript_plugins( line, get_spec('bootstrap_3_to_5') ) - eq(flags, ['The `modal` plugin has been restructured since the removal of jQuery.\n\n' - 'There is now a new way of triggering modal events and interacting with ' - 'modals in javascript.\n\nPlease feel free to update this help text as ' - 'you find common replacements/restructuring\nfor our usage of this plugin. ' - 'Thanks!\n\nOld docs: https://getbootstrap.com/docs/3.4/javascript/#modals\n' - 'New docs: https://getbootstrap.com/docs/5.3/components/modal/#via-javascript\n']) + eq(flags, ["The `modal` plugin has been restructured since the removal of jQuery.\n\n" + "There is now a new way of triggering modal events and interacting with " + "modals in javascript.\nFor instance, if we wanted to hide a modal with " + "id `#bugReport` before, we would now do the\nfollowing...\n\npreviously" + "\n```\n$('#bugReport').modal('hide');\n```\n\nnow\n```\nconst bugReportModal" + " = new bootstrap.Modal($('#bugReport'));\nbugReportModal.hide();\n```\n\n" + "Hint: make sure to list `hqwebapp/js/bootstrap5_loader` as a js dependency " + "in the file where\nbootstrap is referenced.\n\nOld docs: " + "https://getbootstrap.com/docs/3.4/javascript/#modals\nNew docs: " + "https://getbootstrap.com/docs/5.3/components/modal/#via-javascript\n"]) def test_flag_extended_changed_javascript_plugins_bootstrap5(): diff --git a/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/js-modal.txt b/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/js-modal.txt index cec01970d492..cc70e7ef4402 100644 --- a/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/js-modal.txt +++ b/corehq/apps/hqwebapp/utils/bootstrap/changes_guide/js-modal.txt @@ -1,9 +1,22 @@ The `modal` plugin has been restructured since the removal of jQuery. There is now a new way of triggering modal events and interacting with modals in javascript. +For instance, if we wanted to hide a modal with id `#bugReport` before, we would now do the +following... -Please feel free to update this help text as you find common replacements/restructuring -for our usage of this plugin. Thanks! +previously +``` +$('#bugReport').modal('hide'); +``` + +now +``` +const bugReportModal = new bootstrap.Modal($('#bugReport')); +bugReportModal.hide(); +``` + +Hint: make sure to list `hqwebapp/js/bootstrap5_loader` as a js dependency in the file where +bootstrap is referenced. Old docs: https://getbootstrap.com/docs/3.4/javascript/#modals New docs: https://getbootstrap.com/docs/5.3/components/modal/#via-javascript diff --git a/corehq/apps/hqwebapp/views.py b/corehq/apps/hqwebapp/views.py index c7b980972f2c..b2ad3becb4b2 100644 --- a/corehq/apps/hqwebapp/views.py +++ b/corehq/apps/hqwebapp/views.py @@ -76,7 +76,7 @@ DEPLOY_IN_PROGRESS_FLAG, ) from corehq.apps.hqadmin.service_checks import CHECKS, run_checks -from corehq.apps.hqwebapp.decorators import waf_allow +from corehq.apps.hqwebapp.decorators import waf_allow, use_bootstrap5 from corehq.apps.hqwebapp.doc_info import get_doc_info from corehq.apps.hqwebapp.doc_lookup import lookup_doc_id from corehq.apps.hqwebapp.encoders import LazyEncoder @@ -89,6 +89,7 @@ from corehq.apps.hqwebapp.models import HQOauthApplication from corehq.apps.hqwebapp.login_utils import get_custom_login_page from corehq.apps.hqwebapp.utils import get_environment_friendly_name +from corehq.apps.hqwebapp.utils.bootstrap import get_bootstrap_version from corehq.apps.locations.permissions import location_safe from corehq.apps.sms.event_handlers import handle_email_messaging_subevent from corehq.apps.users.event_handlers import handle_email_invite_message @@ -841,14 +842,16 @@ def render_static(request, template, page_name): """ Takes an html file and renders it Commcare HQ's styling """ - return render(request, "hqwebapp/bootstrap3/blank.html", + return render(request, f"hqwebapp/{get_bootstrap_version()}/blank.html", {'tmpl': template, 'page_name': page_name}) +@use_bootstrap5 def apache_license(request): return render_static(request, "apache_license.html", _("Apache License")) +@use_bootstrap5 def bsd_license(request): return render_static(request, "bsd_license.html", _("BSD License")) diff --git a/package.json b/package.json index df71416248b0..1a84fdc62d12 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "bootstrap-switch": "3.3.2", "bootstrap-timepicker": "0.5.1", "bootstrap3-typeahead": "bassjobsen/Bootstrap-3-Typeahead#~3.1.1", - "bootstrap5": "npm:bootstrap@5.2.3", + "bootstrap5": "npm:bootstrap@5.3.1", "calendars": "kbwood/calendars#2.1.2", "clipboard": "1.5.15", "crypto-js": "4.0.0", diff --git a/yarn.lock b/yarn.lock index 3e17d7f9fe63..e3a38d7ece17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -806,10 +806,10 @@ bootstrap3-typeahead@bassjobsen/Bootstrap-3-Typeahead#~3.1.1: version "3.1.1" resolved "https://codeload.github.com/bassjobsen/Bootstrap-3-Typeahead/tar.gz/c65c829fe8411f6eadb88415d09c1e85bb4603d0" -"bootstrap5@npm:bootstrap@5.2.3": - version "5.2.3" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.3.tgz#54739f4414de121b9785c5da3c87b37ff008322b" - integrity sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ== +"bootstrap5@npm:bootstrap@5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.3.1.tgz#8ca07040ad15d7f75891d1504cf14c5dedfb1cfe" + integrity sha512-jzwza3Yagduci2x0rr9MeFSORjcHpt0lRZukZPZQJT1Dth5qzV7XcgGqYzi39KGAVYR8QEDVoO0ubFKOxzMG+g== bootstrap@3.4.1, bootstrap@^3.3: version "3.4.1" @@ -5725,7 +5725,7 @@ wide-align@^1.1.5: dependencies: string-width "^1.0.2 || 2 || 3 || 4" -word-wrap@^1.2.3, "word-wrap@npm:@aashutoshrathi/word-wrap@1.2.5", word-wrap@~1.2.3: +word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.5.tgz#383aeebd5c176c320d6364fb869669559bbdbac9" integrity sha512-plhoNEfSVdHMKXQyAxvH0Zyv3/4NL8r6pwgMQdmHR2vBUXn2t74PN2pBRppqKUa6RMT0yldyvOHG5Dbjwy2mBQ==