From 7f1a0dbeb49f509f8320ab381b04da0bd59411ec Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 31 Oct 2026 11:34:21 +0800 Subject: [PATCH] fix(admin): remove duplicate ticket dialog subtitle Keep the ticket number and status in the sidebar only, remove the unused header description payload and bindings, and update dialog regression coverage. Co-Authored-By: Claude Opus 5 (1M context) --- assets/js/admin-tickets.js | 4 ---- src/Admin/Native/UsersMenusTicketsCenter.php | 1 - src/Admin/Native/UsersMenusTicketsDialogs.php | 8 ++++---- tests/admin/ticket-dialog-runtime.test.cjs | 16 +++++++--------- tests/admin/ticket-native-render.test.cjs | 4 ++++ 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/assets/js/admin-tickets.js b/assets/js/admin-tickets.js index dade79e8..2ff771e8 100644 --- a/assets/js/admin-tickets.js +++ b/assets/js/admin-tickets.js @@ -12,9 +12,7 @@ var panel = detailDialog.querySelector('[data-aksrt-ticket-panel]'); var list = root.querySelector('[data-aksrt-ticket-list]'); var detailTitle = document.getElementById('aksrt-ticket-detail-title'); - var detailDescription = document.getElementById('aksrt-ticket-detail-description'); var initialTitle = detailTitle.textContent; - var initialDescription = detailDescription.textContent; var baselines = new WeakMap(); var active = null; var opener = null; @@ -179,7 +177,6 @@ if (current !== generation || active !== detailDialog) return; panel.innerHTML = data.panel; detailTitle.textContent = data.title; - detailDescription.textContent = data.description; if (typeof data.list === 'string') list.innerHTML = data.list; updateUrl(id, data.page); setupForms(panel, restore); @@ -225,7 +222,6 @@ function openDetail(id, source, refresh, message) { ticketId = id; detailTitle.textContent = initialTitle; - detailDescription.textContent = initialDescription; show(detailDialog, source); updateUrl(id); return loadDetail(id, !!refresh, message || '', {}); diff --git a/src/Admin/Native/UsersMenusTicketsCenter.php b/src/Admin/Native/UsersMenusTicketsCenter.php index 96cfd1c4..bc35413b 100644 --- a/src/Admin/Native/UsersMenusTicketsCenter.php +++ b/src/Admin/Native/UsersMenusTicketsCenter.php @@ -107,7 +107,6 @@ trait UsersMenusTicketsCenter { } $data['panel'] = $this->render_ticket_detail_panel($ticket); $data['title'] = (string) $ticket['title']; - $data['description'] = (string) $ticket['ticket_num'] . ' / ' . (string) $ticket['status_label']; } if ($refresh_list) { ob_start(); diff --git a/src/Admin/Native/UsersMenusTicketsDialogs.php b/src/Admin/Native/UsersMenusTicketsDialogs.php index f64b9dc6..9f28d3b0 100644 --- a/src/Admin/Native/UsersMenusTicketsDialogs.php +++ b/src/Admin/Native/UsersMenusTicketsDialogs.php @@ -41,15 +41,15 @@ trait UsersMenusTicketsDialogs { } echo '' . ($types === [] ? '' : '') . ''; - echo '
'; - echo $this->ticket_dialog_header('detail', __('工单详情', 'aksrt'), __('查看沟通记录并处理工单。', 'aksrt')); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo '
'; + echo $this->ticket_dialog_header('detail', __('工单详情', 'aksrt')); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $this->ticket_dialog_feedback(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo '
'; } - private function ticket_dialog_header(string $key, string $title, string $description): string { + private function ticket_dialog_header(string $key, string $title, string $description = ''): string { return '

' . esc_html($title) . '

' - . '

' . esc_html($description) . '

' + . ($description !== '' ? '

' . esc_html($description) . '

' : '') . '
' . ''; } diff --git a/tests/admin/ticket-dialog-runtime.test.cjs b/tests/admin/ticket-dialog-runtime.test.cjs index 7514e5c6..5bfd3b30 100644 --- a/tests/admin/ticket-dialog-runtime.test.cjs +++ b/tests/admin/ticket-dialog-runtime.test.cjs @@ -269,8 +269,6 @@ function makeRuntime({ href = 'https://site.test/wp-admin/users.php?page=aksrt_t const detailFrame = el('div', {}, detailDialog); const detailTitle = el('h2', { id: 'aksrt-ticket-detail-title', autofocus: '' }, detailFrame); detailTitle.textContent = 'Ticket detail'; - const detailDescription = el('p', { id: 'aksrt-ticket-detail-description' }, detailFrame); - detailDescription.textContent = 'View the conversation'; feedbackBox(detailDialog); const panel = el('div', { 'data-aksrt-ticket-panel': '' }, detailFrame); panel.isPanel = true; @@ -362,7 +360,7 @@ function makeRuntime({ href = 'https://site.test/wp-admin/users.php?page=aksrt_t document, window, fetch, URL, AbortController, setTimeout, clearTimeout, }, { filename: scriptPath }); - return { document, window, root, list, createDialog, detailDialog, createForm, createOpener, detailTitle, detailDescription, panel, viewsById, fetchCalls }; + return { document, window, root, list, createDialog, detailDialog, createForm, createOpener, detailTitle, panel, viewsById, fetchCalls }; } function response(data, status = 200) { @@ -396,7 +394,7 @@ function loadDetail(runtime, id = 41, status = 'pending') { assert.ok(opener, `missing opener for ${id}`); runtime.root.fire('click', { target: opener }); assert.equal(runtime.fetchCalls.length, 1); - resolveFetch(runtime, 0, { success: true, data: { panel: `ticket:${id}:${status}`, title: `Ticket ${id}`, description: `#${id}`, page: 1 } }); + resolveFetch(runtime, 0, { success: true, data: { panel: `ticket:${id}:${status}`, title: `Ticket ${id}`, page: 1 } }); return tick(); } @@ -444,7 +442,7 @@ test('detail load ignores a response that arrives after cancellation', async () assert.equal(runtime.detailDialog.open, false); assert.equal(pending.options.signal.aborted, true); - resolveFetch(runtime, 0, { success: true, data: { panel: 'ticket:41', title: 'Late title', description: 'Late', page: 1 } }); + resolveFetch(runtime, 0, { success: true, data: { panel: 'ticket:41', title: 'Late title', page: 1 } }); await tick(); assert.equal(runtime.panel.querySelector('[data-aksrt-ticket-form]'), null); assert.equal(runtime.detailTitle.textContent, 'Ticket detail'); @@ -467,7 +465,7 @@ test('deep link loads an ID even when it is absent from the current list', async assert.equal(read.searchParams.get('ticket_type_id'), '6'); assert.equal(read.searchParams.get('s'), 'network'); assert.equal(read.searchParams.get('paged'), '3'); - resolveFetch(runtime, 0, { success: true, data: { panel: 'ticket:987', title: 'Ticket 987', description: '#987', page: 3 } }); + resolveFetch(runtime, 0, { success: true, data: { panel: 'ticket:987', title: 'Ticket 987', page: 3 } }); await tick(); assert.equal(runtime.panel.querySelector('[data-aksrt-ticket-detail="987"]') !== null, true); }); @@ -510,7 +508,7 @@ test('successful create waits for its asynchronous close event before opening th assert.equal(runtime.fetchCalls.length, 2); assert.equal(runtime.detailDialog.open, true); assert.equal(runtime.document.documentElement.classList.contains('aksrt-ticket-modal-open'), true); - resolveFetch(runtime, 1, { success: true, data: { panel: 'ticket:303', title: 'New issue', description: '#303', list: 'updated rows', page: 1 } }); + resolveFetch(runtime, 1, { success: true, data: { panel: 'ticket:303', title: 'New issue', list: 'updated rows', page: 1 } }); await tick(); assert.equal(runtime.panel.querySelector('[data-aksrt-ticket-detail="303"]') !== null, true); assert.equal(runtime.list.innerHTML, 'updated rows'); @@ -546,7 +544,7 @@ test('reply, status, and note saves refresh detail and list while restoring othe const statusAfterSave = kind === 'status' ? 'handling' : 'pending'; resolveFetch(runtime, 2, { success: true, - data: { panel: `ticket:41:${statusAfterSave}`, title: 'Ticket 41', description: '#41', list: `rows-after-${kind}`, page: 1 }, + data: { panel: `ticket:41:${statusAfterSave}`, title: 'Ticket 41', list: `rows-after-${kind}`, page: 1 }, }); await tick(); @@ -630,7 +628,7 @@ test('a saved write followed by a failed refresh retries only the read', async ( runtime.root.fire('click', { target: retry }); assert.equal(runtime.fetchCalls.length, 4); assert.equal(runtime.fetchCalls[3].options.method, undefined); - resolveFetch(runtime, 3, { success: true, data: { panel: 'ticket:41', title: 'Ticket 41', description: '#41', list: 'fresh rows', page: 1 } }); + resolveFetch(runtime, 3, { success: true, data: { panel: 'ticket:41', title: 'Ticket 41', list: 'fresh rows', page: 1 } }); await tick(); assert.equal(runtime.fetchCalls.filter((call) => call.options.method === 'POST').length, 1); assert.equal(formsIn(runtime).note.querySelector('[name="content"]').value, 'Keep this draft'); diff --git a/tests/admin/ticket-native-render.test.cjs b/tests/admin/ticket-native-render.test.cjs index 45ac6068..e6a4bfc2 100644 --- a/tests/admin/ticket-native-render.test.cjs +++ b/tests/admin/ticket-native-render.test.cjs @@ -18,6 +18,8 @@ test('page renders header creation action and one of each dialog, without eagerl assert.equal((html.match(/工单号<\/dt>
TK-00021<\/dd>/); }); test('read handler enforces capability, nonce and record existence', () => {