Compare commits

...

17 commits

Author SHA1 Message Date
github-actions[bot]
a2307b5b07 Update KiCad symbols and footprints lists
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
2026-06-15 07:29:32 +00:00
dependabot[bot]
98df91d785
Bump codecov/codecov-action from 6 to 7 (#1407)
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6 to 7.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-14 23:22:04 +02:00
Jan Böhmer
bffb2c1d70 Bumped versionnn to 2.12.2 2026-06-14 23:21:36 +02:00
Jan Böhmer
d44ce85d89 Merge branch 'fix_deprecations' 2026-06-14 23:20:08 +02:00
Jan Böhmer
12f4a3606e Remove deprecation logging by default and added env to reenable it again
The files can easily get quite large and probably also not good for performance. This fixes issue #1405
2026-06-14 23:19:59 +02:00
d-buchmann
192c5fcaa3
Update hide_sidebar_controller.js (#1404)
With this fix, the sidebar state is reapplied correctly on page reload.
2026-06-14 22:52:08 +02:00
d-buchmann
63d507b2f3
Update StorageLocation.php (#1403)
fixes #1398
2026-06-14 22:48:58 +02:00
Jan Böhmer
ef7e6d6f3b Fixed MYSQL_ATTR_INIT_COMMAND deprecation 2026-06-14 22:44:17 +02:00
Jan Böhmer
350e5a0245 Fixed deprecationn in TreeController 2026-06-14 22:40:23 +02:00
Jan Böhmer
704f7e7645
Update KiCad symbols and footprints lists (#1402)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-14 22:32:31 +02:00
Jan Böhmer
589f420b79 Updated dependencies 2026-06-14 22:19:43 +02:00
Jan Böhmer
dfbdac7688 Avoid using render in datatables, as it require escaping
This commit also fixes an XSS vulnerability in IPN project bom
2026-06-14 22:16:00 +02:00
Jan Böhmer
11b41ee66a Hardened against potential XSS injection in table columns 2026-06-14 12:08:25 +02:00
Jan Böhmer
c9dd27712c Fixed stored XSS vulnerability in BOM Validation Service 2026-06-14 11:55:16 +02:00
Jan Böhmer
8421636b1c Use HTML sanatizer to harden HTML rendering on log_details page
Should be more safe than use |raw directly and for these smalls things performance hit is zero.
2026-06-10 23:43:07 +02:00
Jan Böhmer
b357ee196c Avoid usage of raw filter in javascript to minimize risk 2026-06-10 23:37:57 +02:00
Jan Böhmer
0c5f8dc9fd Updated dependencies 2026-06-10 23:37:22 +02:00
28 changed files with 540 additions and 348 deletions

10
.env
View file

@ -149,6 +149,16 @@ DISABLE_YEAR2038_BUG_CHECK=0
#TRUSTED_PROXIES=127.0.0.0/8,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 #TRUSTED_PROXIES=127.0.0.0/8,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
#TRUSTED_HOSTS='^(localhost|example\.com)$' #TRUSTED_HOSTS='^(localhost|example\.com)$'
###################################################################################
# Logging settings
###################################################################################
# The minimum level a deprecation notice must have to be written to the var/log/<env>_deprecations.log file.
# Deprecation notices are logged with level "info", so this disables the deprecation log by default.
# Set to debug to log all deprecation notices
DEPRECATION_LOG_LEVEL=emergency
###> symfony/lock ### ###> symfony/lock ###
# Choose one of the stores below # Choose one of the stores below

View file

@ -129,7 +129,7 @@ jobs:
run: ./bin/phpunit --coverage-clover=coverage.xml run: ./bin/phpunit --coverage-clover=coverage.xml
- name: Upload coverage - name: Upload coverage
uses: codecov/codecov-action@v6 uses: codecov/codecov-action@v7
with: with:
env_vars: PHP_VERSION,DB_TYPE env_vars: PHP_VERSION,DB_TYPE
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}

View file

@ -1 +1 @@
2.12.1 2.12.2

View file

@ -51,7 +51,7 @@ export default class extends Controller {
//Make the state persistent over reloads //Make the state persistent over reloads
if(localStorage.getItem(STORAGE_KEY) === 'true') { if(localStorage.getItem(STORAGE_KEY) === 'true') {
sidebarHide(); this.hideSidebar();
} }
} }

View file

@ -70,6 +70,7 @@
"symfony/flex": "^v2.3.1", "symfony/flex": "^v2.3.1",
"symfony/form": "7.4.*", "symfony/form": "7.4.*",
"symfony/framework-bundle": "7.4.*", "symfony/framework-bundle": "7.4.*",
"symfony/html-sanitizer": "7.4.*",
"symfony/http-client": "7.4.*", "symfony/http-client": "7.4.*",
"symfony/http-kernel": "7.4.*", "symfony/http-kernel": "7.4.*",
"symfony/mailer": "7.4.*", "symfony/mailer": "7.4.*",

424
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -51,6 +51,7 @@ when@prod:
type: stream type: stream
channels: [deprecation] channels: [deprecation]
path: "%kernel.logs_dir%/%kernel.environment%_deprecations.log" path: "%kernel.logs_dir%/%kernel.environment%_deprecations.log"
level: "%env(DEPRECATION_LOG_LEVEL)%"
when@docker: when@docker:
monolog: monolog:
@ -75,3 +76,4 @@ when@docker:
type: stream type: stream
channels: [deprecation] channels: [deprecation]
path: "%kernel.logs_dir%/%kernel.environment%_deprecations.log" path: "%kernel.logs_dir%/%kernel.environment%_deprecations.log"
level: "%env(DEPRECATION_LOG_LEVEL)%"

View file

@ -653,7 +653,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* time_based_uuid_node?: scalar|Param|null, * time_based_uuid_node?: scalar|Param|null,
* }, * },
* html_sanitizer?: bool|array{ // HtmlSanitizer configuration * html_sanitizer?: bool|array{ // HtmlSanitizer configuration
* enabled?: bool|Param, // Default: false * enabled?: bool|Param, // Default: true
* sanitizers?: array<string, array{ // Default: [] * sanitizers?: array<string, array{ // Default: []
* allow_safe_elements?: bool|Param, // Allows "safe" elements and attributes. // Default: false * allow_safe_elements?: bool|Param, // Allows "safe" elements and attributes. // Default: false
* allow_static_elements?: bool|Param, // Allows all static elements and attributes from the W3C Sanitizer API standard. // Default: false * allow_static_elements?: bool|Param, // Allows all static elements and attributes from the W3C Sanitizer API standard. // Default: false
@ -718,7 +718,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* servicename?: scalar|Param|null, // Overrules dbname parameter if given and used as SERVICE_NAME or SID connection parameter for Oracle depending on the service parameter. * servicename?: scalar|Param|null, // Overrules dbname parameter if given and used as SERVICE_NAME or SID connection parameter for Oracle depending on the service parameter.
* sessionMode?: scalar|Param|null, // The session mode to use for the oci8 driver * sessionMode?: scalar|Param|null, // The session mode to use for the oci8 driver
* server?: scalar|Param|null, // The name of a running database server to connect to for SQL Anywhere. * server?: scalar|Param|null, // The name of a running database server to connect to for SQL Anywhere.
* default_dbname?: scalar|Param|null, // Override the default database (postgres) to connect to for PostgreSQL connexion. * default_dbname?: scalar|Param|null, // Override the default database (postgres) to connect to for PostgreSQL connection.
* sslmode?: scalar|Param|null, // Determines whether or with what priority a SSL TCP/IP connection will be negotiated with the server for PostgreSQL. * sslmode?: scalar|Param|null, // Determines whether or with what priority a SSL TCP/IP connection will be negotiated with the server for PostgreSQL.
* sslrootcert?: scalar|Param|null, // The name of a file containing SSL certificate authority (CA) certificate(s). If the file exists, the server's certificate will be verified to be signed by one of these authorities. * sslrootcert?: scalar|Param|null, // The name of a file containing SSL certificate authority (CA) certificate(s). If the file exists, the server's certificate will be verified to be signed by one of these authorities.
* sslcert?: scalar|Param|null, // The path to the SSL client certificate file for PostgreSQL. * sslcert?: scalar|Param|null, // The path to the SSL client certificate file for PostgreSQL.
@ -769,7 +769,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* servicename?: scalar|Param|null, // Overrules dbname parameter if given and used as SERVICE_NAME or SID connection parameter for Oracle depending on the service parameter. * servicename?: scalar|Param|null, // Overrules dbname parameter if given and used as SERVICE_NAME or SID connection parameter for Oracle depending on the service parameter.
* sessionMode?: scalar|Param|null, // The session mode to use for the oci8 driver * sessionMode?: scalar|Param|null, // The session mode to use for the oci8 driver
* server?: scalar|Param|null, // The name of a running database server to connect to for SQL Anywhere. * server?: scalar|Param|null, // The name of a running database server to connect to for SQL Anywhere.
* default_dbname?: scalar|Param|null, // Override the default database (postgres) to connect to for PostgreSQL connexion. * default_dbname?: scalar|Param|null, // Override the default database (postgres) to connect to for PostgreSQL connection.
* sslmode?: scalar|Param|null, // Determines whether or with what priority a SSL TCP/IP connection will be negotiated with the server for PostgreSQL. * sslmode?: scalar|Param|null, // Determines whether or with what priority a SSL TCP/IP connection will be negotiated with the server for PostgreSQL.
* sslrootcert?: scalar|Param|null, // The name of a file containing SSL certificate authority (CA) certificate(s). If the file exists, the server's certificate will be verified to be signed by one of these authorities. * sslrootcert?: scalar|Param|null, // The name of a file containing SSL certificate authority (CA) certificate(s). If the file exists, the server's certificate will be verified to be signed by one of these authorities.
* sslcert?: scalar|Param|null, // The path to the SSL client certificate file for PostgreSQL. * sslcert?: scalar|Param|null, // The path to the SSL client certificate file for PostgreSQL.
@ -801,7 +801,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* servicename?: scalar|Param|null, // Overrules dbname parameter if given and used as SERVICE_NAME or SID connection parameter for Oracle depending on the service parameter. * servicename?: scalar|Param|null, // Overrules dbname parameter if given and used as SERVICE_NAME or SID connection parameter for Oracle depending on the service parameter.
* sessionMode?: scalar|Param|null, // The session mode to use for the oci8 driver * sessionMode?: scalar|Param|null, // The session mode to use for the oci8 driver
* server?: scalar|Param|null, // The name of a running database server to connect to for SQL Anywhere. * server?: scalar|Param|null, // The name of a running database server to connect to for SQL Anywhere.
* default_dbname?: scalar|Param|null, // Override the default database (postgres) to connect to for PostgreSQL connexion. * default_dbname?: scalar|Param|null, // Override the default database (postgres) to connect to for PostgreSQL connection.
* sslmode?: scalar|Param|null, // Determines whether or with what priority a SSL TCP/IP connection will be negotiated with the server for PostgreSQL. * sslmode?: scalar|Param|null, // Determines whether or with what priority a SSL TCP/IP connection will be negotiated with the server for PostgreSQL.
* sslrootcert?: scalar|Param|null, // The name of a file containing SSL certificate authority (CA) certificate(s). If the file exists, the server's certificate will be verified to be signed by one of these authorities. * sslrootcert?: scalar|Param|null, // The name of a file containing SSL certificate authority (CA) certificate(s). If the file exists, the server's certificate will be verified to be signed by one of these authorities.
* sslcert?: scalar|Param|null, // The path to the SSL client certificate file for PostgreSQL. * sslcert?: scalar|Param|null, // The path to the SSL client certificate file for PostgreSQL.

View file

@ -279,9 +279,13 @@ See the [information providers]({% link usage/information_provider_system.md %})
* `BANNER`: You can configure the text that should be shown as the banner on the homepage. Useful especially for docker * `BANNER`: You can configure the text that should be shown as the banner on the homepage. Useful especially for docker
containers. In all other applications you can just change the `config/banner.md` file. containers. In all other applications you can just change the `config/banner.md` file.
* `DISABLE_YEAR2038_BUG_CHECK` (env only): If set to `1`, the year 2038 bug check is disabled on 32-bit systems, and dates after * `DISABLE_YEAR2038_BUG_CHECK` (env only): If set to `1`, the year 2038 bug check is disabled on 32-bit systems, and dates after
2038 are no longer forbidden. However this will lead to 500 error messages when rendering dates after 2038 as all current 2038 are no longer forbidden. However, this will lead to 500 error messages when rendering dates after 2038 as all current
32-bit PHP versions can not format these dates correctly. This setting is for the case that future PHP versions will 32-bit PHP versions can not format these dates correctly. This setting is for the case that future PHP versions will
handle this correctly on 32-bit systems. 64-bit systems are not affected by this bug, and the check is always disabled. handle this correctly on 32-bit systems. 64-bit systems are not affected by this bug, and the check is always disabled.
* `DEPRECATION_LOG_LEVEL` (default `emergency`) (env only): In the `prod` and `docker` environments, PHP/Symfony
deprecation notices are written to their own `var/log/<env>_deprecations.log` file. This option sets the minimum log
level a deprecation notice must have to be written there. Since deprecation notices are logged with level `info`,
the default value of `emergency` effectively disables this dedicated deprecation log. Set it to `debug` to enable it.
## Banner ## Banner

View file

@ -1,4 +1,4 @@
# Generated on Mon Jun 1 07:07:44 UTC 2026 # Generated on Mon Jun 15 07:28:00 UTC 2026
# This file contains all footprints available in the offical KiCAD library # This file contains all footprints available in the offical KiCAD library
Audio_Module:Reverb_BTDR-1H Audio_Module:Reverb_BTDR-1H
Audio_Module:Reverb_BTDR-1V Audio_Module:Reverb_BTDR-1V
@ -12012,7 +12012,6 @@ Package_DFN_QFN:WDFN-8-1EP_4x3mm_P0.65mm_EP2.4x1.8mm_ThermalVias
Package_DFN_QFN:WDFN-8-1EP_6x5mm_P1.27mm_EP3.4x4mm Package_DFN_QFN:WDFN-8-1EP_6x5mm_P1.27mm_EP3.4x4mm
Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm
Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm_ThermalVias Package_DFN_QFN:WDFN-8-1EP_8x6mm_P1.27mm_EP6x4.8mm_ThermalVias
Package_DFN_QFN:WDFN-8_2x2mm_P0.5mm
Package_DFN_QFN:WFDFPN-8-1EP_3x2mm_P0.5mm_EP1.25x1.35mm Package_DFN_QFN:WFDFPN-8-1EP_3x2mm_P0.5mm_EP1.25x1.35mm
Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm
Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm_ThermalVias Package_DFN_QFN:WQFN-14-1EP_2.5x2.5mm_P0.5mm_EP1.45x1.45mm_ThermalVias
@ -12358,7 +12357,6 @@ Package_DirectFET:DirectFET_SQ
Package_DirectFET:DirectFET_ST Package_DirectFET:DirectFET_ST
Package_LCC:Analog_LCC-8_5x5mm_P1.27mm Package_LCC:Analog_LCC-8_5x5mm_P1.27mm
Package_LCC:MO047AD_PLCC-52_19.1x19.1mm_P1.27mm Package_LCC:MO047AD_PLCC-52_19.1x19.1mm_P1.27mm
Package_LCC:PLCC-20
Package_LCC:PLCC-20_9.0x9.0mm_P1.27mm Package_LCC:PLCC-20_9.0x9.0mm_P1.27mm
Package_LCC:PLCC-20_SMD-Socket Package_LCC:PLCC-20_SMD-Socket
Package_LCC:PLCC-20_THT-Socket Package_LCC:PLCC-20_THT-Socket

View file

@ -1,4 +1,4 @@
# Generated on Mon Jun 1 07:08:24 UTC 2026 # Generated on Mon Jun 15 07:28:38 UTC 2026
# This file contains all symbols available in the offical KiCAD library # This file contains all symbols available in the offical KiCAD library
4xxx:14528 4xxx:14528
4xxx:14529 4xxx:14529
@ -5300,21 +5300,39 @@ Converter_DCDC:TMR-4812
Converter_DCDC:TMR-4821 Converter_DCDC:TMR-4821
Converter_DCDC:TMR-4822 Converter_DCDC:TMR-4822
Converter_DCDC:TMR-4823 Converter_DCDC:TMR-4823
Converter_DCDC:TMR10-1211WI
Converter_DCDC:TMR10-1212WI
Converter_DCDC:TMR10-1213WI
Converter_DCDC:TMR10-1215WI
Converter_DCDC:TMR10-1222WI
Converter_DCDC:TMR10-1223WI
Converter_DCDC:TMR10-2410WIR Converter_DCDC:TMR10-2410WIR
Converter_DCDC:TMR10-2411WI
Converter_DCDC:TMR10-2411WIR Converter_DCDC:TMR10-2411WIR
Converter_DCDC:TMR10-2412WI
Converter_DCDC:TMR10-2412WIR Converter_DCDC:TMR10-2412WIR
Converter_DCDC:TMR10-2413WI
Converter_DCDC:TMR10-2413WIR Converter_DCDC:TMR10-2413WIR
Converter_DCDC:TMR10-2415WI
Converter_DCDC:TMR10-2415WIR Converter_DCDC:TMR10-2415WIR
Converter_DCDC:TMR10-2421WIR Converter_DCDC:TMR10-2421WIR
Converter_DCDC:TMR10-2422WI
Converter_DCDC:TMR10-2422WIR Converter_DCDC:TMR10-2422WIR
Converter_DCDC:TMR10-2423WI
Converter_DCDC:TMR10-2423WIR Converter_DCDC:TMR10-2423WIR
Converter_DCDC:TMR10-4810WIR Converter_DCDC:TMR10-4810WIR
Converter_DCDC:TMR10-4811WI
Converter_DCDC:TMR10-4811WIR Converter_DCDC:TMR10-4811WIR
Converter_DCDC:TMR10-4812WI
Converter_DCDC:TMR10-4812WIR Converter_DCDC:TMR10-4812WIR
Converter_DCDC:TMR10-4813WI
Converter_DCDC:TMR10-4813WIR Converter_DCDC:TMR10-4813WIR
Converter_DCDC:TMR10-4815WI
Converter_DCDC:TMR10-4815WIR Converter_DCDC:TMR10-4815WIR
Converter_DCDC:TMR10-4821WIR Converter_DCDC:TMR10-4821WIR
Converter_DCDC:TMR10-4822WI
Converter_DCDC:TMR10-4822WIR Converter_DCDC:TMR10-4822WIR
Converter_DCDC:TMR10-4823WI
Converter_DCDC:TMR10-4823WIR Converter_DCDC:TMR10-4823WIR
Converter_DCDC:TMR10-7210WIR Converter_DCDC:TMR10-7210WIR
Converter_DCDC:TMR10-7211WIR Converter_DCDC:TMR10-7211WIR
@ -14593,6 +14611,8 @@ MCU_Texas:LM4F111C4QR
MCU_Texas:LM4F111E5QR MCU_Texas:LM4F111E5QR
MCU_Texas:LM4F111H5QR MCU_Texas:LM4F111H5QR
MCU_Texas:MSP432E401Y MCU_Texas:MSP432E401Y
MCU_Texas:MSPM0C110xSDDF
MCU_Texas:MSPM0C110xSDSG
MCU_Texas:TM4C1230C3PM MCU_Texas:TM4C1230C3PM
MCU_Texas:TM4C1230D5PM MCU_Texas:TM4C1230D5PM
MCU_Texas:TM4C1230E6PM MCU_Texas:TM4C1230E6PM
@ -15115,6 +15135,7 @@ Memory_Flash:AM29F400Bx-xxEx
Memory_Flash:AM29F400Bx-xxSx Memory_Flash:AM29F400Bx-xxSx
Memory_Flash:AM29PDL128G Memory_Flash:AM29PDL128G
Memory_Flash:AT25DF041x-UxN-x Memory_Flash:AT25DF041x-UxN-x
Memory_Flash:AT25SF041B-SSHD-X
Memory_Flash:AT25SF081-SSHD-X Memory_Flash:AT25SF081-SSHD-X
Memory_Flash:AT25SF081-SSHF-X Memory_Flash:AT25SF081-SSHF-X
Memory_Flash:AT25SF081-XMHD-X Memory_Flash:AT25SF081-XMHD-X
@ -15670,6 +15691,7 @@ Power_Management:LM5069MM-1
Power_Management:LM5069MM-2 Power_Management:LM5069MM-2
Power_Management:LM66100DCK Power_Management:LM66100DCK
Power_Management:LM74700 Power_Management:LM74700
Power_Management:LM74701-Q1
Power_Management:LMG3410 Power_Management:LMG3410
Power_Management:LMG5200 Power_Management:LMG5200
Power_Management:LT1641-1 Power_Management:LT1641-1
@ -15771,6 +15793,7 @@ Power_Management:TPS22810DBV
Power_Management:TPS22810DRV Power_Management:TPS22810DRV
Power_Management:TPS22917DBV Power_Management:TPS22917DBV
Power_Management:TPS22917LDBV Power_Management:TPS22917LDBV
Power_Management:TPS22919DCK
Power_Management:TPS22929D Power_Management:TPS22929D
Power_Management:TPS22993 Power_Management:TPS22993
Power_Management:TPS2412D Power_Management:TPS2412D
@ -16480,6 +16503,7 @@ RF_Module:DWM3000
RF_Module:E18-MS1-PCB RF_Module:E18-MS1-PCB
RF_Module:E73-2G4M04S-52810 RF_Module:E73-2G4M04S-52810
RF_Module:E73-2G4M04S-52832 RF_Module:E73-2G4M04S-52832
RF_Module:ESP-01
RF_Module:ESP-07 RF_Module:ESP-07
RF_Module:ESP-12E RF_Module:ESP-12E
RF_Module:ESP-12F RF_Module:ESP-12F
@ -16681,6 +16705,19 @@ Reference_Voltage:LM4040LP-4.1
Reference_Voltage:LM4040LP-5 Reference_Voltage:LM4040LP-5
Reference_Voltage:LM4040LP-8.2 Reference_Voltage:LM4040LP-8.2
Reference_Voltage:LM4041LP-ADJ Reference_Voltage:LM4041LP-ADJ
Reference_Voltage:LM4050xEM3-2.1
Reference_Voltage:LM4050xEM3-2.5
Reference_Voltage:LM4050xEM3-3.0
Reference_Voltage:LM4050xEM3-3.3
Reference_Voltage:LM4050xEM3-4.1
Reference_Voltage:LM4050xEM3-5.0
Reference_Voltage:LM4050xEX3-2.1
Reference_Voltage:LM4050xEX3-2.5
Reference_Voltage:LM4050xEX3-3.3
Reference_Voltage:LM4050xEX3-4.1
Reference_Voltage:LM4050xEX3-5.0
Reference_Voltage:LM4051xEM3-1.2
Reference_Voltage:LM4051xEX3-1.2
Reference_Voltage:LM4125AIM5-2.5 Reference_Voltage:LM4125AIM5-2.5
Reference_Voltage:LM4125IM5-2.0 Reference_Voltage:LM4125IM5-2.0
Reference_Voltage:LM4125IM5-2.5 Reference_Voltage:LM4125IM5-2.5
@ -16828,7 +16865,6 @@ Reference_Voltage:MCP1501-25xCH
Reference_Voltage:MCP1501-25xRW Reference_Voltage:MCP1501-25xRW
Reference_Voltage:MCP1501-25xSN Reference_Voltage:MCP1501-25xSN
Reference_Voltage:MCP1501-30xCH Reference_Voltage:MCP1501-30xCH
Reference_Voltage:MCP1501-30xRW
Reference_Voltage:MCP1501-30xSN Reference_Voltage:MCP1501-30xSN
Reference_Voltage:MCP1501-33xCH Reference_Voltage:MCP1501-33xCH
Reference_Voltage:MCP1501-33xRW Reference_Voltage:MCP1501-33xRW
@ -20989,6 +21025,7 @@ Sensor_Temperature:MCP9501
Sensor_Temperature:MCP9502 Sensor_Temperature:MCP9502
Sensor_Temperature:MCP9503 Sensor_Temperature:MCP9503
Sensor_Temperature:MCP9504 Sensor_Temperature:MCP9504
Sensor_Temperature:MCP96xx01x-x-MX
Sensor_Temperature:MCP9700Ax-ELT Sensor_Temperature:MCP9700Ax-ELT
Sensor_Temperature:MCP9700Ax-ETT Sensor_Temperature:MCP9700Ax-ETT
Sensor_Temperature:MCP9700Ax-HLT Sensor_Temperature:MCP9700Ax-HLT

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Controller; namespace App\Controller;
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use App\Entity\ProjectSystem\Project; use App\Entity\ProjectSystem\Project;
use App\Entity\Parts\Category; use App\Entity\Parts\Category;
@ -55,7 +56,7 @@ class TreeController extends AbstractController
#[Route(path: '/category/{id}', name: 'tree_category')] #[Route(path: '/category/{id}', name: 'tree_category')]
#[Route(path: '/categories', name: 'tree_category_root')] #[Route(path: '/categories', name: 'tree_category_root')]
public function categoryTree(?Category $category = null): JsonResponse public function categoryTree(#[MapEntity(id: 'id')] ?Category $category = null): JsonResponse
{ {
if ($this->isGranted('@parts.read') && $this->isGranted('@categories.read')) { if ($this->isGranted('@parts.read') && $this->isGranted('@categories.read')) {
$tree = $this->treeGenerator->getTreeView(Category::class, $category, 'list_parts_root'); $tree = $this->treeGenerator->getTreeView(Category::class, $category, 'list_parts_root');
@ -68,7 +69,7 @@ class TreeController extends AbstractController
#[Route(path: '/footprint/{id}', name: 'tree_footprint')] #[Route(path: '/footprint/{id}', name: 'tree_footprint')]
#[Route(path: '/footprints', name: 'tree_footprint_root')] #[Route(path: '/footprints', name: 'tree_footprint_root')]
public function footprintTree(?Footprint $footprint = null): JsonResponse public function footprintTree(#[MapEntity(id: 'id')] ?Footprint $footprint = null): JsonResponse
{ {
if ($this->isGranted('@parts.read') && $this->isGranted('@footprints.read')) { if ($this->isGranted('@parts.read') && $this->isGranted('@footprints.read')) {
$tree = $this->treeGenerator->getTreeView(Footprint::class, $footprint, 'list_parts_root'); $tree = $this->treeGenerator->getTreeView(Footprint::class, $footprint, 'list_parts_root');
@ -80,7 +81,7 @@ class TreeController extends AbstractController
#[Route(path: '/location/{id}', name: 'tree_location')] #[Route(path: '/location/{id}', name: 'tree_location')]
#[Route(path: '/locations', name: 'tree_location_root')] #[Route(path: '/locations', name: 'tree_location_root')]
public function locationTree(?StorageLocation $location = null): JsonResponse public function locationTree(#[MapEntity(id: 'id')] ?StorageLocation $location = null): JsonResponse
{ {
if ($this->isGranted('@parts.read') && $this->isGranted('@storelocations.read')) { if ($this->isGranted('@parts.read') && $this->isGranted('@storelocations.read')) {
$tree = $this->treeGenerator->getTreeView(StorageLocation::class, $location, 'list_parts_root'); $tree = $this->treeGenerator->getTreeView(StorageLocation::class, $location, 'list_parts_root');
@ -93,7 +94,7 @@ class TreeController extends AbstractController
#[Route(path: '/manufacturer/{id}', name: 'tree_manufacturer')] #[Route(path: '/manufacturer/{id}', name: 'tree_manufacturer')]
#[Route(path: '/manufacturers', name: 'tree_manufacturer_root')] #[Route(path: '/manufacturers', name: 'tree_manufacturer_root')]
public function manufacturerTree(?Manufacturer $manufacturer = null): JsonResponse public function manufacturerTree(#[MapEntity(id: 'id')] ?Manufacturer $manufacturer = null): JsonResponse
{ {
if ($this->isGranted('@parts.read') && $this->isGranted('@manufacturers.read')) { if ($this->isGranted('@parts.read') && $this->isGranted('@manufacturers.read')) {
$tree = $this->treeGenerator->getTreeView(Manufacturer::class, $manufacturer, 'list_parts_root'); $tree = $this->treeGenerator->getTreeView(Manufacturer::class, $manufacturer, 'list_parts_root');
@ -106,7 +107,7 @@ class TreeController extends AbstractController
#[Route(path: '/supplier/{id}', name: 'tree_supplier')] #[Route(path: '/supplier/{id}', name: 'tree_supplier')]
#[Route(path: '/suppliers', name: 'tree_supplier_root')] #[Route(path: '/suppliers', name: 'tree_supplier_root')]
public function supplierTree(?Supplier $supplier = null): JsonResponse public function supplierTree(#[MapEntity(id: 'id')] ?Supplier $supplier = null): JsonResponse
{ {
if ($this->isGranted('@parts.read') && $this->isGranted('@suppliers.read')) { if ($this->isGranted('@parts.read') && $this->isGranted('@suppliers.read')) {
$tree = $this->treeGenerator->getTreeView(Supplier::class, $supplier, 'list_parts_root'); $tree = $this->treeGenerator->getTreeView(Supplier::class, $supplier, 'list_parts_root');
@ -119,7 +120,7 @@ class TreeController extends AbstractController
#[Route(path: '/device/{id}', name: 'tree_device')] #[Route(path: '/device/{id}', name: 'tree_device')]
#[Route(path: '/devices', name: 'tree_device_root')] #[Route(path: '/devices', name: 'tree_device_root')]
public function deviceTree(?Project $device = null): JsonResponse public function deviceTree(#[MapEntity(id: 'id')] ?Project $device = null): JsonResponse
{ {
if ($this->isGranted('@projects.read')) { if ($this->isGranted('@projects.read')) {
$tree = $this->treeGenerator->getTreeView(Project::class, $device, 'devices'); $tree = $this->treeGenerator->getTreeView(Project::class, $device, 'devices');

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\DataTables; namespace App\DataTables;
use App\DataTables\Column\HTMLColumn;
use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\LocaleDateTimeColumn;
use App\DataTables\Column\PrettyBoolColumn; use App\DataTables\Column\PrettyBoolColumn;
use App\DataTables\Column\RowClassColumn; use App\DataTables\Column\RowClassColumn;
@ -40,14 +41,19 @@ use Omines\DataTablesBundle\DataTable;
use Omines\DataTablesBundle\DataTableTypeInterface; use Omines\DataTablesBundle\DataTableTypeInterface;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
final class AttachmentDataTable implements DataTableTypeInterface final readonly class AttachmentDataTable implements DataTableTypeInterface
{ {
public function __construct(private readonly TranslatorInterface $translator, private readonly EntityURLGenerator $entityURLGenerator, private readonly AttachmentManager $attachmentHelper, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly ElementTypeNameGenerator $elementTypeNameGenerator) public function __construct(private TranslatorInterface $translator, private EntityURLGenerator $entityURLGenerator, private AttachmentManager $attachmentHelper, private AttachmentURLGenerator $attachmentURLGenerator, private ElementTypeNameGenerator $elementTypeNameGenerator)
{ {
} }
public function configure(DataTable $dataTable, array $options): void public function configure(DataTable $dataTable, array $options): void
{ {
/*************************************************************************************************************
* Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the
* HTMLColumn, if necessary
************************************************************************************************************/
$dataTable->add('dont_matter', RowClassColumn::class, [ $dataTable->add('dont_matter', RowClassColumn::class, [
'render' => function ($value, Attachment $context): string { 'render' => function ($value, Attachment $context): string {
//Mark attachments yellow which have an internal file linked that doesn't exist //Mark attachments yellow which have an internal file linked that doesn't exist
@ -59,10 +65,10 @@ final class AttachmentDataTable implements DataTableTypeInterface
}, },
]); ]);
$dataTable->add('picture', TextColumn::class, [ $dataTable->add('picture', HTMLColumn::class, [
'label' => '', 'label' => '',
'className' => 'no-colvis', 'className' => 'no-colvis',
'render' => function ($value, Attachment $context): string { 'data' => function (Attachment $context): string {
if ($context->isPicture() if ($context->isPicture()
&& $this->attachmentHelper->isInternalFileExisting($context)) { && $this->attachmentHelper->isInternalFileExisting($context)) {
@ -95,65 +101,65 @@ final class AttachmentDataTable implements DataTableTypeInterface
'orderField' => 'NATSORT(attachment.name)', 'orderField' => 'NATSORT(attachment.name)',
]); ]);
$dataTable->add('attachment_type', TextColumn::class, [ $dataTable->add('attachment_type', HTMLColumn::class, [
'label' => 'attachment.table.type', 'label' => 'attachment.table.type',
'field' => 'attachment_type.name', 'field' => 'attachment_type.name',
'orderField' => 'NATSORT(attachment_type.name)', 'orderField' => 'NATSORT(attachment_type.name)',
'render' => fn($value, Attachment $context): string => sprintf( 'data' => fn(Attachment $context, $value): string => sprintf(
'<a href="%s">%s</a>', '<a href="%s">%s</a>',
$this->entityURLGenerator->editURL($context->getAttachmentType()), $this->entityURLGenerator->editURL($context->getAttachmentType()),
htmlspecialchars((string) $value) htmlspecialchars((string) $value)
), ),
]); ]);
$dataTable->add('element', TextColumn::class, [ $dataTable->add('element', HTMLColumn::class, [
'label' => 'attachment.table.element', 'label' => 'attachment.table.element',
//'propertyPath' => 'element.name', //'propertyPath' => 'element.name',
'render' => fn($value, Attachment $context): string => sprintf( 'data' => fn(Attachment $context): string => sprintf(
'<a href="%s">%s</a>', '<a href="%s">%s</a>',
$this->entityURLGenerator->infoURL($context->getElement()), $this->entityURLGenerator->infoURL($context->getElement()),
$this->elementTypeNameGenerator->getTypeNameCombination($context->getElement(), true) $this->elementTypeNameGenerator->getTypeNameCombination($context->getElement(), true)
), ),
]); ]);
$dataTable->add('internal_link', TextColumn::class, [ $dataTable->add('internal_link', HTMLColumn::class, [
'label' => 'attachment.table.internal_file', 'label' => 'attachment.table.internal_file',
'propertyPath' => 'filename', 'propertyPath' => 'filename',
'orderField' => 'NATSORT(attachment.original_filename)', 'orderField' => 'NATSORT(attachment.original_filename)',
'render' => function ($value, Attachment $context) { 'data' => function (Attachment $context, $value) {
if ($this->attachmentHelper->isInternalFileExisting($context)) { if ($this->attachmentHelper->isInternalFileExisting($context)) {
return sprintf( return sprintf(
'<a href="%s" target="_blank" data-no-ajax>%s</a>', '<a href="%s" target="_blank" data-no-ajax>%s</a>',
$this->entityURLGenerator->viewURL($context), $this->entityURLGenerator->viewURL($context),
htmlspecialchars($value) htmlspecialchars((string) $value)
); );
} }
return $value; return htmlspecialchars((string) $value);
} },
]); ]);
$dataTable->add('external_link', TextColumn::class, [ $dataTable->add('external_link', HTMLColumn::class, [
'label' => 'attachment.table.external_link', 'label' => 'attachment.table.external_link',
'propertyPath' => 'host', 'propertyPath' => 'host',
'orderField' => 'attachment.external_path', 'orderField' => 'attachment.external_path',
'render' => function ($value, Attachment $context) { 'data' => function (Attachment $context, $value) {
if ($context->hasExternal()) { if ($context->hasExternal()) {
return sprintf( return sprintf(
'<a href="%s" class="link-external" title="%s" target="_blank" rel="noopener">%s</a>', '<a href="%s" class="link-external" title="%s" target="_blank" rel="noopener">%s</a>',
htmlspecialchars((string) $context->getExternalPath()), htmlspecialchars((string) $context->getExternalPath()),
htmlspecialchars((string) $context->getExternalPath()), htmlspecialchars((string) $context->getExternalPath()),
htmlspecialchars($value), htmlspecialchars((string) $value),
); );
} }
return $value; return htmlspecialchars((string) $value);
} },
]); ]);
$dataTable->add('filesize', TextColumn::class, [ $dataTable->add('filesize', HTMLColumn::class, [
'label' => $this->translator->trans('attachment.table.filesize'), 'label' => $this->translator->trans('attachment.table.filesize'),
'render' => function ($value, Attachment $context) { 'data' => function (Attachment $context) {
if (!$context->hasInternal()) { if (!$context->hasInternal()) {
return sprintf( return sprintf(
'<span class="badge bg-primary"> '<span class="badge bg-primary">
@ -168,7 +174,7 @@ final class AttachmentDataTable implements DataTableTypeInterface
'<span class="badge bg-secondary"> '<span class="badge bg-secondary">
<i class="fas fa-hdd fa-fw"></i> %s <i class="fas fa-hdd fa-fw"></i> %s
</span>', </span>',
$this->attachmentHelper->getHumanFileSize($context) htmlspecialchars($this->attachmentHelper->getHumanFileSize($context))
); );
} }

View file

@ -78,7 +78,7 @@ class EntityColumn extends AbstractColumn
); );
} }
return sprintf('<i>%s</i>', $value); return sprintf('<i>%s</i>', htmlspecialchars($value));
} }
return ''; return '';

View file

@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2026 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\DataTables\Column;
use Omines\DataTablesBundle\Column\TextColumn;
/**
* A TextColumn whose value is always treated as raw HTML and therefore never passed through htmlspecialchars().
* The value returned by the 'data' option must already contain properly escaped/sanitized HTML, as it is output as-is.
*/
class HTMLColumn extends TextColumn
{
public function isRaw(): bool
{
return true;
}
}

View file

@ -87,9 +87,9 @@ class IconLinkColumn extends AbstractColumn
return sprintf( return sprintf(
'<a class="btn btn-primary btn-sm %s" href="%s" title="%s"><i class="%s"></i></a>', '<a class="btn btn-primary btn-sm %s" href="%s" title="%s"><i class="%s"></i></a>',
$disabled ? 'disabled' : '', $disabled ? 'disabled' : '',
$href, htmlspecialchars($href),
$title, htmlspecialchars($title ?? ''),
$icon htmlspecialchars($icon ?? '')
); );
} }

View file

@ -22,9 +22,9 @@ declare(strict_types=1);
*/ */
namespace App\DataTables; namespace App\DataTables;
use App\DataTables\Column\HTMLColumn;
use App\DataTables\Column\RowClassColumn; use App\DataTables\Column\RowClassColumn;
use Omines\DataTablesBundle\Adapter\ArrayAdapter; use Omines\DataTablesBundle\Adapter\ArrayAdapter;
use Omines\DataTablesBundle\Column\TextColumn;
use Omines\DataTablesBundle\DataTable; use Omines\DataTablesBundle\DataTable;
use Omines\DataTablesBundle\DataTableFactory; use Omines\DataTablesBundle\DataTableFactory;
use Omines\DataTablesBundle\DataTableTypeInterface; use Omines\DataTablesBundle\DataTableTypeInterface;
@ -32,7 +32,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
class ErrorDataTable implements DataTableTypeInterface final readonly class ErrorDataTable implements DataTableTypeInterface
{ {
public function configureOptions(OptionsResolver $optionsResolver): void public function configureOptions(OptionsResolver $optionsResolver): void
{ {
@ -49,6 +49,11 @@ class ErrorDataTable implements DataTableTypeInterface
public function configure(DataTable $dataTable, array $options): void public function configure(DataTable $dataTable, array $options): void
{ {
/*************************************************************************************************************
* Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the
* HTMLColumn, if necessary
************************************************************************************************************/
$optionsResolver = new OptionsResolver(); $optionsResolver = new OptionsResolver();
$this->configureOptions($optionsResolver); $this->configureOptions($optionsResolver);
$options = $optionsResolver->resolve($options); $options = $optionsResolver->resolve($options);
@ -58,9 +63,9 @@ class ErrorDataTable implements DataTableTypeInterface
'render' => fn($value, $context): string => 'table-warning', 'render' => fn($value, $context): string => 'table-warning',
]) ])
->add('error', TextColumn::class, [ ->add('error', HTMLColumn::class, [
'label' => 'error_table.error', 'label' => 'error_table.error',
'render' => fn($value, $context): string => '<i class="fa-solid fa-triangle-exclamation fa-fw"></i> ' . $value, 'data' => fn($context, $value): string => '<i class="fa-solid fa-triangle-exclamation fa-fw"></i> ' . htmlspecialchars((string) $value),
]) ])
; ;

View file

@ -62,7 +62,7 @@ class PartDataTableHelper
} }
if ($context->getBuiltProject() instanceof Project) { if ($context->getBuiltProject() instanceof Project) {
$icon = sprintf('<i class="fa-solid fa-box-archive fa-fw me-1" title="%s"></i>', $icon = sprintf('<i class="fa-solid fa-box-archive fa-fw me-1" title="%s"></i>',
$this->translator->trans('part.info.projectBuildPart.hint').': '.$context->getBuiltProject()->getName()); $this->translator->trans('part.info.projectBuildPart.hint').': '.htmlspecialchars($context->getBuiltProject()->getName()));
} }

View file

@ -25,6 +25,7 @@ namespace App\DataTables;
use App\DataTables\Column\EnumColumn; use App\DataTables\Column\EnumColumn;
use App\Entity\LogSystem\LogTargetType; use App\Entity\LogSystem\LogTargetType;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use App\DataTables\Column\HTMLColumn;
use App\DataTables\Column\IconLinkColumn; use App\DataTables\Column\IconLinkColumn;
use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\LocaleDateTimeColumn;
use App\DataTables\Column\LogEntryExtraColumn; use App\DataTables\Column\LogEntryExtraColumn;
@ -59,7 +60,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
class LogDataTable implements DataTableTypeInterface final readonly class LogDataTable implements DataTableTypeInterface
{ {
protected LogEntryRepository $logRepo; protected LogEntryRepository $logRepo;
@ -95,6 +96,11 @@ class LogDataTable implements DataTableTypeInterface
public function configure(DataTable $dataTable, array $options): void public function configure(DataTable $dataTable, array $options): void
{ {
/*************************************************************************************************************
* Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the
* HTMLColumn, if necessary
************************************************************************************************************/
$resolver = new OptionsResolver(); $resolver = new OptionsResolver();
$this->configureOptions($resolver); $this->configureOptions($resolver);
$options = $resolver->resolve($options); $options = $resolver->resolve($options);
@ -104,10 +110,10 @@ class LogDataTable implements DataTableTypeInterface
'render' => fn($value, AbstractLogEntry $context) => $this->logLevelHelper->logLevelToTableColorClass($context->getLevelString()), 'render' => fn($value, AbstractLogEntry $context) => $this->logLevelHelper->logLevelToTableColorClass($context->getLevelString()),
]); ]);
$dataTable->add('symbol', TextColumn::class, [ $dataTable->add('symbol', HTMLColumn::class, [
'label' => '', 'label' => '',
'className' => 'no-colvis', 'className' => 'no-colvis',
'render' => fn($value, AbstractLogEntry $context): string => sprintf( 'data' => fn(AbstractLogEntry $context): string => sprintf(
'<i class="fas fa-fw %s" title="%s"></i>', '<i class="fas fa-fw %s" title="%s"></i>',
$this->logLevelHelper->logLevelToIconClass($context->getLevelString()), $this->logLevelHelper->logLevelToIconClass($context->getLevelString()),
$context->getLevelString() $context->getLevelString()
@ -128,10 +134,10 @@ class LogDataTable implements DataTableTypeInterface
) )
]); ]);
$dataTable->add('type', TextColumn::class, [ $dataTable->add('type', HTMLColumn::class, [
'label' => 'log.type', 'label' => 'log.type',
'propertyPath' => 'type', 'propertyPath' => 'type',
'render' => function (string $value, AbstractLogEntry $context) { 'data' => function (AbstractLogEntry $context, string $value) {
$text = $this->translator->trans('log.type.'.$value); $text = $this->translator->trans('log.type.'.$value);
if ($context instanceof PartStockChangedLogEntry) { if ($context instanceof PartStockChangedLogEntry) {
@ -149,20 +155,20 @@ class LogDataTable implements DataTableTypeInterface
'label' => 'log.level', 'label' => 'log.level',
'visible' => 'system_log' === $options['mode'], 'visible' => 'system_log' === $options['mode'],
'propertyPath' => 'levelString', 'propertyPath' => 'levelString',
'render' => fn(string $value, AbstractLogEntry $context) => $this->translator->trans('log.level.'.$value), 'data' => fn(AbstractLogEntry $context, string $value) => $this->translator->trans('log.level.'.$value),
]); ]);
$dataTable->add('user', TextColumn::class, [ $dataTable->add('user', HTMLColumn::class, [
'label' => 'log.user', 'label' => 'log.user',
'orderField' => 'NATSORT(user.name)', 'orderField' => 'NATSORT(user.name)',
'render' => function ($value, AbstractLogEntry $context): string { 'data' => function (AbstractLogEntry $context): string {
$user = $context->getUser(); $user = $context->getUser();
//If user was deleted, show the info from the username field //If user was deleted, show the info from the username field
if (!$user instanceof User) { if (!$user instanceof User) {
if ($context->isCLIEntry()) { if ($context->isCLIEntry()) {
return sprintf('%s [%s]', return sprintf('%s [%s]',
htmlentities((string) $context->getCLIUsername()), htmlspecialchars((string) $context->getCLIUsername()),
$this->translator->trans('log.cli_user') $this->translator->trans('log.cli_user')
); );
} }
@ -170,7 +176,7 @@ class LogDataTable implements DataTableTypeInterface
//Else we just deal with a deleted user //Else we just deal with a deleted user
return sprintf( return sprintf(
'@%s [%s]', '@%s [%s]',
htmlentities($context->getUsername()), htmlspecialchars($context->getUsername()),
$this->translator->trans('log.target_deleted'), $this->translator->trans('log.target_deleted'),
); );
} }
@ -182,7 +188,7 @@ class LogDataTable implements DataTableTypeInterface
$img_url, $img_url,
$this->userAvatarHelper->getAvatarMdURL($user), $this->userAvatarHelper->getAvatarMdURL($user),
$this->urlGenerator->generate('user_info', ['id' => $user->getID()]), $this->urlGenerator->generate('user_info', ['id' => $user->getID()]),
htmlentities($user->getFullName(true)) htmlspecialchars($user->getFullName(true))
); );
}, },
]); ]);
@ -194,7 +200,7 @@ class LogDataTable implements DataTableTypeInterface
'render' => function (LogTargetType $value, AbstractLogEntry $context) { 'render' => function (LogTargetType $value, AbstractLogEntry $context) {
$class = $value->toClass(); $class = $value->toClass();
if (null !== $class) { if (null !== $class) {
return $this->elementTypeNameGenerator->getLocalizedTypeLabel($class); return $this->elementTypeNameGenerator->typeLabel($class);
} }
return ''; return '';
@ -216,9 +222,9 @@ class LogDataTable implements DataTableTypeInterface
'icon' => 'fas fa-fw fa-eye', 'icon' => 'fas fa-fw fa-eye',
'href' => function ($value, AbstractLogEntry $context) { 'href' => function ($value, AbstractLogEntry $context) {
if ( if (
$context instanceof CollectionElementDeleted ||
($context instanceof TimeTravelInterface ($context instanceof TimeTravelInterface
&& $context->hasOldDataInformation()) && $context->hasOldDataInformation())
|| $context instanceof CollectionElementDeleted
) { ) {
try { try {
$target = $this->logRepo->getTargetElement($context); $target = $this->logRepo->getTargetElement($context);

View file

@ -25,6 +25,7 @@ namespace App\DataTables;
use App\DataTables\Adapters\TwoStepORMAdapter; use App\DataTables\Adapters\TwoStepORMAdapter;
use App\DataTables\Column\EntityColumn; use App\DataTables\Column\EntityColumn;
use App\DataTables\Column\EnumColumn; use App\DataTables\Column\EnumColumn;
use App\DataTables\Column\HTMLColumn;
use App\DataTables\Column\IconLinkColumn; use App\DataTables\Column\IconLinkColumn;
use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\LocaleDateTimeColumn;
use App\DataTables\Column\MarkdownColumn; use App\DataTables\Column\MarkdownColumn;
@ -58,7 +59,7 @@ use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
final class PartsDataTable implements DataTableTypeInterface final readonly class PartsDataTable implements DataTableTypeInterface
{ {
public const LENGTH_MENU = [[10, 25, 50, 100, 250, 500, -1], [10, 25, 50, 100, 250, 500, "All"]]; public const LENGTH_MENU = [[10, 25, 50, 100, 250, 500, -1], [10, 25, 50, 100, 250, 500, "All"]];
@ -94,6 +95,11 @@ final class PartsDataTable implements DataTableTypeInterface
* When adding columns here, add them also to PartTableColumns enum, to make them configurable in the settings! * When adding columns here, add them also to PartTableColumns enum, to make them configurable in the settings!
*************************************************************************************************************/ *************************************************************************************************************/
/*************************************************************************************************************
* Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the
* HTMLColumn, if necessary
************************************************************************************************************/
$this->csh $this->csh
//Color the table rows depending on the review and favorite status //Color the table rows depending on the review and favorite status
->add('row_color', RowClassColumn::class, [ ->add('row_color', RowClassColumn::class, [
@ -109,23 +115,23 @@ final class PartsDataTable implements DataTableTypeInterface
}, },
], visibility_configurable: false) ], visibility_configurable: false)
->add('select', SelectColumn::class, visibility_configurable: false) ->add('select', SelectColumn::class, visibility_configurable: false)
->add('picture', TextColumn::class, [ ->add('picture', HTMLColumn::class, [
'label' => '', 'label' => '',
'className' => 'no-colvis', 'className' => 'no-colvis',
'render' => fn($value, Part $context) => $this->partDataTableHelper->renderPicture($context), 'data' => fn(Part $context) => $this->partDataTableHelper->renderPicture($context),
], visibility_configurable: false) ], visibility_configurable: false)
->add('name', TextColumn::class, [ ->add('name', HTMLColumn::class, [
'label' => $this->translator->trans('part.table.name'), 'label' => $this->translator->trans('part.table.name'),
'render' => fn($value, Part $context) => $this->partDataTableHelper->renderName($context), 'data' => fn(Part $context) => $this->partDataTableHelper->renderName($context),
'orderField' => 'NATSORT(part.name)' 'orderField' => 'NATSORT(part.name)'
]) ])
->add('si_value', TextColumn::class, [ ->add('si_value', TextColumn::class, [
'label' => $this->translator->trans('part.table.si_value'), 'label' => $this->translator->trans('part.table.si_value'),
'render' => function ($value, Part $context): string { 'data' => function (Part $context): string {
$siValue = SiValueSort::sqliteSiValue($context->getName()); $siValue = SiValueSort::sqliteSiValue($context->getName());
if ($siValue !== null) { if ($siValue !== null) {
//Output it as scientific number with a big E //Output it as scientific number with a big E
return htmlspecialchars(sprintf('%G', $siValue)); return sprintf('%G', $siValue);
} }
return ''; return '';
}, },
@ -156,38 +162,38 @@ final class PartsDataTable implements DataTableTypeInterface
'label' => $this->translator->trans('part.table.manufacturer'), 'label' => $this->translator->trans('part.table.manufacturer'),
'orderField' => 'NATSORT(_manufacturer.name)' 'orderField' => 'NATSORT(_manufacturer.name)'
]) ])
->add('storelocation', TextColumn::class, [ ->add('storelocation', HTMLColumn::class, [
'label' => $this->translator->trans('part.table.storeLocations'), 'label' => $this->translator->trans('part.table.storeLocations'),
//We need to use a aggregate function to get the first store location, as we have a one-to-many relation //We need to use a aggregate function to get the first store location, as we have a one-to-many relation
'orderField' => 'NATSORT(MIN(_storelocations.name))', 'orderField' => 'NATSORT(MIN(_storelocations.name))',
'render' => fn($value, Part $context) => $this->partDataTableHelper->renderStorageLocations($context), 'data' => fn(Part $context) => $this->partDataTableHelper->renderStorageLocations($context),
], alias: 'storage_location') ], alias: 'storage_location')
->add('amount', TextColumn::class, [ ->add('amount', HTMLColumn::class, [
'label' => $this->translator->trans('part.table.amount'), 'label' => $this->translator->trans('part.table.amount'),
'render' => fn($value, Part $context) => $this->partDataTableHelper->renderAmount($context), 'data' => fn(Part $context) => $this->partDataTableHelper->renderAmount($context),
'orderField' => 'amountSum' 'orderField' => 'amountSum'
]) ])
->add('minamount', TextColumn::class, [ ->add('minamount', TextColumn::class, [
'label' => $this->translator->trans('part.table.minamount'), 'label' => $this->translator->trans('part.table.minamount'),
'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format( 'data' => fn(Part $context, $value): string => $this->amountFormatter->format(
$value, $value,
$context->getPartUnit() $context->getPartUnit()
)), ),
]) ])
->add('partUnit', TextColumn::class, [ ->add('partUnit', TextColumn::class, [
'label' => $this->translator->trans('part.table.partUnit'), 'label' => $this->translator->trans('part.table.partUnit'),
'orderField' => 'NATSORT(_partUnit.name)', 'orderField' => 'NATSORT(_partUnit.name)',
'render' => function ($value, Part $context): string { 'data' => function (Part $context): string {
$partUnit = $context->getPartUnit(); $partUnit = $context->getPartUnit();
if ($partUnit === null) { if ($partUnit === null) {
return ''; return '';
} }
$tmp = htmlspecialchars($partUnit->getName()); $tmp = $partUnit->getName();
if ($partUnit->getUnit()) { if ($partUnit->getUnit()) {
$tmp .= ' (' . htmlspecialchars($partUnit->getUnit()) . ')'; $tmp .= ' (' . $partUnit->getUnit() . ')';
} }
return $tmp; return $tmp;
} }
@ -195,14 +201,14 @@ final class PartsDataTable implements DataTableTypeInterface
->add('partCustomState', TextColumn::class, [ ->add('partCustomState', TextColumn::class, [
'label' => $this->translator->trans('part.table.partCustomState'), 'label' => $this->translator->trans('part.table.partCustomState'),
'orderField' => 'NATSORT(_partCustomState.name)', 'orderField' => 'NATSORT(_partCustomState.name)',
'render' => function($value, Part $context): string { 'data' => function(Part $context): string {
$partCustomState = $context->getPartCustomState(); $partCustomState = $context->getPartCustomState();
if ($partCustomState === null) { if ($partCustomState === null) {
return ''; return '';
} }
return htmlspecialchars($partCustomState->getName()); return $partCustomState->getName();
} }
]) ])
->add('addedDate', LocaleDateTimeColumn::class, [ ->add('addedDate', LocaleDateTimeColumn::class, [
@ -248,25 +254,25 @@ final class PartsDataTable implements DataTableTypeInterface
]) ])
->add('eda_reference', TextColumn::class, [ ->add('eda_reference', TextColumn::class, [
'label' => $this->translator->trans('part.table.eda_reference'), 'label' => $this->translator->trans('part.table.eda_reference'),
'render' => static fn($value, Part $context) => htmlspecialchars($context->getEdaInfo()->getReferencePrefix() ?? ''), 'data' => static fn(Part $context) => $context->getEdaInfo()->getReferencePrefix() ?? '',
'orderField' => 'NATSORT(part.eda_info.reference_prefix)' 'orderField' => 'NATSORT(part.eda_info.reference_prefix)'
]) ])
->add('eda_value', TextColumn::class, [ ->add('eda_value', TextColumn::class, [
'label' => $this->translator->trans('part.table.eda_value'), 'label' => $this->translator->trans('part.table.eda_value'),
'render' => static fn($value, Part $context) => htmlspecialchars($context->getEdaInfo()->getValue() ?? ''), 'data' => static fn(Part $context) => $context->getEdaInfo()->getValue() ?? '',
'orderField' => 'NATSORT(part.eda_info.value)' 'orderField' => 'NATSORT(part.eda_info.value)'
]) ])
->add('eda_status', TextColumn::class, [ ->add('eda_status', HTMLColumn::class, [
'label' => $this->translator->trans('part.table.eda_status'), 'label' => $this->translator->trans('part.table.eda_status'),
'render' => fn($value, Part $context) => $this->partDataTableHelper->renderEdaStatus($context), 'data' => fn(Part $context) => $this->partDataTableHelper->renderEdaStatus($context),
'className' => 'text-center', 'className' => 'text-center',
]); ]);
//Add a column to list the projects where the part is used, when the user has the permission to see the projects //Add a column to list the projects where the part is used, when the user has the permission to see the projects
if ($this->security->isGranted('read', Project::class)) { if ($this->security->isGranted('read', Project::class)) {
$this->csh->add('projects', TextColumn::class, [ $this->csh->add('projects', HTMLColumn::class, [
'label' => $this->translator->trans('project.labelp'), 'label' => $this->translator->trans('project.labelp'),
'render' => function ($value, Part $context): string { 'data' => function (Part $context): string {
//Only show the first 5 projects names //Only show the first 5 projects names
$projects = $context->getProjects(); $projects = $context->getProjects();
$tmp = ""; $tmp = "";
@ -286,7 +292,7 @@ final class PartsDataTable implements DataTableTypeInterface
} }
return $tmp; return $tmp;
} },
]); ]);
} }

View file

@ -25,6 +25,7 @@ namespace App\DataTables;
use App\DataTables\Adapters\TwoStepORMAdapter; use App\DataTables\Adapters\TwoStepORMAdapter;
use App\DataTables\Column\EntityColumn; use App\DataTables\Column\EntityColumn;
use App\DataTables\Column\EnumColumn; use App\DataTables\Column\EnumColumn;
use App\DataTables\Column\HTMLColumn;
use App\DataTables\Column\LocaleDateTimeColumn; use App\DataTables\Column\LocaleDateTimeColumn;
use App\DataTables\Column\MarkdownColumn; use App\DataTables\Column\MarkdownColumn;
use App\DataTables\Helpers\PartDataTableHelper; use App\DataTables\Helpers\PartDataTableHelper;
@ -48,7 +49,7 @@ use Omines\DataTablesBundle\DataTable;
use Omines\DataTablesBundle\DataTableTypeInterface; use Omines\DataTablesBundle\DataTableTypeInterface;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
class ProjectBomEntriesDataTable implements DataTableTypeInterface final readonly class ProjectBomEntriesDataTable implements DataTableTypeInterface
{ {
public function __construct( public function __construct(
protected EntityURLGenerator $entityURLGenerator, protected EntityURLGenerator $entityURLGenerator,
@ -63,17 +64,22 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
public function configure(DataTable $dataTable, array $options): void public function configure(DataTable $dataTable, array $options): void
{ {
/*************************************************************************************************************
* Avoid using render, as it has no escaping, and is a potential security risk. Use data on TextColumn or the
* HTMLColumn, if necessary
************************************************************************************************************/
$dataTable $dataTable
//->add('select', SelectColumn::class) //->add('select', SelectColumn::class)
->add('picture', TextColumn::class, [ ->add('picture', HTMLColumn::class, [
'label' => '', 'label' => '',
'className' => 'no-colvis', 'className' => 'no-colvis',
'render' => function ($value, ProjectBOMEntry $context) { 'data' => function (ProjectBOMEntry $context) {
if(!$context->getPart() instanceof Part) { if(!$context->getPart() instanceof Part) {
return ''; return '';
} }
return $this->partDataTableHelper->renderPicture($context->getPart()); return $this->partDataTableHelper->renderPicture($context->getPart());
} },
]) ])
->add('id', TextColumn::class, [ ->add('id', TextColumn::class, [
@ -85,27 +91,27 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
'label' => $this->translator->trans('project.bom.quantity'), 'label' => $this->translator->trans('project.bom.quantity'),
'className' => 'text-center', 'className' => 'text-center',
'orderField' => 'bom_entry.quantity', 'orderField' => 'bom_entry.quantity',
'render' => function ($value, ProjectBOMEntry $context): float|string { 'data' => function (ProjectBOMEntry $context): float|string {
//If we have a non-part entry, only show the rounded quantity //If we have a non-part entry, only show the rounded quantity
if (!$context->getPart() instanceof Part) { if (!$context->getPart() instanceof Part) {
return round($context->getQuantity()); return round($context->getQuantity());
} }
//Otherwise use the unit of the part to format the quantity //Otherwise use the unit of the part to format the quantity
return htmlspecialchars($this->amountFormatter->format($context->getQuantity(), $context->getPart()->getPartUnit())); return $this->amountFormatter->format($context->getQuantity(), $context->getPart()->getPartUnit());
}, },
]) ])
->add('partId', TextColumn::class, [ ->add('partId', TextColumn::class, [
'label' => $this->translator->trans('project.bom.part_id'), 'label' => $this->translator->trans('project.bom.part_id'),
'visible' => true, 'visible' => true,
'orderField' => 'part.id', 'orderField' => 'part.id',
'render' => function ($value, ProjectBOMEntry $context) { 'data' => function (ProjectBOMEntry $context) {
return $context->getPart() instanceof Part ? (string) $context->getPart()->getId() : ''; return $context->getPart() instanceof Part ? (string) $context->getPart()->getId() : '';
}, },
]) ])
->add('name', TextColumn::class, [ ->add('name', HTMLColumn::class, [
'label' => $this->translator->trans('part.table.name'), 'label' => $this->translator->trans('part.table.name'),
'orderField' => 'NATSORT(part.name)', 'orderField' => 'NATSORT(part.name)',
'render' => function ($value, ProjectBOMEntry $context) { 'data' => function (ProjectBOMEntry $context) {
if(!$context->getPart() instanceof Part) { if(!$context->getPart() instanceof Part) {
return htmlspecialchars((string) $context->getName()); return htmlspecialchars((string) $context->getName());
} }
@ -123,11 +129,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
'label' => $this->translator->trans('part.table.ipn'), 'label' => $this->translator->trans('part.table.ipn'),
'orderField' => 'NATSORT(part.ipn)', 'orderField' => 'NATSORT(part.ipn)',
'visible' => false, 'visible' => false,
'render' => function ($value, ProjectBOMEntry $context) { 'data' => fn (ProjectBOMEntry $context) => $context->getPart()?->getIpn()
if($context->getPart() instanceof Part) {
return $context->getPart()->getIpn();
}
}
]) ])
->add('description', MarkdownColumn::class, [ ->add('description', MarkdownColumn::class, [
'label' => $this->translator->trans('part.table.description'), 'label' => $this->translator->trans('part.table.description'),
@ -172,9 +174,9 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
}, },
]) ])
->add('mountnames', TextColumn::class, [ ->add('mountnames', HTMLColumn::class, [
'label' => 'project.bom.mountnames', 'label' => 'project.bom.mountnames',
'render' => function ($value, ProjectBOMEntry $context) { 'data' => function (ProjectBOMEntry $context) {
$html = ''; $html = '';
foreach (explode(',', $context->getMountnames()) as $mountname) { foreach (explode(',', $context->getMountnames()) as $mountname) {
@ -184,34 +186,34 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
}, },
]) ])
->add('instockAmount', TextColumn::class, [ ->add('instockAmount', HTMLColumn::class, [
'label' => 'project.bom.instockAmount', 'label' => 'project.bom.instockAmount',
'visible' => false, 'visible' => false,
'render' => function ($value, ProjectBOMEntry $context) { 'data' => function (ProjectBOMEntry $context) {
if ($context->getPart() !== null) { if ($context->getPart() !== null) {
return $this->partDataTableHelper->renderAmount($context->getPart()); return $this->partDataTableHelper->renderAmount($context->getPart());
} }
return ''; return '';
} },
]) ])
->add('storelocation', TextColumn::class, [ ->add('storelocation', HTMLColumn::class, [
'label' => $this->translator->trans('part.table.storeLocations'), 'label' => $this->translator->trans('part.table.storeLocations'),
//We need to use a aggregate function to get the first store location, as we have a one-to-many relation //We need to use a aggregate function to get the first store location, as we have a one-to-many relation
'orderField' => 'NATSORT(MIN(_storelocations.name))', 'orderField' => 'NATSORT(MIN(_storelocations.name))',
'visible' => false, 'visible' => false,
'render' => function ($value, ProjectBOMEntry $context) { 'data' => function (ProjectBOMEntry $context) {
if ($context->getPart() !== null) { if ($context->getPart() !== null) {
return $this->partDataTableHelper->renderStorageLocations($context->getPart()); return $this->partDataTableHelper->renderStorageLocations($context->getPart());
} }
return ''; return '';
} },
]) ])
->add('price', TextColumn::class, [ ->add('price', TextColumn::class, [
'label' => 'project.bom.price', 'label' => 'project.bom.price',
'visible' => false, 'visible' => false,
'render' => function ($value, ProjectBOMEntry $context) { 'data' => function (ProjectBOMEntry $context) {
$price = $this->projectBuildHelper->getEntryUnitPrice($context); $price = $this->projectBuildHelper->getEntryUnitPrice($context);
return $this->moneyFormatter->format($price->toScale(2, RoundingMode::Up)->toFloat(), null, 2, true); return $this->moneyFormatter->format($price->toScale(2, RoundingMode::Up)->toFloat(), null, 2, true);
}, },
@ -219,7 +221,7 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface
->add('ext_price', TextColumn::class, [ ->add('ext_price', TextColumn::class, [
'label' => 'project.bom.ext_price', 'label' => 'project.bom.ext_price',
'visible' => false, 'visible' => false,
'render' => function ($value, ProjectBOMEntry $context) { 'data' => function (ProjectBOMEntry $context) {
$price = $this->projectBuildHelper->getEntryUnitPrice($context); $price = $this->projectBuildHelper->getEntryUnitPrice($context);
return $this->moneyFormatter->format( return $this->moneyFormatter->format(
$price->multipliedBy(BigDecimal::fromFloatShortest($context->getQuantity())) $price->multipliedBy(BigDecimal::fromFloatShortest($context->getQuantity()))

View file

@ -35,8 +35,10 @@ class SetSQLModeMiddlewareDriver extends AbstractDriverMiddleware
{ {
//Only set this on MySQL connections, as other databases don't support this parameter //Only set this on MySQL connections, as other databases don't support this parameter
if($params['driver'] === 'pdo_mysql') { if($params['driver'] === 'pdo_mysql') {
//1002 is \PDO::MYSQL_ATTR_INIT_COMMAND constant value //PDO::MYSQL_ATTR_INIT_COMMAND is deprecated since PHP 8.5 in favor of Pdo\Mysql::ATTR_INIT_COMMAND,
$params['driverOptions'][\PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode, \'ONLY_FULL_GROUP_BY\', \'\'))'; //but the Pdo\Mysql class only exists since PHP 8.4. Both constants have the same value (1002).
$initCommandAttr = class_exists(\Pdo\Mysql::class) ? \Pdo\Mysql::ATTR_INIT_COMMAND : \PDO::MYSQL_ATTR_INIT_COMMAND;
$params['driverOptions'][$initCommandAttr] = 'SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode, \'ONLY_FULL_GROUP_BY\', \'\'))';
} }
return parent::connect($params); return parent::connect($params);

View file

@ -80,7 +80,7 @@ use Symfony\Component\Validator\Constraints as Assert;
) )
], ],
uriVariables: [ uriVariables: [
'id' => new Link(fromProperty: 'children', fromClass: Manufacturer::class) 'id' => new Link(fromProperty: 'children', fromClass: StorageLocation::class)
], ],
normalizationContext: ['groups' => ['location:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'] normalizationContext: ['groups' => ['location:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
)] )]

View file

@ -29,13 +29,13 @@ use Symfony\Contracts\Translation\TranslatorInterface;
/** /**
* Service for validating BOM import data with comprehensive validation rules * Service for validating BOM import data with comprehensive validation rules
* and user-friendly error messages. * and user-friendly error messages. The results are not HTML safe, and must be escaped before display!
*/ */
class BOMValidationService readonly class BOMValidationService
{ {
public function __construct( public function __construct(
private readonly EntityManagerInterface $entityManager, private EntityManagerInterface $entityManager,
private readonly TranslatorInterface $translator private TranslatorInterface $translator
) { ) {
} }

View file

@ -58,7 +58,7 @@
</tr> </tr>
<tr> <tr>
<td>{% trans %}log.target{% endtrans %}</td> <td>{% trans %}log.target{% endtrans %}</td>
<td>{{ target_html|raw }}</td> <td>{{ target_html|sanitize_html }}</td>
</tr> </tr>
</table> </table>
@ -111,7 +111,7 @@
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted') %} {% elseif log_entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted') %}
{% include "log_system/details/_extra_collection_element_deleted.html.twig" %} {% include "log_system/details/_extra_collection_element_deleted.html.twig" %}
{% else %} {% else %}
{{ extra_html | raw }} {{ extra_html | sanitize_html }}
{% endif %} {% endif %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -68,7 +68,7 @@
<p class="mb-2">{% trans %}project.bom_import.validation.errors.description{% endtrans %}</p> <p class="mb-2">{% trans %}project.bom_import.validation.errors.description{% endtrans %}</p>
<ul class="mb-0"> <ul class="mb-0">
{% for error in validation_result.errors %} {% for error in validation_result.errors %}
<li>{{ error|raw }}</li> <li>{{ error }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -80,7 +80,7 @@
<p class="mb-2">{% trans %}project.bom_import.validation.warnings.description{% endtrans %}</p> <p class="mb-2">{% trans %}project.bom_import.validation.warnings.description{% endtrans %}</p>
<ul class="mb-0"> <ul class="mb-0">
{% for warning in validation_result.warnings %} {% for warning in validation_result.warnings %}
<li>{{ warning|raw }}</li> <li>{{ warning }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -91,7 +91,7 @@
<h4><i class="fa-solid fa-info-circle fa-fw"></i> {% trans %}project.bom_import.validation.info.title{% endtrans %}</h4> <h4><i class="fa-solid fa-info-circle fa-fw"></i> {% trans %}project.bom_import.validation.info.title{% endtrans %}</h4>
<ul class="mb-0"> <ul class="mb-0">
{% for info in validation_result.info %} {% for info in validation_result.info %}
<li>{{ info|raw }}</li> <li>{{ info }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
@ -139,21 +139,21 @@
{% if line_result.errors is not empty %} {% if line_result.errors is not empty %}
<div class="text-danger"> <div class="text-danger">
{% for error in line_result.errors %} {% for error in line_result.errors %}
<div><i class="fa-solid fa-exclamation-triangle fa-fw"></i> {{ error|raw }}</div> <div><i class="fa-solid fa-exclamation-triangle fa-fw"></i> {{ error }}</div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
{% if line_result.warnings is not empty %} {% if line_result.warnings is not empty %}
<div class="text-warning"> <div class="text-warning">
{% for warning in line_result.warnings %} {% for warning in line_result.warnings %}
<div><i class="fa-solid fa-exclamation-circle fa-fw"></i> {{ warning|raw }}</div> <div><i class="fa-solid fa-exclamation-circle fa-fw"></i> {{ warning }}</div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
{% if line_result.info is not empty %} {% if line_result.info is not empty %}
<div class="text-info"> <div class="text-info">
{% for info in line_result.info %} {% for info in line_result.info %}
<div><i class="fa-solid fa-info-circle fa-fw"></i> {{ info|raw }}</div> <div><i class="fa-solid fa-info-circle fa-fw"></i> {{ info }}</div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}

View file

@ -132,8 +132,8 @@
<script nonce="{{ csp_nonce('script') }}"> <script nonce="{{ csp_nonce('script') }}">
// Function to initialize the field mapping page // Function to initialize the field mapping page
function initializeFieldMapping() { function initializeFieldMapping() {
const suggestions = {{ suggested_mapping|json_encode|raw }}; const suggestions = JSON.parse("{{ suggested_mapping|json_encode|escape('js')}}");
const fieldNameMapping = {{ field_name_mapping|json_encode|raw }}; const fieldNameMapping = JSON.parse("{{ field_name_mapping|json_encode|escape('js') }}");
Object.keys(suggestions).forEach(function(field) { Object.keys(suggestions).forEach(function(field) {
// Use the sanitized field name from the server-side mapping // Use the sanitized field name from the server-side mapping

View file

@ -1887,9 +1887,9 @@
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
"@types/node@*": "@types/node@*":
version "25.9.2" version "25.9.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-25.9.2.tgz#fc8958e757994b71fee516f9634bdb03d1b19e9f" resolved "https://registry.yarnpkg.com/@types/node/-/node-25.9.3.tgz#11dfe7a33e68fa5c560f0aa76cc5595621ef26b9"
integrity sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw== integrity sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==
dependencies: dependencies:
undici-types ">=7.24.0 <7.24.7" undici-types ">=7.24.0 <7.24.7"
@ -2116,9 +2116,9 @@ acorn-walk@^8.0.0:
acorn "^8.11.0" acorn "^8.11.0"
acorn@^8.0.4, acorn@^8.11.0, acorn@^8.15.0, acorn@^8.16.0: acorn@^8.0.4, acorn@^8.11.0, acorn@^8.15.0, acorn@^8.16.0:
version "8.16.0" version "8.17.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.17.0.tgz#1785adb84faf8d8add10369b93826fc2bd08f1fe"
integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== integrity sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==
adjust-sourcemap-loader@^4.0.0: adjust-sourcemap-loader@^4.0.0:
version "4.0.0" version "4.0.0"
@ -2223,9 +2223,9 @@ base64-js@^1.1.2, base64-js@^1.3.0:
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
baseline-browser-mapping@^2.10.12: baseline-browser-mapping@^2.10.12:
version "2.10.34" version "2.10.37"
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz#dedb606362446777cfe328d30d4ee15056d06303" resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz#3e636475b6b293244e2b23e2c71a2ab9d9e6ba7d"
integrity sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw== integrity sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==
big.js@^5.2.2: big.js@^5.2.2:
version "5.2.2" version "5.2.2"
@ -2310,9 +2310,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001782: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001782:
version "1.0.30001797" version "1.0.30001799"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz#1332709e1439f01ff92085dd17001e0a45897ec0" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz#5c909138c27f1a61219d3e092071c1cc7d32dc55"
integrity sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w== integrity sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==
ccount@^2.0.0: ccount@^2.0.0:
version "2.0.1" version "2.0.1"
@ -2877,9 +2877,9 @@ domhandler@^5.0.2, domhandler@^5.0.3:
domelementtype "^2.3.0" domelementtype "^2.3.0"
dompurify@^3.0.3: dompurify@^3.0.3:
version "3.4.8" version "3.4.10"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.4.8.tgz#6c54f8c207160e7f83fcb7f4fd05a82ac36b1cdc" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.4.10.tgz#96704295b4d8aeefcc8c7a90caa579b0ad69e46a"
integrity sha512-yb1cEmaOum7wFvOCSQxyfgVlv5D47Rc30iZWoMpbDIWTnJ6grDDQyu2KFJzB2k7u0pMuJcQ1zphH//fFnw2tjQ== integrity sha512-0xzNv0e7oYC6yyuOGZIABPM4qtg3QxLFniDNPP4ZP90wR8Yq3zgwpRbrNiT4N3IKqDbbYFEJLV+JWEs19aZ//w==
optionalDependencies: optionalDependencies:
"@types/trusted-types" "^2.0.7" "@types/trusted-types" "^2.0.7"
@ -2902,9 +2902,9 @@ domutils@^3.0.1:
domhandler "^5.0.3" domhandler "^5.0.3"
electron-to-chromium@^1.5.328: electron-to-chromium@^1.5.328:
version "1.5.368" version "1.5.372"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.368.tgz#8e8d4600c5f5f01e891f8f843b4a941afb640412" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz#ae8ac69942a37b231773b8fb01759f73733599e3"
integrity sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw== integrity sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==
emoji-regex@^8.0.0: emoji-regex@^8.0.0:
version "8.0.0" version "8.0.0"
@ -2917,9 +2917,9 @@ emojis-list@^3.0.0:
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
enhanced-resolve@^5.0.0, enhanced-resolve@^5.22.0: enhanced-resolve@^5.0.0, enhanced-resolve@^5.22.0:
version "5.23.0" version "5.24.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.23.0.tgz#dfdf8d1c9065e4b52f8a598356138931c07305f9" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.24.0.tgz#cf14b9768a774cb6a5087220c0dc6e55df6ec35a"
integrity sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA== integrity sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ==
dependencies: dependencies:
graceful-fs "^4.2.4" graceful-fs "^4.2.4"
tapable "^2.3.3" tapable "^2.3.3"
@ -4153,25 +4153,25 @@ path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
pdfkit@^0.18.0: pdfkit@^0.19.1:
version "0.18.0" version "0.19.1"
resolved "https://registry.yarnpkg.com/pdfkit/-/pdfkit-0.18.0.tgz#573efa7f4c78a8ab1362232a05a589b97b292216" resolved "https://registry.yarnpkg.com/pdfkit/-/pdfkit-0.19.1.tgz#633d5f031ce6f1ba6ce141325c6cf87fa6acb0a2"
integrity sha512-NvUwSDZ0eYEzqAiWwVQkRkjYUkZ48kcsHuCO31ykqPPIVkwoSDjDGiwIgHHNtsiwls3z3P/zy4q00hl2chg2Ug== integrity sha512-6Gzk+wDwTs4VSxsR5rCMTnIl5nlmkye1oWB0l2hDB1EX6ZNSIBroKQEv+2+fPPn+stVjyqzmsqRJVDfB9fo5DA==
dependencies: dependencies:
"@noble/ciphers" "^1.0.0" "@noble/ciphers" "^1.0.0"
"@noble/hashes" "^1.6.0" "@noble/hashes" "^1.6.0"
fontkit "^2.0.4" fontkit "^2.0.4"
js-md5 "^0.8.3" js-md5 "^0.8.3"
linebreak "^1.1.0" linebreak "^1.1.0"
png-js "^1.0.0" png-js "^1.1.0"
pdfmake@^0.3.7: pdfmake@^0.3.7:
version "0.3.9" version "0.3.11"
resolved "https://registry.yarnpkg.com/pdfmake/-/pdfmake-0.3.9.tgz#c837b471aa81ea0797b7cdac2a03db8ba65e1b7f" resolved "https://registry.yarnpkg.com/pdfmake/-/pdfmake-0.3.11.tgz#b4504d19b8f31fa5063dc1b847b060faa4f7c5bb"
integrity sha512-V8VIcjMG/yk7oJYhYjtvyLXvop3w3zcIB0bHdG3z1vuW8nVeemzRWu7YrOG7QA9KYaf858MZnCUG6hQ1Bei0vA== integrity sha512-Uc49J9hUMyuqJk+U+PxlpBpPr96A4HOOfesGx609EPr2ue82+5/Smq/KTAkEqh0/jUGSi1fumvqZ5yAWijJTJg==
dependencies: dependencies:
linebreak "^1.1.0" linebreak "^1.1.0"
pdfkit "^0.18.0" pdfkit "^0.19.1"
xmldoc "^2.0.3" xmldoc "^2.0.3"
picocolors@^1.0.0, picocolors@^1.1.0, picocolors@^1.1.1: picocolors@^1.0.0, picocolors@^1.1.0, picocolors@^1.1.1:
@ -4196,7 +4196,7 @@ pkg-dir@^4.2.0:
dependencies: dependencies:
find-up "^4.0.0" find-up "^4.0.0"
png-js@^1.0.0: png-js@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/png-js/-/png-js-1.1.0.tgz#60a135216601f807b88a6d61ac93bd42a32c5ee1" resolved "https://registry.yarnpkg.com/png-js/-/png-js-1.1.0.tgz#60a135216601f807b88a6d61ac93bd42a32c5ee1"
integrity sha512-PM/uYGzGdNSzqeOgly68+6wKQDL1SY0a/N+OEa/+br6LnHWOAJB0Npiamnodfq3jd2LS/i2fMeOKSAILjA+m5Q== integrity sha512-PM/uYGzGdNSzqeOgly68+6wKQDL1SY0a/N+OEa/+br6LnHWOAJB0Npiamnodfq3jd2LS/i2fMeOKSAILjA+m5Q==
@ -4423,9 +4423,9 @@ postcss-reduce-transforms@^7.0.3:
postcss-value-parser "^4.2.0" postcss-value-parser "^4.2.0"
postcss-selector-parser@^7.0.0, postcss-selector-parser@^7.1.1: postcss-selector-parser@^7.0.0, postcss-selector-parser@^7.1.1:
version "7.1.1" version "7.1.4"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz#e75d2e0d843f620e5df69076166f4e16f891cb9f" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz#69dc7a526517572ff6b150e352b36a016017b485"
integrity sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg== integrity sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==
dependencies: dependencies:
cssesc "^3.0.0" cssesc "^3.0.0"
util-deprecate "^1.0.2" util-deprecate "^1.0.2"
@ -4549,9 +4549,9 @@ regjsgen@^0.8.0:
integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==
regjsparser@^0.13.0: regjsparser@^0.13.0:
version "0.13.1" version "0.13.2"
resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.13.1.tgz#0593cbacb27527927692030928ae4d3b878d6f8d" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.13.2.tgz#f654734b5c588b22ba3e21693b30523417180808"
integrity sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw== integrity sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==
dependencies: dependencies:
jsesc "~3.1.0" jsesc "~3.1.0"
@ -4733,9 +4733,9 @@ semver@^6.3.1:
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.2, semver@^7.3.4, semver@^7.6.3: semver@^7.3.2, semver@^7.3.4, semver@^7.6.3:
version "7.8.2" version "7.8.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.2.tgz#194bd65723a28cf82542d2bf176b91c26b343be1" resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.4.tgz#c73eceebae0616934be8dff28a7fd70757c8e696"
integrity sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ== integrity sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==
serialize-javascript@^6.0.2: serialize-javascript@^6.0.2:
version "6.0.2" version "6.0.2"
@ -5171,11 +5171,10 @@ vfile@^6.0.0:
vfile-message "^4.0.0" vfile-message "^4.0.0"
watchpack@^2.5.1: watchpack@^2.5.1:
version "2.5.1" version "2.5.2"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.5.1.tgz#dd38b601f669e0cbf567cb802e75cead82cde102" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.5.2.tgz#e12e82d84674266fc1c6dbfe38891b92ff0522ec"
integrity sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg== integrity sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==
dependencies: dependencies:
glob-to-regexp "^0.4.1"
graceful-fs "^4.1.2" graceful-fs "^4.1.2"
web-namespaces@^2.0.0: web-namespaces@^2.0.0: