diff --git a/src/Controller/Component/ACLComponent.php b/src/Controller/Component/ACLComponent.php
index a1f06ea..fc8966c 100644
--- a/src/Controller/Component/ACLComponent.php
+++ b/src/Controller/Component/ACLComponent.php
@@ -811,6 +811,10 @@ class ACLComponent extends Component
__('Instance'),
'url' => '/instance/home',
'children' => [
+ 'settings' => [
+ 'url' => '/instance/settings',
+ 'label' => __('Settings')
+ ],
'migration' => [
'url' => '/instance/migrationIndex',
'label' => __('Database migration')
diff --git a/src/Controller/InstanceController.php b/src/Controller/InstanceController.php
index 074e59a..11ea1c9 100644
--- a/src/Controller/InstanceController.php
+++ b/src/Controller/InstanceController.php
@@ -108,6 +108,7 @@ class InstanceController extends AppController
$all = $this->Settings->getSettings(true);
$this->set('settingsProvider', $all['settingsProvider']);
$this->set('settings', $all['settings']);
+ $this->set('settingsFlattened', $all['settingsFlattened']);
$this->set('notices', $all['notices']);
}
}
diff --git a/src/Model/Table/SettingsProviderTable.php b/src/Model/Table/SettingsProviderTable.php
index ccc3eba..acede80 100644
--- a/src/Model/Table/SettingsProviderTable.php
+++ b/src/Model/Table/SettingsProviderTable.php
@@ -44,20 +44,37 @@ class SettingsProviderTable extends AppTable
* @param array $settings the settings
* @return void
*/
- private function mergeSettingsIntoSettingConfiguration(array $settingConf, array $settings): array
+ private function mergeSettingsIntoSettingConfiguration(array $settingConf, array $settings, string $path=''): array
{
foreach ($settingConf as $key => $value) {
if ($this->isLeaf($value)) {
if (isset($settings[$key])) {
$settingConf[$key]['value'] = $settings[$key];
}
+ if (empty($settingConf[$key]['severity'])) {
+ $settingConf[$key]['severity'] = 'warning';
+ }
$settingConf[$key] = $this->evaluateLeaf($settingConf[$key], $settingConf);
+ $settingConf[$key]['setting-path'] = $path;
} else {
- $settingConf[$key] = $this->mergeSettingsIntoSettingConfiguration($value, $settings);
+ $currentPath = empty($path) ? $key : sprintf('%s.%s', $path, $key);
+ $settingConf[$key] = $this->mergeSettingsIntoSettingConfiguration($value, $settings, $currentPath);
}
}
return $settingConf;
}
+
+ public function flattenSettingsConfiguration(array $settingsProvider, $flattenedSettings=[]): array
+ {
+ foreach ($settingsProvider as $key => $value) {
+ if ($this->isLeaf($value)) {
+ $flattenedSettings[$key] = $value;
+ } else {
+ $flattenedSettings = $this->flattenSettingsConfiguration($value, $flattenedSettings);
+ }
+ }
+ return $flattenedSettings;
+ }
/**
* getNoticesFromSettingsConfiguration Summarize the validation errors
@@ -175,14 +192,14 @@ class SettingsProviderTable extends AppTable
'description' => 'to del',
'errorMessage' => 'to del',
'default' => '',
- 'name' => 'To DEL',
+ 'name' => 'To DEL 2',
'type' => 'string'
],
'to-del3' => [
'description' => 'to del',
'errorMessage' => 'to del',
'default' => '',
- 'name' => 'To DEL',
+ 'name' => 'To DEL 2',
'type' => 'string'
],
],
@@ -227,36 +244,6 @@ class SettingsProviderTable extends AppTable
'type' => 'string',
],
],
- 'Proxy2' => [
- 'host' => [
- 'description' => __('The hostname of an HTTP proxy for outgoing sync requests. Leave empty to not use a proxy.'),
- 'default' => '',
- 'name' => __('Host'),
- 'test' => 'testHostname',
- 'type' => 'string',
- ],
- 'port' => [
- 'description' => __('The TCP port for the HTTP proxy.'),
- 'default' => '',
- 'name' => __('Port'),
- 'test' => 'testForRangeXY',
- 'type' => 'integer',
- ],
- 'user' => [
- 'description' => __('The authentication username for the HTTP proxy.'),
- 'default' => '',
- 'name' => __('User'),
- 'test' => 'testEmptyBecomesDefault',
- 'type' => 'string',
- ],
- 'password' => [
- 'description' => __('The authentication password for the HTTP proxy.'),
- 'default' => '',
- 'name' => __('Password'),
- 'test' => 'testEmptyBecomesDefault',
- 'type' => 'string',
- ],
- ],
],
'UI' => [
'app.ui.dark' => [
@@ -268,6 +255,40 @@ class SettingsProviderTable extends AppTable
],
],
'Security' => [
+ 'Network' => [
+ 'Proxy Test' => [
+ 'proxy-test.host' => [
+ 'description' => __('The hostname of an HTTP proxy for outgoing sync requests. Leave empty to not use a proxy.'),
+ 'default' => '',
+ 'name' => __('Host'),
+ 'test' => 'testHostname',
+ 'type' => 'string',
+ ],
+ 'proxy-test.port' => [
+ 'description' => __('The TCP port for the HTTP proxy.'),
+ 'default' => '',
+ 'name' => __('Port'),
+ 'test' => 'testForRangeXY',
+ 'type' => 'integer',
+ ],
+ 'proxy-test.user' => [
+ 'description' => __('The authentication username for the HTTP proxy.'),
+ 'default' => '',
+ 'dependsOn' => 'host',
+ 'name' => __('User'),
+ 'test' => 'testEmptyBecomesDefault',
+ 'type' => 'string',
+ ],
+ 'proxy-test.password' => [
+ 'description' => __('The authentication password for the HTTP proxy.'),
+ 'default' => '',
+ 'dependsOn' => 'host',
+ 'name' => __('Password'),
+ 'test' => 'testEmptyBecomesDefault',
+ 'type' => 'string',
+ ],
+ ],
+ ]
],
'Features' => [
],
diff --git a/src/Model/Table/SettingsTable.php b/src/Model/Table/SettingsTable.php
index ac79cc7..7a7d130 100644
--- a/src/Model/Table/SettingsTable.php
+++ b/src/Model/Table/SettingsTable.php
@@ -23,10 +23,12 @@ class SettingsTable extends AppTable
return $settings;
} else {
$settingsProvider = $this->SettingsProvider->getSettingsConfiguration($settings);
+ $settingsFlattened = $this->SettingsProvider->flattenSettingsConfiguration($settingsProvider);
$notices = $this->SettingsProvider->getNoticesFromSettingsConfiguration($settingsProvider, $settings);
return [
'settings' => $settings,
'settingsProvider' => $settingsProvider,
+ 'settingsFlattened' => $settingsFlattened,
'notices' => $notices,
];
}
diff --git a/templates/Instance/settings.php b/templates/Instance/settings.php
index daea2bf..07d963b 100644
--- a/templates/Instance/settings.php
+++ b/templates/Instance/settings.php
@@ -17,15 +17,20 @@ $headingPerLevel = [
'warning' => __('Warning settings'),
'info' => __('Info settings'),
];
+$variantFromSeverity = [
+ 'critical' => 'danger',
+ 'warning' => 'warning',
+ 'info' => 'info',
+];
+$this->set('variantFromSeverity', $variantFromSeverity);
-$settingTable = genLevel0($settingsProvider, $this);
$alertVariant = 'info';
$alertBody = '';
$skipHeading = false;
$tableItems = [];
foreach (array_keys($mainNoticeHeading) as $level) {
if(!empty($notices[$level])) {
- $variant = $level == 'critical' ? 'danger' : $level;
+ $variant = $variantFromSeverity[$level];
if (!$skipHeading) {
$alertBody .= sprintf('
%s
', $mainNoticeHeading[$level]);
$alertVariant = $variant;
@@ -60,16 +65,17 @@ $alertBody .= $this->Bootstrap->table([
'items' => $tableItems,
]);
$settingNotice = $this->Bootstrap->alert([
+ 'dismissible' => false,
'variant' => $alertVariant,
'html' => $alertBody
]);
+$settingNotice = sprintf('%s
', $settingNotice);
+$this->set('settingNotice', $settingNotice);
+$settingTable = genLevel0($settingsProvider, $this);
?>
-
- = $settingNotice ?>
-
-
+
= $settingTable; ?>
@@ -86,13 +92,15 @@ function genLevel0($settingsProvider, $appView)
$content0[] = __('No Settings available yet');
}
}
+ array_unshift($level0, __('Setting Diagnostic'));
+ array_unshift($content0, $appView->get('settingNotice'));
$tabsOptions0 = [
// 'vertical' => true,
// 'vertical-size' => 2,
'card' => false,
'pills' => false,
'justify' => 'center',
- 'content-class' => [''],
+ 'nav-class' => ['settings-tabs'],
'data' => [
'navs' => $level0,
'content' => $content0
@@ -124,7 +132,7 @@ function genLevel1($level1Setting, $appView)
$mainPanelHeight = 'calc(100vh - 8px - 42px - 1rem - 56px - 38px - 1rem)';
$container = '';
$container .= "
{$scrollspyNav}
";
- $container .= "
{$contentHtml}
";
+ $container .= "
{$contentHtml}
";
$container .= '
';
return $container;
}
@@ -151,12 +159,28 @@ function genLevel3($level2Name, $settingGroupName, $setting, $appView)
} else {
$tmpID = sprintf('sp-%s-%s', h($level2Name), h($settingGroupName));
$settingGroup .= sprintf('', $tmpID, $tmpID, h($settingGroupName));
+ $groupIssueSeverity = false;
foreach ($setting as $singleSettingName => $singleSetting) {
$tmp = genSingleSetting($singleSettingName, $singleSetting, $appView);
$settingGroup .= sprintf('%s
', $tmp);
+ if (!empty($singleSetting['error'])) {
+ $settingVariant = $appView->get('variantFromSeverity')[$singleSetting['severity']];
+ if ($groupIssueSeverity != 'danger') {
+ if ($groupIssueSeverity != 'warning') {
+ $groupIssueSeverity = $settingVariant;
+ }
+ }
+ }
}
$settingGroup = $appView->Bootstrap->genNode('div', [
- 'class' => ['shadow', 'p-2', 'mb-4', 'rounded', ($appView->get('darkMode') ? 'bg-dark' : 'bg-light')],
+ 'class' => [
+ 'shadow',
+ 'p-2',
+ 'mb-4',
+ 'rounded',
+ (!empty($groupIssueSeverity) ? "callout callout-${groupIssueSeverity}" : ''),
+ ($appView->get('darkMode') ? 'bg-dark' : 'bg-light')
+ ],
], $settingGroup);
}
return $settingGroup;
@@ -175,23 +199,22 @@ function genSingleSetting($settingName, $setting, $appView)
'title' => __('This setting depends on the validity of: {0}', h($setting['dependsOn']))
]));
}
+ $settingId = str_replace('.', '_', $settingName);
$label = $appView->Bootstrap->genNode('label', [
'class' => ['font-weight-bolder', 'mb-0'],
- 'for' => $settingName
+ 'for' => $settingId
], h($setting['name']) . $dependsOnHtml);
$description = '';
if (!empty($setting['description'])) {
$description = $appView->Bootstrap->genNode('small', [
'class' => ['form-text', 'text-muted', 'mt-0'],
- 'id' => "{$settingName}Help"
+ 'id' => "{$settingId}Help"
], h($setting['description']));
}
$error = '';
if (!empty($setting['error'])) {
$textColor = '';
- if ($setting['severity'] != 'critical') {
- $textColor = "text-{$setting['severity']}";
- }
+ $textColor = "text-{$appView->get('variantFromSeverity')[$setting['severity']]}";
$error = $appView->Bootstrap->genNode('div', [
'class' => ['d-block', 'invalid-feedback', $textColor],
], h($setting['errorMessage']));
@@ -200,18 +223,18 @@ function genSingleSetting($settingName, $setting, $appView)
$setting['type'] = 'string';
}
if ($setting['type'] == 'string') {
- $input = genInputString($settingName, $setting, $appView);
+ $input = genInputString($settingId, $setting, $appView);
} elseif ($setting['type'] == 'boolean') {
- $input = genInputCheckbox($settingName, $setting, $appView);
+ $input = genInputCheckbox($settingId, $setting, $appView);
$description = '';
} elseif ($setting['type'] == 'integer') {
- $input = genInputInteger($settingName, $setting, $appView);
+ $input = genInputInteger($settingId, $setting, $appView);
} elseif ($setting['type'] == 'select') {
- $input = genInputSelect($settingName, $setting, $appView);
+ $input = genInputSelect($settingId, $setting, $appView);
} elseif ($setting['type'] == 'multi-select') {
- $input = genInputMultiSelect($settingName, $setting, $appView);
+ $input = genInputMultiSelect($settingId, $setting, $appView);
} else {
- $input = genInputString($settingName, $setting, $appView);
+ $input = genInputString($settingId, $setting, $appView);
}
$container = $appView->Bootstrap->genNode('div', [
'class' => ['form-group', 'mb-2']
@@ -219,23 +242,24 @@ function genSingleSetting($settingName, $setting, $appView)
return $container;
}
-function genInputString($settingName, $setting, $appView)
+function genInputString($settingId, $setting, $appView)
{
- // debug($setting);
return $appView->Bootstrap->genNode('input', [
'class' => [
'form-control',
+ "xxx-{$appView->get('variantFromSeverity')[$setting['severity']]} yyy-{$setting['severity']}",
(!empty($setting['error']) ? 'is-invalid' : ''),
- (!empty($setting['error']) ? ($setting['severity'] != 'critical' ? "border-{$setting['severity']} warning" : '') : ''),
+ (!empty($setting['error']) ? "border-{$appView->get('variantFromSeverity')[$setting['severity']]}" : ''),
+ (!empty($setting['error']) && $setting['severity'] == 'warning' ? 'warning' : ''),
],
'type' => 'text',
- 'id' => $settingName,
+ 'id' => $settingId,
'value' => isset($setting['value']) ? $setting['value'] : "",
'placeholder' => $setting['default'] ?? '',
- 'aria-describedby' => "{$settingName}Help"
+ 'aria-describedby' => "{$settingId}Help"
]);
}
-function genInputCheckbox($settingName, $setting, $appView)
+function genInputCheckbox($settingId, $setting, $appView)
{
$switch = $appView->Bootstrap->genNode('input', [
'class' => [
@@ -244,13 +268,13 @@ function genInputCheckbox($settingName, $setting, $appView)
'type' => 'checkbox',
'value' => !empty($setting['value']) ? 1 : 0,
'checked' => !empty($setting['value']) ? 'checked' : '',
- 'id' => $settingName,
+ 'id' => $settingId,
]);
$label = $appView->Bootstrap->genNode('label', [
'class' => [
'custom-control-label'
],
- 'for' => $settingName,
+ 'for' => $settingId,
], h($setting['description']));
$container = $appView->Bootstrap->genNode('div', [
'class' => [
@@ -260,23 +284,23 @@ function genInputCheckbox($settingName, $setting, $appView)
], implode('', [$switch, $label]));
return $container;
}
-function genInputInteger($settingName, $setting, $appView)
+function genInputInteger($settingId, $setting, $appView)
{
return $appView->Bootstrap->genNode('input', [
'class' => [
'form-control'
],
- 'params' => [
- 'type' => 'integer',
- 'id' => $settingName,
- 'aria-describedby' => "{$settingName}Help"
- ]
+ 'type' => 'number',
+ 'min' => '0',
+ 'step' => 1,
+ 'id' => $settingId,
+ 'aria-describedby' => "{$settingId}Help"
]);
}
-function genInputSelect($settingName, $setting, $appView)
+function genInputSelect($settingId, $setting, $appView)
{
}
-function genInputMultiSelect($settingName, $setting, $appView)
+function genInputMultiSelect($settingId, $setting, $appView)
{
}
@@ -304,7 +328,21 @@ function isLeaf($setting)
?>
+
\ No newline at end of file
diff --git a/templates/layout/default.php b/templates/layout/default.php
index cc8c564..1e2cbde 100644
--- a/templates/layout/default.php
+++ b/templates/layout/default.php
@@ -41,6 +41,7 @@ $cakeDescription = 'Cerebrate';
= $this->Html->script('main.js') ?>
= $this->Html->script('bootstrap-helper.js') ?>
= $this->Html->script('api-helper.js') ?>
+ = $this->Html->script('select2.min.js') ?>
= $this->Html->script('CodeMirror/codemirror.js') ?>
= $this->Html->script('CodeMirror/mode/javascript/javascript') ?>
= $this->Html->script('CodeMirror/addon/hint/show-hint') ?>
@@ -53,6 +54,8 @@ $cakeDescription = 'Cerebrate';
= $this->Html->css('CodeMirror/codemirror-additional') ?>
= $this->Html->css('CodeMirror/addon/hint/show-hint') ?>
= $this->Html->css('CodeMirror/addon/lint/lint') ?>
+ = $this->Html->css('select2.min') ?>
+ = $this->Html->css('select2-bootstrap4.min') ?>
= $this->fetch('meta') ?>
= $this->fetch('css') ?>
= $this->fetch('script') ?>
@@ -83,5 +86,6 @@ $cakeDescription = 'Cerebrate';