forked from fa/breadcrumb-the-shire
feat: centralize breadcrumbs in topbar and remove history navigation
Move breadcrumb rendering from individual page templates into the core topbar. Each page now sets $breadcrumbs in its action .php file; the topbar renders it automatically via the shared partial. - Remove global back/forward buttons and app-nav-history.js component - Remove Alt+Arrow keyboard shortcuts for history navigation - Render breadcrumb in topbar-left section (replaces button area) - Clean up breadcrumb CSS: context-neutral base (flex, no margin) - Recalculate sticky titlebar offset in details container - Migrate all 41 pages (core + helpdesk, audit, addressbook, api-docs) - Add missing breadcrumbs to addressbook detail view - Update architecture contract tests (nav-history references removed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -76,6 +76,10 @@ $csrfKey = Session::$csrfSessionKey;
|
||||
$csrfToken = $session[$csrfKey] ?? '';
|
||||
|
||||
Buffer::set('title', t('Address book'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Address book')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
Buffer::set(
|
||||
'grid_csrf',
|
||||
|
||||
@@ -16,13 +16,6 @@ $filterChipMeta = is_array($filterChipMeta ?? null) ? $filterChipMeta : [];
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Address book')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Address book');
|
||||
$listTitleActionsHtml = '';
|
||||
require templatePath('partials/app-list-titlebar.phtml');
|
||||
|
||||
@@ -36,3 +36,8 @@ Buffer::set('style_groups', json_encode(['address-book']));
|
||||
$name = trim(($user['first_name'] ?? '') . ' ' . ($user['last_name'] ?? ''));
|
||||
$title = $name !== '' ? $name : ($user['email'] ?? t('Address book'));
|
||||
Buffer::set('title', $title);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Address book'), 'path' => 'address-book'],
|
||||
['label' => $title],
|
||||
];
|
||||
|
||||
@@ -8,4 +8,8 @@ Guard::requireLogin();
|
||||
Guard::requireAbilityOrForbidden(ApiDocsAuthorizationPolicy::ABILITY_VIEW);
|
||||
|
||||
Buffer::set('title', t('API docs'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('API docs')],
|
||||
];
|
||||
Buffer::set('style_groups', json_encode(['api-docs']));
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('API docs')],
|
||||
];
|
||||
$specUrl = lurl('admin/api-docs/spec');
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
|
||||
<div class="app-swagger-container">
|
||||
|
||||
@@ -17,6 +17,10 @@ $viewAuth['page'] = app(UiAccessService::class)->pageCapabilities(
|
||||
);
|
||||
|
||||
Buffer::set('title', t('API audit logs'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('API audit logs')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
$filterSchema = require __DIR__ . '/filter-schema.php';
|
||||
|
||||
@@ -11,13 +11,6 @@ $clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchem
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('API audit logs')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('API audit logs');
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
@@ -13,3 +13,8 @@ $auditLog = AuditPageHelper::findOrRedirect(
|
||||
'View API audit entry',
|
||||
$id ?? null
|
||||
);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('API audit logs'), 'path' => 'audit/api-audit'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
|
||||
@@ -51,13 +51,6 @@ $tokenTenantId = (int) ($auditLog['token_tenant_id'] ?? 0);
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('API audit logs'), 'path' => 'audit/api-audit'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
|
||||
$titlebar = [
|
||||
'title' => t('View API audit entry'),
|
||||
'backHref' => 'audit/api-audit',
|
||||
|
||||
@@ -17,6 +17,10 @@ $viewAuth['page'] = app(UiAccessService::class)->pageCapabilities(
|
||||
);
|
||||
|
||||
Buffer::set('title', t('Import audit logs'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Import audit logs')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
$filterSchema = require __DIR__ . '/filter-schema.php';
|
||||
|
||||
@@ -11,13 +11,6 @@ $clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchem
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Import audit logs')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Import audit logs');
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
@@ -13,3 +13,8 @@ $auditRun = AuditPageHelper::findOrRedirect(
|
||||
'View import audit entry',
|
||||
$id ?? null
|
||||
);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Import audit logs'), 'path' => 'audit/import-audit'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
|
||||
@@ -54,13 +54,6 @@ if ($tenantLabel === '') {
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Import audit logs'), 'path' => 'audit/import-audit'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
|
||||
$titlebar = [
|
||||
'title' => t('View import audit entry'),
|
||||
'backHref' => 'audit/import-audit',
|
||||
|
||||
@@ -17,6 +17,10 @@ $viewAuth['page'] = app(UiAccessService::class)->pageCapabilities(
|
||||
);
|
||||
|
||||
Buffer::set('title', t('System audit logs'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('System audit logs')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
$filterSchema = require __DIR__ . '/filter-schema.php';
|
||||
|
||||
@@ -10,13 +10,6 @@ $filterChipMeta = is_array($filterChipMeta ?? null) ? $filterChipMeta : [];
|
||||
$clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchema : [];
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('System audit logs')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('System audit logs');
|
||||
|
||||
@@ -13,3 +13,8 @@ $auditLog = AuditPageHelper::findOrRedirect(
|
||||
'View system audit entry',
|
||||
$id ?? null
|
||||
);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('System audit logs'), 'path' => 'audit/system-audit'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
|
||||
@@ -47,13 +47,6 @@ if ($tenantLabel === '') {
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('System audit logs'), 'path' => 'audit/system-audit'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
|
||||
$titlebar = [
|
||||
'title' => t('View system audit entry'),
|
||||
'backHref' => 'audit/system-audit',
|
||||
|
||||
@@ -20,6 +20,10 @@ $viewAuth['page'] = app(UiAccessService::class)->pageCapabilities(
|
||||
);
|
||||
|
||||
Buffer::set('title', t('User lifecycle logs'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('User lifecycle logs')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
$filterSchema = require __DIR__ . '/filter-schema.php';
|
||||
|
||||
@@ -11,13 +11,6 @@ $clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchem
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('User lifecycle logs')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('User lifecycle logs');
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
@@ -18,6 +18,11 @@ $auditLog = AuditPageHelper::findOrRedirect(
|
||||
'View user lifecycle audit entry',
|
||||
$id ?? null
|
||||
);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('User lifecycle logs'), 'path' => 'audit/user-lifecycle-audit'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
|
||||
$auditService = app(UserLifecycleAuditService::class);
|
||||
$snapshot = null;
|
||||
|
||||
@@ -29,13 +29,6 @@ $isRestorable = $canRestore
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('User lifecycle logs'), 'path' => 'audit/user-lifecycle-audit'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
|
||||
$titlebar = [
|
||||
'title' => t('View user lifecycle audit entry'),
|
||||
'backHref' => 'audit/user-lifecycle-audit',
|
||||
|
||||
@@ -126,3 +126,8 @@ $contactsFilterChipMeta = [
|
||||
|
||||
Buffer::set('title', $customerName . ' — ' . t('Helpdesk'));
|
||||
Buffer::set('style_groups', json_encode(['helpdesk']));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Helpdesk'), 'path' => 'helpdesk'],
|
||||
['label' => $customerName],
|
||||
];
|
||||
|
||||
@@ -37,15 +37,6 @@ $searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
data-controlling-dashboard-url="<?php e(lurl('helpdesk/debitor-controlling-dashboard-data')); ?>"
|
||||
>
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Helpdesk'), 'path' => 'helpdesk'],
|
||||
['label' => $customerName],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
|
||||
<?php
|
||||
$titlebarActions = [];
|
||||
if (!$hasError && $customer !== []) {
|
||||
|
||||
@@ -38,3 +38,7 @@ $isConfigured = $settingsGateway->isConfigured();
|
||||
|
||||
Buffer::set('title', t('Customers'));
|
||||
Buffer::set('style_groups', json_encode(['helpdesk']));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Helpdesk')],
|
||||
];
|
||||
|
||||
@@ -9,13 +9,6 @@ $searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
$filterChipMeta = is_array($filterChipMeta ?? null) ? $filterChipMeta : [];
|
||||
$isConfigured = $isConfigured ?? false;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Helpdesk')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php require templatePath('partials/app-flash.phtml'); ?>
|
||||
|
||||
<?php if (!$isConfigured): ?>
|
||||
|
||||
@@ -163,3 +163,8 @@ $controllingConfigSource = (string) ($controllingConfigEnvelope['source'] ?? 'de
|
||||
|
||||
Buffer::set('title', t('Helpdesk settings'));
|
||||
Buffer::set('style_groups', json_encode(['helpdesk']));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Helpdesk'), 'path' => 'helpdesk'],
|
||||
['label' => t('Settings')],
|
||||
];
|
||||
|
||||
@@ -52,13 +52,6 @@ $isOAuth2 = $authMode === HelpdeskSettingsGateway::AUTH_MODE_OAUTH2;
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Helpdesk'), 'path' => 'helpdesk'],
|
||||
['label' => t('Settings')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
|
||||
$titlebar = [
|
||||
'title' => t('Helpdesk settings'),
|
||||
'backHref' => lurl('helpdesk'),
|
||||
|
||||
@@ -44,3 +44,11 @@ $ticketCommunicationUrl = lurl('helpdesk/ticket-communication-data');
|
||||
|
||||
Buffer::set('title', $ticketDescription . ' — ' . t('Helpdesk'));
|
||||
Buffer::set('style_groups', json_encode(['helpdesk']));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Helpdesk'), 'path' => 'helpdesk'],
|
||||
];
|
||||
if ($ticketCustomerNo !== '') {
|
||||
$breadcrumbs[] = ['label' => (string) ($ticket['Company_Contact_Name'] ?? $ticketCustomerNo), 'path' => 'helpdesk/debitor/' . rawurlencode($ticketCustomerNo)];
|
||||
}
|
||||
$breadcrumbs[] = ['label' => t('Ticket') . ' ' . $ticketNo];
|
||||
|
||||
@@ -26,18 +26,6 @@ $backUrl = $ticketCustomerNo !== '' ? lurl('helpdesk/debitor/' . rawurlencode($t
|
||||
data-ticket-communication-url="<?php e($ticketCommunicationUrl); ?>"
|
||||
>
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Helpdesk'), 'path' => 'helpdesk'],
|
||||
];
|
||||
if ($ticketCustomerNo !== '') {
|
||||
$breadcrumbs[] = ['label' => (string) ($ticket['Company_Contact_Name'] ?? $ticketCustomerNo), 'path' => 'helpdesk/debitor/' . rawurlencode($ticketCustomerNo)];
|
||||
}
|
||||
$breadcrumbs[] = ['label' => t('Ticket') . ' ' . $ticketNo];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
|
||||
<?php
|
||||
$titlebar = [
|
||||
'title' => t('Ticket') . ' ' . $ticketNo,
|
||||
|
||||
@@ -100,3 +100,8 @@ if ($request->isMethod('POST')) {
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', t('Create department'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Departments'), 'path' => 'admin/departments'],
|
||||
['label' => t('Create department')],
|
||||
];
|
||||
|
||||
@@ -10,12 +10,6 @@
|
||||
<section>
|
||||
<?php
|
||||
$hasTenantOptions = !empty($tenants);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Departments'), 'path' => 'admin/departments'],
|
||||
['label' => t('Create department')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => t('Create department'),
|
||||
'backHref' => 'admin/departments',
|
||||
|
||||
@@ -151,4 +151,10 @@ if ($request->isMethod('POST')) {
|
||||
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', $canUpdateDepartment ? t('Edit department') : t('View department'));
|
||||
$titleText = $canUpdateDepartment ? t('Edit department') : t('View department');
|
||||
Buffer::set('title', $titleText);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Departments'), 'path' => 'admin/departments'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
|
||||
@@ -21,12 +21,6 @@ $titleText = $isReadOnly ? t('View department') : t('Edit department');
|
||||
<section>
|
||||
<?php
|
||||
$hasTenantOptions = !empty($tenants);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Departments'), 'path' => 'admin/departments'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => $titleText,
|
||||
'backHref' => 'admin/departments',
|
||||
|
||||
@@ -42,6 +42,10 @@ usort($tenants, static function ($a, $b) {
|
||||
});
|
||||
|
||||
Buffer::set('title', t('Departments'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Departments')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
$csrfKey = Session::$csrfSessionKey;
|
||||
$csrfToken = $session[$csrfKey] ?? '';
|
||||
|
||||
@@ -14,13 +14,6 @@ $activeTenant = (string) ($activeTenant ?? ($toolbarFilterState['tenant'] ?? '')
|
||||
$showTenantTabs = isset($tenants) && is_array($tenants) && count($tenants) > 1;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Departments')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Departments');
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
@@ -54,5 +54,11 @@ $currentSlug = $slug;
|
||||
$currentTitle = (string) $allDocs[$slug];
|
||||
|
||||
Buffer::set('title', $currentTitle . ' - ' . t('Documentation'));
|
||||
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Documentation'), 'path' => 'admin/docs/' . $defaultSlug],
|
||||
['label' => $currentTitle],
|
||||
];
|
||||
Buffer::set('style_groups', json_encode(['docs']));
|
||||
Buffer::set('docs_rendered_html', $renderedHtml);
|
||||
|
||||
@@ -44,14 +44,6 @@
|
||||
</aside>
|
||||
|
||||
<article class="app-docs-content">
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Documentation'), 'path' => 'admin/docs/' . $defaultSlug],
|
||||
['label' => $currentTitle],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php MintyPHP\Buffer::get('docs_rendered_html'); ?>
|
||||
</article>
|
||||
|
||||
|
||||
@@ -136,3 +136,8 @@ foreach ($profileOptions as $option) {
|
||||
}
|
||||
|
||||
Buffer::set('title', t('Imports'));
|
||||
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Imports')],
|
||||
];
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
<?php
|
||||
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Imports')],
|
||||
];
|
||||
|
||||
$hasAllowedProfile = !empty($allowedProfileOptions);
|
||||
|
||||
$renderErrorTable = static function (array $rows): void {
|
||||
@@ -43,7 +38,6 @@ $renderErrorTable = static function (array $rows): void {
|
||||
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php require templatePath('partials/app-breadcrumb.phtml'); ?>
|
||||
<div class="app-details-titlebar" data-detail-unsaved-message="<?php e(t('You have unsaved changes. Leave without saving?')); ?>">
|
||||
<h1><?php e(t('Imports')); ?></h1>
|
||||
</div>
|
||||
|
||||
@@ -11,3 +11,8 @@ $user = $session['user'] ?? null;
|
||||
$first_name = $user['first_name'] ?? '';
|
||||
|
||||
Buffer::set('title', t('Admin'));
|
||||
|
||||
$breadcrumbs = [
|
||||
['label' => t('Login'), 'path' => 'logout'],
|
||||
['label' => t('Home')],
|
||||
];
|
||||
|
||||
@@ -6,13 +6,6 @@
|
||||
*/
|
||||
|
||||
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Login'), 'path' => 'logout'],
|
||||
['label' => t('Home')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<div class="app-dashboard-titlebar">
|
||||
<h1><?php e(t('Welcome back')); ?> <?php e($first_name )?></h1>
|
||||
|
||||
@@ -41,6 +41,10 @@ $clientFilterSchema = $listFilterContext['clientFilterSchema'];
|
||||
$searchConfig = $listFilterContext['searchConfig'];
|
||||
|
||||
Buffer::set('title', t('Mail logs'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Mail logs')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
$csrfKey = Session::$csrfSessionKey;
|
||||
$csrfToken = $session[$csrfKey] ?? '';
|
||||
|
||||
@@ -10,13 +10,6 @@ $clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchem
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Mail logs')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Mail logs');
|
||||
require templatePath('partials/app-list-titlebar.phtml');
|
||||
?>
|
||||
|
||||
@@ -17,3 +17,8 @@ if (!$mailLog) {
|
||||
}
|
||||
|
||||
Buffer::set('title', t('View mail log'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Mail logs'), 'path' => 'admin/mail-log'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
|
||||
@@ -13,14 +13,6 @@ $statusBadge = $status->badgeVariant();
|
||||
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Mail logs'), 'path' => 'admin/mail-log'],
|
||||
['label' => t('View')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<div class="app-details-titlebar">
|
||||
<h1>
|
||||
<a href="admin/mail-log" title="<?php e(t('Back')); ?>" class="app-icon-button"><i class="bi bi-arrow-left"></i></a>
|
||||
|
||||
@@ -66,3 +66,8 @@ if ($request->isMethod('POST')) {
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', t('Create permission'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Permissions'), 'path' => 'admin/permissions'],
|
||||
['label' => t('Create permission')],
|
||||
];
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Permissions'), 'path' => 'admin/permissions'],
|
||||
['label' => t('Create permission')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => t('Create permission'),
|
||||
'backHref' => 'admin/permissions',
|
||||
|
||||
@@ -112,4 +112,10 @@ if ($request->isMethod('POST')) {
|
||||
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', $canUpdatePermission ? t('Edit permission') : t('View permission'));
|
||||
$titleText = $canUpdatePermission ? t('Edit permission') : t('View permission');
|
||||
Buffer::set('title', $titleText);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Permissions'), 'path' => 'admin/permissions'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
|
||||
@@ -13,18 +13,12 @@ use MintyPHP\Session;
|
||||
$canUpdatePermission = (bool) ($canUpdatePermission ?? false);
|
||||
$canDeletePermission = (bool) ($canDeletePermission ?? false);
|
||||
$isReadOnly = !$canUpdatePermission;
|
||||
$titleText = $isReadOnly ? t('View permission') : t('Edit permission');
|
||||
$titleText = $titleText ?? ($isReadOnly ? t('View permission') : t('Edit permission'));
|
||||
|
||||
?>
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Permissions'), 'path' => 'admin/permissions'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => $titleText,
|
||||
'backHref' => 'admin/permissions',
|
||||
|
||||
@@ -49,6 +49,10 @@ $clientFilterSchema = $listFilterContext['clientFilterSchema'];
|
||||
$searchConfig = $listFilterContext['searchConfig'];
|
||||
|
||||
Buffer::set('title', t('Permissions'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Permissions')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
$csrfKey = Session::$csrfSessionKey;
|
||||
$csrfToken = $session[$csrfKey] ?? '';
|
||||
|
||||
@@ -12,13 +12,6 @@ $clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchem
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Permissions')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Permissions');
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
@@ -116,3 +116,8 @@ if ($request->isMethod('POST')) {
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', t('Create role'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Roles'), 'path' => 'admin/roles'],
|
||||
['label' => t('Create role')],
|
||||
];
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Roles'), 'path' => 'admin/roles'],
|
||||
['label' => t('Create role')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => t('Create role'),
|
||||
'backHref' => 'admin/roles',
|
||||
|
||||
@@ -128,4 +128,10 @@ if ($request->isMethod('POST')) {
|
||||
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', $canUpdateRole ? t('Edit role') : t('View role'));
|
||||
$titleText = $canUpdateRole ? t('Edit role') : t('View role');
|
||||
Buffer::set('title', $titleText);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Roles'), 'path' => 'admin/roles'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
|
||||
@@ -21,12 +21,6 @@ $titleText = $isReadOnly ? t('View role') : t('Edit role');
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Roles'), 'path' => 'admin/roles'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => $titleText,
|
||||
'backHref' => 'admin/roles',
|
||||
|
||||
@@ -49,6 +49,10 @@ $clientFilterSchema = $listFilterContext['clientFilterSchema'];
|
||||
$searchConfig = $listFilterContext['searchConfig'];
|
||||
|
||||
Buffer::set('title', t('Roles'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Roles')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
$csrfKey = Session::$csrfSessionKey;
|
||||
$csrfToken = $session[$csrfKey] ?? '';
|
||||
|
||||
@@ -12,13 +12,6 @@ $clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchem
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Roles')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Roles');
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
@@ -73,5 +73,11 @@ $scheduleSummary = $scheduledJobService->scheduleSummary($job ?? []);
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
|
||||
Buffer::set('title', $canManage ? t('Edit scheduled job') : t('View scheduled job'));
|
||||
$titleText = $canManage ? t('Edit scheduled job') : t('View scheduled job');
|
||||
Buffer::set('title', $titleText);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Scheduled jobs'), 'path' => 'admin/scheduled-jobs'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
@@ -39,13 +39,6 @@ if ($canRunNow) {
|
||||
<section>
|
||||
<?php
|
||||
$titleText = $canManage ? t('Edit scheduled job') : t('View scheduled job');
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Scheduled jobs'), 'path' => 'admin/scheduled-jobs'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
|
||||
$titlebar = [
|
||||
'title' => $titleText,
|
||||
'backHref' => 'admin/scheduled-jobs',
|
||||
|
||||
@@ -46,4 +46,8 @@ $clientFilterSchema = $listFilterContext['clientFilterSchema'];
|
||||
$searchConfig = $listFilterContext['searchConfig'];
|
||||
|
||||
Buffer::set('title', t('Scheduled jobs'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Scheduled jobs')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
|
||||
@@ -10,13 +10,6 @@ $clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchem
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Scheduled jobs')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Scheduled jobs');
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
@@ -81,3 +81,8 @@ if ($request->isMethod('POST')) {
|
||||
}
|
||||
|
||||
Buffer::set('title', t('Settings'));
|
||||
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Settings')],
|
||||
];
|
||||
|
||||
@@ -104,11 +104,6 @@ $disabledAttr = $isReadOnly ? 'disabled' : '';
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Settings')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => t('Settings'),
|
||||
'actions' => $canUpdateSettings ? [
|
||||
|
||||
@@ -17,3 +17,8 @@ $currentUserId = (int) ($session['user']['id'] ?? 0);
|
||||
$viewAuth['page'] = app(UiAccessService::class)->pageCapabilities($currentUserId, UiCapabilityMap::PAGE_STATS_INDEX);
|
||||
|
||||
Buffer::set('title', t('Statistics'));
|
||||
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Statistics')],
|
||||
];
|
||||
|
||||
@@ -107,13 +107,6 @@ $canViewAuditTab = (bool) ($auditStatsAvailable ?? false) && (
|
||||
|| ($canViewUserLifecycleAudit && (bool) ($userLifecycleAuditStatsAvailable ?? false))
|
||||
);
|
||||
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Statistics')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<div class="app-dashboard-titlebar">
|
||||
<h1><?php e(t('Statistics')); ?></h1>
|
||||
|
||||
@@ -14,3 +14,8 @@ $permissions = $pageData['permissions'] ?? [];
|
||||
$healthChecks = $overview['health_checks'] ?? [];
|
||||
|
||||
Buffer::set('title', t('System Info'));
|
||||
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('System Info')],
|
||||
];
|
||||
|
||||
@@ -12,13 +12,6 @@ $modules = $modules ?? [];
|
||||
$permissions = $permissions ?? [];
|
||||
$healthChecks = $healthChecks ?? [];
|
||||
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('System Info')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<div class="app-dashboard-titlebar">
|
||||
<h1><?php e(t('System Info')); ?></h1>
|
||||
|
||||
@@ -135,3 +135,8 @@ if ($request->isMethod('POST')) {
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', t('Create tenant'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Tenants'), 'path' => 'admin/tenants'],
|
||||
['label' => t('Create tenant')],
|
||||
];
|
||||
|
||||
@@ -11,12 +11,6 @@
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Tenants'), 'path' => 'admin/tenants'],
|
||||
['label' => t('Create tenant')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => t('Create tenant'),
|
||||
'backHref' => 'admin/tenants',
|
||||
|
||||
@@ -182,4 +182,10 @@ if ($canManageSso && empty($ldapUiState)) {
|
||||
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', $canUpdateTenant ? t('Edit tenant') : t('View tenant'));
|
||||
$titleText = $canUpdateTenant ? t('Edit tenant') : t('View tenant');
|
||||
Buffer::set('title', $titleText);
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Tenants'), 'path' => 'admin/tenants'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
|
||||
@@ -27,12 +27,6 @@ $hasFavicon = $avatarUuid !== '' && $tenantFaviconService->hasFavicon($avatarUui
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Tenants'), 'path' => 'admin/tenants'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => $titleText,
|
||||
'backHref' => 'admin/tenants',
|
||||
|
||||
@@ -46,6 +46,10 @@ $clientFilterSchema = $listFilterContext['clientFilterSchema'];
|
||||
$searchConfig = $listFilterContext['searchConfig'];
|
||||
|
||||
Buffer::set('title', t('Tenants'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Tenants')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
$csrfKey = Session::$csrfSessionKey;
|
||||
$csrfToken = $session[$csrfKey] ?? '';
|
||||
|
||||
@@ -12,13 +12,6 @@ $clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchem
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Tenants')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Tenants');
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
@@ -214,3 +214,8 @@ if (!$customFieldDefinitionsByTenant && $selectedTenantIds) {
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', t('Create user'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Users'), 'path' => 'admin/users'],
|
||||
['label' => t('Create user')],
|
||||
];
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
|
||||
<section>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Users'), 'path' => 'admin/users'],
|
||||
['label' => t('Create user')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
$titlebar = [
|
||||
'title' => t('Create user'),
|
||||
'backHref' => 'admin/users',
|
||||
|
||||
@@ -300,4 +300,12 @@ if ($request->isMethod('POST')) {
|
||||
|
||||
$validationSummaryErrors = $errorBag->toArray();
|
||||
$errors = $errorBag->toFlatList();
|
||||
Buffer::set('title', $isOwnAccount ? t('My account') : ($canEditUser ? t('Edit user') : t('View user')));
|
||||
$titleText = $isOwnAccount ? t('My account') : ($canEditUser ? t('Edit user') : t('View user'));
|
||||
Buffer::set('title', $titleText);
|
||||
if (!($isOwnAccount && !$canViewUsers)) {
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Users'), 'path' => 'admin/users'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -46,16 +46,6 @@ if ($lastLoginAt !== '') {
|
||||
|
||||
<div class="app-details-container">
|
||||
<section>
|
||||
<?php if (!$hideNavigation): ?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Users'), 'path' => 'admin/users'],
|
||||
['label' => $titleText],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
$asideActions = [];
|
||||
$moduleSlots = is_array($layoutNav['moduleSlots'] ?? null) ? $layoutNav['moduleSlots'] : [];
|
||||
|
||||
@@ -56,6 +56,10 @@ $viewAuth['page'] = [
|
||||
];
|
||||
|
||||
Buffer::set('title', t('Users'));
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Users')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
$csrfKey = Session::$csrfSessionKey;
|
||||
$csrfToken = $session[$csrfKey] ?? '';
|
||||
|
||||
@@ -22,13 +22,6 @@ $currentUserUuid = (string) ($_SESSION['user']['uuid'] ?? '');
|
||||
$showTenantTabs = isset($tenants) && is_array($tenants) && count($tenants) > 1;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Users')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Users');
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
@@ -13,7 +13,6 @@ $hotkeyRows = HotkeyService::list();
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Keyboard shortcuts')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -29,6 +29,11 @@ $csrfKey = Session::$csrfSessionKey;
|
||||
$csrfToken = $session[$csrfKey] ?? '';
|
||||
|
||||
Buffer::set('title', t('Search results'));
|
||||
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Search')],
|
||||
];
|
||||
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
Buffer::set(
|
||||
'grid_csrf',
|
||||
|
||||
@@ -8,13 +8,6 @@ $clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchem
|
||||
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
||||
?>
|
||||
<?php
|
||||
$breadcrumbs = [
|
||||
['label' => t('Home'), 'path' => 'admin'],
|
||||
['label' => t('Search')],
|
||||
];
|
||||
require templatePath('partials/app-breadcrumb.phtml');
|
||||
?>
|
||||
<?php
|
||||
$listTitle = t('Search results');
|
||||
require templatePath('partials/app-list-titlebar.phtml');
|
||||
?>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?php
|
||||
$breadcrumbs = $breadcrumbs ?? [];
|
||||
$items = array_values(array_filter($breadcrumbs, static function ($item) {
|
||||
$items = array_values(array_filter($breadcrumbs ?? [], static function ($item) {
|
||||
return !empty($item['label']);
|
||||
}));
|
||||
if (!$items) {
|
||||
|
||||
@@ -27,17 +27,16 @@ $moduleSlots = is_array($layoutNav['moduleSlots'] ?? null) ? $layoutNav['moduleS
|
||||
$moduleTopbarSlots = is_array($moduleSlots['topbar.right_item'] ?? null) ? $moduleSlots['topbar.right_item'] : [];
|
||||
|
||||
?>
|
||||
<header class="app-header" data-app-component="nav-history">
|
||||
<header class="app-header">
|
||||
<nav class="app-topbar">
|
||||
<ul class="app-topbar-left">
|
||||
<li>
|
||||
<a id="global-back" data-tooltip-pos="bottom" data-tooltip="<?php e(t('Back')); ?> (Alt+←)" title="<?php e(t('Back')); ?> (Alt+←)" aria-label="<?php e(t('Back')); ?> (Alt+←)" href="admin"><i class="bi bi-arrow-left"></i></a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="global-forward" data-tooltip-pos="bottom" data-tooltip="<?php e(t('Forward')); ?> (Alt+→)" title="<?php e(t('Forward')); ?> (Alt+→)" aria-label="<?php e(t('Forward')); ?> (Alt+→)" href="admin"><i class="bi bi-arrow-right"></i></a>
|
||||
</li>
|
||||
<li id="async-messages" role="status" aria-live="polite" aria-hidden="true"></li>
|
||||
</ul>
|
||||
<div class="app-topbar-left">
|
||||
<?php
|
||||
if (is_array($breadcrumbs ?? null) && $breadcrumbs !== []) {
|
||||
require __DIR__ . '/app-breadcrumb.phtml';
|
||||
}
|
||||
?>
|
||||
<span id="async-messages" role="status" aria-live="polite" aria-hidden="true"></span>
|
||||
</div>
|
||||
<div class="app-topbar-center">
|
||||
<button type="button" class="app-topbar-search-trigger" data-app-search-trigger aria-label="<?php e(t('Search')); ?>" title="<?php e(t('Search')); ?>">
|
||||
<i class="bi bi-search" aria-hidden="true"></i>
|
||||
|
||||
@@ -15,7 +15,6 @@ trait FrontendRuntimeContractSupport
|
||||
'web/js/components/app-password-hints.js',
|
||||
'web/js/components/app-copy-badge.js',
|
||||
'web/js/components/app-multiselect-init.js',
|
||||
'web/js/components/app-nav-history.js',
|
||||
'web/js/components/app-toggle-sidebar.js',
|
||||
'web/js/components/app-toggle-aside-panels.js',
|
||||
'web/js/components/app-toggle-details-aside.js',
|
||||
|
||||
@@ -25,7 +25,6 @@ class FrontendRuntimeHostContractTest extends TestCase
|
||||
$this->assertStringNotContainsString("assetVersion('js/components/app-bookmark-init.js')", $defaultTemplate);
|
||||
|
||||
$this->assertStringContainsString('data-app-component="flash-auto-dismiss"', $flashPartial);
|
||||
$this->assertStringContainsString('data-app-component="nav-history"', $topbarPartial);
|
||||
$this->assertStringContainsString('data-app-component="tenant-switcher"', $topbarPartial);
|
||||
$this->assertStringContainsString('data-app-component="theme-controls"', $topbarPartial);
|
||||
$this->assertStringContainsString('data-app-component="contrast-toggle"', $topbarPartial);
|
||||
|
||||
@@ -6,12 +6,11 @@
|
||||
* (app-shell.css lines 2844-2956) to avoid layout side-effects.
|
||||
*/
|
||||
.app-breadcrumb {
|
||||
display: block;
|
||||
justify-content: initial;
|
||||
overflow: initial;
|
||||
margin-bottom: 0.375rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
font-size: var(--text-xs);
|
||||
line-height: var(--app-line-height);
|
||||
line-height: var(--leading-tight);
|
||||
}
|
||||
|
||||
.app-breadcrumb ol {
|
||||
|
||||
@@ -119,24 +119,12 @@
|
||||
padding-inline: calc(var(--app-spacing) * 2);
|
||||
}
|
||||
|
||||
.app-details-container .app-breadcrumb {
|
||||
padding-top: calc(var(--app-spacing) * 2);
|
||||
position: sticky;
|
||||
top: 49px;
|
||||
z-index: 10;
|
||||
background: var(--app-background-color);
|
||||
}
|
||||
|
||||
.app-details-container .app-details-titlebar {
|
||||
position: sticky;
|
||||
top: 93px;
|
||||
z-index: 10;
|
||||
background: var(--app-background-color);
|
||||
}
|
||||
|
||||
.app-details-container:not(:has(.app-breadcrumb)) .app-details-titlebar {
|
||||
top: 37px;
|
||||
padding-block-start: var(--app-spacing);
|
||||
z-index: 10;
|
||||
padding-block-start: calc(var(--app-spacing) * 2);
|
||||
background: var(--app-background-color);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
@@ -122,6 +122,10 @@
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.app-topbar-left .app-breadcrumb {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.app-topbar-search-trigger-text,
|
||||
.app-topbar-search-trigger-shortcut {
|
||||
display: none;
|
||||
@@ -160,9 +164,7 @@
|
||||
color var(--app-transition);
|
||||
}
|
||||
|
||||
.app-topbar-left > li > a,
|
||||
.app-topbar-right > li > a,
|
||||
.app-topbar-left button,
|
||||
.app-topbar-right button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -181,39 +183,26 @@
|
||||
color var(--app-transition);
|
||||
}
|
||||
|
||||
.app-topbar-left > li > a:hover,
|
||||
.app-topbar-right > li > a:hover,
|
||||
.app-topbar-left button:hover,
|
||||
.app-topbar-right button:hover,
|
||||
.app-header details.dropdown > summary:not([role]):hover {
|
||||
background: color-mix(in srgb, var(--app-contrast) 8%, transparent);
|
||||
color: var(--app-color);
|
||||
}
|
||||
|
||||
.app-topbar-left > li > a:active,
|
||||
.app-topbar-right > li > a:active,
|
||||
.app-topbar-left button:active,
|
||||
.app-topbar-right button:active,
|
||||
.app-header details.dropdown > summary:not([role]):active {
|
||||
background: color-mix(in srgb, var(--app-contrast) 12%, transparent);
|
||||
}
|
||||
|
||||
.app-topbar-left > li > a:focus-visible,
|
||||
.app-topbar-right > li > a:focus-visible,
|
||||
.app-topbar-left button:focus-visible,
|
||||
.app-topbar-right button:focus-visible,
|
||||
.app-header details.dropdown > summary:not([role]):focus-visible {
|
||||
outline: 2px solid var(--app-primary);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.app-header #global-back.is-disabled,
|
||||
.app-header #global-forward.is-disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.app-topbar-tenant-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -5,7 +5,6 @@ import { initFlashAutoDismiss } from './components/app-flash-auto-dismiss.js';
|
||||
import { initPasswordHints } from './components/app-password-hints.js';
|
||||
import { initBadgeCopy } from './components/app-copy-badge.js';
|
||||
import { initMultiSelectComponent } from './components/app-multiselect-init.js';
|
||||
import { initNavHistory } from './components/app-nav-history.js';
|
||||
import { initSidebarToggle } from './components/app-toggle-sidebar.js';
|
||||
import { initAsidePanels } from './components/app-toggle-aside-panels.js';
|
||||
import { initDetailsAsideToggle } from './components/app-toggle-details-aside.js';
|
||||
@@ -177,10 +176,6 @@ const bootRuntime = async () => {
|
||||
scope: 'global',
|
||||
configPath: 'components.multiSelect',
|
||||
});
|
||||
runtime.register('nav-history', initNavHistory, {
|
||||
selector: '[data-app-component="nav-history"]',
|
||||
configPath: 'components.navHistory',
|
||||
});
|
||||
runtime.register('details-state', initDetailsState, {
|
||||
scope: 'global',
|
||||
configPath: 'components.detailsState',
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* Browser history integration — handles back/forward navigation state.
|
||||
*/
|
||||
import { isEditableTarget } from '../core/app-form-utils.js';
|
||||
import { resolveHost } from '../core/app-dom.js';
|
||||
|
||||
export function initNavHistory(root = document, options = {}) {
|
||||
const {
|
||||
backSelector = '#global-back',
|
||||
forwardSelector = '#global-forward',
|
||||
} = options;
|
||||
const host = resolveHost(root);
|
||||
const back = host.querySelector(backSelector);
|
||||
const forward = host.querySelector(forwardSelector);
|
||||
if (!back && !forward) {
|
||||
return { destroy: () => {} };
|
||||
}
|
||||
|
||||
const setDisabledState = (link, disabled) => {
|
||||
link.setAttribute('aria-disabled', disabled ? 'true' : 'false');
|
||||
link.classList.toggle('is-disabled', disabled);
|
||||
if (disabled) {
|
||||
link.setAttribute('tabindex', '-1');
|
||||
} else {
|
||||
link.removeAttribute('tabindex');
|
||||
}
|
||||
};
|
||||
|
||||
const updateHistoryButtons = () => {
|
||||
const hasHistory = window.history.length > 1;
|
||||
if (back instanceof HTMLElement) {
|
||||
setDisabledState(back, !hasHistory);
|
||||
}
|
||||
if (forward instanceof HTMLElement) {
|
||||
setDisabledState(forward, !hasHistory);
|
||||
}
|
||||
};
|
||||
|
||||
const onKeyDown = (event) => {
|
||||
if (!event.altKey || event.metaKey || event.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
if (isEditableTarget(event.target)) {
|
||||
return;
|
||||
}
|
||||
if (event.key === 'ArrowLeft') {
|
||||
if (window.history.length > 1) {
|
||||
event.preventDefault();
|
||||
window.history.back();
|
||||
}
|
||||
} else if (event.key === 'ArrowRight') {
|
||||
if (window.history.length > 1) {
|
||||
event.preventDefault();
|
||||
window.history.forward();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', onKeyDown);
|
||||
|
||||
const onBackClick = (event) => {
|
||||
event.preventDefault();
|
||||
if (window.history.length > 1) {
|
||||
window.history.back();
|
||||
}
|
||||
};
|
||||
if (back instanceof HTMLElement) {
|
||||
back.addEventListener('click', onBackClick);
|
||||
}
|
||||
|
||||
const onForwardClick = (event) => {
|
||||
event.preventDefault();
|
||||
if (window.history.length > 1) {
|
||||
window.history.forward();
|
||||
}
|
||||
};
|
||||
if (forward instanceof HTMLElement) {
|
||||
forward.addEventListener('click', onForwardClick);
|
||||
}
|
||||
|
||||
window.addEventListener('popstate', updateHistoryButtons);
|
||||
updateHistoryButtons();
|
||||
|
||||
const destroy = () => {
|
||||
document.removeEventListener('keydown', onKeyDown);
|
||||
if (back instanceof HTMLElement) {
|
||||
back.removeEventListener('click', onBackClick);
|
||||
}
|
||||
if (forward instanceof HTMLElement) {
|
||||
forward.removeEventListener('click', onForwardClick);
|
||||
}
|
||||
window.removeEventListener('popstate', updateHistoryButtons);
|
||||
};
|
||||
|
||||
return { destroy, update: updateHistoryButtons };
|
||||
}
|
||||
Reference in New Issue
Block a user