bug_reports_client 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ddf7fc7f7b28ffe23e4a4e2965343975fc2d353887f7215e3c7de627259caa34
4
- data.tar.gz: f5d7058b59536805b5c3554c7a1b34fc367a4db509fd804489bba639b153fed9
3
+ metadata.gz: fbb8da2de255d2a5894ce7079e462b6cc34d53fd3d4077560a4cb7ef3985df64
4
+ data.tar.gz: a01439a1eb84e11e51724dbb6b88456871580c654ede63ca57e261b78ab94c0f
5
5
  SHA512:
6
- metadata.gz: cc3d27ecbfb780ff73c4d13171d03ce10994c780303b4e50ead54a498b4c51725fe6b38cfb2dcd2d4f818baa875a3ac7286b0618ef082fd9d18bddb2865ef2aa
7
- data.tar.gz: 46f0ce019b199b6a86901d4b932905666e28689ba7221e0e5d534a5a98b1a15567bb9353d2978a5f652b4accfdb2de4506391ea1b9a50b80239e14abf966a239
6
+ metadata.gz: ac6b9dd379ca0530da20787480736f05d415fcac662df5ac58e2d52c61ae6054648bc9e0a15a82523e8c1077a4d4e5c9cd03113ad4acd44be7b0499099c96362
7
+ data.tar.gz: 780d9c5e1ce19a35eca0c762dc15a0188f7a3be89958f19f540830e7721641b8ec558e0c9ac8ba5850cb1170c3f229d7a473066a41cb66fa5dcb649a8a2d9930
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2 (16 August 2026)
4
+
5
+ - Resolved-report alerts no longer stack. When a user has two or more
6
+ resolved, undismissed reports, the host layout shows a single collapsed
7
+ banner listing every title with one "Dismiss all" button (new
8
+ `PATCH /dismiss_all` route). A single resolved report keeps its own banner
9
+ and per-report Dismiss as before. Hosts that copied `_alerts.html.erb` via
10
+ the views generator will need to re-copy it to pick this up.
11
+
12
+ ## 0.1.1 (24 July 2026)
13
+
14
+ - The screenshot dropzone's drag-over highlight classes are configurable via
15
+ the `highlight-classes` Stimulus value, so dark-themed hosts can supply
16
+ theme-appropriate classes instead of the light slate defaults.
17
+
18
+ - `BUG_REPORT_APP_HOST` takes precedence over the shared `APP_HOST` env var
19
+ for the engine's public origin. `APP_HOST` is often owned by other host
20
+ concerns (mailers, OIDC issuers) in formats the engine cannot assume -
21
+ prefer the dedicated variable or an explicit `config.app_host`.
22
+
3
23
  ## 0.1.0 (23 July 2026)
4
24
 
5
25
  - Initial release: mountable engine with a schema-driven report form
data/README.md CHANGED
@@ -55,7 +55,7 @@ Environment variables (or set the equivalents in the initializer):
55
55
  | `BUG_REPORT_API_URL` | Base URL of the bug-reports API, e.g. `https://bugs.example.com/api` |
56
56
  | `BUG_REPORT_API_KEY` | This app's API token (Bearer auth) |
57
57
  | `BUG_REPORT_WEBHOOK_SECRET` | This app's webhook secret (HMAC verification of closure callbacks) |
58
- | `APP_HOST` | Public HTTPS origin of this app (callback URL + screenshot links) |
58
+ | `BUG_REPORT_APP_HOST` | Public HTTPS origin of this app (callback URL + screenshot links). Falls back to `APP_HOST`; prefer this or `config.app_host` if `APP_HOST` serves other purposes |
59
59
 
60
60
  On the API side, the app needs an `ApiKey` record and an entry in
61
61
  `config/repo_mapping.yml` mapping its `source` name to a GitHub repository.
@@ -208,7 +208,9 @@ Three Stimulus controllers ship with the engine and are pinned into your
208
208
  importmap automatically: `bug-reports-client--report-type` toggles the
209
209
  bug/feature field groups, `bug-reports-client--screenshot-dropzone` powers
210
210
  the drag-and-drop screenshot picker with thumbnail previews (the hidden file
211
- input stays the submission source, so custom forms can ignore it), and
211
+ input stays the submission source, so custom forms can ignore it; its
212
+ drag-over highlight is themeable via the `highlight-classes` Stimulus
213
+ value), and
212
214
  `bug-reports-client--file-limit` is a standalone file-count guard for
213
215
  hand-rolled forms. Any standard Stimulus setup that loads controllers from
214
216
  the importmap (`eagerLoadControllersFrom` / `lazyLoadControllersFrom`) picks
@@ -90,6 +90,26 @@ module BugReportsClient
90
90
  render :new, status: :unprocessable_entity
91
91
  end
92
92
 
93
+ # PATCH /dismiss_all
94
+ # Dismisses every resolved-and-undismissed alert for the current user in
95
+ # one go - the action behind the collapsed multi-report banner.
96
+ def dismiss_all
97
+ scope = BugReport.where(user: bug_reports_current_user).resolved_and_undismissed
98
+ # Column write, not update!: see dismiss_bug_report
99
+ scope.update_all(dismissed_at: Time.current, updated_at: Time.current)
100
+
101
+ respond_to do |format|
102
+ format.turbo_stream do
103
+ streams = [ turbo_stream.remove("bug_report_alerts") ]
104
+ streams << render_to_string(partial: "bug_reports_client/shared/after_dismiss", formats: [ :turbo_stream ])
105
+ render turbo_stream: streams
106
+ end
107
+ format.html do
108
+ redirect_to fallback_root_path, notice: t("bug_reports_client.flashes.dismissed_all")
109
+ end
110
+ end
111
+ end
112
+
93
113
  # PATCH /:id
94
114
  # Two cases: dismissing a resolved alert (no bug_report params), or
95
115
  # editing an open report (re-syncs the remote issue).
@@ -17,7 +17,10 @@ export default class extends Controller {
17
17
  max: { type: Number, default: 5 },
18
18
  maxBytes: { type: Number, default: 10_485_760 },
19
19
  limitMessage: String,
20
- sizeMessage: String
20
+ sizeMessage: String,
21
+ // Classes toggled on the zone while a file is dragged over it. Dark
22
+ // themes should override via the Stimulus value (space-separated).
23
+ highlightClasses: { type: String, default: "border-slate-500 bg-slate-100" }
21
24
  }
22
25
 
23
26
  connect() {
@@ -47,11 +50,15 @@ export default class extends Controller {
47
50
 
48
51
  dragover(event) {
49
52
  event.preventDefault()
50
- this.zoneTarget.classList.add("border-slate-500", "bg-slate-100")
53
+ this.zoneTarget.classList.add(...this.highlightClassList())
51
54
  }
52
55
 
53
56
  dragleave() {
54
- this.zoneTarget.classList.remove("border-slate-500", "bg-slate-100")
57
+ this.zoneTarget.classList.remove(...this.highlightClassList())
58
+ }
59
+
60
+ highlightClassList() {
61
+ return this.highlightClassesValue.split(/\s+/).filter(Boolean)
55
62
  }
56
63
 
57
64
  drop(event) {
@@ -1,7 +1,12 @@
1
1
  <%# Dismissable alerts for resolved reports. Rendered in HOST layouts via the
2
- bug_report_alerts helper, so routes go through the mount proxy. %>
2
+ bug_report_alerts helper, so routes go through the mount proxy.
3
+
4
+ One resolved report renders as its own banner. Two or more collapse into a
5
+ single banner listing every title with one "Dismiss all" button, so a
6
+ batch of fixes does not stack a wall of green boxes on every page. %>
3
7
  <div id="bug_report_alerts" class="mb-6">
4
- <% resolved_bug_reports.each do |report| %>
8
+ <% if resolved_bug_reports.size == 1 %>
9
+ <% report = resolved_bug_reports.first %>
5
10
  <div id="bug_report_<%= report.id %>" class="flex items-center justify-between p-3 mb-2 border border-green-200 rounded-lg bg-green-50">
6
11
  <div class="flex items-center gap-2">
7
12
  <svg class="flex-shrink-0 w-4 h-4 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -18,5 +23,32 @@
18
23
  <%= t("bug_reports_client.alerts.dismiss") %>
19
24
  <% end %>
20
25
  </div>
26
+ <% else %>
27
+ <div id="bug_report_alerts_collapsed" class="flex items-start justify-between gap-4 p-3 mb-2 border border-green-200 rounded-lg bg-green-50">
28
+ <div class="flex items-start gap-2 min-w-0">
29
+ <svg class="flex-shrink-0 w-4 h-4 mt-0.5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
30
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
31
+ </svg>
32
+ <div class="text-sm text-green-800 min-w-0">
33
+ <p class="font-medium">
34
+ <%= t("bug_reports_client.alerts.resolved_many", count: resolved_bug_reports.size) %>
35
+ </p>
36
+ <ul class="mt-1 space-y-0.5 list-disc list-inside text-green-700">
37
+ <% resolved_bug_reports.each do |report| %>
38
+ <li id="bug_report_<%= report.id %>" class="truncate">
39
+ <span class="text-green-600"><%= report.type_noun.capitalize %>:</span>
40
+ <span class="font-medium"><%= report.title %></span>
41
+ </li>
42
+ <% end %>
43
+ </ul>
44
+ </div>
45
+ </div>
46
+ <%= button_to bug_reports_client.dismiss_all_bug_reports_path,
47
+ method: :patch,
48
+ class: "text-xs text-green-600 hover:text-green-800 font-medium flex-shrink-0 cursor-pointer whitespace-nowrap",
49
+ data: { turbo_stream: true } do %>
50
+ <%= t("bug_reports_client.alerts.dismiss_all") %>
51
+ <% end %>
52
+ </div>
21
53
  <% end %>
22
54
  </div>
@@ -163,11 +163,14 @@ en:
163
163
  submit_failed: "Unable to submit your report. Please try again later."
164
164
  only_open_editable: "Only open %{type_noun}s can be updated."
165
165
  dismissed: "%{type_noun} notification dismissed."
166
+ dismissed_all: "All resolved alerts dismissed."
166
167
  not_permitted: "You do not have permission for this action."
167
168
 
168
169
  alerts:
169
170
  resolved_html: "Your %{type_noun} <span class=\"font-medium\">\"%{title}\"</span> has been resolved."
171
+ resolved_many: "%{count} of your reports have been resolved:"
170
172
  dismiss: "Dismiss"
173
+ dismiss_all: "Dismiss all"
171
174
 
172
175
  filters:
173
176
  type_label: "Type"
data/config/routes.rb CHANGED
@@ -2,11 +2,14 @@
2
2
  # GET /bug_reports - my reports
3
3
  # GET /bug_reports/new - the report form
4
4
  # GET /bug_reports/all - every report (admins, via config.admin_check)
5
+ # PATCH /bug_reports/dismiss_all - dismiss every resolved alert at once
5
6
  # POST /bug_reports/webhook - signed closure callbacks from the API
6
7
  BugReportsClient::Engine.routes.draw do
7
8
  resources :bug_reports, path: "", only: %i[index new create edit update] do
8
9
  collection do
9
10
  get :all
11
+ # Dismiss every resolved alert at once (the collapsed multi-report banner)
12
+ patch :dismiss_all
10
13
  end
11
14
  end
12
15
 
@@ -54,7 +54,11 @@ module BugReportsClient
54
54
  @api_url = ENV.fetch("BUG_REPORT_API_URL", "http://localhost:3002/api")
55
55
  @api_key = ENV["BUG_REPORT_API_KEY"]
56
56
  @webhook_secret = ENV["BUG_REPORT_WEBHOOK_SECRET"]
57
- @app_host = ENV["APP_HOST"]
57
+ # A dedicated variable takes precedence: APP_HOST is commonly shared
58
+ # with other host-app concerns (mailers, OIDC issuers) in formats the
59
+ # engine cannot assume, so hosts can isolate the engine with
60
+ # BUG_REPORT_APP_HOST - or set config.app_host explicitly.
61
+ @app_host = ENV["BUG_REPORT_APP_HOST"] || ENV["APP_HOST"]
58
62
  @app_name = nil
59
63
  @source = nil
60
64
  @mount_path = "/bug_reports"
@@ -1,3 +1,3 @@
1
1
  module BugReportsClient
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -8,7 +8,8 @@ BugReportsClient.configure do |config|
8
8
  config.source = "<%= Rails.application.class.module_parent_name.underscore %>"
9
9
 
10
10
  # The public HTTPS origin of this app, used for the closure callback URL and
11
- # screenshot links in GitHub issues. Defaults to ENV["APP_HOST"].
11
+ # screenshot links in GitHub issues. Defaults to ENV["BUG_REPORT_APP_HOST"],
12
+ # then ENV["APP_HOST"] - set it explicitly if APP_HOST serves other purposes.
12
13
  # config.app_host = "https://myapp.example.com"
13
14
 
14
15
  # Who counts as an admin (can see /bug_reports/all).
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bug_reports_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - PSA Squash Tour
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-23 00:00:00.000000000 Z
11
+ date: 2026-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails