mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-07-30 13:11:39 +00:00
Compare commits
24 commits
e0d100732a
...
abcaa4da90
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abcaa4da90 | ||
|
|
523b07ef2f | ||
|
|
ffe2f8004b | ||
|
|
7244803937 | ||
|
|
214646caa6 | ||
|
|
ffcfdb793f | ||
|
|
e03eda84c5 | ||
|
|
4d3e2e28a5 | ||
|
|
8ed14ca708 | ||
|
|
34257332ff | ||
|
|
2503e63bb2 | ||
|
|
0eba7121aa | ||
|
|
188444b30f | ||
|
|
cd87b59c15 | ||
|
|
b3895c1e91 | ||
|
|
23e22b19e2 | ||
|
|
9c919a9be9 | ||
|
|
eb7da91c44 | ||
|
|
b8fc5d4ace | ||
|
|
fe0809230b | ||
|
|
9d4dabbd20 | ||
|
|
5e18ae2874 | ||
|
|
3e725dd2ec | ||
|
|
ec80115d0a |
66 changed files with 8180 additions and 3660 deletions
2
.github/workflows/assets_artifact_build.yml
vendored
2
.github/workflows/assets_artifact_build.yml
vendored
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
APP_ENV: prod
|
APP_ENV: prod
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
|
|
|
||||||
2
.github/workflows/docker_build.yml
vendored
2
.github/workflows/docker_build.yml
vendored
|
|
@ -32,7 +32,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v7
|
||||||
-
|
-
|
||||||
name: Docker meta
|
name: Docker meta
|
||||||
id: docker_meta
|
id: docker_meta
|
||||||
|
|
|
||||||
2
.github/workflows/docker_frankenphp.yml
vendored
2
.github/workflows/docker_frankenphp.yml
vendored
|
|
@ -32,7 +32,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
-
|
-
|
||||||
name: Checkout
|
name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v7
|
||||||
-
|
-
|
||||||
name: Docker meta
|
name: Docker meta
|
||||||
id: docker_meta
|
id: docker_meta
|
||||||
|
|
|
||||||
2
.github/workflows/static_analysis.yml
vendored
2
.github/workflows/static_analysis.yml
vendored
|
|
@ -19,7 +19,7 @@ jobs:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
|
|
|
||||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
|
@ -46,7 +46,7 @@ jobs:
|
||||||
if: matrix.db-type == 'postgres'
|
if: matrix.db-type == 'postgres'
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
|
|
|
||||||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
2.12.3
|
2.13.1
|
||||||
|
|
|
||||||
717
composer.lock
generated
717
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -2,3 +2,4 @@ ai:
|
||||||
platform:
|
platform:
|
||||||
lmstudio:
|
lmstudio:
|
||||||
host_url: '%env(string:settings:ai_lmstudio:hostURL)%'
|
host_url: '%env(string:settings:ai_lmstudio:hostURL)%'
|
||||||
|
http_client: 'app.http_client.ai_lmstudio'
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,4 @@ ai:
|
||||||
ollama:
|
ollama:
|
||||||
endpoint: '%env(string:settings:ai_ollama:endpoint)%'
|
endpoint: '%env(string:settings:ai_ollama:endpoint)%'
|
||||||
api_key: '%env(string:settings:ai_ollama:apiKey)%'
|
api_key: '%env(string:settings:ai_ollama:apiKey)%'
|
||||||
|
http_client: 'app.http_client.ai_ollama'
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@ ai:
|
||||||
platform:
|
platform:
|
||||||
openrouter:
|
openrouter:
|
||||||
api_key: '%env(string:settings:ai_openrouter:apiKey)%'
|
api_key: '%env(string:settings:ai_openrouter:apiKey)%'
|
||||||
|
http_client: 'app.http_client.ai_openrouter'
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
services:
|
|
||||||
EasyCorp\EasyLog\EasyLogHandler:
|
|
||||||
public: false
|
|
||||||
arguments: ['%kernel.logs_dir%/%kernel.environment%.log']
|
|
||||||
|
|
||||||
#// FIXME: How to add this configuration automatically without messing up with the monolog configuration?
|
|
||||||
#monolog:
|
|
||||||
# handlers:
|
|
||||||
# buffered:
|
|
||||||
# type: buffer
|
|
||||||
# handler: easylog
|
|
||||||
# channels: ['!event']
|
|
||||||
# level: debug
|
|
||||||
# easylog:
|
|
||||||
# type: service
|
|
||||||
# id: EasyCorp\EasyLog\EasyLogHandler
|
|
||||||
|
|
@ -20,16 +20,16 @@
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use Symfony\Config\DoctrineConfig;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class extends the default doctrine ORM configuration to enable native lazy objects on PHP 8.4+.
|
* This file enables 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.
|
* We have to do this in a PHP file, because the yaml file does not support conditionals on PHP version.
|
||||||
|
*
|
||||||
|
* TODO: Remove this file when we drop support for PHP < 8.4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return static function(DoctrineConfig $doctrine) {
|
// On PHP 8.4+ we can use native lazy objects, which are much more efficient than proxies.
|
||||||
//On PHP 8.4+ we can use native lazy objects, which are much more efficient than proxies.
|
if (PHP_VERSION_ID >= 80400) {
|
||||||
if (PHP_VERSION_ID >= 80400) {
|
return ['doctrine' => ['orm' => ['enable_native_lazy_objects' => true]]];
|
||||||
$doctrine->orm()->enableNativeLazyObjects(true);
|
}
|
||||||
}
|
|
||||||
};
|
return [];
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||||
* }
|
* }
|
||||||
* @psalm-type ServicesConfig = array{
|
* @psalm-type ServicesConfig = array{
|
||||||
* _defaults?: DefaultsType,
|
* _defaults?: DefaultsType,
|
||||||
* _instanceof?: InstanceofType,
|
* _instanceof?: array<class-string, InstanceofType>,
|
||||||
* ...<string, DefinitionType|AliasType|PrototypeType|StackType|ArgumentsType|null>
|
* ...<string, DefinitionType|AliasType|PrototypeType|StackType|ArgumentsType|null>
|
||||||
* }
|
* }
|
||||||
* @psalm-type ExtensionType = array<string, mixed>
|
* @psalm-type ExtensionType = array<string, mixed>
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,28 @@ services:
|
||||||
alias: 'doctrine.migrations.dependency_factory'
|
alias: 'doctrine.migrations.dependency_factory'
|
||||||
|
|
||||||
|
|
||||||
|
####################################################################################################################
|
||||||
|
# AI provider HTTP clients (with configurable timeouts)
|
||||||
|
####################################################################################################################
|
||||||
|
|
||||||
|
app.http_client.ai_ollama:
|
||||||
|
class: Symfony\Contracts\HttpClient\HttpClientInterface
|
||||||
|
factory: ['@http_client', 'withOptions']
|
||||||
|
arguments:
|
||||||
|
- { timeout: '%env(int:settings:ai_ollama:timeout)%' }
|
||||||
|
|
||||||
|
app.http_client.ai_lmstudio:
|
||||||
|
class: Symfony\Contracts\HttpClient\HttpClientInterface
|
||||||
|
factory: ['@http_client', 'withOptions']
|
||||||
|
arguments:
|
||||||
|
- { timeout: '%env(int:settings:ai_lmstudio:timeout)%' }
|
||||||
|
|
||||||
|
app.http_client.ai_openrouter:
|
||||||
|
class: Symfony\Contracts\HttpClient\HttpClientInterface
|
||||||
|
factory: ['@http_client', 'withOptions']
|
||||||
|
arguments:
|
||||||
|
- { timeout: '%env(int:settings:ai_openrouter:timeout)%' }
|
||||||
|
|
||||||
####################################################################################################################
|
####################################################################################################################
|
||||||
# Email
|
# Email
|
||||||
####################################################################################################################
|
####################################################################################################################
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated on Mon Jun 15 07:28:00 UTC 2026
|
# Generated on Mon Jul 6 06:43:02 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
|
||||||
|
|
@ -8293,6 +8293,7 @@ Converter_DCDC:Converter_DCDC_Hamamatsu_C11204-1_THT
|
||||||
Converter_DCDC:Converter_DCDC_MeanWell_NID30_THT
|
Converter_DCDC:Converter_DCDC_MeanWell_NID30_THT
|
||||||
Converter_DCDC:Converter_DCDC_MeanWell_NID60_THT
|
Converter_DCDC:Converter_DCDC_MeanWell_NID60_THT
|
||||||
Converter_DCDC:Converter_DCDC_MeanWell_NSD10_THT
|
Converter_DCDC:Converter_DCDC_MeanWell_NSD10_THT
|
||||||
|
Converter_DCDC:Converter_DCDC_MeanWell_SMU02x-xxN_THT
|
||||||
Converter_DCDC:Converter_DCDC_Murata_CRE1xxxxxx3C_THT
|
Converter_DCDC:Converter_DCDC_Murata_CRE1xxxxxx3C_THT
|
||||||
Converter_DCDC:Converter_DCDC_Murata_CRE1xxxxxxDC_THT
|
Converter_DCDC:Converter_DCDC_Murata_CRE1xxxxxxDC_THT
|
||||||
Converter_DCDC:Converter_DCDC_Murata_CRE1xxxxxxSC_THT
|
Converter_DCDC:Converter_DCDC_Murata_CRE1xxxxxxSC_THT
|
||||||
|
|
@ -13030,8 +13031,6 @@ Package_SON:WSON-6-1EP_2x2mm_P0.65mm_EP1x1.6mm
|
||||||
Package_SON:WSON-6-1EP_2x2mm_P0.65mm_EP1x1.6mm_ThermalVias
|
Package_SON:WSON-6-1EP_2x2mm_P0.65mm_EP1x1.6mm_ThermalVias
|
||||||
Package_SON:WSON-6-1EP_3x3mm_P0.95mm
|
Package_SON:WSON-6-1EP_3x3mm_P0.95mm
|
||||||
Package_SON:WSON-6_1.5x1.5mm_P0.5mm
|
Package_SON:WSON-6_1.5x1.5mm_P0.5mm
|
||||||
Package_SON:WSON-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mm
|
|
||||||
Package_SON:WSON-8-1EP_2x2mm_P0.5mm_EP0.9x1.6mm_ThermalVias
|
|
||||||
Package_SON:WSON-8-1EP_3x2.5mm_P0.5mm_EP1.2x1.5mm_PullBack
|
Package_SON:WSON-8-1EP_3x2.5mm_P0.5mm_EP1.2x1.5mm_PullBack
|
||||||
Package_SON:WSON-8-1EP_3x2.5mm_P0.5mm_EP1.2x1.5mm_PullBack_ThermalVias
|
Package_SON:WSON-8-1EP_3x2.5mm_P0.5mm_EP1.2x1.5mm_PullBack_ThermalVias
|
||||||
Package_SON:WSON-8-1EP_3x3mm_P0.5mm_EP1.2x2mm
|
Package_SON:WSON-8-1EP_3x3mm_P0.5mm_EP1.2x2mm
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -27,6 +27,7 @@ use App\Doctrine\Functions\SiValueSort;
|
||||||
use App\Exceptions\InvalidRegexException;
|
use App\Exceptions\InvalidRegexException;
|
||||||
use Doctrine\DBAL\Driver\Connection;
|
use Doctrine\DBAL\Driver\Connection;
|
||||||
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;
|
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;
|
||||||
|
use Pdo\Sqlite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This middleware is used to add the regexp operator to the SQLite platform.
|
* This middleware is used to add the regexp operator to the SQLite platform.
|
||||||
|
|
@ -44,17 +45,30 @@ class SQLiteRegexExtensionMiddlewareDriver extends AbstractDriverMiddleware
|
||||||
if ($params['driver'] === 'pdo_sqlite') {
|
if ($params['driver'] === 'pdo_sqlite') {
|
||||||
$native_connection = $connection->getNativeConnection();
|
$native_connection = $connection->getNativeConnection();
|
||||||
|
|
||||||
//Ensure that the function really exists on the connection, as it is marked as experimental according to PHP documentation
|
|
||||||
if($native_connection instanceof \PDO) {
|
if($native_connection instanceof \PDO) {
|
||||||
$native_connection->sqliteCreateFunction('REGEXP', self::regexp(...), 2, \PDO::SQLITE_DETERMINISTIC);
|
|
||||||
$native_connection->sqliteCreateFunction('FIELD', self::field(...), -1, \PDO::SQLITE_DETERMINISTIC);
|
|
||||||
$native_connection->sqliteCreateFunction('FIELD2', self::field2(...), 2, \PDO::SQLITE_DETERMINISTIC);
|
|
||||||
|
|
||||||
//Create a new collation for natural sorting
|
//Use the new PDO::createFunction and PDO::createCollation methods if available (PHP 8.4+)
|
||||||
$native_connection->sqliteCreateCollation('NATURAL_CMP', strnatcmp(...));
|
if (is_a($native_connection, Sqlite::class)) { #TODO: Remove this check when PHP 8.4 is the minimum requirement
|
||||||
|
$native_connection->createFunction('REGEXP', self::regexp(...), 2, Sqlite::DETERMINISTIC);
|
||||||
|
$native_connection->createFunction('FIELD', self::field(...), -1, Sqlite::DETERMINISTIC);
|
||||||
|
$native_connection->createFunction('FIELD2', self::field2(...), 2, Sqlite::DETERMINISTIC);
|
||||||
|
|
||||||
//Create a function for SI prefix value sorting
|
//Create a new collation for natural sorting
|
||||||
$native_connection->sqliteCreateFunction('SI_VALUE', SiValueSort::sqliteSiValue(...), 1, \PDO::SQLITE_DETERMINISTIC);
|
$native_connection->createCollation('NATURAL_CMP', strnatcmp(...));
|
||||||
|
|
||||||
|
//Create a function for SI prefix value sorting
|
||||||
|
$native_connection->createFunction('SI_VALUE', SiValueSort::sqliteSiValue(...), 1, Sqlite::DETERMINISTIC);
|
||||||
|
} else {
|
||||||
|
$native_connection->sqliteCreateFunction('REGEXP', self::regexp(...), 2, \PDO::SQLITE_DETERMINISTIC);
|
||||||
|
$native_connection->sqliteCreateFunction('FIELD', self::field(...), -1, \PDO::SQLITE_DETERMINISTIC);
|
||||||
|
$native_connection->sqliteCreateFunction('FIELD2', self::field2(...), 2, \PDO::SQLITE_DETERMINISTIC);
|
||||||
|
|
||||||
|
//Create a new collation for natural sorting
|
||||||
|
$native_connection->sqliteCreateCollation('NATURAL_CMP', strnatcmp(...));
|
||||||
|
|
||||||
|
//Create a function for SI prefix value sorting
|
||||||
|
$native_connection->sqliteCreateFunction('SI_VALUE', SiValueSort::sqliteSiValue(...), 1, \PDO::SQLITE_DETERMINISTIC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,4 +132,4 @@ class SQLiteRegexExtensionMiddlewareDriver extends AbstractDriverMiddleware
|
||||||
|
|
||||||
return $index + 1;
|
return $index + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,21 +65,16 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/attachment_types/{id}/children.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: AttachmentType::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the children elements of an attachment type.'),
|
||||||
|
security: 'is_granted("@attachment_types.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['attachment_type:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['attachment_type:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['attachment_type:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['attachment_type:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/attachment_types/{id}/children.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(openapi: new Operation(summary: 'Retrieves the children elements of an attachment type.'),
|
|
||||||
security: 'is_granted("@attachment_types.read")')
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'children', fromClass: AttachmentType::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['attachment_type:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
||||||
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
||||||
|
|
|
||||||
|
|
@ -68,23 +68,16 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/categories/{id}/children.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: Category::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the children elements of a category.'),
|
||||||
|
security: 'is_granted("@categories.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['category:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['category:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['category:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['category:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/categories/{id}/children.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the children elements of a category.'),
|
|
||||||
security: 'is_granted("@categories.read")'
|
|
||||||
)
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'children', fromClass: Category::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['category:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
||||||
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
||||||
|
|
|
||||||
|
|
@ -67,23 +67,16 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/footprints/{id}/children.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: Footprint::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the children elements of a footprint.'),
|
||||||
|
security: 'is_granted("@footprints.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['footprint:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['footprint:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['footprint:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['footprint:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/footprints/{id}/children.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the children elements of a footprint.'),
|
|
||||||
security: 'is_granted("@footprints.read")'
|
|
||||||
)
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'children', fromClass: Footprint::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['footprint:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
||||||
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,11 @@ use Doctrine\DBAL\Types\Types;
|
||||||
use Doctrine\ORM\Mapping\Column;
|
use Doctrine\ORM\Mapping\Column;
|
||||||
use Doctrine\ORM\Mapping\Embeddable;
|
use Doctrine\ORM\Mapping\Embeddable;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a reference to a info provider inside a part.
|
* This class represents a reference to an info provider inside a part.
|
||||||
* @see \App\Tests\Entity\Parts\InfoProviderReferenceTest
|
* @see \App\Tests\Entity\Parts\InfoProviderReferenceTest
|
||||||
*/
|
*/
|
||||||
#[Embeddable]
|
#[Embeddable]
|
||||||
|
|
@ -157,4 +159,44 @@ class InfoProviderReference
|
||||||
$ref->last_updated = new \DateTimeImmutable();
|
$ref->last_updated = new \DateTimeImmutable();
|
||||||
return $ref;
|
return $ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a reference to an info provider based on the given parameters.
|
||||||
|
* @param string|null $provider_key
|
||||||
|
* @param string|null $provider_id
|
||||||
|
* @param string|null $provider_url
|
||||||
|
* @param \DateTimeImmutable|null $last_updated
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function create(?string $provider_key, ?string $provider_id, ?string $provider_url, ?\DateTimeImmutable $last_updated): self
|
||||||
|
{
|
||||||
|
$ref = new InfoProviderReference();
|
||||||
|
$ref->provider_key = $provider_key;
|
||||||
|
$ref->provider_id = $provider_id;
|
||||||
|
$ref->provider_url = $provider_url;
|
||||||
|
$ref->last_updated = $last_updated;
|
||||||
|
return $ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Assert\Callback()]
|
||||||
|
public function validate(ExecutionContextInterface $context, mixed $payload): void
|
||||||
|
{
|
||||||
|
if ($this->provider_key === null && $this->provider_id !== null) {
|
||||||
|
$context->buildViolation('info_providers.validation.provider_id_without_key')
|
||||||
|
->atPath('provider_key')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->provider_key === null && $this->provider_url !== null) {
|
||||||
|
$context->buildViolation('info_providers.validation.provider_url_without_key')
|
||||||
|
->atPath('provider_url')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->provider_key !== null && $this->provider_id === null) {
|
||||||
|
$context->buildViolation('info_providers.validation.provider_key_without_id')
|
||||||
|
->atPath('provider_id')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,23 +66,16 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/manufacturers/{id}/children.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: Manufacturer::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the children elements of a manufacturer.'),
|
||||||
|
security: 'is_granted("@manufacturers.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['manufacturer:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['manufacturer:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['manufacturer:write', 'company:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['manufacturer:write', 'company:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/manufacturers/{id}/children.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the children elements of a manufacturer.'),
|
|
||||||
security: 'is_granted("@manufacturers.read")'
|
|
||||||
)
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'children', fromClass: Manufacturer::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['manufacturer:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
||||||
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
||||||
|
|
|
||||||
|
|
@ -71,23 +71,16 @@ use Symfony\Component\Validator\Constraints\Length;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/measurement_units/{id}/children.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: MeasurementUnit::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the children elements of a MeasurementUnit.'),
|
||||||
|
security: 'is_granted("@measurement_units.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['measurement_unit:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['measurement_unit:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['measurement_unit:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['measurement_unit:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/measurement_units/{id}/children.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the children elements of a MeasurementUnit.'),
|
|
||||||
security: 'is_granted("@measurement_units.read")'
|
|
||||||
)
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'children', fromClass: MeasurementUnit::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['measurement_unit:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "unit"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "unit"])]
|
||||||
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ trait AdvancedPropertyTrait
|
||||||
*/
|
*/
|
||||||
#[ORM\Embedded(class: InfoProviderReference::class, columnPrefix: 'provider_reference_')]
|
#[ORM\Embedded(class: InfoProviderReference::class, columnPrefix: 'provider_reference_')]
|
||||||
#[Groups(['full', 'part:read'])]
|
#[Groups(['full', 'part:read'])]
|
||||||
|
#[Assert\Valid()]
|
||||||
protected InfoProviderReference $providerReference;
|
protected InfoProviderReference $providerReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -67,23 +67,16 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/storage_locations/{id}/children.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: StorageLocation::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the children elements of a storage location.'),
|
||||||
|
security: 'is_granted("@storelocations.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['location:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['location:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['location:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['location:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/storage_locations/{id}/children.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the children elements of a storage location.'),
|
|
||||||
security: 'is_granted("@storelocations.read")'
|
|
||||||
)
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'children', fromClass: StorageLocation::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['location:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
||||||
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
||||||
|
|
|
||||||
|
|
@ -71,21 +71,16 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/suppliers/{id}/children.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: Supplier::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the children elements of a supplier.'),
|
||||||
|
security: 'is_granted("@manufacturers.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['supplier:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['supplier:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['supplier:write', 'company:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['supplier:write', 'company:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/suppliers/{id}/children.{_format}',
|
|
||||||
operations: [new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the children elements of a supplier.'),
|
|
||||||
security: 'is_granted("@manufacturers.read")'
|
|
||||||
)],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'children', fromClass: Supplier::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['supplier:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
||||||
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
||||||
|
|
|
||||||
|
|
@ -71,23 +71,16 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/currencies/{id}/children.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: Currency::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the children elements of a currency.'),
|
||||||
|
security: 'is_granted("@currencies.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['currency:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['currency:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['currency:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['currency:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/currencies/{id}/children.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the children elements of a currency.'),
|
|
||||||
security: 'is_granted("@currencies.read")'
|
|
||||||
)
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'children', fromClass: Currency::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['currency:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "iso_code"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "iso_code"])]
|
||||||
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
||||||
|
|
|
||||||
|
|
@ -71,23 +71,17 @@ use Symfony\Component\Validator\Constraints\Length;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/parts/{id}/orderdetails.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(toProperty: 'part', fromClass: Part::class)],
|
||||||
|
normalizationContext: ['groups' => ['orderdetail:read', 'pricedetail:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the orderdetails of a part.'),
|
||||||
|
security: 'is_granted("@parts.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['orderdetail:read', 'orderdetail:read:standalone', 'api:basic:read', 'pricedetail:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['orderdetail:read', 'orderdetail:read:standalone', 'api:basic:read', 'pricedetail:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['orderdetail:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['orderdetail:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/parts/{id}/orderdetails.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the orderdetails of a part.'),
|
|
||||||
security: 'is_granted("@parts.read")'
|
|
||||||
)
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(toProperty: 'part', fromClass: Part::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['orderdetail:read', 'pricedetail:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["supplierpartnr", "supplier_product_url"])]
|
#[ApiFilter(LikeFilter::class, properties: ["supplierpartnr", "supplier_product_url"])]
|
||||||
|
|
|
||||||
|
|
@ -66,23 +66,16 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
new Post(securityPostDenormalize: 'is_granted("create", object)'),
|
||||||
new Patch(security: 'is_granted("edit", object)'),
|
new Patch(security: 'is_granted("edit", object)'),
|
||||||
new Delete(security: 'is_granted("delete", object)'),
|
new Delete(security: 'is_granted("delete", object)'),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/projects/{id}/children.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: Project::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the children elements of a project.'),
|
||||||
|
security: 'is_granted("@projects.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['project:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['project:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['project:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['project:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/projects/{id}/children.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the children elements of a project.'),
|
|
||||||
security: 'is_granted("@projects.read")'
|
|
||||||
)
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'children', fromClass: Project::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['project:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
|
||||||
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
|
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
|
||||||
|
|
@ -117,7 +110,7 @@ class Project extends AbstractStructuralDBElement
|
||||||
/**
|
/**
|
||||||
* @var string|null The current status of the project
|
* @var string|null The current status of the project
|
||||||
*/
|
*/
|
||||||
#[Assert\Choice(['draft', 'planning', 'in_production', 'finished', 'archived'])]
|
#[Assert\Choice(choices: ['draft', 'planning', 'in_production', 'finished', 'archived'])]
|
||||||
#[Groups(['extended', 'full', 'project:read', 'project:write', 'import'])]
|
#[Groups(['extended', 'full', 'project:read', 'project:write', 'import'])]
|
||||||
#[ORM\Column(type: Types::STRING, length: 64, nullable: true)]
|
#[ORM\Column(type: Types::STRING, length: 64, nullable: true)]
|
||||||
protected ?string $status = null;
|
protected ?string $status = null;
|
||||||
|
|
|
||||||
|
|
@ -63,23 +63,16 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
new Post(uriTemplate: '/project_bom_entries.{_format}', securityPostDenormalize: 'is_granted("create", object)',),
|
new Post(uriTemplate: '/project_bom_entries.{_format}', securityPostDenormalize: 'is_granted("create", object)',),
|
||||||
new Patch(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("edit", object)',),
|
new Patch(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("edit", object)',),
|
||||||
new Delete(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("delete", object)',),
|
new Delete(uriTemplate: '/project_bom_entries/{id}.{_format}', security: 'is_granted("delete", object)',),
|
||||||
|
new GetCollection(
|
||||||
|
uriTemplate: '/projects/{id}/bom.{_format}',
|
||||||
|
uriVariables: ['id' => new Link(fromProperty: 'bom_entries', fromClass: Project::class)],
|
||||||
|
openapi: new Operation(summary: 'Retrieves the BOM entries of the given project.'),
|
||||||
|
security: 'is_granted("@projects.read")'
|
||||||
|
),
|
||||||
],
|
],
|
||||||
normalizationContext: ['groups' => ['bom_entry:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
normalizationContext: ['groups' => ['bom_entry:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
|
||||||
denormalizationContext: ['groups' => ['bom_entry:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'],
|
denormalizationContext: ['groups' => ['bom_entry:write', 'api:basic:write'], 'openapi_definition_name' => 'Write'],
|
||||||
)]
|
)]
|
||||||
#[ApiResource(
|
|
||||||
uriTemplate: '/projects/{id}/bom.{_format}',
|
|
||||||
operations: [
|
|
||||||
new GetCollection(
|
|
||||||
openapi: new Operation(summary: 'Retrieves the BOM entries of the given project.'),
|
|
||||||
security: 'is_granted("@projects.read")'
|
|
||||||
)
|
|
||||||
],
|
|
||||||
uriVariables: [
|
|
||||||
'id' => new Link(fromProperty: 'bom_entries', fromClass: Project::class)
|
|
||||||
],
|
|
||||||
normalizationContext: ['groups' => ['bom_entry:read', 'api:basic:read'], 'openapi_definition_name' => 'Read']
|
|
||||||
)]
|
|
||||||
#[ApiFilter(PropertyFilter::class)]
|
#[ApiFilter(PropertyFilter::class)]
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", 'mountnames'])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", 'mountnames'])]
|
||||||
#[ApiFilter(RangeFilter::class, properties: ['quantity'])]
|
#[ApiFilter(RangeFilter::class, properties: ['quantity'])]
|
||||||
|
|
|
||||||
79
src/Form/Extension/DateTimeModelTimezoneExtension.php
Normal file
79
src/Form/Extension/DateTimeModelTimezoneExtension.php
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?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\Form\Extension;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractTypeExtension;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Catches timezone mismatches between a DateTimeInterface model value and the effective
|
||||||
|
* model_timezone configured on the field.
|
||||||
|
*
|
||||||
|
* Doctrine's UTCDateTimeImmutableType always returns UTC DateTimeImmutable objects, so any
|
||||||
|
* date/datetime field that omits `model_timezone: 'UTC'` will silently corrupt stored values
|
||||||
|
* (the transformer treats the UTC instant as if it were in the user's local timezone).
|
||||||
|
* This extension throws a \LogicException early so the mistake is caught at development time.
|
||||||
|
*/
|
||||||
|
class DateTimeModelTimezoneExtension extends AbstractTypeExtension
|
||||||
|
{
|
||||||
|
public static function getExtendedTypes(): iterable
|
||||||
|
{
|
||||||
|
return [DateTimeType::class, DateType::class];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder->addEventListener(FormEvents::POST_SET_DATA, static function (FormEvent $event) use ($options): void {
|
||||||
|
$data = $event->getData();
|
||||||
|
|
||||||
|
if (!$data instanceof \DateTimeInterface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the effective model timezone: explicit option or the PHP default set at build time.
|
||||||
|
// This mirrors what BaseDateTimeTransformer does in its constructor.
|
||||||
|
$modelTimezone = $options['model_timezone'] ?? date_default_timezone_get();
|
||||||
|
|
||||||
|
$dataOffset = $data->getTimezone()->getOffset($data);
|
||||||
|
$modelOffset = (new \DateTimeZone($modelTimezone))->getOffset($data);
|
||||||
|
|
||||||
|
if ($dataOffset !== $modelOffset) {
|
||||||
|
throw new \LogicException(sprintf(
|
||||||
|
'Form field "%s" received a %s with timezone "%s" (UTC offset %+d s), '
|
||||||
|
. 'but the effective model_timezone is "%s" (UTC offset %+d s). '
|
||||||
|
. 'Set the "model_timezone" option to match the timezone of your data source.',
|
||||||
|
$event->getForm()->getName(),
|
||||||
|
get_debug_type($data),
|
||||||
|
$data->getTimezone()->getName(),
|
||||||
|
$dataOffset,
|
||||||
|
$modelTimezone,
|
||||||
|
$modelOffset
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
113
src/Form/InfoProviderSystem/InfoProviderReferenceType.php
Normal file
113
src/Form/InfoProviderSystem/InfoProviderReferenceType.php
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
|
||||||
|
namespace App\Form\InfoProviderSystem;
|
||||||
|
|
||||||
|
use App\Entity\Parts\InfoProviderReference;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\DataMapperInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\UrlType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class InfoProviderReferenceType extends AbstractType implements DataMapperInterface
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->setDataMapper($this)
|
||||||
|
->add('provider_key', ProviderSelectType::class, [
|
||||||
|
'label' => 'info_providers.provider_key',
|
||||||
|
'input' => 'string',
|
||||||
|
'multiple' => false,
|
||||||
|
'required' => false,
|
||||||
|
'only_active' => false,
|
||||||
|
])
|
||||||
|
->add('provider_id', TextType::class, [
|
||||||
|
'label' => 'info_providers.provider_id',
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
|
->add('provider_url', UrlType::class, [
|
||||||
|
'label' => 'info_providers.provider_url',
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => InfoProviderReference::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function mapDataToForms(mixed $viewData, \Traversable $forms): void
|
||||||
|
{
|
||||||
|
if ($viewData === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$viewData instanceof InfoProviderReference) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var FormInterface[] $forms */
|
||||||
|
$forms = iterator_to_array($forms);
|
||||||
|
|
||||||
|
$forms['provider_key']->setData($viewData->getProviderKey());
|
||||||
|
$forms['provider_id']->setData($viewData->getProviderId());
|
||||||
|
$forms['provider_url']->setData($viewData->getProviderUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mapFormsToData(\Traversable $forms, mixed &$viewData): void
|
||||||
|
{
|
||||||
|
/** @var FormInterface[] $forms */
|
||||||
|
$forms = iterator_to_array($forms);
|
||||||
|
|
||||||
|
$providerKey = $forms['provider_key']->getData();
|
||||||
|
$providerId = $forms['provider_id']->getData();
|
||||||
|
$providerUrl = $forms['provider_url']->getData();
|
||||||
|
|
||||||
|
if ($viewData === null) {
|
||||||
|
$viewData = InfoProviderReference::noProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$viewData instanceof InfoProviderReference) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$oldDate = $viewData->getLastUpdated();
|
||||||
|
|
||||||
|
//If all fields are empty, we set the view data to a new instance without provider information
|
||||||
|
if ($providerKey === null && $providerId === null && $providerUrl === null) {
|
||||||
|
$viewData = InfoProviderReference::noProvider();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewData = InfoProviderReference::create($providerKey, $providerId, $providerUrl, $oldDate);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -31,12 +31,12 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\OptionsResolver\Options;
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use Symfony\Component\Translation\StaticMessage;
|
use Symfony\Component\Translation\StaticMessage;
|
||||||
|
use Symfony\Component\Translation\TranslatableMessage;
|
||||||
|
|
||||||
class ProviderSelectType extends AbstractType
|
class ProviderSelectType extends AbstractType
|
||||||
{
|
{
|
||||||
public function __construct(private readonly ProviderRegistry $providerRegistry)
|
public function __construct(private readonly ProviderRegistry $providerRegistry)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getParent(): string
|
public function getParent(): string
|
||||||
|
|
@ -46,17 +46,22 @@ class ProviderSelectType extends AbstractType
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
{
|
{
|
||||||
$providers = $this->providerRegistry->getActiveProviders();
|
|
||||||
|
|
||||||
$resolver->setDefault('input', 'object');
|
$resolver->setDefault('input', 'object');
|
||||||
$resolver->setAllowedTypes('input', 'string');
|
$resolver->setAllowedTypes('input', 'string');
|
||||||
//Either the form returns the provider objects or their keys
|
//Either the form returns the provider objects or their keys
|
||||||
$resolver->setAllowedValues('input', ['object', 'string']);
|
$resolver->setAllowedValues('input', ['object', 'string']);
|
||||||
$resolver->setDefault('multiple', true);
|
$resolver->setDefault('multiple', true);
|
||||||
|
|
||||||
$resolver->setDefault('choices', function (Options $options) use ($providers) {
|
//Only show active providers in the list, or also inactive ones
|
||||||
|
$resolver->setDefault('only_active', true);
|
||||||
|
$resolver->setAllowedTypes('only_active', 'bool');
|
||||||
|
|
||||||
|
|
||||||
|
$resolver->setDefault('choices', function (Options $options) {
|
||||||
|
$providers = $options['only_active'] ? $this->providerRegistry->getActiveProviders() : $this->providerRegistry->getProviders();
|
||||||
|
|
||||||
if ('object' === $options['input']) {
|
if ('object' === $options['input']) {
|
||||||
return $this->providerRegistry->getActiveProviders();
|
return $providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmp = [];
|
$tmp = [];
|
||||||
|
|
@ -69,20 +74,35 @@ class ProviderSelectType extends AbstractType
|
||||||
});
|
});
|
||||||
|
|
||||||
//The choice_label and choice_value only needs to be set if we want the objects
|
//The choice_label and choice_value only needs to be set if we want the objects
|
||||||
$resolver->setDefault('choice_label', function (Options $options){
|
$resolver->setDefault('choice_label', function (Options $options) {
|
||||||
if ('object' === $options['input']) {
|
if ('object' === $options['input']) {
|
||||||
return ChoiceList::label($this, static fn (?InfoProviderInterface $choice) => new StaticMessage($choice?->getProviderInfo()['name']));
|
return ChoiceList::label($this, static fn(?InfoProviderInterface $choice
|
||||||
|
) => new StaticMessage($choice?->getProviderInfo()['name']));
|
||||||
}
|
}
|
||||||
|
|
||||||
return static fn ($choice, $key, $value) => new StaticMessage($key);
|
return static fn($choice, $key, $value) => new StaticMessage($key);
|
||||||
});
|
});
|
||||||
$resolver->setDefault('choice_value', function (Options $options) {
|
$resolver->setDefault('choice_value', function (Options $options) {
|
||||||
if ('object' === $options['input']) {
|
if ('object' === $options['input']) {
|
||||||
return ChoiceList::value($this, static fn(?InfoProviderInterface $choice) => $choice?->getProviderKey());
|
return ChoiceList::value($this,
|
||||||
|
static fn(?InfoProviderInterface $choice) => $choice?->getProviderKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
$resolver->setDefault('group_by', function (Options $options) {
|
||||||
|
//Do not show groups when only active providers are shown, because then all providers are active and the group would be useless
|
||||||
|
if ($options['only_active']) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function ($choice, $key, string $value) {
|
||||||
|
if ($this->providerRegistry->getProviderByKey($value)->isActive()) {
|
||||||
|
return new TranslatableMessage('info_providers.providers_list.active');
|
||||||
|
}
|
||||||
|
return new TranslatableMessage('info_providers.providers_list.disabled');
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ use App\Entity\Parts\Part;
|
||||||
use App\Entity\Parts\PartCustomState;
|
use App\Entity\Parts\PartCustomState;
|
||||||
use App\Entity\PriceInformations\Orderdetail;
|
use App\Entity\PriceInformations\Orderdetail;
|
||||||
use App\Form\AttachmentFormType;
|
use App\Form\AttachmentFormType;
|
||||||
|
use App\Form\InfoProviderSystem\InfoProviderReferenceType;
|
||||||
use App\Form\ParameterType;
|
use App\Form\ParameterType;
|
||||||
use App\Form\Part\EDA\EDAPartInfoType;
|
use App\Form\Part\EDA\EDAPartInfoType;
|
||||||
use App\Form\Type\MasterPictureAttachmentType;
|
use App\Form\Type\MasterPictureAttachmentType;
|
||||||
|
|
@ -225,6 +226,10 @@ class PartBaseType extends AbstractType
|
||||||
'empty_data' => null,
|
'empty_data' => null,
|
||||||
'label' => 'part.gtin',
|
'label' => 'part.gtin',
|
||||||
])
|
])
|
||||||
|
->add('providerReference', InfoProviderReferenceType::class, [
|
||||||
|
'label' => false,
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
;
|
;
|
||||||
|
|
||||||
//Comment section
|
//Comment section
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,10 @@ class PartLotType extends AbstractType
|
||||||
$builder->add('last_stocktake_at', DateTimeType::class, [
|
$builder->add('last_stocktake_at', DateTimeType::class, [
|
||||||
'label' => 'part_lot.edit.last_stocktake_at',
|
'label' => 'part_lot.edit.last_stocktake_at',
|
||||||
'widget' => 'single_text',
|
'widget' => 'single_text',
|
||||||
|
'model_timezone' => 'UTC', // The database stores the datetime in UTC, so we need to set the model timezone to UTC
|
||||||
'disabled' => !$this->security->isGranted('@parts_stock.stocktake'),
|
'disabled' => !$this->security->isGranted('@parts_stock.stocktake'),
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
'with_seconds' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class AttachmentTypeType extends AbstractType
|
||||||
return StructuralEntityType::class;
|
return StructuralEntityType::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
{
|
{
|
||||||
$resolver->define('attachment_filter_class')->allowedTypes('null', 'string')->default(null);
|
$resolver->define('attachment_filter_class')->allowedTypes('null', 'string')->default(null);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,10 @@ final class ProjectBuildRequest
|
||||||
$remaining_amount = $this->getNeededAmountForBOMEntry($bom_entry);
|
$remaining_amount = $this->getNeededAmountForBOMEntry($bom_entry);
|
||||||
foreach($this->getPartLotsForBOMEntry($bom_entry) as $lot) {
|
foreach($this->getPartLotsForBOMEntry($bom_entry) as $lot) {
|
||||||
//If the lot has instock use it for the build
|
//If the lot has instock use it for the build
|
||||||
$this->withdraw_amounts[$lot->getID()] = min($remaining_amount, $lot->getAmount());
|
$id = $lot->getID() ?? throw new \RuntimeException("Part lot needs to have an ID!");
|
||||||
$remaining_amount -= max(0, $this->withdraw_amounts[$lot->getID()]);
|
|
||||||
|
$this->withdraw_amounts[$id] = min($remaining_amount, $lot->getAmount());
|
||||||
|
$remaining_amount -= max(0, $this->withdraw_amounts[$id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -176,6 +178,10 @@ final class ProjectBuildRequest
|
||||||
{
|
{
|
||||||
$lot_id = $lot instanceof PartLot ? $lot->getID() : $lot;
|
$lot_id = $lot instanceof PartLot ? $lot->getID() : $lot;
|
||||||
|
|
||||||
|
if ($lot_id === null) {
|
||||||
|
throw new \InvalidArgumentException('The given lot must have an ID!');
|
||||||
|
}
|
||||||
|
|
||||||
if (! array_key_exists($lot_id, $this->withdraw_amounts)) {
|
if (! array_key_exists($lot_id, $this->withdraw_amounts)) {
|
||||||
throw new \InvalidArgumentException('The given lot is not in the withdraw amounts array!');
|
throw new \InvalidArgumentException('The given lot is not in the withdraw amounts array!');
|
||||||
}
|
}
|
||||||
|
|
@ -192,10 +198,12 @@ final class ProjectBuildRequest
|
||||||
{
|
{
|
||||||
if ($lot instanceof PartLot) {
|
if ($lot instanceof PartLot) {
|
||||||
$lot_id = $lot->getID();
|
$lot_id = $lot->getID();
|
||||||
} elseif (is_int($lot)) {
|
|
||||||
$lot_id = $lot;
|
|
||||||
} else {
|
} else {
|
||||||
throw new \InvalidArgumentException('The given lot must be an instance of PartLot or an ID of a PartLot!');
|
$lot_id = $lot;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($lot_id === null) {
|
||||||
|
throw new \InvalidArgumentException('The given lot must have an ID!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->withdraw_amounts[$lot_id] = $amount;
|
$this->withdraw_amounts[$lot_id] = $amount;
|
||||||
|
|
@ -296,7 +304,7 @@ final class ProjectBuildRequest
|
||||||
* @param bool $dont_check_quantity
|
* @param bool $dont_check_quantity
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDontCheckQuantity(bool $dont_check_quantity): ProjectBuildRequest
|
public function setDontCheckQuantity(bool $dont_check_quantity): self
|
||||||
{
|
{
|
||||||
$this->dont_check_quantity = $dont_check_quantity;
|
$this->dont_check_quantity = $dont_check_quantity;
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,6 @@ class DBElementRepository extends EntityRepository
|
||||||
{
|
{
|
||||||
$reflection = new ReflectionClass($element::class);
|
$reflection = new ReflectionClass($element::class);
|
||||||
$property = $reflection->getProperty($field);
|
$property = $reflection->getProperty($field);
|
||||||
$property->setAccessible(true);
|
|
||||||
$property->setValue($element, $new_value);
|
$property->setValue($element, $new_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,6 @@ trait PKImportHelperTrait
|
||||||
|
|
||||||
$reflectionClass = new \ReflectionClass($entity);
|
$reflectionClass = new \ReflectionClass($entity);
|
||||||
$property = $reflectionClass->getProperty('addedDate');
|
$property = $reflectionClass->getProperty('addedDate');
|
||||||
$property->setAccessible(true);
|
|
||||||
$property->setValue($entity, $date);
|
$property->setValue($entity, $date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ final class DTOJsonSchemaConverter
|
||||||
public function getJSONSchema(): array
|
public function getJSONSchema(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => 'clock',
|
'name' => 'part_detail',
|
||||||
'strict' => true,
|
'strict' => true,
|
||||||
'schema' => [
|
'schema' => [
|
||||||
'type' => 'object',
|
'type' => 'object',
|
||||||
|
|
|
||||||
|
|
@ -282,6 +282,10 @@ final class AIWebProvider implements InfoProviderInterface
|
||||||
try {
|
try {
|
||||||
$aiPlatform = $this->AIPlatformRegistry->getPlatform($this->settings->platform ?? throw new \RuntimeException('No AI platform selected') );
|
$aiPlatform = $this->AIPlatformRegistry->getPlatform($this->settings->platform ?? throw new \RuntimeException('No AI platform selected') );
|
||||||
|
|
||||||
|
// AI inference can take much longer than PHP's default max_execution_time (typically 30s).
|
||||||
|
// The HTTP client timeout already enforces the configured limit; disable PHP's constraint here.
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
//'openai/gpt-5-mini'
|
//'openai/gpt-5-mini'
|
||||||
$result = $aiPlatform->invoke($this->settings->model ?? throw new \RuntimeException('No model selected'), $input, [
|
$result = $aiPlatform->invoke($this->settings->model ?? throw new \RuntimeException('No model selected'), $input, [
|
||||||
'response_format' => [
|
'response_format' => [
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ class AISettings
|
||||||
{
|
{
|
||||||
use SettingsTrait;
|
use SettingsTrait;
|
||||||
|
|
||||||
|
public const TIMEOUT_LIMIT = 600;
|
||||||
|
|
||||||
#[EmbeddedSettings]
|
#[EmbeddedSettings]
|
||||||
public ?OpenRouterSettings $openRouter = null;
|
public ?OpenRouterSettings $openRouter = null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,17 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Settings\AISettings;
|
namespace App\Settings\AISettings;
|
||||||
|
|
||||||
use App\Form\Type\APIKeyType;
|
|
||||||
use App\Services\AI\AIPlatformSettingsInterface;
|
use App\Services\AI\AIPlatformSettingsInterface;
|
||||||
use App\Settings\SettingsIcon;
|
use App\Settings\SettingsIcon;
|
||||||
use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
|
use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
|
||||||
use Jbtronics\SettingsBundle\Settings\Settings;
|
use Jbtronics\SettingsBundle\Settings\Settings;
|
||||||
use Jbtronics\SettingsBundle\Settings\SettingsParameter;
|
use Jbtronics\SettingsBundle\Settings\SettingsParameter;
|
||||||
use Jbtronics\SettingsBundle\Settings\SettingsTrait;
|
use Jbtronics\SettingsBundle\Settings\SettingsTrait;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\UrlType;
|
use Symfony\Component\Form\Extension\Core\Type\UrlType;
|
||||||
use Symfony\Component\Translation\StaticMessage;
|
use Symfony\Component\Translation\StaticMessage;
|
||||||
use Symfony\Component\Translation\TranslatableMessage as TM;
|
use Symfony\Component\Translation\TranslatableMessage as TM;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
#[Settings(name: 'ai_lmstudio', label: new TM("settings.ai.lmstudio"))]
|
#[Settings(name: 'ai_lmstudio', label: new TM("settings.ai.lmstudio"))]
|
||||||
#[SettingsIcon("fa-robot")]
|
#[SettingsIcon("fa-robot")]
|
||||||
|
|
@ -46,6 +47,14 @@ class LMStudioSettings implements AIPlatformSettingsInterface
|
||||||
envVar: "AI_LMSTUDIO_HOSTURL", envVarMode: EnvVarMode::OVERWRITE)]
|
envVar: "AI_LMSTUDIO_HOSTURL", envVarMode: EnvVarMode::OVERWRITE)]
|
||||||
public ?string $hostURL = null;
|
public ?string $hostURL = null;
|
||||||
|
|
||||||
|
#[SettingsParameter(label: new TM("settings.ai.timeout"),
|
||||||
|
description: new TM("settings.ai.timeout.help"),
|
||||||
|
formType: NumberType::class,
|
||||||
|
formOptions: ["scale" => 0, "attr" => ["min" => 1]],
|
||||||
|
)]
|
||||||
|
#[Assert\Range(min: 1, max: AISettings::TIMEOUT_LIMIT)]
|
||||||
|
public int $timeout = 180;
|
||||||
|
|
||||||
public function isAIPlatformEnabled(): bool
|
public function isAIPlatformEnabled(): bool
|
||||||
{
|
{
|
||||||
return $this->hostURL !== null && $this->hostURL !== "";
|
return $this->hostURL !== null && $this->hostURL !== "";
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,11 @@ use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
|
||||||
use Jbtronics\SettingsBundle\Settings\Settings;
|
use Jbtronics\SettingsBundle\Settings\Settings;
|
||||||
use Jbtronics\SettingsBundle\Settings\SettingsParameter;
|
use Jbtronics\SettingsBundle\Settings\SettingsParameter;
|
||||||
use Jbtronics\SettingsBundle\Settings\SettingsTrait;
|
use Jbtronics\SettingsBundle\Settings\SettingsTrait;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\UrlType;
|
use Symfony\Component\Form\Extension\Core\Type\UrlType;
|
||||||
use Symfony\Component\Translation\StaticMessage;
|
use Symfony\Component\Translation\StaticMessage;
|
||||||
use Symfony\Component\Translation\TranslatableMessage as TM;
|
use Symfony\Component\Translation\TranslatableMessage as TM;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
#[Settings(name: 'ai_ollama', label: new TM("settings.ai.ollama"))]
|
#[Settings(name: 'ai_ollama', label: new TM("settings.ai.ollama"))]
|
||||||
#[SettingsIcon("fa-robot")]
|
#[SettingsIcon("fa-robot")]
|
||||||
|
|
@ -51,6 +53,14 @@ class OllamaSettings implements AIPlatformSettingsInterface
|
||||||
envVar: "AI_OLLAMA_API_KEY", envVarMode: EnvVarMode::OVERWRITE)]
|
envVar: "AI_OLLAMA_API_KEY", envVarMode: EnvVarMode::OVERWRITE)]
|
||||||
public ?string $apiKey = null;
|
public ?string $apiKey = null;
|
||||||
|
|
||||||
|
#[SettingsParameter(label: new TM("settings.ai.timeout"),
|
||||||
|
description: new TM("settings.ai.timeout.help"),
|
||||||
|
formType: NumberType::class,
|
||||||
|
formOptions: ["scale" => 0, "attr" => ["min" => 1]]
|
||||||
|
)]
|
||||||
|
#[Assert\Range(min: 1, max: AISettings::TIMEOUT_LIMIT)]
|
||||||
|
public int $timeout = 180;
|
||||||
|
|
||||||
public function isAIPlatformEnabled(): bool
|
public function isAIPlatformEnabled(): bool
|
||||||
{
|
{
|
||||||
return $this->endpoint !== null && $this->endpoint !== "";
|
return $this->endpoint !== null && $this->endpoint !== "";
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,9 @@ use Jbtronics\SettingsBundle\Metadata\EnvVarMode;
|
||||||
use Jbtronics\SettingsBundle\Settings\Settings;
|
use Jbtronics\SettingsBundle\Settings\Settings;
|
||||||
use Jbtronics\SettingsBundle\Settings\SettingsParameter;
|
use Jbtronics\SettingsBundle\Settings\SettingsParameter;
|
||||||
use Jbtronics\SettingsBundle\Settings\SettingsTrait;
|
use Jbtronics\SettingsBundle\Settings\SettingsTrait;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||||
use Symfony\Component\Translation\TranslatableMessage as TM;
|
use Symfony\Component\Translation\TranslatableMessage as TM;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
#[Settings(name: 'ai_openrouter', label: new TM("settings.ai.openrouter"), description: "settings.ai.openrouter.help")]
|
#[Settings(name: 'ai_openrouter', label: new TM("settings.ai.openrouter"), description: "settings.ai.openrouter.help")]
|
||||||
#[SettingsIcon("fa-robot")]
|
#[SettingsIcon("fa-robot")]
|
||||||
|
|
@ -43,6 +45,14 @@ class OpenRouterSettings implements AIPlatformSettingsInterface
|
||||||
formOptions: ["help_html" => true], envVar: "AI_OPENROUTER_KEY", envVarMode: EnvVarMode::OVERWRITE)]
|
formOptions: ["help_html" => true], envVar: "AI_OPENROUTER_KEY", envVarMode: EnvVarMode::OVERWRITE)]
|
||||||
public ?string $apiKey = null;
|
public ?string $apiKey = null;
|
||||||
|
|
||||||
|
#[SettingsParameter(label: new TM("settings.ai.timeout"),
|
||||||
|
description: new TM("settings.ai.timeout.help"),
|
||||||
|
formType: NumberType::class,
|
||||||
|
formOptions: ["scale" => 0, "attr" => ["min" => 1]],
|
||||||
|
envVar: "int:AI_OPENROUTER_TIMEOUT", envVarMode: EnvVarMode::OVERWRITE)]
|
||||||
|
#[Assert\Range(min: 1, max: AISettings::TIMEOUT_LIMIT)]
|
||||||
|
public int $timeout = 90;
|
||||||
|
|
||||||
public function isAIPlatformEnabled(): bool
|
public function isAIPlatformEnabled(): bool
|
||||||
{
|
{
|
||||||
return $this->apiKey !== null && $this->apiKey !== "";
|
return $this->apiKey !== null && $this->apiKey !== "";
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<p class="m-0">
|
<p class="m-0">
|
||||||
<b>{% trans %}log.collection_deleted.deleted{% endtrans %}</b>:
|
<b>{% trans %}log.collection_deleted.deleted{% endtrans %}</b>:
|
||||||
{{ entity_type_label(entry.deletedElementClass) }} #{{ entry.deletedElementID }}
|
{{ type_label(entry.deletedElementClass) }} #{{ entry.deletedElementID }}
|
||||||
{% if entry.oldName is not empty %}
|
{% if entry.oldName is not empty %}
|
||||||
({{ entry.oldName }})
|
({{ entry.oldName }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
@ -12,4 +12,4 @@
|
||||||
<p class="m-0">
|
<p class="m-0">
|
||||||
<b>{% trans %}log.collection_deleted.on_collection{% endtrans %}</b>:
|
<b>{% trans %}log.collection_deleted.on_collection{% endtrans %}</b>:
|
||||||
{{ log_helper.translate_field(entry.collectionName) }}
|
{{ log_helper.translate_field(entry.collectionName) }}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -15,3 +15,24 @@
|
||||||
{{ form_row(form.partUnit) }}
|
{{ form_row(form.partUnit) }}
|
||||||
{{ form_row(form.partCustomState) }}
|
{{ form_row(form.partCustomState) }}
|
||||||
{{ form_row(form.gtin) }}
|
{{ form_row(form.gtin) }}
|
||||||
|
|
||||||
|
<div class="{{ offset_label }} {{ col_input }} ps-1">
|
||||||
|
<div class="accordion" id="accordionProviderReference">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header">
|
||||||
|
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#collapseProviderReference" aria-expanded="true" aria-controls="collapseProviderReference">
|
||||||
|
<span>{% trans %}part.edit.provider_reference{% endtrans %}</span>
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="collapseProviderReference" class="accordion-collapse collapse" data-bs-parent="#accordionProviderReference">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% trans %}part.edit.provider_reference.warning{% endtrans %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ form_widget(form.providerReference) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@
|
||||||
<a href="{{ part.providerReference.providerUrl }}" rel="noopener">
|
<a href="{{ part.providerReference.providerUrl }}" rel="noopener">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span title="{{ part.providerReference.providerKey }}">{{ info_provider_label(part.providerReference.providerKey)|default(part.providerReference.providerKey) }}</span>: {{ part.providerReference.providerId }}
|
<span title="{{ part.providerReference.providerKey }}">{{ info_provider_label(part.providerReference.providerKey)|default(part.providerReference.providerKey) }}</span>: {{ part.providerReference.providerId }}
|
||||||
<span> ({{ part.providerReference.lastUpdated | format_datetime() }})</span>
|
<span> ({{ part.providerReference.lastUpdated ? (part.providerReference.lastUpdated | format_datetime()) : ("part.info_provider_reference.updated_never"|trans) }})</span>
|
||||||
{% if part.providerReference.providerUrl %}
|
{% if part.providerReference.providerUrl %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<div class="carousel-caption text-white">
|
<div class="carousel-caption text-white">
|
||||||
<div><b>{{ pic.name }}</b></div>
|
<div><b>{{ pic.name }}</b></div>
|
||||||
<div>{% if pic.filename %}({{ pic.filename }}) {% endif %}</div>
|
<div>{% if pic.filename %}({{ pic.filename }}) {% endif %}</div>
|
||||||
<div>{{ entity_type_label(pic.element) }}</div>
|
<div>{{ type_label(pic.element) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
@ -41,4 +41,4 @@
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<img src="{{ asset('img/part_placeholder.svg') }}" class="img-fluid img-thumbnail bg-light mb-2" alt="Part main image" height="300" width="300">
|
<img src="{{ asset('img/part_placeholder.svg') }}" class="img-fluid img-thumbnail bg-light mb-2" alt="Part main image" height="300" width="300">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
<i>({{ timeTravel | format_datetime('short') }})</i>
|
<i>({{ timeTravel | format_datetime('short') }})</i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if part.projectBuildPart %}
|
{% if part.projectBuildPart %}
|
||||||
(<i>{{ entity_type_label(part.builtProject) }}</i>: <a class="text-white" href="{{ entity_url(part.builtProject) }}">{{ part.builtProject.name }}</a>)
|
(<i>{{ type_label(part.builtProject) }}</i>: <a class="text-white" href="{{ entity_url(part.builtProject) }}">{{ part.builtProject.name }}</a>)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
<span class="float-end">
|
<span class="float-end">
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ use App\Doctrine\Functions\SiValueSort;
|
||||||
use Doctrine\DBAL\Platforms\MySQLPlatform;
|
use Doctrine\DBAL\Platforms\MySQLPlatform;
|
||||||
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
||||||
use Doctrine\DBAL\Platforms\SQLitePlatform;
|
use Doctrine\DBAL\Platforms\SQLitePlatform;
|
||||||
|
use PHPUnit\Framework\Attributes\DataProvider;
|
||||||
|
|
||||||
final class SiValueSortTest extends AbstractDoctrineFunctionTestCase
|
final class SiValueSortTest extends AbstractDoctrineFunctionTestCase
|
||||||
{
|
{
|
||||||
|
|
@ -71,9 +72,7 @@ final class SiValueSortTest extends AbstractDoctrineFunctionTestCase
|
||||||
$this->assertSame('SI_VALUE(part_name)', $sql);
|
$this->assertSame('SI_VALUE(part_name)', $sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
#[DataProvider('sqliteSiValueProvider')]
|
||||||
* @dataProvider sqliteSiValueProvider
|
|
||||||
*/
|
|
||||||
public function testSqliteSiValue(?string $input, ?float $expected): void
|
public function testSqliteSiValue(?string $input, ?float $expected): void
|
||||||
{
|
{
|
||||||
$result = SiValueSort::sqliteSiValue($input);
|
$result = SiValueSort::sqliteSiValue($input);
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,6 @@ final class AttachmentTest extends TestCase
|
||||||
{
|
{
|
||||||
$reflection = new ReflectionClass($object);
|
$reflection = new ReflectionClass($object);
|
||||||
$reflection_property = $reflection->getProperty($property);
|
$reflection_property = $reflection->getProperty($property);
|
||||||
$reflection_property->setAccessible(true);
|
|
||||||
$reflection_property->setValue($object, $value);
|
$reflection_property->setValue($object, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,12 @@ final class ProjectBuildRequestTest extends TestCase
|
||||||
|
|
||||||
$part2->setName('Part 2');
|
$part2->setName('Part 2');
|
||||||
$part2->setPartUnit($float_unit);
|
$part2->setPartUnit($float_unit);
|
||||||
$this->lot2 = new PartLot();
|
$this->lot2 = new class extends PartLot {
|
||||||
|
public function getID(): ?int
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
};;
|
||||||
$part2->addPartLot($this->lot2);
|
$part2->addPartLot($this->lot2);
|
||||||
$this->lot2->setAmount(2.5);
|
$this->lot2->setAmount(2.5);
|
||||||
$this->lot2->setDescription('Lot 2');
|
$this->lot2->setDescription('Lot 2');
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,6 @@ final class BuerklinProviderTest extends TestCase
|
||||||
public function testAttributesToParametersParsesUnitsAndValues(): void
|
public function testAttributesToParametersParsesUnitsAndValues(): void
|
||||||
{
|
{
|
||||||
$method = new \ReflectionMethod(BuerklinProvider::class, 'attributesToParameters');
|
$method = new \ReflectionMethod(BuerklinProvider::class, 'attributesToParameters');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$features = [
|
$features = [
|
||||||
[
|
[
|
||||||
|
|
@ -127,7 +126,6 @@ final class BuerklinProviderTest extends TestCase
|
||||||
public function testComplianceParameters(): void
|
public function testComplianceParameters(): void
|
||||||
{
|
{
|
||||||
$method = new \ReflectionMethod(BuerklinProvider::class, 'complianceToParameters');
|
$method = new \ReflectionMethod(BuerklinProvider::class, 'complianceToParameters');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$product = [
|
$product = [
|
||||||
'labelRoHS' => 'Yes',
|
'labelRoHS' => 'Yes',
|
||||||
|
|
@ -158,7 +156,6 @@ final class BuerklinProviderTest extends TestCase
|
||||||
public function testImageSelectionPrefersZoomAndDeduplicates(): void
|
public function testImageSelectionPrefersZoomAndDeduplicates(): void
|
||||||
{
|
{
|
||||||
$method = new \ReflectionMethod(BuerklinProvider::class, 'getProductImages');
|
$method = new \ReflectionMethod(BuerklinProvider::class, 'getProductImages');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$images = [
|
$images = [
|
||||||
['format' => 'product', 'url' => '/img/a.webp'],
|
['format' => 'product', 'url' => '/img/a.webp'],
|
||||||
|
|
@ -176,7 +173,6 @@ final class BuerklinProviderTest extends TestCase
|
||||||
public function testFootprintExtraction(): void
|
public function testFootprintExtraction(): void
|
||||||
{
|
{
|
||||||
$method = new \ReflectionMethod(BuerklinProvider::class, 'getPartDetail');
|
$method = new \ReflectionMethod(BuerklinProvider::class, 'getPartDetail');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$product = [
|
$product = [
|
||||||
'code' => 'TEST1',
|
'code' => 'TEST1',
|
||||||
|
|
@ -212,7 +208,6 @@ final class BuerklinProviderTest extends TestCase
|
||||||
];
|
];
|
||||||
|
|
||||||
$method = new \ReflectionMethod(BuerklinProvider::class, 'pricesToVendorInfo');
|
$method = new \ReflectionMethod(BuerklinProvider::class, 'pricesToVendorInfo');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$vendorInfo = $method->invoke($this->provider, 'SKU1', 'https://x', $detailPrice);
|
$vendorInfo = $method->invoke($this->provider, 'SKU1', 'https://x', $detailPrice);
|
||||||
|
|
||||||
|
|
@ -260,7 +255,6 @@ final class BuerklinProviderTest extends TestCase
|
||||||
);
|
);
|
||||||
|
|
||||||
$method = new \ReflectionMethod(BuerklinProvider::class, 'convertPartDetailToSearchResult');
|
$method = new \ReflectionMethod(BuerklinProvider::class, 'convertPartDetailToSearchResult');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$dto = $method->invoke($this->provider, $detail);
|
$dto = $method->invoke($this->provider, $detail);
|
||||||
|
|
||||||
|
|
@ -273,13 +267,13 @@ final class BuerklinProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->assertSame(['buerklin.com'], $this->provider->getHandledDomains());
|
$this->assertSame(['buerklin.com'], $this->provider->getHandledDomains());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[DataProvider('buerklinIdFromUrlProvider')]
|
#[DataProvider('buerklinIdFromUrlProvider')]
|
||||||
public function testGetIDFromURLExtractsId(string $url, ?string $expected): void
|
public function testGetIDFromURLExtractsId(string $url, ?string $expected): void
|
||||||
{
|
{
|
||||||
$this->assertSame($expected, $this->provider->getIDFromURL($url));
|
$this->assertSame($expected, $this->provider->getIDFromURL($url));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function buerklinIdFromUrlProvider(): \Iterator
|
public static function buerklinIdFromUrlProvider(): \Iterator
|
||||||
{
|
{
|
||||||
yield 'de long path' => [
|
yield 'de long path' => [
|
||||||
|
|
|
||||||
|
|
@ -367,7 +367,6 @@ final class LCSCProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$reflection = new \ReflectionClass($this->provider);
|
$reflection = new \ReflectionClass($this->provider);
|
||||||
$method = $reflection->getMethod('sanitizeField');
|
$method = $reflection->getMethod('sanitizeField');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$this->assertNull($method->invokeArgs($this->provider, [null]));
|
$this->assertNull($method->invokeArgs($this->provider, [null]));
|
||||||
$this->assertEquals('Clean text', $method->invokeArgs($this->provider, ['Clean text']));
|
$this->assertEquals('Clean text', $method->invokeArgs($this->provider, ['Clean text']));
|
||||||
|
|
@ -378,7 +377,6 @@ final class LCSCProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$reflection = new \ReflectionClass($this->provider);
|
$reflection = new \ReflectionClass($this->provider);
|
||||||
$method = $reflection->getMethod('getUsedCurrency');
|
$method = $reflection->getMethod('getUsedCurrency');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$this->assertEquals('USD', $method->invokeArgs($this->provider, ['US$']));
|
$this->assertEquals('USD', $method->invokeArgs($this->provider, ['US$']));
|
||||||
$this->assertEquals('USD', $method->invokeArgs($this->provider, ['$']));
|
$this->assertEquals('USD', $method->invokeArgs($this->provider, ['$']));
|
||||||
|
|
@ -391,7 +389,6 @@ final class LCSCProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$reflection = new \ReflectionClass($this->provider);
|
$reflection = new \ReflectionClass($this->provider);
|
||||||
$method = $reflection->getMethod('getProductShortURL');
|
$method = $reflection->getMethod('getProductShortURL');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$result = $method->invokeArgs($this->provider, ['C123456']);
|
$result = $method->invokeArgs($this->provider, ['C123456']);
|
||||||
$this->assertEquals('https://www.lcsc.com/product-detail/C123456.html', $result);
|
$this->assertEquals('https://www.lcsc.com/product-detail/C123456.html', $result);
|
||||||
|
|
@ -401,7 +398,6 @@ final class LCSCProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$reflection = new \ReflectionClass($this->provider);
|
$reflection = new \ReflectionClass($this->provider);
|
||||||
$method = $reflection->getMethod('getProductDatasheets');
|
$method = $reflection->getMethod('getProductDatasheets');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$result = $method->invokeArgs($this->provider, [null]);
|
$result = $method->invokeArgs($this->provider, [null]);
|
||||||
$this->assertIsArray($result);
|
$this->assertIsArray($result);
|
||||||
|
|
@ -417,7 +413,6 @@ final class LCSCProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$reflection = new \ReflectionClass($this->provider);
|
$reflection = new \ReflectionClass($this->provider);
|
||||||
$method = $reflection->getMethod('getProductImages');
|
$method = $reflection->getMethod('getProductImages');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$result = $method->invokeArgs($this->provider, [null]);
|
$result = $method->invokeArgs($this->provider, [null]);
|
||||||
$this->assertIsArray($result);
|
$this->assertIsArray($result);
|
||||||
|
|
@ -434,7 +429,6 @@ final class LCSCProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$reflection = new \ReflectionClass($this->provider);
|
$reflection = new \ReflectionClass($this->provider);
|
||||||
$method = $reflection->getMethod('attributesToParameters');
|
$method = $reflection->getMethod('attributesToParameters');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$attributes = [
|
$attributes = [
|
||||||
['paramNameEn' => 'Resistance', 'paramValueEn' => '1kΩ'],
|
['paramNameEn' => 'Resistance', 'paramValueEn' => '1kΩ'],
|
||||||
|
|
@ -454,7 +448,6 @@ final class LCSCProviderTest extends TestCase
|
||||||
{
|
{
|
||||||
$reflection = new \ReflectionClass($this->provider);
|
$reflection = new \ReflectionClass($this->provider);
|
||||||
$method = $reflection->getMethod('pricesToVendorInfo');
|
$method = $reflection->getMethod('pricesToVendorInfo');
|
||||||
$method->setAccessible(true);
|
|
||||||
|
|
||||||
$prices = [
|
$prices = [
|
||||||
['ladder' => 1, 'productPrice' => '0.10', 'currencySymbol' => 'US$'],
|
['ladder' => 1, 'productPrice' => '0.10', 'currencySymbol' => 'US$'],
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,12 @@
|
||||||
<target>Los!</target>
|
<target>Los!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="8d38e7538" name="user.password_strength.crack_time">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>user.password_strength.crack_time</source>
|
||||||
|
<target>Geschätzte Zeit bis zum Knacken: %time%</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="dBtnOk01" name="dialog.btn.ok">
|
<unit id="dBtnOk01" name="dialog.btn.ok">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>dialog.btn.ok</source>
|
<source>dialog.btn.ok</source>
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,11 @@
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="8d38e7538" name="user.password_strength.crack_time">
|
<unit id="8d38e7538" name="user.password_strength.crack_time">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>user.password_strength.crack_time</source>
|
<source>user.password_strength.crack_time</source>
|
||||||
<target>Estimated time to crack: %time%</target>
|
<target>Estimated time to crack: %time%</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="dBtnOk01" name="dialog.btn.ok">
|
<unit id="dBtnOk01" name="dialog.btn.ok">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>dialog.btn.ok</source>
|
<source>dialog.btn.ok</source>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
<unit id="R4hoCqe" name="part.labelp">
|
<unit id="R4hoCqe" name="part.labelp">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.labelp</source>
|
<source>part.labelp</source>
|
||||||
<target>部件</target>
|
<target>物料</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="S4CxO.T" name="entity.select.group.new_not_added_to_DB">
|
<unit id="S4CxO.T" name="entity.select.group.new_not_added_to_DB">
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
<unit id="c44gN8b" name="user.password_strength.medium">
|
<unit id="c44gN8b" name="user.password_strength.medium">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>user.password_strength.medium</source>
|
<source>user.password_strength.medium</source>
|
||||||
<target>中</target>
|
<target>中等</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="NwiBLHc" name="user.password_strength.strong">
|
<unit id="NwiBLHc" name="user.password_strength.strong">
|
||||||
|
|
@ -52,7 +52,13 @@
|
||||||
<unit id="U5IhkwB" name="search.submit">
|
<unit id="U5IhkwB" name="search.submit">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>search.submit</source>
|
<source>search.submit</source>
|
||||||
<target>GO!</target>
|
<target>搜索</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="8d38e7538" name="user.password_strength.crack_time">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>user.password_strength.crack_time</source>
|
||||||
|
<target>预计破解时间:%time%</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="dBtnOk01" name="dialog.btn.ok">
|
<unit id="dBtnOk01" name="dialog.btn.ok">
|
||||||
|
|
|
||||||
|
|
@ -13617,6 +13617,36 @@ Buerklin-API-Authentication-Server:
|
||||||
<target>Host-URL</target>
|
<target>Host-URL</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="UeFbCNh" name="settings.ai.ollama">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>settings.ai.ollama</source>
|
||||||
|
<target>Ollama</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="9nfJ_vr" name="settings.ai.ollama.endpoint">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>settings.ai.ollama.endpoint</source>
|
||||||
|
<target>Endpoint URL</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="67dSwE5" name="settings.ai.ollama.apiKey">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>settings.ai.ollama.apiKey</source>
|
||||||
|
<target>API Key</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="VxXEQUD" name="settings.ai.timeout">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>settings.ai.timeout</source>
|
||||||
|
<target>Timeout</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="vRgtpoJ" name="settings.ai.timeout.help">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>settings.ai.timeout.help</source>
|
||||||
|
<target>Maximale Wartezeit in Sekunden auf eine Antwort. Die lokale KI-Inferenz kann mehrere Minuten dauern, die Inferenz in der Cloud ist in der Regel schneller.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="kuDv.So" name="browser_plugin.recent_pages.title">
|
<unit id="kuDv.So" name="browser_plugin.recent_pages.title">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>browser_plugin.recent_pages.title</source>
|
<source>browser_plugin.recent_pages.title</source>
|
||||||
|
|
@ -13665,5 +13695,53 @@ Buerklin-API-Authentication-Server:
|
||||||
<target>Sie können diesen zufällig generierten Wert verwenden (geben Sie ihn niemandem weiter):</target>
|
<target>Sie können diesen zufällig generierten Wert verwenden (geben Sie ihn niemandem weiter):</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="cEwxoSj" name="info_providers.provider_key">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.provider_key</source>
|
||||||
|
<target>Informationsquelle</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="0sjPRNV" name="info_providers.provider_id">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.provider_id</source>
|
||||||
|
<target>Provider ID</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="2DzzAxZ" name="info_providers.provider_url">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.provider_url</source>
|
||||||
|
<target>Provider URL</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="4v3QmF6" name="part.edit.provider_reference">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.edit.provider_reference</source>
|
||||||
|
<target>Referenz auf Informationsquelle</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="9X2qEi7" name="log.element_edited.changed_fields.providerReference.provider_key">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>log.element_edited.changed_fields.providerReference.provider_key</source>
|
||||||
|
<target>Informationsquelle</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="MWXgWDb" name="log.element_edited.changed_fields.providerReference.provider_id">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>log.element_edited.changed_fields.providerReference.provider_id</source>
|
||||||
|
<target>Provider ID</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="83fSFvo" name="part.info_provider_reference.updated_never">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.info_provider_reference.updated_never</source>
|
||||||
|
<target>Niemals aktualisiert</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="yIK_Wtj" name="part.edit.provider_reference.warning">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.edit.provider_reference.warning</source>
|
||||||
|
<target>Warnung: Das Ändern der Werte an dieser Stelle kann den Mechanismus zum Abrufen von Informationen beeinträchtigen! Sie sollten nach Möglichkeit die Funktion „Von Informationsquelle aktualisieren“ verwenden.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
|
|
@ -13637,6 +13637,18 @@ Buerklin-API Authentication server:
|
||||||
<target>API Key</target>
|
<target>API Key</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="VxXEQUD" name="settings.ai.timeout">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>settings.ai.timeout</source>
|
||||||
|
<target>Timeout</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="vRgtpoJ" name="settings.ai.timeout.help">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>settings.ai.timeout.help</source>
|
||||||
|
<target>Maximum time in seconds to wait for a response. Local AI inference might take multiple minutes, cloud inference is normally faster.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="kuDv.So" name="browser_plugin.recent_pages.title">
|
<unit id="kuDv.So" name="browser_plugin.recent_pages.title">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>browser_plugin.recent_pages.title</source>
|
<source>browser_plugin.recent_pages.title</source>
|
||||||
|
|
@ -13685,5 +13697,53 @@ Buerklin-API Authentication server:
|
||||||
<target>You can use this randomly generated value (share it with nobody):</target>
|
<target>You can use this randomly generated value (share it with nobody):</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="cEwxoSj" name="info_providers.provider_key">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.provider_key</source>
|
||||||
|
<target>Info provider</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="0sjPRNV" name="info_providers.provider_id">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.provider_id</source>
|
||||||
|
<target>Provider ID</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="2DzzAxZ" name="info_providers.provider_url">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.provider_url</source>
|
||||||
|
<target>Provider URL</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="4v3QmF6" name="part.edit.provider_reference">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.edit.provider_reference</source>
|
||||||
|
<target>Info provider reference</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="9X2qEi7" name="log.element_edited.changed_fields.providerReference.provider_key">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>log.element_edited.changed_fields.providerReference.provider_key</source>
|
||||||
|
<target>Information provider</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="MWXgWDb" name="log.element_edited.changed_fields.providerReference.provider_id">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>log.element_edited.changed_fields.providerReference.provider_id</source>
|
||||||
|
<target>Provider ID</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="83fSFvo" name="part.info_provider_reference.updated_never">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.info_provider_reference.updated_never</source>
|
||||||
|
<target>Never updated</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="yIK_Wtj" name="part.edit.provider_reference.warning">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.edit.provider_reference.warning</source>
|
||||||
|
<target>Warning: Changing values here can break the info retrieval mechanism! You should use the "update from info provider" functionality whenever possible.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -4,19 +4,19 @@
|
||||||
<unit id="GrLNa9P" name="user.login_error.user_disabled">
|
<unit id="GrLNa9P" name="user.login_error.user_disabled">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>user.login_error.user_disabled</source>
|
<source>user.login_error.user_disabled</source>
|
||||||
<target>账户已被禁用。请联系管理员</target>
|
<target>此账户已被禁用!如果这是个错误请联系管理员。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="IFQ5XrG" name="saml.error.cannot_login_local_user_per_saml">
|
<unit id="IFQ5XrG" name="saml.error.cannot_login_local_user_per_saml">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>saml.error.cannot_login_local_user_per_saml</source>
|
<source>saml.error.cannot_login_local_user_per_saml</source>
|
||||||
<target>无法通过 SSO 以本地用户身份登录。请使用本地用户密码</target>
|
<target>无法通过SSO以本地用户身份登录!请使用本地用户和密码登录。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="wOYPZmb" name="saml.error.cannot_login_saml_user_locally">
|
<unit id="wOYPZmb" name="saml.error.cannot_login_saml_user_locally">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>saml.error.cannot_login_saml_user_locally</source>
|
<source>saml.error.cannot_login_saml_user_locally</source>
|
||||||
<target>无法使用本地身份验证器以SAML用户身份登录!请改用SSO登录</target>
|
<target>禁止使用本地认证以SAML用户身份登录!请使用SSO登录。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
||||||
|
|
@ -253,5 +253,23 @@
|
||||||
<target>Dies ist keine gültige GTIN / EAN!</target>
|
<target>Dies ist keine gültige GTIN / EAN!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="vnpejmb" name="info_providers.validation.provider_id_without_key">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.validation.provider_id_without_key</source>
|
||||||
|
<target>Wenn Sie eine Anbieter-ID angeben, müssen Sie auch einen Info-Anbieter angeben oder beide entfernen.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="yFlA5OA" name="info_providers.validation.provider_url_without_key">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.validation.provider_url_without_key</source>
|
||||||
|
<target>Wenn Sie eine Anbieter-URL angeben, müssen Sie auch einen Info-Anbieter angeben.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="gUHUXoV" name="info_providers.validation.provider_key_without_id">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.validation.provider_key_without_id</source>
|
||||||
|
<target>Wenn Sie einen Info-Anbieter angeben, müssen Sie auch eine Anbieter-ID angeben oder beides entfernen.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
|
|
@ -253,5 +253,23 @@
|
||||||
<target>This is not an valid GTIN / EAN!</target>
|
<target>This is not an valid GTIN / EAN!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="vnpejmb" name="info_providers.validation.provider_id_without_key">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.validation.provider_id_without_key</source>
|
||||||
|
<target>If you specify an provider ID, you also need to specify an info provider or remove both.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="yFlA5OA" name="info_providers.validation.provider_url_without_key">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.validation.provider_url_without_key</source>
|
||||||
|
<target>If you specify an provider URL, you also need to specify an info provider.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="gUHUXoV" name="info_providers.validation.provider_key_without_id">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>info_providers.validation.provider_key_without_id</source>
|
||||||
|
<target>If you specify an info provider, you also need to provide an provider id, or remove both.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
|
|
@ -4,31 +4,31 @@
|
||||||
<unit id="cRbk.cm" name="part.master_attachment.must_be_picture">
|
<unit id="cRbk.cm" name="part.master_attachment.must_be_picture">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.master_attachment.must_be_picture</source>
|
<source>part.master_attachment.must_be_picture</source>
|
||||||
<target>预览附件必须是有效的图片</target>
|
<target>预览附件必须是有效的图片!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="v8HkcJB" name="structural.entity.unique_name">
|
<unit id="v8HkcJB" name="structural.entity.unique_name">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>structural.entity.unique_name</source>
|
<source>structural.entity.unique_name</source>
|
||||||
<target>相同层下已存在同名元素</target>
|
<target>当前层级已存在同名元素!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="dW7b2B_" name="parameters.validator.min_lesser_typical">
|
<unit id="dW7b2B_" name="parameters.validator.min_lesser_typical">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>parameters.validator.min_lesser_typical</source>
|
<source>parameters.validator.min_lesser_typical</source>
|
||||||
<target>值必须小于或等于标称值 ({{compare_value}})。</target>
|
<target>值必须小于或等于标称值({{ compared_value }})。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="Yfp2uC5" name="parameters.validator.min_lesser_max">
|
<unit id="Yfp2uC5" name="parameters.validator.min_lesser_max">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>parameters.validator.min_lesser_max</source>
|
<source>parameters.validator.min_lesser_max</source>
|
||||||
<target>值必须小于最大值 ({{compare_value}})。</target>
|
<target>值必须小于最大值({{ compared_value }})。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="P6b.8Ou" name="parameters.validator.max_greater_typical">
|
<unit id="P6b.8Ou" name="parameters.validator.max_greater_typical">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>parameters.validator.max_greater_typical</source>
|
<source>parameters.validator.max_greater_typical</source>
|
||||||
<target>值必须大于或等于标称值 ({{compare_value}})。</target>
|
<target>值必须大于或等于标称值({{ compared_value }})。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="P41193Y" name="validator.user.username_already_used">
|
<unit id="P41193Y" name="validator.user.username_already_used">
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
<unit id="EKPQiyf" name="user.invalid_username">
|
<unit id="EKPQiyf" name="user.invalid_username">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>user.invalid_username</source>
|
<source>user.invalid_username</source>
|
||||||
<target>用户名只能包含字母、数字、下划线、点、加号或减号。</target>
|
<target>用户名只能包含字母、数字、下划线、点、加号或减号,且不能以@开头!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="_v.DMg." name="validator.noneofitschild.self">
|
<unit id="_v.DMg." name="validator.noneofitschild.self">
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.noneofitschild.self</source>
|
<source>validator.noneofitschild.self</source>
|
||||||
<target>一个元素不能是它自己的父元素。</target>
|
<target>元素不能成为自生的父级!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="W90LyFQ" name="validator.noneofitschild.children">
|
<unit id="W90LyFQ" name="validator.noneofitschild.children">
|
||||||
|
|
@ -58,199 +58,199 @@
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.noneofitschild.children</source>
|
<source>validator.noneofitschild.children</source>
|
||||||
<target>不能将子元素指定为父元素(会导致循环)。</target>
|
<target>不能将子元素指定为自身父级,这会导致循环引用!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="GAUS.LK" name="validator.select_valid_category">
|
<unit id="GAUS.LK" name="validator.select_valid_category">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.select_valid_category</source>
|
<source>validator.select_valid_category</source>
|
||||||
<target>请选择一个有效的类别。</target>
|
<target>请选择有效的分类!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="h6qELde" name="validator.part_lot.only_existing">
|
<unit id="h6qELde" name="validator.part_lot.only_existing">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_lot.only_existing</source>
|
<source>validator.part_lot.only_existing</source>
|
||||||
<target>无法将新部件添加到此位置,因为它被标记为 "仅现有"</target>
|
<target>无法向此位置增加新物料,因为它被标记为"仅限已有物料"</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="Prriyy0" name="validator.part_lot.location_full.no_increase">
|
<unit id="Prriyy0" name="validator.part_lot.location_full.no_increase">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_lot.location_full.no_increase</source>
|
<source>validator.part_lot.location_full.no_increase</source>
|
||||||
<target>位置已满。数量无法增加(增加值必须小于 {{ old_amount }})。</target>
|
<target>位置已满。数量无法增加(要求必须小于 {{ old_amount }})。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="eeEjB4s" name="validator.part_lot.location_full">
|
<unit id="eeEjB4s" name="validator.part_lot.location_full">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_lot.location_full</source>
|
<source>validator.part_lot.location_full</source>
|
||||||
<target>位置已满。无法添加新部件。</target>
|
<target>位置已满。无法向其中增加新物料。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="2yWi8eP" name="validator.part_lot.single_part">
|
<unit id="2yWi8eP" name="validator.part_lot.single_part">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_lot.single_part</source>
|
<source>validator.part_lot.single_part</source>
|
||||||
<target>该位置只能储存一个部件。</target>
|
<target>此位置只能包含单个物料并且已满!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="A.TFhbb" name="validator.attachment.must_not_be_null">
|
<unit id="A.TFhbb" name="validator.attachment.must_not_be_null">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.attachment.must_not_be_null</source>
|
<source>validator.attachment.must_not_be_null</source>
|
||||||
<target>必须选择附件类型。</target>
|
<target>必须选择附件类型!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id=".lqKoij" name="validator.orderdetail.supplier_must_not_be_null">
|
<unit id=".lqKoij" name="validator.orderdetail.supplier_must_not_be_null">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.orderdetail.supplier_must_not_be_null</source>
|
<source>validator.orderdetail.supplier_must_not_be_null</source>
|
||||||
<target>必须选择供应商。</target>
|
<target>必须选择供应商!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="bcNZzK." name="validator.measurement_unit.use_si_prefix_needs_unit">
|
<unit id="bcNZzK." name="validator.measurement_unit.use_si_prefix_needs_unit">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.measurement_unit.use_si_prefix_needs_unit</source>
|
<source>validator.measurement_unit.use_si_prefix_needs_unit</source>
|
||||||
<target>要启用 SI 前缀,必须设置单位符号。</target>
|
<target>要启用SI前缀,必须设置单位符号!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="gZ5FFL1" name="part.ipn.must_be_unique">
|
<unit id="gZ5FFL1" name="part.ipn.must_be_unique">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.ipn.must_be_unique</source>
|
<source>part.ipn.must_be_unique</source>
|
||||||
<target>内部部件号是唯一的。{{ value }} 已被使用!</target>
|
<target>内部物料号必须唯一。{{ value }} 已被使用!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="P31Yg.d" name="validator.project.bom_entry.name_or_part_needed">
|
<unit id="P31Yg.d" name="validator.project.bom_entry.name_or_part_needed">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.project.bom_entry.name_or_part_needed</source>
|
<source>validator.project.bom_entry.name_or_part_needed</source>
|
||||||
<target>您必须为 BOM 条目选择部件,或为非部件 BOM 条目设置名称。</target>
|
<target>必须为[物料BOM条目]选择一个物料,或为[非物料BOM条目]设定名称。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
|
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>project.bom_entry.name_already_in_bom</source>
|
<source>project.bom_entry.name_already_in_bom</source>
|
||||||
<target>已存在具有该名称的 BOM 条目。</target>
|
<target>已存在同名BOM条目!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="jB3B50E" name="project.bom_entry.part_already_in_bom">
|
<unit id="jB3B50E" name="project.bom_entry.part_already_in_bom">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>project.bom_entry.part_already_in_bom</source>
|
<source>project.bom_entry.part_already_in_bom</source>
|
||||||
<target>该部件已存在于 BOM 中。</target>
|
<target>此物料已存在于BOM中!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="NdkzP1n" name="project.bom_entry.mountnames_quantity_mismatch">
|
<unit id="NdkzP1n" name="project.bom_entry.mountnames_quantity_mismatch">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>project.bom_entry.mountnames_quantity_mismatch</source>
|
<source>project.bom_entry.mountnames_quantity_mismatch</source>
|
||||||
<target>挂载名称的数量必须与 BOM 数量匹配。</target>
|
<target>装配名称数量必须与BOM数量匹配!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="8teRCgR" name="project.bom_entry.can_not_add_own_builds_part">
|
<unit id="8teRCgR" name="project.bom_entry.can_not_add_own_builds_part">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>project.bom_entry.can_not_add_own_builds_part</source>
|
<source>project.bom_entry.can_not_add_own_builds_part</source>
|
||||||
<target>您无法将项目自己的生产映射部件添加到 BOM 中。</target>
|
<target>不能将[项目自身]的[组装输出物料]增加到BOM中。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="asBxPxe" name="project.bom_has_to_include_all_subelement_parts">
|
<unit id="asBxPxe" name="project.bom_has_to_include_all_subelement_parts">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>project.bom_has_to_include_all_subelement_parts</source>
|
<source>project.bom_has_to_include_all_subelement_parts</source>
|
||||||
<target>项目 BOM 必须包括所有子项目生产的部件。项目 %project_name% 的 %part_name% 部件丢失。</target>
|
<target>项目BOM必须包含所有子项目的组装物料。缺少项目 %project_name% 的物料 %part_name%!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="uxaE9Ct" name="project.bom_entry.price_not_allowed_on_parts">
|
<unit id="uxaE9Ct" name="project.bom_entry.price_not_allowed_on_parts">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>project.bom_entry.price_not_allowed_on_parts</source>
|
<source>project.bom_entry.price_not_allowed_on_parts</source>
|
||||||
<target>与部件关联的 BOM 条目上不允许有价格。请在部件上定义价格。</target>
|
<target>与物料关联的BOM条目不允许设置价格。请在物料上定义价格。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="xZ68Nzl" name="validator.project_build.lot_bigger_than_needed">
|
<unit id="xZ68Nzl" name="validator.project_build.lot_bigger_than_needed">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.project_build.lot_bigger_than_needed</source>
|
<source>validator.project_build.lot_bigger_than_needed</source>
|
||||||
<target>选择的提取数量超出所需数量。</target>
|
<target>选择的数量超过所需数量!请减少到所需数量。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="68_.V_X" name="validator.project_build.lot_smaller_than_needed">
|
<unit id="68_.V_X" name="validator.project_build.lot_smaller_than_needed">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.project_build.lot_smaller_than_needed</source>
|
<source>validator.project_build.lot_smaller_than_needed</source>
|
||||||
<target>选择的提取数量少于所需数量。</target>
|
<target>选择的数量少于所需数量!请增加到所需数量。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="yZGS8uZ" name="part.name.must_match_category_regex">
|
<unit id="yZGS8uZ" name="part.name.must_match_category_regex">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>part.name.must_match_category_regex</source>
|
<source>part.name.must_match_category_regex</source>
|
||||||
<target>部件名称与类别指定的正则表达式不匹配:%regex%</target>
|
<target>物料名称与分类指定的正则表达式不匹配:%regex%</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="Q8wP5Jd" name="validator.attachment.name_not_blank">
|
<unit id="Q8wP5Jd" name="validator.attachment.name_not_blank">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.attachment.name_not_blank</source>
|
<source>validator.attachment.name_not_blank</source>
|
||||||
<target>手动设置值,或上传文件使用其文件名作为附件的名称。</target>
|
<target>在此处设置值,或上传文件后自动使用其文件名作为附件名称。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="DH0IkNR" name="validator.part_lot.owner_must_match_storage_location_owner">
|
<unit id="DH0IkNR" name="validator.part_lot.owner_must_match_storage_location_owner">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_lot.owner_must_match_storage_location_owner</source>
|
<source>validator.part_lot.owner_must_match_storage_location_owner</source>
|
||||||
<target>该 批次的所有者 必须与 所选存储位置的所有者(%owner_name%) 匹配!</target>
|
<target>此物料批号的所有者必须与所选存储位置的所有者(%owner_name%)匹配!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="TzySicw" name="validator.part_lot.owner_must_not_be_anonymous">
|
<unit id="TzySicw" name="validator.part_lot.owner_must_not_be_anonymous">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_lot.owner_must_not_be_anonymous</source>
|
<source>validator.part_lot.owner_must_not_be_anonymous</source>
|
||||||
<target>批次所有者不能是匿名用户。</target>
|
<target>物料批号所有者不能是匿名用户!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="GthNWUb" name="validator.part_association.must_set_an_value_if_type_is_other">
|
<unit id="GthNWUb" name="validator.part_association.must_set_an_value_if_type_is_other">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_association.must_set_an_value_if_type_is_other</source>
|
<source>validator.part_association.must_set_an_value_if_type_is_other</source>
|
||||||
<target>如果将类型设置为 "other" 则必须为其设置一个描述性值。</target>
|
<target>当类型设置为"其他"时必须为其设定描述性值!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="Be4Im81" name="validator.part_association.part_cannot_be_associated_with_itself">
|
<unit id="Be4Im81" name="validator.part_association.part_cannot_be_associated_with_itself">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_association.part_cannot_be_associated_with_itself</source>
|
<source>validator.part_association.part_cannot_be_associated_with_itself</source>
|
||||||
<target>部件不能与自己关联。</target>
|
<target>物料不能与自身关联!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="q5Ej6Xm" name="validator.part_association.already_exists">
|
<unit id="q5Ej6Xm" name="validator.part_association.already_exists">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_association.already_exists</source>
|
<source>validator.part_association.already_exists</source>
|
||||||
<target>与此部件的关联已存在。</target>
|
<target>与此物料的关联已存在!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="HbI5bga" name="validator.part_lot.vendor_barcode_must_be_unique">
|
<unit id="HbI5bga" name="validator.part_lot.vendor_barcode_must_be_unique">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.part_lot.vendor_barcode_must_be_unique</source>
|
<source>validator.part_lot.vendor_barcode_must_be_unique</source>
|
||||||
<target>该供应商条码已在另一批次中使用。条形码必须是唯一的</target>
|
<target>此供应商条码值已在另一物料批号中使用。条码必须唯一!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="ufQJh7E" name="validator.year_2038_bug_on_32bit">
|
<unit id="ufQJh7E" name="validator.year_2038_bug_on_32bit">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.year_2038_bug_on_32bit</source>
|
<source>validator.year_2038_bug_on_32bit</source>
|
||||||
<target>由于技术限制,在32位系统中无法选择2038年1月19日之后的日期!</target>
|
<target>由于技术限制,在32位系统上无法选择2038-01-19之后的日期!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="iM9yb_p" name="validator.fileSize.invalidFormat">
|
<unit id="iM9yb_p" name="validator.fileSize.invalidFormat">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.fileSize.invalidFormat</source>
|
<source>validator.fileSize.invalidFormat</source>
|
||||||
<target>文件大小格式无效。请使用整数并以 K、M 或 G 作为后缀,分别代表 KB、MB 或 GB。</target>
|
<target>无效的文件大小格式。请使用整数后加 K(KByte)、M(MByte)、G(GByte)的后缀。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="ZFxQ0BZ" name="validator.invalid_range">
|
<unit id="ZFxQ0BZ" name="validator.invalid_range">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.invalid_range</source>
|
<source>validator.invalid_range</source>
|
||||||
<target>给定的范围无效</target>
|
<target>指定的范围无效!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="m4gp2P_" name="validator.google_code.wrong_code">
|
<unit id="m4gp2P_" name="validator.google_code.wrong_code">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.google_code.wrong_code</source>
|
<source>validator.google_code.wrong_code</source>
|
||||||
<target>验证码无效。请检查验证器应用设置是否正确,并确保服务器与认证设备的时间均已同步。</target>
|
<target>验证码无效。请检查验证器应用是否正确设置,并且切薄服务器和验证设备的时间均正确。</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="I330cr5" name="settings.synonyms.type_synonyms.collection_type.duplicate">
|
<unit id="I330cr5" name="settings.synonyms.type_synonyms.collection_type.duplicate">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>settings.synonyms.type_synonyms.collection_type.duplicate</source>
|
<source>settings.synonyms.type_synonyms.collection_type.duplicate</source>
|
||||||
<target>该类型在此语言下已存在翻译定义!</target>
|
<target>已为此类型和语言定义了翻译!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="zT_j_oQ" name="validator.invalid_gtin">
|
<unit id="zT_j_oQ" name="validator.invalid_gtin">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>validator.invalid_gtin</source>
|
<source>validator.invalid_gtin</source>
|
||||||
<target>无效的GTIN / EAN 码。</target>
|
<target>这不是有效的GTIN/EAN!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
||||||
249
yarn.lock
249
yarn.lock
|
|
@ -2,58 +2,58 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@algolia/autocomplete-core@1.19.8":
|
"@algolia/autocomplete-core@1.19.9":
|
||||||
version "1.19.8"
|
version "1.19.9"
|
||||||
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.19.8.tgz#7c84c771d28643fb00d09026c05013fb97aeea23"
|
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.19.9.tgz#bbed371e56aeea4a31a3af239f16733e1b8aedca"
|
||||||
integrity sha512-3YEorYg44niXcm7gkft3nXYItHd44e8tmh4D33CTszPgP0QWkaLEaFywiNyJBo7UL/mqObA/G9RYuU7R8tN1IA==
|
integrity sha512-4U2JKLMWlDu0CotYyUkWakDxr8AIav3QtIUXXRpfavYN29aVWfzlwJp9T0rPKEf/dO2QCPAUc0Kq1Tj1GJxo2A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@algolia/autocomplete-plugin-algolia-insights" "1.19.8"
|
"@algolia/autocomplete-plugin-algolia-insights" "1.19.9"
|
||||||
"@algolia/autocomplete-shared" "1.19.8"
|
"@algolia/autocomplete-shared" "1.19.9"
|
||||||
|
|
||||||
"@algolia/autocomplete-js@1.19.8", "@algolia/autocomplete-js@^1.17.0":
|
"@algolia/autocomplete-js@1.19.9", "@algolia/autocomplete-js@^1.17.0":
|
||||||
version "1.19.8"
|
version "1.19.9"
|
||||||
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-js/-/autocomplete-js-1.19.8.tgz#35960525442d741a0a4ee5ac4e1fcd6c550355ff"
|
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-js/-/autocomplete-js-1.19.9.tgz#b41ac9bdda41503e3766e430ab4e66adc5854737"
|
||||||
integrity sha512-9Sfr9Un3vObdtnj6IqzxoD9XisjFJxA9WAyVxmOkwTD9aVluyNwDeEWeGLy12xhRyILjA5C7byto159cZcdEEA==
|
integrity sha512-AXtqH+BBjDrTeoqCqOom082umhMtL/RF3+DVQSkoukh/1aaFdevNAtCqxwQSUCKQFLo0YLcDsB0cBItnl1X+bg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@algolia/autocomplete-core" "1.19.8"
|
"@algolia/autocomplete-core" "1.19.9"
|
||||||
"@algolia/autocomplete-preset-algolia" "1.19.8"
|
"@algolia/autocomplete-preset-algolia" "1.19.9"
|
||||||
"@algolia/autocomplete-shared" "1.19.8"
|
"@algolia/autocomplete-shared" "1.19.9"
|
||||||
htm "^3.1.1"
|
htm "^3.1.1"
|
||||||
preact "^10.13.2"
|
preact "^10.13.2"
|
||||||
|
|
||||||
"@algolia/autocomplete-plugin-algolia-insights@1.19.8":
|
"@algolia/autocomplete-plugin-algolia-insights@1.19.9":
|
||||||
version "1.19.8"
|
version "1.19.9"
|
||||||
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.8.tgz#f60d21edbe2a42e6d4e2215430733e3f51641471"
|
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.9.tgz#f799737d13bf0c4ec8421619c7107fa05c836535"
|
||||||
integrity sha512-ZvJWO8ZZJDpc1LNM2TTBdmQsZBLMR4rU5iNR2OYvEeFBiaf/0ESnRSSLQbryarJY4SVxtoz6A2ZtDMNM+iQEAA==
|
integrity sha512-6mExC6X7762s2SV3eJy3QOkB8bdMmnUhQ2agvGVDuzwoGyr3PquGSY/0vPQXCfiAiCaXUz1rXn+lwghgSi0l0w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@algolia/autocomplete-shared" "1.19.8"
|
"@algolia/autocomplete-shared" "1.19.9"
|
||||||
|
|
||||||
"@algolia/autocomplete-plugin-recent-searches@^1.17.0":
|
"@algolia/autocomplete-plugin-recent-searches@^1.17.0":
|
||||||
version "1.19.8"
|
version "1.19.9"
|
||||||
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-recent-searches/-/autocomplete-plugin-recent-searches-1.19.8.tgz#74c1d64bea603cc29ac14a4ee8e6d7ccd4d1423d"
|
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-recent-searches/-/autocomplete-plugin-recent-searches-1.19.9.tgz#f17d46a7909effdea7763489e32f06867f498449"
|
||||||
integrity sha512-Y8bLNJcdMCjSp4Mp6pfcdfl1kGCwogzlaJFUtREK3kInwDL4Ea7Fx0DO8eg8sHBkcsxq7XGHD23OH5+AmYQsKw==
|
integrity sha512-SSUAULhKXK8IFZQoRlBoKLYso3s+i5R62ALxcec8MX44y2cHSmWFyWVOMOKYiywtOmpYW5XLLLVZUWststszWw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@algolia/autocomplete-core" "1.19.8"
|
"@algolia/autocomplete-core" "1.19.9"
|
||||||
"@algolia/autocomplete-js" "1.19.8"
|
"@algolia/autocomplete-js" "1.19.9"
|
||||||
"@algolia/autocomplete-preset-algolia" "1.19.8"
|
"@algolia/autocomplete-preset-algolia" "1.19.9"
|
||||||
"@algolia/autocomplete-shared" "1.19.8"
|
"@algolia/autocomplete-shared" "1.19.9"
|
||||||
|
|
||||||
"@algolia/autocomplete-preset-algolia@1.19.8":
|
"@algolia/autocomplete-preset-algolia@1.19.9":
|
||||||
version "1.19.8"
|
version "1.19.9"
|
||||||
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.19.8.tgz#1bfffba816d497193d89692e17aa31cba875e96a"
|
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.19.9.tgz#6f5138118b8cf55c2c2a543ebcc5bf3b7c381fc2"
|
||||||
integrity sha512-5XhJe5uXXLrt+C1MjIv1/BfGNHZyD1xkAYMVANTjdY+PXwO4o+3YIK2XGU0MxHTGryy70G6+xVO9TB7xA+3hGQ==
|
integrity sha512-x/vKrHNy2Swp83AJ+PX0hhxhkgUqWVNV6bk440LkqQOwT8CfK4EN3M/gHIt8L9YAwbJvOgviE/Vr3g3AOyDwsA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@algolia/autocomplete-shared" "1.19.8"
|
"@algolia/autocomplete-shared" "1.19.9"
|
||||||
|
|
||||||
"@algolia/autocomplete-shared@1.19.8":
|
"@algolia/autocomplete-shared@1.19.9":
|
||||||
version "1.19.8"
|
version "1.19.9"
|
||||||
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.8.tgz#5d723d8bdb448efbb1b0e1c7ff94cc18e5b1dc0e"
|
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.9.tgz#c5b05e23c71027e4e45a301f286593dffdcdfbdf"
|
||||||
integrity sha512-h5hf2t8ejF6vlOgvLaZzQbWs5SyH2z4PAWygNAvvD/2RI29hdQ54ldUGwqVuj9Srs+n8XUKTPUqb7fvhBhQrnQ==
|
integrity sha512-YosP9Uoek6y/Ur1r1qeogk4biMe/hzkyNcgMCciw0//3XpCM7VlYLSHnyt/vOnEOGhCCc0+3v+unEiH6zz+Z1A==
|
||||||
|
|
||||||
"@algolia/autocomplete-theme-classic@^1.17.0":
|
"@algolia/autocomplete-theme-classic@^1.17.0":
|
||||||
version "1.19.8"
|
version "1.19.9"
|
||||||
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-theme-classic/-/autocomplete-theme-classic-1.19.8.tgz#33706300a2f711ac9386ec8008a0f119ffdccd7b"
|
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-theme-classic/-/autocomplete-theme-classic-1.19.9.tgz#27a22f3047b248d7ef4082e562f47e73ee64c815"
|
||||||
integrity sha512-FYmpeOyL5Wy444ZGp1IW57fevpMSBMewN37j+0WULMTJZGobnvTgVEKjYIgtv5Ku4/RNNp54rtEx2/OU6l8GYA==
|
integrity sha512-MWCQXWC1qbDDXE1W0fPPGRLNNRLy8zupd6pRCabBuI6gyjR0aJaah5m3S1MucJcmXRqV9/ErkMBjnw7iKGCrvA==
|
||||||
|
|
||||||
"@babel/code-frame@^7.29.7":
|
"@babel/code-frame@^7.29.7":
|
||||||
version "7.29.7"
|
version "7.29.7"
|
||||||
|
|
@ -1570,9 +1570,9 @@
|
||||||
es-toolkit "1.45.1"
|
es-toolkit "1.45.1"
|
||||||
|
|
||||||
"@colordx/core@^5.4.3":
|
"@colordx/core@^5.4.3":
|
||||||
version "5.4.3"
|
version "5.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/@colordx/core/-/core-5.4.3.tgz#35a8d239b324a6cdf9a16de9970a32c8abc24824"
|
resolved "https://registry.yarnpkg.com/@colordx/core/-/core-5.5.0.tgz#d786dfde8781bbe56a0be9f862f9ab5d1ab4629d"
|
||||||
integrity sha512-kIxYSfA5T8HXjav55UaaH/o/cKivF6jCCGIb8eqtcsfI46wsvlSiT8jMDyrl779qLec3c2c2oHBZo4oAhvbjrQ==
|
integrity sha512-3PxTH8itZzltK0U9jTwVVnjLXvnDYuq3m+QXsHkENxWiPRh4WaoLcs1SQjqgZ55kS+QyirpH5BVwzP2gMVG6EQ==
|
||||||
|
|
||||||
"@discoveryjs/json-ext@^0.6.1", "@discoveryjs/json-ext@^0.6.3":
|
"@discoveryjs/json-ext@^0.6.1", "@discoveryjs/json-ext@^0.6.3":
|
||||||
version "0.6.3"
|
version "0.6.3"
|
||||||
|
|
@ -1621,9 +1621,9 @@
|
||||||
tslib "^2.8.0"
|
tslib "^2.8.0"
|
||||||
|
|
||||||
"@fortawesome/fontawesome-free@^7.0.0":
|
"@fortawesome/fontawesome-free@^7.0.0":
|
||||||
version "7.2.0"
|
version "7.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-7.2.0.tgz#188c1053ce422ad1f934d7df242a973fcb89636d"
|
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-7.3.0.tgz#c26db8baad037c5dff9d88980757cb5d90540d8a"
|
||||||
integrity sha512-3DguDv/oUE+7vjMeTSOjCSG+KeawgVQOHrKRnvUuqYh1mfArrh7s+s8hXW3e4RerBA1+Wh+hBqf8sJNpqNrBWg==
|
integrity sha512-Yw4Qa43P6e4Xwh0TwEUkHQNRJInWaqIBo73VJmns3j2AIlZPAvUcR4yGIxCPqPRCgyJ5KIVIalF/I1GxhZ/Kgw==
|
||||||
|
|
||||||
"@hotwired/stimulus-webpack-helpers@^1.0.1":
|
"@hotwired/stimulus-webpack-helpers@^1.0.1":
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
|
|
@ -1887,9 +1887,9 @@
|
||||||
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
|
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "26.0.0"
|
version "26.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-26.0.0.tgz#d4aece9e9412e9f2008d59bc2d74f5279316b665"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-26.0.1.tgz#4a60e2c7a6d68bd261e265f8983bfe1601263ce3"
|
||||||
integrity sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA==
|
integrity sha512-fc3KiUoBt6kie0N9bIW3E47vZsuaMf0PM2AaUpLCLT0s/LvX1nxAim6Fc049cNxODPpGm6qRAuUOB86SkRuPQw==
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types "~8.3.0"
|
undici-types "~8.3.0"
|
||||||
|
|
||||||
|
|
@ -1921,9 +1921,9 @@
|
||||||
"@types/yargs-parser" "*"
|
"@types/yargs-parser" "*"
|
||||||
|
|
||||||
"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.3.0":
|
"@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.3.0":
|
||||||
version "1.3.1"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.1.tgz#0e8f34854df7966b09304a18e808b23997bb9fc1"
|
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.2.tgz#a03ad82cd5676414d068ba86f880c5681194aadf"
|
||||||
integrity sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==
|
integrity sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA==
|
||||||
|
|
||||||
"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1":
|
"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1":
|
||||||
version "1.14.1"
|
version "1.14.1"
|
||||||
|
|
@ -2251,10 +2251,10 @@ base64-js@^1.1.2, base64-js@^1.3.0:
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||||
|
|
||||||
baseline-browser-mapping@^2.10.12:
|
baseline-browser-mapping@^2.10.38:
|
||||||
version "2.10.38"
|
version "2.10.40"
|
||||||
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz#c84d093c4bf7325c5053c279d90f153c66526042"
|
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz#f372c8eb36ff4ad0b5e7ae467014abef124554ba"
|
||||||
integrity sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==
|
integrity sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==
|
||||||
|
|
||||||
big.js@^5.2.2:
|
big.js@^5.2.2:
|
||||||
version "5.2.2"
|
version "5.2.2"
|
||||||
|
|
@ -2281,13 +2281,6 @@ bootswatch@^5.1.3:
|
||||||
resolved "https://registry.yarnpkg.com/bootswatch/-/bootswatch-5.3.8.tgz#534538ce50285e52cb715823f8b4d734f73956e7"
|
resolved "https://registry.yarnpkg.com/bootswatch/-/bootswatch-5.3.8.tgz#534538ce50285e52cb715823f8b4d734f73956e7"
|
||||||
integrity sha512-88mnH9tv+x6DV+scBxYFOpM4YSDVhyfEgbhqaEfvkHNctKI9qRcACxIP9nmBZ5mSeLXtsgax1VsRkUs1eWjlAQ==
|
integrity sha512-88mnH9tv+x6DV+scBxYFOpM4YSDVhyfEgbhqaEfvkHNctKI9qRcACxIP9nmBZ5mSeLXtsgax1VsRkUs1eWjlAQ==
|
||||||
|
|
||||||
braces@^3.0.3:
|
|
||||||
version "3.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
|
|
||||||
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
|
|
||||||
dependencies:
|
|
||||||
fill-range "^7.1.1"
|
|
||||||
|
|
||||||
brotli@^1.3.2:
|
brotli@^1.3.2:
|
||||||
version "1.3.3"
|
version "1.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/brotli/-/brotli-1.3.3.tgz#7365d8cc00f12cf765d2b2c898716bcf4b604d48"
|
resolved "https://registry.yarnpkg.com/brotli/-/brotli-1.3.3.tgz#7365d8cc00f12cf765d2b2c898716bcf4b604d48"
|
||||||
|
|
@ -2303,14 +2296,14 @@ browserify-zlib@^0.2.0:
|
||||||
pako "~1.0.5"
|
pako "~1.0.5"
|
||||||
|
|
||||||
browserslist@^4.0.0, browserslist@^4.24.0, browserslist@^4.28.1, browserslist@^4.28.2:
|
browserslist@^4.0.0, browserslist@^4.24.0, browserslist@^4.28.1, browserslist@^4.28.2:
|
||||||
version "4.28.2"
|
version "4.28.4"
|
||||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.2.tgz#f50b65362ef48974ca9f50b3680566d786b811d2"
|
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.4.tgz#dd8b8167a32845ff5f8cd6ce13f5abba16cd04c9"
|
||||||
integrity sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==
|
integrity sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==
|
||||||
dependencies:
|
dependencies:
|
||||||
baseline-browser-mapping "^2.10.12"
|
baseline-browser-mapping "^2.10.38"
|
||||||
caniuse-lite "^1.0.30001782"
|
caniuse-lite "^1.0.30001799"
|
||||||
electron-to-chromium "^1.5.328"
|
electron-to-chromium "^1.5.376"
|
||||||
node-releases "^2.0.36"
|
node-releases "^2.0.48"
|
||||||
update-browserslist-db "^1.2.3"
|
update-browserslist-db "^1.2.3"
|
||||||
|
|
||||||
bs-custom-file-input@^1.3.4:
|
bs-custom-file-input@^1.3.4:
|
||||||
|
|
@ -2333,7 +2326,7 @@ caniuse-api@^3.0.0:
|
||||||
lodash.memoize "^4.1.2"
|
lodash.memoize "^4.1.2"
|
||||||
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.30001799:
|
||||||
version "1.0.30001799"
|
version "1.0.30001799"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz#5c909138c27f1a61219d3e092071c1cc7d32dc55"
|
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz#5c909138c27f1a61219d3e092071c1cc7d32dc55"
|
||||||
integrity sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==
|
integrity sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==
|
||||||
|
|
@ -2925,10 +2918,10 @@ domutils@^3.0.1:
|
||||||
domelementtype "^2.3.0"
|
domelementtype "^2.3.0"
|
||||||
domhandler "^5.0.3"
|
domhandler "^5.0.3"
|
||||||
|
|
||||||
electron-to-chromium@^1.5.328:
|
electron-to-chromium@^1.5.376:
|
||||||
version "1.5.376"
|
version "1.5.380"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.376.tgz#16a9d4b72cb16c416aa73a879d92b047b96797ac"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.380.tgz#6dbe112f22b35ccdf627f894ad7515cdd35f6388"
|
||||||
integrity sha512-cUVA7/RvbFTEuw/i3obUwDTRIXojaxkResf+ibByPFxjc6XK3VNtcQXV0NSbAlJ0FMjcJGgftVVB4Qo184EXvA==
|
integrity sha512-W6d5AbuEoRayO447cqrg6lKJIlscgRnnxOZl/08kfV71BQDoEBC7Wwis68z87LjyK6f4kWyTaubuDbhHKrZkbA==
|
||||||
|
|
||||||
emoji-regex@^8.0.0:
|
emoji-regex@^8.0.0:
|
||||||
version "8.0.0"
|
version "8.0.0"
|
||||||
|
|
@ -2940,10 +2933,10 @@ emojis-list@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
|
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
|
||||||
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
|
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
|
||||||
|
|
||||||
enhanced-resolve@^5.0.0, enhanced-resolve@^5.22.0:
|
enhanced-resolve@^5.22.2:
|
||||||
version "5.24.0"
|
version "5.24.1"
|
||||||
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.24.0.tgz#cf14b9768a774cb6a5087220c0dc6e55df6ec35a"
|
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.24.1.tgz#b2439adf5d31d7e4764de1f9ecf942d6cd3fc874"
|
||||||
integrity sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ==
|
integrity sha512-7DdUaTjmNwMcH2gLr1qycesKII3BK4RLy/mdAb7x10Lq7bR4aNKHt1BR1ZALSv0rPM/hF5wYF0PhGop/rJm8vw==
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs "^4.2.4"
|
graceful-fs "^4.2.4"
|
||||||
tapable "^2.3.3"
|
tapable "^2.3.3"
|
||||||
|
|
@ -3057,13 +3050,6 @@ fastest-levenshtein@1.0.16, fastest-levenshtein@^1.0.12, fastest-levenshtein@^1.
|
||||||
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
|
resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
|
||||||
integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
|
integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
|
||||||
|
|
||||||
fill-range@^7.1.1:
|
|
||||||
version "7.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
|
|
||||||
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
|
|
||||||
dependencies:
|
|
||||||
to-regex-range "^5.0.1"
|
|
||||||
|
|
||||||
find-up@^4.0.0:
|
find-up@^4.0.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
|
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
|
||||||
|
|
@ -3120,11 +3106,6 @@ github-slugger@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a"
|
resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a"
|
||||||
integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==
|
integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==
|
||||||
|
|
||||||
glob-to-regexp@^0.4.1:
|
|
||||||
version "0.4.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
|
|
||||||
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
|
|
||||||
|
|
||||||
good-listener@^1.2.2:
|
good-listener@^1.2.2:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
|
resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
|
||||||
|
|
@ -3375,11 +3356,6 @@ is-fullwidth-code-point@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
|
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
|
||||||
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
|
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
|
||||||
|
|
||||||
is-number@^7.0.0:
|
|
||||||
version "7.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
|
||||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
|
||||||
|
|
||||||
is-plain-obj@^4.0.0:
|
is-plain-obj@^4.0.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0"
|
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0"
|
||||||
|
|
@ -4049,14 +4025,6 @@ micromark@^4.0.0:
|
||||||
micromark-util-symbol "^2.0.0"
|
micromark-util-symbol "^2.0.0"
|
||||||
micromark-util-types "^2.0.0"
|
micromark-util-types "^2.0.0"
|
||||||
|
|
||||||
micromatch@^4.0.0:
|
|
||||||
version "4.0.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
|
||||||
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
|
|
||||||
dependencies:
|
|
||||||
braces "^3.0.3"
|
|
||||||
picomatch "^2.3.1"
|
|
||||||
|
|
||||||
mime-db@^1.54.0:
|
mime-db@^1.54.0:
|
||||||
version "1.54.0"
|
version "1.54.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
|
||||||
|
|
@ -4070,6 +4038,16 @@ mini-css-extract-plugin@^2.6.0:
|
||||||
schema-utils "^4.0.0"
|
schema-utils "^4.0.0"
|
||||||
tapable "^2.2.1"
|
tapable "^2.2.1"
|
||||||
|
|
||||||
|
minimizer-webpack-plugin@^5.6.1:
|
||||||
|
version "5.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.6.1.tgz#289922a4c96c4ed1ddb76b8a00bd8074e89a2f7f"
|
||||||
|
integrity sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw==
|
||||||
|
dependencies:
|
||||||
|
"@jridgewell/trace-mapping" "^0.3.25"
|
||||||
|
jest-worker "^27.4.5"
|
||||||
|
schema-utils "^4.3.0"
|
||||||
|
terser "^5.31.1"
|
||||||
|
|
||||||
mrmime@^2.0.0:
|
mrmime@^2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.1.tgz#bc3e87f7987853a54c9850eeb1f1078cd44adddc"
|
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.1.tgz#bc3e87f7987853a54c9850eeb1f1078cd44adddc"
|
||||||
|
|
@ -4081,9 +4059,9 @@ ms@^2.1.3:
|
||||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||||
|
|
||||||
nanoid@^3.3.12:
|
nanoid@^3.3.12:
|
||||||
version "3.3.14"
|
version "3.3.15"
|
||||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.14.tgz#02d7e019f05dd8eeee2779c6f42206c06542ab33"
|
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.15.tgz#36c490fad8c6e86c824c940dfdde999b69ed4316"
|
||||||
integrity sha512-U9kYi5bpVMEI31yC8iw4bJJp0avcHXA0W8/wNfLfnvJYzihQo2ZRPYPvpAAd570HAcCBjCTN7vnr+v4StKl1IQ==
|
integrity sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==
|
||||||
|
|
||||||
neo-async@^2.6.2:
|
neo-async@^2.6.2:
|
||||||
version "2.6.2"
|
version "2.6.2"
|
||||||
|
|
@ -4102,10 +4080,10 @@ node-notifier@^9.0.0:
|
||||||
uuid "^8.3.0"
|
uuid "^8.3.0"
|
||||||
which "^2.0.2"
|
which "^2.0.2"
|
||||||
|
|
||||||
node-releases@^2.0.36:
|
node-releases@^2.0.48:
|
||||||
version "2.0.48"
|
version "2.0.50"
|
||||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.48.tgz#4da73d040ada751fc9959d993f27de48792e3b7d"
|
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.50.tgz#597197a852071ce42fc2550e58e223242bcba969"
|
||||||
integrity sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==
|
integrity sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==
|
||||||
|
|
||||||
nth-check@^2.0.1:
|
nth-check@^2.0.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
|
|
@ -4203,12 +4181,7 @@ picocolors@^1.0.0, picocolors@^1.1.0, picocolors@^1.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
|
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
|
||||||
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
|
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
|
||||||
|
|
||||||
picomatch@^2.3.1:
|
picomatch@^4.0.0, picomatch@^4.0.3:
|
||||||
version "2.3.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.2.tgz#5a942915e26b372dc0f0e6753149a16e6b1c5601"
|
|
||||||
integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==
|
|
||||||
|
|
||||||
picomatch@^4.0.3:
|
|
||||||
version "4.0.4"
|
version "4.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589"
|
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589"
|
||||||
integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==
|
integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==
|
||||||
|
|
@ -4475,18 +4448,18 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
|
||||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||||
|
|
||||||
postcss@^8.2.14, postcss@^8.4.40:
|
postcss@^8.2.14, postcss@^8.4.40:
|
||||||
version "8.5.15"
|
version "8.5.16"
|
||||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.15.tgz#d1eaf677a324e9ec02196da2d3fecf4a0b9a735c"
|
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.16.tgz#1230ce0b5df354c24c0ea45f99ce5f6a88279d28"
|
||||||
integrity sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==
|
integrity sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^3.3.12"
|
nanoid "^3.3.12"
|
||||||
picocolors "^1.1.1"
|
picocolors "^1.1.1"
|
||||||
source-map-js "^1.2.1"
|
source-map-js "^1.2.1"
|
||||||
|
|
||||||
preact@^10.13.2:
|
preact@^10.13.2:
|
||||||
version "10.29.2"
|
version "10.29.3"
|
||||||
resolved "https://registry.yarnpkg.com/preact/-/preact-10.29.2.tgz#3e6069c471718b8d124d1cd67565114532e88d70"
|
resolved "https://registry.yarnpkg.com/preact/-/preact-10.29.3.tgz#36f96b7a8edc2fccea76daa5e7545597dc15ab28"
|
||||||
integrity sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==
|
integrity sha512-D9NL1GAnJZhc3RndVs4gDdxEeU9TcHgywMrhhOsnpdlvFjdbx0gAsLUnH6JEhlJH5giL7Tx5biWPUSEXE/HPzw==
|
||||||
|
|
||||||
pretty-error@^4.0.0:
|
pretty-error@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
|
|
@ -4744,7 +4717,7 @@ semver@^6.3.1:
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||||
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.6.3:
|
||||||
version "7.8.5"
|
version "7.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69"
|
||||||
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
|
integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==
|
||||||
|
|
@ -4926,7 +4899,7 @@ tapable@^2.0.0, tapable@^2.2.1, tapable@^2.3.0, tapable@^2.3.3:
|
||||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.3.tgz#5da7c9992c46038221267985ab28421a8879f160"
|
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.3.tgz#5da7c9992c46038221267985ab28421a8879f160"
|
||||||
integrity sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==
|
integrity sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==
|
||||||
|
|
||||||
terser-webpack-plugin@^5.3.0, terser-webpack-plugin@^5.5.0:
|
terser-webpack-plugin@^5.3.0:
|
||||||
version "5.6.1"
|
version "5.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz#47bc41bd8b8fab8383b62ec763b7394829097e7b"
|
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz#47bc41bd8b8fab8383b62ec763b7394829097e7b"
|
||||||
integrity sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==
|
integrity sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==
|
||||||
|
|
@ -4961,13 +4934,6 @@ tmp@^0.2.5:
|
||||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.7.tgz#26f4db11d1601ce8012dcb8a798ece1c06a99059"
|
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.7.tgz#26f4db11d1601ce8012dcb8a798ece1c06a99059"
|
||||||
integrity sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==
|
integrity sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==
|
||||||
|
|
||||||
to-regex-range@^5.0.1:
|
|
||||||
version "5.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
|
||||||
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
|
||||||
dependencies:
|
|
||||||
is-number "^7.0.0"
|
|
||||||
|
|
||||||
tom-select@^2.1.0:
|
tom-select@^2.1.0:
|
||||||
version "2.6.1"
|
version "2.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/tom-select/-/tom-select-2.6.1.tgz#54be5c4431d5d59c8c4897e6e051963bac11f44a"
|
resolved "https://registry.yarnpkg.com/tom-select/-/tom-select-2.6.1.tgz#54be5c4431d5d59c8c4897e6e051963bac11f44a"
|
||||||
|
|
@ -4997,14 +4963,12 @@ trough@^2.0.0:
|
||||||
integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==
|
integrity sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==
|
||||||
|
|
||||||
ts-loader@^9.2.6:
|
ts-loader@^9.2.6:
|
||||||
version "9.6.1"
|
version "9.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.6.1.tgz#4a5e87a24c2f9f0e6f1fee3e844e4591f2628e55"
|
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.6.2.tgz#a08f4935ddb87edbd58ce33b7b2558c2a77fdd47"
|
||||||
integrity sha512-8FMHnmxtpncUAu0ZjkqpXnOTlwc9eY95esH8WVN94guTPPdkg2ofVdiVM5j8L2lmjiGerXd56zXb/D2JyVQPLg==
|
integrity sha512-R4iuczmtgxvtuI556s+hTZ6/7Ee03VCAk/l/M8LY1OAsUgB7YydsCxkgq9D9pKRaD7GJqUi2u8fp9zZP/ufjKA==
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk "^4.1.0"
|
chalk "^4.1.0"
|
||||||
enhanced-resolve "^5.0.0"
|
picomatch "^4.0.0"
|
||||||
micromatch "^4.0.0"
|
|
||||||
semver "^7.3.4"
|
|
||||||
source-map "^0.7.4"
|
source-map "^0.7.4"
|
||||||
|
|
||||||
tslib@^2.8.0:
|
tslib@^2.8.0:
|
||||||
|
|
@ -5180,7 +5144,7 @@ vfile@^6.0.0:
|
||||||
"@types/unist" "^3.0.0"
|
"@types/unist" "^3.0.0"
|
||||||
vfile-message "^4.0.0"
|
vfile-message "^4.0.0"
|
||||||
|
|
||||||
watchpack@^2.5.1:
|
watchpack@^2.5.2:
|
||||||
version "2.5.2"
|
version "2.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.5.2.tgz#e12e82d84674266fc1c6dbfe38891b92ff0522ec"
|
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.5.2.tgz#e12e82d84674266fc1c6dbfe38891b92ff0522ec"
|
||||||
integrity sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==
|
integrity sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==
|
||||||
|
|
@ -5266,9 +5230,9 @@ webpack-sources@^3.5.0:
|
||||||
integrity sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==
|
integrity sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==
|
||||||
|
|
||||||
webpack@^5.74.0:
|
webpack@^5.74.0:
|
||||||
version "5.107.2"
|
version "5.108.1"
|
||||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.107.2.tgz#dea14dcb177b46b29de15f952f7303691ee2b596"
|
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.108.1.tgz#cd5856f9a88e55f344d64a6623c09bf34446cc9d"
|
||||||
integrity sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ==
|
integrity sha512-UUCihHQK3O7483Woa0SulNLDeAiOhHI2PN2PAPU4fVWJqbzhv04EJ8FaWtB9WWh3i8fRt28543U7VfuJTOrpgQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/estree" "^1.0.8"
|
"@types/estree" "^1.0.8"
|
||||||
"@types/json-schema" "^7.0.15"
|
"@types/json-schema" "^7.0.15"
|
||||||
|
|
@ -5279,19 +5243,18 @@ webpack@^5.74.0:
|
||||||
acorn-import-phases "^1.0.3"
|
acorn-import-phases "^1.0.3"
|
||||||
browserslist "^4.28.1"
|
browserslist "^4.28.1"
|
||||||
chrome-trace-event "^1.0.2"
|
chrome-trace-event "^1.0.2"
|
||||||
enhanced-resolve "^5.22.0"
|
enhanced-resolve "^5.22.2"
|
||||||
es-module-lexer "^2.1.0"
|
es-module-lexer "^2.1.0"
|
||||||
eslint-scope "5.1.1"
|
eslint-scope "5.1.1"
|
||||||
events "^3.2.0"
|
events "^3.2.0"
|
||||||
glob-to-regexp "^0.4.1"
|
|
||||||
graceful-fs "^4.2.11"
|
graceful-fs "^4.2.11"
|
||||||
loader-runner "^4.3.2"
|
loader-runner "^4.3.2"
|
||||||
mime-db "^1.54.0"
|
mime-db "^1.54.0"
|
||||||
|
minimizer-webpack-plugin "^5.6.1"
|
||||||
neo-async "^2.6.2"
|
neo-async "^2.6.2"
|
||||||
schema-utils "^4.3.3"
|
schema-utils "^4.3.3"
|
||||||
tapable "^2.3.0"
|
tapable "^2.3.0"
|
||||||
terser-webpack-plugin "^5.5.0"
|
watchpack "^2.5.2"
|
||||||
watchpack "^2.5.1"
|
|
||||||
webpack-sources "^3.5.0"
|
webpack-sources "^3.5.0"
|
||||||
|
|
||||||
which@^2.0.1, which@^2.0.2:
|
which@^2.0.1, which@^2.0.2:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue