Files
sure/app/javascript/controllers/expandable_controller.js
T
Juan José MataandClaude Opus 5 47525d7a73 Add expandable dialog for debug log table (#3051)
* feat(debug): add expandable view to the debug event log

The /settings/debug table packs seven columns of long-form diagnostics
into one row, so messages, context IDs, and metadata are all cramped and
hard to read.

Borrows the expand pattern from the dashboard cashflow chart (#739):
hovering a log row reveals a DS::Button icon trigger (always visible
below `lg`, where there is no hover state, and on keyboard focus) that
opens the entry in a roomy DS::Dialog. The expanded view lays the entry
out vertically — level/category as DS::Pill badges, the full message,
source, each context ID labelled, and pretty-printed metadata in a
scrollable block.

- Extract the row into a `_log_entry` partial now that it carries the
  trigger and its dialog.
- Add a generic `expandable` Stimulus controller that opens the <dialog>
  inside its scope, since the trigger sits outside the DS--dialog
  controller's scope.
- Add `Settings::DebugsHelper` for the level-to-pill-tone mapping and the
  context field list, keeping the logic out of the template.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRNRykqxBvgWwA2Wm8KiXH

* refactor(debug): expand the whole log table, not individual rows

The expand affordance belongs on the table card, matching the dashboard
cashflow chart it is modelled on: one trigger in the card's header strip
reopens the entire log in a near full-width dialog, where all seven
columns finally have room.

- Extract the table into a `_log_table` partial so the inline card and
  the expanded dialog render the same markup, and give its header
  `sticky top-0` — inert inline, useful once the expanded copy scrolls.
- Drop the per-row trigger, its detail dialog, and the `Settings::DebugsHelper`
  and locale keys that only existed to support them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRNRykqxBvgWwA2Wm8KiXH

* fix(debug): reveal expand button on coarse pointers, lift width to DS

Addresses review feedback on the expandable debug log table.

- The expand trigger was hidden by `lg:opacity-0` and only revealed by
  hover, so a touch-only device wide enough to hit `lg` — a large tablet —
  had no way to discover it. Viewport width is the wrong proxy for hover
  capability; switch to the shape the dashboard insights feed already
  uses: hidden by default, revealed by hover, focus, or `pointer-coarse`.
- The `!w-[96vw] max-w-[1650px]` expanded-dialog shape was hand-rolled at
  the callsite in two places. Lift it into `DS::Dialog::WIDTHS[:expanded]`
  and use it from both the debug log and the dashboard cashflow chart, so
  the arbitrary values live in the design system rather than in views. The
  emitted class string is unchanged in both cases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRNRykqxBvgWwA2Wm8KiXH

* fix(ds): stop the expanded dialog overflowing narrow viewports

`!w-[96vw]` applied at every breakpoint, but `dialog_inner_classes` only
drops its `mx-3` gutter at `lg`. Below that the panel is 96vw + 24px of
margins inside a dialog box that is narrower than the viewport — `vw`
counts the scrollbar, the dialog's percentage-based box does not — so the
panel is clipped on both sides. Flex-shrink cannot absorb it either, once
nowrap content (the debug log's timestamp and context cells) raises the
panel's min-content width.

Scope the 96vw to `lg` and up, where the gutter is gone. Below `lg` the
base `w-full` + `mx-3` already fits, which is what every other dialog
width does.

Measured in Chromium against Tailwind 4.1.8 output, panel clipped per side:

  viewport            320    375    390    768   1024   1400
  !w-[96vw]         12.6   11.5   11.2      0      0      0
  lg:!w-[96vw]         0      0      0      0      0      0

Widths at 768/1024/1400 are unchanged (706/978/1344px).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRNRykqxBvgWwA2Wm8KiXH

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-16 08:02:23 +02:00

25 lines
781 B
JavaScript

import { Controller } from "@hotwired/stimulus";
// Connects to data-controller="expandable"
//
// Reopens a cramped card (a chart, a wide table) in a roomier modal, mirroring
// the dashboard cashflow expand button. The trigger lives outside the <dialog>,
// so it is out of scope for the DS--dialog controller's own actions — this thin
// wrapper bridges the two.
//
// Native <dialog> tracks the previously focused element across showModal() /
// close(), so focus returns to the expand button on its own.
export default class extends Controller {
static targets = ["dialog"];
open() {
const dialog = this.hasDialogTarget
? this.dialogTarget
: this.element.querySelector("dialog");
if (!dialog || dialog.open) return;
dialog.showModal();
}
}