Repo Interface für tests
This commit is contained in:
@@ -112,229 +112,72 @@ require templatePath('partials/app-list-filters.phtml');
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<script src="<?php e(asset('vendor/gridjs/gridjs.umd.js')); ?>"></script>
|
||||
<script src="<?php e(asset('vendor/gridjs/plugins/selection/selection.umd.js')); ?>"></script>
|
||||
<script type="module">
|
||||
import { initStandardListPage } from "<?php e(assetVersion('js/core/app-grid-factory.js')); ?>";
|
||||
import { initUsersListPage } from "<?php e(assetVersion('js/pages/app-users-list.js')); ?>";
|
||||
import { bindBulkVisibility } from "<?php e(assetVersion('js/components/app-bulk-selection.js')); ?>";
|
||||
import { buildUrl, badgeHtml, getAppBase, escapeHtml, buildBadgeList } from "<?php e(assetVersion('js/pages/app-list-utils.js')); ?>";
|
||||
import { showAsyncFlash, withLoading } from "<?php e(assetVersion('js/components/app-async-flash.js')); ?>";
|
||||
const appBase = getAppBase();
|
||||
const gridSearch = <?php gridJsonForJs($searchConfig); ?>;
|
||||
const filterSchema = <?php gridJsonForJs($clientFilterSchema); ?>;
|
||||
const usersFilterChipMeta = <?php gridJsonForJs($filterChipMeta); ?>;
|
||||
const currentUserUuid = "<?php e($currentUserUuid); ?>";
|
||||
const canUpdateUsers = <?php e($canUpdateUsers ? 'true' : 'false'); ?>;
|
||||
const canUpdateSelf = <?php e($canUpdateSelf ? 'true' : 'false'); ?>;
|
||||
const csrf = <?php MintyPHP\Buffer::get('grid_csrf'); ?>;
|
||||
const labels = {
|
||||
active: "<?php e(t('Active')); ?>",
|
||||
inactive: "<?php e(t('Inactive')); ?>",
|
||||
never: "<?php e(t('Never')); ?>",
|
||||
bulkActivateConfirm: "<?php e(t('Activate users?')); ?>",
|
||||
bulkDeactivateConfirm: "<?php e(t('Deactivate users?')); ?>",
|
||||
bulkDeleteConfirm: "<?php e(t('Delete users?')); ?>",
|
||||
bulkSendAccessConfirm: "<?php e(t('Send access emails to selected users?')); ?>",
|
||||
bulkAccessPdfConfirm: "<?php e(t('Generate access PDFs for selected users?')); ?>",
|
||||
primaryTenant: "<?php e(t('Primary tenant')); ?>",
|
||||
bulkMessages: {
|
||||
'activate': {
|
||||
success: "<?php e(t('%d users activated')); ?>",
|
||||
error: "<?php e(t('Failed to activate users')); ?>"
|
||||
},
|
||||
'deactivate': {
|
||||
success: "<?php e(t('%d users deactivated')); ?>",
|
||||
error: "<?php e(t('Failed to deactivate users')); ?>"
|
||||
},
|
||||
'delete': {
|
||||
success: "<?php e(t('%d users deleted')); ?>",
|
||||
error: "<?php e(t('Failed to delete users')); ?>"
|
||||
},
|
||||
'send-access': {
|
||||
success: "<?php e(t('Access emails sent to %d users')); ?>",
|
||||
partial: "<?php e(t('Access emails sent to %d users, %f failed')); ?>",
|
||||
error: "<?php e(t('Failed to send access emails')); ?>"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const buildBulkUrl = (action) => buildUrl(appBase, `admin/users/bulk/${action}`);
|
||||
|
||||
const initUsersGrid = () => {
|
||||
const rowSelection = window.gridjs?.plugins?.selection?.RowSelection;
|
||||
if (!rowSelection) {
|
||||
throw new Error('Grid.js RowSelection plugin is not available.');
|
||||
}
|
||||
const activeIndex = 6;
|
||||
const uuidIndex = 2;
|
||||
const canEditRow = (row) => {
|
||||
const uuid = row?.cells?.[uuidIndex]?.data;
|
||||
if (!uuid) return false;
|
||||
if (uuid === currentUserUuid) {
|
||||
return canUpdateUsers || canUpdateSelf;
|
||||
}
|
||||
return canUpdateUsers;
|
||||
};
|
||||
|
||||
const initialsForRow = (row) => {
|
||||
const first = row?.cells?.[3]?.data ?? '';
|
||||
const last = row?.cells?.[4]?.data ?? '';
|
||||
const parts = [first, last]
|
||||
.map((value) => String(value || '').trim())
|
||||
.filter(Boolean);
|
||||
const chars = parts.map((value) => value[0] || '').join('').toUpperCase();
|
||||
return chars || '?';
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "<?php e(t('Avatar')); ?>",
|
||||
sort: false,
|
||||
formatter: (cell, row) => {
|
||||
if (!cell) {
|
||||
const initials = escapeHtml(initialsForRow(row));
|
||||
return gridjs.html(`<span class="grid-avatar grid-avatar-placeholder">${initials}</span>`);
|
||||
}
|
||||
const src = new URL(`admin/users/avatar-file?uuid=${cell}&size=64`, appBase).toString();
|
||||
const full = new URL(`admin/users/avatar-file?uuid=${cell}&size=256`, appBase).toString();
|
||||
return gridjs.html(`<a data-fslightbox="user-avatars" href="${full}"><img class="grid-avatar" src="${src}" alt="" loading="lazy"></a>`);
|
||||
}
|
||||
},
|
||||
{ name: 'UUID', hidden: true },
|
||||
{ name: "<?php e(t('First name')); ?>", sort: true },
|
||||
{ name: "<?php e(t('Last name')); ?>", sort: true },
|
||||
{ name: "<?php e(t('Email')); ?>", sort: true },
|
||||
{
|
||||
name: "<?php e(t('State')); ?>",
|
||||
sort: true,
|
||||
formatter: (cell) => cell
|
||||
? gridjs.html(`<span class="badge" data-variant="success">${labels.active}</span>`)
|
||||
: gridjs.html(`<span class="badge" data-variant="danger">${labels.inactive}</span>`)
|
||||
},
|
||||
{
|
||||
name: "<?php e(t('Tenants')); ?>",
|
||||
sort: false,
|
||||
formatter: (cell) => gridjs.html(buildBadgeList(cell, { primaryTooltip: labels.primaryTenant }))
|
||||
},
|
||||
{ name: "<?php e(t('Departments')); ?>", sort: false, formatter: (cell) => gridjs.html(buildBadgeList(cell)) },
|
||||
{ name: "<?php e(t('Roles')); ?>", sort: false, formatter: (cell) => gridjs.html(buildBadgeList(cell)) },
|
||||
{ name: "<?php e(t('Phone')); ?>", sort: false },
|
||||
{ name: "<?php e(t('Mobile')); ?>", sort: false },
|
||||
{ name: "<?php e(t('Short dial')); ?>", sort: false },
|
||||
{ name: "<?php e(t('Created')); ?>", sort: true, formatter: (cell) => badgeHtml(gridjs, cell) },
|
||||
{ name: "<?php e(t('Modified')); ?>", sort: true, formatter: (cell) => badgeHtml(gridjs, cell) },
|
||||
{
|
||||
name: "<?php e(t('Last login')); ?>",
|
||||
sort: true,
|
||||
formatter: (cell) => badgeHtml(gridjs, cell || labels.never)
|
||||
},
|
||||
{ name: 'ID', hidden: true }
|
||||
];
|
||||
|
||||
const gridOptions = {
|
||||
gridjs: window.gridjs,
|
||||
container: '#users-grid',
|
||||
dataUrl: 'admin/users/data',
|
||||
appBase,
|
||||
columns,
|
||||
sortColumns: [null, null, 'first_name', 'last_name', 'email', 'active', null, null, null, null, null, null, 'created', 'modified', 'last_login_at', null],
|
||||
paginationLimit: 10,
|
||||
language: <?php MintyPHP\Buffer::get('grid_lang'); ?>,
|
||||
mapData: (data) => data.data.map((row) => [
|
||||
row.has_avatar ? row.uuid : '',
|
||||
row.uuid,
|
||||
row.first_name,
|
||||
row.last_name,
|
||||
row.email,
|
||||
row.active,
|
||||
row.tenants,
|
||||
row.departments,
|
||||
row.roles,
|
||||
row.phone,
|
||||
row.mobile,
|
||||
row.short_dial,
|
||||
row.created,
|
||||
row.modified,
|
||||
row.last_login,
|
||||
row.id
|
||||
]),
|
||||
selection: {
|
||||
enabled: true,
|
||||
id: 'selectRow',
|
||||
component: rowSelection,
|
||||
selectAllLabel: "<?php e(t('Select all')); ?>",
|
||||
props: {
|
||||
id: (row) => row.cell(uuidIndex).data
|
||||
},
|
||||
getSelectedIds: ({ container }) => {
|
||||
if (!container) return [];
|
||||
return Array.from(container.querySelectorAll('.gridjs-tr-selected'))
|
||||
.map((row) => row.getAttribute('data-uuid'))
|
||||
.filter(Boolean);
|
||||
}
|
||||
},
|
||||
search: gridSearch,
|
||||
filterSchema,
|
||||
urlSync: true,
|
||||
rowDataset: (row) => ({
|
||||
uuid: row?.cells?.[uuidIndex]?.data
|
||||
}),
|
||||
rowDblClick: {
|
||||
getUrl: (rowData) => {
|
||||
if (!canEditRow(rowData)) {
|
||||
return '';
|
||||
}
|
||||
const uuid = rowData?.cells?.[uuidIndex]?.data;
|
||||
return uuid ? new URL(`admin/users/edit/${uuid}`, appBase).toString() : '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const { gridConfig } = initStandardListPage({
|
||||
grid: gridOptions,
|
||||
filters: {
|
||||
mode: 'drawer',
|
||||
chipMeta: usersFilterChipMeta,
|
||||
watchInputs: ['#user-search'],
|
||||
preserveFilterParamsOnReset: ['tenant'],
|
||||
drawer: {
|
||||
countExcludeParams: ['tenant']
|
||||
},
|
||||
clearMetaOptions: {
|
||||
preserveFilterParams: ['tenant']
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!gridConfig || !gridConfig.grid) {
|
||||
console.warn('Users grid init failed');
|
||||
return null;
|
||||
}
|
||||
|
||||
return { ...gridConfig, indices: { activeIndex, uuidIndex } };
|
||||
};
|
||||
|
||||
const gridConfig = initUsersGrid();
|
||||
initUsersListPage({
|
||||
gridConfig,
|
||||
appBase,
|
||||
csrf,
|
||||
labels,
|
||||
buildBulkUrl,
|
||||
bulkDownloadForms: {
|
||||
'access-pdf': '#users-access-pdf-bulk-form'
|
||||
},
|
||||
resetOptions: {
|
||||
resetPage: true,
|
||||
urlHistoryMode: 'push',
|
||||
preserveFilterParams: ['tenant']
|
||||
},
|
||||
showFlash: showAsyncFlash,
|
||||
withLoading
|
||||
});
|
||||
bindBulkVisibility({
|
||||
containerSelector: '#users-grid',
|
||||
buttonSelector: '[data-users-bulk]'
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
$gridLang = json_decode(appBufferValue('grid_lang'), true);
|
||||
if (!is_array($gridLang)) {
|
||||
$gridLang = [];
|
||||
}
|
||||
$gridCsrf = json_decode(appBufferValue('grid_csrf'), true);
|
||||
if (!is_array($gridCsrf)) {
|
||||
$gridCsrf = [];
|
||||
}
|
||||
$pageConfig = [
|
||||
'gridSearch' => $searchConfig,
|
||||
'filterSchema' => $clientFilterSchema,
|
||||
'filterChipMeta' => $filterChipMeta,
|
||||
'currentUserUuid' => (string) $currentUserUuid,
|
||||
'canUpdateUsers' => (bool) $canUpdateUsers,
|
||||
'canUpdateSelf' => (bool) $canUpdateSelf,
|
||||
'csrf' => $gridCsrf,
|
||||
'gridLang' => $gridLang,
|
||||
'labels' => [
|
||||
'avatar' => t('Avatar'),
|
||||
'firstName' => t('First name'),
|
||||
'lastName' => t('Last name'),
|
||||
'email' => t('Email'),
|
||||
'state' => t('State'),
|
||||
'tenants' => t('Tenants'),
|
||||
'departments' => t('Departments'),
|
||||
'roles' => t('Roles'),
|
||||
'phone' => t('Phone'),
|
||||
'mobile' => t('Mobile'),
|
||||
'shortDial' => t('Short dial'),
|
||||
'created' => t('Created'),
|
||||
'modified' => t('Modified'),
|
||||
'lastLogin' => t('Last login'),
|
||||
'selectAll' => t('Select all'),
|
||||
'active' => t('Active'),
|
||||
'inactive' => t('Inactive'),
|
||||
'never' => t('Never'),
|
||||
'bulkActivateConfirm' => t('Activate users?'),
|
||||
'bulkDeactivateConfirm' => t('Deactivate users?'),
|
||||
'bulkDeleteConfirm' => t('Delete users?'),
|
||||
'bulkSendAccessConfirm' => t('Send access emails to selected users?'),
|
||||
'bulkAccessPdfConfirm' => t('Generate access PDFs for selected users?'),
|
||||
'primaryTenant' => t('Primary tenant'),
|
||||
'bulkMessages' => [
|
||||
'activate' => [
|
||||
'success' => t('%d users activated'),
|
||||
'error' => t('Failed to activate users'),
|
||||
],
|
||||
'deactivate' => [
|
||||
'success' => t('%d users deactivated'),
|
||||
'error' => t('Failed to deactivate users'),
|
||||
],
|
||||
'delete' => [
|
||||
'success' => t('%d users deleted'),
|
||||
'error' => t('Failed to delete users'),
|
||||
],
|
||||
'send-access' => [
|
||||
'success' => t('Access emails sent to %d users'),
|
||||
'partial' => t('Access emails sent to %d users, %f failed'),
|
||||
'error' => t('Failed to send access emails'),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
?>
|
||||
<script src="<?php e(assetVersion('vendor/gridjs/gridjs.umd.js')); ?>"></script>
|
||||
<script src="<?php e(assetVersion('vendor/gridjs/plugins/selection/selection.umd.js')); ?>"></script>
|
||||
<script type="application/json" id="page-config-admin-users-index"><?php gridJsonForJs($pageConfig); ?></script>
|
||||
<script type="module" src="<?php e(assetVersion('js/pages/admin-users-index.js')); ?>"></script>
|
||||
|
||||
Reference in New Issue
Block a user