Files
sure/test/controllers/settings/debugs_controller_test.rb
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

94 lines
2.5 KiB
Ruby

require "test_helper"
class Settings::DebugsControllerTest < ActionDispatch::IntegrationTest
setup do
ensure_tailwind_build
@entry = DebugLogEntry.create!(
category: "security_price_fetch",
level: "warn",
message: "Could not fetch prices",
source: "Security::Price::Importer",
provider_key: "twelve_data",
family: families(:dylan_family),
account: accounts(:depository),
user: users(:family_admin),
metadata: { ticker: "AAPL" }
)
end
test "super admins can view debug log" do
sign_in users(:sure_support_staff)
get settings_debug_url
assert_response :success
assert_match "Debug event log", response.body
assert_match @entry.message, response.body
end
test "the log table can be expanded into a larger dialog" do
sign_in users(:sure_support_staff)
get settings_debug_url
assert_response :success
assert_select "[data-controller=expandable]", 1
assert_select "button[data-action=?]", "click->expandable#open", count: 1
# The expanded copy is the same table, so both render every entry.
assert_select "table tbody tr", 2
assert_select "dialog[data-expandable-target=dialog] table tbody tr", 1
end
test "no expand trigger is rendered when there are no entries" do
sign_in users(:sure_support_staff)
DebugLogEntry.delete_all
get settings_debug_url
assert_response :success
assert_select "button[data-action=?]", "click->expandable#open", count: 0
assert_select "dialog[data-expandable-target=dialog]", 0
end
test "non super admins are redirected" do
sign_in users(:family_admin)
get settings_debug_url
assert_redirected_to root_url
end
test "filters by provider key" do
sign_in users(:sure_support_staff)
DebugLogEntry.create!(
category: "security_price_fetch",
level: "warn",
message: "Should be filtered out",
source: "Security::Price::Importer",
provider_key: "finnhub",
family: families(:dylan_family),
account: accounts(:depository),
user: users(:family_admin),
metadata: { ticker: "MSFT" }
)
get settings_debug_url, params: { provider_key: "twelve_data" }
assert_response :success
assert_match @entry.message, response.body
refute_match "Should be filtered out", response.body
end
test "ignores invalid uuid filters" do
sign_in users(:sure_support_staff)
get settings_debug_url, params: { family_id: "not-a-uuid" }
assert_response :success
assert_match @entry.message, response.body
end
end