From cb2f5741accd5bf510d03233ed8457cef8a6a35c Mon Sep 17 00:00:00 2001 From: Mathijs van Veluw Date: Sat, 29 Nov 2025 22:57:57 +0100 Subject: [PATCH] Some small admin js/css updates (#6501) * Some small admin js/css updates - Updated JS libraries - Fixed some eslint errors - Small update on the theme icon's to be a bit smaller and better sized. Used OXVG via OXVGUI to shrink and optimze them. Probably Fixes #6493 Signed-off-by: BlackDex * Adjust the size of the moon to be more inline with the other icons Signed-off-by: BlackDex --------- Signed-off-by: BlackDex --- src/static/scripts/admin.js | 2 +- src/static/scripts/admin_users.js | 2 +- src/static/scripts/bootstrap.bundle.js | 7 +- src/static/scripts/bootstrap.css | 7 +- src/static/scripts/datatables.css | 19 +- src/static/scripts/datatables.js | 612 ++++++++++++++----------- src/static/templates/admin/base.hbs | 25 +- 7 files changed, 361 insertions(+), 313 deletions(-) diff --git a/src/static/scripts/admin.js b/src/static/scripts/admin.js index f3c41942..3f6bb1df 100644 --- a/src/static/scripts/admin.js +++ b/src/static/scripts/admin.js @@ -1,6 +1,6 @@ "use strict"; /* eslint-env es2017, browser */ -/* exported BASE_URL, _post */ +/* exported BASE_URL, _post _delete */ function getBaseUrl() { // If the base URL is `https://vaultwarden.example.com/base/path/admin/`, diff --git a/src/static/scripts/admin_users.js b/src/static/scripts/admin_users.js index be30e105..99e39aab 100644 --- a/src/static/scripts/admin_users.js +++ b/src/static/scripts/admin_users.js @@ -1,6 +1,6 @@ "use strict"; /* eslint-env es2017, browser, jquery */ -/* global _post:readable, BASE_URL:readable, reload:readable, jdenticon:readable */ +/* global _post:readable, _delete:readable BASE_URL:readable, reload:readable, jdenticon:readable */ function deleteUser(event) { event.preventDefault(); diff --git a/src/static/scripts/bootstrap.bundle.js b/src/static/scripts/bootstrap.bundle.js index 91eea7e7..93cbd3fe 100644 --- a/src/static/scripts/bootstrap.bundle.js +++ b/src/static/scripts/bootstrap.bundle.js @@ -1,5 +1,5 @@ /*! - * Bootstrap v5.3.7 (https://getbootstrap.com/) + * Bootstrap v5.3.8 (https://getbootstrap.com/) * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ @@ -647,7 +647,7 @@ * Constants */ - const VERSION = '5.3.7'; + const VERSION = '5.3.8'; /** * Class definition @@ -3690,9 +3690,6 @@ this._element.setAttribute('aria-expanded', 'false'); Manipulator.removeDataAttribute(this._menu, 'popper'); EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget); - - // Explicitly return focus to the trigger element - this._element.focus(); } _getConfig(config) { config = super._getConfig(config); diff --git a/src/static/scripts/bootstrap.css b/src/static/scripts/bootstrap.css index e9479ad9..b83f5079 100644 --- a/src/static/scripts/bootstrap.css +++ b/src/static/scripts/bootstrap.css @@ -1,6 +1,6 @@ @charset "UTF-8"; /*! - * Bootstrap v5.3.7 (https://getbootstrap.com/) + * Bootstrap v5.3.8 (https://getbootstrap.com/) * Copyright 2011-2025 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ @@ -547,6 +547,10 @@ legend + * { -webkit-appearance: textfield; outline-offset: -2px; } +[type=search]::-webkit-search-cancel-button { + cursor: pointer; + filter: grayscale(1); +} /* rtl:raw: [type="tel"], @@ -6208,6 +6212,7 @@ textarea.form-control-lg { .spinner-grow, .spinner-border { display: inline-block; + flex-shrink: 0; width: var(--bs-spinner-width); height: var(--bs-spinner-height); vertical-align: var(--bs-spinner-vertical-align); diff --git a/src/static/scripts/datatables.css b/src/static/scripts/datatables.css index 4d927abf..af6a9b1e 100644 --- a/src/static/scripts/datatables.css +++ b/src/static/scripts/datatables.css @@ -4,20 +4,21 @@ * * To rebuild or modify this file with the latest versions of the included * software please visit: - * https://datatables.net/download/#bs5/dt-2.3.2 + * https://datatables.net/download/#bs5/dt-2.3.5 * * Included libraries: - * DataTables 2.3.2 + * DataTables 2.3.5 */ :root { --dt-row-selected: 13, 110, 253; --dt-row-selected-text: 255, 255, 255; - --dt-row-selected-link: 9, 10, 11; + --dt-row-selected-link: 228, 228, 228; --dt-row-stripe: 0, 0, 0; --dt-row-hover: 0, 0, 0; --dt-column-ordering: 0, 0, 0; --dt-header-align-items: center; + --dt-header-vertical-align: middle; --dt-html-background: white; } :root.dark { @@ -112,7 +113,7 @@ table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order, table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order { position: relative; width: 12px; - height: 20px; + height: 24px; } table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after, table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:before, @@ -144,7 +145,8 @@ table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after { opacity: 0.6; } -table.dataTable thead > tr > th.sorting_desc_disabled span.dt-column-order:after, table.dataTable thead > tr > th.sorting_asc_disabled span.dt-column-order:before, +table.dataTable thead > tr > th.dt-orderable-none:not(.dt-ordering-asc, .dt-ordering-desc) span.dt-column-order:empty, table.dataTable thead > tr > th.sorting_desc_disabled span.dt-column-order:after, table.dataTable thead > tr > th.sorting_asc_disabled span.dt-column-order:before, +table.dataTable thead > tr > td.dt-orderable-none:not(.dt-ordering-asc, .dt-ordering-desc) span.dt-column-order:empty, table.dataTable thead > tr > td.sorting_desc_disabled span.dt-column-order:after, table.dataTable thead > tr > td.sorting_asc_disabled span.dt-column-order:before { display: none; @@ -340,6 +342,7 @@ table.dataTable thead td, table.dataTable tfoot th, table.dataTable tfoot td { text-align: left; + vertical-align: var(--dt-header-vertical-align); } table.dataTable thead th.dt-head-left, table.dataTable thead td.dt-head-left, @@ -422,10 +425,6 @@ table.dataTable tbody td.dt-body-nowrap { white-space: nowrap; } -:root { - --dt-header-align-items: flex-end; -} - /*! Bootstrap 5 integration for DataTables * * ©2020 SpryMedia Ltd, all rights reserved. @@ -453,7 +452,7 @@ table.table.dataTable > tbody > tr.selected > * { color: rgb(var(--dt-row-selected-text)); } table.table.dataTable > tbody > tr.selected a { - color: rgb(9, 10, 11); + color: rgb(228, 228, 228); color: rgb(var(--dt-row-selected-link)); } table.table.dataTable.table-striped > tbody > tr:nth-of-type(2n+1) > * { diff --git a/src/static/scripts/datatables.js b/src/static/scripts/datatables.js index 0ba22347..961af0b4 100644 --- a/src/static/scripts/datatables.js +++ b/src/static/scripts/datatables.js @@ -4,13 +4,13 @@ * * To rebuild or modify this file with the latest versions of the included * software please visit: - * https://datatables.net/download/#bs5/dt-2.3.2 + * https://datatables.net/download/#bs5/dt-2.3.5 * * Included libraries: - * DataTables 2.3.2 + * DataTables 2.3.5 */ -/*! DataTables 2.3.2 +/*! DataTables 2.3.5 * © SpryMedia Ltd - datatables.net/license */ @@ -178,6 +178,9 @@ this.id = sId; } + // Replacing an existing colgroup with our own. Not ideal, but a merge could take a lot of code + $this.children('colgroup').remove(); + /* Create the settings object for this table and set some of the default parameters */ var oSettings = $.extend( true, {}, DataTable.models.oSettings, { "sDestroyWidth": $this[0].style.width, @@ -513,7 +516,7 @@ * * @type string */ - builder: "bs5/dt-2.3.2", + builder: "bs5/dt-2.3.5", /** * Buttons. For use with the Buttons extension for DataTables. This is @@ -743,7 +746,7 @@ * * The extension options for ordering of data available here is complimentary * to the default type based ordering that DataTables typically uses. It - * allows much greater control over the the data that is being used to + * allows much greater control over the data that is being used to * order a column, but is necessarily therefore more complex. * * This type of ordering is useful if you want to do ordering based on data @@ -902,7 +905,7 @@ * `{type}-asc` and `{type}-desc` together. It is generally recommended * that only `{type}-pre` is used, as this provides the optimal * implementation in terms of speed, although the others are provided - * for compatibility with existing Javascript sort functions. + * for compatibility with existing JavaScript sort functions. * * `{type}-pre`: Functions defined take a single parameter: * @@ -912,7 +915,7 @@ * * * `{*}` Data to be sorted upon * - * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort + * `{type}-asc` and `{type}-desc`: Functions are typical JavaScript sort * functions, taking two parameters: * * 1. `{*}` Data to compare to the second parameter @@ -1136,7 +1139,7 @@ }; // Convert from a formatted number with characters other than `.` as the - // decimal place, to a Javascript number + // decimal place, to a JavaScript number var _numToDecimal = function ( num, decimalPoint ) { // Cache created regular expressions for speed as this function is called often if ( ! _re_dic[ decimalPoint ] ) { @@ -1202,19 +1205,19 @@ var _pluck = function ( a, prop, prop2 ) { var out = []; - var i=0, ien=a.length; + var i=0, iLen=a.length; // Could have the test in the loop for slightly smaller code, but speed // is essential here if ( prop2 !== undefined ) { - for ( ; i') .html( columns[i][titleProp] || '' ) .appendTo( row ); @@ -3492,6 +3495,14 @@ { var iDataIndex = aiDisplay[j]; var aoData = oSettings.aoData[ iDataIndex ]; + + // Row has been deleted - can't be displayed + if (aoData === null) + { + continue; + } + + // Row node hasn't been created yet if ( aoData.nTr === null ) { _fnCreateTr( oSettings, iDataIndex ); @@ -3620,7 +3631,7 @@ return $( '' ) .append( $('', { - 'colSpan': _fnVisbleColumns( settings ), + 'colSpan': _fnVisibleColumns( settings ), 'class': settings.oClasses.empty.row } ).html( zero ) )[0]; } @@ -3804,7 +3815,7 @@ var line = row[ item ].contents; - for ( var i=0, ien=line.length ; i divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; var paddingSide = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); @@ -5437,7 +5428,7 @@ visibleColumns = _fnGetColumns( settings, 'bVisible' ), tableWidthAttr = table.getAttribute('width'), // from DOM element tableContainer = table.parentNode, - i, column, columnIdx; + i, j, column, columnIdx; var styleWidth = table.style.width; var containerWidth = _fnWrapperWidth(settings); @@ -5471,17 +5462,16 @@ false ); - // Construct a single row, worst case, table with the widest - // node in the data, assign any user defined widths, then insert it into - // the DOM and allow the browser to do all the hard work of calculating - // table widths + // Construct a worst case table with the widest, assign any user defined + // widths, then insert it into the DOM and allow the browser to do all + // the hard work of calculating table widths var tmpTable = $(table.cloneNode()) .css( 'visibility', 'hidden' ) + .css( 'margin', 0 ) .removeAttr( 'id' ); // Clean up the table body - tmpTable.append('') - var tr = $('').appendTo( tmpTable.find('tbody') ); + tmpTable.append('') // Clone the table header and footer - we can't use the header / footer // from the cloned table, since if scrolling is active, the table's @@ -5521,23 +5511,37 @@ } } ); - // Find the widest piece of data for each column and put it into the table - for ( i=0 ; i') - .addClass(autoClass) - .addClass(column.sClass) - .append(insert) - .appendTo(tr); + for ( i=0 ; i').appendTo( tmpTable.find('tbody') ); + + for ( j=0 ; j') + .addClass(autoClass) + .addClass(column.sClass) + .append(insert) + .appendTo(tr); + } + } } // Tidy the temporary table - remove name attributes so there aren't @@ -5676,20 +5680,32 @@ } /** - * Get the maximum strlen for each data column + * Get the widest strings for each column. + * + * It is very difficult to determine what the widest string actually is due to variable character + * width and kerning. Doing an exact calculation with the DOM or even Canvas would kill performance + * and this is a critical point, so we use two techniques to determine a collection of the longest + * strings from the column, which will likely contain the widest strings: + * + * 1) Get the top three longest strings from the column + * 2) Get the top three widest words (i.e. an unbreakable phrase) + * * @param {object} settings dataTables settings object * @param {int} colIdx column of interest - * @returns {string} string of the max length + * @returns {string[]} Array of the longest strings * @memberof DataTable#oApi */ - function _fnGetMaxLenString( settings, colIdx ) + function _fnGetWideStrings( settings, colIdx ) { var column = settings.aoColumns[colIdx]; - if (! column.maxLenString) { - var s, max='', maxLen = -1; - - for ( var i=0, ien=settings.aiDisplayMaster.length ; i maxLen ) { - // We want the HTML in the string, but the length that - // is important is the stripped string - max = cellString; - maxLen = s.length; - } + collection.push({ + str: s, + len: s.length + }); + + allStrings.push(s); } - column.maxLenString = max; + // Order and then cut down to the size we need + collection + .sort(function (a, b) { + return b.len - a.len; + }) + .splice(3); + + column.wideStrings = collection.map(function (item) { + return item.str; + }); + + // Longest unbroken string + let parts = allStrings.join(' ').split(' '); + + parts.sort(function (a, b) { + return b.length - a.length; + }); + + if (parts.length) { + column.wideStrings.push(parts[0]); + } + + if (parts.length > 1) { + column.wideStrings.push(parts[1]); + } + + if (parts.length > 2) { + column.wideStrings.push(parts[3]); + } } - return column.maxLenString; + return column.wideStrings; } @@ -5811,7 +5855,7 @@ : [column]; if ( columns.length ) { - for ( var i=0, ien=columns.length ; i - + - - - - - - - - - - + + + - - + + - - + +