diff --git a/.env b/.env index 28e53b97..5c7deb23 100644 --- a/.env +++ b/.env @@ -72,10 +72,10 @@ ERROR_PAGE_SHOW_HELP=1 ################################################################################## # The default page size for the part table (set to -1 to show all parts on one page) -TABLE_DEFAULT_PAGE_SIZE=50 +#TABLE_DEFAULT_PAGE_SIZE=50 # Configure which columns will be visible by default in the parts table (and in which order). # This is a comma separated list of column names. See documentation for available values. -TABLE_PARTS_DEFAULT_COLUMNS=name,description,category,footprint,manufacturer,storage_location,amount +#TABLE_PARTS_DEFAULT_COLUMNS=name,description,category,footprint,manufacturer,storage_location,amount ################################################################################## # Info provider settings diff --git a/config/packages/datatables.yaml b/config/packages/datatables.yaml index dc116f97..f0fe44b9 100644 --- a/config/packages/datatables.yaml +++ b/config/packages/datatables.yaml @@ -9,7 +9,7 @@ datatables: # Set options, as documented at https://datatables.net/reference/option/ options: lengthMenu : [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]] - pageLength: '%partdb.table.default_page_size%' # Set to -1 to disable pagination (i.e. show all rows) by default + pageLength: 50 # Set to -1 to disable pagination (i.e. show all rows) by default #dom: "<'row' <'col-sm-12' tr>><'row' <'col-sm-6'l><'col-sm-6 text-right'pif>>" dom: " <'row'<'col mb-2 input-group' B l> <'col mb-2' <'pull-end' p>>> <'card' diff --git a/config/parameters.yaml b/config/parameters.yaml index f694410a..2a7fa19a 100644 --- a/config/parameters.yaml +++ b/config/parameters.yaml @@ -43,11 +43,6 @@ parameters: ###################################################################################################################### partdb.saml.enabled: '%env(bool:SAML_ENABLED)%' # If this is set to true, SAML authentication is enabled - ###################################################################################################################### - # Table settings - ###################################################################################################################### - partdb.table.default_page_size: '%env(int:TABLE_DEFAULT_PAGE_SIZE)%' # The default number of entries shown per page in tables - partdb.table.parts.default_columns: '%env(trim:string:TABLE_PARTS_DEFAULT_COLUMNS)%' # The default columns in part tables and their order ###################################################################################################################### # Miscellaneous @@ -102,8 +97,6 @@ parameters: env(EMAIL_SENDER_NAME): 'Part-DB Mailer' env(ALLOW_EMAIL_PW_RESET): 0 - env(TABLE_DEFAULT_PAGE_SIZE): 50 - env(TRUSTED_PROXIES): '127.0.0.1' #By default trust only our own server env(TRUSTED_HOSTS): '' # Trust all host names by default diff --git a/config/services.yaml b/config/services.yaml index e43f2485..d4962b56 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -171,9 +171,6 @@ services: #################################################################################################################### # Table settings #################################################################################################################### - App\DataTables\PartsDataTable: - arguments: - $visible_columns: '%partdb.table.parts.default_columns%' App\DataTables\Helpers\ColumnSortHelper: shared: false # Service has a state so not share it between different tables diff --git a/src/DataTables/Helpers/ColumnSortHelper.php b/src/DataTables/Helpers/ColumnSortHelper.php index 05bd8182..b7b5b567 100644 --- a/src/DataTables/Helpers/ColumnSortHelper.php +++ b/src/DataTables/Helpers/ColumnSortHelper.php @@ -72,7 +72,8 @@ class ColumnSortHelper * Apply the visibility configuration to the given DataTable and configure the columns. * @param DataTable $dataTable * @param string|array $visible_columns Either a list or a comma separated string of column names, which should - * be visible by default. If a column is not listed here, it will be hidden by default. + * be visible by default. If a column is not listed here, it will be hidden by default. If an array of enum values are passed, + * their value will be used as the column name. * @return void */ public function applyVisibilityAndConfigureColumns(DataTable $dataTable, string|array $visible_columns, @@ -83,6 +84,14 @@ class ColumnSortHelper $visible_columns = array_map(trim(...), explode(",", $visible_columns)); } + //If $visible_columns is a list of enum values, convert them to the column names + foreach ($visible_columns as &$value) { + if ($value instanceof \BackedEnum) { + $value = $value->value; + } + } + unset ($value); + $processed_columns = []; //First add all columns which visibility is not configurable diff --git a/src/DataTables/PartsDataTable.php b/src/DataTables/PartsDataTable.php index 28c564b1..4169dc6f 100644 --- a/src/DataTables/PartsDataTable.php +++ b/src/DataTables/PartsDataTable.php @@ -45,6 +45,7 @@ use App\Entity\Parts\PartLot; use App\Entity\ProjectSystem\Project; use App\Services\EntityURLGenerator; use App\Services\Formatters\AmountFormatter; +use App\Settings\BehaviorSettings\TableSettings; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\QueryBuilder; use Omines\DataTablesBundle\Adapter\Doctrine\ORM\SearchCriteriaProvider; @@ -63,8 +64,8 @@ final class PartsDataTable implements DataTableTypeInterface private readonly AmountFormatter $amountFormatter, private readonly PartDataTableHelper $partDataTableHelper, private readonly Security $security, - private readonly string $visible_columns, private readonly ColumnSortHelper $csh, + private readonly TableSettings $tableSettings, ) { } @@ -243,7 +244,7 @@ final class PartsDataTable implements DataTableTypeInterface ]); //Apply the user configured order and visibility and add the columns to the table - $this->csh->applyVisibilityAndConfigureColumns($dataTable, $this->visible_columns, + $this->csh->applyVisibilityAndConfigureColumns($dataTable, $this->tableSettings->partsDefaultColumns, "TABLE_PARTS_DEFAULT_COLUMNS"); $dataTable->addOrderBy('name') diff --git a/src/Settings/BehaviorSettings/BehaviorSettings.php b/src/Settings/BehaviorSettings/BehaviorSettings.php index 9f611eab..97a1759e 100644 --- a/src/Settings/BehaviorSettings/BehaviorSettings.php +++ b/src/Settings/BehaviorSettings/BehaviorSettings.php @@ -34,4 +34,7 @@ class BehaviorSettings #[EmbeddedSettings] public ?SidebarSettings $sidebar = null; + + #[EmbeddedSettings] + public ?TableSettings $table = null; } \ No newline at end of file diff --git a/src/Settings/BehaviorSettings/PartTableColumns.php b/src/Settings/BehaviorSettings/PartTableColumns.php new file mode 100644 index 00000000..eea6ad86 --- /dev/null +++ b/src/Settings/BehaviorSettings/PartTableColumns.php @@ -0,0 +1,66 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Settings\BehaviorSettings; + +use Symfony\Contracts\Translation\TranslatableInterface; +use Symfony\Contracts\Translation\TranslatorInterface; + +enum PartTableColumns : string implements TranslatableInterface +{ + + case NAME = "name"; + case ID = "id"; + case IPN = "ipn"; + case DESCRIPTION = "description"; + case CATEGORY = "category"; + case FOOTPRINT = "footprint"; + case MANUFACTURER = "manufacturer"; + case LOCATION = "storage_location"; + case AMOUNT = "amount"; + case MIN_AMOUNT = "minamount"; + case PART_UNIT = "partUnit"; + case ADDED_DATE = "addedDate"; + case LAST_MODIFIED = "lastModified"; + case NEEDS_REVIEW = "needs_review"; + case FAVORITE = "favorite"; + case MANUFACTURING_STATUS = "manufacturing_status"; + case MPN = "manufacturer_product_number"; + case MASS = "mass"; + case TAGS = "tags"; + case ATTACHMENTS = "attachments"; + case EDIT = "edit"; + + public function trans(TranslatorInterface $translator, ?string $locale = null): string + { + $key = match($this) { + self::LOCATION => 'part.table.storeLocations', + self::NEEDS_REVIEW => 'part.table.needsReview', + self::MANUFACTURING_STATUS => 'part.table.manufacturingStatus', + self::MPN => 'part.table.mpn', + default => 'part.table.' . $this->value, + }; + + return $translator->trans($key, locale: $locale); + } +} \ No newline at end of file diff --git a/src/Settings/BehaviorSettings/SidebarSettings.php b/src/Settings/BehaviorSettings/SidebarSettings.php index cba99b4f..3e93d634 100644 --- a/src/Settings/BehaviorSettings/SidebarSettings.php +++ b/src/Settings/BehaviorSettings/SidebarSettings.php @@ -50,6 +50,7 @@ class SidebarSettings formOptions: ['class' => SidebarItems::class, 'multiple' => true, 'ordered' => true] )] #[Assert\NotBlank()] + #[Assert\Unique()] public array $items = [SidebarItems::CATEGORIES, SidebarItems::PROJECTS, SidebarItems::TOOLS]; /** diff --git a/src/Settings/BehaviorSettings/TableSettings.php b/src/Settings/BehaviorSettings/TableSettings.php new file mode 100644 index 00000000..7b4e7912 --- /dev/null +++ b/src/Settings/BehaviorSettings/TableSettings.php @@ -0,0 +1,90 @@ +. + */ + +declare(strict_types=1); + + +namespace App\Settings\BehaviorSettings; + +use App\Settings\SettingsIcon; +use Jbtronics\SettingsBundle\Metadata\EnvVarMode; +use Jbtronics\SettingsBundle\ParameterTypes\ArrayType; +use Jbtronics\SettingsBundle\ParameterTypes\EnumType; +use Jbtronics\SettingsBundle\Settings\Settings; +use Jbtronics\SettingsBundle\Settings\SettingsParameter; +use Jbtronics\SettingsBundle\Settings\SettingsTrait; +use Symfony\Component\Translation\TranslatableMessage as TM; +use Symfony\Component\Validator\Constraints as Assert; + +#[Settings(label: new TM("settings.behavior.table"))] +#[SettingsIcon('fa-table')] +class TableSettings +{ + use SettingsTrait; + + #[SettingsParameter( + label: new TM("settings.behavior.table.default_page_size"), + description: new TM("settings.behavior.table.default_page_size.help"), + envVar: "int:TABLE_DEFAULT_PAGE_SIZE", + envVarMode: EnvVarMode::OVERWRITE, + )] + #[Assert\AtLeastOneOf(constraints: + [ + new Assert\Positive(), + new Assert\EqualTo(value: -1) + ] + )] + public int $fullDefaultPageSize = 50; + + + /** @var PartTableColumns[] */ + #[SettingsParameter(ArrayType::class, + label: new TM("settings.behavior.table.parts_default_columns"), + description: new TM("settings.behavior.table.parts_default_columns.help"), + options: ['type' => EnumType::class, 'options' => ['class' => PartTableColumns::class]], + formType: \Symfony\Component\Form\Extension\Core\Type\EnumType::class, + formOptions: ['class' => PartTableColumns::class, 'multiple' => true, 'ordered' => true], + envVar: "TABLE_PARTS_DEFAULT_COLUMNS", envVarMode: EnvVarMode::OVERWRITE, envVarMapper: [self::class, 'mapPartsDefaultColumnsEnv'] + )] + #[Assert\NotBlank()] + #[Assert\Unique()] + #[Assert\All([new Assert\Type(PartTableColumns::class)])] + public array $partsDefaultColumns = [PartTableColumns::NAME, PartTableColumns::DESCRIPTION, + PartTableColumns::CATEGORY, PartTableColumns::FOOTPRINT, PartTableColumns::MANUFACTURER, + PartTableColumns::LOCATION, PartTableColumns::AMOUNT]; + + + public static function mapPartsDefaultColumnsEnv(string $columns): array + { + $exploded = explode(',', $columns); + $ret = []; + foreach ($exploded as $column) { + $enum = PartTableColumns::tryFrom($column); + if (!$enum) { + throw new \InvalidArgumentException("Invalid column '$column' in TABLE_PARTS_DEFAULT_COLUMNS"); + } + + $ret[] = $enum; + } + + return $ret; + } + +} \ No newline at end of file