Squashed commit

Make it possible to actively not-check a mandatory checkbox Userfield (closes #2601)
Pluralize the "opened" localization string (closes #2280)
Added a trendline to the price history chart (closes #2237)
Various minor style/code refinements
This commit is contained in:
Bernd Bestel 2025-01-14 17:54:06 +01:00
parent c99dd46007
commit 11d28622e8
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
32 changed files with 134 additions and 86 deletions

View File

@ -67,7 +67,7 @@
### Userfield improvements/fixes
- New Userfield type "Select list" for a list of predefined values where a single or also multiple values can then be selected on the entity object
- New Userfield type "Link" - a single-line-textbox where the content will be rendered as a clickable link
- Userfields of type "checkbox" are rendered as a checkmark in tables when checked (instead of "1" as till now)
- Userfields of type "Checkbox" are rendered as a checkmark in tables when checked (instead of "1" as till now)
- Product Userfields are now also rendered on the shopping list (for items which have a product referenced)
- Fixed that the Userfield type "Preset list" had always the caption "Product group" instead of the configured one (thanks @oncleben31)

View File

@ -32,6 +32,7 @@
### Recipes
- Optimized that when adding missing recipe ingredients with the option "Only check if any amount is in stock" enabled to the shopping list and when no corresponding unit conversion exists, the amount/unit is now taken "as is" (as defined in the recipe ingredient) into the created shopping list item
- Added a trendline to the price history chart (product card)
- Fixed that calories/costs of recipe ingredients were wrong when the ingredient option "Only check if any amount is in stock" was set and the on the ingredient used quantity unit was different from the product's QU stock
- Fixed that multi-nested recipes (at least 3 levels of "included recipes") resulted in wrong amounts/costs/calories calculated for the ingredients orginating in those nested recipes (also affected the meal plan)
@ -61,6 +62,8 @@
### Userfields
- Optimized Userfields of type "Checkbox"
- When it's a mandatory Userfield, the initial state of the corresponding checkbox is now indeterminate, means it's now also possible to actively not check it (previously mandatory meant the checkbox has to be set)
- Fixed that Userfield default values were not initialized for the `stock` entity (so affecting the purchase and inventory page)
- Fixed that uploading bigger or multiple files (so when the upload usually takes a little longer) didn't work (Userfield type "File")

View File

@ -221,11 +221,12 @@ DefaultUserSetting('calendar_color_chores', '#ffc107'); // The event color (hex
DefaultUserSetting('calendar_color_batteries', '#17a2b8'); // The event color (hex code) for due battery charge cycles
DefaultUserSetting('calendar_color_meal_plan', '#6c757d'); // The event color (hex code) for meal plan items
// Component configuration for Quagga2 - read https://github.com/ericblade/quagga2#configobject for details
// Component configuration for Quagga2
// See https://github.com/ericblade/quagga2#configobject for details
// Below is a generic good configuration,
// for an iPhone 7 Plus, halfsample = true, patchsize = small, frequency = 5 yields very good results
// For an iPhone 7 Plus, halfsample = true, patchsize = small, frequency = 5 yields very good results
DefaultUserSetting('quagga2_numofworkers', 4);
DefaultUserSetting('quagga2_halfsample', false);
DefaultUserSetting('quagga2_patchsize', 'medium');
DefaultUserSetting('quagga2_frequency', 10);
DefaultUserSetting('quagga2_debug', true);
DefaultUserSetting('quagga2_debug', false);

View File

@ -836,7 +836,9 @@ msgid "Not opened"
msgstr ""
msgid "Opened"
msgstr ""
msgid_plural "Opened"
msgstr[0] ""
msgstr[1] ""
msgid "%s opened"
msgstr ""

View File

@ -15,6 +15,7 @@
"chartjs-plugin-colorschemes": "^0.4.0",
"chartjs-plugin-doughnutlabel": "^2.0.3",
"chartjs-plugin-piechart-outlabels": "^0.1.4",
"chartjs-plugin-trendline": "^2.1.6",
"datatables.net": "^1.10.22",
"datatables.net-bs4": "^1.10.22",
"datatables.net-colreorder": "^1.5.2",

View File

@ -209,21 +209,16 @@ a:not([href]) {
white-space: pre-wrap;
}
/* Barcodescanner Quagga2 */
#barcodescanner-container {
max-height: 90vw;
/* Camera Barcodescanner Quagga2 */
#camerabarcodescanner-container {
max-height: 90vh;
}
#livestream-container {
max-height: 100%;
}
#barcodescanner-livestream video {
#camerabarcodescanner-livestream video {
width: 100%;
}
#barcodescanner-livestream canvas {
#camerabarcodescanner-livestream canvas {
width: 100%;
}
@ -304,6 +299,14 @@ a:not([href]) {
overflow-y: auto;
}
.btn.dropdown-toggle:after {
vertical-align: 0;
margin: 0;
border: none;
content: '\f107';
font-family: 'Font Awesome 6 Free';
}
/* Third party component customizations - DataTables */
.dataTable td {
vertical-align: middle !important;
@ -362,14 +365,6 @@ html {
min-height: inherit;
}
.dropdown-toggle:after {
vertical-align: 0;
margin: 0;
border: none;
content: '\f107';
font-family: 'Font Awesome 6 Free';
}
/* Third party component customizations - Tempus Dominus */
.bootstrap-datetimepicker-widget.dropdown-menu {
width: auto !important;

View File

@ -874,3 +874,9 @@ $(document).on("click", "#clear-filter-button", function(e)
{
$(".tooltip").tooltip("hide");
});
$(document).on("click", '.btn, a, button', function(e)
{
// Remove focus after click
document.activeElement.blur();
});

View File

@ -20,21 +20,21 @@ $("#expected_barcode").on("keyup", function(e)
if ($("#expected_barcode").val().length > 1)
{
$("#scanned_barcode").removeAttr("disabled");
$("#barcodescanner-start-button").removeAttr("disabled");
$("#barcodescanner-start-button").removeClass("disabled");
$("#camerabarcodescanner-start-button").removeAttr("disabled");
$("#camerabarcodescanner-start-button").removeClass("disabled");
}
else
{
$("#scanned_barcode").attr("disabled", "");
$("#barcodescanner-start-button").attr("disabled", "");
$("#barcodescanner-start-button").addClass("disabled");
$("#camerabarcodescanner-start-button").attr("disabled", "");
$("#camerabarcodescanner-start-button").addClass("disabled");
}
});
setTimeout(function()
{
$("#barcodescanner-start-button").attr("disabled", "");
$("#barcodescanner-start-button").addClass("disabled");
$("#camerabarcodescanner-start-button").attr("disabled", "");
$("#camerabarcodescanner-start-button").addClass("disabled");
$("#expected_barcode").focus();
}, 500);

View File

@ -117,7 +117,6 @@ $(document).on('click', '.track-charge-cycle-button', function(e)
$(document).on('click', '.battery-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var batteryId = $(e.currentTarget).attr('data-battery-id');
Grocy.Api.Get('batteries/' + batteryId + '/printlabel', function(labelData)

View File

@ -91,7 +91,6 @@ $('#battery-form input').keydown(function(event)
$(document).on('click', '.battery-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var batteryId = $(e.currentTarget).attr('data-battery-id');
Grocy.Api.Get('batteries/' + batteryId + '/printlabel', function(labelData)

View File

@ -271,7 +271,6 @@ Grocy.Components.ProductPicker.GetPicker().on('change', function(e)
$(document).on('click', '.chore-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var choreId = $(e.currentTarget).attr('data-chore-id');
Grocy.Api.Get('chores/' + choreId + '/printlabel', function(labelData)

View File

@ -213,7 +213,6 @@ $(document).on('click', '.track-chore-button', function(e)
$(document).on('click', '.chore-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var choreId = $(e.currentTarget).attr('data-chore-id');
Grocy.Api.Get('chores/' + choreId + '/printlabel', function(labelData)

View File

@ -37,30 +37,29 @@ Grocy.Components.CameraBarcodeScanner.CheckCapabilities = async function()
var hasTorch = typeof capabilities.torch === 'boolean' && capabilities.torch;
// Remove the torch button if the select camera doesn't have a torch
var button = document.querySelector('.torch');
if (!hasTorch)
{
button.classList.add('disabled');
document.querySelector('.camerabarcodescanner-modal .modal-footer').setAttribute('style', 'display:none !important;');
}
else
{
button.classList.remove('disabled');
document.querySelector('.camerabarcodescanner-modal .modal-footer').setAttribute('style', 'flex;');
}
// Reduce the height of the video, if it's higher than then the viewport
if (!Grocy.Components.CameraBarcodeScanner.LiveVideoSizeAdjusted)
{
var bc = document.getElementById('barcodescanner-container');
var bc = document.getElementById('camerabarcodescanner-container');
if (bc)
{
var bcAspectRatio = bc.offsetWidth / bc.offsetHeight;
var settings = track.getSettings();
if (bcAspectRatio > settings.aspectRatio)
{
var v = document.querySelector('#barcodescanner-livestream video');
var v = document.querySelector('#camerabarcodescanner-livestream video');
if (v)
{
var c = document.querySelector('#barcodescanner-livestream canvas')
var c = document.querySelector('#camerabarcodescanner-livestream canvas')
var newWidth = v.clientWidth / bcAspectRatio * settings.aspectRatio + 'px';
v.style.width = newWidth;
c.style.width = newWidth;
@ -81,7 +80,7 @@ Grocy.Components.CameraBarcodeScanner.StartScanning = function()
inputStream: {
name: "Live",
type: "LiveStream",
target: document.querySelector("#barcodescanner-livestream"),
target: document.querySelector("#camerabarcodescanner-livestream"),
constraints: {
facingMode: "environment",
...(window.localStorage.getItem('cameraId') && { deviceId: window.localStorage.getItem('cameraId') }), // If preferred cameraId is set, request to use that specific camera
@ -234,7 +233,7 @@ Quagga.onProcessed(function(result)
}
});
$(document).on("click", "#barcodescanner-start-button", async function(e)
$(document).on("click", "#camerabarcodescanner-start-button", async function(e)
{
e.preventDefault();
var inputElement = $(e.currentTarget).prev();
@ -248,12 +247,12 @@ $(document).on("click", "#barcodescanner-start-button", async function(e)
Grocy.Components.CameraBarcodeScanner.CurrentTarget = inputElement.attr("data-target");
var dialog = bootbox.dialog({
message: '<div id="barcodescanner-container" class="col"><div id="barcodescanner-livestream"></div></div>',
message: '<div id="camerabarcodescanner-container" class="col"><div id="camerabarcodescanner-livestream"></div></div>',
title: __t('Scan a barcode'),
size: 'large',
backdrop: true,
closeButton: true,
className: "form",
className: "form camerabarcodescanner-modal",
buttons: {
torch: {
label: '<i class="fa-solid fa-lightbulb"></i>',
@ -296,11 +295,11 @@ Grocy.Components.CameraBarcodeScanner.Init = function()
{
if ($(this).hasAttr("disabled"))
{
$(this).after('<a id="barcodescanner-start-button" class="btn btn-sm btn-primary text-white disabled" data-target="' + $(this).attr("data-target") + '"><i class="fa-solid fa-camera"></i></a>');
$(this).after('<a id="camerabarcodescanner-start-button" class="btn btn-sm btn-primary text-white disabled" data-target="' + $(this).attr("data-target") + '"><i class="fa-solid fa-camera"></i></a>');
}
else
{
$(this).after('<a id="barcodescanner-start-button" class="btn btn-sm btn-primary text-white" data-target="' + $(this).attr("data-target") + '"><i class="fa-solid fa-camera"></i></a>');
$(this).after('<a id="camerabarcodescanner-start-button" class="btn btn-sm btn-primary text-white" data-target="' + $(this).attr("data-target") + '"><i class="fa-solid fa-camera"></i></a>');
}
Grocy.Components.CameraBarcodeScanner.InitDone = true;

View File

@ -136,7 +136,10 @@ Grocy.Components.ProductCard.Refresh = function(productId)
$("#productcard-no-price-data-hint").addClass("d-none");
Grocy.Components.ProductCard.ReInitPriceHistoryChart();
var datasets = {};
datasets["_TrendlineDataset"] = []
var chart = Grocy.Components.ProductCard.PriceHistoryChart.data;
priceHistoryDataPoints.forEach((dataPoint) =>
{
@ -150,18 +153,41 @@ Grocy.Components.ProductCard.Refresh = function(productId)
{
datasets[key] = []
}
chart.labels.push(moment(dataPoint.date).toDate());
datasets[key].push({ x: moment(dataPoint.date).toDate(), y: dataPoint.price * productDetails.qu_conversion_factor_price_to_stock });
datasets["_TrendlineDataset"].push({ x: moment(dataPoint.date).toDate(), y: dataPoint.price * productDetails.qu_conversion_factor_price_to_stock });
});
Object.keys(datasets).forEach((key) =>
{
chart.datasets.push({
data: datasets[key],
fill: false,
borderColor: "HSL(" + (129 * chart.datasets.length) + ",100%,50%)",
label: key,
});
if (key != "_TrendlineDataset")
{
chart.datasets.push({
data: datasets[key],
fill: false,
borderColor: "HSL(" + (129 * chart.datasets.length) + ",100%,50%)",
label: key
});
}
else
{
chart.datasets.push({
data: datasets[key],
fill: false,
borderColor: "HSL(" + (129 * chart.datasets.length) + ",100%,50%)",
label: key,
hidden: true,
alwaysShowTrendline: true,
trendlineLinear: {
colorMin: "rgba(0, 0, 0, 0.3)",
colorMax: "rgba(0, 0, 0, 0.3)",
lineStyle: "dotted",
width: 3
}
});
}
});
Grocy.Components.ProductCard.PriceHistoryChart.update();
@ -234,7 +260,13 @@ Grocy.Components.ProductCard.ReInitPriceHistoryChart = function()
}]
},
legend: {
display: true
display: true,
labels: {
filter: function(item, chart)
{
return item.text != "_TrendlineDataset";
}
}
},
tooltips: {
callbacks: {

View File

@ -76,15 +76,15 @@ Grocy.Components.ProductPicker.HideCustomError = function()
Grocy.Components.ProductPicker.Disable = function()
{
Grocy.Components.ProductPicker.GetInputElement().attr("disabled", "");
$("#barcodescanner-start-button").attr("disabled", "");
$("#barcodescanner-start-button").addClass("disabled");
$("#camerabarcodescanner-start-button").attr("disabled", "");
$("#camerabarcodescanner-start-button").addClass("disabled");
}
Grocy.Components.ProductPicker.Enable = function()
{
Grocy.Components.ProductPicker.GetInputElement().removeAttr("disabled");
$("#barcodescanner-start-button").removeAttr("disabled");
$("#barcodescanner-start-button").removeClass("disabled");
$("#camerabarcodescanner-start-button").removeAttr("disabled");
$("#camerabarcodescanner-start-button").removeClass("disabled");
}
$('.product-combobox').combobox({
@ -295,7 +295,7 @@ $('#product_id_text_input').on('blur', function(e)
{
Grocy.Components.ProductPicker.PopupOpen = false;
Grocy.Components.ProductPicker.SetValue('');
$("#barcodescanner-start-button").click();
$("#camerabarcodescanner-start-button").click();
}
};
}

View File

@ -182,11 +182,19 @@ Grocy.Components.UserfieldsForm.Load = function()
if (userfield.type == "datetime" && userfield.default_value == "now")
{
input.val(moment().format("YYYY-MM-DD HH:mm:ss"))
input.val(moment().format("YYYY-MM-DD HH:mm:ss"));
}
else if (userfield.type == "date" && userfield.default_value == "now")
{
input.val(moment().format("YYYY-MM-DD"))
input.val(moment().format("YYYY-MM-DD"));
}
else if (userfield.type == "checkbox" && userfield.input_required == 1)
{
input.prop("indeterminate", true);
input.on("change", function()
{
input.removeAttr("required");
});
}
});
@ -212,6 +220,12 @@ Grocy.Components.UserfieldsForm.Load = function()
{
var input = $(".userfield-input[data-userfield-name='" + key + "']");
if (input.attr("type") == "checkbox")
{
// The required attribute for checkboxes is only relevant when creating objects
input.removeAttr("required");
}
if (input.attr("type") == "checkbox" && value == 1)
{
input.prop("checked", true);

View File

@ -287,7 +287,7 @@ function OnLocationChange(locationId, stockId)
var openTxt = __t("Not opened");
if (stockEntry.open == 1)
{
openTxt = __t("Opened");
openTxt = __n(stockEntry.amount, "Opened", "Opened");
}
if (stockEntry.location_id == locationId)
@ -672,7 +672,6 @@ $(document).on("change", "#scan-mode", function(e)
$("#scan-mode-button").on("click", function(e)
{
document.activeElement.blur();
$("#scan-mode").click();
$("#scan-mode-button").toggleClass("btn-success").toggleClass("btn-danger");
if ($("#scan-mode").prop("checked"))

View File

@ -267,7 +267,6 @@ setTimeout(function()
$(document).on('click', '.product-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var productId = $(e.currentTarget).attr('data-product-id');
Grocy.Api.Get('stock/products/' + productId + '/printlabel', function(labelData)

View File

@ -689,7 +689,6 @@ $("#scan-mode").on("change", function(e)
$("#scan-mode-button").on("click", function(e)
{
document.activeElement.blur();
$("#scan-mode").click();
$("#scan-mode-button").toggleClass("btn-success").toggleClass("btn-danger");
if ($("#scan-mode").prop("checked"))

View File

@ -379,7 +379,6 @@ $(window).on("message", function(e)
$(document).on('click', '.recipe-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var recipeId = $(e.currentTarget).attr('data-recipe-id');
Grocy.Api.Get('recipes/' + recipeId + '/printlabel', function(labelData)

View File

@ -429,7 +429,6 @@ if (window.location.hash === "#fullscreen")
$(document).on('click', '.recipe-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var recipeId = $(e.currentTarget).attr('data-recipe-id');
Grocy.Api.Get('recipes/' + recipeId + '/printlabel', function(labelData)

View File

@ -559,7 +559,6 @@ $("#description").on("summernote.change", function()
$(document).on("click", "#save-description-button", function(e)
{
e.preventDefault();
document.activeElement.blur();
Grocy.Api.Put('objects/shopping_lists/' + $("#selected-shopping-list").val(), { description: $("#description").val() },
function(result)
@ -576,7 +575,6 @@ $(document).on("click", "#save-description-button", function(e)
$(document).on("click", "#clear-description-button", function(e)
{
e.preventDefault();
document.activeElement.blur();
$("#description").summernote("reset");
$("#save-description-button").click();

View File

@ -161,7 +161,6 @@ $(document).on('click', '.product-open-button', function(e)
$(document).on('click', '.stockentry-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var stockId = $(e.currentTarget).attr('data-stock-id');
Grocy.Api.Get('stock/entry/' + stockId + '/printlabel', function(labelData)
@ -288,7 +287,7 @@ function RefreshStockEntryRow(stockRowId)
if (result.open == 1)
{
$('#stock-' + stockRowId + '-opened-amount').text(__t('Opened'));
$('#stock-' + stockRowId + '-opened-amount').text(__n(result.amount, 'Opened', 'Opened'));
}
else
{

View File

@ -137,7 +137,6 @@ $(document).on('click', '.undo-stock-booking-button', function(e)
$(document).on('click', '.product-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var productId = $(e.currentTarget).attr('data-product-id');
Grocy.Api.Get('stock/products/' + productId + '/printlabel', function(labelData)

View File

@ -113,7 +113,6 @@ $("#search").on("keyup", Delay(function()
$(document).on('click', '.product-grocycode-label-print', function(e)
{
e.preventDefault();
document.activeElement.blur();
var productId = $(e.currentTarget).attr('data-product-id');
Grocy.Api.Get('stock/products/' + productId + '/printlabel', function(labelData)

View File

@ -340,7 +340,7 @@ $("#location_id_from").on('change', function(e)
var openTxt = __t("Not opened");
if (stockEntry.open == 1)
{
openTxt = __t("Opened");
openTxt = __n(stockEntry.amount, "Opened", "Opened");
}
if (stockEntry.location_id == locationId)

View File

@ -10,7 +10,7 @@
@push('pageStyles')
<style>
#barcodescanner-start-button {
#camerabarcodescanner-start-button {
position: absolute;
right: 0;
margin-top: 4px;
@ -18,8 +18,8 @@
cursor: pointer;
}
.combobox-container #barcodescanner-start-button {
margin-right: 36px !important;
.combobox-container #camerabarcodescanner-start-button {
margin-right: 38px !important;
}
</style>
@endpush

View File

@ -747,6 +747,7 @@
<script src="{{ $U('/packages/chartjs-plugin-colorschemes/dist/chartjs-plugin-colorschemes.min.js?v=', true) }}{{ $version}}"></script>
<script src="{{ $U('/packages/chartjs-plugin-doughnutlabel/dist/chartjs-plugin-doughnutlabel.js?v=', true) }}{{ $version }}"></script>
<script src="{{ $U('/packages/chartjs-plugin-piechart-outlabels/dist/chartjs-plugin-piechart-outlabels.min.js?v=', true) }}{{ $version}}"></script>
<script src="{{ $U('/packages/chartjs-plugin-trendline/dist/chartjs-plugin-trendline.min.js?v=', true) }}{{ $version}}"></script>
@endif
<script src="{{ $U('/js/extensions.js?v=', true) }}{{ $version }}"></script>

View File

@ -249,8 +249,11 @@
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $listItem->qu_id);
if ($productQuConversion)
{
if (is_numeric($listItem->amount) && is_numeric($productQuConversion->factor)) // However people manage to have a non-number here, happened at least a trilion times for Grocy Mobile (iOS) users
{
$listItem->amount = $listItem->amount * $productQuConversion->factor;
}
}
@endphp
@endif
<td>

View File

@ -259,7 +259,7 @@
<span id="stock-{{ $stockEntry->id }}-amount"
class="locale-number locale-number-quantity-amount">{{ $stockEntry->amount }}</span> <span id="product-{{ $stockEntry->product_id }}-qu-name">{{ $__n($stockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name_plural, true) }}</span>
<span id="stock-{{ $stockEntry->id }}-opened-amount"
class="small font-italic">@if($stockEntry->open == 1){{ $__t('Opened') }}@endif</span>
class="small font-italic">@if($stockEntry->open == 1){{ $__n($stockEntry->amount, 'Opened', 'Opened') }}@endif</span>
</td>
<td class="@if(!GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) d-none @endif">
<span id="stock-{{ $stockEntry->id }}-due-date">{{ $stockEntry->best_before_date }}</span>

View File

@ -137,7 +137,7 @@
<div class="custom-control custom-checkbox">
<input @if($stockEntry->open == 1) checked @endif class="form-check-input custom-control-input" type="checkbox" id="open" name="open" value="1">
<label class="form-check-label custom-control-label"
for="open">{{ $__t('Opened') }}</label>
for="open">{{ $__n(1, 'Opened', 'Opened') }}</label>
</div>
</div>
@endif

View File

@ -167,6 +167,11 @@ chartjs-plugin-piechart-outlabels@^0.1.4:
resolved "https://registry.yarnpkg.com/chartjs-plugin-piechart-outlabels/-/chartjs-plugin-piechart-outlabels-0.1.4.tgz#e97e19a12202d74f9040d9e4641987c9d1e458fc"
integrity sha512-IaYkh6ab8nLAvgioQ+BwU0awfMbxwmfO2AeBL+S45VVx9AdObovr9+aE+ShUO2Og96y6eJpCxZGJr4zXB7YnRw==
chartjs-plugin-trendline@^2.1.6:
version "2.1.6"
resolved "https://registry.yarnpkg.com/chartjs-plugin-trendline/-/chartjs-plugin-trendline-2.1.6.tgz#5090155cae06681c9888a63305991d868cff3596"
integrity sha512-73lpSv87RcIeu0so4ndEE48Xf08Q4scz079tSgYdfeGuIce4JKcSE64oluhz/j6NpBr50Z7PPwolGJ0cLtknRw==
color-convert@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@ -229,11 +234,11 @@ datatables.net-bs4@^1.10.22, datatables.net-bs4@^1.13.0:
jquery "1.8 - 4"
datatables.net-bs4@^2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/datatables.net-bs4/-/datatables.net-bs4-2.2.0.tgz#bf35a667b05a3ee5dc4626d07c92a57d0dfc2090"
integrity sha512-dTgsblxSftIkLuyUItcQwbRfunAhFygxwpXxLCfKmE3xA8QBkl8KREAx9OQuVxJUMc5Ao+LCknd5kT+kzEqREg==
version "2.2.1"
resolved "https://registry.yarnpkg.com/datatables.net-bs4/-/datatables.net-bs4-2.2.1.tgz#07e9da60d88c6e872ffdbb63c5d96a164e8e11aa"
integrity sha512-YJpbGGTqrOhS6p8BolGv16mdmljaq4ewhc0dbm3yd02UQ86A2cWQ2tDq6lE966tvRD43JE0PPAc5wLgsRozReg==
dependencies:
datatables.net "2.2.0"
datatables.net "2.2.1"
jquery ">=1.7"
datatables.net-colreorder-bs4@^1.5.2:
@ -302,10 +307,10 @@ datatables.net@1.13.11, datatables.net@^1.10.22, datatables.net@^1.13.0, datatab
dependencies:
jquery "1.8 - 4"
datatables.net@2.2.0, datatables.net@^2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-2.2.0.tgz#d7e92ede9a3bf23ac4c360e475fbe6313f16fd56"
integrity sha512-q/G5ylL+AhMLFFHNYQAgvooCZtmbudc7wwzKkCZI4B1HnYec4SqnWtcTFjC7P6EtL1UGyx16FcjQ0U84S86mLg==
datatables.net@2.2.1, datatables.net@^2:
version "2.2.1"
resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-2.2.1.tgz#30506074a42eb6f9bfdd823bd7e97d7458c6f1c4"
integrity sha512-Hz7f+a77xGdroAzej88aobT5nkQIJ2Oy1JI7yh2cl0QAXQSJDXOKkOLknu+nphVP8CP8w9MtLCmwMst/F8niiQ==
dependencies:
jquery ">=1.7"