feat(admin): replace ticket dialogs with in-page views
Ticket handling on users.php?page=aksrt_tickets no longer uses dialogs. The list, the workspace (?id=N) and the assisted create form (?view=new) are server-rendered page views that carry the list filters and page for going back. Writes still go through the ticket REST routes; on success the page reloads with a native notice, and unsent drafts in other forms survive the reload via sessionStorage. Uncertain or conflicting writes lock every form and only offer a reload. Remove dead code: UsersMenusTicketsDialogs, the aksrt_ticket_view AJAX read and its nonce, dialog CSS/JS (backdrop, scroll lock, focus return, read races) and the dialog runtime test. Fix the create link carrying an unclamped page number on out-of-range list pages. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
48e54dc115
commit
d86a85e6a6
13 files changed
+720
-1264
No files matched your search
@@ -3,8 +3,6 @@
|
||||
namespace {
|
||||
define('ABSPATH', __DIR__);
|
||||
define('ARRAY_A', 'ARRAY_A');
|
||||
$GLOBALS['allowed'] = true;
|
||||
$GLOBALS['valid_nonce'] = true;
|
||||
function __($text, $domain = '') { return $text; }
|
||||
function esc_html($text) { return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8'); }
|
||||
function esc_attr($text) { return esc_html($text); }
|
||||
@@ -25,19 +23,12 @@ namespace {
|
||||
function get_users($args) { return [(object) ['ID' => 7, 'display_name' => 'Operator'], (object) ['ID' => 8, 'display_name' => 'Second']]; }
|
||||
function get_edit_user_link($id) { return admin_url('user-edit.php?user_id=' . $id); }
|
||||
function aksrt_get_avatar_url($id, $size) { return 'https://example.test/avatar/' . $id; }
|
||||
function current_user_can($cap) { return $GLOBALS['allowed']; }
|
||||
function check_ajax_referer($action, $key, $die) { return $action === 'aksrt_ticket_view' && $key === 'nonce' && $GLOBALS['valid_nonce']; }
|
||||
function add_query_arg($args, $url, $base = null) {
|
||||
if (!is_array($args)) { $args = [$args => $url]; $url = $base; }
|
||||
$parts = parse_url($url);
|
||||
parse_str($parts['query'] ?? '', $query);
|
||||
return $parts['scheme'] . '://' . $parts['host'] . ($parts['path'] ?? '') . '?' . http_build_query(array_merge($query, $args));
|
||||
}
|
||||
class JsonReply extends \Exception {
|
||||
public function __construct(public array $payload, public int $status) { parent::__construct(); }
|
||||
}
|
||||
function wp_send_json_success($data) { throw new JsonReply(['success' => true, 'data' => $data], 200); }
|
||||
function wp_send_json_error($data, $status) { throw new JsonReply(['success' => false, 'data' => $data], $status); }
|
||||
}
|
||||
namespace AKSRT\Ticket {
|
||||
class TicketSettings {
|
||||
@@ -108,7 +99,7 @@ namespace AKSRT\Core {
|
||||
}
|
||||
namespace {
|
||||
$root = dirname(__DIR__, 2);
|
||||
foreach (['NativeUi', 'AdminListPagination', 'UsersMenusTicketsList', 'UsersMenusTicketsDialogs', 'UsersMenusTicketsDetail', 'UsersMenusTicketsCenter'] as $file) {
|
||||
foreach (['NativeUi', 'AdminListPagination', 'UsersMenusTicketsList', 'UsersMenusTicketsCreate', 'UsersMenusTicketsDetail', 'UsersMenusTicketsCenter'] as $file) {
|
||||
require $root . '/src/Admin/Native/' . $file . '.php';
|
||||
}
|
||||
require $root . '/src/Ticket/TicketQuery.php';
|
||||
@@ -129,38 +120,31 @@ namespace {
|
||||
public function prepare($sql, $params) { $this->sql = $sql; $this->params = $params; return $sql; }
|
||||
public function get_results($sql, $format) { return [['status' => 'closed', 'total' => 2]]; }
|
||||
}
|
||||
$page = new TicketPage();
|
||||
$_GET = ['status' => 'handling', 'ticket_type_id' => 1, 's' => 'needle', 'paged' => 99, 'id' => 99];
|
||||
ob_start();
|
||||
$page->render_tickets_page();
|
||||
$html = ob_get_clean();
|
||||
$initial = ['queries' => \AKSRT\Ticket\TicketRepository::$queries, 'counts' => \AKSRT\Ticket\TicketRepository::$counts, 'detail_reads' => \AKSRT\Ticket\TicketRepository::$reads, 'reply_reads' => \AKSRT\Ticket\TicketRepository::$replies_read];
|
||||
function view($page, array $args) {
|
||||
$_GET = $args;
|
||||
try { $page->ajax_ticket_view(); } catch (JsonReply $reply) { return ['status' => $reply->status] + $reply->payload; }
|
||||
throw new \RuntimeException('Expected JSON response');
|
||||
function render_page(TicketPage $page, array $get): string {
|
||||
$_GET = $get;
|
||||
ob_start();
|
||||
$page->render_tickets_page();
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
$closed = view($page, ['id' => 99, 'status' => 'pending', 's' => 'not in list', 'refresh_list' => 1, 'paged' => 99]);
|
||||
$open = view($page, ['id' => 21]);
|
||||
$missing = view($page, ['id' => 404]);
|
||||
$GLOBALS['allowed'] = false;
|
||||
$denied = view($page, ['id' => 21]);
|
||||
$GLOBALS['allowed'] = true;
|
||||
$GLOBALS['valid_nonce'] = false;
|
||||
$nonce = view($page, ['id' => 21]);
|
||||
$GLOBALS['valid_nonce'] = true;
|
||||
$repo = \AKSRT\Ticket\TicketRepository::class;
|
||||
$page = new TicketPage();
|
||||
$list = render_page($page, ['status' => 'handling', 'ticket_type_id' => 1, 's' => 'needle', 'paged' => 99]);
|
||||
$initial = ['queries' => $repo::$queries, 'counts' => $repo::$counts, 'detail_reads' => $repo::$reads, 'reply_reads' => $repo::$replies_read];
|
||||
$list_queries = count($repo::$queries);
|
||||
$open = render_page($page, ['id' => 21, 'status' => 'pending', 's' => 'not in list', 'paged' => 3, 'aksrt_ticket_msg' => 'reply']);
|
||||
$closed = render_page($page, ['id' => 99]);
|
||||
$missing = render_page($page, ['id' => 404]);
|
||||
$detail_list_queries = count($repo::$queries) - $list_queries;
|
||||
$create = render_page($page, ['view' => 'new', 'status' => 'pending', 'paged' => 2]);
|
||||
$bogus_notice = render_page($page, ['id' => 21, 'aksrt_ticket_msg' => '<script>']);
|
||||
\AKSRT\Ticket\TicketTypeService::$empty = true;
|
||||
ob_start();
|
||||
$page->render_tickets_page();
|
||||
$no_types = ob_get_clean();
|
||||
$no_types = render_page($page, ['view' => 'new']);
|
||||
\AKSRT\Ticket\TicketTypeService::$empty = false;
|
||||
\AKSRT\Ticket\TicketSettings::$orders = false;
|
||||
ob_start();
|
||||
$page->render_tickets_page();
|
||||
$no_orders = ob_get_clean();
|
||||
$no_orders = render_page($page, ['view' => 'new']);
|
||||
$GLOBALS['wpdb'] = new FakeDb();
|
||||
$query = new QueryProbe();
|
||||
$where = $query->where([]);
|
||||
$statistic = $query->counts(['status' => ['pending', 'handling', 'closed', 'archived'], 'ticket_type_id' => 1, 'keywords' => 'needle']);
|
||||
echo json_encode(compact('html', 'initial', 'closed', 'open', 'missing', 'denied', 'nonce', 'no_types', 'no_orders', 'where', 'statistic') + ['count_sql' => $GLOBALS['wpdb']->sql, 'count_params' => $GLOBALS['wpdb']->params], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
echo json_encode(compact('list', 'initial', 'open', 'closed', 'missing', 'detail_list_queries', 'create', 'bogus_notice', 'no_types', 'no_orders', 'where', 'statistic') + ['count_sql' => $GLOBALS['wpdb']->sql, 'count_params' => $GLOBALS['wpdb']->params], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
Reference in new issue
Block a user