diff --git a/config/routes.php b/config/routes.php
index f7580c944..d5433e051 100644
--- a/config/routes.php
+++ b/config/routes.php
@@ -99,8 +99,21 @@
// Admin.
$routes->prefix('admin', ['_namePrefix' => 'admin:'], function (RouteBuilder $routes) {
-
- foreach (['appearance', 'applications', 'async_jobs', 'config', 'endpoints', 'roles', 'roles_modules', 'endpoint_permissions', 'objects_history', 'user_accesses'] as $controller) {
+ $adminRoutes = [
+ 'appearance',
+ 'applications',
+ 'async_jobs',
+ 'config',
+ 'endpoints',
+ 'roles',
+ 'roles_modules',
+ 'endpoint_permissions',
+ 'objects_history',
+ 'user_accesses',
+ 'system_info',
+ ];
+
+ foreach ($adminRoutes as $controller) {
// Routes connected here are prefixed with '/admin'
$name = Inflector::camelize($controller);
$routes->get(
diff --git a/resources/js/app/app.js b/resources/js/app/app.js
index b9e8c8874..4ec2b2e56 100644
--- a/resources/js/app/app.js
+++ b/resources/js/app/app.js
@@ -75,6 +75,7 @@ const _vueInstance = new Vue({
Permissions:() => import(/* webpackChunkName: "permissions" */'app/components/permissions/permissions'),
PaginationNavigation:() => import(/* webpackChunkName: "pagination-navigation" */'app/components/pagination-navigation/pagination-navigation'),
ObjectsHistory:() => import(/* webpackChunkName: "objects-history" */'app/components/objects-history/objects-history'),
+ SystemInfo:() => import(/* webpackChunkName: "system-info" */'app/components/system-info/system-info'),
UserAccesses:() => import(/* webpackChunkName: "user-accesses" */'app/components/user-accesses/user-accesses'),
Icon,
},
diff --git a/resources/js/app/components/system-info/system-info.vue b/resources/js/app/components/system-info/system-info.vue
new file mode 100644
index 000000000..3f59052b7
--- /dev/null
+++ b/resources/js/app/components/system-info/system-info.vue
@@ -0,0 +1,45 @@
+
+
+
+ {{ key }}:
+ {{ item }}
+
+
+
+
+
diff --git a/src/Controller/Admin/SystemInfoController.php b/src/Controller/Admin/SystemInfoController.php
new file mode 100644
index 000000000..74069e358
--- /dev/null
+++ b/src/Controller/Admin/SystemInfoController.php
@@ -0,0 +1,82 @@
+ for more details.
+ */
+namespace App\Controller\Admin;
+
+use BEdita\SDK\BEditaClientException;
+use Cake\Core\Configure;
+use Cake\Http\Response;
+use Cake\Utility\Hash;
+use Twig\Environment;
+
+/**
+ * System info Controller
+ */
+class SystemInfoController extends AdministrationBaseController
+{
+ /**
+ * @inheritDoc
+ */
+ public function index(): ?Response
+ {
+ $this->set('system_info', $this->getSystemInfo());
+ $this->set('api_info', $this->getApiInfo());
+
+ return null;
+ }
+
+ /**
+ * Get system info.
+ *
+ * @return array
+ */
+ public function getSystemInfo(): array
+ {
+ return [
+ 'Version' => Configure::read('Manager.version'),
+ 'CakePHP' => Configure::version(),
+ 'PHP' => phpversion(),
+ 'Twig' => Environment::VERSION,
+ 'Vuejs' => '',
+ 'Operating System' => php_uname(),
+ 'PHP Server API' => php_sapi_name(),
+ 'Extensions' => get_loaded_extensions(),
+ 'Extensions info' => get_loaded_extensions(true),
+ 'Memory limit' => ini_get('memory_limit'),
+ 'Post max size' => sprintf('%dM', intVal(substr(ini_get('post_max_size'), 0, -1))),
+ 'Upload max size' => sprintf('%dM', intVal(substr(ini_get('upload_max_filesize'), 0, -1))),
+ ];
+ }
+
+ /**
+ * Get api info from API server.
+ *
+ * @return array
+ */
+ public function getApiInfo(): array
+ {
+ $info = [
+ 'Url' => Configure::read('API.apiBaseUrl'),
+ 'Version' => Hash::get((array)$this->viewBuilder()->getVar('project'), 'version'),
+ ];
+ try {
+ $info = (array)Hash::get(
+ $this->apiClient->get('/admin/sysinfo'),
+ 'meta.info'
+ );
+ } catch (BEditaClientException $e) {
+ $this->log($e->getMessage(), 'error');
+ }
+
+ return $info;
+ }
+}
diff --git a/src/View/Helper/LayoutHelper.php b/src/View/Helper/LayoutHelper.php
index 531f9a2f5..b1ce4dbee 100644
--- a/src/View/Helper/LayoutHelper.php
+++ b/src/View/Helper/LayoutHelper.php
@@ -191,6 +191,7 @@ protected function commandLinkClass(): string
'EndpointPermissions' => 'has-background-black',
'Tags' => 'has-background-module-tags',
'ObjectsHistory' => 'has-background-black',
+ 'SystemInfo' => 'has-background-black',
'UserAccesses' => 'has-background-black',
];
diff --git a/templates/Element/Admin/sidebar.twig b/templates/Element/Admin/sidebar.twig
index 8a40f23a1..f5f2ddf99 100644
--- a/templates/Element/Admin/sidebar.twig
+++ b/templates/Element/Admin/sidebar.twig
@@ -1,5 +1,17 @@
{# Append urls to sidebar #}
-{% set actions = ['appearance', 'applications', 'endpoints', 'endpoint_permissions', 'roles', 'roles_modules', 'config', 'async_jobs', 'objects_history', 'user_accesses'] %}
+{% set actions = [
+ 'appearance',
+ 'applications',
+ 'endpoints',
+ 'endpoint_permissions',
+ 'roles',
+ 'roles_modules',
+ 'config',
+ 'async_jobs',
+ 'objects_history',
+ 'user_accesses',
+ 'system_info',
+] %}
{% set controllerAction = _view.request.getparam('controller')|default('') %}
{% for action in actions %}
{% if action == controllerAction|underscore %}
diff --git a/templates/Pages/Admin/SystemInfo/index.twig b/templates/Pages/Admin/SystemInfo/index.twig
new file mode 100644
index 000000000..b7b6b5fa7
--- /dev/null
+++ b/templates/Pages/Admin/SystemInfo/index.twig
@@ -0,0 +1,19 @@
+{{ element('Admin/sidebar') }}
+
+{% do _view.assign('title', __('Administration') ~ ' ' ~ __('System information')) %}
+{% do _view.assign('bodyViewClass', 'view-module view-admin') %}
+
+
BEdita Manager
+
+
+
+
+API
+
+
+
+ {{ __('API could be distributed in multiple nodes. The following data refers to a single node') }}
+
+
+
+
diff --git a/tests/TestCase/Controller/Admin/ConfigControllerTest.php b/tests/TestCase/Controller/Admin/ConfigControllerTest.php
index a3287c24f..e7d5473cf 100644
--- a/tests/TestCase/Controller/Admin/ConfigControllerTest.php
+++ b/tests/TestCase/Controller/Admin/ConfigControllerTest.php
@@ -97,6 +97,6 @@ public function testBeforeFilter(): void
$event = $this->CfgController->dispatchEvent('Controller.beforeFilter');
$this->CfgController->beforeFilter($event);
$viewVars = (array)$this->CfgController->viewBuilder()->getVars();
- static::assertEquals(['' => __('No application'), 1 => 'default-app', 2 => 'manager'], $viewVars['applications']);
+ static::assertContains('manager', $viewVars['applications']);
}
}
diff --git a/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php b/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php
new file mode 100644
index 000000000..7fccfa40b
--- /dev/null
+++ b/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php
@@ -0,0 +1,120 @@
+ [
+ 'REQUEST_METHOD' => 'GET',
+ ],
+ 'params' => [
+ 'resource_type' => 'applications',
+ ],
+ ];
+
+ /**
+ * API client
+ *
+ * @var \BEdita\SDK\BEditaClient
+ */
+ protected $client;
+
+ /**
+ * @inheritDoc
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+
+ $config = array_merge($this->defaultRequestConfig, []);
+ $request = new ServerRequest($config);
+ $this->SystemInfoController = new SystemInfoController($request);
+ $this->client = ApiClientProvider::getApiClient();
+ $adminUser = getenv('BEDITA_ADMIN_USR');
+ $adminPassword = getenv('BEDITA_ADMIN_PWD');
+ $response = $this->client->authenticate($adminUser, $adminPassword);
+ $this->client->setupTokens($response['meta']);
+ }
+
+ /**
+ * Test `index` method
+ *
+ * @return void
+ * @covers ::index()
+ */
+ public function testIndex(): void
+ {
+ $this->SystemInfoController->index();
+ $keys = [
+ 'system_info',
+ 'api_info',
+ ];
+ $viewVars = (array)$this->SystemInfoController->viewBuilder()->getVars();
+ foreach ($keys as $expectedKey) {
+ static::assertArrayHasKey($expectedKey, $viewVars);
+ }
+ }
+
+ /**
+ * Test `getSystemInfo` method
+ *
+ * @return void
+ * @covers ::getSystemInfo()
+ */
+ public function testGetSystemInfo(): void
+ {
+ $expectedKeys = [
+ 'Version',
+ 'CakePHP',
+ 'PHP',
+ 'Twig',
+ 'Vuejs',
+ 'Operating System',
+ 'PHP Server API',
+ 'Extensions',
+ 'Extensions info',
+ 'Memory limit',
+ 'Post max size',
+ 'Upload max size',
+ ];
+ $actual = $this->SystemInfoController->getSystemInfo();
+ foreach ($expectedKeys as $expectedKey) {
+ static::assertArrayHasKey($expectedKey, $actual);
+ }
+ }
+
+ /**
+ * Test `getApiInfo` method
+ *
+ * @return void
+ * @covers ::getApiInfo()
+ */
+ public function testGetApiInfo(): void
+ {
+ $expectedKeys = [
+ 'Url',
+ 'Version',
+ ];
+ $actual = $this->SystemInfoController->getApiInfo();
+ foreach ($expectedKeys as $expectedKey) {
+ static::assertArrayHasKey($expectedKey, $actual);
+ }
+ }
+}