UX and architecture fixes: bulk-delete, template guard, statuses config
Bug fixes: - bulk-delete action called undefined bulkDelete() — wired to the existing showBulkDeleteModal() so the confirmation modal actually shows UX: - Template loader now checks for existing title/description and asks for confirmation before overwriting user-typed content - Visibility select shows a dynamic hint paragraph that updates when the user changes the selection (public/internal/confidential) Architecture: - TICKET_STATUSES added to config as single source of truth; all hardcoded ['Open','Pending','In Progress','Closed'] arrays in DashboardView now read from config; bulk-status modal in dashboard.js reads window.TICKET_STATUSES (set from PHP) with array fallback - ASSET_VERSION now auto-computed from max mtime of dashboard/ticket CSS+JS files so browsers always pick up changes on deploy; manual override still available via ASSET_VERSION in .env - Removed 10 dead standalone stat methods from StatsModel (getOpenTicketCount, getClosedTicketCount, getTicketsByPriority, etc.) — all superseded by the consolidated fetchAllStats() queries, never called externally Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -180,6 +180,7 @@ include __DIR__ . '/layout_header.php';
|
||||
<option value="internal">Internal — Specific groups only</option>
|
||||
<option value="confidential">Confidential — Creator, assignee, and admins only</option>
|
||||
</select>
|
||||
<p id="visibilityHint" class="lt-form-hint">Everyone who is logged in can view this ticket.</p>
|
||||
</div>
|
||||
|
||||
<div id="visibilityGroupsContainer" class="lt-form-group is-hidden" aria-live="polite">
|
||||
@@ -296,21 +297,39 @@ include __DIR__ . '/layout_header.php';
|
||||
}
|
||||
|
||||
// ── Visibility groups toggle ──────────────────────────────
|
||||
var visibilityHints = {
|
||||
'public': 'Everyone who is logged in can view this ticket.',
|
||||
'internal': 'Only members of the selected groups (plus admins) can view this ticket.',
|
||||
'confidential': 'Only you, the assignee, and admins can view this ticket.'
|
||||
};
|
||||
function toggleVisibilityGroups() {
|
||||
var vis = document.getElementById('visibility').value;
|
||||
var container = document.getElementById('visibilityGroupsContainer');
|
||||
var hint = document.getElementById('visibilityHint');
|
||||
if (vis === 'internal') {
|
||||
container.classList.remove('is-hidden');
|
||||
} else {
|
||||
container.classList.add('is-hidden');
|
||||
container.querySelectorAll('.visibility-group-checkbox').forEach(function (cb) { cb.checked = false; });
|
||||
}
|
||||
if (hint) hint.textContent = visibilityHints[vis] || '';
|
||||
}
|
||||
|
||||
// ── Template loader ───────────────────────────────────────
|
||||
function loadTemplate() {
|
||||
var tplId = document.getElementById('templateSelect').value;
|
||||
if (!tplId) return;
|
||||
|
||||
// Warn before overwriting content the user has already typed
|
||||
var existingTitle = (document.getElementById('title').value || '').trim();
|
||||
var existingDesc = (document.getElementById('description').value || '').trim();
|
||||
if (existingTitle || existingDesc) {
|
||||
if (!confirm('Applying this template will overwrite your current title and description. Continue?')) {
|
||||
document.getElementById('templateSelect').value = '';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lt.api.get('/api/get_template.php?template_id=' + encodeURIComponent(tplId))
|
||||
.then(function (data) {
|
||||
if (!data.success || !data.template) {
|
||||
|
||||
@@ -51,6 +51,7 @@ if (!empty($_GET['assigned_to'])) {
|
||||
$activeFilters[] = ['type' => 'assigned_to', 'value' => $_GET['assigned_to'], 'label' => 'Assigned: ' . $label];
|
||||
}
|
||||
|
||||
$_lt_statuses = $GLOBALS['config']['TICKET_STATUSES'];
|
||||
$currentStatus = isset($_GET['status']) ? explode(',', $_GET['status']) : ['Open', 'Pending', 'In Progress'];
|
||||
$currentCategories = isset($_GET['category']) ? explode(',', $_GET['category']) : [];
|
||||
$currentTypes = isset($_GET['type']) ? explode(',', $_GET['type']) : [];
|
||||
@@ -181,7 +182,7 @@ include __DIR__ . '/layout_header.php';
|
||||
<!-- Status Filter -->
|
||||
<fieldset class="lt-filter-group">
|
||||
<legend class="lt-filter-label">Status</legend>
|
||||
<?php foreach (['Open', 'Pending', 'In Progress', 'Closed'] as $s): ?>
|
||||
<?php foreach ($GLOBALS['config']['TICKET_STATUSES'] as $s): ?>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox sidebar-filter"
|
||||
name="status" value="<?= htmlspecialchars($s) ?>"
|
||||
@@ -592,11 +593,11 @@ include __DIR__ . '/layout_header.php';
|
||||
<div class="lt-kv-row">
|
||||
<span class="lt-kv-label">Default status filters</span>
|
||||
<span class="lt-kv-value lt-flex lt-flex-wrap lt-flex-gap-sm">
|
||||
<?php foreach (['Open','Pending','In Progress','Closed'] as $sf): ?>
|
||||
<?php foreach ($_lt_statuses as $sf): ?>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox" name="defaultFilters" value="<?= $sf ?>"
|
||||
<input type="checkbox" class="lt-checkbox" name="defaultFilters" value="<?= htmlspecialchars($sf) ?>"
|
||||
<?= in_array($sf, ['Open','Pending','In Progress']) ? 'checked' : '' ?>>
|
||||
<?= $sf ?>
|
||||
<?= htmlspecialchars($sf) ?>
|
||||
</label>
|
||||
<?php endforeach ?>
|
||||
</span>
|
||||
@@ -824,6 +825,7 @@ include __DIR__ . '/layout_header.php';
|
||||
DASHBOARD INLINE SCRIPT
|
||||
═══════════════════════════════════════════════════════════ -->
|
||||
<script nonce="<?= $nonce ?>">
|
||||
window.TICKET_STATUSES = <?= json_encode($GLOBALS['config']['TICKET_STATUSES']) ?>;
|
||||
// Initialize keyboard and table navigation
|
||||
if (window.lt) {
|
||||
lt.keys.initDefaults();
|
||||
|
||||
Reference in New Issue
Block a user