diff --git a/.editorconfig b/.editorconfig index 293886f..d2a5d7f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,7 +13,7 @@ insert_final_newline = true trim_trailing_whitespace = true # TS/JS-Files -[*.{ts,js}] +[*.{ts,js,mjs}] indent_size = 2 # JSON-Files @@ -51,8 +51,8 @@ indent_size = 2 indent_size = 2 # XLF-Files -[*.xlf] -indent_style = tab +[*.{xlf,xliff}] +indent_size = 2 # SQL-Files [*.sql] diff --git a/.gitattributes b/.gitattributes index 3e9f198..bd7cff0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,5 @@ /.github/ export-ignore /Build/ export-ignore -/Tests/ export-ignore /.gitattributes export-ignore /.gitignore export-ignore /.editorconfig export-ignore diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a40146c..cc069cc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,7 +2,6 @@ name: tests on: - push: pull_request: jobs: diff --git a/.gitignore b/.gitignore index 015afb4..d5d3d87 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ ######################## -# cache_analyzer +# mysql_widget # global ignore file ######################## diff --git a/Build/Scripts/runTests.sh b/Build/Scripts/runTests.sh index c807b41..5fe43e6 100755 --- a/Build/Scripts/runTests.sh +++ b/Build/Scripts/runTests.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # -# EXT:examples test runner based on docker/podman. +# EXT:mysqlreport test runner based on docker/podman. # trap 'cleanUp;exit 2' SIGINT @@ -60,8 +60,8 @@ handleDbmsOptions() { echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 exit 1 fi - [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10.4" - if ! [[ ${DBMS_VERSION} =~ ^(10.4|10.5|10.6|10.7|10.8|10.9|10.10|10.11|11.0|11.1)$ ]]; then + [ -z "${DBMS_VERSION}" ] && DBMS_VERSION="10.11" + if ! [[ ${DBMS_VERSION} =~ ^(10.6|10.7|10.8|10.9|10.10|10.11|11.0|11.1)$ ]]; then echo "Invalid combination -d ${DBMS} -i ${DBMS_VERSION}" >&2 echo >&2 echo "Use \".Build/Scripts/runTests.sh -h\" to display help and valid options" >&2 diff --git a/Build/phpunit/FunctionalTestsBootstrap.php b/Build/phpunit/FunctionalTestsBootstrap.php index a95bc52..9882f8f 100644 --- a/Build/phpunit/FunctionalTestsBootstrap.php +++ b/Build/phpunit/FunctionalTestsBootstrap.php @@ -1,4 +1,5 @@ > - */ - protected array $innoDbStatus = []; - - /** - * @var array - */ - protected array $handlerStatus = []; - - /** - * @return array{labels: array, datasets: array} - */ - public function getChartData(): array - { - return [ - 'labels' => [ - 0 => 'Used', - 1 => 'Misc', - 2 => 'Free', - ], - 'datasets' => [ - [ - 'backgroundColor' => WidgetApi::getDefaultChartColors(), - 'border' => 0, - 'data' => $this->getInnoDbChartData(), - ], - ], - ]; - } - - /** - * @return array An array of innodb buffer pool pages with keys 0 for 'data', 1 for 'misc', and 2 for 'free' - */ - protected function getInnoDbChartData(): array - { - $innoDbStatus = $this->getInnoDbStatus(); - - return [ - 0 => $innoDbStatus['Innodb_buffer_pool_pages_data'], - 1 => $innoDbStatus['Innodb_buffer_pool_pages_misc'], - 2 => $innoDbStatus['Innodb_buffer_pool_pages_free'], - ]; - } - - /** - * @return array|int[][] - */ - protected function getInnoDbStatus(): array - { - if ($this->innoDbStatus === []) { - $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionByName( - ConnectionPool::DEFAULT_CONNECTION_NAME, - ); - $queryResult = $connection->executeQuery('SHOW GLOBAL STATUS LIKE \'Innodb_%\''); - - $innoDbStatus = []; - while ($row = $queryResult->fetchAssociative()) { - $innoDbStatus[$row['Variable_name']] = $row['Value']; - } - - $this->innoDbStatus = $innoDbStatus; - } - - return $this->innoDbStatus; - } - - /** - * @return array|int[] - */ - protected function getHandlerStatus(): array - { - if (empty($this->handlerStatus)) { - $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionByName( - ConnectionPool::DEFAULT_CONNECTION_NAME, - ); - $queryResult = $connection->executeQuery('SHOW GLOBAL STATUS LIKE \'Handler_%\''); - - $handlerStatus = []; - while ($row = $queryResult->fetchAssociative()) { - $handlerStatus[$row['Variable_name']] = $row['Value']; - } - - $this->handlerStatus = $handlerStatus; - } - - return $this->handlerStatus; - } - - public function getInnoDbPageSize(): int - { - return (int)$this->getInnoDbStatus()['Innodb_page_size']; - } - - public function getInnoDbPoolDataTotal(): int - { - return (int)$this->getInnoDbStatus()['Innodb_buffer_pool_pages_total'] * $this->getInnoDbPageSize(); - } - - public function getInnoDbPoolDataUsed(): int - { - $data = (int)$this->getInnoDbStatus()['Innodb_buffer_pool_pages_data'] * $this->getInnoDbPageSize(); - $misc = (int)$this->getInnoDbStatus()['Innodb_buffer_pool_pages_misc'] * $this->getInnoDbPageSize(); - - return $data + $misc; - } - - public function getInnoDbBufferPoolWaitFree(): int - { - return (int)$this->getInnoDbStatus()['Innodb_buffer_pool_wait_free']; - } - - public function getInnoDbHitRatio(): float - { - $readRequests = (int)$this->getInnoDbStatus()['Innodb_buffer_pool_read_requests']; - $reads = (int)$this->getInnoDbStatus()['Innodb_buffer_pool_reads']; - - if ($readRequests === 0) { - return 0.0; - } - - return round($readRequests / ($readRequests + $reads) * 100, 2); - } - - public function getHandlerReadRatio(): float - { - $handlerReadRndNext = (int)$this->getHandlerStatus()['Handler_read_rnd_next']; - $handlerReadRnd = (int)$this->getHandlerStatus()['Handler_read_rnd']; - $handlerReadFirst = (int)$this->getHandlerStatus()['Handler_read_first']; - $handlerReadNext = (int)$this->getHandlerStatus()['Handler_read_next']; - $handlerReadKey = (int)$this->getHandlerStatus()['Handler_read_key']; - $handlerReadPrev = (int)$this->getHandlerStatus()['Handler_read_prev']; - - return round( - ($handlerReadRndNext + $handlerReadRnd) / ($handlerReadRndNext + $handlerReadRnd + $handlerReadFirst + $handlerReadNext + $handlerReadKey + $handlerReadPrev), - 2, - ); - } -} diff --git a/Classes/Domain/Factory/HandlerFactory.php b/Classes/Domain/Factory/HandlerFactory.php new file mode 100644 index 0000000..8e1b414 --- /dev/null +++ b/Classes/Domain/Factory/HandlerFactory.php @@ -0,0 +1,47 @@ +connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME); + $queryResult = $connection->executeQuery('SHOW GLOBAL STATUS LIKE \'Handler_%\''); + + $innoDbStatus = []; + while ($row = $queryResult->fetchAssociative()) { + $innoDbStatus[$row['Variable_name']] = $row['Value']; + } + } catch (Exception $e) { + return null; + } + + return new Handler( + handlerReadRndNext: (int)($innoDbStatus['Handler_read_rnd_next'] ?? 0), + handlerReadRnd: (int)($innoDbStatus['Handler_read_rnd'] ?? 0), + handlerReadFirst: (int)($innoDbStatus['Handler_read_first'] ?? 0), + handlerReadNext: (int)($innoDbStatus['Handler_read_next'] ?? 0), + handlerReadKey: (int)($innoDbStatus['Handler_read_key'] ?? 0), + handlerReadPrev: (int)($innoDbStatus['Handler_read_prev'] ?? 0), + ); + } +} diff --git a/Classes/Domain/Factory/InnoDbStatusFactory.php b/Classes/Domain/Factory/InnoDbStatusFactory.php new file mode 100644 index 0000000..0dacd58 --- /dev/null +++ b/Classes/Domain/Factory/InnoDbStatusFactory.php @@ -0,0 +1,49 @@ +connectionPool->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME); + $queryResult = $connection->executeQuery('SHOW GLOBAL STATUS LIKE \'Innodb_%\''); + + $innoDbStatus = []; + while ($row = $queryResult->fetchAssociative()) { + $innoDbStatus[$row['Variable_name']] = $row['Value']; + } + } catch (Exception $e) { + return null; + } + + return new InnoDbStatus( + innodbBufferPoolPagesData: (int)($innoDbStatus['Innodb_buffer_pool_pages_data'] ?? 0), + innodbBufferPoolPagesFree: (int)($innoDbStatus['Innodb_buffer_pool_pages_free'] ?? 0), + innodbBufferPoolPagesMisc: (int)($innoDbStatus['Innodb_buffer_pool_pages_misc'] ?? 0), + innodbBufferPoolPagesTotal: (int)($innoDbStatus['Innodb_buffer_pool_pages_total'] ?? 0), + innodbBufferPoolReadRequests: (int)($innoDbStatus['Innodb_buffer_pool_read_requests'] ?? 0), + innodbBufferPoolReads: (int)($innoDbStatus['Innodb_buffer_pool_reads'] ?? 0), + innodbBufferPoolWaitFree: (int)($innoDbStatus['Innodb_buffer_pool_wait_free'] ?? 0), + innodbPageSize: (int)($innoDbStatus['Innodb_page_size'] ?? 0), + ); + } +} diff --git a/Classes/Domain/Model/Handler.php b/Classes/Domain/Model/Handler.php new file mode 100644 index 0000000..0a989dd --- /dev/null +++ b/Classes/Domain/Model/Handler.php @@ -0,0 +1,54 @@ +handlerReadRndNext; + } + + public function getHandlerReadRnd(): int + { + return $this->handlerReadRnd; + } + + public function getHandlerReadFirst(): int + { + return $this->handlerReadFirst; + } + + public function getHandlerReadNext(): int + { + return $this->handlerReadNext; + } + + public function getHandlerReadKey(): int + { + return $this->handlerReadKey; + } + + public function getHandlerReadPrev(): int + { + return $this->handlerReadPrev; + } +} diff --git a/Classes/Domain/Model/InnoDbStatus.php b/Classes/Domain/Model/InnoDbStatus.php new file mode 100644 index 0000000..097bfbd --- /dev/null +++ b/Classes/Domain/Model/InnoDbStatus.php @@ -0,0 +1,79 @@ +innodbBufferPoolPagesData; + } + + public function getInnodbBufferPoolPagesFree(): int + { + return $this->innodbBufferPoolPagesFree; + } + + public function getInnodbBufferPoolPagesMisc(): int + { + return $this->innodbBufferPoolPagesMisc; + } + + public function getInnodbBufferPoolPagesTotal(): int + { + return $this->innodbBufferPoolPagesTotal; + } + + public function getInnodbBufferPoolReadRequests(): int + { + return $this->innodbBufferPoolReadRequests; + } + + public function getInnodbBufferPoolReads(): int + { + return $this->innodbBufferPoolReads; + } + + public function getInnodbBufferPoolWaitFree(): int + { + return $this->innodbBufferPoolWaitFree; + } + + public function getInnodbPageSize(): int + { + return $this->innodbPageSize; + } + + public function getInnoDbPoolDataTotalBytes(): int + { + return $this->getInnodbBufferPoolPagesTotal() * $this->getInnoDbPageSize(); + } + + public function getInnoDbPoolDataUsedBytes(): int + { + $data = $this->getInnodbBufferPoolPagesData() * $this->getInnoDbPageSize(); + $misc = $this->getInnodbBufferPoolPagesMisc() * $this->getInnoDbPageSize(); + + return $data + $misc; + } +} diff --git a/Classes/Widget/DisplayUnit.php b/Classes/Widget/DisplayUnit.php new file mode 100644 index 0000000..d5863da --- /dev/null +++ b/Classes/Widget/DisplayUnit.php @@ -0,0 +1,19 @@ + 'Percentage', + 'mb' => 'MegaByte', + 'gb' => 'GigaByte', + ], + ), + ]; + } + + public function renderWidget(WidgetContext $context): WidgetResult + { + $this->widgetContext = $context; + + $innoDbStatus = $this->innoDbStatusFactory->getInnoDbStatus(); + + $view = $this->backendViewFactory->create($context->request); + $view->assignMultiple([ + 'configuration' => $this->configuration, + 'usedData' => $this->formatBytes( + $innoDbStatus->getInnoDbPoolDataUsedBytes(), + $innoDbStatus->getInnoDbPoolDataTotalBytes(), + DisplayUnit::from($context->settings->get('unit')), + ), + 'totalData' => $this->formatBytes( + $innoDbStatus->getInnoDbPoolDataTotalBytes(), + $innoDbStatus->getInnoDbPoolDataTotalBytes(), + DisplayUnit::from($context->settings->get('unit')), + ), + ]); + + return new WidgetResult( + content: $view->render('Widget/InnoDbBufferPool'), + label: $context->configuration->getTitle(), + refreshable: true, + ); + } + + /** + * @return array + */ + public function getEventData(): array + { + $innoDbStatus = $this->innoDbStatusFactory->getInnoDbStatus(); + + return [ + 'graphConfig' => [ + 'type' => 'doughnut', + 'options' => [ + 'maintainAspectRatio' => false, + 'legend' => [ + 'display' => true, + 'position' => 'bottom', + ], + 'tooltips' => [ + 'enabled' => true, + ], + ], + 'data' => [ + 'labels' => [ + 0 => 'Used', + 1 => 'Misc', + 2 => 'Free', + ], + 'datasets' => [ + [ + 'backgroundColor' => WidgetApi::getDefaultChartColors(), + 'border' => 0, + 'data' => [ + 0 => $this->formatBytes( + $innoDbStatus->getInnodbBufferPoolPagesData(), + $innoDbStatus->getInnodbBufferPoolPagesTotal(), + DisplayUnit::from($this->widgetContext->settings->get('unit')), + true, + ), + 1 => $this->formatBytes( + $innoDbStatus->getInnodbBufferPoolPagesMisc(), + $innoDbStatus->getInnodbBufferPoolPagesTotal(), + DisplayUnit::from($this->widgetContext->settings->get('unit')), + true, + ), + 2 => $this->formatBytes( + $innoDbStatus->getInnodbBufferPoolPagesFree(), + $innoDbStatus->getInnodbBufferPoolPagesTotal(), + DisplayUnit::from($this->widgetContext->settings->get('unit')), + true, + ), + ], + ], + ], + ], + ], + ]; + } + + protected function formatBytes(int $bytes, int $total, DisplayUnit $displayUnit, bool $returnPlain = false): float|string + { + if ($displayUnit->value === 'mb') { + $unit = ' MB'; + $data = $bytes / 1024 / 1024; + } elseif ($displayUnit->value === 'gb') { + $unit = ' GB'; + $data = $bytes / 1024 / 1024 / 1024; + } else { + $unit = '%'; + $data = 100 / $total * $bytes; + } + + if ($returnPlain) { + return (float)$data; + } + + return number_format($data, 2, ',', '.') . $unit; + } + + public function getJavaScriptModuleInstructions(): array + { + return [ + JavaScriptModuleInstruction::create('@typo3/dashboard/contrib/chartjs.js'), + JavaScriptModuleInstruction::create('@typo3/dashboard/chart-initializer.js'), + ]; + } +} diff --git a/Classes/Widget/InnoDbStatusWidget.php b/Classes/Widget/InnoDbStatusWidget.php new file mode 100644 index 0000000..0205c26 --- /dev/null +++ b/Classes/Widget/InnoDbStatusWidget.php @@ -0,0 +1,84 @@ +innoDbStatusFactory->getInnoDbStatus(); + $handler = $this->handlerFactory->getHandler(); + + $view = $this->backendViewFactory->create($context->request); + $view->assignMultiple([ + 'configuration' => $this->configuration, + 'bufferPoolTooSmall' => $innoDbStatus->getInnodbBufferPoolWaitFree() > 0, + 'readHitRatio' => $this->getInnoDbHitRatio($innoDbStatus), + 'handlerReadRatio' => $this->getHandlerReadRatio($handler), + ]); + + return new WidgetResult( + content: $view->render('Widget/InnoDbStatus'), + label: $context->configuration->getTitle(), + refreshable: true, + ); + } + + protected function getInnoDbHitRatio(InnoDbStatus $innoDbStatus): float + { + $readRequests = $innoDbStatus->getInnodbBufferPoolReadRequests(); + $reads = $innoDbStatus->getInnodbBufferPoolReads(); + + if ($readRequests === 0) { + return 0.0; + } + + return round($readRequests / ($readRequests + $reads) * 100, 2); + } + + protected function getHandlerReadRatio(Handler $handler): float + { + $handlerReadRndNext = $handler->getHandlerReadRndNext(); + $handlerReadRnd = $handler->getHandlerReadRnd(); + $handlerReadFirst = $handler->getHandlerReadFirst(); + $handlerReadNext = $handler->getHandlerReadNext(); + $handlerReadKey = $handler->getHandlerReadKey(); + $handlerReadPrev = $handler->getHandlerReadPrev(); + + return round( + ($handlerReadRndNext + $handlerReadRnd) / ($handlerReadRndNext + $handlerReadRnd + $handlerReadFirst + $handlerReadNext + $handlerReadKey + $handlerReadPrev), + 2, + ); + } +} diff --git a/Classes/Widgets/InnoDbBufferPool.php b/Classes/Widgets/InnoDbBufferPool.php deleted file mode 100644 index 3578207..0000000 --- a/Classes/Widgets/InnoDbBufferPool.php +++ /dev/null @@ -1,93 +0,0 @@ -request = $request; - } - - public function renderWidgetContent(): string - { - $view = $this->backendViewFactory->create($this->request); - $view->assignMultiple([ - 'configuration' => $this->configuration, - 'usedData' => $this->dataProvider->getInnoDbPoolDataUsed(), - 'totalData' => $this->dataProvider->getInnoDbPoolDataTotal(), - ]); - - return $view->render('Widget/InnoDbBufferPool'); - } - - /** - * @return array - */ - public function getEventData(): array - { - return [ - 'graphConfig' => [ - 'type' => 'doughnut', - 'options' => [ - 'maintainAspectRatio' => false, - 'legend' => [ - 'display' => true, - 'position' => 'bottom', - ], - 'tooltips' => [ - 'enabled' => true, - ], - 'title' => [ - 'display' => true, - 'text' => 'Usage in %', - ], - ], - 'data' => $this->dataProvider->getChartData(), - ], - ]; - } - - public function getJavaScriptModuleInstructions(): array - { - return [ - JavaScriptModuleInstruction::create('@typo3/dashboard/contrib/chartjs.js'), - JavaScriptModuleInstruction::create('@typo3/dashboard/chart-initializer.js'), - ]; - } - - /** - * @phpstan-return array - */ - public function getOptions(): array - { - return []; - } -} diff --git a/Classes/Widgets/InnoDbStatus.php b/Classes/Widgets/InnoDbStatus.php deleted file mode 100644 index aa18976..0000000 --- a/Classes/Widgets/InnoDbStatus.php +++ /dev/null @@ -1,56 +0,0 @@ -request = $request; - } - - public function renderWidgetContent(): string - { - $view = $this->backendViewFactory->create($this->request); - $view->assignMultiple([ - 'configuration' => $this->configuration, - 'bufferPoolTooSmall' => $this->dataProvider->getInnoDbBufferPoolWaitFree() > 0, - 'readHitRatio' => $this->dataProvider->getInnoDbHitRatio(), - 'handlerReadRatio' => $this->dataProvider->getHandlerReadRatio(), - ]); - - return $view->render('Widget/InnoDbStatus'); - } - - /** - * @phpstan-return array - */ - public function getOptions(): array - { - return []; - } -} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index ceda3de..bc73afa 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -8,9 +8,7 @@ services: resource: '../Classes/*' dashboard.widget.innodb.bufferpool: - class: 'StefanFroemken\MySqlWidget\Widgets\InnoDbBufferPool' - arguments: - $dataProvider: '@StefanFroemken\MySqlWidget\DataProvider\InnoDbDataProvider' + class: 'StefanFroemken\MySqlWidget\Widget\InnoDbBufferPoolWidget' tags: - name: dashboard.widget identifier: 'mysql.innodb.bufferpool' @@ -22,9 +20,7 @@ services: width: 'small' dashboard.widget.innodb.status: - class: 'StefanFroemken\MySqlWidget\Widgets\InnoDbStatus' - arguments: - $dataProvider: '@StefanFroemken\MySqlWidget\DataProvider\InnoDbDataProvider' + class: 'StefanFroemken\MySqlWidget\Widget\InnoDbStatusWidget' tags: - name: dashboard.widget identifier: 'mysql.innodb.status' diff --git a/Documentation/ChangeLog/Index.rst b/Documentation/ChangeLog/Index.rst index 99c1eda..9c8e53f 100644 --- a/Documentation/ChangeLog/Index.rst +++ b/Documentation/ChangeLog/Index.rst @@ -7,6 +7,11 @@ ChangeLog ========= +**Version 2.0.0** + +* Add TYPO3 14 compatibility +* Remove TYPO3 12 and 13 compatibility + **Version 1.0.1** * Add new extension icon diff --git a/Documentation/guides.xml b/Documentation/guides.xml index 85aeacb..16d0389 100644 --- a/Documentation/guides.xml +++ b/Documentation/guides.xml @@ -14,8 +14,8 @@ typo3-core-preferred="stable" /> + + + + + Display Unit + + + + + Select the measurement unit for the InnoDB Buffer Pool data. You can choose between percentage, Megabytes, or Gigabytes. + + + + diff --git a/Resources/Private/Templates/Widget/InnoDbBufferPool.html b/Resources/Private/Templates/Widget/InnoDbBufferPool.html index 05ce86c..8e63f86 100644 --- a/Resources/Private/Templates/Widget/InnoDbBufferPool.html +++ b/Resources/Private/Templates/Widget/InnoDbBufferPool.html @@ -11,6 +11,6 @@ - {usedData -> f:format.bytes(decimals: 2)} (used + misc) of {totalData -> f:format.bytes(decimals: 2)} used + {usedData} (used + misc) of {totalData} used diff --git a/composer.json b/composer.json index 6b504c0..9594194 100644 --- a/composer.json +++ b/composer.json @@ -25,14 +25,14 @@ "source": "https://github.com/froemken/mysql_widget" }, "require": { - "php": "^8.1", - "typo3/cms-core": "^12.4.17 || ^13.1.1", - "typo3/cms-dashboard": "^12.4.17 || ^13.1.1" + "typo3/cms-core": "^14.0", + "typo3/cms-dashboard": "^14.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.52", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^11.0.3", + "ergebnis/composer-normalize": "~2.48.0", + "friendsofphp/php-cs-fixer": "^3.88", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^11.5", "typo3/testing-framework": "dev-main" }, "autoload": { @@ -40,11 +40,6 @@ "StefanFroemken\\MySqlWidget\\": "Classes" } }, - "autoload-dev": { - "psr-4": { - "StefanFroemken\\MySqlWidget\\Tests\\": "Tests" - } - }, "replace": { "typo3-ter/mysql_widget": "self.version", "typo3-ter/mysql-widget": "self.version" diff --git a/ext_emconf.php b/ext_emconf.php index acd6839..5bfe9e5 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -9,12 +9,11 @@ 'author_company' => '', 'state' => 'stable', 'clearCacheOnLoad' => 0, - 'version' => '1.0.1', + 'version' => '2.0.0', 'constraints' => [ 'depends' => [ - 'php' => '8.1.0-8.3.99', - 'typo3' => '12.4.17-13.4.99', - 'dashboard' => '12.4.17-13.4.99', + 'typo3' => '14.0.0-14.99.99', + 'dashboard' => '14.0.0-14.99.99', ], 'conflicts' => [ ],