feedback_engine 0.4.0 → 0.4.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 +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +61 -3
- data/Rakefile +14 -3
- data/app/views/feedback_engine/feedbacks/index.html.erb +1 -1
- data/app/views/layouts/feedback_engine/application.html.erb +3 -2
- data/config/locales/feedback_engine.ar.yml +1 -1
- data/config/locales/feedback_engine.bg.yml +1 -1
- data/config/locales/feedback_engine.bn.yml +1 -1
- data/config/locales/feedback_engine.de.yml +1 -1
- data/config/locales/feedback_engine.el.yml +1 -1
- data/config/locales/feedback_engine.en.yml +2 -1
- data/config/locales/feedback_engine.es.yml +1 -1
- data/config/locales/feedback_engine.fr.yml +1 -1
- data/config/locales/feedback_engine.hi.yml +1 -1
- data/config/locales/feedback_engine.hr.yml +1 -1
- data/config/locales/feedback_engine.id.yml +1 -1
- data/config/locales/feedback_engine.it.yml +1 -1
- data/config/locales/feedback_engine.ja.yml +1 -1
- data/config/locales/feedback_engine.ko.yml +1 -1
- data/config/locales/feedback_engine.lb.yml +1 -1
- data/config/locales/feedback_engine.nl.yml +1 -1
- data/config/locales/feedback_engine.pl.yml +1 -1
- data/config/locales/feedback_engine.pt.yml +1 -1
- data/config/locales/feedback_engine.ro.yml +1 -1
- data/config/locales/feedback_engine.ru.yml +1 -1
- data/config/locales/feedback_engine.th.yml +1 -1
- data/config/locales/feedback_engine.tr.yml +1 -1
- data/config/locales/feedback_engine.uk.yml +1 -1
- data/config/locales/feedback_engine.ur.yml +1 -1
- data/config/locales/feedback_engine.vi.yml +1 -1
- data/config/locales/feedback_engine.zh-CN.yml +1 -1
- data/lib/feedback_engine/version.rb +1 -1
- data/lib/feedback_engine/widget.rb +4 -2
- metadata +4 -2
- /data/{app/assets → lib}/feedback_engine/widget.js +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 39367932533823837a4fd7aea327721b0a7602f1126c4aa22957da7f446e4216
|
|
4
|
+
data.tar.gz: 8083993df53341407986e39e1c35abdff31b81cb4e919757e541fe2213511658
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a1c398155420791fab17aa5cfd0fadfd14402bbb08b13c551e7ae35f2409a5c22fb315980a92f5bd8edd69102b3e875533f71a3b61bc35ee35e26096dde8121
|
|
7
|
+
data.tar.gz: 31ad4cd63d5dba0dab5f97c237d3ebd49d54ed7bb78b7e13d890bc7f8df6bd41a199caebcdd9559f637e0479f63f1d2c48330ac70537470b9987f4c997faf9c8
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.2 (2026-07-25)
|
|
4
|
+
|
|
5
|
+
- The default title CTA (`feedback_engine.title`, used as the modal heading
|
|
6
|
+
and by host-rendered triggers) now reads "Send bug/feature request" instead
|
|
7
|
+
of "Send feedback", localized in all 26 bundled languages.
|
|
8
|
+
- The test suite migrated from RSpec to Minitest (development-only change;
|
|
9
|
+
nothing in the shipped gem is affected). `bundle exec rake test` and
|
|
10
|
+
`rake test:system` replace the rspec commands.
|
|
11
|
+
|
|
12
|
+
## 0.4.1 (2026-07-23)
|
|
13
|
+
|
|
14
|
+
- The widget JavaScript moved from `app/assets/` to `lib/` (it was always
|
|
15
|
+
inlined server-side, never served as an asset). Rails auto-registers every
|
|
16
|
+
engine's `app/assets/*` directory with the host's asset pipeline, so
|
|
17
|
+
Propshaft hosts were ingesting the file into their asset namespace under
|
|
18
|
+
the bare logical name `widget.js` — colliding with any other gem or host
|
|
19
|
+
file of the same name — and needlessly digesting a public copy at
|
|
20
|
+
precompile. The gem is now invisible to Sprockets/Propshaft entirely.
|
|
21
|
+
No behavior change.
|
|
22
|
+
|
|
3
23
|
## 0.4.0 (2026-07-22)
|
|
4
24
|
|
|
5
25
|
- Removed the clipboard-paste / drag-and-drop / file-chips screenshot intake
|
data/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# feedback_engine
|
|
2
2
|
|
|
3
3
|
[](https://rubygems.org/gems/feedback_engine)
|
|
4
|
+
[](https://rubygems.org/gems/feedback_engine)
|
|
4
5
|
[](https://github.com/yshmarov/feedback-engine/actions/workflows/ci.yml)
|
|
5
6
|
[](MIT-LICENSE)
|
|
6
7
|
|
|
@@ -12,6 +13,30 @@ every submission in your own database. A minimal built-in dashboard lets you
|
|
|
12
13
|
browse and triage what users send. No third-party service, no data leaves your
|
|
13
14
|
app.
|
|
14
15
|
|
|
16
|
+
<picture>
|
|
17
|
+
<source media="(prefers-color-scheme: dark)" srcset="demo-widget-dark.png">
|
|
18
|
+
<img alt="The feedback widget: type, section, message, and screenshots" src="demo-widget-light.png" width="420">
|
|
19
|
+
</picture>
|
|
20
|
+
|
|
21
|
+
<picture>
|
|
22
|
+
<source media="(prefers-color-scheme: dark)" srcset="demo-dashboard-dark.png">
|
|
23
|
+
<img alt="The built-in triage dashboard: status tabs, filters, search" src="demo-dashboard-light.png" width="820">
|
|
24
|
+
</picture>
|
|
25
|
+
|
|
26
|
+
Both the widget and the dashboard follow the viewer's system appearance —
|
|
27
|
+
these screenshots are the same pages in light and dark mode.
|
|
28
|
+
|
|
29
|
+
## Why not Canny (or another feedback SaaS)?
|
|
30
|
+
|
|
31
|
+
Hosted feedback tools are great until you notice the trade: your users'
|
|
32
|
+
feedback lives in someone else's database, behind someone else's login, at a
|
|
33
|
+
per-seat price. `feedback_engine` keeps the core loop — collect, triage,
|
|
34
|
+
resolve — inside your app: **your database, your users, your auth, one gem.**
|
|
35
|
+
Attribution plugs into whatever authentication you already have, gating is a
|
|
36
|
+
lambda, and submissions are ordinary ActiveRecord rows you can query, export,
|
|
37
|
+
or wire into Slack. (A public voting board à la Canny is on the
|
|
38
|
+
[roadmap](https://github.com/yshmarov/feedback-engine/issues/1).)
|
|
39
|
+
|
|
15
40
|
- **Zero UI dependencies.** The widget is plain JavaScript and styles itself.
|
|
16
41
|
No Tailwind, no Stimulus, no importmap, no build step. The dashboard renders
|
|
17
42
|
its own styles too.
|
|
@@ -146,10 +171,42 @@ any element and (optionally) hide the button:
|
|
|
146
171
|
config.show_button = false # optional
|
|
147
172
|
```
|
|
148
173
|
|
|
174
|
+
Gate the trigger with the same check the widget uses — `feedback_engine_tag`
|
|
175
|
+
renders nothing when `config.enabled` rejects the request, so an unguarded
|
|
176
|
+
trigger would be a dead button for those users. The gem ships a
|
|
177
|
+
`feedback_engine.title` label ("Send bug/feature request") in every bundled language, so
|
|
178
|
+
a localized trigger needs no keys of your own:
|
|
179
|
+
|
|
180
|
+
```erb
|
|
181
|
+
<% if FeedbackEngine.enabled?(request) %>
|
|
182
|
+
<button data-feedback-engine-open><%= t("feedback_engine.title") %></button>
|
|
183
|
+
<% end %>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Loading the widget only where it's used
|
|
187
|
+
|
|
188
|
+
`feedback_engine_tag` in the layout puts the widget on every page. If your
|
|
189
|
+
only trigger lives on one page, render the tag on that page instead — for
|
|
190
|
+
example into the layout's `<head>` via `content_for`:
|
|
191
|
+
|
|
149
192
|
```erb
|
|
150
|
-
|
|
193
|
+
<%# app/views/layouts/application.html.erb %>
|
|
194
|
+
<head>
|
|
195
|
+
...
|
|
196
|
+
<%= yield :head %>
|
|
197
|
+
</head>
|
|
198
|
+
|
|
199
|
+
<%# app/views/users/show.html.erb — the page with the trigger %>
|
|
200
|
+
<% content_for :head, feedback_engine_tag %>
|
|
151
201
|
```
|
|
152
202
|
|
|
203
|
+
This is Turbo-safe: the script installs its document-level listeners once per
|
|
204
|
+
session and re-renders on `turbo:load` (see [Turbo](#turbo)), whether it
|
|
205
|
+
arrives on the first page load or a later visit. The trade-off: a
|
|
206
|
+
`data-feedback-engine-open` element on a page that never rendered the tag
|
|
207
|
+
silently does nothing — if triggers may appear on several pages, keep the tag
|
|
208
|
+
in the layout.
|
|
209
|
+
|
|
153
210
|
### Protecting the dashboard
|
|
154
211
|
|
|
155
212
|
The dashboard (index/show/triage) is gated by `config.authorize_admin`, which
|
|
@@ -266,11 +323,12 @@ document-level listeners once and re-renders on `turbo:load`.
|
|
|
266
323
|
|
|
267
324
|
```bash
|
|
268
325
|
bin/setup # or: bundle install
|
|
269
|
-
bundle exec
|
|
326
|
+
bundle exec rake test # unit + integration
|
|
327
|
+
bundle exec rake test:system # browser tests (headless Chrome)
|
|
270
328
|
bundle exec rubocop
|
|
271
329
|
```
|
|
272
330
|
|
|
273
|
-
Tests run against a dummy Rails app under `
|
|
331
|
+
Tests run against a dummy Rails app under `test/dummy`; the widget itself is
|
|
274
332
|
covered by Capybara system tests in a real browser. CI runs the suite across
|
|
275
333
|
Rails 7.1 / 7.2 / 8.0 / 8.1 and Ruby 3.2–3.4 (per-version Gemfiles live in
|
|
276
334
|
`gemfiles/`).
|
data/Rakefile
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'bundler/gem_tasks'
|
|
4
|
-
require '
|
|
4
|
+
require 'rake/testtask'
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
|
7
|
+
t.libs << 'test'
|
|
8
|
+
t.test_files = FileList['test/**/*_test.rb'].exclude('test/system/**/*')
|
|
9
|
+
end
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
namespace :test do
|
|
12
|
+
desc 'Run browser (system) tests'
|
|
13
|
+
Rake::TestTask.new(:system) do |t|
|
|
14
|
+
t.libs << 'test'
|
|
15
|
+
t.test_files = FileList['test/system/**/*_test.rb']
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
task default: :test
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<thead>
|
|
33
33
|
<tr>
|
|
34
34
|
<th><%= t('feedback_engine.kind', default: 'Type') %></th>
|
|
35
|
-
<th><%= t('feedback_engine.message', default: 'Message') %></th>
|
|
35
|
+
<th><%= t('feedback_engine.dashboard.message', default: 'Message') %></th>
|
|
36
36
|
<th><%= t('feedback_engine.section', default: 'Section') %></th>
|
|
37
37
|
<th><%= t('feedback_engine.dashboard.from', default: 'From') %></th>
|
|
38
38
|
<th><%= t('feedback_engine.dashboard.filed', default: 'Filed') %></th>
|
|
@@ -33,8 +33,9 @@
|
|
|
33
33
|
.count { display: inline-block; min-width: 20px; padding: 0 6px; margin-left: 4px; border-radius: 999px;
|
|
34
34
|
background: var(--border); font-size: 12px; text-align: center; }
|
|
35
35
|
.filters { margin-bottom: 16px; display: flex; gap: 8px; align-items: center; }
|
|
36
|
-
.filters select { padding: 6px 8px; border: 1px solid var(--border);
|
|
37
|
-
background: var(--surface); color: var(--text); }
|
|
36
|
+
.filters select, .filters input[type=search] { padding: 6px 8px; border: 1px solid var(--border);
|
|
37
|
+
border-radius: 8px; background: var(--surface); color: var(--text); font: inherit; }
|
|
38
|
+
.filters input[type=search] { flex: 1; max-width: 320px; }
|
|
38
39
|
.card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
|
|
39
40
|
table { width: 100%; border-collapse: collapse; }
|
|
40
41
|
th, td { padding: 10px 14px; text-align: left; vertical-align: top; }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
en:
|
|
2
2
|
feedback_engine:
|
|
3
3
|
button: "Feedback"
|
|
4
|
-
title: "Send
|
|
4
|
+
title: "Send bug/feature request"
|
|
5
5
|
kind: "Type"
|
|
6
6
|
kinds:
|
|
7
7
|
bug: "Bug report"
|
|
@@ -30,6 +30,7 @@ en:
|
|
|
30
30
|
title: "Feedback"
|
|
31
31
|
all_kinds: "All types"
|
|
32
32
|
filter: "Filter"
|
|
33
|
+
message: "Message"
|
|
33
34
|
search: "Search"
|
|
34
35
|
search_placeholder: "Search message, author, section…"
|
|
35
36
|
from: "From"
|
|
@@ -7,9 +7,11 @@ module FeedbackEngine
|
|
|
7
7
|
# framework, no build step) and styles itself inline, so it drops into any
|
|
8
8
|
# Rails app regardless of its CSS or JS setup. It is inlined into the page
|
|
9
9
|
# rather than served as a separate asset to avoid any dependency on the
|
|
10
|
-
# host's asset pipeline
|
|
10
|
+
# host's asset pipeline — and it lives under lib/ (not app/assets/) so a
|
|
11
|
+
# host that *does* run a pipeline never ingests it either: nothing lands in
|
|
12
|
+
# the host's asset namespace or precompiled output.
|
|
11
13
|
module Widget
|
|
12
|
-
SOURCE = File.expand_path('
|
|
14
|
+
SOURCE = File.expand_path('widget.js', __dir__)
|
|
13
15
|
|
|
14
16
|
# Right-to-left scripts, so the form renders mirrored for those locales.
|
|
15
17
|
# Matched on the language subtag, so region variants ("ar-EG") count too.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: feedback_engine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yaroslav Shmarov
|
|
@@ -38,7 +38,6 @@ files:
|
|
|
38
38
|
- MIT-LICENSE
|
|
39
39
|
- README.md
|
|
40
40
|
- Rakefile
|
|
41
|
-
- app/assets/feedback_engine/widget.js
|
|
42
41
|
- app/controllers/feedback_engine/application_controller.rb
|
|
43
42
|
- app/controllers/feedback_engine/feedbacks_controller.rb
|
|
44
43
|
- app/controllers/feedback_engine/screenshots_controller.rb
|
|
@@ -79,6 +78,7 @@ files:
|
|
|
79
78
|
- lib/feedback_engine/configuration.rb
|
|
80
79
|
- lib/feedback_engine/engine.rb
|
|
81
80
|
- lib/feedback_engine/version.rb
|
|
81
|
+
- lib/feedback_engine/widget.js
|
|
82
82
|
- lib/feedback_engine/widget.rb
|
|
83
83
|
- lib/generators/feedback_engine/install/install_generator.rb
|
|
84
84
|
- lib/generators/feedback_engine/install/templates/create_feedback_engine_feedbacks.rb.tt
|
|
@@ -87,8 +87,10 @@ homepage: https://github.com/yshmarov/feedback-engine
|
|
|
87
87
|
licenses:
|
|
88
88
|
- MIT
|
|
89
89
|
metadata:
|
|
90
|
+
homepage_uri: https://github.com/yshmarov/feedback-engine
|
|
90
91
|
source_code_uri: https://github.com/yshmarov/feedback-engine
|
|
91
92
|
changelog_uri: https://github.com/yshmarov/feedback-engine/blob/main/CHANGELOG.md
|
|
93
|
+
bug_tracker_uri: https://github.com/yshmarov/feedback-engine/issues
|
|
92
94
|
rubygems_mfa_required: 'true'
|
|
93
95
|
rdoc_options: []
|
|
94
96
|
require_paths:
|
|
File without changes
|