Introduce a helper that returns the registered route TARGET for a given
source path, so URLs built for endpoints that carry query parameters do
not rely on MintyPHP's applyRoutes() rewrite layer — that layer compares
the full request URI (including `?query`) against source paths and
silently misses modules where path ≠ target.
- core/Support/helpers/app.php: endpointUrl($path) consults
ModuleRegistry::getRoutes(), returns lurl(target) when the path is a
registered module source path, otherwise falls through to lurl($path).
Safe fallback when the container or registry is unavailable.
- modules/audit/pages/audit/system-audit/index(default).phtml: replace
the ad-hoc target-path workaround with endpointUrl('admin/system-audit/
export'). Callers can now write the natural source path without
knowing about the rewrite trap.
- Apply the same helper to modules/helpdesk/.../domains/index and
pages/admin/users/index for consistency — a no-op where path already
equals target, but establishes the convention: every export/data
endpoint URL in page configs goes through endpointUrl().
- tests/Support/Helpers/EndpointUrlTest: 5 cases covering source→target
resolution, idempotence when path == target, fall-through for
unregistered paths, leading-slash normalization, and graceful
degradation when the registry is missing. Uses
AppContainerIsolationTrait per the contract test in
tests/Architecture/AppContainerIsolationContractTest.
Gates: PHPUnit 1894 OK, PHPStan 0 errors, module:sync ok.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
96 lines
4.2 KiB
PHTML
96 lines
4.2 KiB
PHTML
<?php
|
|
$toolbarFilterSchema = is_array($toolbarFilterSchema ?? null) ? $toolbarFilterSchema : [];
|
|
$searchToolbarFilterSchema = is_array($searchToolbarFilterSchema ?? null) ? $searchToolbarFilterSchema : [];
|
|
$drawerToolbarFilterSchema = is_array($drawerToolbarFilterSchema ?? null) ? $drawerToolbarFilterSchema : [];
|
|
$toolbarFilterState = is_array($toolbarFilterState ?? null) ? $toolbarFilterState : [];
|
|
$toolbarOptionSets = is_array($toolbarOptionSets ?? null) ? $toolbarOptionSets : [];
|
|
$clientFilterSchema = is_array($clientFilterSchema ?? null) ? $clientFilterSchema : [];
|
|
$searchConfig = is_array($searchConfig ?? null) ? $searchConfig : null;
|
|
$filterChipMeta = is_array($filterChipMeta ?? null) ? $filterChipMeta : [];
|
|
$isConfigured = $isConfigured ?? false;
|
|
?>
|
|
<?php require templatePath('partials/app-flash.phtml'); ?>
|
|
|
|
<?php if (!$isConfigured): ?>
|
|
<div class="notice" data-variant="warning" role="alert">
|
|
<p><?php e(t('BC connection is not configured. Please configure the connection in the settings.')); ?></p>
|
|
<a href="<?php e(lurl('helpdesk/settings')); ?>" role="button" class="secondary outline small">
|
|
<?php e(t('Open settings')); ?>
|
|
</a>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php
|
|
ob_start();
|
|
require templatePath('partials/app-list-export-dropdown.phtml');
|
|
$listTitleActionsHtml = ob_get_clean();
|
|
$listTitle = t('Domains');
|
|
require templatePath('partials/app-list-titlebar.phtml');
|
|
?>
|
|
<?php
|
|
$filterUiNamespace = 'helpdesk-domains';
|
|
require templatePath('partials/app-list-filters.phtml');
|
|
?>
|
|
<div class="app-list-table">
|
|
<div id="helpdesk-domains-grid"></div>
|
|
</div>
|
|
|
|
<dialog
|
|
data-app-security-dialog
|
|
aria-labelledby="sec-dialog-title"
|
|
aria-describedby="sec-dialog-domain"
|
|
>
|
|
<article class="app-confirm-dialog app-dialog-sm">
|
|
<header>
|
|
<h2 id="sec-dialog-title"><?php e(t('Security level')); ?></h2>
|
|
<button type="button" class="close" data-sec-dialog-close aria-label="<?php e(t('Close')); ?>" title="<?php e(t('Close')); ?>"></button>
|
|
</header>
|
|
<p id="sec-dialog-domain" class="muted"></p>
|
|
<div class="app-form-grid">
|
|
<?php $csrfKey = \MintyPHP\Session::$csrfSessionKey; $csrfToken = (string) ($_SESSION[$csrfKey] ?? ''); ?>
|
|
<input type="hidden" name="<?php e($csrfKey); ?>" id="sec-dialog-csrf" value="<?php e($csrfToken); ?>">
|
|
<div class="app-form-group">
|
|
<label for="sec-dialog-level"><?php e(t('Security level')); ?></label>
|
|
<select id="sec-dialog-level" name="security_level">
|
|
<option value="niedrig"><?php e(t('Low')); ?></option>
|
|
<option value="normal"><?php e(t('Normal')); ?></option>
|
|
<option value="hoch"><?php e(t('High')); ?></option>
|
|
<option value="kritisch"><?php e(t('Critical')); ?></option>
|
|
</select>
|
|
</div>
|
|
<div class="app-form-group">
|
|
<label for="sec-dialog-note"><?php e(t('Note')); ?></label>
|
|
<textarea id="sec-dialog-note" name="note" rows="3" placeholder="<?php e(t('Optional note...')); ?>"></textarea>
|
|
</div>
|
|
</div>
|
|
<footer>
|
|
<button type="button" class="secondary outline" data-sec-dialog-cancel><?php e(t('Cancel')); ?></button>
|
|
<button type="button" class="primary" data-sec-dialog-save><?php e(t('Save')); ?></button>
|
|
</footer>
|
|
</article>
|
|
</dialog>
|
|
|
|
<script src="<?php e(assetVersion('vendor/gridjs/gridjs.umd.js')); ?>"></script>
|
|
<script type="application/json" id="page-config-helpdesk-domains"><?php gridJsonForJs([
|
|
'dataUrl' => lurl('helpdesk/domains-data'),
|
|
'domainBaseUrl' => lurl('helpdesk/domain/'),
|
|
'securityLevelDataUrl' => lurl('helpdesk/domains/security-level-data'),
|
|
'exportUrl' => endpointUrl('helpdesk/domains/export'),
|
|
'gridLang' => gridLang(),
|
|
'gridSearch' => $searchConfig,
|
|
'filterSchema' => $clientFilterSchema,
|
|
'filterChipMeta' => $filterChipMeta,
|
|
'labels' => [
|
|
'no' => t('No.'),
|
|
'customerName' => t('Customer Name'),
|
|
'url' => t('URL'),
|
|
'state' => t('State'),
|
|
'administration' => t('Administration'),
|
|
'contractType' => t('Contract type'),
|
|
'securityLevel' => t('Security level'),
|
|
'note' => t('Note'),
|
|
'saveError' => t('Save failed'),
|
|
],
|
|
]); ?></script>
|
|
<script type="module" src="<?php e(assetVersion('modules/helpdesk/js/pages/helpdesk-domains-index.js')); ?>"></script>
|