Compare commits

..

1 commit

Author SHA1 Message Date
Jan Böhmer
64aac13a08 New translations messages.en.xlf (English) 2025-09-22 00:01:38 +02:00
21 changed files with 1062 additions and 1800 deletions

View file

@ -1 +1 @@
2.2.0
2.1.2

View file

@ -25,6 +25,7 @@
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^3.2.0",
"dompdf/dompdf": "^v3.0.0",
"part-db/swap-bundle": "^6.0.0",
"gregwar/captcha-bundle": "^2.1.0",
"hshn/base64-encoded-file": "^5.0",
"jbtronics/2fa-webauthn": "^3.0.0",
@ -36,7 +37,6 @@
"league/csv": "^9.8.0",
"league/html-to-markdown": "^5.0.1",
"liip/imagine-bundle": "^2.2",
"maennchen/zipstream-php": "2.1",
"nbgrp/onelogin-saml-bundle": "^v2.0.2",
"nelexa/zip": "^4.0",
"nelmio/cors-bundle": "^2.3",
@ -45,7 +45,6 @@
"omines/datatables-bundle": "^0.10.0",
"paragonie/sodium_compat": "^1.21",
"part-db/label-fonts": "^1.0",
"part-db/swap-bundle": "^6.0.0",
"phpoffice/phpspreadsheet": "^5.0.0",
"rhukster/dom-sanitizer": "^1.0",
"runtime/frankenphp-symfony": "^0.2.0",

208
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": "10fd1b276a868a4f195721ac5fcd82de",
"content-hash": "9c3361c37d7c8efd7adef0d83efb86ff",
"packages": [
{
"name": "amphp/amp",
@ -4022,16 +4022,16 @@
},
{
"name": "dompdf/dompdf",
"version": "v3.1.2",
"version": "v3.1.1",
"source": {
"type": "git",
"url": "https://github.com/dompdf/dompdf.git",
"reference": "b3493e35d31a5e76ec24c3b64a29b0034b2f32a6"
"reference": "794ec856134a73d2a69a474c5d4faa47e1e645b1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/b3493e35d31a5e76ec24c3b64a29b0034b2f32a6",
"reference": "b3493e35d31a5e76ec24c3b64a29b0034b2f32a6",
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/794ec856134a73d2a69a474c5d4faa47e1e645b1",
"reference": "794ec856134a73d2a69a474c5d4faa47e1e645b1",
"shasum": ""
},
"require": {
@ -4080,9 +4080,9 @@
"homepage": "https://github.com/dompdf/dompdf",
"support": {
"issues": "https://github.com/dompdf/dompdf/issues",
"source": "https://github.com/dompdf/dompdf/tree/v3.1.2"
"source": "https://github.com/dompdf/dompdf/tree/v3.1.1"
},
"time": "2025-09-23T03:06:41+00:00"
"time": "2025-09-20T17:30:31+00:00"
},
{
"name": "dompdf/php-font-lib",
@ -4945,16 +4945,16 @@
},
{
"name": "jbtronics/dompdf-font-loader-bundle",
"version": "v1.1.5",
"version": "v1.1.4",
"source": {
"type": "git",
"url": "https://github.com/jbtronics/dompdf-font-loader-bundle.git",
"reference": "83a0e50ecceefea0a63915dae758e00788fd067e"
"reference": "1b41014a2dd9e82ba6a62e61deeebe3cdc1eaf1f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jbtronics/dompdf-font-loader-bundle/zipball/83a0e50ecceefea0a63915dae758e00788fd067e",
"reference": "83a0e50ecceefea0a63915dae758e00788fd067e",
"url": "https://api.github.com/repos/jbtronics/dompdf-font-loader-bundle/zipball/1b41014a2dd9e82ba6a62e61deeebe3cdc1eaf1f",
"reference": "1b41014a2dd9e82ba6a62e61deeebe3cdc1eaf1f",
"shasum": ""
},
"require": {
@ -4994,22 +4994,22 @@
],
"support": {
"issues": "https://github.com/jbtronics/dompdf-font-loader-bundle/issues",
"source": "https://github.com/jbtronics/dompdf-font-loader-bundle/tree/v1.1.5"
"source": "https://github.com/jbtronics/dompdf-font-loader-bundle/tree/v1.1.4"
},
"time": "2025-07-25T20:29:05+00:00"
"time": "2025-07-07T20:39:34+00:00"
},
{
"name": "jbtronics/settings-bundle",
"version": "v3.1.1",
"version": "v3.0.1",
"source": {
"type": "git",
"url": "https://github.com/jbtronics/settings-bundle.git",
"reference": "1067dd3d816cd0a6be7ac3d3989587ea05040bd4"
"reference": "9103bd7f78f0b223d1c7167feb824004fc2a9f07"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jbtronics/settings-bundle/zipball/1067dd3d816cd0a6be7ac3d3989587ea05040bd4",
"reference": "1067dd3d816cd0a6be7ac3d3989587ea05040bd4",
"url": "https://api.github.com/repos/jbtronics/settings-bundle/zipball/9103bd7f78f0b223d1c7167feb824004fc2a9f07",
"reference": "9103bd7f78f0b223d1c7167feb824004fc2a9f07",
"shasum": ""
},
"require": {
@ -5070,7 +5070,7 @@
],
"support": {
"issues": "https://github.com/jbtronics/settings-bundle/issues",
"source": "https://github.com/jbtronics/settings-bundle/tree/v3.1.1"
"source": "https://github.com/jbtronics/settings-bundle/tree/v3.0.1"
},
"funding": [
{
@ -5082,7 +5082,7 @@
"type": "github"
}
],
"time": "2025-09-22T22:00:15+00:00"
"time": "2025-08-24T21:20:15+00:00"
},
{
"name": "jfcherng/php-color-output",
@ -6427,29 +6427,36 @@
},
{
"name": "maennchen/zipstream-php",
"version": "2.1.0",
"version": "3.1.2",
"source": {
"type": "git",
"url": "https://github.com/maennchen/ZipStream-PHP.git",
"reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58"
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/c4c5803cc1f93df3d2448478ef79394a5981cc58",
"reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58",
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/aeadcf5c412332eb426c0f9b4485f6accba2a99f",
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f",
"shasum": ""
},
"require": {
"myclabs/php-enum": "^1.5",
"php": ">= 7.1",
"psr/http-message": "^1.0",
"symfony/polyfill-mbstring": "^1.0"
"ext-mbstring": "*",
"ext-zlib": "*",
"php-64bit": "^8.2"
},
"require-dev": {
"brianium/paratest": "^7.7",
"ext-zip": "*",
"guzzlehttp/guzzle": ">= 6.3",
"friendsofphp/php-cs-fixer": "^3.16",
"guzzlehttp/guzzle": "^7.5",
"mikey179/vfsstream": "^1.6",
"phpunit/phpunit": ">= 7.5"
"php-coveralls/php-coveralls": "^2.5",
"phpunit/phpunit": "^11.0",
"vimeo/psalm": "^6.0"
},
"suggest": {
"guzzlehttp/psr7": "^2.4",
"psr/http-message": "^2.0"
},
"type": "library",
"autoload": {
@ -6486,19 +6493,15 @@
],
"support": {
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
"source": "https://github.com/maennchen/ZipStream-PHP/tree/2.1.0"
"source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.2"
},
"funding": [
{
"url": "https://github.com/maennchen",
"type": "github"
},
{
"url": "https://opencollective.com/zipstream",
"type": "open_collective"
}
],
"time": "2020-05-30T13:11:16+00:00"
"time": "2025-01-27T12:07:53+00:00"
},
{
"name": "markbaker/complex",
@ -6777,69 +6780,6 @@
],
"time": "2025-03-24T10:02:05+00:00"
},
{
"name": "myclabs/php-enum",
"version": "1.8.5",
"source": {
"type": "git",
"url": "https://github.com/myclabs/php-enum.git",
"reference": "e7be26966b7398204a234f8673fdad5ac6277802"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/php-enum/zipball/e7be26966b7398204a234f8673fdad5ac6277802",
"reference": "e7be26966b7398204a234f8673fdad5ac6277802",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^7.3 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "1.*",
"vimeo/psalm": "^4.6.2 || ^5.2"
},
"type": "library",
"autoload": {
"psr-4": {
"MyCLabs\\Enum\\": "src/"
},
"classmap": [
"stubs/Stringable.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP Enum contributors",
"homepage": "https://github.com/myclabs/php-enum/graphs/contributors"
}
],
"description": "PHP Enum implementation",
"homepage": "https://github.com/myclabs/php-enum",
"keywords": [
"enum"
],
"support": {
"issues": "https://github.com/myclabs/php-enum/issues",
"source": "https://github.com/myclabs/php-enum/tree/1.8.5"
},
"funding": [
{
"url": "https://github.com/mnapoli",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum",
"type": "tidelift"
}
],
"time": "2025-01-14T11:49:03+00:00"
},
{
"name": "nbgrp/onelogin-saml-bundle",
"version": "v2.0.3",
@ -7588,26 +7528,24 @@
},
{
"name": "paragonie/constant_time_encoding",
"version": "v3.1.1",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git",
"reference": "5e9b582660b997de205a84c02a3aac7c060900c9"
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/5e9b582660b997de205a84c02a3aac7c060900c9",
"reference": "5e9b582660b997de205a84c02a3aac7c060900c9",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512",
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512",
"shasum": ""
},
"require": {
"php": "^8"
},
"require-dev": {
"infection/infection": "^0",
"nikic/php-fuzzer": "^0",
"phpunit/phpunit": "^9|^10|^11",
"vimeo/psalm": "^4|^5|^6"
"phpunit/phpunit": "^9",
"vimeo/psalm": "^4|^5"
},
"type": "library",
"autoload": {
@ -7653,7 +7591,7 @@
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
"source": "https://github.com/paragonie/constant_time_encoding"
},
"time": "2025-09-22T21:00:33+00:00"
"time": "2024-05-08T12:36:18+00:00"
},
{
"name": "paragonie/random_compat",
@ -8929,16 +8867,16 @@
},
{
"name": "psr/http-message",
"version": "1.1",
"version": "2.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
"shasum": ""
},
"require": {
@ -8947,7 +8885,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
"dev-master": "2.0.x-dev"
}
},
"autoload": {
@ -8962,7 +8900,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
@ -8976,9 +8914,9 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/1.1"
"source": "https://github.com/php-fig/http-message/tree/2.0"
},
"time": "2023-04-04T09:50:52+00:00"
"time": "2023-04-04T09:54:51+00:00"
},
{
"name": "psr/link",
@ -18872,16 +18810,16 @@
},
{
"name": "phpunit/phpunit",
"version": "11.5.40",
"version": "11.5.39",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "4102b2f9250d6dd57d1a1c8c4132b1c744b14b1c"
"reference": "ad5597f79d8489d2870073ac0bc0dd0ad1fa9931"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4102b2f9250d6dd57d1a1c8c4132b1c744b14b1c",
"reference": "4102b2f9250d6dd57d1a1c8c4132b1c744b14b1c",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ad5597f79d8489d2870073ac0bc0dd0ad1fa9931",
"reference": "ad5597f79d8489d2870073ac0bc0dd0ad1fa9931",
"shasum": ""
},
"require": {
@ -18905,7 +18843,7 @@
"sebastian/comparator": "^6.3.2",
"sebastian/diff": "^6.0.2",
"sebastian/environment": "^7.2.1",
"sebastian/exporter": "^6.3.1",
"sebastian/exporter": "^6.3.0",
"sebastian/global-state": "^7.0.2",
"sebastian/object-enumerator": "^6.0.1",
"sebastian/type": "^5.1.3",
@ -18953,7 +18891,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.40"
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.39"
},
"funding": [
{
@ -18977,7 +18915,7 @@
"type": "tidelift"
}
],
"time": "2025-09-23T06:23:40+00:00"
"time": "2025-09-14T06:20:41+00:00"
},
{
"name": "rector/rector",
@ -20475,16 +20413,16 @@
},
{
"name": "sebastian/exporter",
"version": "6.3.1",
"version": "6.3.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "8f67e53d3fcaf53105f95cc14f1630493d0fa2e6"
"reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/8f67e53d3fcaf53105f95cc14f1630493d0fa2e6",
"reference": "8f67e53d3fcaf53105f95cc14f1630493d0fa2e6",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3",
"reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3",
"shasum": ""
},
"require": {
@ -20498,7 +20436,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "6.3-dev"
"dev-main": "6.1-dev"
}
},
"autoload": {
@ -20541,27 +20479,15 @@
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"security": "https://github.com/sebastianbergmann/exporter/security/policy",
"source": "https://github.com/sebastianbergmann/exporter/tree/6.3.1"
"source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
"type": "tidelift"
}
],
"time": "2025-09-22T05:34:00+00:00"
"time": "2024-12-05T09:17:50+00:00"
},
{
"name": "sebastian/global-state",

View file

@ -1,33 +0,0 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2025 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/>.
*/
declare(strict_types=1);
/**
* This class extends the default doctrine ORM configuration to enable native lazy objects on PHP 8.4+.
* We have to do this in a PHP file, because the yaml file does not support conditionals on PHP version.
*/
return static function(\Symfony\Config\DoctrineConfig $doctrine) {
//On PHP 8.4+ we can use native lazy objects, which are much more efficient than proxies.
if (PHP_VERSION_ID >= 80400) {
$doctrine->orm()->enableNativeLazyObjects(true);
}
};

View file

@ -4,7 +4,7 @@
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
failOnDeprecation="false"
failOnDeprecation="true"
failOnNotice="true"
failOnWarning="true"
bootstrap="tests/bootstrap.php"

View file

@ -154,18 +154,13 @@ class PartListsController extends AbstractController
$filter_changer($filter);
}
//If we are in a post request for the tables, we only have to apply the filter form if the submit query param was set
//This saves us some time from creating this complicated term on simple list pages, where no special filter is applied
$filterForm = null;
if ($request->getMethod() !== 'POST' || $request->query->has('part_filter')) {
$filterForm = $this->createForm(PartFilterType::class, $filter, ['method' => 'GET']);
if ($form_changer !== null) {
$form_changer($filterForm);
}
$filterForm->handleRequest($formRequest);
$filterForm = $this->createForm(PartFilterType::class, $filter, ['method' => 'GET']);
if($form_changer !== null) {
$form_changer($filterForm);
}
$filterForm->handleRequest($formRequest);
$table = $this->dataTableFactory->createFromType(PartsDataTable::class, array_merge(
['filter' => $filter], $additional_table_vars),
['pageLength' => $this->tableSettings->fullDefaultPageSize, 'lengthMenu' => PartsDataTable::LENGTH_MENU])
@ -191,7 +186,7 @@ class PartListsController extends AbstractController
return $this->render($template, array_merge([
'datatable' => $table,
'filterForm' => $filterForm?->createView(),
'filterForm' => $filterForm->createView(),
], $additonal_template_vars));
}

View file

@ -81,7 +81,7 @@ abstract class AbstractCompany extends AbstractPartsContainingDBElement
/**
* @var string The website of the company
*/
#[Assert\Url(requireTld: false)]
#[Assert\Url]
#[Groups(['full', 'company:read', 'company:write', 'import', 'extended'])]
#[ORM\Column(type: Types::STRING)]
#[Assert\Length(max: 255)]

View file

@ -49,7 +49,7 @@ trait ManufacturerTrait
/**
* @var string The url to the part on the manufacturer's homepage
*/
#[Assert\Url(requireTld: false)]
#[Assert\Url]
#[Groups(['full', 'import', 'part:read', 'part:write'])]
#[ORM\Column(type: Types::TEXT)]
protected string $manufacturer_product_url = '';

View file

@ -124,7 +124,7 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N
/**
* @var string The URL to the product on the supplier's website
*/
#[Assert\Url(requireTld: false)]
#[Assert\Url]
#[Groups(['full', 'import', 'orderdetail:read', 'orderdetail:write'])]
#[ORM\Column(type: Types::TEXT)]
protected string $supplier_product_url = '';

View file

@ -38,7 +38,7 @@ class EnforceEventCommentTypesType extends AbstractType
return EnumType::class;
}
public function configureOptions(OptionsResolver $resolver): void
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'multiple' => true,
@ -46,4 +46,4 @@ class EnforceEventCommentTypesType extends AbstractType
'empty_data' => [],
]);
}
}
}

View file

@ -44,10 +44,10 @@ class LocaleSelectType extends AbstractType
return LocaleType::class;
}
public function configureOptions(OptionsResolver $resolver): void
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'preferred_choices' => $this->preferred_languages,
]);
}
}
}

View file

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace App\Security;
use App\Entity\UserSystem\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AccountStatusException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
@ -52,7 +51,7 @@ final class UserChecker implements UserCheckerInterface
*
* @throws AccountStatusException
*/
public function checkPostAuth(UserInterface $user, ?TokenInterface $token = null): void
public function checkPostAuth(UserInterface $user): void
{
if (!$user instanceof User) {
return;

View file

@ -27,7 +27,6 @@ use App\Entity\ProjectSystem\Project;
use App\Entity\ProjectSystem\ProjectBOMEntry;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
/**
@ -47,7 +46,7 @@ class BOMEntryVoter extends Voter
return $this->supportsAttribute($attribute) && is_a($subject, ProjectBOMEntry::class, true);
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
if (!is_a($subject, ProjectBOMEntry::class, true)) {
return false;
@ -88,4 +87,4 @@ class BOMEntryVoter extends Voter
{
return $subjectType === 'string' || is_a($subjectType, ProjectBOMEntry::class, true);
}
}
}

View file

@ -26,7 +26,6 @@ namespace App\Security\Voter;
use App\Services\UserSystem\PermissionManager;
use App\Services\UserSystem\VoterHelper;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Vote;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
/**
@ -42,7 +41,7 @@ final class HasAccessPermissionsVoter extends Voter
{
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token, ?Vote $vote = null): bool
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
{
$user = $this->helper->resolveUser($token);
return $this->permissionManager->hasAnyPermissionSetToAllowInherited($user);
@ -57,4 +56,4 @@ final class HasAccessPermissionsVoter extends Voter
{
return $attribute === self::ROLE;
}
}
}

View file

@ -1,76 +0,0 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2025 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/>.
*/
declare(strict_types=1);
namespace App\Services\InfoProviderSystem\Providers;
use App\Services\InfoProviderSystem\DTOs\FileDTO;
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
use Symfony\Component\DependencyInjection\Attribute\When;
/**
* This is a provider, which is used during tests. It always returns no results.
*/
#[When(env: 'test')]
class EmptyProvider implements InfoProviderInterface
{
public function getProviderInfo(): array
{
return [
'name' => 'Empty Provider',
'description' => 'This is a test provider',
//'url' => 'https://example.com',
'disabled_help' => 'This provider is disabled for testing purposes'
];
}
public function getProviderKey(): string
{
return 'empty';
}
public function isActive(): bool
{
return true;
}
public function searchByKeyword(string $keyword): array
{
return [
];
}
public function getCapabilities(): array
{
return [
ProviderCapabilities::BASIC,
ProviderCapabilities::FOOTPRINT,
];
}
public function getDetails(string $id): PartDetailDTO
{
throw new \RuntimeException('No part details available');
}
}

View file

@ -305,17 +305,6 @@ class MouserProvider implements InfoProviderInterface
return (float)$val;
}
private function mapCurrencyCode(string $currency): string
{
//Mouser uses "RMB" for Chinese Yuan, but the correct ISO code is "CNY"
if ($currency === "RMB") {
return "CNY";
}
//For all other currencies, we assume that the ISO code is correct
return $currency;
}
/**
* Converts the pricing (StandardPricing field) from the Mouser API to an array of PurchaseInfoDTOs
* @param array $price_breaks
@ -332,7 +321,7 @@ class MouserProvider implements InfoProviderInterface
$prices[] = new PriceDTO(
minimum_discount_amount: $price_break['Quantity'],
price: (string)$number,
currency_iso_code: $this->mapCurrencyCode($price_break['Currency'])
currency_iso_code: $price_break['Currency']
);
}

View file

@ -761,12 +761,12 @@ class BulkInfoProviderImportControllerTest extends WebTestCase
// Create field mappings with multiple keywords
$fieldMappings = [
new \App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO('empty', ['test'], 1)
new \App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO('name', ['lcsc'], 1)
];
// The service should be able to process the request and throw an exception when no results are found
try {
$response = $bulkService->performBulkSearch([$part], $fieldMappings, false);
$bulkService->performBulkSearch([$part], $fieldMappings, false);
$this->fail('Expected RuntimeException to be thrown when no search results are found');
} catch (\RuntimeException $e) {
$this->assertStringContainsString('No search results found', $e->getMessage());

View file

@ -8924,12 +8924,6 @@ Element 1 -&gt; Element 1.2</target>
<target>Bauteil ändern</target>
</segment>
</unit>
<unit id="keLmdcq" name="part_list.action.scrollable_hint">
<segment state="translated">
<source>part_list.action.scrollable_hint</source>
<target>Scrollen Sie, um alle Aktionen anzuzeigen</target>
</segment>
</unit>
<unit id="w3XOUoO" name="part_list.action.action.title">
<segment state="translated">
<source>part_list.action.action.title</source>
@ -9320,72 +9314,6 @@ Element 1 -&gt; Element 1.2</target>
<target>Name des Anhangs</target>
</segment>
</unit>
<unit id="_5zM4Zv" name="filter.bulk_import_job.label">
<segment state="translated">
<source>filter.bulk_import_job.label</source>
<target>Massenimport-Auftrag</target>
</segment>
</unit>
<unit id="rXReB8s" name="filter.bulk_import_job.job_status">
<segment state="translated">
<source>filter.bulk_import_job.job_status</source>
<target>Auftragsstatus</target>
</segment>
</unit>
<unit id="VSY.FIr" name="filter.bulk_import_job.part_status_in_job">
<segment state="translated">
<source>filter.bulk_import_job.part_status_in_job</source>
<target>Bauteile-Status in Auftrag</target>
</segment>
</unit>
<unit id="2Euegw5" name="filter.bulk_import_job.status.pending">
<segment state="translated">
<source>filter.bulk_import_job.status.pending</source>
<target>Ausstehend</target>
</segment>
</unit>
<unit id="JT3CbaE" name="filter.bulk_import_job.status.in_progress">
<segment state="translated">
<source>filter.bulk_import_job.status.in_progress</source>
<target>In Bearbeitung</target>
</segment>
</unit>
<unit id="J9uBFFo" name="filter.bulk_import_job.status.completed">
<segment state="translated">
<source>filter.bulk_import_job.status.completed</source>
<target>Abgeschlossen</target>
</segment>
</unit>
<unit id="lv4PVt2" name="filter.bulk_import_job.status.stopped">
<segment state="translated">
<source>filter.bulk_import_job.status.stopped</source>
<target>Angehalten</target>
</segment>
</unit>
<unit id="0qKD5hC" name="filter.bulk_import_job.status.failed">
<segment state="translated">
<source>filter.bulk_import_job.status.failed</source>
<target>Fehlgeschlagen</target>
</segment>
</unit>
<unit id="q35A9Tf" name="filter.bulk_import_job.part_status.pending">
<segment state="translated">
<source>filter.bulk_import_job.part_status.pending</source>
<target>Ausstehend</target>
</segment>
</unit>
<unit id=".Bxg5IL" name="filter.bulk_import_job.part_status.completed">
<segment state="translated">
<source>filter.bulk_import_job.part_status.completed</source>
<target>Abgeschlossen</target>
</segment>
</unit>
<unit id="kRFtBzL" name="filter.bulk_import_job.part_status.skipped">
<segment state="translated">
<source>filter.bulk_import_job.part_status.skipped</source>
<target>Übersprungen</target>
</segment>
</unit>
<unit id="YcIyWEZ" name="filter.choice_constraint.operator.ANY">
<segment state="translated">
<source>filter.choice_constraint.operator.ANY</source>
@ -10958,12 +10886,6 @@ Element 1 -&gt; Element 1.2</target>
<target>Export als XML</target>
</segment>
</unit>
<unit id="X.gTRGX" name="part_list.action.export_xlsx">
<segment state="translated">
<source>part_list.action.export_xlsx</source>
<target>Export als Excel</target>
</segment>
</unit>
<unit id="w0AgPEI" name="parts.import.title">
<segment state="translated">
<source>parts.import.title</source>
@ -13559,635 +13481,5 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
<target>Min. Vorschaubild-Breite (px)</target>
</segment>
</unit>
<unit id="vkjf5qA" name="info_providers.bulk_import.step1.title">
<segment state="translated">
<source>info_providers.bulk_import.step1.title</source>
<target>Massenimport von Datenquellen Schritt 1</target>
</segment>
</unit>
<unit id="dqV7NUB" name="info_providers.bulk_import.parts_selected">
<segment state="translated">
<source>info_providers.bulk_import.parts_selected</source>
<target>Bauteile ausgewählt</target>
</segment>
</unit>
<unit id="o474JoG" name="info_providers.bulk_import.step1.global_mapping_description">
<segment state="translated">
<source>info_providers.bulk_import.step1.global_mapping_description</source>
<target>Konfigurieren Sie Feldzuordnungen, die auf alle ausgewählten Teile angewendet werden sollen. Beispiel: „MPN → LCSC + Mouser” bedeutet, dass die Anbieter LCSC und Mouser anhand des MPN-Feldes jedes Teils durchsucht werden.</target>
</segment>
</unit>
<unit id="d9OFVmQ" name="info_providers.bulk_import.selected_parts">
<segment state="translated">
<source>info_providers.bulk_import.selected_parts</source>
<target>Ausgewählte Bauteile</target>
</segment>
</unit>
<unit id="0IM.WJg" name="info_providers.bulk_import.field_mappings">
<segment state="translated">
<source>info_providers.bulk_import.field_mappings</source>
<target>Feldzuordnungen</target>
</segment>
</unit>
<unit id="cZb6a7b" name="info_providers.bulk_import.field_mappings_help">
<segment state="translated">
<source>info_providers.bulk_import.field_mappings_help</source>
<target>Legen Sie fest, welche Bauteilefelder mit welchen Informationsanbietern durchsucht werden sollen. Mehrere Zuordnungen werden kombiniert.</target>
</segment>
</unit>
<unit id="hImbHbq" name="info_providers.bulk_import.add_mapping">
<segment state="translated">
<source>info_providers.bulk_import.add_mapping</source>
<target>Zuordnung hinzufügen</target>
</segment>
</unit>
<unit id="u4_QWOb" name="info_providers.bulk_import.search_results.title">
<segment state="translated">
<source>info_providers.bulk_import.search_results.title</source>
<target>Suchergebnisse</target>
</segment>
</unit>
<unit id="aXSJ0L3" name="info_providers.bulk_import.errors">
<segment state="translated">
<source>info_providers.bulk_import.errors</source>
<target>Fehler</target>
</segment>
</unit>
<unit id="TPEhXlb" name="info_providers.bulk_import.results_found">
<segment state="translated">
<source>info_providers.bulk_import.results_found</source>
<target>%count% Ergebnisse gefunden</target>
</segment>
</unit>
<unit id="8coVh8q" name="info_providers.bulk_import.source_field">
<segment state="translated">
<source>info_providers.bulk_import.source_field</source>
<target>Bauteilefeld</target>
</segment>
</unit>
<unit id="VdUOMZf" name="info_providers.bulk_import.view_existing">
<segment state="translated">
<source>info_providers.bulk_import.view_existing</source>
<target>Existierendes ansehen</target>
</segment>
</unit>
<unit id="LPN5MOO" name="info_providers.bulk_search.search_field">
<segment state="translated">
<source>info_providers.bulk_search.search_field</source>
<target>Suchfeld</target>
</segment>
</unit>
<unit id="DTm1q3f" name="info_providers.bulk_search.providers">
<segment state="translated">
<source>info_providers.bulk_search.providers</source>
<target>Datenquellen</target>
</segment>
</unit>
<unit id="5zem1xb" name="info_providers.bulk_import.actions.label">
<segment state="translated">
<source>info_providers.bulk_import.actions.label</source>
<target>Aktionen</target>
</segment>
</unit>
<unit id="rA4WDLA" name="info_providers.bulk_search.providers.help">
<segment state="translated">
<source>info_providers.bulk_search.providers.help</source>
<target>Wählen Sie aus, welche Datenquellen durchsucht werden sollen, wenn Bauteile dieses Feld haben.</target>
</segment>
</unit>
<unit id="OS0qJRC" name="info_providers.bulk_search.submit">
<segment state="translated">
<source>info_providers.bulk_search.submit</source>
<target>Alle Bauteile suchen</target>
</segment>
</unit>
<unit id="ItmvNLj" name="info_providers.bulk_search.field.select">
<segment state="translated">
<source>info_providers.bulk_search.field.select</source>
<target>Wählen Sie ein Feld zum Suchen aus</target>
</segment>
</unit>
<unit id="AKm8Kw9" name="info_providers.bulk_search.field.mpn">
<segment state="translated">
<source>info_providers.bulk_search.field.mpn</source>
<target>Herstellernummer (MPN)</target>
</segment>
</unit>
<unit id="Wne2ljh" name="info_providers.bulk_search.field.name">
<segment state="translated">
<source>info_providers.bulk_search.field.name</source>
<target>Bauteile Name</target>
</segment>
</unit>
<unit id="iOh1gJZ" name="part_list.action.action.info_provider">
<segment state="translated">
<source>part_list.action.action.info_provider</source>
<target>Datenquellen</target>
</segment>
</unit>
<unit id="xukxTs_" name="part_list.action.bulk_info_provider_import">
<segment state="translated">
<source>part_list.action.bulk_info_provider_import</source>
<target>Massenimport von Datenquellen</target>
</segment>
</unit>
<unit id="yzpXFkB" name="info_providers.bulk_import.step1.spn_recommendation">
<segment state="translated">
<source>info_providers.bulk_import.step1.spn_recommendation</source>
<target>Lieferantenteilenummer (SPN) wird für bessere Ergebnisse empfohlen. Fügen Sie für jeden Lieferanten eine Zuordnung hinzu, damit dessen SPNs verwendet werden können.</target>
</segment>
</unit>
<unit id="QDr.VVc" name="info_providers.bulk_import.update_part">
<segment state="translated">
<source>info_providers.bulk_import.update_part</source>
<target>Bauteil aktualisieren</target>
</segment>
</unit>
<unit id="e_DDQ2u" name="info_providers.bulk_import.prefetch_details">
<segment state="translated">
<source>info_providers.bulk_import.prefetch_details</source>
<target>Vorabruf der Bauteiledetails</target>
</segment>
</unit>
<unit id="v4T9Uwz" name="info_providers.bulk_import.prefetch_details_help">
<segment state="translated">
<source>info_providers.bulk_import.prefetch_details_help</source>
<target>Details für alle Ergebnisse vorab abrufen. Dies dauert zwar länger, beschleunigt jedoch den Arbeitsablauf für die Aktualisierung von Bauteilen.</target>
</segment>
</unit>
<unit id="mRdK1ts" name="info_providers.bulk_import.step2.title">
<segment state="translated">
<source>info_providers.bulk_import.step2.title</source>
<target>Massenimport von Informationsquellen</target>
</segment>
</unit>
<unit id="Y.b5mGJ" name="info_providers.bulk_import.step2.card_title">
<segment state="translated">
<source>info_providers.bulk_import.step2.card_title</source>
<target>Massenimport für %count% Bauteile %date%</target>
</segment>
</unit>
<unit id="fyatGYL" name="info_providers.bulk_import.parts">
<segment state="translated">
<source>info_providers.bulk_import.parts</source>
<target>Bauteile</target>
</segment>
</unit>
<unit id="hlBJ6Qh" name="info_providers.bulk_import.results">
<segment state="translated">
<source>info_providers.bulk_import.results</source>
<target>Ergebnisse</target>
</segment>
</unit>
<unit id="V8eTEPM" name="info_providers.bulk_import.created_at">
<segment state="translated">
<source>info_providers.bulk_import.created_at</source>
<target>Erstellt am</target>
</segment>
</unit>
<unit id="CiqevAs" name="info_providers.bulk_import.status.in_progress">
<segment state="translated">
<source>info_providers.bulk_import.status.in_progress</source>
<target>In Bearbeitung</target>
</segment>
</unit>
<unit id="YeLN8i_" name="info_providers.bulk_import.status.completed">
<segment state="translated">
<source>info_providers.bulk_import.status.completed</source>
<target>Abgeschlossen</target>
</segment>
</unit>
<unit id="TIzGVyk" name="info_providers.bulk_import.status.failed">
<segment state="translated">
<source>info_providers.bulk_import.status.failed</source>
<target>Fehlgeschlagen</target>
</segment>
</unit>
<unit id="RxaZ6kn" name="info_providers.bulk_import.table.name">
<segment state="translated">
<source>info_providers.bulk_import.table.name</source>
<target>Name</target>
</segment>
</unit>
<unit id="36MkrQF" name="info_providers.bulk_import.table.description">
<segment state="translated">
<source>info_providers.bulk_import.table.description</source>
<target>Beschreibung</target>
</segment>
</unit>
<unit id="Y_yl259" name="info_providers.bulk_import.table.manufacturer">
<segment state="translated">
<source>info_providers.bulk_import.table.manufacturer</source>
<target>Hersteller</target>
</segment>
</unit>
<unit id="FgXYE1H" name="info_providers.bulk_import.table.provider">
<segment state="translated">
<source>info_providers.bulk_import.table.provider</source>
<target>Quelle</target>
</segment>
</unit>
<unit id="_gf1tWi" name="info_providers.bulk_import.table.source_field">
<segment state="translated">
<source>info_providers.bulk_import.table.source_field</source>
<target>Bauteilefeld</target>
</segment>
</unit>
<unit id="CoSmRQc" name="info_providers.bulk_import.back">
<segment state="translated">
<source>info_providers.bulk_import.back</source>
<target>Zurück</target>
</segment>
</unit>
<unit id="Hn7AtYS" name="info_providers.bulk_import.progress">
<segment state="translated">
<source>info_providers.bulk_import.progress</source>
<target>Fortschritt:</target>
</segment>
</unit>
<unit id="w9LaKAB" name="info_providers.bulk_import.status.pending">
<segment state="translated">
<source>info_providers.bulk_import.status.pending</source>
<target>Ausstehend</target>
</segment>
</unit>
<unit id="KcADJb." name="info_providers.bulk_import.completed">
<segment state="translated">
<source>info_providers.bulk_import.completed</source>
<target>abgeschlossen</target>
</segment>
</unit>
<unit id="hptkZvI" name="info_providers.bulk_import.skipped">
<segment state="translated">
<source>info_providers.bulk_import.skipped</source>
<target>übersprungen</target>
</segment>
</unit>
<unit id="vylzyYJ" name="info_providers.bulk_import.mark_completed">
<segment state="translated">
<source>info_providers.bulk_import.mark_completed</source>
<target>Als abgeschlossen markieren</target>
</segment>
</unit>
<unit id="ePdcL7W" name="info_providers.bulk_import.mark_skipped">
<segment state="translated">
<source>info_providers.bulk_import.mark_skipped</source>
<target>Als übersprungen markieren</target>
</segment>
</unit>
<unit id="3HeDhTB" name="info_providers.bulk_import.mark_pending">
<segment state="translated">
<source>info_providers.bulk_import.mark_pending</source>
<target>Als ausstehend markieren</target>
</segment>
</unit>
<unit id="p.igAUH" name="info_providers.bulk_import.skip_reason">
<segment state="translated">
<source>info_providers.bulk_import.skip_reason</source>
<target>Grund des Überspringens</target>
</segment>
</unit>
<unit id="6bTLFzZ" name="info_providers.bulk_import.editing_part">
<segment state="translated">
<source>info_providers.bulk_import.editing_part</source>
<target>Bearbeite Bauteil als Teil des Massenimports</target>
</segment>
</unit>
<unit id="ItOX1kK" name="info_providers.bulk_import.complete">
<segment state="translated">
<source>info_providers.bulk_import.complete</source>
<target>Abgeschlossen</target>
</segment>
</unit>
<unit id="bHLXJ8Z" name="info_providers.bulk_import.existing_jobs">
<segment state="translated">
<source>info_providers.bulk_import.existing_jobs</source>
<target>Existierende Aufträge</target>
</segment>
</unit>
<unit id="jg2YuGQ" name="info_providers.bulk_import.job_name">
<segment state="translated">
<source>info_providers.bulk_import.job_name</source>
<target>Auftragsname</target>
</segment>
</unit>
<unit id="jUc1.Um" name="info_providers.bulk_import.parts_count">
<segment state="translated">
<source>info_providers.bulk_import.parts_count</source>
<target>Bauteileanzahl</target>
</segment>
</unit>
<unit id="aY1IgEO" name="info_providers.bulk_import.results_count">
<segment state="translated">
<source>info_providers.bulk_import.results_count</source>
<target>Ergebnisanzahl</target>
</segment>
</unit>
<unit id="1GAZk4m" name="info_providers.bulk_import.progress_label">
<segment state="translated">
<source>info_providers.bulk_import.progress_label</source>
<target>Fortschritt: %current%/%total%</target>
</segment>
</unit>
<unit id="k78UdMX" name="info_providers.bulk_import.manage_jobs">
<segment state="translated">
<source>info_providers.bulk_import.manage_jobs</source>
<target>Massenimportaufträge verwalten</target>
</segment>
</unit>
<unit id="mJ73hdI" name="info_providers.bulk_import.view_results">
<segment state="translated">
<source>info_providers.bulk_import.view_results</source>
<target>Ergebnisse anzeigen</target>
</segment>
</unit>
<unit id="d5ZxGBG" name="info_providers.bulk_import.status">
<segment state="translated">
<source>info_providers.bulk_import.status</source>
<target>Status</target>
</segment>
</unit>
<unit id="Z.AgcWf" name="info_providers.bulk_import.manage_jobs_description">
<segment state="translated">
<source>info_providers.bulk_import.manage_jobs_description</source>
<target>Alle Ihre Massenimportaufträge anzeigen und verwalten. Um einen neuen Auftrag zu erstellen, wählen Sie Bauteile aus und klicken Sie auf „Massenimport von Informationsanbietern”.</target>
</segment>
</unit>
<unit id="0lCZLRC" name="info_providers.bulk_import.no_jobs_found">
<segment state="translated">
<source>info_providers.bulk_import.no_jobs_found</source>
<target>Es wurden keine Massenimportaufträge gefunden.</target>
</segment>
</unit>
<unit id="LheSXys" name="info_providers.bulk_import.create_first_job">
<segment state="translated">
<source>info_providers.bulk_import.create_first_job</source>
<target>Erstellen Sie Ihren ersten Massenimportauftrag, indem Sie mehrere Bauteile in einer Bauteiletabelle auswählen und die Option „Massenimport aus Informationsanbieter“ auswählen.</target>
</segment>
</unit>
<unit id="Lm_DPbH" name="info_providers.bulk_import.confirm_delete_job">
<segment state="translated">
<source>info_providers.bulk_import.confirm_delete_job</source>
<target>Möchten Sie diesen Auftrag wirklich löschen?</target>
</segment>
</unit>
<unit id="kZd.W42" name="info_providers.bulk_import.job_name_template">
<segment state="translated">
<source>info_providers.bulk_import.job_name_template</source>
<target>Massenimport für %count% Teile</target>
</segment>
</unit>
<unit id="W6GycWK" name="info_providers.bulk_import.step2.instructions.title">
<segment state="translated">
<source>info_providers.bulk_import.step2.instructions.title</source>
<target>So verwenden Sie den Massenimport</target>
</segment>
</unit>
<unit id="QTkki_T" name="info_providers.bulk_import.step2.instructions.description">
<segment state="translated">
<source>info_providers.bulk_import.step2.instructions.description</source>
<target>Befolgen Sie diese Schritte, um Ihre Teile effizient zu aktualisieren:</target>
</segment>
</unit>
<unit id="OI1oD42" name="info_providers.bulk_import.step2.instructions.step1">
<segment state="translated">
<source>info_providers.bulk_import.step2.instructions.step1</source>
<target>Klicken Sie auf „Teil aktualisieren“, um ein Teil aus den Informationsquellen zu aktualisieren.</target>
</segment>
</unit>
<unit id="U.QKhv." name="info_providers.bulk_import.step2.instructions.step2">
<segment state="translated">
<source>info_providers.bulk_import.step2.instructions.step2</source>
<target>Überprüfen und ändern Sie die Teileinformationen nach Bedarf. Hinweis: Sie müssen zweimal auf „Speichern“ klicken, um die Änderungen zu speichern.</target>
</segment>
</unit>
<unit id="WlnTz0N" name="info_providers.bulk_import.step2.instructions.step3">
<segment state="translated">
<source>info_providers.bulk_import.step2.instructions.step3</source>
<target>Klicken Sie auf „Abgeschlossen“, um den Teil als erledigt zu markieren und zu dieser Übersicht zurückzukehren.</target>
</segment>
</unit>
<unit id="IyXU.4X" name="info_providers.bulk_import.created_by">
<segment state="translated">
<source>info_providers.bulk_import.created_by</source>
<target>Erstellt von</target>
</segment>
</unit>
<unit id="egSjRGI" name="info_providers.bulk_import.completed_at">
<segment state="translated">
<source>info_providers.bulk_import.completed_at</source>
<target>Abgeschlossen am</target>
</segment>
</unit>
<unit id="9L.HbvX" name="info_providers.bulk_import.action.label">
<segment state="translated">
<source>info_providers.bulk_import.action.label</source>
<target>Aktion</target>
</segment>
</unit>
<unit id="vcNdo9m" name="info_providers.bulk_import.action.delete">
<segment state="translated">
<source>info_providers.bulk_import.action.delete</source>
<target>Löschen</target>
</segment>
</unit>
<unit id="bE3MUIU" name="info_providers.bulk_import.status.active">
<segment state="translated">
<source>info_providers.bulk_import.status.active</source>
<target>Aktiv</target>
</segment>
</unit>
<unit id="R3FVzb3" name="info_providers.bulk_import.progress.title">
<segment state="translated">
<source>info_providers.bulk_import.progress.title</source>
<target>Fortschritt</target>
</segment>
</unit>
<unit id="pKciwfa" name="info_providers.bulk_import.progress.completed_text">
<segment state="translated">
<source>info_providers.bulk_import.progress.completed_text</source>
<target>%completed%/%total% abgeschlossen</target>
</segment>
</unit>
<unit id="9yPFVrM" name="info_providers.bulk_import.status.stopped">
<segment state="translated">
<source>info_providers.bulk_import.status.stopped</source>
<target>Angehalten</target>
</segment>
</unit>
<unit id="we_yrOV" name="info_providers.bulk_import.action.stop">
<segment state="translated">
<source>info_providers.bulk_import.action.stop</source>
<target>Stop</target>
</segment>
</unit>
<unit id="SNkUbfh" name="info_providers.bulk_import.confirm_stop_job">
<segment state="translated">
<source>info_providers.bulk_import.confirm_stop_job</source>
<target>Sind sie sicher, dass sie diesen Auftrag anhalten wollen?</target>
</segment>
</unit>
<unit id="dlO_h_K" name="part.filter.in_bulk_import_job">
<segment state="translated">
<source>part.filter.in_bulk_import_job</source>
<target>Im Massenimport-Auftrag</target>
</segment>
</unit>
<unit id="rOeRN8O" name="part.filter.bulk_import_job_status">
<segment state="translated">
<source>part.filter.bulk_import_job_status</source>
<target>Status des Massenimportauftrags</target>
</segment>
</unit>
<unit id="940sEqZ" name="part.filter.bulk_import_part_status">
<segment state="translated">
<source>part.filter.bulk_import_part_status</source>
<target>Status des Bauteils im Massenimport</target>
</segment>
</unit>
<unit id="rv.QfEA" name="part.edit.tab.bulk_import">
<segment state="translated">
<source>part.edit.tab.bulk_import</source>
<target>Massenimportauftrag</target>
</segment>
</unit>
<unit id="BUAqJHD" name="bulk_import.status.pending">
<segment state="translated">
<source>bulk_import.status.pending</source>
<target>Ausstehend</target>
</segment>
</unit>
<unit id="GkVa8H3" name="bulk_import.status.in_progress">
<segment state="translated">
<source>bulk_import.status.in_progress</source>
<target>In Bearbeitung</target>
</segment>
</unit>
<unit id="da3QKdj" name="bulk_import.status.completed">
<segment state="translated">
<source>bulk_import.status.completed</source>
<target>Abgeschlossen</target>
</segment>
</unit>
<unit id="YM7qaAP" name="bulk_import.status.stopped">
<segment state="translated">
<source>bulk_import.status.stopped</source>
<target>Angehalten</target>
</segment>
</unit>
<unit id="5SSBsBs" name="bulk_import.status.failed">
<segment state="translated">
<source>bulk_import.status.failed</source>
<target>Fehlgeschlagen</target>
</segment>
</unit>
<unit id="JprgheW" name="bulk_import.part_status.pending">
<segment state="translated">
<source>bulk_import.part_status.pending</source>
<target>Ausstehend</target>
</segment>
</unit>
<unit id="iDoZxrE" name="bulk_import.part_status.completed">
<segment state="translated">
<source>bulk_import.part_status.completed</source>
<target>Abgeschlossen</target>
</segment>
</unit>
<unit id="KInkh07" name="bulk_import.part_status.skipped">
<segment state="translated">
<source>bulk_import.part_status.skipped</source>
<target>Übersprungen</target>
</segment>
</unit>
<unit id="tmVFe1V" name="bulk_import.part_status.failed">
<segment state="translated">
<source>bulk_import.part_status.failed</source>
<target>Fehlgeschlagen</target>
</segment>
</unit>
<unit id="Jxg8Jia" name="bulk_info_provider_import_job.label">
<segment state="translated">
<source>bulk_info_provider_import_job.label</source>
<target>Massenimport von Informationquellen</target>
</segment>
</unit>
<unit id="SV1_VvJ" name="bulk_info_provider_import_job_part.label">
<segment state="translated">
<source>bulk_info_provider_import_job_part.label</source>
<target>Massenimportauftrag Bauteil</target>
</segment>
</unit>
<unit id="XQV7AkF" name="info_providers.bulk_search.priority">
<segment state="translated">
<source>info_providers.bulk_search.priority</source>
<target>Priorität</target>
</segment>
</unit>
<unit id="XR9mZP_" name="info_providers.bulk_search.priority.help">
<segment state="translated">
<source>info_providers.bulk_search.priority.help</source>
<target>Niedrigere Zahlen = höhere Priorität. Gleiche Priorität = Ergebnisse kombinieren. Unterschiedliche Prioritäten = zuerst die höchste versuchen, bei fehlenden Ergebnissen auf die niedrigere zurückgreifen.</target>
</segment>
</unit>
<unit id="Iz3Ow0_" name="info_providers.bulk_import.priority_system.title">
<segment state="translated">
<source>info_providers.bulk_import.priority_system.title</source>
<target>Prioritätssystem</target>
</segment>
</unit>
<unit id="CPwXFjE" name="info_providers.bulk_import.priority_system.description">
<segment state="translated">
<source>info_providers.bulk_import.priority_system.description</source>
<target>Lower numbers = higher priority. Same priority = combine results. Different priorities = try highest first, fallback if no results.</target>
</segment>
</unit>
<unit id="v.rTI5s" name="info_providers.bulk_import.priority_system.example">
<segment state="translated">
<source>info_providers.bulk_import.priority_system.example</source>
<target>Beispiel: Priorität 1: „LCSC SPN → LCSC“, Priorität 2: „MPN → LCSC + Mouser“, Priorität 3: „Name → Alle Anbieter“</target>
</segment>
</unit>
<unit id="yMhBL_K" name="info_providers.bulk_import.search.submit">
<segment state="translated">
<source>info_providers.bulk_import.search.submit</source>
<target>Datenquellen</target>
</segment>
</unit>
<unit id="NSXIcCk" name="info_providers.bulk_import.research.title">
<segment state="translated">
<source>info_providers.bulk_import.research.title</source>
<target>Bauteile erneut suchen</target>
</segment>
</unit>
<unit id="i53VvpV" name="info_providers.bulk_import.research.description">
<segment state="translated">
<source>info_providers.bulk_import.research.description</source>
<target>Erneute Suche nach Teilen unter Verwendung aktualisierter Informationen (z. B. neue MPNs). Verwendet dieselben Feldzuordnungen wie die ursprüngliche Suche.</target>
</segment>
</unit>
<unit id="S2HVT9P" name="info_providers.bulk_import.research.all_pending">
<segment state="translated">
<source>info_providers.bulk_import.research.all_pending</source>
<target>Alle ausstehenden Teile erneut suchen</target>
</segment>
</unit>
<unit id="ri9TEXX" name="info_providers.bulk_import.research.part">
<segment state="translated">
<source>info_providers.bulk_import.research.part</source>
<target>Erneut suchen</target>
</segment>
</unit>
<unit id="izeEDar" name="info_providers.bulk_import.research.part_tooltip">
<segment state="translated">
<source>info_providers.bulk_import.research.part_tooltip</source>
<target>Dieses Bauteil mit aktualisierten Informationen erneut suchen</target>
</segment>
</unit>
<unit id="jPCU0MO" name="info_providers.bulk_import.max_mappings_reached">
<segment state="translated">
<source>info_providers.bulk_import.max_mappings_reached</source>
<target>Maximale Anzahl von Zuordnungen erreicht</target>
</segment>
</unit>
</file>
</xliff>

View file

@ -9339,6 +9339,12 @@ Element 1 -&gt; Element 1.2</target>
<target>Part Status in Job</target>
</segment>
</unit>
<unit id="LS0ckg6" name="filter.bulk_import_job.status.any">
<segment state="translated">
<source>filter.bulk_import_job.status.any</source>
<target>Any Status</target>
</segment>
</unit>
<unit id="2Euegw5" name="filter.bulk_import_job.status.pending">
<segment state="translated">
<source>filter.bulk_import_job.status.pending</source>
@ -9369,6 +9375,12 @@ Element 1 -&gt; Element 1.2</target>
<target>Failed</target>
</segment>
</unit>
<unit id="T1zyhcD" name="filter.bulk_import_job.part_status.any">
<segment state="translated">
<source>filter.bulk_import_job.part_status.any</source>
<target>Any Part Status</target>
</segment>
</unit>
<unit id="q35A9Tf" name="filter.bulk_import_job.part_status.pending">
<segment state="translated">
<source>filter.bulk_import_job.part_status.pending</source>
@ -13626,6 +13638,12 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>Source Field</target>
</segment>
</unit>
<unit id="eL7WKtX" name="info_providers.bulk_import.create_part">
<segment state="translated">
<source>info_providers.bulk_import.create_part</source>
<target>Create Part</target>
</segment>
</unit>
<unit id="VdUOMZf" name="info_providers.bulk_import.view_existing">
<segment state="translated">
<source>info_providers.bulk_import.view_existing</source>
@ -13692,6 +13710,18 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>Bulk Info Provider Import</target>
</segment>
</unit>
<unit id="HtoFAm0" name="info_providers.bulk_import.clear_selections">
<segment state="translated">
<source>info_providers.bulk_import.clear_selections</source>
<target>Clear All Selections</target>
</segment>
</unit>
<unit id="CHfk1d." name="info_providers.bulk_import.clear_row">
<segment state="translated">
<source>info_providers.bulk_import.clear_row</source>
<target>Clear this row's selections</target>
</segment>
</unit>
<unit id="yzpXFkB" name="info_providers.bulk_import.step1.spn_recommendation">
<segment state="translated">
<source>info_providers.bulk_import.step1.spn_recommendation</source>
@ -13794,18 +13824,126 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>Source Field</target>
</segment>
</unit>
<unit id="9iBuLfS" name="info_providers.bulk_import.table.action">
<segment state="translated">
<source>info_providers.bulk_import.table.action</source>
<target>Action</target>
</segment>
</unit>
<unit id="qgyoLWA" name="info_providers.bulk_import.action.select">
<segment state="translated">
<source>info_providers.bulk_import.action.select</source>
<target>Select</target>
</segment>
</unit>
<unit id="aSo.jkT" name="info_providers.bulk_import.action.deselect">
<segment state="translated">
<source>info_providers.bulk_import.action.deselect</source>
<target>Deselect</target>
</segment>
</unit>
<unit id="ViKzR5M" name="info_providers.bulk_import.action.view_details">
<segment state="translated">
<source>info_providers.bulk_import.action.view_details</source>
<target>View Details</target>
</segment>
</unit>
<unit id="8qnf_gP" name="info_providers.bulk_import.no_results">
<segment state="translated">
<source>info_providers.bulk_import.no_results</source>
<target>No results found</target>
</segment>
</unit>
<unit id="KDNhQMH" name="info_providers.bulk_import.processing">
<segment state="translated">
<source>info_providers.bulk_import.processing</source>
<target>Processing...</target>
</segment>
</unit>
<unit id="eGaXfru" name="info_providers.bulk_import.error">
<segment state="translated">
<source>info_providers.bulk_import.error</source>
<target>Error occurred during import</target>
</segment>
</unit>
<unit id="HiczSH4" name="info_providers.bulk_import.success">
<segment state="translated">
<source>info_providers.bulk_import.success</source>
<target>Import completed successfully</target>
</segment>
</unit>
<unit id="yt3kZvQ" name="info_providers.bulk_import.partial_success">
<segment state="translated">
<source>info_providers.bulk_import.partial_success</source>
<target>Import completed with some errors</target>
</segment>
</unit>
<unit id="LrlWQ0." name="info_providers.bulk_import.retry">
<segment state="translated">
<source>info_providers.bulk_import.retry</source>
<target>Retry</target>
</segment>
</unit>
<unit id="mjzOCYY" name="info_providers.bulk_import.cancel">
<segment state="translated">
<source>info_providers.bulk_import.cancel</source>
<target>Cancel</target>
</segment>
</unit>
<unit id="QphMXMq" name="info_providers.bulk_import.confirm">
<segment state="translated">
<source>info_providers.bulk_import.confirm</source>
<target>Confirm Import</target>
</segment>
</unit>
<unit id="CoSmRQc" name="info_providers.bulk_import.back">
<segment state="translated">
<source>info_providers.bulk_import.back</source>
<target>Back</target>
</segment>
</unit>
<unit id="Flgdv5w" name="info_providers.bulk_import.next">
<segment state="translated">
<source>info_providers.bulk_import.next</source>
<target>Next</target>
</segment>
</unit>
<unit id="N8uN_eL" name="info_providers.bulk_import.finish">
<segment state="translated">
<source>info_providers.bulk_import.finish</source>
<target>Finish</target>
</segment>
</unit>
<unit id="Hn7AtYS" name="info_providers.bulk_import.progress">
<segment state="translated">
<source>info_providers.bulk_import.progress</source>
<target>Progress:</target>
</segment>
</unit>
<unit id="FfSQT4T" name="info_providers.bulk_import.time_remaining">
<segment state="translated">
<source>info_providers.bulk_import.time_remaining</source>
<target>Estimated time remaining: %time%</target>
</segment>
</unit>
<unit id="g1pqdBr" name="info_providers.bulk_import.details_modal.title">
<segment state="translated">
<source>info_providers.bulk_import.details_modal.title</source>
<target>Part Details</target>
</segment>
</unit>
<unit id="_P5nIFz" name="info_providers.bulk_import.details_modal.close">
<segment state="translated">
<source>info_providers.bulk_import.details_modal.close</source>
<target>Close</target>
</segment>
</unit>
<unit id="GGMVm_." name="info_providers.bulk_import.details_modal.select_this_part">
<segment state="translated">
<source>info_providers.bulk_import.details_modal.select_this_part</source>
<target>Select This Part</target>
</segment>
</unit>
<unit id="w9LaKAB" name="info_providers.bulk_import.status.pending">
<segment state="translated">
<source>info_providers.bulk_import.status.pending</source>
@ -14010,6 +14148,24 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>%completed% / %total% completed</target>
</segment>
</unit>
<unit id="Y53fY_F" name="info_providers.bulk_import.error.deleting_job">
<segment state="translated">
<source>info_providers.bulk_import.error.deleting_job</source>
<target>Error deleting job</target>
</segment>
</unit>
<unit id="i.EWgLw" name="info_providers.bulk_import.error.unknown">
<segment state="translated">
<source>info_providers.bulk_import.error.unknown</source>
<target>Unknown error</target>
</segment>
</unit>
<unit id="XrRgd0t" name="info_providers.bulk_import.error.deleting_job_with_details">
<segment state="translated">
<source>info_providers.bulk_import.error.deleting_job_with_details</source>
<target>Error deleting job: %error%</target>
</segment>
</unit>
<unit id="9yPFVrM" name="info_providers.bulk_import.status.stopped">
<segment state="translated">
<source>info_providers.bulk_import.status.stopped</source>
@ -14034,6 +14190,18 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>In Bulk Import Job</target>
</segment>
</unit>
<unit id="Q9UiUw." name="part.filter.in_bulk_import_job.yes">
<segment state="translated">
<source>part.filter.in_bulk_import_job.yes</source>
<target>Yes</target>
</segment>
</unit>
<unit id="6m0ooZf" name="part.filter.in_bulk_import_job.no">
<segment state="translated">
<source>part.filter.in_bulk_import_job.no</source>
<target>No</target>
</segment>
</unit>
<unit id="rOeRN8O" name="part.filter.bulk_import_job_status">
<segment state="translated">
<source>part.filter.bulk_import_job_status</source>
@ -14106,6 +14274,12 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>Failed</target>
</segment>
</unit>
<unit id="Unr5IS7" name="filter.operator">
<segment state="translated">
<source>filter.operator</source>
<target>Operator</target>
</segment>
</unit>
<unit id="Jxg8Jia" name="bulk_info_provider_import_job.label">
<segment state="translated">
<source>bulk_info_provider_import_job.label</source>
@ -14154,6 +14328,12 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>Search Providers</target>
</segment>
</unit>
<unit id="pPndxuf" name="info_providers.bulk_import.searching">
<segment state="translated">
<source>info_providers.bulk_import.searching</source>
<target>Searching</target>
</segment>
</unit>
<unit id="NSXIcCk" name="info_providers.bulk_import.research.title">
<segment state="translated">
<source>info_providers.bulk_import.research.title</source>

View file

@ -1,23 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="pl">
<file id="security.en">
<unit id="GrLNa9P" name="user.login_error.user_disabled">
<unit id="aazoCks" name="user.login_error.user_disabled">
<segment state="translated">
<source>user.login_error.user_disabled</source>
<target>Twoje konto jest wyłączone! Skontaktuj się z administratorem, jeśli uważasz, że jest to niewłaściwe.</target>
</segment>
</unit>
<unit id="IFQ5XrG" name="saml.error.cannot_login_local_user_per_saml">
<unit id="Dpb9AmY" name="saml.error.cannot_login_local_user_per_saml">
<segment state="translated">
<source>saml.error.cannot_login_local_user_per_saml</source>
<target>Nie możesz zalogować się jako użytkownik lokalny poprzez SSO! Zamiast tego użyj hasła użytkownika lokalnego.</target>
</segment>
</unit>
<unit id="wOYPZmb" name="saml.error.cannot_login_saml_user_locally">
<segment state="translated">
<source>saml.error.cannot_login_saml_user_locally</source>
<target>Nie można zalogować się lokalnie do tego użytkownika</target>
</segment>
</unit>
</file>
</xliff>

1579
yarn.lock

File diff suppressed because it is too large Load diff