activeadmin-command_palette 0.1.8 → 0.1.9

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: 3801c8198b67b942accb14aa27744358b7991e66bf36de38de9fa94a796c89b4
4
- data.tar.gz: 9e103a701673046e5203ef0878484c17047ebcf61fc83cc91e2cff94bef49723
3
+ metadata.gz: 761e971bf2eb65439610f528638603ba826aabf467d368fd33dd64b036b71bdd
4
+ data.tar.gz: 954b5c0eaae03a6d77bfc928dc7d3fe3b33264254d5c2deb958920bdd2e5c402
5
5
  SHA512:
6
- metadata.gz: 12c57eb1fa8b2682c53f4c2616806de2a8bc1449949d3850bff5deef2d10f687c5ebcb7fd861126ed0dafdc64a68b4c15b7186c09438bcb0eab4e5fb9cef670c
7
- data.tar.gz: bd79f196c0e4a3330191b4bee534d2fce4010faa3199cbdcd46c19531b25a8dce41e7367476bbc691d6053f3264823df198c3f08c4a7e25cab7f80324d5ba96a
6
+ metadata.gz: 02d020e34c042e0e4932009b19993cb5a94da75ce1014e13456fb4cd51c73b1244b89a255fc9e86329f939049d7581f2b418a0914349d53828b8ad52c0555257
7
+ data.tar.gz: f8004fd341df11671cfaa26c5d1048c234009f9e2956517988baf04940597d9bc9e78cc50178c3f5c227582f7a9854ee7a1118e51c858a7456ae1b4dfbd6c5b0
data/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # CHANGELOG
2
2
 
3
- ## Unreleased
3
+ ## 0.1.9 (2026-11-03)
4
+
5
+ - Keep navigation working when browser storage is unavailable.
6
+ - Fail closed when release confirmation input reaches EOF.
7
+ - Enforce CSRF protection on the options endpoint itself.
8
+ - Treat a nil host finder payload as an empty result list.
9
+ - Prefer `new_admin_user_session_path` before `new_user_session_path` for the sign-in recovery link.
10
+ - Navigate only through resolved `http`/`https` URLs after same-origin checks.
11
+ - Document host finder authorization, POST preference, and options rate limits in the install README.
12
+ - Use ASCII punctuation in palette copy, breadcrumbs, and help strings.
13
+ - Mark RFC 0007 and RFC 0008 Stable after their feedback windows closed.
4
14
 
5
15
  ## 0.1.8
6
16
 
data/README.md CHANGED
@@ -58,7 +58,7 @@ ActiveAdmin.register User do
58
58
  find_by :email, :nickname, :name
59
59
  order :name
60
60
  actions :view, :create, :edit, :destroy
61
- create help: "Create user — optional email=", params: [
61
+ create help: "Create user - optional email=", params: [
62
62
  {name: "email", required: false, query_key: "user[email]"}
63
63
  ]
64
64
  member "Open in chat",
@@ -88,7 +88,7 @@ end
88
88
 
89
89
  `reload!` (run from ActiveAdmin `after_load`) merges resource DSL actions/finders with the global `actions` list.
90
90
 
91
- Action fields: `scope` (`global` / `collection` / `member`), `when` (`any` / `index` / `show` / `new` / `edit`), `resource`, `verb` (`view` / `create` / `edit` / `destroy` / …), `params`, `help`, `finder_kind`, `query`, `if` (boolean or callable evaluated in the view on each request), optional `detail` / `keywords`. The layout emits a page `context` value used to gate member and collection actions.
91
+ Action fields: `scope` (`global` / `collection` / `member`), `when` (`any` / `index` / `show` / `new` / `edit`), `resource`, `verb` (`view` / `create` / `edit` / `destroy` / ...), `params`, `help`, `finder_kind`, `query`, `if` (boolean or callable evaluated in the view on each request), optional `detail` / `keywords`. The layout emits a page `context` value used to gate member and collection actions.
92
92
 
93
93
  Finder rows may include optional `detail` (second line under the label; `subtitle` is accepted as an alias) and `keywords` (extra client match strings). Longer registered prefixes win when several share a start (for example `@team` before `@`).
94
94
 
@@ -96,7 +96,13 @@ Finder rows may include optional `detail` (second line under the label; `subtitl
96
96
 
97
97
  Apply host authorization before returning rows. Prefer this match order when building SQL: exact primary key, then exact unique columns from `find_by`, then prefix match, then `ILIKE` / `LIKE`, then `limit`. Put a stable person-facing name in `label` and email, identifier, or id in `detail` when that helps operators disambiguate.
98
98
 
99
- Mount the engine inside your authenticated admin boundary and set `authorize_with` so the JSON options endpoint stays closed to unsigned or unauthorized callers.
99
+ Host checklist before production:
100
+
101
+ 1. Mount the engine inside the authenticated admin boundary.
102
+ 2. Set `authorize_with` so unsigned or unauthorized callers cannot hit the JSON options endpoint.
103
+ 3. Scope every finder with the same record policy as the ActiveAdmin resource (`accessible_by`, `policy_scope`, or equivalent). Do not copy a bare `.all` finder into a multi-role or multi-tenant app.
104
+ 4. Prefer the CSRF-protected `POST` client path. Treat `GET .../options` as a legacy integration surface: `q` can appear in access logs, proxies, and history.
105
+ 5. Rate-limit `/admin/command_palette/options` at the host (the gem caps rows per request, not request volume).
100
106
 
101
107
  ### Related surfaces
102
108
 
@@ -135,7 +141,7 @@ make release
135
141
 
136
142
  ## Design RFCs
137
143
 
138
- Numbered design documents for the public contract live in [`rfcs/`](rfcs/README.md). Shipped features are specified in RFC 0003 through RFC 0006. Finder detail and bounded POST search are proposed in RFC 0007 and RFC 0008. Process rules are RFC 0001.
144
+ Numbered design documents for the public contract live in [`rfcs/`](rfcs/README.md). Shipped features are specified in RFC 0003 through RFC 0008. Process rules are RFC 0001.
139
145
 
140
146
  ## Links
141
147
 
@@ -59,7 +59,7 @@ Gem::Specification.new do |spec|
59
59
  spec.add_development_dependency "rubocop-rails", "~> 2.34"
60
60
  spec.add_development_dependency "rubocop-rspec", "~> 3.8"
61
61
  spec.add_development_dependency "rubocop-thread_safety", "~> 0.7"
62
- spec.add_development_dependency "sqlite3", ">= 2.9.6"
62
+ spec.add_development_dependency "sqlite3", ">= 2.10.2"
63
63
  spec.add_development_dependency "standard", "~> 1.52"
64
64
  spec.add_development_dependency "standard-custom", "~> 1.0"
65
65
  spec.add_development_dependency "standard-performance", "~> 1.8"
@@ -21,7 +21,7 @@ export default class extends Controller {
21
21
  minQueryLength: { type: Number, default: 2 },
22
22
  requestTimeout: { type: Number, default: REQUEST_TIMEOUT_MS },
23
23
  empty: { type: String, default: "No matches" },
24
- loading: { type: String, default: "Searching…" },
24
+ loading: { type: String, default: "Searching..." },
25
25
  error: { type: String, default: "Search failed. Try again." },
26
26
  unauthorized: {
27
27
  type: String,
@@ -489,7 +489,11 @@ export default class extends Controller {
489
489
  0,
490
490
  RECENT_LIMIT
491
491
  );
492
- sessionStorage.setItem(RECENT_KEY, JSON.stringify(next));
492
+ try {
493
+ sessionStorage.setItem(RECENT_KEY, JSON.stringify(next));
494
+ } catch (_error) {
495
+ // Navigation must remain available when browser storage is disabled.
496
+ }
493
497
  }
494
498
 
495
499
  render() {
@@ -716,7 +720,7 @@ export default class extends Controller {
716
720
  rows.push({
717
721
  id: `${action.id}-param-${param.name}`,
718
722
  kind: "help",
719
- label: `${param.name}= (${required})${param.help ? ` — ${param.help}` : ""}`,
723
+ label: `${param.name}= (${required})${param.help ? ` - ${param.help}` : ""}`,
720
724
  url: null,
721
725
  });
722
726
  });
@@ -785,7 +789,7 @@ export default class extends Controller {
785
789
  const resolved = new URL(url, window.location.href);
786
790
  if (resolved.protocol !== "http:" && resolved.protocol !== "https:") return null;
787
791
  if (sameOrigin && resolved.origin !== window.location.origin) return null;
788
- return url;
792
+ return resolved.href;
789
793
  } catch (_error) {
790
794
  return null;
791
795
  }
@@ -3,6 +3,8 @@
3
3
  module ActiveAdmin
4
4
  module CommandPalette
5
5
  class OptionsController < ::ApplicationController
6
+ protect_from_forgery with: :exception
7
+
6
8
  before_action :prevent_command_palette_caching
7
9
  before_action :authenticate_command_palette_user!
8
10
 
@@ -5,17 +5,17 @@ en:
5
5
  open: Open command palette
6
6
  open_short: Search
7
7
  query_label: Search commands
8
- placeholder: "Go to… > actions ? help"
9
- footer: "↑↓ navigate ↵ open esc close"
8
+ placeholder: "Go to... > actions ? help"
9
+ footer: "Up/Down navigate Enter open Esc close"
10
10
  empty: No matches
11
- loading: Searching…
11
+ loading: Searching...
12
12
  error: Search failed. Try again.
13
13
  unauthorized: Session expired. Sign in again to keep searching.
14
14
  forbidden: You do not have permission to search these records.
15
15
  required: required
16
16
  optional: optional
17
17
  help:
18
- go: "Go / Find — type to jump pages and records"
19
- actions: "> Actions — run registered commands"
20
- resource: "> View / Create — search or open new; Edit / Delete on a record page"
21
- modes: "? Help — show these mode tips"
18
+ go: "Go / Find - type to jump pages and records"
19
+ actions: "> Actions - run registered commands"
20
+ resource: "> View / Create - search or open new; Edit / Delete on a record page"
21
+ modes: "? Help - show these mode tips"
@@ -5,17 +5,17 @@ fi:
5
5
  open: Avaa komentovalikko
6
6
  open_short: Haku
7
7
  query_label: Hae komentoja
8
- placeholder: "Siirry… > toiminnot ? ohje"
9
- footer: "↑↓ siirry ↵ avaa esc sulje"
8
+ placeholder: "Siirry... > toiminnot ? ohje"
9
+ footer: "Ylös/Alas siirry Enter avaa Esc sulje"
10
10
  empty: Ei osumia
11
- loading: Haetaan…
11
+ loading: Haetaan...
12
12
  error: Haku epäonnistui. Yritä uudelleen.
13
13
  unauthorized: Istunto päättyi. Kirjaudu uudelleen jatkaaksesi hakua.
14
14
  forbidden: Sinulla ei ole oikeutta hakea näitä tietueita.
15
15
  required: pakollinen
16
16
  optional: valinnainen
17
17
  help:
18
- go: "Siirry / Haku — kirjoita sivuille ja tietueisiin"
19
- actions: "> Toiminnot — suorita rekisteröityjä komentoja"
20
- resource: "> Näytä / Luo — hae tai avaa uusi; Muokkaa / Poista tietuesivulla"
21
- modes: "? Ohje — näytä nämä tilavihjeet"
18
+ go: "Siirry / Haku - kirjoita sivuille ja tietueisiin"
19
+ actions: "> Toiminnot - suorita rekisteröityjä komentoja"
20
+ resource: "> Näytä / Luo - hae tai avaa uusi; Muokkaa / Poista tietuesivulla"
21
+ modes: "? Ohje - näytä nämä tilavihjeet"
@@ -5,17 +5,17 @@ sv:
5
5
  open: Öppna kommandopaletten
6
6
  open_short: Sök
7
7
  query_label: Sök kommandon
8
- placeholder: "Gå till… > åtgärder ? hjälp"
9
- footer: "↑↓ navigera ↵ öppna esc stäng"
8
+ placeholder: "Gå till... > åtgärder ? hjälp"
9
+ footer: "Upp/Ner navigera Enter öppna Esc stäng"
10
10
  empty: Inga träffar
11
- loading: Söker…
11
+ loading: Söker...
12
12
  error: Sökningen misslyckades. Försök igen.
13
13
  unauthorized: Sessionen har gått ut. Logga in igen för att fortsätta söka.
14
14
  forbidden: Du har inte behörighet att söka efter dessa poster.
15
15
  required: obligatorisk
16
16
  optional: valfri
17
17
  help:
18
- go: "Gå / Sök — skriv för att hoppa till sidor och poster"
19
- actions: "> Åtgärder — kör registrerade kommandon"
20
- resource: "> Visa / Skapa — sök eller öppna ny; Redigera / Ta bort på postsida"
21
- modes: "? Hjälp — visa dessa tipslägen"
18
+ go: "Gå / Sök - skriv för att hoppa till sidor och poster"
19
+ actions: "> Åtgärder - kör registrerade kommandon"
20
+ resource: "> Visa / Skapa - sök eller öppna ny; Redigera / Ta bort på postsida"
21
+ modes: "? Hjälp - visa dessa tipslägen"
@@ -167,7 +167,7 @@ module ActiveAdmin
167
167
  entry = {
168
168
  id: "nav-#{item.id}",
169
169
  kind: "navigate",
170
- label: crumbs.join(" › "),
170
+ label: crumbs.join(" > "),
171
171
  url: url,
172
172
  method: "get"
173
173
  }
@@ -83,7 +83,7 @@ module ActiveAdmin
83
83
  finder_kind: kind,
84
84
  scope: "global",
85
85
  when: "any",
86
- help: "View #{noun} — type a search term"
86
+ help: "View #{noun} - type a search term"
87
87
  }
88
88
  end
89
89
 
@@ -65,6 +65,8 @@ module ActiveAdmin
65
65
  end
66
66
 
67
67
  def normalize_results(results, kind:, limit:)
68
+ return [] if results.nil?
69
+
68
70
  results.take(limit).map { |item| normalize(item, kind) }
69
71
  end
70
72
 
@@ -70,11 +70,11 @@ module ActiveAdmin
70
70
  end
71
71
 
72
72
  def command_palette_sign_in_path
73
- if respond_to?(:new_user_session_path)
74
- new_user_session_path
75
- else
76
- "/user/sign_in"
73
+ %i[new_admin_user_session_path new_user_session_path].each do |helper_name|
74
+ return public_send(helper_name) if respond_to?(helper_name)
77
75
  end
76
+
77
+ "/user/sign_in"
78
78
  end
79
79
 
80
80
  def command_palette_help_items
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveAdmin
4
4
  module CommandPalette
5
- VERSION = "0.1.8"
5
+ VERSION = "0.1.9"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeadmin-command_palette
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Makarov
@@ -245,14 +245,14 @@ dependencies:
245
245
  requirements:
246
246
  - - ">="
247
247
  - !ruby/object:Gem::Version
248
- version: 2.9.6
248
+ version: 2.10.2
249
249
  type: :development
250
250
  prerelease: false
251
251
  version_requirements: !ruby/object:Gem::Requirement
252
252
  requirements:
253
253
  - - ">="
254
254
  - !ruby/object:Gem::Version
255
- version: 2.9.6
255
+ version: 2.10.2
256
256
  - !ruby/object:Gem::Dependency
257
257
  name: standard
258
258
  requirement: !ruby/object:Gem::Requirement