new: [user-settings] Added user settings feature
parent
7ab8a93fbd
commit
39fdb8ec0d
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Migrations\AbstractMigration;
|
||||||
|
use Phinx\Db\Adapter\MysqlAdapter;
|
||||||
|
|
||||||
|
|
||||||
|
class UserSettings extends AbstractMigration
|
||||||
|
{
|
||||||
|
|
||||||
|
public $autoId = false; // turn off automatic `id` column create. We want it to be `int(10) unsigned`
|
||||||
|
|
||||||
|
|
||||||
|
public function change()
|
||||||
|
{
|
||||||
|
$table = $this->table('user_settings', [
|
||||||
|
'signed' => false,
|
||||||
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
|
]);
|
||||||
|
$table
|
||||||
|
->addColumn('id', 'integer', [
|
||||||
|
'autoIncrement' => true,
|
||||||
|
'limit' => 10,
|
||||||
|
'signed' => false,
|
||||||
|
])
|
||||||
|
->addPrimaryKey('id')
|
||||||
|
->addColumn('name', 'string', [
|
||||||
|
'default' => null,
|
||||||
|
'null' => false,
|
||||||
|
'limit' => 255,
|
||||||
|
'comment' => 'The name of the user setting',
|
||||||
|
])
|
||||||
|
->addColumn('value', 'text', [
|
||||||
|
'default' => null,
|
||||||
|
'null' => true,
|
||||||
|
'limit' => MysqlAdapter::TEXT_LONG,
|
||||||
|
'comment' => 'The value of the user setting',
|
||||||
|
])
|
||||||
|
->addColumn('user_id', 'integer', [
|
||||||
|
'default' => null,
|
||||||
|
'null' => true,
|
||||||
|
'signed' => false,
|
||||||
|
'length' => 10,
|
||||||
|
])
|
||||||
|
->addColumn('created', 'datetime', [
|
||||||
|
'default' => null,
|
||||||
|
'null' => false,
|
||||||
|
])
|
||||||
|
->addColumn('modified', 'datetime', [
|
||||||
|
'default' => null,
|
||||||
|
'null' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$table->addForeignKey('user_id', 'users', 'id', ['delete'=> 'CASCADE', 'update'=> 'CASCADE']);
|
||||||
|
|
||||||
|
$table->addIndex('name')
|
||||||
|
->addIndex('user_id')
|
||||||
|
->addIndex('created')
|
||||||
|
->addIndex('modified');
|
||||||
|
|
||||||
|
$table->create();
|
||||||
|
}
|
||||||
|
}
|
|
@ -196,6 +196,7 @@ class CRUDComponent extends Component
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->Controller->entity = $data;
|
||||||
$this->Controller->set('entity', $data);
|
$this->Controller->set('entity', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,6 +318,7 @@ class CRUDComponent extends Component
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->Controller->entity = $data;
|
||||||
$this->Controller->set('entity', $data);
|
$this->Controller->set('entity', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
namespace BreadcrumbNavigation;
|
||||||
|
|
||||||
|
require_once(APP . 'Controller' . DS . 'Component' . DS . 'Navigation' . DS . 'base.php');
|
||||||
|
|
||||||
|
class UserSettingsNavigation extends BaseNavigation
|
||||||
|
{
|
||||||
|
public function addLinks()
|
||||||
|
{
|
||||||
|
$bcf = $this->bcf;
|
||||||
|
$request = $this->request;
|
||||||
|
$this->bcf->addLink('UserSettings', 'index', 'Users', 'view', function ($config) use ($bcf, $request) {
|
||||||
|
if (!empty($request->getQuery('Users_id'))) {
|
||||||
|
$user_id = h($request->getQuery('Users_id'));
|
||||||
|
$linkData = [
|
||||||
|
'label' => __('View user ({0})', h($user_id)),
|
||||||
|
'url' => sprintf('/users/view/%s', h($user_id))
|
||||||
|
];
|
||||||
|
return $linkData;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
$this->bcf->addLink('UserSettings', 'index', 'Users', 'edit', function ($config) use ($bcf, $request) {
|
||||||
|
if (!empty($request->getQuery('Users_id'))) {
|
||||||
|
$user_id = h($request->getQuery('Users_id'));
|
||||||
|
$linkData = [
|
||||||
|
'label' => __('Edit user ({0})', h($user_id)),
|
||||||
|
'url' => sprintf('/users/edit/%s', h($user_id))
|
||||||
|
];
|
||||||
|
return $linkData;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
if (!empty($request->getQuery('Users_id'))) {
|
||||||
|
$this->bcf->addSelfLink('UserSettings', 'index');
|
||||||
|
}
|
||||||
|
if ($this->request->getParam('controller') == 'UserSettings' && $this->request->getParam('action') == 'index') {
|
||||||
|
if (!empty($this->request->getQuery('Users_id'))) {
|
||||||
|
$user_id = $this->request->getQuery('Users_id');
|
||||||
|
$this->bcf->addParent('UserSettings', 'index', 'Users', 'view', [
|
||||||
|
'textGetter' => [
|
||||||
|
'path' => 'username',
|
||||||
|
'varname' => 'settingsForUser',
|
||||||
|
],
|
||||||
|
'url' => "/users/view/{$user_id}"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
namespace BreadcrumbNavigation;
|
||||||
|
|
||||||
|
require_once(APP . 'Controller' . DS . 'Component' . DS . 'Navigation' . DS . 'base.php');
|
||||||
|
|
||||||
|
class UsersNavigation extends BaseNavigation
|
||||||
|
{
|
||||||
|
public function addLinks()
|
||||||
|
{
|
||||||
|
$bcf = $this->bcf;
|
||||||
|
$request = $this->request;
|
||||||
|
$this->bcf->addLink('Users', 'view', 'UserSettings', 'index', function ($config) use ($bcf, $request) {
|
||||||
|
if (!empty($this->passedData[0])) {
|
||||||
|
$user_id = $this->passedData[0];
|
||||||
|
$linkData = [
|
||||||
|
'label' => __('User Setting ({0})', h($user_id)),
|
||||||
|
'url' => sprintf('/user-settings/index?Users.id=%s', h($user_id))
|
||||||
|
];
|
||||||
|
return $linkData;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
$this->bcf->addLink('Users', 'edit', 'UserSettings', 'index', function ($config) use ($bcf, $request) {
|
||||||
|
if (!empty($this->passedData[0])) {
|
||||||
|
$user_id = $this->passedData[0];
|
||||||
|
$linkData = [
|
||||||
|
'label' => __('User Setting ({0})', h($user_id)),
|
||||||
|
'url' => sprintf('/user-settings/index?Users.id=%s', h($user_id))
|
||||||
|
];
|
||||||
|
return $linkData;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ class NavigationComponent extends Component
|
||||||
'Broods' => 'network-wired',
|
'Broods' => 'network-wired',
|
||||||
'Roles' => 'id-badge',
|
'Roles' => 'id-badge',
|
||||||
'Users' => 'users',
|
'Users' => 'users',
|
||||||
|
'UserSettings' => 'user-cog',
|
||||||
'Inbox' => 'inbox',
|
'Inbox' => 'inbox',
|
||||||
'Outbox' => 'inbox',
|
'Outbox' => 'inbox',
|
||||||
'MetaTemplates' => 'object-group',
|
'MetaTemplates' => 'object-group',
|
||||||
|
@ -128,6 +129,7 @@ class NavigationComponent extends Component
|
||||||
'Users',
|
'Users',
|
||||||
'Tags',
|
'Tags',
|
||||||
'LocalTools',
|
'LocalTools',
|
||||||
|
'UserSettings',
|
||||||
];
|
];
|
||||||
foreach ($CRUDControllers as $controller) {
|
foreach ($CRUDControllers as $controller) {
|
||||||
$bcf->setDefaultCRUDForModel($controller);
|
$bcf->setDefaultCRUDForModel($controller);
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Controller\AppController;
|
||||||
|
use Cake\Utility\Hash;
|
||||||
|
use Cake\Utility\Text;
|
||||||
|
use \Cake\Database\Expression\QueryExpression;
|
||||||
|
use Cake\Http\Exception\NotFoundException;
|
||||||
|
use Cake\Http\Exception\MethodNotAllowedException;
|
||||||
|
use Cake\Http\Exception\ForbiddenException;
|
||||||
|
|
||||||
|
class UserSettingsController extends AppController
|
||||||
|
{
|
||||||
|
public $quickFilterFields = [['name' => true], ['value' => true]];
|
||||||
|
public $filterFields = ['name', 'value', 'Users.id'];
|
||||||
|
public $containFields = ['Users'];
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$conditions = [];
|
||||||
|
$this->CRUD->index([
|
||||||
|
'conditions' => [],
|
||||||
|
'contain' => $this->containFields,
|
||||||
|
'filters' => $this->filterFields,
|
||||||
|
'quickFilters' => $this->quickFilterFields,
|
||||||
|
]);
|
||||||
|
$responsePayload = $this->CRUD->getResponsePayload();
|
||||||
|
if (!empty($responsePayload)) {
|
||||||
|
return $responsePayload;
|
||||||
|
}
|
||||||
|
if (!empty($this->request->getQuery('Users_id'))) {
|
||||||
|
$settingsForUser = $this->UserSettings->Users->find()->where([
|
||||||
|
'id' => $this->request->getQuery('Users_id')
|
||||||
|
])->first();
|
||||||
|
$this->set('settingsForUser', $settingsForUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add($user_id = false)
|
||||||
|
{
|
||||||
|
$this->CRUD->add([
|
||||||
|
'redirect' => ['action' => 'index', $user_id],
|
||||||
|
'beforeSave' => function($data) use ($user_id) {
|
||||||
|
$data['user_id'] = $user_id;
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
$responsePayload = $this->CRUD->getResponsePayload();
|
||||||
|
if (!empty($responsePayload)) {
|
||||||
|
return $responsePayload;
|
||||||
|
}
|
||||||
|
$dropdownData = [
|
||||||
|
'user' => $this->UserSettings->Users->find('list', [
|
||||||
|
'sort' => ['username' => 'asc']
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
$this->set(compact('dropdownData'));
|
||||||
|
$this->set('user_id', $user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit($id)
|
||||||
|
{
|
||||||
|
$entity = $this->UserSettings->find()->where([
|
||||||
|
'id' => $id
|
||||||
|
])->first();
|
||||||
|
$entity = $this->CRUD->edit($id, [
|
||||||
|
'redirect' => ['action' => 'index', $entity->user_id]
|
||||||
|
]);
|
||||||
|
$responsePayload = $this->CRUD->getResponsePayload();
|
||||||
|
if (!empty($responsePayload)) {
|
||||||
|
return $responsePayload;
|
||||||
|
}
|
||||||
|
$dropdownData = [
|
||||||
|
'user' => $this->UserSettings->Users->find('list', [
|
||||||
|
'sort' => ['username' => 'asc']
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
$this->set(compact('dropdownData'));
|
||||||
|
$this->set('user_id', $this->entity->user_id);
|
||||||
|
$this->render('add');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete($id)
|
||||||
|
{
|
||||||
|
$this->CRUD->delete($id);
|
||||||
|
$responsePayload = $this->CRUD->getResponsePayload();
|
||||||
|
if (!empty($responsePayload)) {
|
||||||
|
return $responsePayload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ class UsersController extends AppController
|
||||||
{
|
{
|
||||||
public $filterFields = ['Individuals.uuid', 'username', 'Individuals.email', 'Individuals.first_name', 'Individuals.last_name'];
|
public $filterFields = ['Individuals.uuid', 'username', 'Individuals.email', 'Individuals.first_name', 'Individuals.last_name'];
|
||||||
public $quickFilterFields = ['Individuals.uuid', ['username' => true], ['Individuals.first_name' => true], ['Individuals.last_name' => true], 'Individuals.email'];
|
public $quickFilterFields = ['Individuals.uuid', ['username' => true], ['Individuals.first_name' => true], ['Individuals.last_name' => true], 'Individuals.email'];
|
||||||
public $containFields = ['Individuals', 'Roles'];
|
public $containFields = ['Individuals', 'Roles', 'UserSettings'];
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Model\Entity;
|
||||||
|
|
||||||
|
use App\Model\Entity\AppModel;
|
||||||
|
|
||||||
|
class UserSetting extends AppModel
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Model\Table;
|
||||||
|
|
||||||
|
use App\Model\Table\AppTable;
|
||||||
|
use Cake\ORM\Table;
|
||||||
|
use Cake\Validation\Validator;
|
||||||
|
|
||||||
|
class UserSettingsTable extends AppTable
|
||||||
|
{
|
||||||
|
public function initialize(array $config): void
|
||||||
|
{
|
||||||
|
parent::initialize($config);
|
||||||
|
$this->addBehavior('Timestamp');
|
||||||
|
$this->belongsTo(
|
||||||
|
'Users'
|
||||||
|
);
|
||||||
|
$this->setDisplayField('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validationDefault(Validator $validator): Validator
|
||||||
|
{
|
||||||
|
$validator
|
||||||
|
->requirePresence(['name', 'user_id'], 'create')
|
||||||
|
->notEmptyString('name', __('Please fill this field'))
|
||||||
|
->notEmptyString('user_id', __('Please supply the user id to which this setting belongs to'));
|
||||||
|
return $validator;
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,13 @@ class UsersTable extends AppTable
|
||||||
'cascadeCallbacks' => false
|
'cascadeCallbacks' => false
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
$this->hasMany(
|
||||||
|
'UserSettings',
|
||||||
|
[
|
||||||
|
'dependent' => true,
|
||||||
|
'cascadeCallbacks' => true
|
||||||
|
]
|
||||||
|
);
|
||||||
$this->setDisplayField('username');
|
$this->setDisplayField('username');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
echo $this->element('genericElements/Form/genericForm', [
|
||||||
|
'data' => [
|
||||||
|
'description' => __('User settings are used to register setting tied to user profile.'),
|
||||||
|
'model' => 'UserSettings',
|
||||||
|
'fields' => [
|
||||||
|
[
|
||||||
|
'field' => 'user_id',
|
||||||
|
'type' => 'dropdown',
|
||||||
|
'label' => __('User'),
|
||||||
|
'options' => $dropdownData['user'],
|
||||||
|
'value' => !empty($user_id) ? $user_id : '',
|
||||||
|
'disabled' => !empty($user_id),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'field' => 'name',
|
||||||
|
'label' => __('Setting Name'),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'field' => 'value',
|
||||||
|
'label' => __('Setting Value'),
|
||||||
|
'type' => 'codemirror',
|
||||||
|
'codemirror' => [
|
||||||
|
'height' => '10rem',
|
||||||
|
'mode' => [
|
||||||
|
'name' => 'text',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'submit' => [
|
||||||
|
'action' => $this->request->getParam('action')
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
?>
|
||||||
|
</div>
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
$title = __('User Setting index');
|
||||||
|
if (!empty($settingsForUser)) {
|
||||||
|
$title .= __(' of {0}', $settingsForUser->username);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $this->element('genericElements/IndexTable/index_table', [
|
||||||
|
'data' => [
|
||||||
|
'data' => $data,
|
||||||
|
'top_bar' => [
|
||||||
|
'children' => [
|
||||||
|
[
|
||||||
|
'type' => 'simple',
|
||||||
|
'children' => [
|
||||||
|
'data' => [
|
||||||
|
'type' => 'simple',
|
||||||
|
'text' => __('Add Setting'),
|
||||||
|
'class' => 'btn btn-primary',
|
||||||
|
'popover_url' => sprintf('/userSettings/add/%s', h($this->request->getQuery('Users_id')))
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => 'search',
|
||||||
|
'button' => __('Filter'),
|
||||||
|
'placeholder' => __('Enter value to search'),
|
||||||
|
'data' => '',
|
||||||
|
'searchKey' => 'value'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'fields' => [
|
||||||
|
[
|
||||||
|
'name' => '#',
|
||||||
|
'sort' => 'id',
|
||||||
|
'data_path' => 'id',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => __('User'),
|
||||||
|
'sort' => 'user.username',
|
||||||
|
'data_path' => 'user.username',
|
||||||
|
'url' => '/users/view/{{0}}',
|
||||||
|
'url_vars' => ['user.id']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => __('Setting Name'),
|
||||||
|
'sort' => 'name',
|
||||||
|
'data_path' => 'name',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => __('Setting Value'),
|
||||||
|
'sort' => 'value',
|
||||||
|
'data_path' => 'value',
|
||||||
|
'class' => 'font-monospace'
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'title' => $title,
|
||||||
|
'description' => __('The list of user settings in this Cerebrate instance. All users can have setting tied to their user profile.'),
|
||||||
|
'actions' => [
|
||||||
|
[
|
||||||
|
'open_modal' => '/userSettings/edit/[onclick_params_data_path]',
|
||||||
|
'modal_params_data_path' => 'id',
|
||||||
|
'icon' => 'edit'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'open_modal' => '/userSettings/delete/[onclick_params_data_path]',
|
||||||
|
'modal_params_data_path' => 'id',
|
||||||
|
'icon' => 'trash'
|
||||||
|
],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
echo '</div>';
|
||||||
|
?>
|
|
@ -75,6 +75,13 @@ echo $this->element('genericElements/IndexTable/index_table', [
|
||||||
'url' => '/roles/view/{{0}}',
|
'url' => '/roles/view/{{0}}',
|
||||||
'url_vars' => ['role.id']
|
'url_vars' => ['role.id']
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'name' => __('# User Settings'),
|
||||||
|
'element' => 'count_summary',
|
||||||
|
'data_path' => 'user_settings',
|
||||||
|
'url' => '/user-settings/index?Users.id={{url_data}}',
|
||||||
|
'url_data_path' => 'id'
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'title' => __('User index'),
|
'title' => __('User index'),
|
||||||
'description' => __('The list of enrolled users in this Cerebrate instance. All of the users have or at one point had access to the system.'),
|
'description' => __('The list of enrolled users in this Cerebrate instance. All of the users have or at one point had access to the system.'),
|
||||||
|
|
|
@ -51,6 +51,11 @@ echo $this->element(
|
||||||
'url' => '/EncryptionKeys/index?Users.id={{0}}',
|
'url' => '/EncryptionKeys/index?Users.id={{0}}',
|
||||||
'url_params' => ['id'],
|
'url_params' => ['id'],
|
||||||
'title' => __('Encryption keys')
|
'title' => __('Encryption keys')
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'url' => '/UserSettings/index?Users.id={{0}}',
|
||||||
|
'url_params' => ['id'],
|
||||||
|
'title' => __('User settings')
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
$controlParams = [
|
$controlParams = [
|
||||||
'options' => $fieldData['options'],
|
'options' => $fieldData['options'],
|
||||||
'empty' => $fieldData['empty'] ?? false,
|
'empty' => $fieldData['empty'] ?? false,
|
||||||
|
'value' => $fieldData['value'] ?? [],
|
||||||
|
'multiple' => $fieldData['multiple'] ?? false,
|
||||||
|
'disabled' => $fieldData['disabled'] ?? false,
|
||||||
'class' => ($fieldData['class'] ?? '') . ' formDropdown form-select'
|
'class' => ($fieldData['class'] ?? '') . ' formDropdown form-select'
|
||||||
];
|
];
|
||||||
echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData);
|
echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData);
|
||||||
|
|
|
@ -19,7 +19,7 @@ use Cake\Routing\Router;
|
||||||
<i class="me-1 <?= $this->FontAwesome->getClass('user-circle') ?>"></i>
|
<i class="me-1 <?= $this->FontAwesome->getClass('user-circle') ?>"></i>
|
||||||
<?= __('My Account') ?>
|
<?= __('My Account') ?>
|
||||||
</a>
|
</a>
|
||||||
<a class="dropdown-item" href="<?= Router::url(['controller' => 'users', 'action' => 'userSettings', 'plugin' => null]) ?>">
|
<a class="dropdown-item" href="<?= Router::url(['controller' => 'user-settings', 'action' => 'index', 'plugin' => null, '?' => ['Users.id' => h($this->request->getAttribute('identity')['id'])]]) ?>">
|
||||||
<i class="me-1 <?= $this->FontAwesome->getClass('user-cog') ?>"></i>
|
<i class="me-1 <?= $this->FontAwesome->getClass('user-cog') ?>"></i>
|
||||||
<?= __('Settings') ?>
|
<?= __('Settings') ?>
|
||||||
</a>
|
</a>
|
||||||
|
|
Loading…
Reference in New Issue