Merge branch 'log_detail_page'

This commit is contained in:
Jan Böhmer 2023-05-16 00:08:12 +02:00
commit d991e15a94
44 changed files with 3105 additions and 1734 deletions

3
.env
View file

@ -71,6 +71,9 @@ HISTORY_SAVE_CHANGED_FIELDS=1
HISTORY_SAVE_CHANGED_DATA=1
# Save the data of an element that gets removed into log entry. This allows to undelete an element
HISTORY_SAVE_REMOVED_DATA=1
# Save the new data of an element that gets changed or added. This allows an easy comparison of the old and new data on the detail page
# This option only becomes active when HISTORY_SAVE_CHANGED_DATA is set to 1
HISTORY_SAVE_NEW_DATA=1
###################################################################################
# Error pages settings

View file

@ -44,6 +44,7 @@ export default class extends Controller
const title = this.element.dataset.deleteTitle;
const form = this.element;
const submitter = event.submitter;
const that = this;
const confirm = bootbox.confirm({
@ -58,6 +59,14 @@ export default class extends Controller
const submit_btn = document.createElement('button');
submit_btn.type = 'submit';
submit_btn.style.display = 'none';
//If the clicked button has a value, set it on the submit button
if (submitter.value) {
submit_btn.value = submitter.value;
}
if (submitter.name) {
submit_btn.name = submitter.name;
}
form.appendChild(submit_btn);
submit_btn.click();
} else {

View file

@ -0,0 +1,40 @@
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Controller} from "@hotwired/stimulus";
import JSONFormatter from 'json-formatter-js';
/**
* This controller implements an element that renders a JSON object as a collapsible tree.
* The JSON object is passed as a data attribute.
* You have to apply the controller to a div element or similar block element which can contain other elements.
*/
export default class extends Controller {
connect() {
const depth_to_open = this.element.dataset.depthToOpen ?? 0;
const json_string = this.element.dataset.json;
const json_object = JSON.parse(json_string);
const formatter = new JSONFormatter(json_object, depth_to_open);
this.element.appendChild(formatter.render());
}
}

View file

@ -105,4 +105,19 @@ form .col-form-label.required:after, form label.required:after {
position: relative;
right: -2px;
z-index: 700;
}
/****************************************
* HTML diff styling
****************************************/
/* Insertations are marked with green background and bold */
ins {
background-color: #95f095;
font-weight: bold;
}
del {
background-color: #f09595;
font-weight: bold;
}

View file

@ -4,16 +4,17 @@
"require": {
"php": "^7.4 || ^8.0",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-dom": "*",
"beberlei/doctrineextensions": "^1.2",
"brick/math": "^0.8.15",
"composer/package-versions-deprecated": "1.11.99.4",
"doctrine/annotations": "^1.6",
"doctrine/data-fixtures": "^1.6.6",
"doctrine/dbal": "^3.4.6",
"doctrine/doctrine-bundle": "^2.0",
"doctrine/doctrine-migrations-bundle": "^3.0",
@ -25,6 +26,7 @@
"gregwar/captcha-bundle": "^2.1.0",
"hslavich/oneloginsaml-bundle": "^2.10",
"jbtronics/2fa-webauthn": "^1.0.0",
"jfcherng/php-diff": "^6.14",
"league/csv": "^9.8.0",
"league/html-to-markdown": "^5.0.1",
"liip/imagine-bundle": "^2.2",
@ -78,9 +80,7 @@
"twig/intl-extra": "^3.0",
"twig/markdown-extra": "^3.0",
"web-auth/webauthn-symfony-bundle": "^3.3",
"webmozart/assert": "^1.4",
"doctrine/data-fixtures": "^1.6.6"
"webmozart/assert": "^1.4"
},
"require-dev": {
"dama/doctrine-test-bundle": "^7.0",

317
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "112549e8d6425274bb56b648d18c3878",
"content-hash": "51206f9aa7e372b40ef62a105c4a3f13",
"packages": [
{
"name": "beberlei/assert",
@ -1538,16 +1538,16 @@
},
{
"name": "doctrine/orm",
"version": "2.15.0",
"version": "2.15.1",
"source": {
"type": "git",
"url": "https://github.com/doctrine/orm.git",
"reference": "7b5fafffbeb560e75adc349e71bf1e90463796d2"
"reference": "9bc6f5b4ac6f1e7d4248b2efbd01a748782075bc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/orm/zipball/7b5fafffbeb560e75adc349e71bf1e90463796d2",
"reference": "7b5fafffbeb560e75adc349e71bf1e90463796d2",
"url": "https://api.github.com/repos/doctrine/orm/zipball/9bc6f5b4ac6f1e7d4248b2efbd01a748782075bc",
"reference": "9bc6f5b4ac6f1e7d4248b2efbd01a748782075bc",
"shasum": ""
},
"require": {
@ -1583,7 +1583,7 @@
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2",
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
"vimeo/psalm": "4.30.0 || 5.9.0"
"vimeo/psalm": "4.30.0 || 5.11.0"
},
"suggest": {
"ext-dom": "Provides support for XSD validation for XML mapping files",
@ -1633,9 +1633,9 @@
],
"support": {
"issues": "https://github.com/doctrine/orm/issues",
"source": "https://github.com/doctrine/orm/tree/2.15.0"
"source": "https://github.com/doctrine/orm/tree/2.15.1"
},
"time": "2023-04-26T18:52:02+00:00"
"time": "2023-05-07T18:56:25+00:00"
},
{
"name": "doctrine/persistence",
@ -2628,6 +2628,242 @@
},
"time": "2022-10-03T22:29:32+00:00"
},
{
"name": "jfcherng/php-color-output",
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/jfcherng/php-color-output.git",
"reference": "6c7bf16686cc6a291647fcb87491640a2d5edd20"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jfcherng/php-color-output/zipball/6c7bf16686cc6a291647fcb87491640a2d5edd20",
"reference": "6c7bf16686cc6a291647fcb87491640a2d5edd20",
"shasum": ""
},
"require": {
"php": ">=7.1.3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.19",
"liip/rmt": "^1.6",
"phan/phan": "^2 || ^3 || ^4",
"phpunit/phpunit": ">=7 <10",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Jfcherng\\Utility\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jack Cherng",
"email": "jfcherng@gmail.com"
}
],
"description": "Make your PHP command-line application colorful.",
"keywords": [
"ansi-colors",
"color",
"command-line",
"str-color"
],
"support": {
"issues": "https://github.com/jfcherng/php-color-output/issues",
"source": "https://github.com/jfcherng/php-color-output/tree/3.0.0"
},
"funding": [
{
"url": "https://www.paypal.me/jfcherng/5usd",
"type": "custom"
}
],
"time": "2021-05-27T02:45:54+00:00"
},
{
"name": "jfcherng/php-diff",
"version": "6.14.2",
"source": {
"type": "git",
"url": "https://github.com/jfcherng/php-diff.git",
"reference": "8b2bd0c987f69835a816642193d62a7c3664ca96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jfcherng/php-diff/zipball/8b2bd0c987f69835a816642193d62a7c3664ca96",
"reference": "8b2bd0c987f69835a816642193d62a7c3664ca96",
"shasum": ""
},
"require": {
"jfcherng/php-color-output": "^3",
"jfcherng/php-mb-string": "^1.4.6",
"jfcherng/php-sequence-matcher": "^3.2.9",
"php": ">=7.4"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.8",
"liip/rmt": "^1.6",
"phan/phan": "^5",
"phpunit/phpunit": "^9",
"squizlabs/php_codesniffer": "^3.6"
},
"type": "library",
"autoload": {
"psr-4": {
"Jfcherng\\Diff\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jack Cherng",
"email": "jfcherng@gmail.com"
},
{
"name": "Chris Boulton",
"email": "chris.boulton@interspire.com"
}
],
"description": "A comprehensive library for generating differences between two strings in multiple formats (unified, side by side HTML etc).",
"keywords": [
"diff",
"udiff",
"unidiff",
"unified diff"
],
"support": {
"issues": "https://github.com/jfcherng/php-diff/issues",
"source": "https://github.com/jfcherng/php-diff/tree/6.14.2"
},
"funding": [
{
"url": "https://www.paypal.me/jfcherng/5usd",
"type": "custom"
}
],
"time": "2023-03-15T19:26:28+00:00"
},
{
"name": "jfcherng/php-mb-string",
"version": "1.4.8",
"source": {
"type": "git",
"url": "https://github.com/jfcherng/php-mb-string.git",
"reference": "ef8926ff849863bfea234e99ee827947bedd86b0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jfcherng/php-mb-string/zipball/ef8926ff849863bfea234e99ee827947bedd86b0",
"reference": "ef8926ff849863bfea234e99ee827947bedd86b0",
"shasum": ""
},
"require": {
"php": ">=7.1.3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.18",
"phan/phan": "^2 || ^3 || ^4",
"phpunit/phpunit": "^7.2 || ^8 || ^9"
},
"suggest": {
"ext-iconv": "Either \"ext-iconv\" or \"ext-mbstring\" is requried.",
"ext-mbstring": "Either \"ext-iconv\" or \"ext-mbstring\" is requried."
},
"type": "library",
"autoload": {
"psr-4": {
"Jfcherng\\Utility\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jack Cherng",
"email": "jfcherng@gmail.com"
}
],
"description": "A high performance multibytes sting implementation for frequently reading/writing operations.",
"support": {
"issues": "https://github.com/jfcherng/php-mb-string/issues",
"source": "https://github.com/jfcherng/php-mb-string/tree/1.4.8"
},
"funding": [
{
"url": "https://www.paypal.me/jfcherng/5usd",
"type": "custom"
}
],
"time": "2023-04-17T14:22:37+00:00"
},
{
"name": "jfcherng/php-sequence-matcher",
"version": "3.2.9",
"source": {
"type": "git",
"url": "https://github.com/jfcherng/php-sequence-matcher.git",
"reference": "5de2243aa611a66395d85ba1a9169b439bd13e4d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jfcherng/php-sequence-matcher/zipball/5de2243aa611a66395d85ba1a9169b439bd13e4d",
"reference": "5de2243aa611a66395d85ba1a9169b439bd13e4d",
"shasum": ""
},
"require": {
"php": ">=7.1.3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.19",
"phan/phan": "^2.5 || ^3 || ^4 || ^5",
"phpunit/phpunit": ">=7 <10",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Jfcherng\\Diff\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Jack Cherng",
"email": "jfcherng@gmail.com"
},
{
"name": "Chris Boulton",
"email": "chris.boulton@interspire.com"
}
],
"description": "A longest sequence matcher. The logic is primarily based on the Python difflib package.",
"support": {
"issues": "https://github.com/jfcherng/php-sequence-matcher/issues",
"source": "https://github.com/jfcherng/php-sequence-matcher/tree/3.2.9"
},
"funding": [
{
"url": "https://www.paypal.me/jfcherng/5usd",
"type": "custom"
}
],
"time": "2023-03-11T06:56:44+00:00"
},
{
"name": "laminas/laminas-code",
"version": "4.7.1",
@ -4393,6 +4629,7 @@
"issues": "https://github.com/php-http/message-factory/issues",
"source": "https://github.com/php-http/message-factory/tree/1.1.0"
},
"abandoned": "psr/http-factory",
"time": "2023-04-14T14:16:17+00:00"
},
{
@ -14575,16 +14812,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.10.14",
"version": "1.10.15",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "d232901b09e67538e5c86a724be841bea5768a7c"
"reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/d232901b09e67538e5c86a724be841bea5768a7c",
"reference": "d232901b09e67538e5c86a724be841bea5768a7c",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd",
"reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd",
"shasum": ""
},
"require": {
@ -14633,20 +14870,20 @@
"type": "tidelift"
}
],
"time": "2023-04-19T13:47:27+00:00"
"time": "2023-05-09T15:28:01+00:00"
},
{
"name": "phpstan/phpstan-doctrine",
"version": "1.3.38",
"version": "1.3.40",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-doctrine.git",
"reference": "f1499e54358052fef17d349881ee87a7c4cc4c67"
"reference": "f741919a720af6f84249abc62befeb15eee7bc88"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/f1499e54358052fef17d349881ee87a7c4cc4c67",
"reference": "f1499e54358052fef17d349881ee87a7c4cc4c67",
"url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/f741919a720af6f84249abc62befeb15eee7bc88",
"reference": "f741919a720af6f84249abc62befeb15eee7bc88",
"shasum": ""
},
"require": {
@ -14701,9 +14938,9 @@
"description": "Doctrine extensions for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-doctrine/issues",
"source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.38"
"source": "https://github.com/phpstan/phpstan-doctrine/tree/1.3.40"
},
"time": "2023-05-04T10:53:10+00:00"
"time": "2023-05-11T11:26:04+00:00"
},
{
"name": "phpstan/phpstan-symfony",
@ -14847,12 +15084,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "f86a07b7eb07f9297e939d8c5f97178b2c189dfe"
"reference": "d1af11449398214f9664514ce705c5154ead9c38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/f86a07b7eb07f9297e939d8c5f97178b2c189dfe",
"reference": "f86a07b7eb07f9297e939d8c5f97178b2c189dfe",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/d1af11449398214f9664514ce705c5154ead9c38",
"reference": "d1af11449398214f9664514ce705c5154ead9c38",
"shasum": ""
},
"conflict": {
@ -15037,6 +15274,7 @@
"ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3",
"ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3",
"ibexa/post-install": "<=1.0.4",
"ibexa/user": ">=4,<4.4.3",
"icecoder/icecoder": "<=8.1",
"idno/known": "<=1.3.1",
"illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10",
@ -15079,7 +15317,7 @@
"laravel/framework": "<6.20.42|>=7,<7.30.6|>=8,<8.75",
"laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10",
"latte/latte": "<2.10.8",
"lavalite/cms": "<=5.8",
"lavalite/cms": "<=9",
"lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5",
"league/commonmark": "<0.18.3",
"league/flysystem": "<1.1.4|>=2,<2.1.1",
@ -15177,6 +15415,7 @@
"phpwhois/phpwhois": "<=4.2.5",
"phpxmlrpc/extras": "<0.6.1",
"phpxmlrpc/phpxmlrpc": "<4.9.2",
"pimcore/customer-management-framework-bundle": "<3.3.9",
"pimcore/data-hub": "<1.2.4",
"pimcore/perspective-editor": "<1.5.1",
"pimcore/pimcore": "<10.5.21",
@ -15363,7 +15602,7 @@
"wp-graphql/wp-graphql": "<0.3.5",
"wpanel/wpanel4-cms": "<=4.3.1",
"wpcloud/wp-stateless": "<3.2",
"wwbn/avideo": "<12.4",
"wwbn/avideo": "<=12.4",
"xataface/xataface": "<3",
"xpressengine/xpressengine": "<3.0.15",
"yeswiki/yeswiki": "<4.1",
@ -15445,20 +15684,20 @@
"type": "tidelift"
}
],
"time": "2023-05-06T00:13:11+00:00"
"time": "2023-05-12T21:03:58+00:00"
},
{
"name": "sebastian/diff",
"version": "4.0.4",
"version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
"reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
"reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
"shasum": ""
},
"require": {
@ -15503,7 +15742,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
"source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
},
"funding": [
{
@ -15511,7 +15750,7 @@
"type": "github"
}
],
"time": "2020-10-26T13:10:38+00:00"
"time": "2023-05-07T05:35:17+00:00"
},
{
"name": "spatie/array-to-xml",
@ -16059,16 +16298,16 @@
},
{
"name": "symplify/easy-coding-standard",
"version": "11.3.2",
"version": "11.3.4",
"source": {
"type": "git",
"url": "https://github.com/easy-coding-standard/easy-coding-standard.git",
"reference": "d4159e06c0970e71a2a58d350160241e7cb3994b"
"reference": "c72eb4bdf30e54de2d31aef596f96642ff443741"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/easy-coding-standard/easy-coding-standard/zipball/d4159e06c0970e71a2a58d350160241e7cb3994b",
"reference": "d4159e06c0970e71a2a58d350160241e7cb3994b",
"url": "https://api.github.com/repos/easy-coding-standard/easy-coding-standard/zipball/c72eb4bdf30e54de2d31aef596f96642ff443741",
"reference": "c72eb4bdf30e54de2d31aef596f96642ff443741",
"shasum": ""
},
"require": {
@ -16101,7 +16340,7 @@
],
"support": {
"issues": "https://github.com/easy-coding-standard/easy-coding-standard/issues",
"source": "https://github.com/easy-coding-standard/easy-coding-standard/tree/11.3.2"
"source": "https://github.com/easy-coding-standard/easy-coding-standard/tree/11.3.4"
},
"funding": [
{
@ -16113,7 +16352,7 @@
"type": "github"
}
],
"time": "2023-03-22T15:28:51+00:00"
"time": "2023-05-10T14:44:08+00:00"
},
{
"name": "vimeo/psalm",
@ -16233,12 +16472,12 @@
"platform": {
"php": "^7.4 || ^8.0",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-intl": "*",
"ext-json": "*",
"ext-mbstring": "*",
"ext-dom": "*"
"ext-mbstring": "*"
},
"platform-dev": [],
"platform-overrides": {

View file

@ -125,3 +125,9 @@ parameters:
env(DEFAULT_URI): 'https://partdb.changeme.invalid/'
env(SAML_ROLE_MAPPING): '{}'
env(HISTORY_SAVE_CHANGED_DATA): 1
env(HISTORY_SAVE_CHANGED_FIELDS): 1
env(HISTORY_SAVE_REMOVED_DATA): 1
env(HISTORY_SAVE_NEW_DATA): 1

View file

@ -78,6 +78,7 @@ services:
$save_changed_fields: '%env(bool:HISTORY_SAVE_CHANGED_FIELDS)%'
$save_changed_data: '%env(bool:HISTORY_SAVE_CHANGED_DATA)%'
$save_removed_data: '%env(bool:HISTORY_SAVE_REMOVED_DATA)%'
$save_new_data: '%env(bool:HISTORY_SAVE_NEW_DATA)%'
tags:
- { name: 'doctrine.event_subscriber' }

View file

@ -46,8 +46,9 @@ The following configuration options can only be changed by the server administra
### History/Eventlog related settings
The following options are used to configure, which (and how much) data is written to the system log:
* `HISTORY_SAVE_CHANGED_FIELDS`: When this option is set to true, the name of the fields which are changed, are saved to the DB (so for example it is logged that a user has changed, that the user has changed the name and description of the field, but not the data/content of these changes)
* `HISTORY_SAVE_CHANGED_DATA`: When this option is set to true, the changed data is saved to log (so it is logged, that a user has changed the name of a part and what the name was before). This can increase database size, when you have a lot of changes to enties.
* `HISTORY_SAVE_CHANGED_DATA`: When this option is set to true, the changed data is saved to log (so it is logged, that a user has changed the name of a part and what the name was before). This can increase database size, when you have a lot of changes to entities.
* `HISTORY_SAVE_REMOVED_DATA`: When this option is set to true, removed data is saved to log, meaning that you can easily undelete an entity, when it was removed accidentally.
* `HISTORY_SAVE_NEW_DATA`: When this option is set to true, the new data (the data after a change) is saved to element changed log entries. This allows you to easily see the changes between two revisions of an entity. This can increase database size, when you have a lot of changes to entities.
If you wanna use want to revert changes or view older revisions of entities, then `HISTORY_SAVE_CHANGED_FIELDS`, `HISTORY_SAVE_CHANGED_DATA` and `HISTORY_SAVE_REMOVED_DATA` all have to be true.

View file

@ -77,6 +77,7 @@
"emoji.json": "^14.0.0",
"exports-loader": "^3.0.0",
"html5-qrcode": "^2.2.1",
"json-formatter-js": "^2.3.4",
"jszip": "^3.2.0",
"katex": "^0.16.0",
"marked": "^4.3.0",

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Controller;
use App\DataTables\Column\LogEntryTargetColumn;
use App\DataTables\Filters\LogFilter;
use App\DataTables\LogDataTable;
use App\Entity\Base\AbstractDBElement;
@ -33,6 +34,9 @@ use App\Entity\LogSystem\ElementEditedLogEntry;
use App\Form\Filters\LogFilterType;
use App\Repository\DBElementRepository;
use App\Services\LogSystem\EventUndoHelper;
use App\Services\LogSystem\LogEntryExtraFormatter;
use App\Services\LogSystem\LogLevelHelper;
use App\Services\LogSystem\LogTargetHelper;
use App\Services\LogSystem\TimeTravel;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
@ -93,6 +97,51 @@ class LogController extends AbstractController
]);
}
/**
* @Route("/{id}/details", name="log_details")
* @param Request $request
* @param AbstractLogEntry $logEntry
* @return Response
*/
public function logDetails(Request $request, AbstractLogEntry $logEntry, LogEntryExtraFormatter $logEntryExtraFormatter,
LogLevelHelper $logLevelHelper, LogTargetHelper $logTargetHelper, EntityManagerInterface $entityManager): Response
{
$this->denyAccessUnlessGranted('show_details', $logEntry);
$extra_html = $logEntryExtraFormatter->format($logEntry);
$target_html = $logTargetHelper->formatTarget($logEntry);
$repo = $entityManager->getRepository(AbstractLogEntry::class);
$target_element = $repo->getTargetElement($logEntry);
return $this->render('log_system/details/log_details.html.twig', [
'log_entry' => $logEntry,
'target_element' => $target_element,
'extra_html' => $extra_html,
'target_html' => $target_html,
'log_level_helper' => $logLevelHelper,
]);
}
/**
* @Route("/{id}/delete", name="log_delete", methods={"DELETE"})
*/
public function deleteLogEntry(Request $request, AbstractLogEntry $logEntry, EntityManagerInterface $entityManager): RedirectResponse
{
$this->denyAccessUnlessGranted('delete', $logEntry);
if ($this->isCsrfTokenValid('delete'.$logEntry->getId(), $request->request->get('_token'))) {
//Remove part
$entityManager->remove($logEntry);
//Flush changes
$entityManager->flush();
$this->addFlash('success', 'log.delete.success');
}
return $this->redirectToRoute('homepage');
}
/**
* @Route("/undo", name="log_undo", methods={"POST"})
*/

View file

@ -36,6 +36,7 @@ use App\Exceptions\EntityNotSupportedException;
use App\Repository\LogEntryRepository;
use App\Services\ElementTypeNameGenerator;
use App\Services\EntityURLGenerator;
use App\Services\LogSystem\LogTargetHelper;
use Doctrine\ORM\EntityManagerInterface;
use Omines\DataTablesBundle\Column\AbstractColumn;
use Symfony\Component\OptionsResolver\OptionsResolver;
@ -43,21 +44,11 @@ use Symfony\Contracts\Translation\TranslatorInterface;
class LogEntryTargetColumn extends AbstractColumn
{
protected EntityManagerInterface $em;
protected LogEntryRepository $entryRepository;
protected EntityURLGenerator $entityURLGenerator;
protected ElementTypeNameGenerator $elementTypeNameGenerator;
protected TranslatorInterface $translator;
private LogTargetHelper $logTargetHelper;
public function __construct(EntityManagerInterface $entityManager, EntityURLGenerator $entityURLGenerator,
ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator)
public function __construct(LogTargetHelper $logTargetHelper)
{
$this->em = $entityManager;
$this->entryRepository = $entityManager->getRepository(AbstractLogEntry::class);
$this->entityURLGenerator = $entityURLGenerator;
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
$this->translator = $translator;
$this->logTargetHelper = $logTargetHelper;
}
/**
@ -80,71 +71,9 @@ class LogEntryTargetColumn extends AbstractColumn
public function render($value, $context): string
{
if ($context instanceof UserNotAllowedLogEntry && $this->options['showAccessDeniedPath']) {
return htmlspecialchars($context->getPath());
}
/** @var AbstractLogEntry $context */
$target = $this->entryRepository->getTargetElement($context);
$tmp = '';
//The element is existing
if ($target instanceof NamedElementInterface && !empty($target->getName())) {
try {
$tmp = sprintf(
'<a href="%s">%s</a>',
$this->entityURLGenerator->infoURL($target),
$this->elementTypeNameGenerator->getTypeNameCombination($target, true)
);
} catch (EntityNotSupportedException $exception) {
$tmp = $this->elementTypeNameGenerator->getTypeNameCombination($target, true);
}
} elseif ($target instanceof AbstractDBElement) { //Target does not have a name
$tmp = sprintf(
'<i>%s</i>: %s',
$this->elementTypeNameGenerator->getLocalizedTypeLabel($target),
$target->getID()
);
} elseif (null === $target && $context->hasTarget()) { //Element was deleted
$tmp = sprintf(
'<i>%s</i>: %s [%s]',
$this->elementTypeNameGenerator->getLocalizedTypeLabel($context->getTargetClass()),
$context->getTargetID(),
$this->translator->trans('log.target_deleted')
);
}
//Add a hint to the associated element if possible
if (null !== $target && $this->options['show_associated']) {
if ($target instanceof Attachment && null !== $target->getElement()) {
$on = $target->getElement();
} elseif ($target instanceof AbstractParameter && null !== $target->getElement()) {
$on = $target->getElement();
} elseif ($target instanceof PartLot && null !== $target->getPart()) {
$on = $target->getPart();
} elseif ($target instanceof Orderdetail && null !== $target->getPart()) {
$on = $target->getPart();
} elseif ($target instanceof Pricedetail && null !== $target->getOrderdetail() && null !== $target->getOrderdetail()->getPart()) {
$on = $target->getOrderdetail()->getPart();
} elseif ($target instanceof ProjectBOMEntry && null !== $target->getProject()) {
$on = $target->getProject();
}
if (isset($on) && is_object($on)) {
try {
$tmp .= sprintf(
' (<a href="%s">%s</a>)',
$this->entityURLGenerator->infoURL($on),
$this->elementTypeNameGenerator->getTypeNameCombination($on, true)
);
} catch (EntityNotSupportedException $exception) {
$tmp .= ' ('.$this->elementTypeNameGenerator->getTypeNameCombination($target, true).')';
}
}
}
//Log is not associated with an element
return $tmp;
return $this->logTargetHelper->formatTarget($context, [
'showAccessDeniedPath' => $this->options['showAccessDeniedPath'],
'show_associated' => $this->options['show_associated'],
]);
}
}

View file

@ -73,13 +73,13 @@ class RevertLogColumn extends AbstractColumn
{
if (
$context instanceof CollectionElementDeleted
|| ($context instanceof ElementDeletedLogEntry && $context->hasOldDataInformations())
|| ($context instanceof ElementDeletedLogEntry && $context->hasOldDataInformation())
) {
$icon = 'fa-trash-restore';
$title = $this->translator->trans('log.undo.undelete');
} elseif (
$context instanceof ElementCreatedLogEntry
|| ($context instanceof ElementEditedLogEntry && $context->hasOldDataInformations())
|| ($context instanceof ElementEditedLogEntry && $context->hasOldDataInformation())
) {
$icon = 'fa-undo';
$title = $this->translator->trans('log.undo.undo');

View file

@ -43,6 +43,7 @@ use App\Exceptions\EntityNotSupportedException;
use App\Repository\LogEntryRepository;
use App\Services\ElementTypeNameGenerator;
use App\Services\EntityURLGenerator;
use App\Services\LogSystem\LogLevelHelper;
use App\Services\UserSystem\UserAvatarHelper;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
@ -67,10 +68,11 @@ class LogDataTable implements DataTableTypeInterface
protected LogEntryRepository $logRepo;
protected Security $security;
protected UserAvatarHelper $userAvatarHelper;
protected LogLevelHelper $logLevelHelper;
public function __construct(ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator,
UrlGeneratorInterface $urlGenerator, EntityURLGenerator $entityURLGenerator, EntityManagerInterface $entityManager,
Security $security, UserAvatarHelper $userAvatarHelper)
Security $security, UserAvatarHelper $userAvatarHelper, LogLevelHelper $logLevelHelper)
{
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
$this->translator = $translator;
@ -79,6 +81,7 @@ class LogDataTable implements DataTableTypeInterface
$this->logRepo = $entityManager->getRepository(AbstractLogEntry::class);
$this->security = $security;
$this->userAvatarHelper = $userAvatarHelper;
$this->logLevelHelper = $logLevelHelper;
}
public function configureOptions(OptionsResolver $optionsResolver): void
@ -112,69 +115,18 @@ class LogDataTable implements DataTableTypeInterface
//This special $$rowClass column is used to set the row class depending on the log level. The class gets set by the frontend controller
$dataTable->add('dont_matter', RowClassColumn::class, [
'render' => static function ($value, AbstractLogEntry $context) {
switch ($context->getLevel()) {
case AbstractLogEntry::LEVEL_EMERGENCY:
case AbstractLogEntry::LEVEL_ALERT:
case AbstractLogEntry::LEVEL_CRITICAL:
case AbstractLogEntry::LEVEL_ERROR:
return 'table-danger';
case AbstractLogEntry::LEVEL_WARNING:
return 'table-warning';
case AbstractLogEntry::LEVEL_NOTICE:
return 'table-info';
default:
return '';
}
'render' => function ($value, AbstractLogEntry $context) {
return $this->logLevelHelper->logLevelToTableColorClass($context->getLevelString());
},
]);
$dataTable->add('symbol', TextColumn::class, [
'label' => '',
'className' => 'no-colvis',
'render' => static function ($value, AbstractLogEntry $context) {
switch ($context->getLevelString()) {
case LogLevel::DEBUG:
$symbol = 'fa-bug';
break;
case LogLevel::INFO:
$symbol = 'fa-info';
break;
case LogLevel::NOTICE:
$symbol = 'fa-flag';
break;
case LogLevel::WARNING:
$symbol = 'fa-exclamation-circle';
break;
case LogLevel::ERROR:
$symbol = 'fa-exclamation-triangle';
break;
case LogLevel::CRITICAL:
$symbol = 'fa-bolt';
break;
case LogLevel::ALERT:
$symbol = 'fa-radiation';
break;
case LogLevel::EMERGENCY:
$symbol = 'fa-skull-crossbones';
break;
default:
$symbol = 'fa-question-circle';
break;
}
'render' => function ($value, AbstractLogEntry $context) {
return sprintf(
'<i class="fas fa-fw %s" title="%s"></i>',
$symbol,
$this->logLevelHelper->logLevelToIconClass($context->getLevelString()),
$context->getLevelString()
);
},
@ -188,6 +140,12 @@ class LogDataTable implements DataTableTypeInterface
$dataTable->add('timestamp', LocaleDateTimeColumn::class, [
'label' => 'log.timestamp',
'timeFormat' => 'medium',
'render' => function (string $value, AbstractLogEntry $context) {
return sprintf('<a href="%s">%s</a>',
$this->urlGenerator->generate('log_details', ['id' => $context->getId()]),
$value
);
}
]);
$dataTable->add('type', TextColumn::class, [
@ -278,7 +236,7 @@ class LogDataTable implements DataTableTypeInterface
'href' => function ($value, AbstractLogEntry $context) {
if (
($context instanceof TimeTravelInterface
&& $context->hasOldDataInformations())
&& $context->hasOldDataInformation())
|| $context instanceof CollectionElementDeleted
) {
try {

View file

@ -0,0 +1,41 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Entity\Contracts;
interface LogWithNewDataInterface
{
/**
* Checks if this entry has information about the new data.
* @return bool
*/
public function hasNewDataInformation(): bool;
/**
* Returns the new data for this entry.
*/
public function getNewData(): array;
/**
* Sets the new data for this entry.
* @return $this
*/
public function setNewData(array $new_data): self;
}

View file

@ -31,7 +31,7 @@ interface TimeTravelInterface
*
* @return bool true if this entry has information about the changed data
*/
public function hasOldDataInformations(): bool;
public function hasOldDataInformation(): bool;
/**
* Returns the data the entity had before this log entry.

View file

@ -88,7 +88,7 @@ class ElementDeletedLogEntry extends AbstractLogEntry implements TimeTravelInter
return $this;
}
public function hasOldDataInformations(): bool
public function hasOldDataInformation(): bool
{
return !empty($this->extra['o']);
}

View file

@ -25,6 +25,7 @@ namespace App\Entity\LogSystem;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Contracts\LogWithCommentInterface;
use App\Entity\Contracts\LogWithEventUndoInterface;
use App\Entity\Contracts\LogWithNewDataInterface;
use App\Entity\Contracts\TimeTravelInterface;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
@ -32,7 +33,7 @@ use InvalidArgumentException;
/**
* @ORM\Entity()
*/
class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterface, LogWithCommentInterface, LogWithEventUndoInterface
class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterface, LogWithCommentInterface, LogWithEventUndoInterface, LogWithNewDataInterface
{
protected string $typeString = 'element_edited';
@ -49,7 +50,7 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
*/
public function hasChangedFieldsInfo(): bool
{
return isset($this->extra['f']) || $this->hasOldDataInformations();
return isset($this->extra['f']) || $this->hasOldDataInformation();
}
/**
@ -59,7 +60,7 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
*/
public function getChangedFields(): array
{
if ($this->hasOldDataInformations()) {
if ($this->hasOldDataInformation()) {
return array_keys($this->getOldData());
}
@ -92,7 +93,29 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
return $this;
}
public function hasOldDataInformations(): bool
public function hasNewDataInformation(): bool
{
return !empty($this->extra['n']);
}
public function getNewData(): array
{
return $this->extra['n'] ?? [];
}
/**
* Sets the old data for this entry.
*
* @return $this
*/
public function setNewData(array $new_data): self
{
$this->extra['n'] = $new_data;
return $this;
}
public function hasOldDataInformation(): bool
{
return !empty($this->extra['d']);
}

View file

@ -113,7 +113,7 @@ class SecurityEventLogEntry extends AbstractLogEntry
{
$key = $this->extra['e'];
return static::SECURITY_TYPE_MAPPING[$key] ?? 'unkown';
return static::SECURITY_TYPE_MAPPING[$key] ?? 'unknown';
}
/**

View file

@ -78,11 +78,12 @@ class EventLoggerSubscriber implements EventSubscriber
protected bool $save_changed_fields;
protected bool $save_changed_data;
protected bool $save_removed_data;
protected bool $save_new_data;
protected PropertyAccessorInterface $propertyAccessor;
public function __construct(EventLogger $logger, SerializerInterface $serializer, EventCommentHelper $commentHelper,
bool $save_changed_fields, bool $save_changed_data, bool $save_removed_data, PropertyAccessorInterface $propertyAccessor,
EventUndoHelper $eventUndoHelper)
bool $save_changed_fields, bool $save_changed_data, bool $save_removed_data, bool $save_new_data,
PropertyAccessorInterface $propertyAccessor, EventUndoHelper $eventUndoHelper)
{
$this->logger = $logger;
$this->serializer = $serializer;
@ -93,6 +94,8 @@ class EventLoggerSubscriber implements EventSubscriber
$this->save_changed_fields = $save_changed_fields;
$this->save_changed_data = $save_changed_data;
$this->save_removed_data = $save_removed_data;
//This option only makes sense if save_changed_data is true
$this->save_new_data = $save_new_data && $save_changed_data;
}
public function onFlush(OnFlushEventArgs $eventArgs): void
@ -150,6 +153,7 @@ class EventLoggerSubscriber implements EventSubscriber
$log->setTargetElementID($undoEvent->getDeletedElementID());
}
}
$this->logger->log($log);
}
}
@ -301,6 +305,24 @@ class EventLoggerSubscriber implements EventSubscriber
}, ARRAY_FILTER_USE_BOTH);
}
/**
* Restrict the length of every string in the given array to MAX_STRING_LENGTH, to save memory in the case of very
* long strings (e.g. images in notes)
* @param array $fields
* @return array
*/
protected function fieldLengthRestrict(array $fields): array
{
return array_map(
static function ($value) {
if (is_string($value)) {
return mb_strimwidth($value, 0, self::MAX_STRING_LENGTH, '...');
}
return $value;
}, $fields);
}
protected function saveChangeSet(AbstractDBElement $entity, AbstractLogEntry $logEntry, EntityManagerInterface $em, bool $element_deleted = false): void
{
$uow = $em->getUnitOfWork();
@ -314,20 +336,24 @@ class EventLoggerSubscriber implements EventSubscriber
} else { //Otherwise we have to get it from entity changeset
$changeSet = $uow->getEntityChangeSet($entity);
$old_data = array_combine(array_keys($changeSet), array_column($changeSet, 0));
//If save_new_data is enabled, we extract it from the change set
if ($this->save_new_data) {
$new_data = array_combine(array_keys($changeSet), array_column($changeSet, 1));
}
}
$old_data = $this->filterFieldRestrictions($entity, $old_data);
//Restrict length of string fields, to save memory...
$old_data = array_map(
static function ($value) {
if (is_string($value)) {
return mb_strimwidth($value, 0, self::MAX_STRING_LENGTH, '...');
}
return $value;
}, $old_data);
$old_data = $this->fieldLengthRestrict($old_data);
$logEntry->setOldData($old_data);
if (!empty($new_data)) {
$new_data = $this->filterFieldRestrictions($entity, $new_data);
$new_data = $this->fieldLengthRestrict($new_data);
$logEntry->setNewData($new_data);
}
}
/**

View file

@ -24,13 +24,28 @@ namespace App\Security\Voter;
use App\Entity\LogSystem\AbstractLogEntry;
use App\Entity\UserSystem\User;
use App\Services\UserSystem\PermissionManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;
class LogEntryVoter extends ExtendedVoter
{
public const ALLOWED_OPS = ['read', 'delete'];
public const ALLOWED_OPS = ['read', 'show_details', 'delete'];
private Security $security;
public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, Security $security)
{
parent::__construct($resolver, $entityManager);
$this->security = $security;
}
protected function voteOnUser(string $attribute, $subject, User $user): bool
{
if (!$subject instanceof AbstractLogEntry) {
throw new \InvalidArgumentException('The subject must be an instance of '.AbstractLogEntry::class);
}
if ('delete' === $attribute) {
return $this->resolver->inherit($user, 'system', 'delete_logs') ?? false;
}
@ -47,13 +62,24 @@ class LogEntryVoter extends ExtendedVoter
return $this->resolver->inherit($user, 'system', 'show_logs') ?? false;
}
if ('show_details' === $attribute) {
//To view details of a element related log entry, the user needs to be able to view the history of this entity type
$targetClass = $subject->getTargetClass();
if (null !== $targetClass) {
return $this->security->isGranted('show_history', $targetClass) ?? false;
}
//In other cases, this behaves like the read permission
return $this->voteOnUser('read', $subject, $user);
}
return false;
}
protected function supports($attribute, $subject): bool
{
if ($subject instanceof AbstractLogEntry) {
return in_array($subject, static::ALLOWED_OPS, true);
return in_array($attribute, static::ALLOWED_OPS, true);
}
return false;

View file

@ -24,6 +24,7 @@ namespace App\Services;
use App\Entity\Attachments\Attachment;
use App\Entity\Attachments\AttachmentType;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Contracts\NamedElementInterface;
use App\Entity\ProjectSystem\Project;
use App\Entity\LabelSystem\LabelProfile;
@ -43,17 +44,20 @@ use App\Entity\ProjectSystem\ProjectBOMEntry;
use App\Entity\UserSystem\Group;
use App\Entity\UserSystem\User;
use App\Exceptions\EntityNotSupportedException;
use Doctrine\ORM\Mapping\Entity;
use function get_class;
use Symfony\Contracts\Translation\TranslatorInterface;
class ElementTypeNameGenerator
{
protected TranslatorInterface $translator;
private EntityURLGenerator $entityURLGenerator;
protected array $mapping;
public function __construct(TranslatorInterface $translator)
public function __construct(TranslatorInterface $translator, EntityURLGenerator $entityURLGenerator)
{
$this->translator = $translator;
$this->entityURLGenerator = $entityURLGenerator;
//Child classes has to become before parent classes
$this->mapping = [
@ -132,4 +136,81 @@ class ElementTypeNameGenerator
return $type.': '.$entity->getName();
}
/**
* Returns a HTML formatted label for the given enitity in the format "Type: Name" (on elements with a name) and
* "Type: ID" (on elements without a name). If possible the value is given as a link to the element.
* @param AbstractDBElement $entity The entity for which the label should be generated
* @param bool $include_associated If set to true, the associated entity (like the part belonging to a part lot) is included in the label to give further information
* @return string
*/
public function formatLabelHTMLForEntity(AbstractDBElement $entity, bool $include_associated = false): string
{
//The element is existing
if ($entity instanceof NamedElementInterface && !empty($entity->getName())) {
try {
$tmp = sprintf(
'<a href="%s">%s</a>',
$this->entityURLGenerator->infoURL($entity),
$this->getTypeNameCombination($entity, true)
);
} catch (EntityNotSupportedException $exception) {
$tmp = $this->getTypeNameCombination($entity, true);
}
} else { //Target does not have a name
$tmp = sprintf(
'<i>%s</i>: %s',
$this->getLocalizedTypeLabel($entity),
$entity->getID()
);
}
//Add a hint to the associated element if possible
if ($include_associated) {
if ($entity instanceof Attachment && null !== $entity->getElement()) {
$on = $entity->getElement();
} elseif ($entity instanceof AbstractParameter && null !== $entity->getElement()) {
$on = $entity->getElement();
} elseif ($entity instanceof PartLot && null !== $entity->getPart()) {
$on = $entity->getPart();
} elseif ($entity instanceof Orderdetail && null !== $entity->getPart()) {
$on = $entity->getPart();
} elseif ($entity instanceof Pricedetail && null !== $entity->getOrderdetail() && null !== $entity->getOrderdetail()->getPart()) {
$on = $entity->getOrderdetail()->getPart();
} elseif ($entity instanceof ProjectBOMEntry && null !== $entity->getProject()) {
$on = $entity->getProject();
}
if (isset($on) && is_object($on)) {
try {
$tmp .= sprintf(
' (<a href="%s">%s</a>)',
$this->entityURLGenerator->infoURL($on),
$this->getTypeNameCombination($on, true)
);
} catch (EntityNotSupportedException $exception) {
}
}
}
return $tmp;
}
/**
* Create a HTML formatted label for a deleted element of which we only know the class and the ID.
* Please note that it is not checked if the element really not exists anymore, so you have to do this yourself.
* @param string $class
* @param int $id
* @return string
*/
public function formatElementDeletedHTML(string $class, int $id): string
{
return sprintf(
'<i>%s</i>: %s [%s]',
$this->getLocalizedTypeLabel($class),
$id,
$this->translator->trans('log.target_deleted')
);
}
}

View file

@ -0,0 +1,163 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Services\LogSystem;
use App\Entity\LogSystem\AbstractLogEntry;
use App\Services\ElementTypeNameGenerator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class LogDataFormatter
{
private const STRING_MAX_LENGTH = 1024;
private TranslatorInterface $translator;
private EntityManagerInterface $entityManager;
private ElementTypeNameGenerator $elementTypeNameGenerator;
public function __construct(TranslatorInterface $translator, EntityManagerInterface $entityManager, ElementTypeNameGenerator $elementTypeNameGenerator)
{
$this->translator = $translator;
$this->entityManager = $entityManager;
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
}
/**
* Formats the given data of a log entry as HTML
* @param mixed $data
* @param AbstractLogEntry $logEntry
* @param string $fieldName
* @return string
*/
public function formatData($data, AbstractLogEntry $logEntry, string $fieldName): string
{
if (is_string($data)) {
$tmp = '<span class="text-muted user-select-none">"</span>' . mb_strimwidth(htmlspecialchars($data), 0, self::STRING_MAX_LENGTH, ) . '<span class="text-muted user-select-none">"</span>';
//Show special characters and line breaks
$tmp = preg_replace('/\n/', '<span class="text-muted user-select-none">\\n</span><br>', $tmp);
$tmp = preg_replace('/\r/', '<span class="text-muted user-select-none">\\r</span>', $tmp);
$tmp = preg_replace('/\t/', '<span class="text-muted user-select-none">\\t</span>', $tmp);
return $tmp;
}
if (is_bool($data)) {
return $this->formatBool($data);
}
if (is_int($data)) {
return (string) $data;
}
if (is_float($data)) {
return (string) $data;
}
if (is_null($data)) {
return '<i>null</i>';
}
if (is_array($data)) {
//If the array contains only one element with the key @id, it is a reference to another entity (foreign key)
if (isset($data['@id'])) {
return $this->formatForeignKey($data, $logEntry, $fieldName);
}
//If the array contains a "date", "timezone_type" and "timezone" key, it is a DateTime object
if (isset($data['date'], $data['timezone_type'], $data['timezone'])) {
return $this->formatDateTime($data);
}
return $this->formatJSON($data);
}
throw new \RuntimeException('Type of $data not supported (' . gettype($data) . ')');
}
private function formatJSON(array $data): string
{
$json = htmlspecialchars(json_encode($data, JSON_PRETTY_PRINT), ENT_QUOTES | ENT_SUBSTITUTE);
return sprintf(
'<div data-controller="elements--json-formatter" data-json="%s"></div>',
$json
);
}
private function formatForeignKey(array $data, AbstractLogEntry $logEntry, string $fieldName): string
{
//Extract the id from the @id key
$id = $data['@id'];
try {
//Retrieve the class type from the logEntry and retrieve the doctrine metadata
$classMetadata = $this->entityManager->getClassMetadata($logEntry->getTargetClass());
$fkTargetClass = $classMetadata->getAssociationTargetClass($fieldName);
//Try to retrieve the entity from the database
$entity = $this->entityManager->getRepository($fkTargetClass)->find($id);
//If the entity was found, return a label for this entity
if ($entity) {
return $this->elementTypeNameGenerator->formatLabelHTMLForEntity($entity, true);
} else { //Otherwise the entity was deleted, so return the id
return $this->elementTypeNameGenerator->formatElementDeletedHTML($fkTargetClass, $id);
}
} catch (\InvalidArgumentException|\ReflectionException $exception) {
return '<i>unknown target class</i>: ' . $id;
}
}
private function formatDateTime(array $data): string
{
if (!isset($data['date'], $data['timezone_type'], $data['timezone'])) {
return '<i>unknown DateTime format</i>';
}
$date = $data['date'];
$timezoneType = $data['timezone_type'];
$timezone = $data['timezone'];
if (!is_string($date) || !is_int($timezoneType) || !is_string($timezone)) {
return '<i>unknown DateTime format</i>';
}
try {
$dateTime = new \DateTime($date, new \DateTimeZone($timezone));
} catch (\Exception $exception) {
return '<i>unknown DateTime format</i>';
}
//Format it to the users locale
$formatter = new \IntlDateFormatter(null, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::MEDIUM);
return $formatter->format($dateTime);
}
private function formatBool(bool $data): string
{
return $data ? $this->translator->trans('true') : $this->translator->trans('false');
}
}

View file

@ -0,0 +1,76 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Services\LogSystem;
use Jfcherng\Diff\DiffHelper;
class LogDiffFormatter
{
/**
* Format the diff between the given data, depending on the type of the data.
* If the diff is not possible, an empty string is returned.
* @param $old_data
* @param $new_data
* @return string
*/
public function formatDiff($old_data, $new_data): string
{
if (is_string($old_data) && is_string($new_data)) {
return $this->diffString($old_data, $new_data);
}
if (is_numeric($old_data) && is_numeric($new_data)) {
return $this->diffNumeric($old_data, $new_data);
}
return '';
}
private function diffString(string $old_data, string $new_data): string
{
return DiffHelper::calculate($old_data, $new_data, 'Combined',
[ //Diff options
'context' => 2,
],
[ //Render options
'detailLevel' => 'char',
'showHeader' => false,
]);
}
private function diffNumeric($old_data, $new_data): string
{
if ((!is_numeric($old_data)) || (!is_numeric($new_data))) {
throw new \InvalidArgumentException('The given data is not numeric.');
}
$difference = $new_data - $old_data;
//Positive difference
if ($difference > 0) {
return sprintf('<span class="text-success">+%s</span>', $difference);
} else if ($difference < 0) {
return sprintf('<span class="text-danger">%s</span>', $difference);
} else {
return sprintf('<span class="text-muted">%s</span>', $difference);
}
}
}

View file

@ -131,9 +131,9 @@ class LogEntryExtraFormatter
if (($context instanceof LogWithEventUndoInterface) && $context->isUndoEvent()) {
if ('undo' === $context->getUndoMode()) {
$array['log.undo_mode.undo'] = (string) $context->getUndoEventID();
$array['log.undo_mode.undo'] = '#' . $context->getUndoEventID();
} elseif ('revert' === $context->getUndoMode()) {
$array['log.undo_mode.revert'] = (string) $context->getUndoEventID();
$array['log.undo_mode.revert'] = '#' . $context->getUndoEventID();
}
}

View file

@ -0,0 +1,80 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Services\LogSystem;
use App\Entity\LogSystem\AbstractLogEntry;
use Psr\Log\LogLevel;
class LogLevelHelper
{
/**
* Returns the FontAwesome icon class for the given log level.
* This returns just the specific icon class (so 'fa-info' for example).
* @param string $logLevel The string representation of the log level (one of the LogLevel::* constants)
* @return string
*/
public function logLevelToIconClass(string $logLevel): string
{
switch ($logLevel) {
case LogLevel::DEBUG:
return 'fa-bug';
case LogLevel::INFO:
return 'fa-info';
case LogLevel::NOTICE:
return 'fa-flag';
case LogLevel::WARNING:
return 'fa-exclamation-circle';
case LogLevel::ERROR:
return 'fa-exclamation-triangle';
case LogLevel::CRITICAL:
return 'fa-bolt';
case LogLevel::ALERT:
return 'fa-radiation';
case LogLevel::EMERGENCY:
return 'fa-skull-crossbones';
default:
return 'fa-question-circle';
}
}
/**
* Returns the Bootstrap table color class for the given log level.
* @param string $logLevel The string representation of the log level (one of the LogLevel::* constants)
* @return string The table color class (one of the 'table-*' classes)
*/
public function logLevelToTableColorClass(string $logLevel): string
{
switch ($logLevel) {
case LogLevel::EMERGENCY:
case LogLevel::ALERT:
case LogLevel::CRITICAL:
case LogLevel::ERROR:
return 'table-danger';
case LogLevel::WARNING:
return 'table-warning';
case LogLevel::NOTICE:
return 'table-info';
default:
return '';
}
}
}

View file

@ -0,0 +1,94 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Services\LogSystem;
use App\Entity\Attachments\Attachment;
use App\Entity\Base\AbstractDBElement;
use App\Entity\Contracts\NamedElementInterface;
use App\Entity\LogSystem\AbstractLogEntry;
use App\Entity\LogSystem\UserNotAllowedLogEntry;
use App\Entity\Parameters\AbstractParameter;
use App\Entity\Parts\PartLot;
use App\Entity\PriceInformations\Orderdetail;
use App\Entity\PriceInformations\Pricedetail;
use App\Entity\ProjectSystem\ProjectBOMEntry;
use App\Exceptions\EntityNotSupportedException;
use App\Repository\LogEntryRepository;
use App\Services\ElementTypeNameGenerator;
use App\Services\EntityURLGenerator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
class LogTargetHelper
{
protected EntityManagerInterface $em;
protected LogEntryRepository $entryRepository;
protected EntityURLGenerator $entityURLGenerator;
protected ElementTypeNameGenerator $elementTypeNameGenerator;
protected TranslatorInterface $translator;
public function __construct(EntityManagerInterface $entityManager, EntityURLGenerator $entityURLGenerator,
ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator)
{
$this->em = $entityManager;
$this->entryRepository = $entityManager->getRepository(AbstractLogEntry::class);
$this->entityURLGenerator = $entityURLGenerator;
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
$this->translator = $translator;
}
private function configureOptions(OptionsResolver $resolver): self
{
$resolver->setDefault('show_associated', true);
$resolver->setDefault('showAccessDeniedPath', true);
return $this;
}
public function formatTarget(AbstractLogEntry $context, array $options = []): string
{
$optionsResolver = new OptionsResolver();
$this->configureOptions($optionsResolver);
$options = $optionsResolver->resolve($options);
if ($context instanceof UserNotAllowedLogEntry && $options['showAccessDeniedPath']) {
return htmlspecialchars($context->getPath());
}
/** @var AbstractLogEntry $context */
$target = $this->entryRepository->getTargetElement($context);
//If the target is null and the context has a target, that means that the target was deleted. Show it that way.
if ($target === null) {
if ($context->hasTarget()) {
return $this->elementTypeNameGenerator->formatElementDeletedHTML($context->getTargetClass(),
$context->getTargetId());
}
//If no target is set, we can't do anything
return '';
}
//Otherwise we can return a label for the target
return $this->elementTypeNameGenerator->formatLabelHTMLForEntity($target, $options['show_associated']);
}
}

View file

@ -194,7 +194,7 @@ class TimeTravel
public function applyEntry(AbstractDBElement $element, TimeTravelInterface $logEntry): void
{
//Skip if this does not provide any info...
if (!$logEntry->hasOldDataInformations()) {
if (!$logEntry->hasOldDataInformation()) {
return;
}
if (!$element instanceof TimeStampableInterface) {

View file

@ -71,6 +71,8 @@ final class EntityExtension extends AbstractExtension
new TwigFunction('entity_type', [$this, 'getEntityType']),
/* Returns the URL to the given entity */
new TwigFunction('entity_url', [$this, 'generateEntityURL']),
/* Returns the URL to the given entity in timetravel mode */
new TwigFunction('timetravel_url', [$this->entityURLGenerator, 'timetravelURL']),
/* Generates a JSON array of the given tree */
new TwigFunction('tree_data', [$this, 'treeData']),

47
src/Twig/LogExtension.php Normal file
View file

@ -0,0 +1,47 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Twig;
use App\Services\LogSystem\LogDataFormatter;
use App\Services\LogSystem\LogDiffFormatter;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
final class LogExtension extends AbstractExtension
{
private LogDataFormatter $logDataFormatter;
private LogDiffFormatter $logDiffFormatter;
public function __construct(LogDataFormatter $logDataFormatter, LogDiffFormatter $logDiffFormatter)
{
$this->logDataFormatter = $logDataFormatter;
$this->logDiffFormatter = $logDiffFormatter;
}
public function getFunctions()
{
return [
new TwigFunction('format_log_data', [$this->logDataFormatter, 'formatData'], ['is_safe' => ['html']]),
new TwigFunction('format_log_diff', [$this->logDiffFormatter, 'formatDiff'], ['is_safe' => ['html']]),
];
}
}

View file

@ -0,0 +1,23 @@
{# @var entry \App\Entity\LogSystem\DatabaseUpdatedLogEntry #}
{% if entry.successful %}
<h5><span class="badge bg-success badge-success">
<i class="fa-solid fa-check"></i>
{% trans %}log.database_updated.success{% endtrans %}
</span></h5>
{% else %}
<h5><span class="badge bg-danger badge-danger">
<i class="fa-solid fa-xmark"></i>
{% trans %}log.database_updated.failed{% endtrans %}</span>
</h5>
{% endif %}
<span class="badge bg-secondary badge-secondary badge-pill" title="{% trans %}log.database_updated.old_version{% endtrans %}">
<i class="fa-solid fa-database"></i>
{{ entry.oldVersion }}
</span>
<i class="fa-solid fa-arrow-right-long"></i>
<span class="badge bg-primary badge-primary badge-pill" title="{% trans %}log.database_updated.new_version{% endtrans %}">
<i class="fa-solid fa-database"></i>
{{ entry.newVersion }}
</span>

View file

@ -0,0 +1,11 @@
{# @var entry \App\Entity\LogSystem\ElementCreatedLogEntry #}
{% import "log_system/details/helper.macro.html.twig" as log_helper %}
{{ log_helper.comment_field(entry) }}
{% if entry.creationInstockValue %}
<p>
<b>{% trans %}log.element_created.original_instock{% endtrans %}:</b>
{{ entry.creationInstockValue }}
</p>
{% endif %}

View file

@ -0,0 +1,8 @@
{# @var entry \App\Entity\LogSystem\ElementDeletedLogEntry #}
{% import "log_system/details/helper.macro.html.twig" as log_helper %}
<span class="badge badge-notice"></span>
{{ log_helper.comment_field(entry) }}
{{ log_helper.data_change_table(entry) }}

View file

@ -0,0 +1,11 @@
{# @var entry \App\Entity\LogSystem\ElementDeletedLogEntry #}
{% import "log_system/details/helper.macro.html.twig" as log_helper %}
{% if entry.undoEvent %}
<span class="badge badge-info bg-info">Test</span>
{% endif %}
{{ log_helper.comment_field(entry) }}
{{ log_helper.data_change_table(entry) }}

View file

@ -0,0 +1,9 @@
{# @var entry \App\Entity\LogSystem\UserLoginLogEntry #}
IP: &nbsp;
<span class="badge bg-primary badge-primary">
<i class="fa-solid fa-network-wired"></i>
{{ entry.iPAddress }}
</span>
<p class="text-muted">{% trans %}log.user_login.ip_anonymize_hint{% endtrans %}</p>

View file

@ -0,0 +1,9 @@
{# @var entry \App\Entity\LogSystem\UserLoginLogEntry #}
{% trans %}log.user_login.login_from_ip{% endtrans %}: &nbsp;
<span class="badge bg-primary badge-primary">
<i class="fa-solid fa-network-wired"></i>
{{ entry.iPAddress }}
</span>
<p class="text-muted">{% trans %}log.user_login.ip_anonymize_hint{% endtrans %}</p>

View file

@ -0,0 +1,4 @@
{# @var entry \App\Entity\LogSystem\UserNotAllowedLogEntry #}
{% trans %}log.user_not_allowed.unauthorized_access_attempt_to{% endtrans %}: &nbsp;<code>{{ entry.path }}</code>
<p class="text-muted">{% trans %}log.user_not_allowed.hint{% endtrans %}</p>

View file

@ -0,0 +1,140 @@
{% macro undo_buttons(entry, target_element) %}
{# @var entry \App\Entity\LogSystem\ElementEditedLogEntry|\App\Entity\LogSystem\ElementDeletedLogEntry entry #}
{% set disabled = not is_granted('revert_element', entry.targetClass) %}
{% if entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted')
or (entry is instanceof('App\\Entity\\LogSystem\\ElementDeletedLogEntry') and entry.hasOldDataInformation) %}
{% set icon = 'fa-trash-restore' %}
{% set title = 'log.undo.undelete'|trans %}
{% set title_short = 'log.undo.undelete.short'|trans %}
{% elseif entry is instanceof('App\\Entity\\LogSystem\\ElementCreatedLogEntry')
or (entry is instanceof('App\\Entity\\LogSystem\\ElementEditedLogEntry') and entry.hasOldDataInformation) %}
{% set icon = 'fa-undo' %}
{% set title = 'log.undo.undo'|trans %}
{% set title_short = 'log.undo.undo.short'|trans %}
{% endif %}
<form method="post" action="{{ path("log_undo") }}"
{{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
data-delete-title="{% trans %}log.undo.confirm_title{% endtrans %}"
data-delete-message="{% trans %}log.undo.confirm_message{% endtrans %}">
<input type="hidden" name="redirect_back" value="{{ app.request.requestUri }}">
<div class="btn-group btn-group-sm" role="group">
<button type="submit" class="btn btn-outline-secondary" name="undo" value="{{ entry.id }}" {% if disabled %}disabled{% endif %}>
<i class="fas fa-fw {{ icon }}" title="{{ title }}"></i> {{ title_short }}
</button>
<button type="submit" class="btn btn-outline-secondary" name="revert" value="{{ entry.id }}" {% if disabled %}disabled{% endif %}>
<i class="fas fa-fw fa-backward" title="{% trans %}log.undo.revert{% endtrans %}"></i> {{ 'log.undo.revert.short' | trans }}
</button>
{# View button #}
{% if target_element and ((attribute(entry, 'oldDataInformation') is defined and entry.oldDataInformation)
or entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted')) %}
<a class="btn btn-outline-secondary" href="{{ timetravel_url(target_element, entry.timestamp)}}"><i class="fas fa-fw fa-eye"></i>
{% trans %}log.view_version{% endtrans %}
</a>
{% endif %}
</div>
</form>
{% endmacro %}
{% macro comment_field(entry) %}
{# @var entry \App\Entity\Contracts\LogWithComment #}
<p class="mb-0">
<b>{% trans %}edit.log_comment{% endtrans %}:</b>
{% if entry.comment %}
{{ entry.comment }}
{% else %}
<span class="text-muted">{% trans %}log.no_comment{% endtrans %}</span>
{% endif %}
</p>
{% endmacro %}
{% macro data_change_table(entry) %}
{# @var entry \App\Entity\LogSystem\ElementEditedLogEntry|\App\Entity\LogSystem\ElementDeletedLogEntry entry #}
{% set fields, old_data, new_data = {}, {}, {} %}
{# For log entries where only the changed fields are saved, this is the last executed assignment #}
{% if attribute(entry, 'changedFieldInfo') is defined and entry.changedFieldsInfo %}
{% set fields = entry.changedFields %}
{% endif %}
{# For log entries, where we know the old data, this is the last exectuted assignment #}
{% if attribute(entry, 'oldDataInformation') is defined and entry.oldDataInformation %}
{# We have to use the keys of oldData here, as changedFields might not be available #}
{% set fields = entry.oldData | keys %}
{% set old_data = entry.oldData %}
{% endif %}
{# For log entries, where we have new data, we define it #}
{% if attribute(entry, 'newDataInformation') is defined and entry.newDataInformation %}
{# We have to use the keys of oldData here, as changedFields might not be available #}
{% set fields = entry.newData | keys %}
{% set new_data = entry.newData %}
{% endif %}
{% if fields is not empty %}
<table class="table table-hover table-striped table-sm table-bordered mt-2">
<thead>
<tr>
<th>{% trans %}log.element_changed.field{% endtrans %}</th>
{% if old_data is not empty %}
<th>{% trans %}log.element_changed.data_before{% endtrans %}</th>
{% endif %}
{% if new_data is not empty %}
<th>{% trans %}log.element_changed.data_after{% endtrans %}</th>
{% endif %}
{% if new_data is not empty and old_data is not empty %} {# Diff column #}
<th>{% trans %}log.element_changed.diff{% endtrans %}</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for field in fields %}
<tr>
<td title="{{ field }}">
{% set trans_key = 'log.element_edited.changed_fields.'~field %}
{# If the translation key is not found, the translation key is returned, and we dont show the translation #}
{% if trans_key|trans != trans_key %}
{{ ('log.element_edited.changed_fields.'~field) | trans }}
<span class="text-muted">({{ field }})</span>
{% else %}
{{ field }}
{% endif %}
</td>
{% if old_data is not empty %}
<td>
{% if old_data[field] is defined %}
{{ format_log_data(old_data[field], entry, field) }}
{% endif %}
</td>
{% endif %}
{% if new_data is not empty %}
<td>
{% if new_data[field] is defined %}
{{ format_log_data(new_data[field], entry, field) }}
{% endif %}
</td>
{% endif %}
{% if new_data is not empty and old_data is not empty %}
<td>
{% if new_data[field] is defined and old_data[field] is defined %}
{{ format_log_diff(old_data[field], new_data[field]) }}
{% endif %}
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endmacro %}

View file

@ -0,0 +1,115 @@
{% extends "main_card.html.twig" %}
{% import "helper.twig" as helper %}
{% import "log_system/details/helper.macro.html.twig" as log_helper %}
{% block title %}
{% trans %}log.details.title{% endtrans %}:
{{ ('log.type.' ~ log_entry.type) | trans }} ({{ log_entry.timestamp | format_datetime('short') }})
{% endblock %}
{% block card_title %}
<i class="fas fa-binoculars"></i>
{% trans %}log.details.title{% endtrans %}:
<i>{{ ('log.type.' ~ log_entry.type) | trans }}</i> ({{ log_entry.timestamp | format_datetime('short') }})
<span class="float-end">ID: {{ log_entry.iD }}</span>
{% endblock %}
{% block card_body %}
<table class="table table-striped table-hover mb-0 {{ log_level_helper.logLevelToTableColorClass(log_entry.levelString) }}">
<tr>
<td>{% trans %}log.timestamp{% endtrans %}</td>
<td>{{ log_entry.timestamp | format_datetime('full') }}</td>
</tr>
<tr>
<td>{% trans %}log.type{% endtrans %}</td>
<td>
{{ ('log.type.' ~ log_entry.type) | trans }}
{% if log_entry.type == 'part_stock_changed' %}
({{ ('log.part_stock_changed.' ~ log_entry.instockChangeType)|trans }})
{% endif %}
{% if log_entry is instanceof('App\\Entity\\Contracts\\LogWithEventUndoInterface') and log_entry.undoEvent %}
<b>({{ ('log.undo_mode.' ~ log_entry.undoMode)|trans }}: <a href="{{ path('log_details', {"id": log_entry.UndoEventID}) }}">#{{ log_entry.UndoEventID }}</a>)</b>
{% endif %}
</td>
</tr>
<tr>
<td>{% trans %}log.level{% endtrans %}</td>
<td>
<i class="fa-solid {{ log_level_helper.logLevelToIconClass(log_entry.levelString) }} fa-fw"></i>
{{ ('log.level.'~ log_entry.levelString)|trans }}
</td>
</tr>
<tr>
<td>{% trans %}log.user{% endtrans %}
<td>
{% if log_entry.cLIEntry %}
<i class="fa-solid fa-terminal"></i>
{{ log_entry.cLIUsername }} ({% trans %}log.cli_user{% endtrans %})
{% else %}
{% if log_entry.user %}
{{ helper.user_icon_link(log_entry.user) }} (@{{ log_entry.user.username }})
{% else %}
@{{ log_entry.username }} ({% trans %}log.target_deleted{% endtrans %}
{% endif %}
{% endif %}
</td>
</tr>
<tr>
<td>{% trans %}log.target{% endtrans %}</td>
<td>{{ target_html|raw }}</td>
</tr>
</table>
<div class="card-body">
<div class="row mb-2">
<div class="col-6">
{% if log_entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted')
or log_entry is instanceof('App\\Entity\\LogSystem\\ElementDeletedLogEntry')
or log_entry is instanceof('App\\Entity\\LogSystem\\ElementCreatedLogEntry')
or log_entry is instanceof('App\\Entity\\LogSystem\\ElementEditedLogEntry')
%}
{{ log_helper.undo_buttons(log_entry, target_element) }}
{% endif %}
</div>
<div class="col-6 text-end">
<form method="post" class="" action="{{ path('log_delete', {'id': log_entry.iD}) }}" {{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
data-delete-title="{% trans %}log.delete.message.title{% endtrans %}"
data-delete-message="{% trans %}log.delete.message{% endtrans %}">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ log_entry.id) }}">
<button type="submit" class="btn btn-sm btn-outline-danger" {% if not is_granted('delete', log_entry) %}disabled{% endif %}>
<i class="fa-solid fa-trash"></i>
{% trans %}log.details.delete_entry{% endtrans %}
</button>
</form>
</div>
</div>
{# This assignment is to improve autocomplete on the subpages, as PHPstorm ignores typehints for log_entry #}
{% set entry = log_entry %}
{% if log_entry is instanceof('App\\Entity\\LogSystem\\DatabaseUpdatedLogEntry') %}
{% include "log_system/details/_extra_database_updated.html.twig" %}
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\ElementCreatedLogEntry') %}
{% include "log_system/details/_extra_element_created.html.twig" %}
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\ElementEditedLogEntry') %}
{% include "log_system/details/_extra_element_edited.html.twig" %}
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\ElementDeletedLogEntry') %}
{% include "log_system/details/_extra_element_deleted.html.twig" %}
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\UserLoginLogEntry')
or log_entry is instanceof('App\\Entity\\LogSystem\\UserLogoutLogEntry') %}
{% include "log_system/details/_extra_user_login.html.twig" %}
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\UserNotAllowedLogEntry') %}
{% include "log_system/details/_extra_user_not_allowed.html.twig" %}
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\SecurityEventLogEntry') %}
{% include "log_system/details/_extra_security_event.html.twig" %}
{% else %}
{{ extra_html | raw }}
{% endif %}
</div>
{% endblock %}

File diff suppressed because it is too large Load diff

View file

@ -11289,6 +11289,54 @@ Element 3</target>
<target>Show email on public profile page</target>
</segment>
</unit>
<unit id="4rkjIk2" name="log.details.title">
<segment>
<source>log.details.title</source>
<target>Log details</target>
</segment>
</unit>
<unit id="aeYMkHS" name="log.user_login.login_from_ip">
<segment>
<source>log.user_login.login_from_ip</source>
<target>Login from IP address</target>
</segment>
</unit>
<unit id="9jOklgS" name="log.user_login.ip_anonymize_hint">
<segment>
<source>log.user_login.ip_anonymize_hint</source>
<target>If the last digits of the IP address are missing, then the GPDR mode is enabled, in which IP addresses are anynomized.</target>
</segment>
</unit>
<unit id="kaMyDVi" name="log.user_not_allowed.unauthorized_access_attempt_to">
<segment>
<source>log.user_not_allowed.unauthorized_access_attempt_to</source>
<target>Unauthorized access attempt to page</target>
</segment>
</unit>
<unit id="EibB1Wh" name="log.user_not_allowed.hint">
<segment>
<source>log.user_not_allowed.hint</source>
<target>The request was blocked. No action should be required.</target>
</segment>
</unit>
<unit id="JVE17kW" name="log.no_comment">
<segment>
<source>log.no_comment</source>
<target>No comment</target>
</segment>
</unit>
<unit id="5xvPvME" name="log.element_changed.field">
<segment>
<source>log.element_changed.field</source>
<target>Field</target>
</segment>
</unit>
<unit id="vufWYhV" name="log.element_changed.data_before">
<segment>
<source>log.element_changed.data_before</source>
<target>Data before change</target>
</segment>
</unit>
<unit id="qk2u9Qg" name="error_table.error">
<segment>
<source>error_table.error</source>
@ -11301,5 +11349,77 @@ Element 3</target>
<target>Invalid Regex expression</target>
</segment>
</unit>
<unit id="VKPOkNO" name="log.element_changed.data_after">
<segment>
<source>log.element_changed.data_after</source>
<target>Data after change</target>
</segment>
</unit>
<unit id="DiNGTl8" name="log.element_changed.diff">
<segment>
<source>log.element_changed.diff</source>
<target>Diff</target>
</segment>
</unit>
<unit id="OB_fVDI" name="log.undo.undo.short">
<segment>
<source>log.undo.undo.short</source>
<target>Undo</target>
</segment>
</unit>
<unit id="AvoT6DL" name="log.undo.revert.short">
<segment>
<source>log.undo.revert.short</source>
<target>Revert to this timestamp</target>
</segment>
</unit>
<unit id="YdXQd2_" name="log.view_version">
<segment>
<source>log.view_version</source>
<target>View version</target>
</segment>
</unit>
<unit id="l47W4kt" name="log.undo.undelete.short">
<segment>
<source>log.undo.undelete.short</source>
<target>Undelete</target>
</segment>
</unit>
<unit id="PDJYeqj" name="log.element_edited.changed_fields.id">
<segment>
<source>log.element_edited.changed_fields.id</source>
<target>ID</target>
</segment>
</unit>
<unit id="cQTNNI7" name="log.element_edited.changed_fields.id_owner">
<segment>
<source>log.element_edited.changed_fields.id_owner</source>
<target>Owner</target>
</segment>
</unit>
<unit id="h1eBlp8" name="log.element_edited.changed_fields.parent_id">
<segment>
<source>log.element_edited.changed_fields.parent_id</source>
<target>Parent</target>
</segment>
</unit>
<unit id="GUthgcU" name="log.details.delete_entry">
<segment>
<source>log.details.delete_entry</source>
<target>Delete log entry</target>
</segment>
</unit>
<unit id="Wv0WAmO" name="log.delete.message.title">
<segment>
<source>log.delete.message.title</source>
<target>Do you really want to delete the log entry?</target>
</segment>
</unit>
<unit id="5tbpaLR" name="log.delete.message">
<segment>
<source>log.delete.message</source>
<target>If this is an element history entry, this breaks the element history! This can lead to unexpected results when using the time travel function.</target>
</segment>
</unit>
</file>
</xliff>

View file

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="de">
<file id="security.en">
<file id="security.de">
<unit id="aazoCks" name="user.login_error.user_disabled">
<segment state="translated">
<segment>
<source>user.login_error.user_disabled</source>
<target>Ihr Account ist deaktiviert! Kontaktiere einen Administrator, wenn Sie denken, dass dies ein Fehler ist.</target>
</segment>
</unit>
<unit id="Dpb9AmY" name="saml.error.cannot_login_local_user_per_saml">
<segment state="translated">
<segment>
<source>saml.error.cannot_login_local_user_per_saml</source>
<target>Sie können sich per SSO nicht als lokaler Nutzer einloggen! Nutzen Sie stattdessen ihr lokales Passwort.</target>
</segment>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="de">
<file id="validators.en">
<file id="validators.de">
<unit id="xevSdCK" name="part.master_attachment.must_be_picture">
<notes>
<note category="file-source" priority="1">Part-DB1\src\Entity\Attachments\AttachmentContainingDBElement.php:0</note>
@ -37,7 +37,7 @@
<note priority="1">Part-DB1\src\Entity\UserSystem\Group.php:0</note>
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
</notes>
<segment state="translated">
<segment>
<source>part.master_attachment.must_be_picture</source>
<target>Der Vorschauanhang muss ein gültiges Bild sein!</target>
</segment>
@ -82,7 +82,7 @@
<note priority="1">src\Entity\StructuralDBElement.php:0</note>
<note priority="1">src\Entity\Supplier.php:0</note>
</notes>
<segment state="translated">
<segment>
<source>structural.entity.unique_name</source>
<target>Es kann auf jeder Ebene nur ein Objekt mit dem gleichem Namen geben!</target>
</segment>
@ -102,7 +102,7 @@
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
</notes>
<segment state="translated">
<segment>
<source>parameters.validator.min_lesser_typical</source>
<target>Wert muss kleiner oder gleich als der typische Wert sein ({{ compared_value }}).</target>
</segment>
@ -122,7 +122,7 @@
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
</notes>
<segment state="translated">
<segment>
<source>parameters.validator.min_lesser_max</source>
<target>Wert muss kleiner als der Maximalwert sein ({{ compared_value }}).</target>
</segment>
@ -142,7 +142,7 @@
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
</notes>
<segment state="translated">
<segment>
<source>parameters.validator.max_greater_typical</source>
<target>Wert muss größer oder gleich dem typischen Wert sein ({{ compared_value }}).</target>
</segment>
@ -152,7 +152,7 @@
<note category="file-source" priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
</notes>
<segment state="translated">
<segment>
<source>validator.user.username_already_used</source>
<target>Es existiert bereits ein Benutzer mit diesem Namen.</target>
</segment>
@ -162,7 +162,7 @@
<note category="file-source" priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
</notes>
<segment state="translated">
<segment>
<source>user.invalid_username</source>
<target>Der Benutzername darf nur Buchstaben, Zahlen, Unterstriche, Punkte, Plus- oder Minuszeichen enthalten.</target>
</segment>
@ -171,7 +171,7 @@
<notes>
<note category="state" priority="1">obsolete</note>
</notes>
<segment state="translated">
<segment>
<source>validator.noneofitschild.self</source>
<target>Ein Element kann nicht sein eigenenes übergeordnetes Element sein!</target>
</segment>
@ -180,127 +180,127 @@
<notes>
<note category="state" priority="1">obsolete</note>
</notes>
<segment state="final">
<segment>
<source>validator.noneofitschild.children</source>
<target>Ein Kindelement kann nicht das übergeordnete Element sein!</target>
</segment>
</unit>
<unit id="ayNr6QK" name="validator.select_valid_category">
<segment state="translated">
<segment>
<source>validator.select_valid_category</source>
<target>Bitte wählen Sie eine gültige Kategorie.</target>
</segment>
</unit>
<unit id="6vIlN5q" name="validator.part_lot.only_existing">
<segment state="translated">
<segment>
<source>validator.part_lot.only_existing</source>
<target>Der Lagerort wurde als "nur bestehende Teile" markiert, daher können keine neuen Teile hinzugefügt werden.</target>
</segment>
</unit>
<unit id="3xoKOIS" name="validator.part_lot.location_full.no_increase">
<segment state="translated">
<segment>
<source>validator.part_lot.location_full.no_increase</source>
<target>Lagerort ist voll. Bestand kann nicht erhöht werden (neuer Wert muss kleiner sein als {{old_amount}}).</target>
</segment>
</unit>
<unit id="R6Ov4Yt" name="validator.part_lot.location_full">
<segment state="final">
<segment>
<source>validator.part_lot.location_full</source>
<target>Der Lagerort ist voll, daher können keine neue Teile hinzugefügt werden.</target>
</segment>
</unit>
<unit id="BNQk2e7" name="validator.part_lot.single_part">
<segment state="final">
<segment>
<source>validator.part_lot.single_part</source>
<target>Der Lagerort wurde als "Nur ein Bauteil" markiert, daher kann kein neues Bauteil hinzugefügt werden.</target>
</segment>
</unit>
<unit id="4gPskOG" name="validator.attachment.must_not_be_null">
<segment state="translated">
<segment>
<source>validator.attachment.must_not_be_null</source>
<target>Sie müssen ein Dateitypen auswählen!</target>
</segment>
</unit>
<unit id="cDDVrWT" name="validator.orderdetail.supplier_must_not_be_null">
<segment state="translated">
<segment>
<source>validator.orderdetail.supplier_must_not_be_null</source>
<target>Sie müssen einen Lieferanten auswählen!</target>
</segment>
</unit>
<unit id="k5DDdB4" name="validator.measurement_unit.use_si_prefix_needs_unit">
<segment state="translated">
<segment>
<source>validator.measurement_unit.use_si_prefix_needs_unit</source>
<target>Um SI-Prefixe zu aktivieren, müssen Sie einen Einheitensymbol setzen!</target>
</segment>
</unit>
<unit id="DuzIOCr" name="part.ipn.must_be_unique">
<segment state="translated">
<segment>
<source>part.ipn.must_be_unique</source>
<target>Die Internal Part Number (IPN) muss einzigartig sein. Der Wert {{value}} wird bereits benutzt!</target>
</segment>
</unit>
<unit id="Z4Kuuo2" name="validator.project.bom_entry.name_or_part_needed">
<segment state="translated">
<segment>
<source>validator.project.bom_entry.name_or_part_needed</source>
<target>Sie müssen ein Bauteil auswählen, oder einen Namen für ein nicht-Bauteil BOM-Eintrag setzen!</target>
</segment>
</unit>
<unit id="WF_v4ih" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<segment>
<source>project.bom_entry.name_already_in_bom</source>
<target>Es gibt bereits einen BOM Eintrag mit diesem Namen!</target>
</segment>
</unit>
<unit id="5v4p85H" name="project.bom_entry.part_already_in_bom">
<segment state="translated">
<segment>
<source>project.bom_entry.part_already_in_bom</source>
<target>Dieses Bauteil existiert bereits in der BOM!</target>
</segment>
</unit>
<unit id="3lM32Tw" name="project.bom_entry.mountnames_quantity_mismatch">
<segment state="translated">
<segment>
<source>project.bom_entry.mountnames_quantity_mismatch</source>
<target>Die Anzahl der Bestückungsnamen muss mit der Menge der zu bestückenden Bauteile übereinstimmen!</target>
</segment>
</unit>
<unit id="x47D5WT" name="project.bom_entry.can_not_add_own_builds_part">
<segment state="translated">
<segment>
<source>project.bom_entry.can_not_add_own_builds_part</source>
<target>Die BOM eines Projektes kann nicht das eigene Produktionsbauteil enthalten!</target>
</segment>
</unit>
<unit id="2x2XDI_" name="project.bom_has_to_include_all_subelement_parts">
<segment state="translated">
<segment>
<source>project.bom_has_to_include_all_subelement_parts</source>
<target>Die Projekt-BOM muss alle Produktionsbauteile der Unterprojekte enthalten. Bauteil %part_name% des Projektes %project_name% fehlt!</target>
</segment>
</unit>
<unit id="U9b1EzD" name="project.bom_entry.price_not_allowed_on_parts">
<segment state="translated">
<segment>
<source>project.bom_entry.price_not_allowed_on_parts</source>
<target>Sie können keinen Preis für Bauteil-BOM-Einträge definieren. Definieren Sie die Preise stattdessen auf dem Bauteil.</target>
</segment>
</unit>
<unit id="ID056SR" name="validator.project_build.lot_bigger_than_needed">
<segment state="translated">
<segment>
<source>validator.project_build.lot_bigger_than_needed</source>
<target>Sie haben mehr zur Entnahme ausgewählt als notwendig. Entfernen Sie die überflüssige Anzahl.</target>
</segment>
</unit>
<unit id="6hV5UqD" name="validator.project_build.lot_smaller_than_needed">
<segment state="translated">
<segment>
<source>validator.project_build.lot_smaller_than_needed</source>
<target>Sie haben weniger zur Entnahme ausgewählt, als zum Bau notwendig ist! Fügen Sie mehr hinzu.</target>
</segment>
</unit>
<unit id="G9ZKt.4" name="part.name.must_match_category_regex">
<segment state="translated">
<segment>
<source>part.name.must_match_category_regex</source>
<target>Der Bauteilename entspricht nicht dem regulären Ausdruck, der von der Kategorie vorgegeben wurde: %regex%</target>
</segment>
</unit>
<unit id="m8kMFhf" name="validator.attachment.name_not_blank">
<segment state="translated">
<segment>
<source>validator.attachment.name_not_blank</source>
<target>Wählen Sie einen Wert, oder laden Sie eine Datei hoch, um dessen Dateiname automatisch als Namen für diesen Anhang zu nutzen.</target>
</segment>

505
yarn.lock
View file

@ -1327,115 +1327,115 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
"@esbuild/android-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz#4aa8d8afcffb4458736ca9b32baa97d7cb5861ea"
integrity sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==
"@esbuild/android-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
integrity sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==
"@esbuild/android-arm@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.18.tgz#74a7e95af4ee212ebc9db9baa87c06a594f2a427"
integrity sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==
"@esbuild/android-arm@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz#5898f7832c2298bc7d0ab53701c57beb74d78b4d"
integrity sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==
"@esbuild/android-x64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.18.tgz#1dcd13f201997c9fe0b204189d3a0da4eb4eb9b6"
integrity sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==
"@esbuild/android-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz#658368ef92067866d95fb268719f98f363d13ae1"
integrity sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==
"@esbuild/darwin-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz#444f3b961d4da7a89eb9bd35cfa4415141537c2a"
integrity sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==
"@esbuild/darwin-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz#584c34c5991b95d4d48d333300b1a4e2ff7be276"
integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==
"@esbuild/darwin-x64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz#a6da308d0ac8a498c54d62e0b2bfb7119b22d315"
integrity sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==
"@esbuild/darwin-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz#7751d236dfe6ce136cce343dce69f52d76b7f6cb"
integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==
"@esbuild/freebsd-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz#b83122bb468889399d0d63475d5aea8d6829c2c2"
integrity sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==
"@esbuild/freebsd-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz#cacd171665dd1d500f45c167d50c6b7e539d5fd2"
integrity sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==
"@esbuild/freebsd-x64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz#af59e0e03fcf7f221b34d4c5ab14094862c9c864"
integrity sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==
"@esbuild/freebsd-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz#0769456eee2a08b8d925d7c00b79e861cb3162e4"
integrity sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==
"@esbuild/linux-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz#8551d72ba540c5bce4bab274a81c14ed01eafdcf"
integrity sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==
"@esbuild/linux-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz#38e162ecb723862c6be1c27d6389f48960b68edb"
integrity sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==
"@esbuild/linux-arm@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz#e09e76e526df4f665d4d2720d28ff87d15cdf639"
integrity sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==
"@esbuild/linux-arm@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz#1a2cd399c50040184a805174a6d89097d9d1559a"
integrity sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==
"@esbuild/linux-ia32@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz#47878860ce4fe73a36fd8627f5647bcbbef38ba4"
integrity sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==
"@esbuild/linux-ia32@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz#e28c25266b036ce1cabca3c30155222841dc035a"
integrity sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==
"@esbuild/linux-loong64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz#3f8fbf5267556fc387d20b2e708ce115de5c967a"
integrity sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==
"@esbuild/linux-loong64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz#0f887b8bb3f90658d1a0117283e55dbd4c9dcf72"
integrity sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==
"@esbuild/linux-mips64el@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz#9d896d8f3c75f6c226cbeb840127462e37738226"
integrity sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==
"@esbuild/linux-mips64el@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz#f5d2a0b8047ea9a5d9f592a178ea054053a70289"
integrity sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==
"@esbuild/linux-ppc64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz#3d9deb60b2d32c9985bdc3e3be090d30b7472783"
integrity sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==
"@esbuild/linux-ppc64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz#876590e3acbd9fa7f57a2c7d86f83717dbbac8c7"
integrity sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==
"@esbuild/linux-riscv64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz#8a943cf13fd24ff7ed58aefb940ef178f93386bc"
integrity sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==
"@esbuild/linux-riscv64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz#7f49373df463cd9f41dc34f9b2262d771688bf09"
integrity sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==
"@esbuild/linux-s390x@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz#66cb01f4a06423e5496facabdce4f7cae7cb80e5"
integrity sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==
"@esbuild/linux-s390x@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz#e2afd1afcaf63afe2c7d9ceacd28ec57c77f8829"
integrity sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==
"@esbuild/linux-x64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz#23c26050c6c5d1359c7b774823adc32b3883b6c9"
integrity sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==
"@esbuild/linux-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4"
integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==
"@esbuild/netbsd-x64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz#789a203d3115a52633ff6504f8cbf757f15e703b"
integrity sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==
"@esbuild/netbsd-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz#c29fb2453c6b7ddef9a35e2c18b37bda1ae5c462"
integrity sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==
"@esbuild/openbsd-x64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz#d7b998a30878f8da40617a10af423f56f12a5e90"
integrity sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==
"@esbuild/openbsd-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz#95e75a391403cb10297280d524d66ce04c920691"
integrity sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==
"@esbuild/sunos-x64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz#ecad0736aa7dae07901ba273db9ef3d3e93df31f"
integrity sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==
"@esbuild/sunos-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz#722eaf057b83c2575937d3ffe5aeb16540da7273"
integrity sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==
"@esbuild/win32-arm64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz#58dfc177da30acf956252d7c8ae9e54e424887c4"
integrity sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==
"@esbuild/win32-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz#9aa9dc074399288bdcdd283443e9aeb6b9552b6f"
integrity sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==
"@esbuild/win32-ia32@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz#340f6163172b5272b5ae60ec12c312485f69232b"
integrity sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==
"@esbuild/win32-ia32@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz#95ad43c62ad62485e210f6299c7b2571e48d2b03"
integrity sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==
"@esbuild/win32-x64@0.17.18":
version "0.17.18"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz#3a8e57153905308db357fd02f57c180ee3a0a1fa"
integrity sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==
"@esbuild/win32-x64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061"
integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==
"@foliojs-fork/fontkit@^1.9.1":
version "1.9.1"
@ -1752,9 +1752,9 @@
integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==
"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33":
version "4.17.34"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz#c119e85b75215178bc127de588e93100698ab4cc"
integrity sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==
version "4.17.35"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f"
integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==
dependencies:
"@types/node" "*"
"@types/qs" "*"
@ -1826,9 +1826,9 @@
integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
"@types/node@*":
version "20.1.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.1.0.tgz#258805edc37c327cf706e64c6957f241ca4c4c20"
integrity sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==
version "20.1.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.1.4.tgz#83f148d2d1f5fe6add4c53358ba00d97fc4cdb71"
integrity sha512-At4pvmIOki8yuwLtd7BNHl3CiWNbtclUbNtScGx4OHfBd4/oWoJC8KRCIxXwkdndzhxOsPXihrsOoydxBjlE9Q==
"@types/parse-json@^4.0.0":
version "4.0.0"
@ -1904,125 +1904,125 @@
dependencies:
"@types/yargs-parser" "*"
"@webassemblyjs/ast@1.11.5", "@webassemblyjs/ast@^1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.5.tgz#6e818036b94548c1fb53b754b5cae3c9b208281c"
integrity sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==
"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==
dependencies:
"@webassemblyjs/helper-numbers" "1.11.5"
"@webassemblyjs/helper-wasm-bytecode" "1.11.5"
"@webassemblyjs/helper-numbers" "1.11.6"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/floating-point-hex-parser@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz#e85dfdb01cad16b812ff166b96806c050555f1b4"
integrity sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ==
"@webassemblyjs/floating-point-hex-parser@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431"
integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==
"@webassemblyjs/helper-api-error@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz#1e82fa7958c681ddcf4eabef756ce09d49d442d1"
integrity sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA==
"@webassemblyjs/helper-api-error@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768"
integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==
"@webassemblyjs/helper-buffer@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz#91381652ea95bb38bbfd270702351c0c89d69fba"
integrity sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg==
"@webassemblyjs/helper-buffer@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093"
integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==
"@webassemblyjs/helper-numbers@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz#23380c910d56764957292839006fecbe05e135a9"
integrity sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA==
"@webassemblyjs/helper-numbers@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5"
integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==
dependencies:
"@webassemblyjs/floating-point-hex-parser" "1.11.5"
"@webassemblyjs/helper-api-error" "1.11.5"
"@webassemblyjs/floating-point-hex-parser" "1.11.6"
"@webassemblyjs/helper-api-error" "1.11.6"
"@xtuc/long" "4.2.2"
"@webassemblyjs/helper-wasm-bytecode@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz#e258a25251bc69a52ef817da3001863cc1c24b9f"
integrity sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA==
"@webassemblyjs/helper-wasm-bytecode@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9"
integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==
"@webassemblyjs/helper-wasm-section@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz#966e855a6fae04d5570ad4ec87fbcf29b42ba78e"
integrity sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA==
"@webassemblyjs/helper-wasm-section@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577"
integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==
dependencies:
"@webassemblyjs/ast" "1.11.5"
"@webassemblyjs/helper-buffer" "1.11.5"
"@webassemblyjs/helper-wasm-bytecode" "1.11.5"
"@webassemblyjs/wasm-gen" "1.11.5"
"@webassemblyjs/ast" "1.11.6"
"@webassemblyjs/helper-buffer" "1.11.6"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/wasm-gen" "1.11.6"
"@webassemblyjs/ieee754@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz#b2db1b33ce9c91e34236194c2b5cba9b25ca9d60"
integrity sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg==
"@webassemblyjs/ieee754@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a"
integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==
dependencies:
"@xtuc/ieee754" "^1.2.0"
"@webassemblyjs/leb128@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.5.tgz#482e44d26b6b949edf042a8525a66c649e38935a"
integrity sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ==
"@webassemblyjs/leb128@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7"
integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==
dependencies:
"@xtuc/long" "4.2.2"
"@webassemblyjs/utf8@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.5.tgz#83bef94856e399f3740e8df9f63bc47a987eae1a"
integrity sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ==
"@webassemblyjs/utf8@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a"
integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==
"@webassemblyjs/wasm-edit@^1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz#93ee10a08037657e21c70de31c47fdad6b522b2d"
integrity sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ==
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab"
integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==
dependencies:
"@webassemblyjs/ast" "1.11.5"
"@webassemblyjs/helper-buffer" "1.11.5"
"@webassemblyjs/helper-wasm-bytecode" "1.11.5"
"@webassemblyjs/helper-wasm-section" "1.11.5"
"@webassemblyjs/wasm-gen" "1.11.5"
"@webassemblyjs/wasm-opt" "1.11.5"
"@webassemblyjs/wasm-parser" "1.11.5"
"@webassemblyjs/wast-printer" "1.11.5"
"@webassemblyjs/ast" "1.11.6"
"@webassemblyjs/helper-buffer" "1.11.6"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/helper-wasm-section" "1.11.6"
"@webassemblyjs/wasm-gen" "1.11.6"
"@webassemblyjs/wasm-opt" "1.11.6"
"@webassemblyjs/wasm-parser" "1.11.6"
"@webassemblyjs/wast-printer" "1.11.6"
"@webassemblyjs/wasm-gen@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz#ceb1c82b40bf0cf67a492c53381916756ef7f0b1"
integrity sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA==
"@webassemblyjs/wasm-gen@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268"
integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==
dependencies:
"@webassemblyjs/ast" "1.11.5"
"@webassemblyjs/helper-wasm-bytecode" "1.11.5"
"@webassemblyjs/ieee754" "1.11.5"
"@webassemblyjs/leb128" "1.11.5"
"@webassemblyjs/utf8" "1.11.5"
"@webassemblyjs/ast" "1.11.6"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/ieee754" "1.11.6"
"@webassemblyjs/leb128" "1.11.6"
"@webassemblyjs/utf8" "1.11.6"
"@webassemblyjs/wasm-opt@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz#b52bac29681fa62487e16d3bb7f0633d5e62ca0a"
integrity sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw==
"@webassemblyjs/wasm-opt@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2"
integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==
dependencies:
"@webassemblyjs/ast" "1.11.5"
"@webassemblyjs/helper-buffer" "1.11.5"
"@webassemblyjs/wasm-gen" "1.11.5"
"@webassemblyjs/wasm-parser" "1.11.5"
"@webassemblyjs/ast" "1.11.6"
"@webassemblyjs/helper-buffer" "1.11.6"
"@webassemblyjs/wasm-gen" "1.11.6"
"@webassemblyjs/wasm-parser" "1.11.6"
"@webassemblyjs/wasm-parser@1.11.5", "@webassemblyjs/wasm-parser@^1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz#7ba0697ca74c860ea13e3ba226b29617046982e2"
integrity sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew==
"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1"
integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==
dependencies:
"@webassemblyjs/ast" "1.11.5"
"@webassemblyjs/helper-api-error" "1.11.5"
"@webassemblyjs/helper-wasm-bytecode" "1.11.5"
"@webassemblyjs/ieee754" "1.11.5"
"@webassemblyjs/leb128" "1.11.5"
"@webassemblyjs/utf8" "1.11.5"
"@webassemblyjs/ast" "1.11.6"
"@webassemblyjs/helper-api-error" "1.11.6"
"@webassemblyjs/helper-wasm-bytecode" "1.11.6"
"@webassemblyjs/ieee754" "1.11.6"
"@webassemblyjs/leb128" "1.11.6"
"@webassemblyjs/utf8" "1.11.6"
"@webassemblyjs/wast-printer@1.11.5":
version "1.11.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz#7a5e9689043f3eca82d544d7be7a8e6373a6fa98"
integrity sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA==
"@webassemblyjs/wast-printer@1.11.6":
version "1.11.6"
resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20"
integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==
dependencies:
"@webassemblyjs/ast" "1.11.5"
"@webassemblyjs/ast" "1.11.6"
"@xtuc/long" "4.2.2"
"@webpack-cli/configtest@^1.2.0":
@ -2074,9 +2074,9 @@ acorn-globals@^6.0.0:
acorn-walk "^7.1.1"
acorn-import-assertions@^1.7.6:
version "1.8.0"
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9"
integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==
version "1.9.0"
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac"
integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==
acorn-node@^1.3.0:
version "1.8.2"
@ -2524,9 +2524,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001449:
version "1.0.30001485"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001485.tgz#026bb7319f1e483391872dc303a973d4f513f619"
integrity sha512-8aUpZ7sjhlOyiNsg+pgcrTTPUXKh+rg544QYHSvQErljVEKJzvkYkCR/hUFeeVoEfTToUtY9cUKNRC7+c45YkA==
version "1.0.30001487"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001487.tgz#d882d1a34d89c11aea53b8cdc791931bdab5fe1b"
integrity sha512-83564Z3yWGqXsh2vaH/mhXfEM0wX+NlBCm1jYHOb97TrTWJEmPTccZgeLTPBUUb0PNVo+oomb7wkimZBIERClA==
chalk@^2.0.0, chalk@^2.3.2:
version "2.4.2"
@ -3312,9 +3312,9 @@ ee-first@1.1.1:
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
electron-to-chromium@^1.4.284:
version "1.4.385"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.385.tgz#1afd8d6280d510145148777b899ff481c65531ff"
integrity sha512-L9zlje9bIw0h+CwPQumiuVlfMcV4boxRjFIWDcLfFqTZNbkwOExBzfmswytHawObQX4OUhtNv8gIiB21kOurIg==
version "1.4.394"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.394.tgz#989abe104a40366755648876cde2cdeda9f31133"
integrity sha512-0IbC2cfr8w5LxTz+nmn2cJTGafsK9iauV2r5A5scfzyovqLrxuLoxOHE5OBobP3oVIggJT+0JfKnw9sm87c8Hw==
emoji-regex@^8.0.0:
version "8.0.0"
@ -3336,10 +3336,10 @@ encodeurl@~1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
enhanced-resolve@^5.0.0, enhanced-resolve@^5.13.0:
version "5.13.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz#26d1ecc448c02de997133217b5c1053f34a0a275"
integrity sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==
enhanced-resolve@^5.0.0, enhanced-resolve@^5.14.0:
version "5.14.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz#0b6c676c8a3266c99fa281e4433a706f5c0c61c4"
integrity sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==
dependencies:
graceful-fs "^4.2.4"
tapable "^2.2.0"
@ -3434,32 +3434,32 @@ esbuild-loader@^3.0.1:
webpack-sources "^1.4.3"
esbuild@^0.17.6:
version "0.17.18"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.18.tgz#f4f8eb6d77384d68cd71c53eb6601c7efe05e746"
integrity sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==
version "0.17.19"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955"
integrity sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==
optionalDependencies:
"@esbuild/android-arm" "0.17.18"
"@esbuild/android-arm64" "0.17.18"
"@esbuild/android-x64" "0.17.18"
"@esbuild/darwin-arm64" "0.17.18"
"@esbuild/darwin-x64" "0.17.18"
"@esbuild/freebsd-arm64" "0.17.18"
"@esbuild/freebsd-x64" "0.17.18"
"@esbuild/linux-arm" "0.17.18"
"@esbuild/linux-arm64" "0.17.18"
"@esbuild/linux-ia32" "0.17.18"
"@esbuild/linux-loong64" "0.17.18"
"@esbuild/linux-mips64el" "0.17.18"
"@esbuild/linux-ppc64" "0.17.18"
"@esbuild/linux-riscv64" "0.17.18"
"@esbuild/linux-s390x" "0.17.18"
"@esbuild/linux-x64" "0.17.18"
"@esbuild/netbsd-x64" "0.17.18"
"@esbuild/openbsd-x64" "0.17.18"
"@esbuild/sunos-x64" "0.17.18"
"@esbuild/win32-arm64" "0.17.18"
"@esbuild/win32-ia32" "0.17.18"
"@esbuild/win32-x64" "0.17.18"
"@esbuild/android-arm" "0.17.19"
"@esbuild/android-arm64" "0.17.19"
"@esbuild/android-x64" "0.17.19"
"@esbuild/darwin-arm64" "0.17.19"
"@esbuild/darwin-x64" "0.17.19"
"@esbuild/freebsd-arm64" "0.17.19"
"@esbuild/freebsd-x64" "0.17.19"
"@esbuild/linux-arm" "0.17.19"
"@esbuild/linux-arm64" "0.17.19"
"@esbuild/linux-ia32" "0.17.19"
"@esbuild/linux-loong64" "0.17.19"
"@esbuild/linux-mips64el" "0.17.19"
"@esbuild/linux-ppc64" "0.17.19"
"@esbuild/linux-riscv64" "0.17.19"
"@esbuild/linux-s390x" "0.17.19"
"@esbuild/linux-x64" "0.17.19"
"@esbuild/netbsd-x64" "0.17.19"
"@esbuild/openbsd-x64" "0.17.19"
"@esbuild/sunos-x64" "0.17.19"
"@esbuild/win32-arm64" "0.17.19"
"@esbuild/win32-ia32" "0.17.19"
"@esbuild/win32-x64" "0.17.19"
escalade@^3.1.1:
version "3.1.1"
@ -3832,12 +3832,13 @@ get-assigned-identifiers@^1.1.0:
integrity sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==
get-intrinsic@^1.0.2, get-intrinsic@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f"
integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==
version "1.2.1"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82"
integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
has-proto "^1.0.1"
has-symbols "^1.0.3"
get-port@^3.1.0:
@ -3955,6 +3956,11 @@ has-property-descriptors@^1.0.0:
dependencies:
get-intrinsic "^1.1.1"
has-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
has-symbols@^1.0.2, has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
@ -4370,9 +4376,9 @@ jest-worker@^29.1.2:
supports-color "^8.0.0"
jquery@>=1.7, jquery@^3.5.1:
version "3.6.4"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.4.tgz#ba065c188142100be4833699852bf7c24dc0252f"
integrity sha512-v28EW9DWDFpzcD9O5iyJXg3R3+q+mET5JhnjJzQUZMHOv67bpSIHq81GEYpPNZHG+XXHsfSme3nxp/hndKEcsQ==
version "3.7.0"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.0.tgz#fe2c01a05da500709006d8790fe21c8a39d75612"
integrity sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==
js-tokens@^4.0.0:
version "4.0.0"
@ -4422,6 +4428,11 @@ jsesc@~0.5.0:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==
json-formatter-js@^2.3.4:
version "2.3.4"
resolved "https://registry.yarnpkg.com/json-formatter-js/-/json-formatter-js-2.3.4.tgz#0b49b6facd0d54cb220eb65988157c0977a85c6f"
integrity sha512-gmAzYRtPRmYzeAT4T7+t3NhTF89JOAIioCVDddl9YDb3ls3kWcskirafw/MZGJaRhEU6fRimGJHl7CC7gaAI2Q==
json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
@ -5826,9 +5837,9 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.8:
version "7.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0"
integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==
version "7.5.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.1.tgz#c90c4d631cf74720e46b21c1d37ea07edfab91ec"
integrity sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==
dependencies:
lru-cache "^6.0.0"
@ -6250,20 +6261,20 @@ terser-webpack-plugin@^4.2.3:
webpack-sources "^1.4.3"
terser-webpack-plugin@^5.3.0, terser-webpack-plugin@^5.3.7:
version "5.3.7"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz#ef760632d24991760f339fe9290deb936ad1ffc7"
integrity sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==
version "5.3.8"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.8.tgz#415e03d2508f7de63d59eca85c5d102838f06610"
integrity sha512-WiHL3ElchZMsK27P8uIUh4604IgJyAW47LVXGbEoB21DbQcZ+OuMpGjVYnEUaqcWM6dO8uS2qUbA7LSCWqvsbg==
dependencies:
"@jridgewell/trace-mapping" "^0.3.17"
jest-worker "^27.4.5"
schema-utils "^3.1.1"
serialize-javascript "^6.0.1"
terser "^5.16.5"
terser "^5.16.8"
terser@^5.16.5, terser@^5.3.4:
version "5.17.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.1.tgz#948f10830454761e2eeedc6debe45c532c83fd69"
integrity sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==
terser@^5.16.8, terser@^5.3.4:
version "5.17.3"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.3.tgz#7f908f16b3cdf3f6c0f8338e6c1c674837f90d25"
integrity sha512-AudpAZKmZHkG9jueayypz4duuCFJMMNGRMwaPvQKWfxKedh8Z2x3OCoDqIIi1xx5+iwx1u6Au8XQcc9Lke65Yg==
dependencies:
"@jridgewell/source-map" "^0.3.2"
acorn "^8.5.0"
@ -6618,9 +6629,9 @@ webpack-dev-middleware@^5.3.1:
schema-utils "^4.0.0"
webpack-dev-server@^4.8.0:
version "4.13.3"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.13.3.tgz#9feb740b8b56b886260bae1360286818a221bae8"
integrity sha512-KqqzrzMRSRy5ePz10VhjyL27K2dxqwXQLP5rAKwRJBPUahe7Z2bBWzHw37jeb8GCPKxZRO79ZdQUAPesMh/Nug==
version "4.15.0"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.0.tgz#87ba9006eca53c551607ea0d663f4ae88be7af21"
integrity sha512-HmNB5QeSl1KpulTBQ8UT4FPrByYyaLxpJoQ0+s7EvUrMc16m0ZS1sgb1XGqzmgCPk0c9y+aaXxn11tbLzuM7NQ==
dependencies:
"@types/bonjour" "^3.5.9"
"@types/connect-history-api-fallback" "^1.3.5"
@ -6691,9 +6702,9 @@ webpack-sources@^3.2.3:
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
webpack@^5.74.0:
version "5.82.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.82.0.tgz#3c0d074dec79401db026b4ba0fb23d6333f88e7d"
integrity sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==
version "5.82.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.82.1.tgz#8f38c78e53467556e8a89054ebd3ef6e9f67dbab"
integrity sha512-C6uiGQJ+Gt4RyHXXYt+v9f+SN1v83x68URwgxNQ98cvH8kxiuywWGP4XeNZ1paOzZ63aY3cTciCEQJNFUljlLw==
dependencies:
"@types/eslint-scope" "^3.7.3"
"@types/estree" "^1.0.0"
@ -6704,7 +6715,7 @@ webpack@^5.74.0:
acorn-import-assertions "^1.7.6"
browserslist "^4.14.5"
chrome-trace-event "^1.0.2"
enhanced-resolve "^5.13.0"
enhanced-resolve "^5.14.0"
es-module-lexer "^1.2.1"
eslint-scope "5.1.1"
events "^3.2.0"