diff --git a/.github/workflows/assets_artifact_build.yml b/.github/workflows/assets_artifact_build.yml index 8ce7ccf6..3409b7fd 100644 --- a/.github/workflows/assets_artifact_build.yml +++ b/.github/workflows/assets_artifact_build.yml @@ -37,7 +37,7 @@ jobs: run: | echo "::set-output name=dir::$(composer config cache-files-dir)" - - uses: actions/cache@v4 + - uses: actions/cache@v5 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -51,7 +51,7 @@ jobs: id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - - uses: actions/cache@v4 + - uses: actions/cache@v5 id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} @@ -80,13 +80,13 @@ jobs: run: zip -r /tmp/partdb_assets.zip public/build/ vendor/ - name: Upload assets artifact - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: Only dependencies and built assets path: /tmp/partdb_assets.zip - name: Upload full artifact - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: Full Part-DB including dependencies and built assets path: /tmp/partdb_with_assets.zip diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml index d8b099eb..f47ce87b 100644 --- a/.github/workflows/static_analysis.yml +++ b/.github/workflows/static_analysis.yml @@ -34,7 +34,7 @@ jobs: run: | echo "::set-output name=dir::$(composer config cache-files-dir)" - - uses: actions/cache@v4 + - uses: actions/cache@v5 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 822f5af6..3df1955a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -81,7 +81,7 @@ jobs: id: composer-cache run: | echo "::set-output name=dir::$(composer config cache-files-dir)" - - uses: actions/cache@v4 + - uses: actions/cache@v5 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -92,7 +92,7 @@ jobs: id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - - uses: actions/cache@v4 + - uses: actions/cache@v5 id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) with: path: ${{ steps.yarn-cache-dir-path.outputs.dir }} diff --git a/src/DataTables/ProjectBomEntriesDataTable.php b/src/DataTables/ProjectBomEntriesDataTable.php index fcb06984..96e69d9a 100644 --- a/src/DataTables/ProjectBomEntriesDataTable.php +++ b/src/DataTables/ProjectBomEntriesDataTable.php @@ -29,6 +29,7 @@ use App\DataTables\Helpers\PartDataTableHelper; use App\Entity\Attachments\Attachment; use App\Entity\Parts\Part; use App\Entity\ProjectSystem\ProjectBOMEntry; +use App\Services\ElementTypeNameGenerator; use App\Services\EntityURLGenerator; use App\Services\Formatters\AmountFormatter; use Doctrine\ORM\QueryBuilder; @@ -41,7 +42,8 @@ use Symfony\Contracts\Translation\TranslatorInterface; class ProjectBomEntriesDataTable implements DataTableTypeInterface { - public function __construct(protected TranslatorInterface $translator, protected PartDataTableHelper $partDataTableHelper, protected EntityURLGenerator $entityURLGenerator, protected AmountFormatter $amountFormatter) + public function __construct(protected TranslatorInterface $translator, protected PartDataTableHelper $partDataTableHelper, + protected EntityURLGenerator $entityURLGenerator, protected AmountFormatter $amountFormatter, private readonly ElementTypeNameGenerator $elementTypeNameGenerator) { } @@ -79,7 +81,14 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface return htmlspecialchars($this->amountFormatter->format($context->getQuantity(), $context->getPart()->getPartUnit())); }, ]) - + ->add('partId', TextColumn::class, [ + 'label' => $this->translator->trans('project.bom.part_id'), + 'visible' => true, + 'orderField' => 'part.id', + 'render' => function ($value, ProjectBOMEntry $context) { + return $context->getPart() instanceof Part ? (string) $context->getPart()->getId() : ''; + }, + ]) ->add('name', TextColumn::class, [ 'label' => $this->translator->trans('part.table.name'), 'orderField' => 'NATSORT(part.name)', diff --git a/src/Services/InfoProviderSystem/Providers/DigikeyProvider.php b/src/Services/InfoProviderSystem/Providers/DigikeyProvider.php index 423b5244..d7eb6e4f 100644 --- a/src/Services/InfoProviderSystem/Providers/DigikeyProvider.php +++ b/src/Services/InfoProviderSystem/Providers/DigikeyProvider.php @@ -311,6 +311,14 @@ class DigikeyProvider implements InfoProviderInterface 'auth_bearer' => $this->authTokenManager->getAlwaysValidTokenString(self::OAUTH_APP_NAME) ]); + if ($response->getStatusCode() === 404) { + //No media found + return [ + 'datasheets' => [], + 'images' => [], + ]; + } + $media_array = $response->toArray(); foreach ($media_array['MediaLinks'] as $media_link) { diff --git a/src/Services/InfoProviderSystem/Providers/ProviderCapabilities.php b/src/Services/InfoProviderSystem/Providers/ProviderCapabilities.php index fd67cd2c..bced19de 100644 --- a/src/Services/InfoProviderSystem/Providers/ProviderCapabilities.php +++ b/src/Services/InfoProviderSystem/Providers/ProviderCapabilities.php @@ -31,9 +31,6 @@ enum ProviderCapabilities /** Basic information about a part, like the name, description, part number, manufacturer etc */ case BASIC; - /** Information about the footprint of a part */ - case FOOTPRINT; - /** Provider can provide a picture for a part */ case PICTURE; @@ -43,6 +40,24 @@ enum ProviderCapabilities /** Provider can provide prices for a part */ case PRICE; + /** Information about the footprint of a part */ + case FOOTPRINT; + + /** + * Get the order index for displaying capabilities in a stable order. + * @return int + */ + public function getOrderIndex(): int + { + return match($this) { + self::BASIC => 1, + self::PICTURE => 2, + self::DATASHEET => 3, + self::PRICE => 4, + self::FOOTPRINT => 5, + }; + } + public function getTranslationKey(): string { return 'info_providers.capabilities.' . match($this) { diff --git a/templates/info_providers/providers.macro.html.twig b/templates/info_providers/providers.macro.html.twig index bf530ebd..bec8f24b 100644 --- a/templates/info_providers/providers.macro.html.twig +++ b/templates/info_providers/providers.macro.html.twig @@ -27,7 +27,7 @@ title="{% trans %}info_providers.settings.title{% endtrans %}" > {% endif %} - {% for capability in provider.capabilities %} + {% for capability in provider.capabilities|sort((a, b) => a.orderIndex <=> b.orderIndex) %} {# @var capability \App\Services\InfoProviderSystem\Providers\ProviderCapabilities #} diff --git a/templates/label_system/dialog.html.twig b/templates/label_system/dialog.html.twig index b9149aa3..11877a4c 100644 --- a/templates/label_system/dialog.html.twig +++ b/templates/label_system/dialog.html.twig @@ -135,8 +135,8 @@ {% block additional_content %} {% if pdf_data %} -
- +
+
{% endif %} diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 0be77adb..b651e94f 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -1,4 +1,4 @@ - + @@ -14032,128 +14032,128 @@ You can do this in the provider info list. - + settings.misc.ipn_suggest.useDuplicateDescription.help When enabled, the part’s description is used to find existing parts with the same description and to determine the next available IPN by incrementing their numeric suffix for the suggestion list. - + settings.misc.ipn_suggest.regex.help A PCRE-compatible regular expression every IPN has to fulfill. Leave empty to allow everything as IPN. - + user.labelp Users - + currency.labelp Currencies - + measurement_unit.labelp Measurement units - + attachment_type.labelp Attachment types - + label_profile.labelp Label profiles - + part_custom_state.labelp Custom part states - + group.labelp Groups - + settings.synonyms.type_synonym.type Type - + settings.synonyms.type_synonym.language Language - + settings.synonyms.type_synonym.translation_singular Translation Singular - + settings.synonyms.type_synonym.translation_plural Translation Plural - + settings.synonyms.type_synonym.add_entry Add entry - + settings.synonyms.type_synonym.remove_entry Remove entry - + settings.synonyms Synonyms - + settings.synonyms.help The synonyms systems allow overriding how Part-DB call certain things. This can be useful, especially if Part-DB is used in a different context than electronics. Please note that this system is currently experimental, and the synonyms defined here might not show up at all places. - + settings.synonyms.type_synonyms Type synonyms - + settings.synonyms.type_synonyms.help Type synonyms allow you to replace the labels of built-in data types. For example, you can rename "Footprint" to something else. - + log.element_edited.changed_fields.part_ipn_prefix IPN prefix - + part.labelp Parts @@ -14279,13 +14279,19 @@ Please note that this system is currently experimental, and the synonyms defined - - Do not remove! Used for datatables rendering. - - - datatable.datatable.lengthMenu - _MENU_ - + + Do not remove! Used for datatables rendering. + + + datatable.datatable.lengthMenu + _MENU_ + + + + + project.bom.part_id + [Part] ID + diff --git a/translations/validators.en.xlf b/translations/validators.en.xlf index d52f9c30..c1d6f6b8 100644 --- a/translations/validators.en.xlf +++ b/translations/validators.en.xlf @@ -366,7 +366,7 @@ - + settings.synonyms.type_synonyms.collection_type.duplicate There is already a translation defined for this type and language!