diff --git a/CHANGELOG.md b/CHANGELOG.md index 001c72088..83324f2f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file. * Removed admin/access-config.json fetch * Aligned with v. 2.5.2. * Removed themes. +* Added command to migrate config.json files. ### NB! Prior to 3.x the project was split into separate repositories diff --git a/README.md b/README.md index b7d9fb752..3c9d9ce57 100644 --- a/README.md +++ b/README.md @@ -2,26 +2,26 @@ ## Table of Contents -1. [Description](#description) -2. [ADR - Architectural Decision Records](#adr---architectural-decision-records) -3. [Technologies](#technologies) -4. [Versioning](#versioning) -5. [Taskfile](#taskfile) -6. [Development setup](#development-setup) -7. [Production setup](#production-setup) -8. [Coding standards](#coding-standards) -9. [Stateless](#stateless) -10. [OIDC providers](#oidc-providers) -11. [JWT Auth](#jwt-auth) -12. [Test](#test) -13. [API specification and generated code](#api-specification-and-generated-code) -14. [Configuration](#configuration) -15. [Rest API & Relationships](#rest-api--relationships) -16. [Error codes in the Client](#error-codes-in-the-client) -17. [Preview mode in the Client](#preview-mode-in-the-client) -18. [Feeds](#feeds) -19. [Custom Templates](#custom-templates) -20. [Upgrade Guide](#upgrade-guide) +- [Description](#description) +- [ADR - Architectural Decision Records](#adr---architectural-decision-records) +- [Technologies](#technologies) +- [Versioning](#versioning) +- [Taskfile](#taskfile) +- [Development setup](#development-setup) +- [Production setup](#production-setup) +- [Coding standards](#coding-standards) +- [Stateless](#stateless) +- [OIDC providers](#oidc-providers) +- [JWT Auth](#jwt-auth) +- [Test](#test) +- [API specification and generated code](#api-specification-and-generated-code) +- [Configuration](#configuration) +- [Rest API & Relationships](#rest-api--relationships) +- [Error codes in the Client](#error-codes-in-the-client) +- [Preview mode in the Client](#preview-mode-in-the-client) +- [Feeds](#feeds) +- [Custom Templates](#custom-templates) +- [Upgrade Guide](#upgrade-guide) ## Description @@ -586,7 +586,9 @@ custom themes. ## Custom Templates -It is possible to include your own templates in your installation. +OS2Display ships with some standard templates. These are located in `assets/shared/templates`. + +It is possible to include custom templates in your installation. ### Location @@ -620,6 +622,9 @@ The `.jsx` should expose the following functions: For an example of a custom template see `assets/shared/custom-templates-example/`. +In production, these custom templates need to be built together with the normal templates with the `npm run build` +command. + ### Contributing template If you think the template could be used by other, consider contributing the template to the project as a pull request. diff --git a/UPGRADE.md b/UPGRADE.md index 4e2334f07..8346af6ef 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,8 +1,12 @@ # Upgrade Guide -## 2.x -> 3.0.0 +## Table of contents -The upgrade from 2.x to 3.0.0 of OS2Display introduces a major change to the project. +- ### [2.x -> 3.0](#2x---30) + +## 2.x -> 3.0 + +The upgrade from 2.x to 3.0 of OS2Display introduces a major change to the project. The Admin and Client apps and the Templates that previously existed in separate repositories from the API, have been included in the API repository. The API repository has been renamed from to @@ -13,6 +17,17 @@ Because of these changes, it will be necessary to adjust the server setup to mat ### Upgrade steps +#### 0 - Convert external templates to custom templates + +Instead of loading javascript for templates from possibly external urls we have made the change to only include +templates that are a part of the code. Standard templates are now located in `assets/shared/templates/`. +Custom templates are located in `assets/shared/custom-templates`. + +Because of this change, external templates in 2.x will have to be converted to custom templates. +Custom templates are documented in the [README.md#custom-templates](README.md#custom-templates). + +The important thing is that the `id` of the template should remain the same when converted to a custom template. + #### 1 - Upgrade the API to the latest version of 2.x #### 2 - Configure the following environment variables in `.env.local` @@ -40,6 +55,13 @@ CLIENT_DEBUG=false These values were previously added to Admin and Client: `/public/config.json`. See [README.md](./README.md) for a description of the configuration options. +You can convert your previous config.json files to .env config with the following commands: + +```shell +docker compose exec phpfpm bin/console app:utils:convert-config-json-to-env --type=admin path/to/admin/config.json +docker compose exec phpfpm bin/console app:utils:convert-config-json-to-env --type=client path/to/client/config.json +``` + #### 3 - Run doctrine migrate ```shell diff --git a/composer.json b/composer.json index 4fcee8dac..69958df2d 100644 --- a/composer.json +++ b/composer.json @@ -131,14 +131,6 @@ "fixtures-load": [ "bin/console hautelook:fixtures:load --no-interaction" ], - "prepare-code": [ - "bin/console doctrine:schema:validate", - "@coding-standards-apply", - "vendor/bin/rector", - "vendor/bin/psalm --no-cache", - "@test-setup", - "@test" - ], "test": [ "vendor/bin/phpunit --stop-on-failure" ], diff --git a/src/Command/UpdateCommand.php b/src/Command/UpdateCommand.php index ad52ca0d5..f2dd2227d 100644 --- a/src/Command/UpdateCommand.php +++ b/src/Command/UpdateCommand.php @@ -19,12 +19,11 @@ )] class UpdateCommand extends Command { - private TemplateService $templateService; - - public function __construct(TemplateService $templateService, ?string $name = null) - { + public function __construct( + private readonly TemplateService $templateService, + ?string $name = null, + ) { parent::__construct($name); - $this->templateService = $templateService; } final protected function execute(InputInterface $input, OutputInterface $output): int diff --git a/src/Command/Utils/ConvertConfigJsonToEnvCommand.php b/src/Command/Utils/ConvertConfigJsonToEnvCommand.php new file mode 100644 index 000000000..959c9d531 --- /dev/null +++ b/src/Command/Utils/ConvertConfigJsonToEnvCommand.php @@ -0,0 +1,102 @@ +addArgument('filepath', InputArgument::REQUIRED, 'Path to the file or URL to convert'); + $this->addOption('type', 't', InputOption::VALUE_REQUIRED, 'Type of the config (admin or client).', null, ['admin', 'client']); + } + + final protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $type = $input->getOption('type'); + + if (!in_array($type, ['admin', 'client'])) { + $io->error('Invalid type'); + + return Command::INVALID; + } + + try { + $content = file_get_contents($input->getArgument('filepath')); + + if (false === $content) { + throw new \Exception('Error reading file'); + } + + $config = json_decode($content, true, 512, JSON_THROW_ON_ERROR); + } catch (\Exception|\JsonException $e) { + $io->error($e->getMessage()); + + return Command::INVALID; + } + + if ('admin' === $type) { + $io->success('Insert the following lines in .env.local'); + + $rejseplanenApiKey = $config['rejseplanenApiKey'] ?? null; + $showScreenStatus = $config['showScreenStatus'] ?? null; + $touchButtonRegions = $config['touchButtonRegions'] ?? null; + $loginMethods = $config['loginMethods'] ?? null; + + if (null !== $loginMethods) { + // Remove enabled field since this is unused in v3. + foreach ($loginMethods as &$method) { + unset($method['enabled']); + } + } + + $io->writeln('###> Admin configuration ###'); + null !== $rejseplanenApiKey && $io->writeln('ADMIN_REJSEPLANEN_APIKEY="'.$rejseplanenApiKey.'"'); + null !== $showScreenStatus && $io->writeln('ADMIN_SHOW_SCREEN_STATUS='.var_export($showScreenStatus, true)); + null !== $touchButtonRegions && $io->writeln('ADMIN_TOUCH_BUTTON_REGIONS='.var_export($touchButtonRegions, true)); + null !== $loginMethods && $io->writeln("ADMIN_LOGIN_METHODS='".json_encode($loginMethods)."'"); + // This is a conversion from an url to boolean value. If the url is not empty, it is interpreted as true. + !empty($config['previewClient']) && $io->writeln('ADMIN_ENHANCED_PREVIEW=true'); + $io->writeln('###< Admin configuration ###'); + } elseif ('client' === $type) { + $io->success('Insert the following lines in .env.local'); + + $loginCheckTimeout = $config['loginCheckTimeout'] ?? null; + $refreshTokenTimeout = $config['refreshTokenTimeout'] ?? null; + $releaseTimestampIntervalTimeout = $config['releaseTimestampIntervalTimeout'] ?? null; + $schedulingInterval = $config['schedulingInterval'] ?? null; + $pullStrategyInterval = $config['dataStrategy']['config']['interval'] ?? null; + $debug = $config['debug'] ?? null; + + $colorScheme = $config['colorScheme'] ?? null; + $colorSchemeValue = null !== $colorScheme ? "'".json_encode($colorScheme)."'" : null; + + $io->writeln('###> Client configuration ###'); + null !== $loginCheckTimeout && $io->writeln('CLIENT_LOGIN_CHECK_TIMEOUT='.$loginCheckTimeout); + null !== $refreshTokenTimeout && $io->writeln('CLIENT_REFRESH_TOKEN_TIMEOUT='.$refreshTokenTimeout); + null !== $releaseTimestampIntervalTimeout && $io->writeln('CLIENT_RELEASE_TIMESTAMP_INTERVAL_TIMEOUT='.$releaseTimestampIntervalTimeout); + null !== $schedulingInterval && $io->writeln('CLIENT_SCHEDULING_INTERVAL='.$schedulingInterval); + null !== $pullStrategyInterval && $io->writeln('CLIENT_PULL_STRATEGY_INTERVAL='.$pullStrategyInterval); + null !== $colorSchemeValue && $io->writeln('CLIENT_COLOR_SCHEME='.$colorSchemeValue); + null !== $debug && $io->writeln('CLIENT_DEBUG=true'); + $io->writeln('###< Client configuration ###'); + } + + return Command::SUCCESS; + } +} diff --git a/src/Command/GenerateUlid.php b/src/Command/Utils/GenerateUlid.php similarity index 84% rename from src/Command/GenerateUlid.php rename to src/Command/Utils/GenerateUlid.php index a454d7884..42ae28c73 100644 --- a/src/Command/GenerateUlid.php +++ b/src/Command/Utils/GenerateUlid.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Command; +namespace App\Command\Utils; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; @@ -12,8 +12,8 @@ use Symfony\Component\Uid\Ulid; #[AsCommand( - name: 'app:ulid:generate', - description: 'Generate a new ULID', + name: 'app:utils:generate-ulid', + description: 'Generate a new ULID.', )] class GenerateUlid extends Command {