Compare commits

..

168 commits

Author SHA1 Message Date
Copilot
0000cd7a02
Fix spelling and grammar mistakes in documentation (#1127)
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
* Initial plan

* Fix spelling and grammar mistakes in documentation

Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com>
2025-12-05 00:05:31 +01:00
Copilot
9a1dbe06dc
Fix spelling and grammar mistakes in German and English translations (#1125)
* Initial plan

* Fix spelling and grammar mistakes in German and English translations

Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com>
2025-12-04 23:44:03 +01:00
Jan Böhmer
fd7106af28 Allow that the DEFAULT_URI does not end with a slash
We normalize the url with an env var processor before passing it to the saml lib, to avoid an error. Fixes issue #1118
2025-12-04 23:31:42 +01:00
Jan Böhmer
cb6da36954 Merge remote-tracking branch 'origin/master' 2025-12-04 23:04:47 +01:00
Jan Böhmer
a5275f7be7 Increase DB field length for URLs to 2048 chars
This fixes issue #1122
2025-12-04 23:04:44 +01:00
dependabot[bot]
17f9755b86
Bump actions/checkout from 5 to 6 (#1116)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-04 22:41:11 +01:00
Copilot
a3d6f77fda
Add missing German translations to messages.de.xlf (#1124)
* Initial plan

* Add 41 missing German translations to messages.de.xlf

Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jbtronics <5410681+jbtronics@users.noreply.github.com>
2025-12-04 22:33:59 +01:00
Jan Böhmer
36e1fcfbed Fixed bulk provider imports, issue described in #869
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / docker (push) Waiting to run
Docker Image Build (FrankenPHP) / docker (push) Waiting to run
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
This makes PR #1110 obsolete
2025-12-03 22:22:21 +01:00
Jan Böhmer
1925a71f30 Added translations for new IPN suggestion settings 2025-12-03 21:52:48 +01:00
Jan Böhmer
023d38d170 Allow to configure seperators, category fallback and a global prefix for IPN generation
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Translations still missing
2025-12-01 23:56:36 +01:00
Jan Böhmer
9a1961bcd7 Fixed fixtures loading (for real now hopefully) 2025-12-01 22:56:47 +01:00
Jan Böhmer
f27f0ab12d Fixed fixtures loading
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / docker (push) Waiting to run
Docker Image Build (FrankenPHP) / docker (push) Waiting to run
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
2025-11-30 23:40:53 +01:00
Jan Böhmer
9f2989444a Fixed phpstan issues 2025-11-30 23:37:34 +01:00
Jan Böhmer
8efc1ab07d Save changes to yarn.lock 2025-11-30 23:33:11 +01:00
Jan Böhmer
1596b4d7ea Updated jbtronics/settings-bundle for fixing compatibility issues with symfony 7.4 2025-11-30 23:27:27 +01:00
Jan Böhmer
d8ec65461e fixed error messages related to datafixtures in prod 2025-11-30 21:30:17 +01:00
Jan Böhmer
d89a76bdc3 Removed unnecessary frankenphp-symfony runtime, as it is now part of symonfy 7.4 2025-11-30 21:30:00 +01:00
Jan Böhmer
3b4a099285 Use AutowireIterator instead of deprecated TaggedIterator
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / docker (push) Waiting to run
Docker Image Build (FrankenPHP) / docker (push) Waiting to run
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
2025-11-30 15:43:25 +01:00
Jan Böhmer
161a9e930d Made IPN format help placeholder translatable 2025-11-30 15:38:46 +01:00
Jan Böhmer
3649fffde1 Made password toggle buttons labels translatable 2025-11-30 15:36:54 +01:00
Jan Böhmer
d55d9b43f9 Removed more clutter in settings form translation 2025-11-30 15:33:52 +01:00
Jan Böhmer
8e11e06077 Fixed multi translation of env var tooltip to remove clutter in translation editor 2025-11-30 15:28:22 +01:00
Jan Böhmer
e112a8dbe0 Use static message in settings to remove translation editor clutter 2025-11-30 15:17:37 +01:00
Jan Böhmer
5d843ec8eb Merge branch 'symfony74' 2025-11-30 15:10:21 +01:00
Jan Böhmer
3518321f0e Updated webpack-encore bundle 2025-11-30 15:10:13 +01:00
Jan Böhmer
4750a50fb9 Updated stimulus recipe 2025-11-30 15:07:59 +01:00
Jan Böhmer
52a9975769 Updated security recipe 2025-11-30 15:03:23 +01:00
Jan Böhmer
bb650c2218 Updated routing recipe 2025-11-30 15:01:37 +01:00
Jan Böhmer
3dc66542b2 Updated monolog recipe 2025-11-30 14:51:56 +01:00
Jan Böhmer
070ce800d5 Updated framework bundle recipe 2025-11-30 14:50:46 +01:00
Jan Böhmer
57dc4242b2 Updated phpunit bridge recipe 2025-11-30 14:48:00 +01:00
Jan Böhmer
5fa2167755 config/references update 2025-11-30 14:45:49 +01:00
Jan Böhmer
4eac63b683 Fixed phpunit deprecations 2025-11-30 14:45:40 +01:00
Jan Böhmer
171508fcad Fixed deprecated csv reader usage 2025-11-30 14:34:45 +01:00
Jan Böhmer
e4f8252e0f Upgraded to symfony 7.4 2025-11-30 14:30:04 +01:00
Jan Böhmer
e513960401 Updated dependencies 2025-11-30 14:26:37 +01:00
Jan Böhmer
84e35603b1 Made sidebar toggle button smaller 2025-11-30 14:20:50 +01:00
Jan Böhmer
3459731ca8 Show plural translation for entity type labels in synonym settings 2025-11-30 14:16:54 +01:00
Jan Böhmer
819a8cc56d Fixed category field in part edit page not being correctly rendered 2025-11-30 14:02:42 +01:00
Jan Böhmer
95c5ab7b8b Removed unnecessary polyfills
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
2025-11-12 21:54:41 +01:00
Jan Böhmer
f184afc918 Updated dependencies 2025-11-12 21:49:44 +01:00
web-devinition.de
54f318ecac
Implemented the ability to set user-defined synonyms/labels for internal element types
* Implementiere bevorzugte Sprachauswahl und Datenquellen-Synonyme

Die Spracheinstellungen/System-Settings wurden um die Möglichkeit ergänzt, bevorzugte Sprachen für die Dropdown-Menüs festzulegen. Zudem wurde ein Datenquellen-Synonymsystem implementiert, um benutzerfreundlichere Bezeichnungen anzuzeigen und zu personalisieren.

* Anpassung aus Analyse

* Entferne alten JSON-basierten Datenquellen-Synonym-Handler

Die Verwaltung der Datenquellen-Synonyme wurde überarbeitet, um ein flexibleres und strukturiertes Konzept zu ermöglichen. Der bestehende JSON-basierte Ansatz wurde durch eine neue Service-basierte Architektur ersetzt, die eine bessere Handhabung und Erweiterbarkeit erlaubt.

* Ermögliche Rückgabe aller möglichen Sprachoptionen in Verbindung mit den vom Nutzer freigeschalteten.

* Removed unnecessary service definition

The tag is applied via autoconfiguration

* Use default translations for the NotBlank constraint

* Started refactoring ElementTypeNameGenerator

* Made ElementTypeNameGenerator class readonly

* Modified form to work properly with new datastructure

* Made the form more beautiful and space saving

* Made synonym form even more space saving

* Allow to define overrides for any element label there is

* Use defined synonyms in ElementTypeNameGenerator

* Use ElementTypeNameGenerator where possible

* Register synonyms for element types as global translation parameters

* Revert changes done to permission layout

* Use new synonym system for admin page titles

* Removed now unnecessary services

* Reworked settings name and translation

* Renamed all files to Synonyms

* Removed unnecessary translations

* Removed unnecessary translations

* Fixed duplicate check

* Renamed synoynms translations

* Use our synonyms for permission translations

* Fixed phpstan issue

* Added tests

---------

Co-authored-by: Marcel Diegelmann <marcel.diegelmann@gmail.com>
Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2025-11-12 21:35:02 +01:00
Jan Böhmer
5e3bd26e27
New Crowdin updates (#1105)
* New translations validators.en.xlf (French)

* New translations security.en.xlf (French)

* New translations messages.en.xlf (French)

* New translations messages.en.xlf (French)
2025-11-12 21:34:05 +01:00
Jan Böhmer
e53b72a8d1 Merge remote-tracking branch 'origin/master'
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
2025-11-03 00:37:00 +01:00
Jan Böhmer
e8ff15ad0f Updated dependencies 2025-11-03 00:36:56 +01:00
dependabot[bot]
ec6b3ae414
Bump actions/setup-node from 5 to 6 (#1086)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 00:35:12 +01:00
dependabot[bot]
07e4521c30
Bump actions/upload-artifact from 4 to 5 (#1091)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 00:35:03 +01:00
web-devinition.de
771857e014
Added feature for part IPN suggest with category prefixes (#1054)
* Erweiterungstätigkeiten zur IPN-Vorschlagsliste anhand von Präfixen aus den Kategorien

* Umstellung Migrationen bzgl. Multi-Plattform-Support.
Zunächst MySQL, SQLite Statements integrieren.

* Postgre Statements integrieren

* SQL-Formatierung in Migration verbessern

* Erweitere IPN-Suggest um Bauteilbeschreibung.

Die Implementierung berücksichtigt nun zusätzlich die Bauteilbeschreibung zu maximal 150 Zeichen Länge für die Generierung von IPN-Vorschlägen und Inkrementen.

* Anpassungen aus Analyse vornehmen

* IPN-Validierung für Parts überarbeiten

* IPN-Vorschlagslogik um Konfiguration erweitert

* Anpassungen aus phpstan Analyse

* IPN-Vorschlagslogik erweitert und Bauteil-IPN vereindeutigt

Die IPN-Logik wurde um eine Konfiguration zur automatischen Suffix-Anfügung und die Berücksichtigung von doppelten Beschreibungen bei Bedarf ergänzt. Zudem wurde das Datenmodell angepasst, um eine eindeutige Speicherung der IPN zu gewährleisten.

* Regex-Konfigurationsmöglichkeit für IPN-Vorschläge einführen

Die Einstellungen für die IPN-Vorschlagslogik wurden um eine Regex-Validierung und eine Hilfetext-Konfiguration erweitert. Tests und Änderungen an den Formularoptionen wurden implementiert.

* Match range assert and form limits in suggestPartDigits

* Keep existing behavior with autoAppend suffix by default

* Show the regex hint in the browser validation notice.

* Improved translations

* Removed unnecessary service definition

* Removed german comments

---------

Co-authored-by: Marcel Diegelmann <marcel.diegelmann@gmail.com>
Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2025-11-03 00:31:47 +01:00
web-devinition.de
14a4f1f437
Added custom part status (#1053)
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
* Benutzerdefinierten Bauteilstatus einführen

* PartCustomStateController hinzufügen

* Umstellung Migrationen bzgl. Multi-Plattform-Support.
Zunächst MySQL, SQLite Statements integrieren.

* Postgre Statements integrieren

* Semikolon in Migration entfernen

* Migration für PartCustomState aktualisieren

* Benutzerdefinierten Bauteilstatus in TableSettings aufnehmen

* PartCustomStateControllerTest: Attribute für PHPUnit-Gruppen umgestellt

* PartCustomState: Mapping für Parameter korrigieren

* PartCustomState: Darstellung und Zuordnung von Anhängen ergänzt

Die Sidebar wurde um die Anzeige des benutzerdefinierten Bauteilstatus erweitert, inklusive Vorschaubild, sofern vorhanden.

* Migrationen zusammenführen

* PartCustomState: Anpassungen bzgl. Tests

* PartCustomStateEndpoint hinzufügen

* Made custom part states plural for consistency with other entity captions

* Fixed phpunit error

* Fixed phpstan issues

---------

Co-authored-by: Marcel Diegelmann <marcel.diegelmann@gmail.com>
Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2025-10-27 21:58:16 +01:00
Jan Böhmer
600686c32b Fixed phpstan issue
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
2025-10-19 16:20:08 +02:00
Jan Böhmer
2e3ff05d83 Merge remote-tracking branch 'origin/master' 2025-10-19 16:09:34 +02:00
Jan Böhmer
e9dcdbc30d Bump to Version 2.2.1 2025-10-19 16:09:29 +02:00
Jan Böhmer
6cbb482c0f
New Crowdin updates (#1083)
* New translations messages.en.xlf (English)

* New translations messages.en.xlf (English)

* New translations messages.en.xlf (English)

* New translations messages.en.xlf (English)

* New translations messages.en.xlf (German)
2025-10-19 16:08:42 +02:00
Jan Böhmer
68aafc4d2e Better align the part parameter tables to each other
Fixes issue #1066
2025-10-19 15:56:18 +02:00
Jan Böhmer
70354c8599 Try to show an more detailed error message, if digikey needs oauth reconnection 2025-10-19 15:45:48 +02:00
Jan Böhmer
43601e060c Update label when pressing enter in label dialog
Fixes issue #996
2025-10-19 15:15:25 +02:00
Jan Böhmer
56f82a7587 Fixed phpstan issues
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / docker (push) Waiting to run
Docker Image Build (FrankenPHP) / docker (push) Waiting to run
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
2025-10-19 00:39:40 +02:00
Jan Böhmer
4c30cab7c1 Do not change the dropdownParent of tomselect if it is inside a modal
This ensures that it is properly displayed. Fixes issue #1073
2025-10-19 00:34:31 +02:00
Jan Böhmer
1c8ca6c0a2 Added an settings option to change the default behavior of including child categories or not
Fixes issue #1077
2025-10-19 00:19:07 +02:00
Jan Böhmer
5dbe4ba00b Escape like pattern % and _ so that search containing these chars work like expected
This fixes issue #1075
2025-10-19 00:00:03 +02:00
Jan Böhmer
377feaf566 Use yellow alert box for notifying of empty bom on build, show infinite correclty and added translations
Fixes issue #1038
2025-10-18 23:32:20 +02:00
Marc
05839a549c Fix Wrong default number of project builds if BOM is empty #1038 2025-10-18 20:58:19 +02:00
Jan Böhmer
7a1a458abe Fixed error that permission preset was applied when pressing enter in groups and user admin
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / docker (push) Waiting to run
Docker Image Build (FrankenPHP) / docker (push) Waiting to run
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
This fixes issue #1039
2025-10-18 20:53:14 +02:00
Jan Böhmer
c71e4cd063 Updated dependencies 2025-10-18 20:52:45 +02:00
Jan Böhmer
d8e093e0c5 Added documentation about manually deleting the var/cache folder while upgrading from 1 to 2
This is related to issue #1084
2025-10-18 20:15:21 +02:00
Jan Böhmer
351e084ab1 Fixed translation of our placeholder ckeditor plugin by keeping existing translations on localization
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / docker (push) Waiting to run
Docker Image Build (FrankenPHP) / docker (push) Waiting to run
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
2025-10-18 01:17:19 +02:00
Jan Böhmer
bba6fff4a5 Only include the ckeditor translations we really need 2025-10-18 01:07:56 +02:00
Jan Böhmer
a8e92b5f46 Removed unused images leftover from legacy part-db 2025-10-18 01:03:21 +02:00
Jan Böhmer
8315e33258 Added hungarian to list of possible languages
Replaces PR #1081
2025-10-18 00:54:50 +02:00
Jan Böhmer
3881c26ee0 Manually added hungarian translation downloaded from crowdin
Somehow automatic synchronization doesnt work. Related to PR #1081
2025-10-18 00:46:49 +02:00
Jan Böhmer
028c64f6ec Merge remote-tracking branch 'origin/l10n_master' 2025-10-18 00:42:50 +02:00
Jan Böhmer
4088b141a6 New translations validators.en.xlf (Hungarian) 2025-10-17 22:49:41 +02:00
Jan Böhmer
445881bae9 New translations security.en.xlf (Hungarian) 2025-10-17 22:40:52 +02:00
Jan Böhmer
b3f7e445fe New translations messages.en.xlf (English) 2025-10-17 22:40:50 +02:00
Jan Böhmer
1f2a7b86e5 Fixed warning on PHP8.5 2025-10-17 22:39:58 +02:00
Jan Böhmer
ae787530ff Added an settings option to control what languages to show in the dropdown menu 2025-10-17 22:34:27 +02:00
Jan Böhmer
6e4ae15438 Do not remove associated Project BOM entries if part is deleted
Instead the part name is put into the name field. This fixes issue #1068
2025-10-17 21:30:40 +02:00
Jan Böhmer
e06d9da186 Load translations for CKEDITOR if language is not english
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / docker (push) Waiting to run
Docker Image Build (FrankenPHP) / docker (push) Waiting to run
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
2025-10-17 18:15:04 +02:00
Jan Böhmer
b035014867 Fixed english translation for placeholder plugin and use more modern translation system 2025-10-17 17:57:34 +02:00
Jan Böhmer
746aa53bc3 Fixed dropdown button visibility for ckeditor label placeholder plugin
This fixes issue #1056
2025-10-17 17:41:30 +02:00
Jan Böhmer
7b61a00f21 Updated ckeditor 2025-10-17 17:28:11 +02:00
Jan Böhmer
aa24888ee5 New translations messages.en.xlf (English) 2025-10-17 01:31:20 +02:00
Jan Böhmer
c735bfdb1d Made the titles of the settings categories translatable
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / docker (push) Waiting to run
Docker Image Build (FrankenPHP) / docker (push) Waiting to run
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
This fixes issue #1037
2025-10-17 00:35:01 +02:00
Jan Böhmer
41dbc27e27 Updated dependencies 2025-10-17 00:22:06 +02:00
Jan Böhmer
4d98605e93 Fixed problem of missing page breaks when generating multiple labels
This was caused by some behavior change introduced in dompdf 3.1.1
This fixes issue #1070
2025-10-17 00:21:26 +02:00
Jan Böhmer
07166037b9 New translations security.en.xlf (Polish) 2025-09-25 11:53:55 +02:00
Jan Böhmer
e1418dfdc1 Do not create the filter form in the ajax requests for tables, if it is not needed
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
2025-09-24 18:13:30 +02:00
Jan Böhmer
ab92620f56 Merge remote-tracking branch 'origin/l10n_master' 2025-09-23 23:39:29 +02:00
Jan Böhmer
0a4b873b77 New translations messages.en.xlf (German) 2025-09-23 23:38:41 +02:00
Jan Böhmer
23bafa4471 Bumped version to 2.2.0 2025-09-23 23:38:32 +02:00
Jan Böhmer
436d3df83f
New Crowdin updates (#1050)
* New translations messages.en.xlf (English)

* New translations messages.en.xlf (English)

* New translations messages.en.xlf (German)
2025-09-23 23:34:51 +02:00
Jan Böhmer
37393dd6c9 Revert "Removed more unused translations"
This reverts commit 8c15af3105.
2025-09-23 23:12:31 +02:00
Jan Böhmer
8c15af3105 Removed more unused translations 2025-09-23 23:11:48 +02:00
Jan Böhmer
0ac1d19415 Removed unused translations related to bulk imports 2025-09-23 23:06:30 +02:00
Jan Böhmer
63a33d1057 Fixed deprecations 2025-09-23 20:55:22 +02:00
Jan Böhmer
a9d0caad5f Fixed some deprecations
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
2025-09-23 00:03:04 +02:00
Jan Böhmer
6ed4ad4c8c Use native lazy objects for doctrine when on PHP8.4 2025-09-22 23:52:31 +02:00
Jan Böhmer
71946afd75 Updated dependencies 2025-09-22 22:45:58 +02:00
Jan Böhmer
919bf49ec1 Fix the wrong currency code mouser returns for chinese yuan
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / docker (push) Waiting to run
Docker Image Build (FrankenPHP) / docker (push) Waiting to run
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
This fixes issue #1045
2025-09-22 00:20:52 +02:00
Jan Böhmer
001f2e97ea Do not let phpunit fail on deprecations 2025-09-22 00:12:29 +02:00
Jan Böhmer
d2d5490aab Merge remote-tracking branch 'origin/master' 2025-09-22 00:06:25 +02:00
Jan Böhmer
c788fa99e3 Use an older version of maennchen/zipstream-php which is capable of running on 32-bit systems 2025-09-22 00:06:21 +02:00
Jan Böhmer
34d284b1c4 Do not test against real LCSC provider... 2025-09-22 00:05:49 +02:00
dependabot[bot]
67c736f979
Bump actions/setup-node from 4 to 5 (#1034)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 5.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-21 23:52:02 +02:00
Jan Böhmer
6b1e7b3544 Run phpunit tests with PHP8.5 2025-09-21 23:51:36 +02:00
Jan Böhmer
da30a6657e Use the new LCSC endpoint for batch searches 2025-09-21 23:51:11 +02:00
Jan Böhmer
2e0b5edd95 Merge remote-tracking branch 'origin/master' 2025-09-21 23:43:16 +02:00
Jan Böhmer
1d6f0b403a Moved scoll to see more actions hint into optgroup title 2025-09-21 23:43:10 +02:00
Jan Böhmer
df65f39d5e Fixed phpunit tests 2025-09-21 23:33:56 +02:00
Jan Böhmer
1bfea3c48a Fixed phpstan issues 2025-09-21 23:27:56 +02:00
Jan Böhmer
07db1554c7 Updated dependencies 2025-09-21 23:15:28 +02:00
Jan Böhmer
ed1e51f694 Merge branch 'feature/batch-info-provider-import' 2025-09-21 23:14:09 +02:00
Jan Böhmer
5b71d68179 Added tests for new DTO objects 2025-09-21 23:07:45 +02:00
Jan Böhmer
b94e28a961 Added a bit of documentation about the new features 2025-09-21 22:52:23 +02:00
Jan Böhmer
1d52b7c464 Fixed tests 2025-09-21 21:35:13 +02:00
Jan Böhmer
0d49632b92 Refactored constraints, to reuse existing mechanisms 2025-09-21 20:45:18 +02:00
Jan Böhmer
702e5c8732 Use underscore in route paths instead of hyphens to match the other path styles 2025-09-21 19:58:15 +02:00
Jan Böhmer
d2b605edc0 Imrpoved bulk info provider manage page 2025-09-21 19:54:40 +02:00
Jan Böhmer
4c28871283 Fixed problem of failing researchAllParts
This maybe should be revisited in the future, but for now this fix should work
2025-09-21 19:47:49 +02:00
Jan Böhmer
1d38c50abc Fixed step2 template 2025-09-21 19:30:49 +02:00
Jan Böhmer
710569daaf Fixed phpunit tests 2025-09-21 19:03:29 +02:00
Jan Böhmer
92cd645945 Renamed dto to make their relation to batch searches more clear 2025-09-21 17:49:00 +02:00
Jan Böhmer
16126c4000 Encapsulate the fieldmapping data in the importjob further 2025-09-21 17:41:56 +02:00
Jan Böhmer
eda6deff47 Made classes readonly where possible 2025-09-21 14:25:57 +02:00
Jan Böhmer
27a18bdc1e Doing refactoring to remove remains of arrays 2025-09-21 14:24:34 +02:00
Jan Böhmer
98b62cc81e Do not autowire bulkImport parameters globally 2025-09-20 14:33:16 +02:00
barisgit
2c195d9767 Refactor bulk info provider: replace complex arrays with DTOs
- Add BulkSearchResponseDTO, FieldMappingDTO for type safety
- Use composition instead of inheritance in BulkSearchResultDTO
- Remove unnecessary BulkSearchRequestDTO
- Fix N+1 queries and API error handling
- Fix Add Mapping button functionality
2025-09-19 16:28:40 +02:00
Jan Böhmer
bb49c67108 Removed Microsoft X-XSS-Protection header, as it is not recommended on modern browsers anymore and is considered deprecated 2025-09-19 09:18:49 +02:00
Jan Böhmer
f0dc80aac9
New Crowdin updates (#1036)
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
* New translations messages.en.xlf (German)

* New translations validators.en.xlf (German)

* New translations messages.en.xlf (German)

* New translations security.en.xlf (German)

* New translations validators.en.xlf (Dutch)

* New translations messages.en.xlf (German)

* New translations messages.en.xlf (German)

* New translations security.en.xlf (German)

* New translations messages.en.xlf (German)
2025-09-19 09:12:47 +02:00
Jan Böhmer
8998b006e0 Added some type hints for arrays 2025-09-14 23:17:43 +02:00
Jan Böhmer
b4b758c356 Fixed tests 2025-09-14 23:14:00 +02:00
Jan Böhmer
a399b629d1 Use a proper range constraint on the form
Otherwise it is possible to inject invalid data
2025-09-14 23:04:44 +02:00
Jan Böhmer
41a7238ab7 Pass parts object directly to BulkSearchRequestDTO and added some syntax hints 2025-09-14 22:56:12 +02:00
Jan Böhmer
0e99faee0a Moved BulkImportJobStatus enum to own file to make it discoverable by autoloading 2025-09-14 22:23:07 +02:00
Jan Böhmer
13e75808f8 Use validateJobAccess where applicable and ensure permissions for all controller endpoints 2025-09-14 16:24:56 +02:00
Jan Böhmer
1a0fab0615 Use a deterministic method to generate parameter names for filters, to allow for proper caching of queries
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / docker (push) Has been cancelled
Docker Image Build (FrankenPHP) / docker (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
2025-09-09 23:05:03 +02:00
barisgit
46d8c86e0c Improved makefile 2025-09-09 20:57:58 +02:00
barisgit
c7102bcd8c Update bulk info provider test to work with new services approach 2025-09-09 20:54:27 +02:00
barisgit
d6ac16ede0 Refactor bulk import functionality to make controller smaller (use services) add DTOs and use stimulus controllers on frontend 2025-09-09 20:30:27 +02:00
barisgit
65d840c444 Fix invalid flag --memory-limit 2025-09-09 10:31:33 +02:00
Jan Böhmer
52444e05e4 Optimized LCSC batch search calls and extracted it into interface for potential general use in the future 2025-08-31 23:41:16 +02:00
Jan Böhmer
4fcd55748f Use new settings object in LCSCProvider 2025-08-31 23:27:53 +02:00
Jan Böhmer
d57107ed3e Do not use ob_* functions in XSLX exporter, as this affects global state and can lead to sideffects 2025-08-31 23:05:07 +02:00
Jan Böhmer
0c7aa5e92a Fixed phpunit tests 2025-08-31 22:56:10 +02:00
Jan Böhmer
17f123ba8a Fixed logentryRepositoryTest
It seems that this was always wrong, but this was never noticed, because normally the log timestamps are all the same
2025-08-31 22:51:47 +02:00
Jan Böhmer
1156bb52af Added phpoffice dependency 2025-08-31 22:50:56 +02:00
barisgit
71be75b3e7 Improve test coverage 2025-08-31 22:18:25 +02:00
barisgit
5a4f151ca3 Add BulkInfoProviderImportJobPart to element type name generator 2025-08-31 22:18:25 +02:00
barisgit
9729a43f2b Add bulk_info_provider_import_job_part.label 2025-08-31 22:18:24 +02:00
barisgit
4da403569c Increase time limit on batch search and add option to priorities which fields to choose 2025-08-31 22:18:24 +02:00
barisgit
74be016b68 Add abbility to search faster on LCSC without details 2025-08-31 22:18:24 +02:00
barisgit
3896d3d9ab Fix a single failing test 2025-08-31 22:18:24 +02:00
barisgit
ed396765c8 Let symfony manage translations 2025-08-31 22:18:24 +02:00
barisgit
cc9d50a8fe Add makefile to help with development setup, change part_ids in bulk import jobs to junction table and implement filtering based on bulk import jobs status and its associated parts' statuses. 2025-08-31 22:17:05 +02:00
barisgit
9b4d5e9c27 Improve test coverage 2025-08-31 22:16:28 +02:00
barisgit
ccb837e4b4 Fix migration error and dto error 2025-08-31 22:16:28 +02:00
barisgit
2bc39e7791 Add tests and fix static errors 2025-08-31 22:16:27 +02:00
barisgit
fa7f3a1da1 Fix tests 2025-08-31 22:16:27 +02:00
barisgit
c91d37d2a4 More sophisticated two-step bulk import from info providers 2025-08-31 22:16:27 +02:00
barisgit
5ab7ac4d4b Move pageSize and table columns filter buttons apart a bit 2025-08-31 22:16:27 +02:00
barisgit
4c8940f9c3 Simple batch processing 2025-08-31 22:16:27 +02:00
barisgit
aa29f10d51 Remove problematic tests 2025-08-31 22:15:58 +02:00
barisgit
78885ec3c5 Add more tests and fix failing ones 2025-08-31 22:15:58 +02:00
barisgit
1fb137e89f Add export functionality to batch select and fix errors 2025-08-31 22:15:58 +02:00
barisgit
facfb37383 Implement excel based import/export 2025-08-31 22:15:58 +02:00
barisgit
c5751b2aa6 Fix timestamp test 2025-08-31 22:13:54 +02:00
barisgit
aa4299041b Update example import csv to schow real capatibilities 2025-08-31 22:13:54 +02:00
barisgit
c27f2246a3 Update part merger to consider rows with same supplier and spn duplicates 2025-08-31 22:13:54 +02:00
330 changed files with 48803 additions and 13660 deletions

4
.env
View file

@ -31,8 +31,7 @@ DATABASE_EMULATE_NATURAL_SORT=0
# General settings
###################################################################################
# The public reachable URL of this Part-DB installation. This is used for generating links in SAML and email templates
# This must end with a slash!
# The public reachable URL of this Part-DB installation. This is used for generating links in SAML and email templates or when no request context is available.
DEFAULT_URI="https://partdb.changeme.invalid/"
###################################################################################
@ -134,4 +133,5 @@ CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
###> symfony/framework-bundle ###
APP_ENV=prod
APP_SECRET=a03498528f5a5fc089273ec9ae5b2849
APP_SHARE_DIR=var/share
###< symfony/framework-bundle ###

View file

@ -22,7 +22,7 @@ jobs:
APP_ENV: prod
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup PHP
uses: shivammathur/setup-php@v2
@ -60,7 +60,7 @@ jobs:
${{ runner.os }}-yarn-
- name: Setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
@ -80,13 +80,13 @@ jobs:
run: zip -r /tmp/partdb_assets.zip public/build/ vendor/
- name: Upload assets artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: Only dependencies and built assets
path: /tmp/partdb_assets.zip
- name: Upload full artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: Full Part-DB including dependencies and built assets
path: /tmp/partdb_with_assets.zip

View file

@ -20,7 +20,7 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
-
name: Docker meta
id: docker_meta

View file

@ -20,7 +20,7 @@ jobs:
steps:
-
name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
-
name: Docker meta
id: docker_meta

View file

@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Setup PHP
uses: shivammathur/setup-php@v2

View file

@ -21,7 +21,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: ['8.2', '8.3', '8.4' ]
php-versions: ['8.2', '8.3', '8.4', '8.5' ]
db-type: [ 'mysql', 'sqlite', 'postgres' ]
env:
@ -46,7 +46,7 @@ jobs:
if: matrix.db-type == 'postgres'
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Setup PHP
uses: shivammathur/setup-php@v2
@ -104,7 +104,7 @@ jobs:
run: composer install --prefer-dist --no-progress
- name: Setup node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'

3
.gitignore vendored
View file

@ -48,3 +48,6 @@ yarn-error.log
###> phpstan/phpstan ###
phpstan.neon
###< phpstan/phpstan ###
.claude/
CLAUDE.md

View file

@ -20,7 +20,7 @@ was translated in other languages (this is possible via the "Other languages" dr
## Project structure
Part-DB uses symfony's recommended [project structure](https://symfony.com/doc/current/best_practices.html).
Interesting folders are:
* `public`: Everything in this directory will be publicy accessible via web. Use this folder to serve static images.
* `public`: Everything in this directory will be publicly accessible via web. Use this folder to serve static images.
* `assets`: The frontend assets are saved here. You can find the javascript and CSS code here.
* `src`: Part-DB's PHP code is saved here. Note that the sub directories are structured by the classes purposes (so use `Controller` Controllers, `Entities` for Database models, etc.)
* `translations`: The translations used in Part-DB are saved here
@ -49,7 +49,7 @@ Part-DB uses GitHub actions to run various tests and checks on the code:
* PHPunit tests run successful
* Config files, translations and templates has valid syntax
* Doctrine schema valid
* No known vulnerable dependecies are used
* No known vulnerable dependencies are used
* Static analysis successful (phpstan with `--level=2`)
Further the code coverage of the PHPunit tests is determined and uploaded to [CodeCov](https://codecov.io/gh/Part-DB/Part-DB-server).

91
Makefile Normal file
View file

@ -0,0 +1,91 @@
# PartDB Makefile for Test Environment Management
.PHONY: help deps-install lint format format-check test coverage pre-commit all test-typecheck \
test-setup test-clean test-db-create test-db-migrate test-cache-clear test-fixtures test-run test-reset \
section-dev dev-setup dev-clean dev-db-create dev-db-migrate dev-cache-clear dev-warmup dev-reset
# Default target
help: ## Show this help
@awk 'BEGIN {FS = ":.*##"}; /^[a-zA-Z0-9][a-zA-Z0-9_-]+:.*##/ {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
# Dependencies
deps-install: ## Install PHP dependencies with unlimited memory
@echo "📦 Installing PHP dependencies..."
COMPOSER_MEMORY_LIMIT=-1 composer install
yarn install
@echo "✅ Dependencies installed"
# Complete test environment setup
test-setup: test-clean test-db-create test-db-migrate test-fixtures ## Complete test setup (clean, create DB, migrate, fixtures)
@echo "✅ Test environment setup complete!"
# Clean test environment
test-clean: ## Clean test cache and database files
@echo "🧹 Cleaning test environment..."
rm -rf var/cache/test
rm -f var/app_test.db
@echo "✅ Test environment cleaned"
# Create test database
test-db-create: ## Create test database (if not exists)
@echo "🗄️ Creating test database..."
-php bin/console doctrine:database:create --if-not-exists --env test || echo "⚠️ Database creation failed (expected for SQLite) - continuing..."
# Run database migrations for test environment
test-db-migrate: ## Run database migrations for test environment
@echo "🔄 Running database migrations..."
COMPOSER_MEMORY_LIMIT=-1 php bin/console doctrine:migrations:migrate -n --env test
# Clear test cache
test-cache-clear: ## Clear test cache
@echo "🗑️ Clearing test cache..."
rm -rf var/cache/test
@echo "✅ Test cache cleared"
# Load test fixtures
test-fixtures: ## Load test fixtures
@echo "📦 Loading test fixtures..."
php bin/console partdb:fixtures:load -n --env test
# Run PHPUnit tests
test-run: ## Run PHPUnit tests
@echo "🧪 Running tests..."
php bin/phpunit
# Quick test reset (clean + migrate + fixtures, skip DB creation)
test-reset: test-cache-clear test-db-migrate test-fixtures
@echo "✅ Test environment reset complete!"
test-typecheck: ## Run static analysis (PHPStan)
@echo "🧪 Running type checks..."
COMPOSER_MEMORY_LIMIT=-1 composer phpstan
# Development helpers
dev-setup: dev-clean dev-db-create dev-db-migrate dev-warmup ## Complete development setup (clean, create DB, migrate, warmup)
@echo "✅ Development environment setup complete!"
dev-clean: ## Clean development cache and database files
@echo "🧹 Cleaning development environment..."
rm -rf var/cache/dev
rm -f var/app_dev.db
@echo "✅ Development environment cleaned"
dev-db-create: ## Create development database (if not exists)
@echo "🗄️ Creating development database..."
-php bin/console doctrine:database:create --if-not-exists --env dev || echo "⚠️ Database creation failed (expected for SQLite) - continuing..."
dev-db-migrate: ## Run database migrations for development environment
@echo "🔄 Running database migrations..."
COMPOSER_MEMORY_LIMIT=-1 php bin/console doctrine:migrations:migrate -n --env dev
dev-cache-clear: ## Clear development cache
@echo "🗑️ Clearing development cache..."
rm -rf var/cache/dev
@echo "✅ Development cache cleared"
dev-warmup: ## Warm up development cache
@echo "🔥 Warming up development cache..."
COMPOSER_MEMORY_LIMIT=-1 php -d memory_limit=1G bin/console cache:warmup --env dev -n
dev-reset: dev-cache-clear dev-db-migrate ## Quick development reset (cache clear + migrate)
@echo "✅ Development environment reset complete!"

View file

@ -29,8 +29,8 @@ If you want to test Part-DB without installing it, you can use [this](https://de
You can log in with username: *user* and password: *user*.
Every change to the master branch gets automatically deployed, so it represents the current development progress and is
may not completely stable. Please mind, that the free Heroku instance is used, so it can take some time when loading
Every change to the master branch gets automatically deployed, so it represents the current development progress and
may not be completely stable. Please mind, that the free Heroku instance is used, so it can take some time when loading
the page
for the first time.

View file

@ -1 +1 @@
2.1.2
2.2.1

View file

@ -20,11 +20,12 @@
import {Plugin} from 'ckeditor5';
require('./lang/de.js');
require('./lang/en.js');
import { addListToDropdown, createDropdown } from 'ckeditor5';
import {Collection} from 'ckeditor5';
import {Model} from 'ckeditor5';
import {UIModel} from 'ckeditor5';
export default class PartDBLabelUI extends Plugin {
init() {
@ -151,18 +152,28 @@ const PLACEHOLDERS = [
function getDropdownItemsDefinitions(t) {
const itemDefinitions = new Collection();
let first = true;
for ( const group of PLACEHOLDERS) {
//Add group header
//Skip separator for first group
if (!first) {
itemDefinitions.add({
'type': 'separator',
model: new Model( {
model: new UIModel( {
withText: true,
})
});
} else {
first = false;
}
itemDefinitions.add({
type: 'button',
model: new Model( {
model: new UIModel( {
label: t(group.label),
withText: true,
isEnabled: false,
@ -173,7 +184,7 @@ function getDropdownItemsDefinitions(t) {
for ( const entry of group.entries) {
const definition = {
type: 'button',
model: new Model( {
model: new UIModel( {
commandParam: entry[0],
label: t(entry[1]),
tooltip: entry[0],

View file

@ -17,15 +17,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// Make sure that the global object is defined. If not, define it.
window.CKEDITOR_TRANSLATIONS = window.CKEDITOR_TRANSLATIONS || {};
import {add} from "ckeditor5";
// Make sure that the dictionary for Polish translations exist.
window.CKEDITOR_TRANSLATIONS[ 'de' ] = window.CKEDITOR_TRANSLATIONS[ 'de' ] || {};
window.CKEDITOR_TRANSLATIONS[ 'de' ].dictionary = window.CKEDITOR_TRANSLATIONS[ 'de' ].dictionary || {};
// Extend the dictionary for Polish translations with your translations:
Object.assign( window.CKEDITOR_TRANSLATIONS[ 'de' ].dictionary, {
add( "de", {
'Label Placeholder': 'Label Platzhalter',
'Part': 'Bauteil',
@ -88,5 +82,4 @@ Object.assign( window.CKEDITOR_TRANSLATIONS[ 'de' ].dictionary, {
'Instance name': 'Instanzname',
'Target type': 'Zieltyp',
'URL of this Part-DB instance': 'URL dieser Part-DB Instanz',
});

View file

@ -0,0 +1,84 @@
/*
* 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/>.
*/
import {add} from "ckeditor5";
add( "en", {
'Label Placeholder': 'Label placeholder',
'Part': 'Part',
'Database ID': 'Database ID',
'Part name': 'Part name',
'Category': 'Category',
'Category (Full path)': 'Category (full path)',
'Manufacturer': 'Manufacturer',
'Manufacturer (Full path)': 'Manufacturer (full path)',
'Footprint': 'Footprint',
'Footprint (Full path)': 'Footprint (full path)',
'Mass': 'Mass',
'Manufacturer Product Number (MPN)': 'Manufacturer Product Number (MPN)',
'Internal Part Number (IPN)': 'Internal Part Number (IPN)',
'Tags': 'Tags',
'Manufacturing status': 'Manufacturing status',
'Description': 'Description',
'Description (plain text)': 'Description (plain text)',
'Comment': 'Comment',
'Comment (plain text)': 'Comment (plain text)',
'Last modified datetime': 'Last modified datetime',
'Creation datetime': 'Creation datetime',
'IPN as QR code': 'IPN as QR code',
'IPN as Code 128 barcode': 'IPN as Code 128 barcode',
'IPN as Code 39 barcode': 'IPN as Code 39 barcode',
'Lot ID': 'Lot ID',
'Lot name': 'Lot name',
'Lot comment': 'Lot comment',
'Lot expiration date': 'Lot expiration date',
'Lot amount': 'Lot amount',
'Storage location': 'Storage location',
'Storage location (Full path)': 'Storage location (full path)',
'Full name of the lot owner': 'Full name of the lot owner',
'Username of the lot owner': 'Username of the lot owner',
'Barcodes': 'Barcodes',
'Content of the 1D barcodes (like Code 39)': 'Content of the 1D barcodes (like Code 39)',
'Content of the 2D barcodes (QR codes)': 'Content of the 2D barcodes (QR codes)',
'QR code linking to this element': 'QR code linking to this element',
'Code 128 barcode linking to this element': 'Code 128 barcode linking to this element',
'Code 39 barcode linking to this element': 'Code 39 barcode linking to this element',
'Code 93 barcode linking to this element': 'Code 93 barcode linking to this element',
'Datamatrix code linking to this element': 'Datamatrix code linking to this element',
'Location ID': 'Location ID',
'Name': 'Name',
'Full path': 'Full path',
'Parent name': 'Parent name',
'Parent full path': 'Parent full path',
'Full name of the location owner': 'Full name of the location owner',
'Username of the location owner': 'Username of the location owner',
'Username': 'Username',
'Username (including name)': 'Username (including name)',
'Current datetime': 'Current datetime',
'Current date': 'Current date',
'Current time': 'Current time',
'Instance name': 'Instance name',
'Target type': 'Target type',
'URL of this Part-DB instance': 'URL of this Part-DB instance',
} );

View file

@ -0,0 +1,359 @@
import { Controller } from "@hotwired/stimulus"
import { generateCsrfHeaders } from "./csrf_protection_controller"
export default class extends Controller {
static targets = ["progressBar", "progressText"]
static values = {
jobId: Number,
partId: Number,
researchUrl: String,
researchAllUrl: String,
markCompletedUrl: String,
markSkippedUrl: String,
markPendingUrl: String
}
connect() {
// Auto-refresh progress if job is in progress
if (this.hasProgressBarTarget) {
this.startProgressUpdates()
}
// Restore scroll position after page reload (if any)
this.restoreScrollPosition()
}
getHeaders() {
const headers = {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
// Add CSRF headers if available
const form = document.querySelector('form')
if (form) {
const csrfHeaders = generateCsrfHeaders(form)
Object.assign(headers, csrfHeaders)
}
return headers
}
async fetchWithErrorHandling(url, options = {}, timeout = 30000) {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), timeout)
try {
const response = await fetch(url, {
...options,
headers: { ...this.getHeaders(), ...options.headers },
signal: controller.signal
})
clearTimeout(timeoutId)
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Server error (${response.status}): ${errorText}`)
}
return await response.json()
} catch (error) {
clearTimeout(timeoutId)
if (error.name === 'AbortError') {
throw new Error('Request timed out. Please try again.')
} else if (error.message.includes('Failed to fetch')) {
throw new Error('Network error. Please check your connection and try again.')
} else {
throw error
}
}
}
disconnect() {
if (this.progressInterval) {
clearInterval(this.progressInterval)
}
}
startProgressUpdates() {
// Progress updates are handled via page reload for better reliability
// No need for periodic updates since state changes trigger page refresh
}
restoreScrollPosition() {
const savedPosition = sessionStorage.getItem('bulkImportScrollPosition')
if (savedPosition) {
// Restore scroll position after a small delay to ensure page is fully loaded
setTimeout(() => {
window.scrollTo(0, parseInt(savedPosition))
// Clear the saved position so it doesn't interfere with normal navigation
sessionStorage.removeItem('bulkImportScrollPosition')
}, 100)
}
}
async markCompleted(event) {
const partId = event.currentTarget.dataset.partId
try {
const url = this.markCompletedUrlValue.replace('__PART_ID__', partId)
const data = await this.fetchWithErrorHandling(url, { method: 'POST' })
if (data.success) {
this.updateProgressDisplay(data)
this.markRowAsCompleted(partId)
if (data.job_completed) {
this.showJobCompletedMessage()
}
} else {
this.showErrorMessage(data.error || 'Failed to mark part as completed')
}
} catch (error) {
console.error('Error marking part as completed:', error)
this.showErrorMessage(error.message || 'Failed to mark part as completed')
}
}
async markSkipped(event) {
const partId = event.currentTarget.dataset.partId
const reason = prompt('Reason for skipping (optional):') || ''
try {
const url = this.markSkippedUrlValue.replace('__PART_ID__', partId)
const data = await this.fetchWithErrorHandling(url, {
method: 'POST',
body: JSON.stringify({ reason })
})
if (data.success) {
this.updateProgressDisplay(data)
this.markRowAsSkipped(partId)
} else {
this.showErrorMessage(data.error || 'Failed to mark part as skipped')
}
} catch (error) {
console.error('Error marking part as skipped:', error)
this.showErrorMessage(error.message || 'Failed to mark part as skipped')
}
}
async markPending(event) {
const partId = event.currentTarget.dataset.partId
try {
const url = this.markPendingUrlValue.replace('__PART_ID__', partId)
const data = await this.fetchWithErrorHandling(url, { method: 'POST' })
if (data.success) {
this.updateProgressDisplay(data)
this.markRowAsPending(partId)
} else {
this.showErrorMessage(data.error || 'Failed to mark part as pending')
}
} catch (error) {
console.error('Error marking part as pending:', error)
this.showErrorMessage(error.message || 'Failed to mark part as pending')
}
}
updateProgressDisplay(data) {
if (this.hasProgressBarTarget) {
this.progressBarTarget.style.width = `${data.progress}%`
this.progressBarTarget.setAttribute('aria-valuenow', data.progress)
}
if (this.hasProgressTextTarget) {
this.progressTextTarget.textContent = `${data.completed_count} / ${data.total_count} completed`
}
}
markRowAsCompleted(partId) {
// Save scroll position and refresh page to show updated state
sessionStorage.setItem('bulkImportScrollPosition', window.scrollY.toString())
window.location.reload()
}
markRowAsSkipped(partId) {
// Save scroll position and refresh page to show updated state
sessionStorage.setItem('bulkImportScrollPosition', window.scrollY.toString())
window.location.reload()
}
markRowAsPending(partId) {
// Save scroll position and refresh page to show updated state
sessionStorage.setItem('bulkImportScrollPosition', window.scrollY.toString())
window.location.reload()
}
showJobCompletedMessage() {
const alert = document.createElement('div')
alert.className = 'alert alert-success alert-dismissible fade show'
alert.innerHTML = `
<i class="fas fa-check-circle"></i>
Job completed! All parts have been processed.
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`
const container = document.querySelector('.card-body')
container.insertBefore(alert, container.firstChild)
}
async researchPart(event) {
event.preventDefault()
event.stopPropagation()
const partId = event.currentTarget.dataset.partId
const spinner = event.currentTarget.querySelector(`[data-research-spinner="${partId}"]`)
const button = event.currentTarget
// Show loading state
if (spinner) {
spinner.style.display = 'inline-block'
}
button.disabled = true
try {
const url = this.researchUrlValue.replace('__PART_ID__', partId)
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 30000) // 30 second timeout
const response = await fetch(url, {
method: 'POST',
headers: this.getHeaders(),
signal: controller.signal
})
clearTimeout(timeoutId)
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Server error (${response.status}): ${errorText}`)
}
const data = await response.json()
if (data.success) {
this.showSuccessMessage(`Research completed for part. Found ${data.results_count} results.`)
// Save scroll position and reload to show updated results
sessionStorage.setItem('bulkImportScrollPosition', window.scrollY.toString())
window.location.reload()
} else {
this.showErrorMessage(data.error || 'Research failed')
}
} catch (error) {
console.error('Error researching part:', error)
if (error.name === 'AbortError') {
this.showErrorMessage('Research timed out. Please try again.')
} else if (error.message.includes('Failed to fetch')) {
this.showErrorMessage('Network error. Please check your connection and try again.')
} else {
this.showErrorMessage(error.message || 'Research failed due to an unexpected error')
}
} finally {
// Hide loading state
if (spinner) {
spinner.style.display = 'none'
}
button.disabled = false
}
}
async researchAllParts(event) {
event.preventDefault()
event.stopPropagation()
const spinner = document.getElementById('research-all-spinner')
const button = event.currentTarget
// Show loading state
if (spinner) {
spinner.style.display = 'inline-block'
}
button.disabled = true
try {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 120000) // 2 minute timeout for bulk operations
const response = await fetch(this.researchAllUrlValue, {
method: 'POST',
headers: this.getHeaders(),
signal: controller.signal
})
clearTimeout(timeoutId)
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Server error (${response.status}): ${errorText}`)
}
const data = await response.json()
if (data.success) {
this.showSuccessMessage(`Research completed for ${data.researched_count} parts.`)
// Save scroll position and reload to show updated results
sessionStorage.setItem('bulkImportScrollPosition', window.scrollY.toString())
window.location.reload()
} else {
this.showErrorMessage(data.error || 'Bulk research failed')
}
} catch (error) {
console.error('Error researching all parts:', error)
if (error.name === 'AbortError') {
this.showErrorMessage('Bulk research timed out. This may happen with large batches. Please try again or process smaller batches.')
} else if (error.message.includes('Failed to fetch')) {
this.showErrorMessage('Network error. Please check your connection and try again.')
} else {
this.showErrorMessage(error.message || 'Bulk research failed due to an unexpected error')
}
} finally {
// Hide loading state
if (spinner) {
spinner.style.display = 'none'
}
button.disabled = false
}
}
showSuccessMessage(message) {
this.showToast('success', message)
}
showErrorMessage(message) {
this.showToast('error', message)
}
showToast(type, message) {
// Create a simple alert that doesn't disrupt layout
const alertId = 'alert-' + Date.now()
const iconClass = type === 'success' ? 'fa-check-circle' : 'fa-exclamation-triangle'
const alertClass = type === 'success' ? 'alert-success' : 'alert-danger'
const alertHTML = `
<div class="alert ${alertClass} alert-dismissible fade show position-fixed"
style="top: 20px; right: 20px; z-index: 9999; max-width: 400px;"
id="${alertId}">
<i class="fas ${iconClass} me-2"></i>
${message}
<button type="button" class="btn-close" onclick="this.parentElement.remove()" aria-label="Close"></button>
</div>
`
// Add alert to body
document.body.insertAdjacentHTML('beforeend', alertHTML)
// Auto-remove after 5 seconds
setTimeout(() => {
const alertElement = document.getElementById(alertId)
if (alertElement) {
alertElement.remove()
}
}, 5000)
}
}

View file

@ -0,0 +1,92 @@
import { Controller } from "@hotwired/stimulus"
import { generateCsrfHeaders } from "./csrf_protection_controller"
export default class extends Controller {
static values = {
deleteUrl: String,
stopUrl: String,
deleteConfirmMessage: String,
stopConfirmMessage: String
}
connect() {
// Controller initialized
}
getHeaders() {
const headers = {
'X-Requested-With': 'XMLHttpRequest'
}
// Add CSRF headers if available
const form = document.querySelector('form')
if (form) {
const csrfHeaders = generateCsrfHeaders(form)
Object.assign(headers, csrfHeaders)
}
return headers
}
async deleteJob(event) {
const jobId = event.currentTarget.dataset.jobId
const confirmMessage = this.deleteConfirmMessageValue || 'Are you sure you want to delete this job?'
if (confirm(confirmMessage)) {
try {
const deleteUrl = this.deleteUrlValue.replace('__JOB_ID__', jobId)
const response = await fetch(deleteUrl, {
method: 'DELETE',
headers: this.getHeaders()
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`HTTP ${response.status}: ${errorText}`)
}
const data = await response.json()
if (data.success) {
location.reload()
} else {
alert('Error deleting job: ' + (data.error || 'Unknown error'))
}
} catch (error) {
console.error('Error deleting job:', error)
alert('Error deleting job: ' + error.message)
}
}
}
async stopJob(event) {
const jobId = event.currentTarget.dataset.jobId
const confirmMessage = this.stopConfirmMessageValue || 'Are you sure you want to stop this job?'
if (confirm(confirmMessage)) {
try {
const stopUrl = this.stopUrlValue.replace('__JOB_ID__', jobId)
const response = await fetch(stopUrl, {
method: 'POST',
headers: this.getHeaders()
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`HTTP ${response.status}: ${errorText}`)
}
const data = await response.json()
if (data.success) {
location.reload()
} else {
alert('Error stopping job: ' + (data.error || 'Unknown error'))
}
} catch (error) {
console.error('Error stopping job:', error)
alert('Error stopping job: ' + error.message)
}
}
}
}

View file

@ -2,6 +2,8 @@ const nameCheck = /^[-_a-zA-Z0-9]{4,22}$/;
const tokenCheck = /^[-_/+a-zA-Z0-9]{24,}$/;
// Generate and double-submit a CSRF token in a form field and a cookie, as defined by Symfony's SameOriginCsrfTokenManager
// Use `form.requestSubmit()` to ensure that the submit event is triggered. Using `form.submit()` will not trigger the event
// and thus this event-listener will not be executed.
document.addEventListener('submit', function (event) {
generateCsrfToken(event.target);
}, true);
@ -33,8 +35,8 @@ export function generateCsrfToken (formElement) {
if (!csrfCookie && nameCheck.test(csrfToken)) {
csrfField.setAttribute('data-csrf-protection-cookie-value', csrfCookie = csrfToken);
csrfField.defaultValue = csrfToken = btoa(String.fromCharCode.apply(null, (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(18))));
csrfField.dispatchEvent(new Event('change', { bubbles: true }));
}
csrfField.dispatchEvent(new Event('change', { bubbles: true }));
if (csrfCookie && tokenCheck.test(csrfToken)) {
const cookie = csrfCookie + '_' + csrfToken + '=' + csrfCookie + '; path=/; samesite=strict';

View file

@ -34,6 +34,11 @@ export default class extends Controller {
connect() {
let dropdownParent = "body";
if (this.element.closest('.modal')) {
dropdownParent = null
}
let settings = {
persistent: false,
create: true,
@ -42,7 +47,7 @@ export default class extends Controller {
selectOnTab: true,
//This a an ugly solution to disable the delimiter parsing of the TomSelect plugin
delimiter: 'VERY_L0NG_D€LIMITER_WHICH_WILL_NEVER_BE_ENCOUNTERED_IN_A_STRING',
dropdownParent: 'body',
dropdownParent: dropdownParent,
render: {
item: (data, escape) => {
return '<span>' + escape(data.label) + '</span>';

View file

@ -28,6 +28,27 @@ import {EditorWatchdog} from 'ckeditor5';
import "ckeditor5/ckeditor5.css";;
import "../../css/components/ckeditor.css";
const translationContext = require.context(
'ckeditor5/translations',
false,
//Only load the translation files we will really need
/(de|it|fr|ru|ja|cs|da|zh|pl|hu)\.js$/
);
function loadTranslation(language) {
if (!language || language === 'en') {
return null;
}
const lang = language.slice(0, 2);
const path = `./${lang}.js`;
if (translationContext.keys().includes(path)) {
const module = translationContext(path);
return module.default;
} else {
return null;
}
}
/* stimulusFetch: 'lazy' */
export default class extends Controller {
connect() {
@ -63,6 +84,13 @@ export default class extends Controller {
}
}
//Load translations if not english
let translations = loadTranslation(language);
if (translations) {
//Keep existing translations (e.g. from other plugins), if any
config.translations = [window.CKEDITOR_TRANSLATIONS, translations];
}
const watchdog = new EditorWatchdog();
watchdog.setCreator((elementOrData, editorConfig) => {
return EDITOR_TYPE.create(elementOrData, editorConfig)
@ -78,6 +106,15 @@ export default class extends Controller {
editor_div.classList.add(...new_classes.split(","));
}
// Automatic synchronization of source input
editor.model.document.on("change:data", () => {
editor.updateSourceElement();
// Dispatch the input event for further treatment
const event = new Event("input");
this.element.dispatchEvent(event);
});
//This return is important! Otherwise we get mysterious errors in the console
//See: https://github.com/ckeditor/ckeditor5/issues/5897#issuecomment-628471302
return editor;

View file

@ -0,0 +1,250 @@
import { Controller } from "@hotwired/stimulus";
import "../../css/components/autocomplete_bootstrap_theme.css";
export default class extends Controller {
static targets = ["input"];
static values = {
partId: Number,
partCategoryId: Number,
partDescription: String,
suggestions: Object,
commonSectionHeader: String, // Dynamic header for common Prefixes
partIncrementHeader: String, // Dynamic header for new possible part increment
suggestUrl: String,
};
connect() {
this.configureAutocomplete();
this.watchCategoryChanges();
this.watchDescriptionChanges();
}
templates = {
commonSectionHeader({ title, html }) {
return html`
<section class="aa-Source">
<div class="aa-SourceHeader">
<span class="aa-SourceHeaderTitle">${title}</span>
<div class="aa-SourceHeaderLine"></div>
</div>
</section>
`;
},
partIncrementHeader({ title, html }) {
return html`
<section class="aa-Source">
<div class="aa-SourceHeader">
<span class="aa-SourceHeaderTitle">${title}</span>
<div class="aa-SourceHeaderLine"></div>
</div>
</section>
`;
},
list({ html }) {
return html`
<ul class="aa-List" role="listbox"></ul>
`;
},
item({ suggestion, description, html }) {
return html`
<li class="aa-Item" role="option" data-suggestion="${suggestion}" aria-selected="false">
<div class="aa-ItemWrapper">
<div class="aa-ItemContent">
<div class="aa-ItemIcon aa-ItemIcon--noBorder">
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9z"></path>
</svg>
</div>
<div class="aa-ItemContentBody">
<div class="aa-ItemContentTitle">${suggestion}</div>
<div class="aa-ItemContentDescription">${description}</div>
</div>
</div>
</div>
</li>
`;
},
};
configureAutocomplete() {
const inputField = this.inputTarget;
const commonPrefixes = this.suggestionsValue.commonPrefixes || [];
const prefixesPartIncrement = this.suggestionsValue.prefixesPartIncrement || [];
const commonHeader = this.commonSectionHeaderValue;
const partIncrementHeader = this.partIncrementHeaderValue;
if (!inputField || (!commonPrefixes.length && !prefixesPartIncrement.length)) return;
// Check whether the panel should be created at the update
if (this.isPanelInitialized) {
const existingPanel = inputField.parentNode.querySelector(".aa-Panel");
if (existingPanel) {
// Only remove the panel in the update phase
existingPanel.remove();
}
}
// Create panel
const panel = document.createElement("div");
panel.classList.add("aa-Panel");
panel.style.display = "none";
// Create panel layout
const panelLayout = document.createElement("div");
panelLayout.classList.add("aa-PanelLayout", "aa-Panel--scrollable");
// Section for prefixes part increment
if (prefixesPartIncrement.length) {
const partIncrementSection = document.createElement("section");
partIncrementSection.classList.add("aa-Source");
const partIncrementHeaderHtml = this.templates.partIncrementHeader({
title: partIncrementHeader,
html: String.raw,
});
partIncrementSection.innerHTML += partIncrementHeaderHtml;
const partIncrementList = document.createElement("ul");
partIncrementList.classList.add("aa-List");
partIncrementList.setAttribute("role", "listbox");
prefixesPartIncrement.forEach((prefix) => {
const itemHTML = this.templates.item({
suggestion: prefix.title,
description: prefix.description,
html: String.raw,
});
partIncrementList.innerHTML += itemHTML;
});
partIncrementSection.appendChild(partIncrementList);
panelLayout.appendChild(partIncrementSection);
}
// Section for common prefixes
if (commonPrefixes.length) {
const commonSection = document.createElement("section");
commonSection.classList.add("aa-Source");
const commonSectionHeader = this.templates.commonSectionHeader({
title: commonHeader,
html: String.raw,
});
commonSection.innerHTML += commonSectionHeader;
const commonList = document.createElement("ul");
commonList.classList.add("aa-List");
commonList.setAttribute("role", "listbox");
commonPrefixes.forEach((prefix) => {
const itemHTML = this.templates.item({
suggestion: prefix.title,
description: prefix.description,
html: String.raw,
});
commonList.innerHTML += itemHTML;
});
commonSection.appendChild(commonList);
panelLayout.appendChild(commonSection);
}
panel.appendChild(panelLayout);
inputField.parentNode.appendChild(panel);
inputField.addEventListener("focus", () => {
panel.style.display = "block";
});
inputField.addEventListener("blur", () => {
setTimeout(() => {
panel.style.display = "none";
}, 100);
});
// Selection of an item
panelLayout.addEventListener("mousedown", (event) => {
const target = event.target.closest("li");
if (target) {
inputField.value = target.dataset.suggestion;
panel.style.display = "none";
}
});
this.isPanelInitialized = true;
};
watchCategoryChanges() {
const categoryField = document.querySelector('[data-ipn-suggestion="categoryField"]');
const descriptionField = document.querySelector('[data-ipn-suggestion="descriptionField"]');
this.previousCategoryId = Number(this.partCategoryIdValue);
if (categoryField) {
categoryField.addEventListener("change", () => {
const categoryId = Number(categoryField.value);
const description = String(descriptionField?.value ?? '');
// Check whether the category has changed compared to the previous ID
if (categoryId !== this.previousCategoryId) {
this.fetchNewSuggestions(categoryId, description);
this.previousCategoryId = categoryId;
}
});
}
}
watchDescriptionChanges() {
const categoryField = document.querySelector('[data-ipn-suggestion="categoryField"]');
const descriptionField = document.querySelector('[data-ipn-suggestion="descriptionField"]');
this.previousDescription = String(this.partDescriptionValue);
if (descriptionField) {
descriptionField.addEventListener("input", () => {
const categoryId = Number(categoryField.value);
const description = String(descriptionField?.value ?? '');
// Check whether the description has changed compared to the previous one
if (description !== this.previousDescription) {
this.fetchNewSuggestions(categoryId, description);
this.previousDescription = description;
}
});
}
}
fetchNewSuggestions(categoryId, description) {
const baseUrl = this.suggestUrlValue;
const partId = this.partIdValue;
const truncatedDescription = description.length > 150 ? description.substring(0, 150) : description;
const encodedDescription = this.base64EncodeUtf8(truncatedDescription);
const url = `${baseUrl}?partId=${partId}&categoryId=${categoryId}` + (description !== '' ? `&description=${encodedDescription}` : '');
fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
},
})
.then((response) => {
if (!response.ok) {
throw new Error(`Error when calling up the IPN-suggestions: ${response.status}`);
}
return response.json();
})
.then((data) => {
this.suggestionsValue = data;
this.configureAutocomplete();
})
.catch((error) => {
console.error("Errors when loading the new IPN-suggestions:", error);
});
};
base64EncodeUtf8(text) {
const utf8Bytes = new TextEncoder().encode(text);
return btoa(String.fromCharCode(...utf8Bytes));
};
}

View file

@ -10,13 +10,19 @@ export default class extends Controller {
connect() {
//Check if tomselect is inside an modal and do not attach the dropdown to body in that case (as it breaks the modal)
let dropdownParent = "body";
if (this.element.closest('.modal')) {
dropdownParent = null
}
let settings = {
allowEmptyOption: true,
plugins: ['dropdown_input'],
searchField: ["name", "description", "category", "footprint"],
valueField: "id",
labelField: "name",
dropdownParent: 'body',
dropdownParent: dropdownParent,
preload: "focus",
render: {
item: (data, escape) => {

View file

@ -38,13 +38,17 @@ export default class extends Controller {
this._emptyMessage = this.element.getAttribute('title');
}
let dropdownParent = "body";
if (this.element.closest('.modal')) {
dropdownParent = null
}
let settings = {
plugins: ["clear_button"],
allowEmptyOption: true,
selectOnTab: true,
maxOptions: null,
dropdownParent: 'body',
dropdownParent: dropdownParent,
render: {
item: this.renderItem.bind(this),

View file

@ -26,10 +26,15 @@ export default class extends Controller {
_tomSelect;
connect() {
let dropdownParent = "body";
if (this.element.closest('.modal')) {
dropdownParent = null
}
this._tomSelect = new TomSelect(this.element, {
maxItems: 1000,
allowEmptyOption: true,
dropdownParent: 'body',
dropdownParent: dropdownParent,
plugins: ['remove_button'],
});
}

View file

@ -40,6 +40,11 @@ export default class extends Controller {
connect() {
let dropdownParent = "body";
if (this.element.closest('.modal')) {
dropdownParent = null
}
let settings = {
persistent: false,
create: true,
@ -50,7 +55,7 @@ export default class extends Controller {
valueField: 'text',
searchField: 'text',
orderField: 'text',
dropdownParent: 'body',
dropdownParent: dropdownParent,
//This a an ugly solution to disable the delimiter parsing of the TomSelect plugin
delimiter: 'VERY_L0NG_D€LIMITER_WHICH_WILL_NEVER_BE_ENCOUNTERED_IN_A_STRING',

View file

@ -40,7 +40,10 @@ export default class extends Controller {
const allowAdd = this.element.getAttribute("data-allow-add") === "true";
const addHint = this.element.getAttribute("data-add-hint") ?? "";
let dropdownParent = "body";
if (this.element.closest('.modal')) {
dropdownParent = null
}
let settings = {
@ -54,7 +57,7 @@ export default class extends Controller {
maxItems: 1,
delimiter: "$$VERY_LONG_DELIMITER_THAT_SHOULD_NEVER_APPEAR$$",
splitOn: null,
dropdownParent: 'body',
dropdownParent: dropdownParent,
searchField: [
{field: "text", weight : 2},

View file

@ -33,6 +33,11 @@ export default class extends Controller {
_tomSelect;
connect() {
let dropdownParent = "body";
if (this.element.closest('.modal')) {
dropdownParent = null
}
let settings = {
plugins: {
remove_button:{},
@ -43,7 +48,7 @@ export default class extends Controller {
selectOnTab: true,
createOnBlur: true,
create: true,
dropdownParent: 'body',
dropdownParent: dropdownParent,
};
if(this.element.dataset.autocomplete) {

View file

@ -0,0 +1,136 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["tbody", "addButton", "submitButton"]
static values = {
mappingIndex: Number,
maxMappings: Number,
prototype: String,
maxMappingsReachedMessage: String
}
connect() {
this.updateAddButtonState()
this.updateFieldOptions()
this.attachEventListeners()
}
attachEventListeners() {
// Add event listeners to existing field selects
const fieldSelects = this.tbodyTarget.querySelectorAll('select[name*="[field]"]')
fieldSelects.forEach(select => {
select.addEventListener('change', this.updateFieldOptions.bind(this))
})
// Note: Add button click is handled by Stimulus action in template (data-action="click->field-mapping#addMapping")
// No manual event listener needed
// Form submit handler
const form = this.element.querySelector('form')
if (form && this.hasSubmitButtonTarget) {
form.addEventListener('submit', this.handleFormSubmit.bind(this))
}
}
addMapping() {
const currentMappings = this.tbodyTarget.querySelectorAll('.mapping-row').length
if (currentMappings >= this.maxMappingsValue) {
alert(this.maxMappingsReachedMessageValue)
return
}
const newRowHtml = this.prototypeValue.replace(/__name__/g, this.mappingIndexValue)
const tempDiv = document.createElement('div')
tempDiv.innerHTML = newRowHtml
const fieldWidget = tempDiv.querySelector('select[name*="[field]"]') || tempDiv.children[0]
const providerWidget = tempDiv.querySelector('select[name*="[providers]"]') || tempDiv.children[1]
const priorityWidget = tempDiv.querySelector('input[name*="[priority]"]') || tempDiv.children[2]
const newRow = document.createElement('tr')
newRow.className = 'mapping-row'
newRow.innerHTML = `
<td>${fieldWidget ? fieldWidget.outerHTML : ''}</td>
<td>${providerWidget ? providerWidget.outerHTML : ''}</td>
<td>${priorityWidget ? priorityWidget.outerHTML : ''}</td>
<td>
<button type="button" class="btn btn-danger btn-sm" data-action="click->field-mapping#removeMapping">
<i class="fas fa-trash"></i>
</button>
</td>
`
this.tbodyTarget.appendChild(newRow)
this.mappingIndexValue++
const newFieldSelect = newRow.querySelector('select[name*="[field]"]')
if (newFieldSelect) {
newFieldSelect.value = ''
newFieldSelect.addEventListener('change', this.updateFieldOptions.bind(this))
}
this.updateFieldOptions()
this.updateAddButtonState()
}
removeMapping(event) {
const row = event.target.closest('tr')
row.remove()
this.updateFieldOptions()
this.updateAddButtonState()
}
updateFieldOptions() {
const fieldSelects = this.tbodyTarget.querySelectorAll('select[name*="[field]"]')
const selectedFields = Array.from(fieldSelects)
.map(select => select.value)
.filter(value => value && value !== '')
fieldSelects.forEach(select => {
Array.from(select.options).forEach(option => {
const isCurrentValue = option.value === select.value
const isEmptyOption = !option.value || option.value === ''
const isAlreadySelected = selectedFields.includes(option.value)
if (!isEmptyOption && isAlreadySelected && !isCurrentValue) {
option.disabled = true
option.style.display = 'none'
} else {
option.disabled = false
option.style.display = ''
}
})
})
}
updateAddButtonState() {
const currentMappings = this.tbodyTarget.querySelectorAll('.mapping-row').length
if (this.hasAddButtonTarget) {
if (currentMappings >= this.maxMappingsValue) {
this.addButtonTarget.disabled = true
this.addButtonTarget.title = this.maxMappingsReachedMessageValue
} else {
this.addButtonTarget.disabled = false
this.addButtonTarget.title = ''
}
}
}
handleFormSubmit(event) {
if (this.hasSubmitButtonTarget) {
this.submitButtonTarget.disabled = true
// Disable the entire form to prevent changes during processing
const form = event.target
const formElements = form.querySelectorAll('input, select, textarea, button')
formElements.forEach(element => {
if (element !== this.submitButtonTarget) {
element.disabled = true
}
})
}
}
}

View file

@ -0,0 +1,68 @@
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['items'];
static values = {
prototype: String,
prototypeName: { type: String, default: '__name__' },
index: { type: Number, default: 0 },
};
connect() {
if (!this.hasIndexValue || Number.isNaN(this.indexValue)) {
this.indexValue = this.itemsTarget?.children.length || 0;
}
}
add(event) {
event.preventDefault();
const encodedProto = this.prototypeValue || '';
const placeholder = this.prototypeNameValue || '__name__';
if (!encodedProto || !this.itemsTarget) return;
const protoHtml = this._decodeHtmlAttribute(encodedProto);
const idx = this.indexValue;
const html = protoHtml.replace(new RegExp(placeholder, 'g'), String(idx));
const wrapper = document.createElement('div');
wrapper.innerHTML = html;
const newItem = wrapper.firstElementChild;
if (newItem) {
this.itemsTarget.appendChild(newItem);
this.indexValue = idx + 1;
}
}
remove(event) {
event.preventDefault();
const row = event.currentTarget.closest('.tc-item');
if (row) row.remove();
}
_decodeHtmlAttribute(str) {
const tmp = document.createElement('textarea');
tmp.innerHTML = str;
return tmp.value || tmp.textContent || '';
}
}

View file

@ -133,7 +133,7 @@ showing the sidebar (on devices with md or higher)
*/
#sidebar-toggle-button {
position: fixed;
left: 3px;
left: 2px;
bottom: 50%;
}

View file

@ -94,6 +94,11 @@ th.select-checkbox {
display: inline-flex;
}
/** Add spacing between column visibility button and length menu */
.buttons-colvis {
margin-right: 0.2em !important;
}
/** Fix datatables select-checkbox position */
table.dataTable tr.selected td.select-checkbox:after
{

View file

@ -28,7 +28,7 @@ import '../css/app/treeview.css';
import '../css/app/images.css';
// start the Stimulus application
import '../bootstrap';
import '../stimulus_bootstrap';
// Need jQuery? Install it with "yarn add jquery", then uncomment to require it.
const $ = require('jquery');

View file

@ -1,23 +1,4 @@
#!/usr/bin/env php
<?php
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
if (is_file(dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit')) {
if (PHP_VERSION_ID >= 80000) {
require dirname(__DIR__).'/vendor/phpunit/phpunit/phpunit';
} else {
define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__).'/vendor/autoload.php');
require PHPUNIT_COMPOSER_INSTALL;
PHPUnit\TextUI\Command::main();
}
} else {
if (!is_file(dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php')) {
echo "Unable to find the `simple-phpunit.php` script in `vendor/symfony/phpunit-bridge/bin/`.\n";
exit(1);
}
require dirname(__DIR__).'/vendor/symfony/phpunit-bridge/bin/simple-phpunit.php';
}

View file

@ -24,8 +24,7 @@
"doctrine/doctrine-bundle": "^2.0",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^3.2.0",
"dompdf/dompdf": "^v3.0.0",
"part-db/swap-bundle": "^6.0.0",
"dompdf/dompdf": "^3.1.2",
"gregwar/captcha-bundle": "^2.1.0",
"hshn/base64-encoded-file": "^5.0",
"jbtronics/2fa-webauthn": "^3.0.0",
@ -37,6 +36,7 @@
"league/csv": "^9.8.0",
"league/html-to-markdown": "^5.0.1",
"liip/imagine-bundle": "^2.2",
"maennchen/zipstream-php": "2.1",
"nbgrp/onelogin-saml-bundle": "^v2.0.2",
"nelexa/zip": "^4.0",
"nelmio/cors-bundle": "^2.3",
@ -45,8 +45,9 @@
"omines/datatables-bundle": "^0.10.0",
"paragonie/sodium_compat": "^1.21",
"part-db/label-fonts": "^1.0",
"part-db/swap-bundle": "^6.0.0",
"phpoffice/phpspreadsheet": "^5.0.0",
"rhukster/dom-sanitizer": "^1.0",
"runtime/frankenphp-symfony": "^0.2.0",
"s9e/text-formatter": "^2.1",
"scheb/2fa-backup-code": "^v7.11.0",
"scheb/2fa-bundle": "^v7.11.0",
@ -55,36 +56,35 @@
"shivas/versioning-bundle": "^4.0",
"spatie/db-dumper": "^3.3.1",
"symfony/apache-pack": "^1.0",
"symfony/asset": "7.3.*",
"symfony/console": "7.3.*",
"symfony/css-selector": "7.3.*",
"symfony/dom-crawler": "7.3.*",
"symfony/dotenv": "7.3.*",
"symfony/expression-language": "7.3.*",
"symfony/asset": "7.4.*",
"symfony/console": "7.4.*",
"symfony/css-selector": "7.4.*",
"symfony/dom-crawler": "7.4.*",
"symfony/dotenv": "7.4.*",
"symfony/expression-language": "7.4.*",
"symfony/flex": "^v2.3.1",
"symfony/form": "7.3.*",
"symfony/framework-bundle": "7.3.*",
"symfony/http-client": "7.3.*",
"symfony/http-kernel": "7.3.*",
"symfony/mailer": "7.3.*",
"symfony/form": "7.4.*",
"symfony/framework-bundle": "7.4.*",
"symfony/http-client": "7.4.*",
"symfony/http-kernel": "7.4.*",
"symfony/mailer": "7.4.*",
"symfony/monolog-bundle": "^3.1",
"symfony/polyfill-php82": "^1.28",
"symfony/process": "7.3.*",
"symfony/property-access": "7.3.*",
"symfony/property-info": "7.3.*",
"symfony/rate-limiter": "7.3.*",
"symfony/runtime": "7.3.*",
"symfony/security-bundle": "7.3.*",
"symfony/serializer": "7.3.*",
"symfony/string": "7.3.*",
"symfony/translation": "7.3.*",
"symfony/twig-bundle": "7.3.*",
"symfony/process": "7.4.*",
"symfony/property-access": "7.4.*",
"symfony/property-info": "7.4.*",
"symfony/rate-limiter": "7.4.*",
"symfony/runtime": "7.4.*",
"symfony/security-bundle": "7.4.*",
"symfony/serializer": "7.4.*",
"symfony/string": "7.4.*",
"symfony/translation": "7.4.*",
"symfony/twig-bundle": "7.4.*",
"symfony/ux-translator": "^2.10",
"symfony/ux-turbo": "^2.0",
"symfony/validator": "7.3.*",
"symfony/web-link": "7.3.*",
"symfony/validator": "7.4.*",
"symfony/web-link": "7.4.*",
"symfony/webpack-encore-bundle": "^v2.0.1",
"symfony/yaml": "7.3.*",
"symfony/yaml": "7.4.*",
"symplify/easy-coding-standard": "^12.5.20",
"tecnickcom/tc-lib-barcode": "^2.1.4",
"twig/cssinliner-extra": "^3.0",
@ -109,12 +109,19 @@
"phpunit/phpunit": "^11.5.0",
"rector/rector": "^2.0.4",
"roave/security-advisories": "dev-latest",
"symfony/browser-kit": "7.3.*",
"symfony/debug-bundle": "7.3.*",
"symfony/browser-kit": "7.4.*",
"symfony/debug-bundle": "7.4.*",
"symfony/maker-bundle": "^1.13",
"symfony/phpunit-bridge": "7.3.*",
"symfony/stopwatch": "7.3.*",
"symfony/web-profiler-bundle": "7.3.*"
"symfony/phpunit-bridge": "7.4.*",
"symfony/stopwatch": "7.4.*",
"symfony/web-profiler-bundle": "7.4.*"
},
"replace": {
"symfony/polyfill-mbstring": "*",
"symfony/polyfill-php74": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*",
"symfony/polyfill-php82": "*"
},
"suggest": {
"ext-bcmath": "Used to improve price calculation performance",
@ -157,7 +164,7 @@
"post-update-cmd": [
"@auto-scripts"
],
"phpstan": "vendor/bin/phpstan analyse src --level 5 --memory-limit 1G"
"phpstan": "php -d memory_limit=1G vendor/bin/phpstan analyse src --level 5"
},
"conflict": {
"symfony/symfony": "*"
@ -165,7 +172,7 @@
"extra": {
"symfony": {
"allow-contrib": false,
"require": "7.3.*",
"require": "7.4.*",
"docker": true
}
}

4352
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2025 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
/**
* This class extends the default doctrine ORM configuration to enable native lazy objects on PHP 8.4+.
* We have to do this in a PHP file, because the yaml file does not support conditionals on PHP version.
*/
return static function(\Symfony\Config\DoctrineConfig $doctrine) {
//On PHP 8.4+ we can use native lazy objects, which are much more efficient than proxies.
if (PHP_VERSION_ID >= 80400) {
$doctrine->orm()->enableNativeLazyObjects(true);
}
};

View file

@ -10,14 +10,6 @@ when@dev:
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]
# uncomment to get logging in your browser
# you may have to allow bigger header sizes in your Web server configuration
#firephp:
# type: firephp
# level: info
#chromephp:
# type: chromephp
# level: info
console:
type: console
process_psr_3_messages: false
@ -45,6 +37,7 @@ when@prod:
action_level: error
handler: nested
excluded_http_codes: [404, 405]
channels: ["!deprecation"]
buffer_size: 50 # How many messages should be saved? Prevent memory leaks
nested:
type: stream

View file

@ -20,12 +20,6 @@ nelmio_security:
- 'digikey.com'
- 'nexar.com'
# forces Microsoft's XSS-Protection with
# its block mode
xss_protection:
enabled: true
mode_block: true
# Send a full URL in the `Referer` header when performing a same-origin request,
# only send the origin of the document to secure destination (HTTPS->HTTPS),
# and send no header to a less secure destination (HTTPS->HTTP).

View file

@ -1,7 +1,7 @@
framework:
default_locale: 'en'
# Just enable the locales we need for performance reasons.
enabled_locale: '%partdb.locale_menu%'
enabled_locale: ['en', 'de', 'it', 'fr', 'ru', 'ja', 'cs', 'da', 'zh', 'pl']
translator:
default_path: '%kernel.project_dir%/translations'
fallbacks:

View file

@ -1,6 +1,6 @@
twig:
default_path: '%kernel.project_dir%/templates'
form_themes: ['bootstrap_5_horizontal_layout.html.twig', 'form/extended_bootstrap_layout.html.twig', 'form/permission_layout.html.twig', 'form/filter_types_layout.html.twig']
form_themes: ['bootstrap_5_horizontal_layout.html.twig', 'form/extended_bootstrap_layout.html.twig', 'form/permission_layout.html.twig', 'form/filter_types_layout.html.twig', 'form/synonyms_collection.html.twig']
paths:
'%kernel.project_dir%/assets/css': css

View file

@ -8,9 +8,9 @@ parameters:
# This is used as workaround for places where we can not access the settings directly (like the 2FA application names)
partdb.title: '%env(string:settings:customization:instanceName)%' # The title shown inside of Part-DB (e.g. in the navbar and on homepage)
partdb.locale_menu: ['en', 'de', 'it', 'fr', 'ru', 'ja', 'cs', 'da', 'zh', 'pl'] # The languages that are shown in user drop down menu
partdb.locale_menu: ['en', 'de', 'it', 'fr', 'ru', 'ja', 'cs', 'da', 'zh', 'pl', 'hu'] # The languages that are shown in user drop down menu
partdb.default_uri: '%env(string:DEFAULT_URI)%' # The default URI to use for the Part-DB instance (e.g. https://part-db.example.com/). This is used for generating links in emails
partdb.default_uri: '%env(addSlash:string:DEFAULT_URI)%' # The default URI to use for the Part-DB instance (e.g. https://part-db.example.com/). This is used for generating links in emails
partdb.db.emulate_natural_sort: '%env(bool:DATABASE_EMULATE_NATURAL_SORT)%' # If this is set to true, natural sorting is emulated on platforms that do not support it natively. This can be slow on large datasets.
@ -104,3 +104,9 @@ parameters:
env(SAML_ROLE_MAPPING): '{}'
env(DATABASE_EMULATE_NATURAL_SORT): 0
######################################################################################################################
# Bulk Info Provider Import Configuration
######################################################################################################################
partdb.bulk_import.batch_size: 20 # Number of parts to process in each batch during bulk operations
partdb.bulk_import.max_parts_per_operation: 1000 # Maximum number of parts allowed per bulk import operation

View file

@ -18,13 +18,13 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co
parts: # e.g. this maps to perms_parts in User/Group database
group: "data"
label: "perm.parts"
label: "{{part}}"
operations: # Here are all possible operations are listed => the op name is mapped to bit value
read:
label: "perm.read"
# If a part can be read by a user, he can also see all the datastructures (except devices)
alsoSet: ['storelocations.read', 'footprints.read', 'categories.read', 'suppliers.read', 'manufacturers.read',
'currencies.read', 'attachment_types.read', 'measurement_units.read']
'currencies.read', 'attachment_types.read', 'measurement_units.read', 'part_custom_states.read']
apiTokenRole: ROLE_API_READ_ONLY
edit:
label: "perm.edit"
@ -71,7 +71,7 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co
storelocations: &PART_CONTAINING
label: "perm.storelocations"
label: "{{storage_location}}"
group: "data"
operations:
read:
@ -103,35 +103,39 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co
footprints:
<<: *PART_CONTAINING
label: "perm.part.footprints"
label: "{{footprint}}"
categories:
<<: *PART_CONTAINING
label: "perm.part.categories"
label: "{{category}}"
suppliers:
<<: *PART_CONTAINING
label: "perm.part.supplier"
label: "{{supplier}}"
manufacturers:
<<: *PART_CONTAINING
label: "perm.part.manufacturers"
label: "{{manufacturer}}"
projects:
<<: *PART_CONTAINING
label: "perm.projects"
label: "{{project}}"
attachment_types:
<<: *PART_CONTAINING
label: "perm.part.attachment_types"
label: "{{attachment_type}}"
currencies:
<<: *PART_CONTAINING
label: "perm.currencies"
label: "{{currency}}"
measurement_units:
<<: *PART_CONTAINING
label: "perm.measurement_units"
label: "{{measurement_unit}}"
part_custom_states:
<<: *PART_CONTAINING
label: "{{part_custom_state}}"
tools:
label: "perm.part.tools"

2896
config/reference.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,12 @@
# yaml-language-server: $schema=../vendor/symfony/routing/Loader/schema/routing.schema.json
# This file is the entry point to configure the routes of your app.
# Methods with the #[Route] attribute are automatically imported.
# See also https://symfony.com/doc/current/routing.html
# To list all registered routes, run the following command:
# bin/console debug:router
# Redirect every url without an locale to the locale of the user/the global base locale
scan_qr:

View file

@ -1,5 +1,8 @@
# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# See also https://symfony.com/doc/current/service_container/import.html
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
@ -29,6 +32,9 @@ services:
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DataFixtures/'
- '../src/Doctrine/Purger/'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
@ -227,9 +233,15 @@ services:
arguments:
$enforce_index_php: '%env(bool:NO_URL_REWRITE_AVAILABLE)%'
App\Doctrine\Purger\ResetAutoIncrementPurgerFactory:
App\Repository\PartRepository:
arguments:
$translator: '@translator'
tags: ['doctrine.repository_service']
App\EventSubscriber\UserSystem\PartUniqueIpnSubscriber:
tags:
- { name: 'doctrine.fixtures.purger_factory', alias: 'reset_autoincrement_purger' }
- { name: doctrine.event_listener, event: onFlush, connection: default }
# We are needing this service inside a migration, where only the container is injected. So we need to define it as public, to access it from the container.
App\Services\UserSystem\PermissionPresetsHelper:
@ -262,8 +274,21 @@ services:
tags:
- { name: monolog.processor }
when@test:
when@test: &test
services:
App\DataFixtures\:
resource: '../src/DataFixtures/'
autoconfigure: true
autowire: true
App\Doctrine\Purger\:
resource: '../src/Doctrine/Purger/'
App\Doctrine\Purger\ResetAutoIncrementPurgerFactory:
tags:
- { name: 'doctrine.fixtures.purger_factory', alias: 'reset_autoincrement_purger' }
# Decorate the doctrine fixtures load command to use our custom purger by default
doctrine.fixtures_load_command.custom:
decorates: doctrine.fixtures_load_command
@ -272,3 +297,6 @@ when@test:
- '@doctrine.fixtures.loader'
- '@doctrine'
- { default: '@App\Doctrine\Purger\DoNotUsePurgerFactory' }
when@dev:
*test

View file

@ -17,7 +17,7 @@ This allows external applications to interact with Part-DB, extend it or integra
> Some features might be missing or not working yet.
> Also be aware, that there might be security issues in the API, which could allow attackers to access or edit data via
> the API, which
> they normally should be able to access. So currently you should only use the API with trusted users and trusted
> they normally should not be able to access. So currently you should only use the API with trusted users and trusted
> applications.
Part-DB uses [API Platform](https://api-platform.com/) to provide the API, which allows for easy creation of REST APIs
@ -106,11 +106,11 @@ This is a great way to test the API and see how it works, without having to writ
By default, all list endpoints are paginated, which means only a certain number of results is returned per request.
To get another page of the results, you have to use the `page` query parameter, which contains the page number you want
to get (e.g. `/api/categoues/?page=2`).
to get (e.g. `/api/categories/?page=2`).
When using JSONLD, the links to the next page are also included in the `hydra:view` property of the response.
To change the size of the pages (the number of items in a single page) use the `itemsPerPage` query parameter (
e.g. `/api/categoues/?itemsPerPage=50`).
e.g. `/api/categories/?itemsPerPage=50`).
See [API Platform docs](https://api-platform.com/docs/core/pagination) for more infos.

View file

@ -1,4 +1,7 @@
name;description;category;notes;footprint;tags;quantity;storage_location;mass;ipn;mpn;manufacturing_status;manufacturer;supplier;spn;price;favorite;needs_review;minamount;partUnit;manufacturing_status
BC547;NPN transistor;Transistors -> NPN;very important notes;TO -> TO-92;NPN,Transistor;5;Room 1 -> Shelf 1 -> Box 2;10;;;Manufacturer;;You need to fill this line, to use spn and price;BC547C;2,3;0;;;;
BC557;PNP transistor;<b>HTML</b>;;TO -> TO-92;PNP,Transistor;10;Room 2-> Box 3;;Internal1234;;;;;;;;1;;;active
Copper Wire;;Wire;;;;;;;;;;;;;;;;;Meter;
name;description;category;notes;footprint;tags;quantity;storage_location;mass;ipn;mpn;manufacturing_status;manufacturer;supplier;spn;price;favorite;needs_review;minamount;partUnit;eda_info.reference_prefix;eda_info.value;eda_info.visibility;eda_info.exclude_from_bom;eda_info.exclude_from_board;eda_info.exclude_from_sim;eda_info.kicad_symbol;eda_info.kicad_footprint
"MLCC; 0603; 0.22uF";Multilayer ceramic capacitor;Electrical Components->Passive Components->Capacitors_SMD;High quality MLCC;0603;Capacitor,SMD,MLCC,0603;500;Room 1->Shelf 1->Box 2;0.1;CL10B224KO8NNNC;CL10B224KO8NNNC;active;Samsung;LCSC;C160828;0.0023;0;0;1;pcs;C;0.22uF;1;0;0;0;Device:C;Capacitor_SMD:C_0603_1608Metric
"MLCC; 0402; 10pF";Small MLCC for high frequency;Electrical Components->Passive Components->Capacitors_SMD;;0402;Capacitor,SMD,MLCC,0402;500;Room 1->Shelf 1->Box 3;0.05;FCC0402N100J500AT;FCC0402N100J500AT;active;Fenghua;LCSC;C5137557;0.0015;0;0;1;pcs;C;10pF;1;0;0;0;Device:C;Capacitor_SMD:C_0402_1005Metric
"Diode; 1N4148W";Fast switching diode;Electrical Components->Semiconductors->Diodes;Fast recovery time;Diode_SMD:D_SOD-123;Diode,SMD,Schottky;100;Room 2->Box 1;0.2;1N4148W;1N4148W;active;Vishay;LCSC;C917030;0.008;0;0;1;pcs;D;1N4148W;1;0;0;0;Device:D;Diode_SMD:D_SOD-123
BC547;NPN transistor;Transistors->NPN;very important notes;TO->TO-92;NPN,Transistor;5;Room 1->Shelf 1->Box 2;10;BC547;BC547;active;Generic;LCSC;BC547C;2.3;0;0;1;pcs;Q;BC547;1;0;0;0;Device:Q_NPN_EBC;TO_SOT_Packages_SMD:TO-92_HandSolder
BC557;PNP transistor;Transistors->PNP;PNP complement to BC547;TO->TO-92;PNP,Transistor;10;Room 2->Box 3;10;BC557;BC557;active;Generic;LCSC;BC557C;2.1;0;0;1;pcs;Q;BC557;1;0;0;0;Device:Q_PNP_EBC;TO_SOT_Packages_SMD:TO-92_HandSolder
Copper Wire;Bare copper wire;Wire->Copper;For prototyping;Wire;Wire,Copper;50;Room 3->Spool Rack;0.5;CW-22AWG;CW-22AWG;active;Generic;Local Supplier;LS-CW-22;0.15;0;0;1;Meter;W;22AWG;1;0;0;0;Device:Wire;Connector_PinHeader_2.54mm:PinHeader_1x01_P2.54mm_Vertical

1 name description category notes footprint tags quantity storage_location mass ipn mpn manufacturing_status manufacturer supplier spn price favorite needs_review minamount partUnit manufacturing_status eda_info.reference_prefix eda_info.value eda_info.visibility eda_info.exclude_from_bom eda_info.exclude_from_board eda_info.exclude_from_sim eda_info.kicad_symbol eda_info.kicad_footprint
2 BC547 MLCC; 0603; 0.22uF NPN transistor Multilayer ceramic capacitor Transistors -> NPN Electrical Components->Passive Components->Capacitors_SMD very important notes High quality MLCC TO -> TO-92 0603 NPN,Transistor Capacitor,SMD,MLCC,0603 5 500 Room 1 -> Shelf 1 -> Box 2 Room 1->Shelf 1->Box 2 10 0.1 CL10B224KO8NNNC CL10B224KO8NNNC Manufacturer active Samsung You need to fill this line, to use spn and price LCSC BC547C C160828 2,3 0.0023 0 0 1 pcs C 0.22uF 1 0 0 0 Device:C Capacitor_SMD:C_0603_1608Metric
3 BC557 MLCC; 0402; 10pF PNP transistor Small MLCC for high frequency <b>HTML</b> Electrical Components->Passive Components->Capacitors_SMD TO -> TO-92 0402 PNP,Transistor Capacitor,SMD,MLCC,0402 10 500 Room 2-> Box 3 Room 1->Shelf 1->Box 3 0.05 Internal1234 FCC0402N100J500AT FCC0402N100J500AT active Fenghua LCSC C5137557 0.0015 0 1 0 1 pcs active C 10pF 1 0 0 0 Device:C Capacitor_SMD:C_0402_1005Metric
4 Copper Wire Diode; 1N4148W Fast switching diode Wire Electrical Components->Semiconductors->Diodes Fast recovery time Diode_SMD:D_SOD-123 Diode,SMD,Schottky 100 Room 2->Box 1 0.2 1N4148W 1N4148W active Vishay LCSC C917030 0.008 0 0 1 Meter pcs D 1N4148W 1 0 0 0 Device:D Diode_SMD:D_SOD-123
5 BC547 NPN transistor Transistors->NPN very important notes TO->TO-92 NPN,Transistor 5 Room 1->Shelf 1->Box 2 10 BC547 BC547 active Generic LCSC BC547C 2.3 0 0 1 pcs Q BC547 1 0 0 0 Device:Q_NPN_EBC TO_SOT_Packages_SMD:TO-92_HandSolder
6 BC557 PNP transistor Transistors->PNP PNP complement to BC547 TO->TO-92 PNP,Transistor 10 Room 2->Box 3 10 BC557 BC557 active Generic LCSC BC557C 2.1 0 0 1 pcs Q BC557 1 0 0 0 Device:Q_PNP_EBC TO_SOT_Packages_SMD:TO-92_HandSolder
7 Copper Wire Bare copper wire Wire->Copper For prototyping Wire Wire,Copper 50 Room 3->Spool Rack 0.5 CW-22AWG CW-22AWG active Generic Local Supplier LS-CW-22 0.15 0 0 1 Meter W 22AWG 1 0 0 0 Device:Wire Connector_PinHeader_2.54mm:PinHeader_1x01_P2.54mm_Vertical

View file

@ -28,7 +28,7 @@ A part entity has many fields, which can be used to describe it better. Most of
the comment field or the specifications
* **Category** (Required): The category (see there) to which this part belongs to.
* **Tags**: The list of tags this part belongs to. Tags can be used to group parts logically (similar to the category),
but tags are much less strict and formal (they don't have to be defined forehands) and you can assign multiple tags to
but tags are much less strict and formal (they don't have to be defined beforehand) and you can assign multiple tags to
a part. When clicking on a tag, a list with all parts which have the same tag, is shown.
* **Min Instock**: *Not really implemented yet*. Parts where the total instock is below this value, will show up for
ordering.

View file

@ -10,7 +10,7 @@ Part-DBs behavior can be configured to your needs. There are different kinds of
user-changeable (changeable dynamically via frontend), options that can be configured by environment variables, and
options that are only configurable via Symfony config files.
## User configruation
## User configuration
The following things can be changed for every user and a user can change it for himself (if he has the correct permission
for it). Configuration is either possible via the user's own settings page (where you can also change the password) or via
@ -43,7 +43,7 @@ options listed, see `.env` file for the full list of possible env variables.
Environment variables allow to overwrite settings in the web interface. This is useful, if you want to enforce certain
settings to be unchangable by users, or if you want to configure settings in a central place in a deployed environment.
On the settings page, you can hover over a setting to see, which environment variable can be used to overwrite it, it
is shown as tooltip. API keys or similar sensitve data which is overwritten by env variables, are redacted on the web
is shown as tooltip. API keys or similar sensitive data which is overwritten by env variables, are redacted on the web
interface, so that even administrators cannot see them (only the last 2 characters and the length).
For technical and security reasons some settings can only be configured via environment variables and not via the web
@ -116,6 +116,16 @@ bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept
value should be handled as confidential data and not shared publicly.
* `SHOW_PART_IMAGE_OVERLAY`: Set to 0 to disable the part image overlay, which appears if you hover over an image in the
part image gallery
* `IPN_SUGGEST_REGEX`: A global regular expression, that part IPNs have to fulfill. Enforce your own format for your users.
* `IPN_SUGGEST_REGEX_HELP`: Define your own user help text for the Regex format specification.
* `IPN_AUTO_APPEND_SUFFIX`: When enabled, an incremental suffix will be added to the user input when entering an existing
* IPN again upon saving.
* `IPN_SUGGEST_PART_DIGITS`: Defines the fixed number of digits used as the increment at the end of an IPN (Internal Part Number).
IPN prefixes, maintained within part categories and their hierarchy, form the foundation for suggesting complete IPNs.
These suggestions become accessible during IPN input of a part. The constant specifies the digits used to calculate and assign
unique increments for parts within a category hierarchy, ensuring consistency and uniqueness in IPN generation.
* `IPN_USE_DUPLICATE_DESCRIPTION`: When enabled, the parts 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.
### E-Mail settings (all env only)
@ -136,7 +146,7 @@ bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept
* `TABLE_PARTS_DEFAULT_COLUMNS`: The columns in parts tables, which are visible by default (when loading table for first
time).
Also specify the default order of the columns. This is a comma separated list of column names. Available columns
are: `name`, `id`, `ipn`, `description`, `category`, `footprint`, `manufacturer`, `storage_location`, `amount`, `minamount`, `partUnit`, `addedDate`, `lastModified`, `needs_review`, `favorite`, `manufacturing_status`, `manufacturer_product_number`, `mass`, `tags`, `attachments`, `edit`.
are: `name`, `id`, `ipn`, `description`, `category`, `footprint`, `manufacturer`, `storage_location`, `amount`, `minamount`, `partUnit`, `partCustomState`, `addedDate`, `lastModified`, `needs_review`, `favorite`, `manufacturing_status`, `manufacturer_product_number`, `mass`, `tags`, `attachments`, `edit`.
### History/Eventlog-related settings

View file

@ -18,8 +18,7 @@ It is installed on a web server and so can be accessed with any browser without
> You can log in with username: **user** and password: **user**, to change/create data.
>
> Every change to the master branch gets automatically deployed, so it represents the current development progress and
> is
> maybe not completely stable. Please mind, that the free Heroku instance is used, so it can take some time when loading
> may not be completely stable. Please mind, that the free Heroku instance is used, so it can take some time when loading
> the page
> for the first time.
@ -53,7 +52,7 @@ It is installed on a web server and so can be accessed with any browser without
KiCad and see available parts from Part-DB directly inside KiCad.
With these features Part-DB is useful to hobbyists, who want to keep track of their private electronic parts inventory,
or makerspaces, where many users have should have (controlled) access to the shared inventory.
or makerspaces, where many users should have (controlled) access to the shared inventory.
Part-DB is also used by small companies and universities for managing their inventory.

View file

@ -38,7 +38,7 @@ you have started creating data**. So you should choose the database type for you
* **Performance**: SQLite is not as fast as MySQL or PostgreSQL, especially when using complex queries or many users.
* **Emulated RegEx search**: SQLite does not support RegEx search natively. Part-DB can emulate it, however that is pretty slow.
* **Emualted natural sorting**: SQLite does not support natural sorting natively. Part-DB can emulate it, but it is pretty slow.
* **Emulated natural sorting**: SQLite does not support natural sorting natively. Part-DB can emulate it, but it is pretty slow.
* **Limitations with Unicode**: SQLite has limitations in comparisons and sorting of Unicode characters, which might lead to
unexpected behavior when using non-ASCII characters in your data. For example `µ` (micro sign) is not seen as equal to
`μ` (greek minuscule mu), therefore searching for `µ` (micro sign) will not find parts containing `μ` (mu) and vice versa.
@ -131,7 +131,7 @@ The host (here 127.0.0.1) and port should also be specified according to your My
In the `serverVersion` parameter you can specify the version of the MySQL/MariaDB server you are using, in the way the server returns it
(e.g. `8.0.37` for MySQL and `10.4.14-MariaDB`). If you do not know it, you can leave the default value.
If you want to use a unix socket for the connection instead of a TCP connnection, you can specify the socket path in the `unix_socket` parameter.
If you want to use a unix socket for the connection instead of a TCP connection, you can specify the socket path in the `unix_socket` parameter.
```shell
DATABASE_URL="mysql://user:password@localhost/database?serverVersion=8.0.37&unix_socket=/var/run/mysqld/mysqld.sock"
```
@ -150,7 +150,7 @@ In the `serverVersion` parameter you can specify the version of the PostgreSQL s
The `charset` parameter specify the character set of the database. It should be set to `utf8` to ensure that all characters are stored correctly.
If you want to use a unix socket for the connection instead of a TCP connnection, you can specify the socket path in the `host` parameter.
If you want to use a unix socket for the connection instead of a TCP connection, you can specify the socket path in the `host` parameter.
```shell
DATABASE_URL="postgresql://db_user@localhost/db_name?serverVersion=16.6&charset=utf8&host=/var/run/postgresql"
```
@ -177,6 +177,6 @@ In natural sorting, it would be sorted as:
Part-DB can sort names in part tables and tree views naturally. PostgreSQL and MariaDB 10.7+ support natural sorting natively,
and it is automatically used if available.
For SQLite and MySQL < 10.7 it has to be emulated if wanted, which is pretty slow. Therefore it has to be explicity enabled by setting the
For SQLite and MySQL < 10.7 it has to be emulated if wanted, which is pretty slow. Therefore it has to be explicitly enabled by setting the
`DATABASE_EMULATE_NATURAL_SORT` environment variable to `1`. If it is 0 the classical binary sorting is used, on these databases. The emulations
might have some quirks and issues, so it is recommended to use a database which supports natural sorting natively, if you want to use it.

View file

@ -19,7 +19,7 @@ automatic mail providers (like MailChimp or SendGrid). If you want to use one of
Mailer documentation for more information.
We will only cover the configuration of an SMTP provider here, which is sufficient for most use-cases.
You will need an email account, which you can use send emails from via password-bases SMTP authentication, this account
You will need an email account, which you can use to send emails from via password-based SMTP authentication, this account
should be dedicated to Part-DB.
To configure the SMTP provider, you have to set the following environment variables:

View file

@ -143,11 +143,11 @@ services:
# - DB_AUTOMIGRATE=true
# You can configure Part-DB using the webUI or environment variables
# However you can add add any other environment configuration you want here
# However you can add any other environment configuration you want here
# See .env file for all available options or https://docs.part-db.de/configuration.html
# Override value if you want to show to show a given text on homepage.
# When this is outcommented the webUI can be used to configure the banner
# Override value if you want to show a given text on homepage.
# When this is commented out the webUI can be used to configure the banner
#- BANNER=This is a test banner<br>with a line break
database:

View file

@ -7,7 +7,7 @@ nav_order: 10
# Nginx
You can also use [nginx](https://www.nginx.com/) as webserver for Part-DB. Setup Part-DB with apache is a bit easier, so
You can also use [nginx](https://www.nginx.com/) as webserver for Part-DB. Setting up Part-DB with Apache is a bit easier, so
this is the method shown in the guides. This guide assumes that you already have a working nginx installation with PHP
configured.

View file

@ -21,7 +21,7 @@ LDAP or Active Directory server.
{: .warning }
> This feature is currently in beta. Please report any bugs you find.
> So far it has only tested with Keycloak, but it should work with any SAML 2.0 compatible identity provider.
> So far it has only been tested with Keycloak, but it should work with any SAML 2.0 compatible identity provider.
This guide will show you how to configure Part-DB with [Keycloak](https://www.keycloak.org/) as the SAML identity
provider, but it should work with any SAML 2.0 compatible identity provider.
@ -75,8 +75,8 @@ the [Keycloak Getting Started Guide](https://www.keycloak.org/docs/latest/gettin
### Configure Part-DB to use SAML
1. Open the `.env.local` file of Part-DB (or the docker-compose.yaml) for edit
2. Set the `SAMLP_SP_PRIVATE_KEY` environment variable to the content of the private key file you downloaded in the
1. Open the `.env.local` file of Part-DB (or the docker-compose.yaml) for editing
2. Set the `SAML_SP_PRIVATE_KEY` environment variable to the content of the private key file you downloaded in the
previous step. It should start with `MIEE` and end with `=`.
3. Set the `SAML_SP_X509_CERT` environment variable to the content of the Certificate field shown in the `Keys` tab of
the SAML client in Keycloak. It should start with `MIIC` and end with `=`.

View file

@ -9,7 +9,7 @@ Sometimes things go wrong and Part-DB shows an error message. This page should h
## Error messages
When a common, easy fixable error occurs (like a non-up-to-date database), Part-DB will show you some short instructions
When a common, easily fixable error occurs (like a non-up-to-date database), Part-DB will show you some short instructions
on how to fix the problem. If you have a problem that is not listed here, please open an issue on GitHub.
## General procedure

View file

@ -27,7 +27,7 @@ about the requirements at all.
## Changes
* Configuration is now preferably done via a web settings interface. You can still use environment variables, these overwrite
the settings in the web interface. Existing configuration will still work, but you should consider migriting them to the
the settings in the web interface. Existing configuration will still work, but you should consider migrating them to the
web interface as described below.
* The `config/banner.md` file that could been used to customize the banner text, was removed. You can now set the banner text
directly in the admin interface, or by setting the `BANNER` environment variable. If you want to keep your existing
@ -43,19 +43,20 @@ The upgrade process works very similar to a normal (minor release) upgrade.
### Direct installation
**Be sure to execute the following steps as the user that owns the Part-DB files (e.g. `www-data`, or your webserver user). So prepend a `sudo -u wwww-data` where necessary.**
**Be sure to execute the following steps as the user that owns the Part-DB files (e.g. `www-data`, or your webserver user). So prepend a `sudo -u www-data` where necessary.**
1. Make a backup of your existing Part-DB installation, including the database, data directories and the configuration files and `.env.local` file.
The `php bin/console partdb:backup` command can help you with this.
2. Pull the v2 version. For git installation you can do this with `git checkout v2.0.0` (or newer version)
3. Run `composer install --no-dev -o` to update the dependencies.
4. Run `yarn install` and `yarn build` to update the frontend assets.
5. Rund `php bin/console doctrine:migrations:migrate` to update the database schema.
6. Clear the cache with `php bin/console cache:clear`.
7. Open your Part-DB instance in the browser and log in as an admin user.
8. Go to the user or group permissions page, and give yourself (and other administrators) the right to change system settings (under "System" and "Configuration").
9. You can now go to the settings page (under "System" and "Settings") and check if all settings are correct.
10. Parameters which were previously set via environment variables are greyed out and cannot be changed in the web interface.
3. Remove the `var/cache/` directory inside the Part-DB installation to ensure that no old cache files remain.
4. Run `composer install --no-dev -o` to update the dependencies.
5. Run `yarn install` and `yarn build` to update the frontend assets.
6. Run `php bin/console doctrine:migrations:migrate` to update the database schema.
7. Clear the cache with `php bin/console cache:clear`.
8. Open your Part-DB instance in the browser and log in as an admin user.
9. Go to the user or group permissions page, and give yourself (and other administrators) the right to change system settings (under "System" and "Configuration").
10. You can now go to the settings page (under "System" and "Settings") and check if all settings are correct.
11. Parameters which were previously set via environment variables are greyed out and cannot be changed in the web interface.
If you want to change them, you must migrate them to the settings interface as described below.
### Docker installation
@ -78,7 +79,7 @@ To change it, you must migrate your environment variable configuration to the ne
For this there is the new console command `settings:migrate-env-to-settings`, which reads in all environment variables used to overwrite
settings and write them to the database, so that you can safely delete them from your environment variable configuration afterwards, without
loosing your configuration.
losing your configuration.
To run the command, execute `php bin/console settings:migrate-env-to-settings --all` as webserver user (or run `docker exec --user=www-data -it partdb php bin/console settings:migrate-env-to-settings --all` for docker containers).
It will list you all environment variables, it found and ask you for confirmation to migrate them. Answer with `yes` to migrate them and hit enter.
@ -87,3 +88,15 @@ After the migration run successfully, the contents of your environment variables
Go through the environment variables listed by the command and remove them from your environment variable configuration (e.g. `.env.local` file or docker compose file), or just comment them out for now.
If you want to keep some environment variables, just leave them as they are, they will still work as before, the migration command only affects the settings stored in the database.
## Troubleshooting
### cache:clear fails: You have requested a non-existent parameter "jbtronics.settings.proxy_dir".
If you receive an error like
```
In App_KernelProdContainer.php line 2839:
You have requested a non-existent parameter "jbtronics.settings.proxy_dir".
```
when running `php bin/console cache:clear` or `composer install`. You have to manually delete the `var/cache/`
directory inside your Part-DB installation and try again.

View file

@ -6,4 +6,4 @@ has_children: true
---
This section provides information on how to upgrade Part-DB to the latest version.
This is intended for major release upgrades, where requirements or things changes significantly.
This is intended for major release upgrades, where requirements or things change significantly.

View file

@ -24,7 +24,7 @@ sections carefully before proceeding to upgrade.
also more sensitive stuff like database migration works via CLI now, so you should have console access on your server.
* Markdown/HTML is now used instead of BBCode for rich text in description and command fields.
It is possible to migrate your existing BBCode to Markdown
via `php bin/console php bin/console partdb:migrations:convert-bbcode`.
via `php bin/console partdb:migrations:convert-bbcode`.
* Server exceptions are not logged into event log anymore. For security reasons (exceptions can contain sensitive
information) exceptions are only logged to server log (by default under './var/log'), so only the server admins can access it.
* Profile labels are now saved in the database (before they were saved in a separate JSON file). **The profiles of legacy

View file

@ -27,7 +27,7 @@ for more info about these options.
## Backup (manual)
3 parts have to be backup-ed: The configuration files, which contain the instance-specific options, the
3 parts have to be backed up: The configuration files, which contain the instance-specific options, the
uploaded files of attachments, and the database containing the most data of Part-DB.
Everything else like thumbnails and cache files, are recreated automatically when needed.
@ -56,7 +56,7 @@ interface (`mysqldump -uBACKUP -pPASSWORD DATABASE`)
## Restore
Install Part-DB as usual as described in the installation section, except for the database creation/migration part. You
have to use the same database type (SQLite or MySQL) as on the backuped server instance.
have to use the same database type (SQLite or MySQL) as on the backed up server instance.
### Restore configuration
@ -71,7 +71,7 @@ Copy the `uploads/` and the `public/media/` folder from your backup into your ne
#### SQLite
Copy the backup-ed `app.db` into the database folder normally `var/app.db` in Part-DB root folder.
Copy the backed up `app.db` into the database folder normally `var/app.db` in Part-DB root folder.
#### MySQL / MariaDB

View file

@ -60,7 +60,7 @@ If you type in a character, you will get an autocomplete list of all symbols and
### Parts and category visibility
Only parts and their categories, on which there is any kind of EDA metadata are defined show up in KiCad. So if you want to see parts in KiCad,
Only parts and their categories on which there is any kind of EDA metadata defined show up in KiCad. So if you want to see parts in KiCad,
you need to define at least a symbol, footprint, reference prefix, or value on a part, category or footprint.
You can use the "Force visibility" checkbox on a part or category to override this behavior and force parts to be visible or hidden in KiCad.

View file

@ -6,7 +6,7 @@ nav_order: 4
# Getting started
After Part-DB you should begin with customizing the settings, and setting up the basic structures.
After Part-DB you should begin with customizing the settings and setting up the basic structures.
Before starting, it's useful to read a bit about the [concepts of Part-DB]({% link concepts.md %}).
1. TOC

View file

@ -49,7 +49,7 @@ You can upload the file that should be imported here and choose various options
review" after the import. This can be useful if you want to review all imported parts before using them.
* **Create unknown data structures**: If this is selected Part-DB will create new data structures (like categories,
manufacturers, etc.) if no data structure(s) with the same name and path already exists. If this is not selected, only
existing data structures will be used and if no matching data strucure is found, the imported parts field will be empty.
existing data structures will be used and if no matching data structure is found, the imported parts field will be empty.
* **Path delimiter**: Part-DB allows you to create/select nested data structures (like categories, manufacturers, etc.)
by using a path (e.g. `Category 1->Category 1.1`, which will select/create the `Category 1.1` whose parent
is `Category 1`). This path is separated by the path delimiter. If you want to use a different path delimiter than the
@ -142,6 +142,9 @@ You can select between the following export formats:
efficiently.
* **YAML** (Yet Another Markup Language): Very similar to JSON
* **XML** (Extensible Markup Language): Good support with nested data structures. Similar use cases as JSON and YAML.
* **Excel**: Similar to CSV, but in a native Excel format. Can be opened in Excel and LibreOffice Calc. Does not support nested
data structures or sub-data (like parameters, attachments, etc.), very well (many columns are generated, as every
possible sub-data is exported as a separate column).
Also, you can select between the following export levels:

View file

@ -68,10 +68,17 @@ If you already have attachment types for images and datasheets and want the info
can
add the alternative names "Datasheet" and "Image" to the alternative names field of the attachment types.
## Bulk import
If you want to update the information of multiple parts, you can use the bulk import system: Go to a part table and select
the parts you want to update. In the bulk actions dropdown select "Bulk info provider import" and click "Apply".
You will be redirected to a page, where you can select how part fields should be mapped to info provider fields, and the
results will be shown.
## Data providers
The system tries to be as flexible as possible, so many different information sources can be used.
Each information source is called am "info provider" and handles the communication with the external source.
Each information source is called an "info provider" and handles the communication with the external source.
The providers are just a driver that handles the communication with the different external sources and converts them
into a common format Part-DB understands.
That way it is pretty easy to create new providers as they just need to do very little work.
@ -150,7 +157,7 @@ again, to establish a new connection.
### TME
The TME provider uses the API of [TME](https://www.tme.eu/) to search for parts and getting shopping information from
The TME provider uses the API of [TME](https://www.tme.eu/) to search for parts and get shopping information from
them.
To use it you have to create an account at TME and get an API key on the [TME API page](https://developers.tme.eu/en/).
You have to generate a new anonymous key there and enter the key and secret in the Part-DB env configuration (see
@ -169,10 +176,10 @@ The following env configuration options are available:
### Farnell / Element14 / Newark
The Farnell provider uses the [Farnell API](https://partner.element14.com/) to search for parts and getting shopping
The Farnell provider uses the [Farnell API](https://partner.element14.com/) to search for parts and get shopping
information from [Farnell](https://www.farnell.com/).
You have to create an account at Farnell and get an API key on the [Farnell API page](https://partner.element14.com/).
Register a new application there (settings does not matter, as long as you select the "Product Search API") and you will
Register a new application there (settings do not matter, as long as you select the "Product Search API") and you will
get an API key.
The following env configuration options are available:
@ -184,7 +191,7 @@ The following env configuration options are available:
### Mouser
The Mouser provider uses the [Mouser API](https://www.mouser.de/api-home/) to search for parts and getting shopping
The Mouser provider uses the [Mouser API](https://www.mouser.de/api-home/) to search for parts and get shopping
information from [Mouser](https://www.mouser.com/).
You have to create an account at Mouser and register for an API key for the Search API on
the [Mouser API page](https://www.mouser.de/api-home/).
@ -219,7 +226,7 @@ An API key is not required, it is enough to enable the provider using the follow
### OEMsecrets
The oemsecrets provider uses the [oemsecrets API](https://www.oemsecrets.com/) to search for parts and getting shopping
The oemsecrets provider uses the [oemsecrets API](https://www.oemsecrets.com/) to search for parts and get shopping
information from them. Similar to octopart it aggregates offers from different distributors.
You can apply for a free API key on the [oemsecrets API page](https://www.oemsecrets.com/api/) and put the key you get

View file

@ -6,7 +6,7 @@ parent: Usage
# Labels
Part-DB support the generation and printing of labels for parts, part lots and storage locations.
Part-DB supports the generation and printing of labels for parts, part lots and storage locations.
You can use the "Tools -> Label generator" menu entry to create labels or click the label generation link on the part.
You can define label templates by creating Label profiles. This way you can create many similar-looking labels with for

View file

@ -88,9 +88,9 @@ the user as "owner" of a part lot. This way, only he is allowed to add or remove
## Update notifications
Part-DB can show you a notification that there is a newer version than currently installed available. The notification
Part-DB can show you a notification that there is a newer version than currently installed. The notification
will be shown on the homepage and the server info page.
It is only be shown to users which has the `Show available Part-DB updates` permission.
It is only shown to users which have the `Show available Part-DB updates` permission.
For the notification to work, Part-DB queries the GitHub API every 2 days to check for new releases. No data is sent to
GitHub besides the metadata required for the connection (so the public IP address of your computer running Part-DB).
@ -98,6 +98,6 @@ If you don't want Part-DB to query the GitHub API, or if your server can not rea
update notifications by setting the `CHECK_FOR_UPDATES` option to `false`.
## Internet access via proxy
If you server running Part-DB does not have direct access to the internet, but has to use a proxy server, you can configure
If your server running Part-DB does not have direct access to the internet, but has to use a proxy server, you can configure
the proxy settings in the `.env.local` file (or docker env config). You can set the `HTTP_PROXY` and `HTTPS_PROXY` environment
variables to the URL of your proxy server. If your proxy server requires authentication, you can include the username and password in the URL.

View file

@ -1,112 +1,91 @@
# PartDB Makefile for Test Environment Management
.PHONY: help test-setup test-clean test-db-create test-db-migrate test-cache-clear test-fixtures test-run dev-setup dev-clean dev-db-create dev-db-migrate dev-cache-clear dev-warmup dev-reset deps-install
.PHONY: help deps-install lint format format-check test coverage pre-commit all test-typecheck \
test-setup test-clean test-db-create test-db-migrate test-cache-clear test-fixtures test-run test-reset \
section-dev dev-setup dev-clean dev-db-create dev-db-migrate dev-cache-clear dev-warmup dev-reset
# Default target
help:
@echo "PartDB Test Environment Management"
@echo "=================================="
@echo ""
@echo "Available targets:"
@echo " deps-install - Install PHP dependencies with unlimited memory"
@echo ""
@echo "Development Environment:"
@echo " dev-setup - Complete development environment setup (clean, create DB, migrate, warmup)"
@echo " dev-clean - Clean development cache and database files"
@echo " dev-db-create - Create development database (if not exists)"
@echo " dev-db-migrate - Run database migrations for development environment"
@echo " dev-cache-clear - Clear development cache"
@echo " dev-warmup - Warm up development cache"
@echo " dev-reset - Quick development reset (clean + migrate)"
@echo ""
@echo "Test Environment:"
@echo " test-setup - Complete test environment setup (clean, create DB, migrate, load fixtures)"
@echo " test-clean - Clean test cache and database files"
@echo " test-db-create - Create test database (if not exists)"
@echo " test-db-migrate - Run database migrations for test environment"
@echo " test-cache-clear- Clear test cache"
@echo " test-fixtures - Load test fixtures"
@echo " test-run - Run PHPUnit tests"
@echo ""
@echo " help - Show this help message"
help: ## Show this help
@awk 'BEGIN {FS = ":.*##"}; /^[a-zA-Z0-9][a-zA-Z0-9_-]+:.*##/ {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
# Install PHP dependencies with unlimited memory
deps-install:
# Dependencies
deps-install: ## Install PHP dependencies with unlimited memory
@echo "📦 Installing PHP dependencies..."
COMPOSER_MEMORY_LIMIT=-1 composer install
yarn install
@echo "✅ Dependencies installed"
# Complete test environment setup
test-setup: deps-install test-clean test-db-create test-db-migrate test-fixtures
test-setup: test-clean test-db-create test-db-migrate test-fixtures ## Complete test setup (clean, create DB, migrate, fixtures)
@echo "✅ Test environment setup complete!"
# Clean test environment
test-clean:
test-clean: ## Clean test cache and database files
@echo "🧹 Cleaning test environment..."
rm -rf var/cache/test
rm -f var/app_test.db
@echo "✅ Test environment cleaned"
# Create test database
test-db-create:
test-db-create: ## Create test database (if not exists)
@echo "🗄️ Creating test database..."
-php bin/console doctrine:database:create --if-not-exists --env test || echo "⚠️ Database creation failed (expected for SQLite) - continuing..."
# Run database migrations for test environment
test-db-migrate:
test-db-migrate: ## Run database migrations for test environment
@echo "🔄 Running database migrations..."
php -d memory_limit=1G bin/console doctrine:migrations:migrate -n --env test
COMPOSER_MEMORY_LIMIT=-1 php bin/console doctrine:migrations:migrate -n --env test
# Clear test cache
test-cache-clear:
test-cache-clear: ## Clear test cache
@echo "🗑️ Clearing test cache..."
rm -rf var/cache/test
@echo "✅ Test cache cleared"
# Load test fixtures
test-fixtures:
test-fixtures: ## Load test fixtures
@echo "📦 Loading test fixtures..."
php bin/console partdb:fixtures:load -n --env test
# Run PHPUnit tests
test-run:
test-run: ## Run PHPUnit tests
@echo "🧪 Running tests..."
php bin/phpunit
test-typecheck:
@echo "🧪 Running type checks..."
COMPOSER_MEMORY_LIMIT=-1 composer phpstan
# Quick test reset (clean + migrate + fixtures, skip DB creation)
test-reset: test-cache-clear test-db-migrate test-fixtures
@echo "✅ Test environment reset complete!"
test-typecheck: ## Run static analysis (PHPStan)
@echo "🧪 Running type checks..."
COMPOSER_MEMORY_LIMIT=-1 composer phpstan
# Development helpers
dev-setup: deps-install dev-clean dev-db-create dev-db-migrate dev-warmup
dev-setup: dev-clean dev-db-create dev-db-migrate dev-warmup ## Complete development setup (clean, create DB, migrate, warmup)
@echo "✅ Development environment setup complete!"
dev-clean:
dev-clean: ## Clean development cache and database files
@echo "🧹 Cleaning development environment..."
rm -rf var/cache/dev
rm -f var/app_dev.db
@echo "✅ Development environment cleaned"
dev-db-create:
dev-db-create: ## Create development database (if not exists)
@echo "🗄️ Creating development database..."
-php bin/console doctrine:database:create --if-not-exists --env dev || echo "⚠️ Database creation failed (expected for SQLite) - continuing..."
dev-db-migrate:
dev-db-migrate: ## Run database migrations for development environment
@echo "🔄 Running database migrations..."
php -d memory_limit=1G bin/console doctrine:migrations:migrate -n --env dev
COMPOSER_MEMORY_LIMIT=-1 php bin/console doctrine:migrations:migrate -n --env dev
dev-cache-clear:
dev-cache-clear: ## Clear development cache
@echo "🗑️ Clearing development cache..."
php -d memory_limit=1G bin/console cache:clear --env dev -n
rm -rf var/cache/dev
@echo "✅ Development cache cleared"
dev-warmup:
dev-warmup: ## Warm up development cache
@echo "🔥 Warming up development cache..."
php -d memory_limit=1G bin/console cache:warmup --env dev -n
COMPOSER_MEMORY_LIMIT=-1 php -d memory_limit=1G bin/console cache:warmup --env dev -n
dev-reset: dev-cache-clear dev-db-migrate
dev-reset: dev-cache-clear dev-db-migrate ## Quick development reset (cache clear + migrate)
@echo "✅ Development environment reset complete!"

View file

@ -0,0 +1,605 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use App\Migration\AbstractMultiPlatformMigration;
use Doctrine\DBAL\Schema\Schema;
final class Version20250321075747 extends AbstractMultiPlatformMigration
{
public function getDescription(): string
{
return 'Create entity table for custom part states and add custom state to parts';
}
public function mySQLUp(Schema $schema): void
{
$this->addSql(<<<'SQL'
CREATE TABLE part_custom_states (
id INT AUTO_INCREMENT NOT NULL,
parent_id INT DEFAULT NULL,
id_preview_attachment INT DEFAULT NULL,
name VARCHAR(255) NOT NULL,
comment LONGTEXT NOT NULL,
not_selectable TINYINT(1) NOT NULL,
alternative_names LONGTEXT DEFAULT NULL,
last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
INDEX IDX_F552745D727ACA70 (parent_id),
INDEX IDX_F552745DEA7100A1 (id_preview_attachment),
INDEX part_custom_state_name (name),
PRIMARY KEY(id)
)
DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci`
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE part_custom_states ADD CONSTRAINT FK_F552745D727ACA70 FOREIGN KEY (parent_id) REFERENCES part_custom_states (id)
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE part_custom_states ADD CONSTRAINT FK_F552745DEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON DELETE SET NULL
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE parts ADD id_part_custom_state INT DEFAULT NULL AFTER id_part_unit
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE parts ADD CONSTRAINT FK_6940A7FEA3ED1215 FOREIGN KEY (id_part_custom_state) REFERENCES part_custom_states (id)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FEA3ED1215 ON parts (id_part_custom_state)
SQL);
}
public function mySQLDown(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE parts DROP FOREIGN KEY FK_6940A7FEA3ED1215
SQL);
$this->addSql(<<<'SQL'
DROP INDEX IDX_6940A7FEA3ED1215 ON parts
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE parts DROP id_part_custom_state
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE part_custom_states DROP FOREIGN KEY FK_F552745D727ACA70
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE part_custom_states DROP FOREIGN KEY FK_F552745DEA7100A1
SQL);
$this->addSql(<<<'SQL'
DROP TABLE part_custom_states
SQL);
}
public function sqLiteUp(Schema $schema): void
{
$this->addSql(<<<'SQL'
CREATE TABLE "part_custom_states" (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
parent_id INTEGER DEFAULT NULL,
id_preview_attachment INTEGER DEFAULT NULL,
name VARCHAR(255) NOT NULL,
comment CLOB NOT NULL,
not_selectable BOOLEAN NOT NULL,
alternative_names CLOB DEFAULT NULL,
last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT FK_F552745D727ACA70 FOREIGN KEY (parent_id) REFERENCES "part_custom_states" (id) NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_F5AF83CFEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE
)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_F552745D727ACA70 ON "part_custom_states" (parent_id)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX part_custom_state_name ON "part_custom_states" (name)
SQL);
$this->addSql(<<<'SQL'
CREATE TEMPORARY TABLE __temp__parts AS
SELECT
id,
id_preview_attachment,
id_category,
id_footprint,
id_part_unit,
id_manufacturer,
order_orderdetails_id,
built_project_id,
datetime_added,
name,
last_modified,
needs_review,
tags,
mass,
description,
comment,
visible,
favorite,
minamount,
manufacturer_product_url,
manufacturer_product_number,
manufacturing_status,
order_quantity,
manual_order,
ipn,
provider_reference_provider_key,
provider_reference_provider_id,
provider_reference_provider_url,
provider_reference_last_updated,
eda_info_reference_prefix,
eda_info_value,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol,
eda_info_kicad_footprint
FROM parts
SQL);
$this->addSql(<<<'SQL'
DROP TABLE parts
SQL);
$this->addSql(<<<'SQL'
CREATE TABLE parts (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
id_preview_attachment INTEGER DEFAULT NULL,
id_category INTEGER NOT NULL,
id_footprint INTEGER DEFAULT NULL,
id_part_unit INTEGER DEFAULT NULL,
id_manufacturer INTEGER DEFAULT NULL,
id_part_custom_state INTEGER DEFAULT NULL,
order_orderdetails_id INTEGER DEFAULT NULL,
built_project_id INTEGER DEFAULT NULL,
datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
name VARCHAR(255) NOT NULL,
last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
needs_review BOOLEAN NOT NULL,
tags CLOB NOT NULL,
mass DOUBLE PRECISION DEFAULT NULL,
description CLOB NOT NULL,
comment CLOB NOT NULL,
visible BOOLEAN NOT NULL,
favorite BOOLEAN NOT NULL,
minamount DOUBLE PRECISION NOT NULL,
manufacturer_product_url CLOB NOT NULL,
manufacturer_product_number VARCHAR(255) NOT NULL,
manufacturing_status VARCHAR(255) DEFAULT NULL,
order_quantity INTEGER NOT NULL,
manual_order BOOLEAN NOT NULL,
ipn VARCHAR(100) DEFAULT NULL,
provider_reference_provider_key VARCHAR(255) DEFAULT NULL,
provider_reference_provider_id VARCHAR(255) DEFAULT NULL,
provider_reference_provider_url VARCHAR(255) DEFAULT NULL,
provider_reference_last_updated DATETIME DEFAULT NULL,
eda_info_reference_prefix VARCHAR(255) DEFAULT NULL,
eda_info_value VARCHAR(255) DEFAULT NULL,
eda_info_invisible BOOLEAN DEFAULT NULL,
eda_info_exclude_from_bom BOOLEAN DEFAULT NULL,
eda_info_exclude_from_board BOOLEAN DEFAULT NULL,
eda_info_exclude_from_sim BOOLEAN DEFAULT NULL,
eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL,
eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL,
CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES categories (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES footprints (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES measurement_units (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES manufacturers (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FEA3ED1215 FOREIGN KEY (id_part_custom_state) REFERENCES "part_custom_states" (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES orderdetails (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE
)
SQL);
$this->addSql(<<<'SQL'
INSERT INTO parts (
id,
id_preview_attachment,
id_category,
id_footprint,
id_part_unit,
id_manufacturer,
order_orderdetails_id,
built_project_id,
datetime_added,
name,
last_modified,
needs_review,
tags,
mass,
description,
comment,
visible,
favorite,
minamount,
manufacturer_product_url,
manufacturer_product_number,
manufacturing_status,
order_quantity,
manual_order,
ipn,
provider_reference_provider_key,
provider_reference_provider_id,
provider_reference_provider_url,
provider_reference_last_updated,
eda_info_reference_prefix,
eda_info_value,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol,
eda_info_kicad_footprint)
SELECT
id,
id_preview_attachment,
id_category,
id_footprint,
id_part_unit,
id_manufacturer,
order_orderdetails_id,
built_project_id,
datetime_added,
name,
last_modified,
needs_review,
tags,
mass,
description,
comment,
visible,
favorite,
minamount,
manufacturer_product_url,
manufacturer_product_number,
manufacturing_status,
order_quantity,
manual_order,
ipn,
provider_reference_provider_key,
provider_reference_provider_id,
provider_reference_provider_url,
provider_reference_last_updated,
eda_info_reference_prefix,
eda_info_value,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol,
eda_info_kicad_footprint
FROM __temp__parts
SQL);
$this->addSql(<<<'SQL'
DROP TABLE __temp__parts
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX parts_idx_name ON parts (name)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX parts_idx_ipn ON parts (ipn)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX parts_idx_datet_name_last_id_needs ON parts (datetime_added, name, last_modified, id, needs_review)
SQL);
$this->addSql(<<<'SQL'
CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON parts (built_project_id)
SQL);
$this->addSql(<<<'SQL'
CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON parts (order_orderdetails_id)
SQL);
$this->addSql(<<<'SQL'
CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON parts (ipn)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FEEA7100A1 ON parts (id_preview_attachment)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FE7E371A10 ON parts (id_footprint)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FE5697F554 ON parts (id_category)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FE2626CEF9 ON parts (id_part_unit)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FE1ECB93AE ON parts (id_manufacturer)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FEA3ED1215 ON parts (id_part_custom_state)
SQL);
}
public function sqLiteDown(Schema $schema): void
{
$this->addSql(<<<'SQL'
CREATE TEMPORARY TABLE __temp__parts AS
SELECT
id,
id_preview_attachment,
id_category,
id_footprint,
id_part_unit,
id_manufacturer,
order_orderdetails_id,
built_project_id,
datetime_added,
name,
last_modified,
needs_review,
tags,
mass,
description,
comment,
visible,
favorite,
minamount,
manufacturer_product_url,
manufacturer_product_number,
manufacturing_status,
order_quantity,
manual_order,
ipn,
provider_reference_provider_key,
provider_reference_provider_id,
provider_reference_provider_url,
provider_reference_last_updated,
eda_info_reference_prefix,
eda_info_value,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol,
eda_info_kicad_footprint
FROM "parts"
SQL);
$this->addSql(<<<'SQL'
DROP TABLE "parts"
SQL);
$this->addSql(<<<'SQL'
CREATE TABLE "parts" (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
id_preview_attachment INTEGER DEFAULT NULL,
id_category INTEGER NOT NULL,
id_footprint INTEGER DEFAULT NULL,
id_part_unit INTEGER DEFAULT NULL,
id_manufacturer INTEGER DEFAULT NULL,
order_orderdetails_id INTEGER DEFAULT NULL,
built_project_id INTEGER DEFAULT NULL,
datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
name VARCHAR(255) NOT NULL,
last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
needs_review BOOLEAN NOT NULL,
tags CLOB NOT NULL,
mass DOUBLE PRECISION DEFAULT NULL,
description CLOB NOT NULL,
comment CLOB NOT NULL,
visible BOOLEAN NOT NULL,
favorite BOOLEAN NOT NULL,
minamount DOUBLE PRECISION NOT NULL,
manufacturer_product_url CLOB NOT NULL,
manufacturer_product_number VARCHAR(255) NOT NULL,
manufacturing_status VARCHAR(255) DEFAULT NULL,
order_quantity INTEGER NOT NULL,
manual_order BOOLEAN NOT NULL,
ipn VARCHAR(100) DEFAULT NULL,
provider_reference_provider_key VARCHAR(255) DEFAULT NULL,
provider_reference_provider_id VARCHAR(255) DEFAULT NULL,
provider_reference_provider_url VARCHAR(255) DEFAULT NULL,
provider_reference_last_updated DATETIME DEFAULT NULL,
eda_info_reference_prefix VARCHAR(255) DEFAULT NULL,
eda_info_value VARCHAR(255) DEFAULT NULL,
eda_info_invisible BOOLEAN DEFAULT NULL,
eda_info_exclude_from_bom BOOLEAN DEFAULT NULL,
eda_info_exclude_from_board BOOLEAN DEFAULT NULL,
eda_info_exclude_from_sim BOOLEAN DEFAULT NULL,
eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL,
eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL,
CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES "categories" (id) NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES "footprints" (id) NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES "manufacturers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES "orderdetails" (id) NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE
)
SQL);
$this->addSql(<<<'SQL'
INSERT INTO "parts" (
id,
id_preview_attachment,
id_category,
id_footprint,
id_part_unit,
id_manufacturer,
order_orderdetails_id,
built_project_id,
datetime_added,
name,
last_modified,
needs_review,
tags,
mass,
description,
comment,
visible,
favorite,
minamount,
manufacturer_product_url,
manufacturer_product_number,
manufacturing_status,
order_quantity,
manual_order,
ipn,
provider_reference_provider_key,
provider_reference_provider_id,
provider_reference_provider_url,
provider_reference_last_updated,
eda_info_reference_prefix,
eda_info_value,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol,
eda_info_kicad_footprint
) SELECT
id,
id_preview_attachment,
id_category,
id_footprint,
id_part_unit,
id_manufacturer,
order_orderdetails_id,
built_project_id,
datetime_added,
name,
last_modified,
needs_review,
tags,
mass,
description,
comment,
visible,
favorite,
minamount,
manufacturer_product_url,
manufacturer_product_number,
manufacturing_status,
order_quantity,
manual_order,
ipn,
provider_reference_provider_key,
provider_reference_provider_id,
provider_reference_provider_url,
provider_reference_last_updated,
eda_info_reference_prefix,
eda_info_value,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol,
eda_info_kicad_footprint
FROM __temp__parts
SQL);
$this->addSql(<<<'SQL'
DROP TABLE __temp__parts
SQL);
$this->addSql(<<<'SQL'
CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON "parts" (ipn)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FEEA7100A1 ON "parts" (id_preview_attachment)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FE5697F554 ON "parts" (id_category)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FE7E371A10 ON "parts" (id_footprint)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FE2626CEF9 ON "parts" (id_part_unit)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FE1ECB93AE ON "parts" (id_manufacturer)
SQL);
$this->addSql(<<<'SQL'
CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON "parts" (order_orderdetails_id)
SQL);
$this->addSql(<<<'SQL'
CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON "parts" (built_project_id)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX parts_idx_datet_name_last_id_needs ON "parts" (datetime_added, name, last_modified, id, needs_review)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX parts_idx_name ON "parts" (name)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX parts_idx_ipn ON "parts" (ipn)
SQL);
$this->addSql(<<<'SQL'
DROP TABLE "part_custom_states"
SQL);
}
public function postgreSQLUp(Schema $schema): void
{
$this->addSql(<<<'SQL'
CREATE TABLE "part_custom_states" (
id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
parent_id INT DEFAULT NULL,
id_preview_attachment INT DEFAULT NULL, PRIMARY KEY(id),
name VARCHAR(255) NOT NULL,
comment TEXT NOT NULL,
not_selectable BOOLEAN NOT NULL,
alternative_names TEXT DEFAULT NULL,
last_modified TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
datetime_added TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL
)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_F552745D727ACA70 ON "part_custom_states" (parent_id)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_F552745DEA7100A1 ON "part_custom_states" (id_preview_attachment)
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE "part_custom_states"
ADD CONSTRAINT FK_F552745D727ACA70
FOREIGN KEY (parent_id) REFERENCES "part_custom_states" (id) NOT DEFERRABLE INITIALLY IMMEDIATE
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE "part_custom_states"
ADD CONSTRAINT FK_F552745DEA7100A1
FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE parts ADD id_part_custom_state INT DEFAULT NULL
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE parts ADD CONSTRAINT FK_6940A7FEA3ED1215 FOREIGN KEY (id_part_custom_state) REFERENCES "part_custom_states" (id) NOT DEFERRABLE INITIALLY IMMEDIATE
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_6940A7FEA3ED1215 ON parts (id_part_custom_state)
SQL);
}
public function postgreSQLDown(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE "parts" DROP CONSTRAINT FK_6940A7FEA3ED1215
SQL);
$this->addSql(<<<'SQL'
DROP INDEX IDX_6940A7FEA3ED1215
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE "parts" DROP id_part_custom_state
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE "part_custom_states" DROP CONSTRAINT FK_F552745D727ACA70
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE "part_custom_states" DROP CONSTRAINT FK_F552745DEA7100A1
SQL);
$this->addSql(<<<'SQL'
DROP TABLE "part_custom_states"
SQL);
}
}

View file

@ -0,0 +1,307 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use App\Migration\AbstractMultiPlatformMigration;
use Doctrine\DBAL\Schema\Schema;
final class Version20250325073036 extends AbstractMultiPlatformMigration
{
public function getDescription(): string
{
return 'Add part_ipn_prefix column to categories table and remove unique constraint from parts table';
}
public function mySQLUp(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE categories ADD COLUMN part_ipn_prefix VARCHAR(255) NOT NULL DEFAULT ''
SQL);
}
public function mySQLDown(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE categories DROP part_ipn_prefix
SQL);
}
public function sqLiteUp(Schema $schema): void
{
$this->addSql(<<<'SQL'
CREATE TEMPORARY TABLE __temp__categories AS
SELECT
id,
parent_id,
id_preview_attachment,
partname_hint,
partname_regex,
disable_footprints,
disable_manufacturers,
disable_autodatasheets,
disable_properties,
default_description,
default_comment,
comment,
not_selectable,
name,
last_modified,
datetime_added,
alternative_names,
eda_info_reference_prefix,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol
FROM categories
SQL);
$this->addSql('DROP TABLE categories');
$this->addSql(<<<'SQL'
CREATE TABLE categories (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
parent_id INTEGER DEFAULT NULL,
id_preview_attachment INTEGER DEFAULT NULL,
partname_hint CLOB NOT NULL,
partname_regex CLOB NOT NULL,
part_ipn_prefix VARCHAR(255) DEFAULT '' NOT NULL,
disable_footprints BOOLEAN NOT NULL,
disable_manufacturers BOOLEAN NOT NULL,
disable_autodatasheets BOOLEAN NOT NULL,
disable_properties BOOLEAN NOT NULL,
default_description CLOB NOT NULL,
default_comment CLOB NOT NULL,
comment CLOB NOT NULL,
not_selectable BOOLEAN NOT NULL,
name VARCHAR(255) NOT NULL,
last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
alternative_names CLOB DEFAULT NULL,
eda_info_reference_prefix VARCHAR(255) DEFAULT NULL,
eda_info_invisible BOOLEAN DEFAULT NULL,
eda_info_exclude_from_bom BOOLEAN DEFAULT NULL,
eda_info_exclude_from_board BOOLEAN DEFAULT NULL,
eda_info_exclude_from_sim BOOLEAN DEFAULT NULL,
eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL,
CONSTRAINT FK_3AF34668727ACA70 FOREIGN KEY (parent_id) REFERENCES categories (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_3AF34668EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE
)
SQL);
$this->addSql(<<<'SQL'
INSERT INTO categories (
id,
parent_id,
id_preview_attachment,
partname_hint,
partname_regex,
disable_footprints,
disable_manufacturers,
disable_autodatasheets,
disable_properties,
default_description,
default_comment,
comment,
not_selectable,
name,
last_modified,
datetime_added,
alternative_names,
eda_info_reference_prefix,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol
) SELECT
id,
parent_id,
id_preview_attachment,
partname_hint,
partname_regex,
disable_footprints,
disable_manufacturers,
disable_autodatasheets,
disable_properties,
default_description,
default_comment,
comment,
not_selectable,
name,
last_modified,
datetime_added,
alternative_names,
eda_info_reference_prefix,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol
FROM __temp__categories
SQL);
$this->addSql('DROP TABLE __temp__categories');
$this->addSql(<<<'SQL'
CREATE INDEX IDX_3AF34668727ACA70 ON categories (parent_id)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_3AF34668EA7100A1 ON categories (id_preview_attachment)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX category_idx_name ON categories (name)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX category_idx_parent_name ON categories (parent_id, name)
SQL);
}
public function sqLiteDown(Schema $schema): void
{
$this->addSql(<<<'SQL'
CREATE TEMPORARY TABLE __temp__categories AS
SELECT
id,
parent_id,
id_preview_attachment,
partname_hint,
partname_regex,
disable_footprints,
disable_manufacturers,
disable_autodatasheets,
disable_properties,
default_description,
default_comment,
comment,
not_selectable,
name,
last_modified,
datetime_added,
alternative_names,
eda_info_reference_prefix,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol
FROM categories
SQL);
$this->addSql('DROP TABLE categories');
$this->addSql(<<<'SQL'
CREATE TABLE categories (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
parent_id INTEGER DEFAULT NULL,
id_preview_attachment INTEGER DEFAULT NULL,
partname_hint CLOB NOT NULL,
partname_regex CLOB NOT NULL,
disable_footprints BOOLEAN NOT NULL,
disable_manufacturers BOOLEAN NOT NULL,
disable_autodatasheets BOOLEAN NOT NULL,
disable_properties BOOLEAN NOT NULL,
default_description CLOB NOT NULL,
default_comment CLOB NOT NULL,
comment CLOB NOT NULL,
not_selectable BOOLEAN NOT NULL,
name VARCHAR(255) NOT NULL,
last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
alternative_names CLOB DEFAULT NULL,
eda_info_reference_prefix VARCHAR(255) DEFAULT NULL,
eda_info_invisible BOOLEAN DEFAULT NULL,
eda_info_exclude_from_bom BOOLEAN DEFAULT NULL,
eda_info_exclude_from_board BOOLEAN DEFAULT NULL,
eda_info_exclude_from_sim BOOLEAN DEFAULT NULL,
eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL,
CONSTRAINT FK_3AF34668727ACA70 FOREIGN KEY (parent_id) REFERENCES categories (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_3AF34668EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE
)
SQL);
$this->addSql(<<<'SQL'
INSERT INTO categories (
id,
parent_id,
id_preview_attachment,
partname_hint,
partname_regex,
disable_footprints,
disable_manufacturers,
disable_autodatasheets,
disable_properties,
default_description,
default_comment,
comment,
not_selectable,
name,
last_modified,
datetime_added,
alternative_names,
eda_info_reference_prefix,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol
) SELECT
id,
parent_id,
id_preview_attachment,
partname_hint,
partname_regex,
disable_footprints,
disable_manufacturers,
disable_autodatasheets,
disable_properties,
default_description,
default_comment,
comment,
not_selectable,
name,
last_modified,
datetime_added,
alternative_names,
eda_info_reference_prefix,
eda_info_invisible,
eda_info_exclude_from_bom,
eda_info_exclude_from_board,
eda_info_exclude_from_sim,
eda_info_kicad_symbol
FROM __temp__categories
SQL);
$this->addSql('DROP TABLE __temp__categories');
$this->addSql(<<<'SQL'
CREATE INDEX IDX_3AF34668727ACA70 ON categories (parent_id)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_3AF34668EA7100A1 ON categories (id_preview_attachment)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX category_idx_name ON categories (name)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX category_idx_parent_name ON categories (parent_id, name)
SQL);
}
public function postgreSQLUp(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE categories ADD part_ipn_prefix VARCHAR(255) DEFAULT '' NOT NULL
SQL);
}
public function postgreSQLDown(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE "categories" DROP part_ipn_prefix
SQL);
}
}

View file

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use App\Migration\AbstractMultiPlatformMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250802205143 extends AbstractMultiPlatformMigration
{
public function getDescription(): string
{
return 'Add bulk info provider import jobs and job parts tables';
}
public function mySQLUp(Schema $schema): void
{
$this->addSql('CREATE TABLE bulk_info_provider_import_jobs (id INT AUTO_INCREMENT NOT NULL, name LONGTEXT NOT NULL, field_mappings LONGTEXT NOT NULL, search_results LONGTEXT NOT NULL, status VARCHAR(20) NOT NULL, created_at DATETIME NOT NULL, completed_at DATETIME DEFAULT NULL, prefetch_details TINYINT(1) NOT NULL, created_by_id INT NOT NULL, CONSTRAINT FK_7F58C1EDB03A8386 FOREIGN KEY (created_by_id) REFERENCES `users` (id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB');
$this->addSql('CREATE INDEX IDX_7F58C1EDB03A8386 ON bulk_info_provider_import_jobs (created_by_id)');
$this->addSql('CREATE TABLE bulk_info_provider_import_job_parts (id INT AUTO_INCREMENT NOT NULL, status VARCHAR(20) NOT NULL, reason LONGTEXT DEFAULT NULL, completed_at DATETIME DEFAULT NULL, job_id INT NOT NULL, part_id INT NOT NULL, CONSTRAINT FK_CD93F28FBE04EA9 FOREIGN KEY (job_id) REFERENCES bulk_info_provider_import_jobs (id), CONSTRAINT FK_CD93F28F4CE34BEC FOREIGN KEY (part_id) REFERENCES `parts` (id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB');
$this->addSql('CREATE INDEX IDX_CD93F28FBE04EA9 ON bulk_info_provider_import_job_parts (job_id)');
$this->addSql('CREATE INDEX IDX_CD93F28F4CE34BEC ON bulk_info_provider_import_job_parts (part_id)');
$this->addSql('CREATE UNIQUE INDEX unique_job_part ON bulk_info_provider_import_job_parts (job_id, part_id)');
}
public function mySQLDown(Schema $schema): void
{
$this->addSql('DROP TABLE bulk_info_provider_import_job_parts');
$this->addSql('DROP TABLE bulk_info_provider_import_jobs');
}
public function sqLiteUp(Schema $schema): void
{
$this->addSql('CREATE TABLE bulk_info_provider_import_jobs (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name CLOB NOT NULL, field_mappings CLOB NOT NULL, search_results CLOB NOT NULL, status VARCHAR(20) NOT NULL, created_at DATETIME NOT NULL, completed_at DATETIME DEFAULT NULL, prefetch_details BOOLEAN NOT NULL, created_by_id INTEGER NOT NULL, CONSTRAINT FK_7F58C1EDB03A8386 FOREIGN KEY (created_by_id) REFERENCES "users" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('CREATE INDEX IDX_7F58C1EDB03A8386 ON bulk_info_provider_import_jobs (created_by_id)');
$this->addSql('CREATE TABLE bulk_info_provider_import_job_parts (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, status VARCHAR(20) NOT NULL, reason CLOB DEFAULT NULL, completed_at DATETIME DEFAULT NULL, job_id INTEGER NOT NULL, part_id INTEGER NOT NULL, CONSTRAINT FK_CD93F28FBE04EA9 FOREIGN KEY (job_id) REFERENCES bulk_info_provider_import_jobs (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_CD93F28F4CE34BEC FOREIGN KEY (part_id) REFERENCES "parts" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('CREATE INDEX IDX_CD93F28FBE04EA9 ON bulk_info_provider_import_job_parts (job_id)');
$this->addSql('CREATE INDEX IDX_CD93F28F4CE34BEC ON bulk_info_provider_import_job_parts (part_id)');
$this->addSql('CREATE UNIQUE INDEX unique_job_part ON bulk_info_provider_import_job_parts (job_id, part_id)');
}
public function sqLiteDown(Schema $schema): void
{
$this->addSql('DROP TABLE bulk_info_provider_import_job_parts');
$this->addSql('DROP TABLE bulk_info_provider_import_jobs');
}
public function postgreSQLUp(Schema $schema): void
{
$this->addSql('CREATE TABLE bulk_info_provider_import_jobs (id SERIAL PRIMARY KEY NOT NULL, name TEXT NOT NULL, field_mappings TEXT NOT NULL, search_results TEXT NOT NULL, status VARCHAR(20) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, completed_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, prefetch_details BOOLEAN NOT NULL, created_by_id INT NOT NULL, CONSTRAINT FK_7F58C1EDB03A8386 FOREIGN KEY (created_by_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('CREATE INDEX IDX_7F58C1EDB03A8386 ON bulk_info_provider_import_jobs (created_by_id)');
$this->addSql('CREATE TABLE bulk_info_provider_import_job_parts (id SERIAL PRIMARY KEY NOT NULL, status VARCHAR(20) NOT NULL, reason TEXT DEFAULT NULL, completed_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, job_id INT NOT NULL, part_id INT NOT NULL, CONSTRAINT FK_CD93F28FBE04EA9 FOREIGN KEY (job_id) REFERENCES bulk_info_provider_import_jobs (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_CD93F28F4CE34BEC FOREIGN KEY (part_id) REFERENCES parts (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('CREATE INDEX IDX_CD93F28FBE04EA9 ON bulk_info_provider_import_job_parts (job_id)');
$this->addSql('CREATE INDEX IDX_CD93F28F4CE34BEC ON bulk_info_provider_import_job_parts (part_id)');
$this->addSql('CREATE UNIQUE INDEX unique_job_part ON bulk_info_provider_import_job_parts (job_id, part_id)');
}
public function postgreSQLDown(Schema $schema): void
{
$this->addSql('DROP TABLE bulk_info_provider_import_job_parts');
$this->addSql('DROP TABLE bulk_info_provider_import_jobs');
}
}

View file

@ -0,0 +1,156 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use App\Migration\AbstractMultiPlatformMigration;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20251204215443 extends AbstractMultiPlatformMigration
{
public function getDescription(): string
{
return 'Increase URL field lengths to 2048 characters';
}
public function mySQLUp(Schema $schema): void
{
$this->addSql('ALTER TABLE attachments CHANGE external_path external_path VARCHAR(2048) DEFAULT NULL');
$this->addSql('ALTER TABLE manufacturers CHANGE website website VARCHAR(2048) NOT NULL, CHANGE auto_product_url auto_product_url VARCHAR(2048) NOT NULL');
$this->addSql('ALTER TABLE parts CHANGE provider_reference_provider_url provider_reference_provider_url VARCHAR(2048) DEFAULT NULL');
$this->addSql('ALTER TABLE suppliers CHANGE website website VARCHAR(2048) NOT NULL, CHANGE auto_product_url auto_product_url VARCHAR(2048) NOT NULL');
}
public function mySQLDown(Schema $schema): void
{
$this->addSql('ALTER TABLE `attachments` CHANGE external_path external_path VARCHAR(255) DEFAULT NULL');
$this->addSql('ALTER TABLE `manufacturers` CHANGE website website VARCHAR(255) NOT NULL, CHANGE auto_product_url auto_product_url VARCHAR(255) NOT NULL');
$this->addSql('ALTER TABLE `parts` CHANGE provider_reference_provider_url provider_reference_provider_url VARCHAR(255) DEFAULT NULL');
$this->addSql('ALTER TABLE `suppliers` CHANGE website website VARCHAR(255) NOT NULL, CHANGE auto_product_url auto_product_url VARCHAR(255) NOT NULL');
}
public function sqLiteUp(Schema $schema): void
{
$this->addSql('CREATE TEMPORARY TABLE __temp__attachments AS SELECT id, type_id, original_filename, show_in_table, name, last_modified, datetime_added, class_name, element_id, internal_path, external_path FROM attachments');
$this->addSql('DROP TABLE attachments');
$this->addSql('CREATE TABLE attachments (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, type_id INTEGER NOT NULL, original_filename VARCHAR(255) DEFAULT NULL, show_in_table BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, class_name VARCHAR(255) NOT NULL, element_id INTEGER NOT NULL, internal_path VARCHAR(255) DEFAULT NULL, external_path VARCHAR(2048) DEFAULT NULL, CONSTRAINT FK_47C4FAD6C54C8C93 FOREIGN KEY (type_id) REFERENCES attachment_types (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO attachments (id, type_id, original_filename, show_in_table, name, last_modified, datetime_added, class_name, element_id, internal_path, external_path) SELECT id, type_id, original_filename, show_in_table, name, last_modified, datetime_added, class_name, element_id, internal_path, external_path FROM __temp__attachments');
$this->addSql('DROP TABLE __temp__attachments');
$this->addSql('CREATE INDEX attachment_element_idx ON attachments (class_name, element_id)');
$this->addSql('CREATE INDEX attachment_name_idx ON attachments (name)');
$this->addSql('CREATE INDEX attachments_idx_class_name_id ON attachments (class_name, id)');
$this->addSql('CREATE INDEX attachments_idx_id_element_id_class_name ON attachments (id, element_id, class_name)');
$this->addSql('CREATE INDEX IDX_47C4FAD6C54C8C93 ON attachments (type_id)');
$this->addSql('CREATE INDEX IDX_47C4FAD61F1F2A24 ON attachments (element_id)');
$this->addSql('CREATE TEMPORARY TABLE __temp__manufacturers AS SELECT id, parent_id, id_preview_attachment, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added, alternative_names FROM manufacturers');
$this->addSql('DROP TABLE manufacturers');
$this->addSql('CREATE TABLE manufacturers (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(2048) NOT NULL, auto_product_url VARCHAR(2048) NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, alternative_names CLOB DEFAULT NULL, CONSTRAINT FK_94565B12727ACA70 FOREIGN KEY (parent_id) REFERENCES manufacturers (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_94565B12EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO manufacturers (id, parent_id, id_preview_attachment, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added, alternative_names) SELECT id, parent_id, id_preview_attachment, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added, alternative_names FROM __temp__manufacturers');
$this->addSql('DROP TABLE __temp__manufacturers');
$this->addSql('CREATE INDEX IDX_94565B12EA7100A1 ON manufacturers (id_preview_attachment)');
$this->addSql('CREATE INDEX IDX_94565B12727ACA70 ON manufacturers (parent_id)');
$this->addSql('CREATE INDEX manufacturer_name ON manufacturers (name)');
$this->addSql('CREATE INDEX manufacturer_idx_parent_name ON manufacturers (parent_id, name)');
$this->addSql('CREATE TEMPORARY TABLE __temp__parts AS SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, id_part_custom_state, order_orderdetails_id, built_project_id, datetime_added, name, last_modified, needs_review, tags, mass, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, ipn, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated, eda_info_reference_prefix, eda_info_value, eda_info_invisible, eda_info_exclude_from_bom, eda_info_exclude_from_board, eda_info_exclude_from_sim, eda_info_kicad_symbol, eda_info_kicad_footprint FROM parts');
$this->addSql('DROP TABLE parts');
$this->addSql('CREATE TABLE parts (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_preview_attachment INTEGER DEFAULT NULL, id_category INTEGER NOT NULL, id_footprint INTEGER DEFAULT NULL, id_part_unit INTEGER DEFAULT NULL, id_manufacturer INTEGER DEFAULT NULL, id_part_custom_state INTEGER DEFAULT NULL, order_orderdetails_id INTEGER DEFAULT NULL, built_project_id INTEGER DEFAULT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, needs_review BOOLEAN NOT NULL, tags CLOB NOT NULL, mass DOUBLE PRECISION DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, visible BOOLEAN NOT NULL, favorite BOOLEAN NOT NULL, minamount DOUBLE PRECISION NOT NULL, manufacturer_product_url CLOB NOT NULL, manufacturer_product_number VARCHAR(255) NOT NULL, manufacturing_status VARCHAR(255) DEFAULT NULL, order_quantity INTEGER NOT NULL, manual_order BOOLEAN NOT NULL, ipn VARCHAR(100) DEFAULT NULL, provider_reference_provider_key VARCHAR(255) DEFAULT NULL, provider_reference_provider_id VARCHAR(255) DEFAULT NULL, provider_reference_provider_url VARCHAR(2048) DEFAULT NULL, provider_reference_last_updated DATETIME DEFAULT NULL, eda_info_reference_prefix VARCHAR(255) DEFAULT NULL, eda_info_value VARCHAR(255) DEFAULT NULL, eda_info_invisible BOOLEAN DEFAULT NULL, eda_info_exclude_from_bom BOOLEAN DEFAULT NULL, eda_info_exclude_from_board BOOLEAN DEFAULT NULL, eda_info_exclude_from_sim BOOLEAN DEFAULT NULL, eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL, eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL, CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES categories (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES footprints (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES measurement_units (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES manufacturers (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEA3ED1215 FOREIGN KEY (id_part_custom_state) REFERENCES part_custom_states (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES orderdetails (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO parts (id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, id_part_custom_state, order_orderdetails_id, built_project_id, datetime_added, name, last_modified, needs_review, tags, mass, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, ipn, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated, eda_info_reference_prefix, eda_info_value, eda_info_invisible, eda_info_exclude_from_bom, eda_info_exclude_from_board, eda_info_exclude_from_sim, eda_info_kicad_symbol, eda_info_kicad_footprint) SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, id_part_custom_state, order_orderdetails_id, built_project_id, datetime_added, name, last_modified, needs_review, tags, mass, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, ipn, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated, eda_info_reference_prefix, eda_info_value, eda_info_invisible, eda_info_exclude_from_bom, eda_info_exclude_from_board, eda_info_exclude_from_sim, eda_info_kicad_symbol, eda_info_kicad_footprint FROM __temp__parts');
$this->addSql('DROP TABLE __temp__parts');
$this->addSql('CREATE INDEX IDX_6940A7FEA3ED1215 ON parts (id_part_custom_state)');
$this->addSql('CREATE INDEX IDX_6940A7FE1ECB93AE ON parts (id_manufacturer)');
$this->addSql('CREATE INDEX IDX_6940A7FE2626CEF9 ON parts (id_part_unit)');
$this->addSql('CREATE INDEX IDX_6940A7FE5697F554 ON parts (id_category)');
$this->addSql('CREATE INDEX IDX_6940A7FE7E371A10 ON parts (id_footprint)');
$this->addSql('CREATE INDEX IDX_6940A7FEEA7100A1 ON parts (id_preview_attachment)');
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON parts (ipn)');
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON parts (order_orderdetails_id)');
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON parts (built_project_id)');
$this->addSql('CREATE INDEX parts_idx_datet_name_last_id_needs ON parts (datetime_added, name, last_modified, id, needs_review)');
$this->addSql('CREATE INDEX parts_idx_ipn ON parts (ipn)');
$this->addSql('CREATE INDEX parts_idx_name ON parts (name)');
$this->addSql('CREATE TEMPORARY TABLE __temp__suppliers AS SELECT id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added, alternative_names FROM suppliers');
$this->addSql('DROP TABLE suppliers');
$this->addSql('CREATE TABLE suppliers (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, default_currency_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, shipping_costs NUMERIC(11, 5) DEFAULT NULL, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(2048) NOT NULL, auto_product_url VARCHAR(2048) NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, alternative_names CLOB DEFAULT NULL, CONSTRAINT FK_AC28B95C727ACA70 FOREIGN KEY (parent_id) REFERENCES suppliers (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CECD792C0 FOREIGN KEY (default_currency_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO suppliers (id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added, alternative_names) SELECT id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added, alternative_names FROM __temp__suppliers');
$this->addSql('DROP TABLE __temp__suppliers');
$this->addSql('CREATE INDEX IDX_AC28B95CECD792C0 ON suppliers (default_currency_id)');
$this->addSql('CREATE INDEX IDX_AC28B95C727ACA70 ON suppliers (parent_id)');
$this->addSql('CREATE INDEX supplier_idx_name ON suppliers (name)');
$this->addSql('CREATE INDEX supplier_idx_parent_name ON suppliers (parent_id, name)');
$this->addSql('CREATE INDEX IDX_AC28B95CEA7100A1 ON suppliers (id_preview_attachment)');
}
public function sqLiteDown(Schema $schema): void
{
$this->addSql('CREATE TEMPORARY TABLE __temp__attachments AS SELECT id, name, last_modified, datetime_added, original_filename, internal_path, external_path, show_in_table, type_id, class_name, element_id FROM "attachments"');
$this->addSql('DROP TABLE "attachments"');
$this->addSql('CREATE TABLE "attachments" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, original_filename VARCHAR(255) DEFAULT NULL, internal_path VARCHAR(255) DEFAULT NULL, external_path VARCHAR(255) DEFAULT NULL, show_in_table BOOLEAN NOT NULL, type_id INTEGER NOT NULL, class_name VARCHAR(255) NOT NULL, element_id INTEGER NOT NULL, CONSTRAINT FK_47C4FAD6C54C8C93 FOREIGN KEY (type_id) REFERENCES "attachment_types" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO "attachments" (id, name, last_modified, datetime_added, original_filename, internal_path, external_path, show_in_table, type_id, class_name, element_id) SELECT id, name, last_modified, datetime_added, original_filename, internal_path, external_path, show_in_table, type_id, class_name, element_id FROM __temp__attachments');
$this->addSql('DROP TABLE __temp__attachments');
$this->addSql('CREATE INDEX IDX_47C4FAD6C54C8C93 ON "attachments" (type_id)');
$this->addSql('CREATE INDEX IDX_47C4FAD61F1F2A24 ON "attachments" (element_id)');
$this->addSql('CREATE INDEX attachments_idx_id_element_id_class_name ON "attachments" (id, element_id, class_name)');
$this->addSql('CREATE INDEX attachments_idx_class_name_id ON "attachments" (class_name, id)');
$this->addSql('CREATE INDEX attachment_name_idx ON "attachments" (name)');
$this->addSql('CREATE INDEX attachment_element_idx ON "attachments" (class_name, element_id)');
$this->addSql('CREATE TEMPORARY TABLE __temp__manufacturers AS SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, address, phone_number, fax_number, email_address, website, auto_product_url, parent_id, id_preview_attachment FROM "manufacturers"');
$this->addSql('DROP TABLE "manufacturers"');
$this->addSql('CREATE TABLE "manufacturers" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names CLOB DEFAULT NULL, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(255) NOT NULL, auto_product_url VARCHAR(255) NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, CONSTRAINT FK_94565B12727ACA70 FOREIGN KEY (parent_id) REFERENCES "manufacturers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_94565B12EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO "manufacturers" (id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, address, phone_number, fax_number, email_address, website, auto_product_url, parent_id, id_preview_attachment) SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, address, phone_number, fax_number, email_address, website, auto_product_url, parent_id, id_preview_attachment FROM __temp__manufacturers');
$this->addSql('DROP TABLE __temp__manufacturers');
$this->addSql('CREATE INDEX IDX_94565B12727ACA70 ON "manufacturers" (parent_id)');
$this->addSql('CREATE INDEX IDX_94565B12EA7100A1 ON "manufacturers" (id_preview_attachment)');
$this->addSql('CREATE INDEX manufacturer_name ON "manufacturers" (name)');
$this->addSql('CREATE INDEX manufacturer_idx_parent_name ON "manufacturers" (parent_id, name)');
$this->addSql('CREATE TEMPORARY TABLE __temp__parts AS SELECT id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated, eda_info_reference_prefix, eda_info_value, eda_info_invisible, eda_info_exclude_from_bom, eda_info_exclude_from_board, eda_info_exclude_from_sim, eda_info_kicad_symbol, eda_info_kicad_footprint, id_preview_attachment, id_part_custom_state, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id FROM "parts"');
$this->addSql('DROP TABLE "parts"');
$this->addSql('CREATE TABLE "parts" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, needs_review BOOLEAN NOT NULL, tags CLOB NOT NULL, mass DOUBLE PRECISION DEFAULT NULL, ipn VARCHAR(100) DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, visible BOOLEAN NOT NULL, favorite BOOLEAN NOT NULL, minamount DOUBLE PRECISION NOT NULL, manufacturer_product_url CLOB NOT NULL, manufacturer_product_number VARCHAR(255) NOT NULL, manufacturing_status VARCHAR(255) DEFAULT NULL, order_quantity INTEGER NOT NULL, manual_order BOOLEAN NOT NULL, provider_reference_provider_key VARCHAR(255) DEFAULT NULL, provider_reference_provider_id VARCHAR(255) DEFAULT NULL, provider_reference_provider_url VARCHAR(255) DEFAULT NULL, provider_reference_last_updated DATETIME DEFAULT NULL, eda_info_reference_prefix VARCHAR(255) DEFAULT NULL, eda_info_value VARCHAR(255) DEFAULT NULL, eda_info_invisible BOOLEAN DEFAULT NULL, eda_info_exclude_from_bom BOOLEAN DEFAULT NULL, eda_info_exclude_from_board BOOLEAN DEFAULT NULL, eda_info_exclude_from_sim BOOLEAN DEFAULT NULL, eda_info_kicad_symbol VARCHAR(255) DEFAULT NULL, eda_info_kicad_footprint VARCHAR(255) DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, id_part_custom_state INTEGER DEFAULT NULL, id_category INTEGER NOT NULL, id_footprint INTEGER DEFAULT NULL, id_part_unit INTEGER DEFAULT NULL, id_manufacturer INTEGER DEFAULT NULL, order_orderdetails_id INTEGER DEFAULT NULL, built_project_id INTEGER DEFAULT NULL, CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEA3ED1215 FOREIGN KEY (id_part_custom_state) REFERENCES "part_custom_states" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES "categories" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES "footprints" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES "manufacturers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES "orderdetails" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO "parts" (id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated, eda_info_reference_prefix, eda_info_value, eda_info_invisible, eda_info_exclude_from_bom, eda_info_exclude_from_board, eda_info_exclude_from_sim, eda_info_kicad_symbol, eda_info_kicad_footprint, id_preview_attachment, id_part_custom_state, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id) SELECT id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated, eda_info_reference_prefix, eda_info_value, eda_info_invisible, eda_info_exclude_from_bom, eda_info_exclude_from_board, eda_info_exclude_from_sim, eda_info_kicad_symbol, eda_info_kicad_footprint, id_preview_attachment, id_part_custom_state, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id FROM __temp__parts');
$this->addSql('DROP TABLE __temp__parts');
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON "parts" (ipn)');
$this->addSql('CREATE INDEX IDX_6940A7FEEA7100A1 ON "parts" (id_preview_attachment)');
$this->addSql('CREATE INDEX IDX_6940A7FEA3ED1215 ON "parts" (id_part_custom_state)');
$this->addSql('CREATE INDEX IDX_6940A7FE5697F554 ON "parts" (id_category)');
$this->addSql('CREATE INDEX IDX_6940A7FE7E371A10 ON "parts" (id_footprint)');
$this->addSql('CREATE INDEX IDX_6940A7FE2626CEF9 ON "parts" (id_part_unit)');
$this->addSql('CREATE INDEX IDX_6940A7FE1ECB93AE ON "parts" (id_manufacturer)');
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON "parts" (order_orderdetails_id)');
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON "parts" (built_project_id)');
$this->addSql('CREATE INDEX parts_idx_datet_name_last_id_needs ON "parts" (datetime_added, name, last_modified, id, needs_review)');
$this->addSql('CREATE INDEX parts_idx_name ON "parts" (name)');
$this->addSql('CREATE INDEX parts_idx_ipn ON "parts" (ipn)');
$this->addSql('CREATE TEMPORARY TABLE __temp__suppliers AS SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, address, phone_number, fax_number, email_address, website, auto_product_url, shipping_costs, parent_id, default_currency_id, id_preview_attachment FROM "suppliers"');
$this->addSql('DROP TABLE "suppliers"');
$this->addSql('CREATE TABLE "suppliers" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, alternative_names CLOB DEFAULT NULL, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(255) NOT NULL, auto_product_url VARCHAR(255) NOT NULL, shipping_costs NUMERIC(11, 5) DEFAULT NULL, parent_id INTEGER DEFAULT NULL, default_currency_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, CONSTRAINT FK_AC28B95C727ACA70 FOREIGN KEY (parent_id) REFERENCES "suppliers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CECD792C0 FOREIGN KEY (default_currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
$this->addSql('INSERT INTO "suppliers" (id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, address, phone_number, fax_number, email_address, website, auto_product_url, shipping_costs, parent_id, default_currency_id, id_preview_attachment) SELECT id, name, last_modified, datetime_added, comment, not_selectable, alternative_names, address, phone_number, fax_number, email_address, website, auto_product_url, shipping_costs, parent_id, default_currency_id, id_preview_attachment FROM __temp__suppliers');
$this->addSql('DROP TABLE __temp__suppliers');
$this->addSql('CREATE INDEX IDX_AC28B95C727ACA70 ON "suppliers" (parent_id)');
$this->addSql('CREATE INDEX IDX_AC28B95CECD792C0 ON "suppliers" (default_currency_id)');
$this->addSql('CREATE INDEX IDX_AC28B95CEA7100A1 ON "suppliers" (id_preview_attachment)');
$this->addSql('CREATE INDEX supplier_idx_name ON "suppliers" (name)');
$this->addSql('CREATE INDEX supplier_idx_parent_name ON "suppliers" (parent_id, name)');
}
public function postgreSQLUp(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE attachments ALTER external_path TYPE VARCHAR(2048)');
$this->addSql('ALTER TABLE manufacturers ALTER website TYPE VARCHAR(2048)');
$this->addSql('ALTER TABLE manufacturers ALTER auto_product_url TYPE VARCHAR(2048)');
$this->addSql('ALTER TABLE parts ALTER provider_reference_provider_url TYPE VARCHAR(2048)');
$this->addSql('ALTER TABLE suppliers ALTER website TYPE VARCHAR(2048)');
$this->addSql('ALTER TABLE suppliers ALTER auto_product_url TYPE VARCHAR(2048)');
}
public function postgreSQLDown(Schema $schema): void
{
$this->addSql('ALTER TABLE "attachments" ALTER external_path TYPE VARCHAR(255)');
$this->addSql('ALTER TABLE "manufacturers" ALTER website TYPE VARCHAR(255)');
$this->addSql('ALTER TABLE "manufacturers" ALTER auto_product_url TYPE VARCHAR(255)');
$this->addSql('ALTER TABLE "parts" ALTER provider_reference_provider_url TYPE VARCHAR(255)');
$this->addSql('ALTER TABLE "suppliers" ALTER website TYPE VARCHAR(255)');
$this->addSql('ALTER TABLE "suppliers" ALTER auto_product_url TYPE VARCHAR(255)');
}
}

View file

@ -9,9 +9,9 @@
"@symfony/stimulus-bridge": "^4.0.0",
"@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets",
"@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/assets",
"@symfony/webpack-encore": "^5.0.0",
"@symfony/webpack-encore": "^5.1.0",
"bootstrap": "^5.1.3",
"core-js": "^3.23.0",
"core-js": "^3.38.0",
"intl-messageformat": "^10.2.5",
"jquery": "^3.5.1",
"popper.js": "^1.14.7",
@ -50,7 +50,7 @@
"bootbox": "^6.0.0",
"bootswatch": "^5.1.3",
"bs-custom-file-input": "^1.3.4",
"ckeditor5": "^46.0.0",
"ckeditor5": "^47.0.0",
"clipboard": "^2.0.4",
"compression-webpack-plugin": "^11.1.0",
"datatables.net": "^2.0.0",

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,004 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,000 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View file

@ -1,131 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generated by IcoMoon.io -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="384"
height="448"
viewBox="0 0 384 448"
id="svg7"
sodipodi:docname="file_all.svg"
inkscape:version="0.92.1 r15371">
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs11" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview9"
showgrid="false"
inkscape:zoom="0.52678571"
inkscape:cx="192"
inkscape:cy="192.54785"
inkscape:window-x="1272"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg7" />
<g
id="icomoon-ignore" />
<path
d="M367 95c9.25 9.25 17 27.75 17 41v288c0 13.25-10.75 24-24 24h-336c-13.25 0-24-10.75-24-24v-400c0-13.25 10.75-24 24-24h224c13.25 0 31.75 7.75 41 17zM256 34v94h94c-1.5-4.25-3.75-8.5-5.5-10.25l-78.25-78.25c-1.75-1.75-6-4-10.25-5.5zM352 416v-256h-104c-13.25 0-24-10.75-24-24v-104h-192v384h320z"
id="path5"
style="fill:#1a1a1a" />
<flowRoot
xml:space="preserve"
id="flowRoot3687"
style="fill:#ffffff;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;letter-spacing:0px;word-spacing:0px;"><flowRegion
id="flowRegion3689"
style="fill:#ffffff;"><rect
id="rect3691"
width="251.68207"
height="110.74011"
x="69.128677"
y="214.43904"
style="fill:#ffffff;" /></flowRegion><flowPara
id="flowPara3693" /></flowRoot> <g
aria-label="ALL "
transform="matrix(1.7053159,0,0,1.4411413,-124.25849,-88.403923)"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#1a1a1a;fill-opacity:1;stroke:none"
id="flowRoot3699">
<path
d="m 114.24512,247.89827 -6.32813,16.17188 h 6.9375 v 4.64062 H 98.260742 v -4.64062 h 4.031248 l 25.92188,-65.90625 h 5.57812 l 25.92188,65.90625 h 4.03125 v 4.64062 h -20.90625 v -4.64062 h 6.32812 l -6.375,-16.17188 z m 1.82812,-4.64062 h 24.89063 l -12.46875,-31.64063 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:96px;font-family:'Lucida Fax';-inkscape-font-specification:'Lucida Fax';text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path40" />
<path
d="m 218.72949,268.71077 h -48.5625 v -4.64062 h 6.9375 v -60.14063 h -6.9375 v -4.59375 h 23.10938 v 4.59375 h -6.32813 v 59.57813 h 26.01563 v -8.67188 h 5.76562 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:96px;font-family:'Lucida Fax';-inkscape-font-specification:'Lucida Fax';text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path42" />
<path
d="m 273.66699,268.71077 h -48.5625 v -4.64062 h 6.9375 v -60.14063 h -6.9375 v -4.59375 h 23.10938 v 4.59375 h -6.32813 v 59.57813 h 26.01563 v -8.67188 h 5.76562 z"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:96px;font-family:'Lucida Fax';-inkscape-font-specification:'Lucida Fax';text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path44" />
</g>
<g
aria-label="DATASHEET"
transform="matrix(1.3097344,0,0,1.4436797,-64.263952,-115.73324)"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#1a1a1a;fill-opacity:1;stroke:none"
id="flowRoot3709">
<path
d="m 85.748047,302.43555 v 22.67578 h 4.765625 q 6.035156,0 8.828125,-2.73438 2.812503,-2.73437 2.812503,-8.63281 0,-5.85937 -2.812503,-8.57422 -2.792969,-2.73437 -8.828125,-2.73437 z m -3.945313,-3.24219 h 8.105469 q 8.476563,0 12.441407,3.53516 3.96484,3.51562 3.96484,11.01562 0,7.53906 -3.98437,11.07422 -3.984377,3.53516 -12.421877,3.53516 h -8.105469 z"
style="text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path21" />
<path
d="m 121.62695,303.08008 -5.35156,14.51172 h 10.72266 z m -2.22656,-3.88672 h 4.47266 l 11.11328,29.16016 h -4.10156 l -2.65625,-7.48047 h -13.14454 l -2.65625,7.48047 h -4.16015 z"
style="text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path23" />
<path
d="m 132.05664,299.19336 h 24.66797 v 3.32031 h -10.35156 v 25.83985 h -3.96485 v -25.83985 h -10.35156 z"
style="text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path25" />
<path
d="m 167.17383,303.08008 -5.35156,14.51172 h 10.72265 z m -2.22656,-3.88672 h 4.47265 l 11.11328,29.16016 h -4.10156 l -2.65625,-7.48047 h -13.14453 l -2.65625,7.48047 h -4.16016 z"
style="text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path27" />
<path
d="m 202.25195,300.15039 v 3.84766 q -2.24609,-1.07422 -4.23828,-1.60157 -1.99219,-0.52734 -3.84765,-0.52734 -3.22266,0 -4.98047,1.25 -1.73828,1.25 -1.73828,3.55469 0,1.93359 1.15234,2.92969 1.17187,0.97656 4.41406,1.58203 l 2.38281,0.48828 q 4.41407,0.83984 6.50391,2.96875 2.10938,2.10937 2.10938,5.66406 0,4.23828 -2.85157,6.42578 -2.83203,2.1875 -8.32031,2.1875 -2.07031,0 -4.41406,-0.46875 -2.32422,-0.46875 -4.82422,-1.38672 v -4.0625 q 2.40234,1.34766 4.70703,2.03125 2.30469,0.6836 4.53125,0.6836 3.37891,0 5.21484,-1.32813 1.83594,-1.32812 1.83594,-3.78906 0,-2.14844 -1.32812,-3.35938 -1.3086,-1.21093 -4.31641,-1.8164 l -2.40234,-0.46875 q -4.41407,-0.87891 -6.38672,-2.75391 -1.97266,-1.875 -1.97266,-5.21484 0,-3.86719 2.71485,-6.09375 2.73437,-2.22656 7.51953,-2.22656 2.05078,0 4.17968,0.37109 2.12891,0.37109 4.35547,1.11328 z"
style="text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path29" />
<path
d="m 210.16211,299.19336 h 3.94531 v 11.95312 h 14.33594 v -11.95312 h 3.94531 v 29.16016 h -3.94531 V 314.4668 h -14.33594 v 13.88672 h -3.94531 z"
style="text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path31" />
<path
d="m 240.24023,299.19336 h 18.4375 v 3.32031 h -14.49218 v 8.63281 h 13.88672 v 3.32032 h -13.88672 v 10.5664 h 14.84375 v 3.32032 h -18.78907 z"
style="text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path33" />
<path
d="m 265.55273,299.19336 h 18.4375 v 3.32031 h -14.49218 v 8.63281 h 13.88672 v 3.32032 h -13.88672 v 10.5664 h 14.84375 v 3.32032 h -18.78907 z"
style="text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path35" />
<path
d="m 286.82227,299.19336 h 24.66796 v 3.32031 h -10.35156 v 25.83985 h -3.96484 v -25.83985 h -10.35156 z"
style="text-align:center;text-anchor:middle;fill:#1a1a1a"
id="path37" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.4 KiB

View file

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generated by IcoMoon.io -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="384"
height="448"
viewBox="0 0 384 448"
id="svg7"
sodipodi:docname="file_dc.svg"
inkscape:version="0.92.1 r15371">
<metadata
id="metadata13">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs11" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview9"
showgrid="false"
inkscape:zoom="1.0535715"
inkscape:cx="192"
inkscape:cy="219.39394"
inkscape:window-x="1272"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg7" />
<g
id="icomoon-ignore" />
<path
d="M367 95c9.25 9.25 17 27.75 17 41v288c0 13.25-10.75 24-24 24h-336c-13.25 0-24-10.75-24-24v-400c0-13.25 10.75-24 24-24h224c13.25 0 31.75 7.75 41 17zM256 34v94h94c-1.5-4.25-3.75-8.5-5.5-10.25l-78.25-78.25c-1.75-1.75-6-4-10.25-5.5zM352 416v-256h-104c-13.25 0-24-10.75-24-24v-104h-192v384h320z"
id="path5"
style="fill:#1a1a1a" />
<rect
id="rect3685"
width="289.93774"
height="149.66695"
x="48.32296"
y="188.2641"
style="fill:#1a1a1a" />
<flowRoot
xml:space="preserve"
id="flowRoot3687"
style="fill:#ffffff;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;letter-spacing:0px;word-spacing:0px;"><flowRegion
id="flowRegion3689"
style="fill:#ffffff;"><rect
id="rect3691"
width="251.68207"
height="110.74011"
x="69.128677"
y="214.43904"
style="fill:#ffffff;" /></flowRegion><flowPara
id="flowPara3693" /></flowRoot> <text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:191.63136292px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:4.79078484"
x="33.330128"
y="354.68042"
id="text3697"
transform="scale(1.0793658,0.92646993)"><tspan
sodipodi:role="line"
id="tspan3695"
x="33.330128"
y="354.68042"
style="fill:#ffffff;stroke-width:4.79078484">DC</tspan></text>
</svg>

Before

Width:  |  Height:  |  Size: 3 KiB

Some files were not shown because too many files have changed in this diff Show more