feedback_engine 0.1.0

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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +27 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +265 -0
  5. data/Rakefile +8 -0
  6. data/app/assets/feedback_engine/widget.js +368 -0
  7. data/app/controllers/feedback_engine/application_controller.rb +15 -0
  8. data/app/controllers/feedback_engine/feedbacks_controller.rb +120 -0
  9. data/app/helpers/feedback_engine/widget_helper.rb +18 -0
  10. data/app/models/feedback_engine/application_record.rb +7 -0
  11. data/app/models/feedback_engine/feedback.rb +30 -0
  12. data/app/views/feedback_engine/feedbacks/index.html.erb +75 -0
  13. data/app/views/feedback_engine/feedbacks/show.html.erb +63 -0
  14. data/app/views/layouts/feedback_engine/application.html.erb +75 -0
  15. data/config/locales/feedback_engine.ar.yml +23 -0
  16. data/config/locales/feedback_engine.bg.yml +23 -0
  17. data/config/locales/feedback_engine.bn.yml +23 -0
  18. data/config/locales/feedback_engine.de.yml +23 -0
  19. data/config/locales/feedback_engine.el.yml +23 -0
  20. data/config/locales/feedback_engine.en.yml +43 -0
  21. data/config/locales/feedback_engine.es.yml +23 -0
  22. data/config/locales/feedback_engine.fr.yml +23 -0
  23. data/config/locales/feedback_engine.hi.yml +23 -0
  24. data/config/locales/feedback_engine.hr.yml +23 -0
  25. data/config/locales/feedback_engine.id.yml +23 -0
  26. data/config/locales/feedback_engine.it.yml +23 -0
  27. data/config/locales/feedback_engine.ja.yml +23 -0
  28. data/config/locales/feedback_engine.ko.yml +23 -0
  29. data/config/locales/feedback_engine.lb.yml +23 -0
  30. data/config/locales/feedback_engine.nl.yml +23 -0
  31. data/config/locales/feedback_engine.pl.yml +23 -0
  32. data/config/locales/feedback_engine.pt.yml +23 -0
  33. data/config/locales/feedback_engine.ro.yml +23 -0
  34. data/config/locales/feedback_engine.ru.yml +23 -0
  35. data/config/locales/feedback_engine.th.yml +23 -0
  36. data/config/locales/feedback_engine.tr.yml +23 -0
  37. data/config/locales/feedback_engine.uk.yml +23 -0
  38. data/config/locales/feedback_engine.ur.yml +23 -0
  39. data/config/locales/feedback_engine.vi.yml +23 -0
  40. data/config/locales/feedback_engine.zh-CN.yml +23 -0
  41. data/config/routes.rb +8 -0
  42. data/lib/feedback_engine/configuration.rb +87 -0
  43. data/lib/feedback_engine/engine.rb +13 -0
  44. data/lib/feedback_engine/version.rb +5 -0
  45. data/lib/feedback_engine/widget.rb +107 -0
  46. data/lib/feedback_engine.rb +34 -0
  47. data/lib/generators/feedback_engine/install/install_generator.rb +41 -0
  48. data/lib/generators/feedback_engine/install/templates/create_feedback_engine_feedbacks.rb.tt +21 -0
  49. data/lib/generators/feedback_engine/install/templates/initializer.rb +43 -0
  50. metadata +110 -0
@@ -0,0 +1,23 @@
1
+ th:
2
+ feedback_engine:
3
+ button: "ข้อเสนอแนะ"
4
+ title: "ส่งข้อเสนอแนะ"
5
+ kind: "ประเภท"
6
+ kinds:
7
+ bug: "รายงานข้อบกพร่อง"
8
+ feature: "ขอฟีเจอร์"
9
+ other: "อื่น ๆ"
10
+ section: "ส่วน"
11
+ section_any: "ทั่วไป"
12
+ message: "ข้อความของคุณ"
13
+ message_placeholder: "บอกเราว่าคุณคิดอย่างไร…"
14
+ screenshots: "ภาพหน้าจอ"
15
+ screenshots_hint: "ไม่บังคับ สูงสุด %{count} ไฟล์ ไฟล์ละ %{size} MB"
16
+ submit: "ส่งข้อเสนอแนะ"
17
+ cancel: "ยกเลิก"
18
+ close: "ปิด"
19
+ thanks: "ขอบคุณสำหรับข้อเสนอแนะ!"
20
+ error_blank: "กรุณากรอกข้อความ"
21
+ error_save: "ส่งไม่สำเร็จ กรุณาลองอีกครั้ง"
22
+ error_too_many: "ภาพหน้าจอมากเกินไป (สูงสุด %{count})"
23
+ error_too_large: "ภาพหน้าจอมีขนาดใหญ่เกินไป (สูงสุด %{size} MB)"
@@ -0,0 +1,23 @@
1
+ tr:
2
+ feedback_engine:
3
+ button: "Geri bildirim"
4
+ title: "Geri bildirim gönder"
5
+ kind: "Tür"
6
+ kinds:
7
+ bug: "Hata bildirimi"
8
+ feature: "Özellik isteği"
9
+ other: "Diğer"
10
+ section: "Bölüm"
11
+ section_any: "Genel"
12
+ message: "Mesajınız"
13
+ message_placeholder: "Bize düşüncelerinizi anlatın…"
14
+ screenshots: "Ekran görüntüleri"
15
+ screenshots_hint: "isteğe bağlı, en fazla %{count} dosya, her biri %{size} MB"
16
+ submit: "Geri bildirim gönder"
17
+ cancel: "İptal"
18
+ close: "Kapat"
19
+ thanks: "Geri bildiriminiz için teşekkürler!"
20
+ error_blank: "Lütfen bir mesaj girin."
21
+ error_save: "Gönderilemedi. Lütfen tekrar deneyin."
22
+ error_too_many: "Çok fazla ekran görüntüsü (en fazla %{count})."
23
+ error_too_large: "Bir ekran görüntüsü çok büyük (en fazla %{size} MB)."
@@ -0,0 +1,23 @@
1
+ uk:
2
+ feedback_engine:
3
+ button: "Відгук"
4
+ title: "Надіслати відгук"
5
+ kind: "Тип"
6
+ kinds:
7
+ bug: "Повідомити про помилку"
8
+ feature: "Запропонувати функцію"
9
+ other: "Інше"
10
+ section: "Розділ"
11
+ section_any: "Загальне"
12
+ message: "Ваше повідомлення"
13
+ message_placeholder: "Розкажіть, що у вас на думці…"
14
+ screenshots: "Знімки екрана"
15
+ screenshots_hint: "необов'язково, до %{count} файлів, по %{size} МБ"
16
+ submit: "Надіслати відгук"
17
+ cancel: "Скасувати"
18
+ close: "Закрити"
19
+ thanks: "Дякуємо за ваш відгук!"
20
+ error_blank: "Будь ласка, введіть повідомлення."
21
+ error_save: "Не вдалося надіслати. Спробуйте ще раз."
22
+ error_too_many: "Забагато знімків екрана (макс. %{count})."
23
+ error_too_large: "Знімок екрана завеликий (макс. %{size} МБ)."
@@ -0,0 +1,23 @@
1
+ ur:
2
+ feedback_engine:
3
+ button: "رائے"
4
+ title: "رائے بھیجیں"
5
+ kind: "قسم"
6
+ kinds:
7
+ bug: "خرابی کی اطلاع"
8
+ feature: "فیچر کی درخواست"
9
+ other: "دیگر"
10
+ section: "سیکشن"
11
+ section_any: "عمومی"
12
+ message: "آپ کا پیغام"
13
+ message_placeholder: "ہمیں بتائیں آپ کیا سوچ رہے ہیں…"
14
+ screenshots: "اسکرین شاٹس"
15
+ screenshots_hint: "اختیاری، زیادہ سے زیادہ %{count} فائلیں، ہر ایک %{size} MB"
16
+ submit: "رائے بھیجیں"
17
+ cancel: "منسوخ کریں"
18
+ close: "بند کریں"
19
+ thanks: "آپ کی رائے کا شکریہ!"
20
+ error_blank: "براہ کرم پیغام درج کریں۔"
21
+ error_save: "رائے نہیں بھیجی جا سکی۔ دوبارہ کوشش کریں۔"
22
+ error_too_many: "بہت زیادہ اسکرین شاٹس (زیادہ سے زیادہ %{count})۔"
23
+ error_too_large: "ایک اسکرین شاٹ بہت بڑا ہے (زیادہ سے زیادہ %{size} MB)۔"
@@ -0,0 +1,23 @@
1
+ vi:
2
+ feedback_engine:
3
+ button: "Phản hồi"
4
+ title: "Gửi phản hồi"
5
+ kind: "Loại"
6
+ kinds:
7
+ bug: "Báo lỗi"
8
+ feature: "Yêu cầu tính năng"
9
+ other: "Khác"
10
+ section: "Mục"
11
+ section_any: "Chung"
12
+ message: "Tin nhắn của bạn"
13
+ message_placeholder: "Hãy cho chúng tôi biết suy nghĩ của bạn…"
14
+ screenshots: "Ảnh chụp màn hình"
15
+ screenshots_hint: "tùy chọn, tối đa %{count} tệp, mỗi tệp %{size} MB"
16
+ submit: "Gửi phản hồi"
17
+ cancel: "Hủy"
18
+ close: "Đóng"
19
+ thanks: "Cảm ơn phản hồi của bạn!"
20
+ error_blank: "Vui lòng nhập tin nhắn."
21
+ error_save: "Không thể gửi phản hồi. Vui lòng thử lại."
22
+ error_too_many: "Quá nhiều ảnh chụp màn hình (tối đa %{count})."
23
+ error_too_large: "Một ảnh chụp màn hình quá lớn (tối đa %{size} MB)."
@@ -0,0 +1,23 @@
1
+ zh-CN:
2
+ feedback_engine:
3
+ button: "反馈"
4
+ title: "发送反馈"
5
+ kind: "类型"
6
+ kinds:
7
+ bug: "错误报告"
8
+ feature: "功能请求"
9
+ other: "其他"
10
+ section: "板块"
11
+ section_any: "常规"
12
+ message: "您的留言"
13
+ message_placeholder: "告诉我们您的想法……"
14
+ screenshots: "截图"
15
+ screenshots_hint: "可选,最多 %{count} 个文件,每个 %{size} MB"
16
+ submit: "发送反馈"
17
+ cancel: "取消"
18
+ close: "关闭"
19
+ thanks: "感谢您的反馈!"
20
+ error_blank: "请输入留言。"
21
+ error_save: "发送失败,请重试。"
22
+ error_too_many: "截图过多(最多 %{count} 张)。"
23
+ error_too_large: "有一张截图过大(最多 %{size} MB)。"
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ FeedbackEngine::Engine.routes.draw do
4
+ # create is the public widget endpoint; the rest is the triage dashboard.
5
+ resources :feedbacks, only: %i[create index show update destroy]
6
+
7
+ root to: 'feedbacks#index'
8
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FeedbackEngine
4
+ # Host-tunable settings. Everything has a safe default, so a fresh install
5
+ # works with zero configuration; the hooks below let an app decide who can
6
+ # send feedback, who can read it, and how submissions are attributed.
7
+ class Configuration
8
+ # Per-request gate for the widget and the submission endpoint. Return false
9
+ # to hide the widget and reject submissions for this request. Receives the
10
+ # request. Defaults to everyone — feedback collection is meant for real
11
+ # users in production.
12
+ attr_accessor :enabled
13
+
14
+ # Per-request gate for the built-in dashboard (browse and triage feedback).
15
+ # Receives the request. Defaults to development only — override it before
16
+ # deploying, e.g. with an admin check.
17
+ attr_accessor :authorize_admin
18
+
19
+ # Resolve the current user for attribution (optional). Return an object
20
+ # responding to #id, or nil. Receives the request.
21
+ attr_accessor :current_user
22
+
23
+ # Turn a resolved user into a short label stored alongside the feedback and
24
+ # shown in the dashboard. Receives whatever #current_user returned.
25
+ attr_accessor :author_label
26
+
27
+ # The feedback types a user can pick from. Labels resolve through I18n
28
+ # (`feedback_engine.kinds.<kind>`), so you can rename or add kinds freely.
29
+ attr_accessor :kinds
30
+
31
+ # Optional list of app areas ("Billing", "Dashboard", …) shown as a select
32
+ # in the widget. Leave empty to hide the select entirely.
33
+ attr_accessor :sections
34
+
35
+ # Allow screenshot uploads. Requires Active Storage in the host app; the
36
+ # widget hides the upload control when this is false or Active Storage is
37
+ # not set up.
38
+ attr_accessor :screenshots
39
+
40
+ # Upload limits, enforced server-side and mirrored in the widget.
41
+ attr_accessor :max_screenshots, :max_screenshot_size
42
+
43
+ # Show the floating feedback button. Set false to trigger the widget from
44
+ # your own UI instead: any element with a `data-feedback-engine-open`
45
+ # attribute opens the form.
46
+ attr_accessor :show_button
47
+
48
+ # Text on the floating button. Leave nil to use the localized default
49
+ # (the `feedback_engine.button` I18n key).
50
+ attr_accessor :button_label
51
+
52
+ # Where the engine is mounted. The widget posts to
53
+ # "#{mount_path}/feedbacks", so keep this in sync with the `mount` line in
54
+ # your routes.
55
+ attr_accessor :mount_path
56
+
57
+ # Called with each saved feedback — notify Slack, send an email, open a
58
+ # ticket. Runs inline after save; keep it fast or hand off to a job.
59
+ attr_accessor :on_submit
60
+
61
+ def initialize
62
+ @enabled = ->(_request) { true }
63
+ @authorize_admin = ->(_request) { Rails.env.development? }
64
+ @current_user = ->(_request) {}
65
+ @author_label = ->(user) { user.respond_to?(:email) ? user.email : user&.to_s }
66
+ @kinds = %w[bug feature other]
67
+ @sections = []
68
+ @screenshots = true
69
+ @max_screenshots = 3
70
+ @max_screenshot_size = 5 * 1024 * 1024
71
+ @show_button = true
72
+ @button_label = nil
73
+ @mount_path = '/feedback'
74
+ @on_submit = ->(_feedback) {}
75
+ end
76
+
77
+ def feedbacks_endpoint
78
+ "#{mount_path.chomp('/')}/feedbacks"
79
+ end
80
+
81
+ # Screenshots need Active Storage — both the config switch and the host
82
+ # actually having it loaded.
83
+ def screenshots_enabled?
84
+ screenshots && defined?(::ActiveStorage) ? true : false
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FeedbackEngine
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace FeedbackEngine
6
+
7
+ initializer 'feedback_engine.helper' do
8
+ ActiveSupport.on_load(:action_view) do
9
+ include FeedbackEngine::WidgetHelper
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FeedbackEngine
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module FeedbackEngine
6
+ # Serves the self-contained browser widget. The JavaScript is plain ES (no
7
+ # framework, no build step) and styles itself inline, so it drops into any
8
+ # Rails app regardless of its CSS or JS setup. It is inlined into the page
9
+ # rather than served as a separate asset to avoid any dependency on the
10
+ # host's asset pipeline.
11
+ module Widget
12
+ SOURCE = File.expand_path('../../app/assets/feedback_engine/widget.js', __dir__)
13
+
14
+ # Right-to-left scripts, so the form renders mirrored for those locales.
15
+ # Matched on the language subtag, so region variants ("ar-EG") count too.
16
+ RTL_LANGUAGES = %w[ar arc ckb dv fa ha he ks ku ps sd ug ur yi].freeze
17
+
18
+ class << self
19
+ def javascript
20
+ @javascript ||= File.read(SOURCE)
21
+ end
22
+
23
+ # The two <script> tags the helper renders.
24
+ #
25
+ # The config rides in a `type="application/json"` block: it is *data*,
26
+ # not code, so the browser never executes it and Turbo never tries to
27
+ # re-run it on a soft visit — which means it needs no CSP nonce and the
28
+ # widget can re-read the *current* page's config on every `turbo:load`.
29
+ #
30
+ # `nonce:` stamps only the widget script (the code), so it runs under a
31
+ # nonce-based Content-Security-Policy; pass nil when the app has no nonce.
32
+ def snippet(endpoint:, locale:, nonce: nil)
33
+ config = {
34
+ endpoint: endpoint,
35
+ locale: locale.to_s,
36
+ kinds: kinds,
37
+ sections: FeedbackEngine.config.sections.map(&:to_s),
38
+ screenshots: screenshots,
39
+ showButton: FeedbackEngine.config.show_button ? true : false,
40
+ buttonLabel: FeedbackEngine.config.button_label,
41
+ labels: labels,
42
+ rtl: rtl?(locale)
43
+ }
44
+ # Escape "</" so a value can't close the <script> block early.
45
+ json = config.to_json.gsub('</', '<\/')
46
+ nonce_attr = nonce ? %( nonce="#{nonce}") : ''
47
+
48
+ %(<script type="application/json" data-feedback-engine-config>#{json}</script>) +
49
+ %(<script data-feedback-engine-widget#{nonce_attr}>#{javascript}</script>)
50
+ end
51
+
52
+ private
53
+
54
+ def kinds
55
+ FeedbackEngine.config.kinds.map do |kind|
56
+ { value: kind.to_s, label: t("kinds.#{kind}", kind.to_s.humanize) }
57
+ end
58
+ end
59
+
60
+ def screenshots
61
+ {
62
+ enabled: FeedbackEngine.config.screenshots_enabled?,
63
+ max: FeedbackEngine.config.max_screenshots,
64
+ maxSize: FeedbackEngine.config.max_screenshot_size
65
+ }
66
+ end
67
+
68
+ # Every user-facing string in the widget, resolved through Rails I18n so
69
+ # the form follows the app's current locale. Each lookup carries an
70
+ # English default, so the widget stays fully worded even when the host is
71
+ # missing a key for the active locale.
72
+ def labels
73
+ {
74
+ button: t(:button, 'Feedback'),
75
+ title: t(:title, 'Send feedback'),
76
+ kind: t(:kind, 'Type'),
77
+ section: t(:section, 'Section'),
78
+ sectionAny: t(:section_any, 'General'),
79
+ message: t(:message, 'Your message'),
80
+ messagePlaceholder: t(:message_placeholder, "Tell us what's on your mind…"),
81
+ screenshots: t(:screenshots, 'Screenshots'),
82
+ screenshotsHint: t(:screenshots_hint, 'optional, up to %{count} files, %{size} MB each',
83
+ count: FeedbackEngine.config.max_screenshots,
84
+ size: FeedbackEngine.config.max_screenshot_size / (1024 * 1024)),
85
+ submit: t(:submit, 'Send feedback'),
86
+ cancel: t(:cancel, 'Cancel'),
87
+ close: t(:close, 'Close'),
88
+ thanks: t(:thanks, 'Thanks for your feedback!'),
89
+ errorBlank: t(:error_blank, 'Please enter a message.'),
90
+ errorSave: t(:error_save, 'Could not send feedback. Please try again.'),
91
+ errorTooMany: t(:error_too_many, 'Too many screenshots (max %{count}).',
92
+ count: FeedbackEngine.config.max_screenshots),
93
+ errorTooLarge: t(:error_too_large, 'A screenshot is too large (max %{size} MB).',
94
+ size: FeedbackEngine.config.max_screenshot_size / (1024 * 1024))
95
+ }
96
+ end
97
+
98
+ def t(key, default, **args)
99
+ I18n.t(key, scope: :feedback_engine, default: default, **args)
100
+ end
101
+
102
+ def rtl?(locale)
103
+ RTL_LANGUAGES.include?(locale.to_s.downcase.split(/[-_]/).first)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'feedback_engine/version'
4
+ require 'feedback_engine/configuration'
5
+ require 'feedback_engine/widget'
6
+ require 'feedback_engine/engine'
7
+
8
+ # In-app product feedback collection for Rails. A drop-in widget lets users
9
+ # send bug reports, feature requests, and general feedback (with screenshots)
10
+ # from any page; submissions land in your own database, with a minimal built-in
11
+ # dashboard to browse and triage them.
12
+ module FeedbackEngine
13
+ class << self
14
+ def config
15
+ @config ||= Configuration.new
16
+ end
17
+
18
+ def configure
19
+ yield config
20
+ end
21
+
22
+ # Can this request send feedback? Checked on the server for the endpoint
23
+ # and by the helper before rendering the widget.
24
+ def enabled?(request)
25
+ !!config.enabled.call(request)
26
+ end
27
+
28
+ # Can this request browse and triage feedback? Checked by every dashboard
29
+ # action.
30
+ def admin?(request)
31
+ !!config.authorize_admin.call(request)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+ require 'rails/generators/active_record'
5
+
6
+ module FeedbackEngine
7
+ module Generators
8
+ class InstallGenerator < Rails::Generators::Base
9
+ include ActiveRecord::Generators::Migration
10
+
11
+ source_root File.expand_path('templates', __dir__)
12
+
13
+ desc 'Installs feedback_engine: config initializer, migration, and engine mount.'
14
+
15
+ def create_initializer
16
+ copy_file 'initializer.rb', 'config/initializers/feedback_engine.rb'
17
+ end
18
+
19
+ def create_feedbacks_migration
20
+ migration_template 'create_feedback_engine_feedbacks.rb.tt',
21
+ 'db/migrate/create_feedback_engine_feedbacks.rb'
22
+ end
23
+
24
+ def mount_engine
25
+ route %(mount FeedbackEngine::Engine => "/feedback")
26
+ end
27
+
28
+ def post_install
29
+ say "\nfeedback_engine installed. Run `rails db:migrate`, then add", :green
30
+ say '`<%= feedback_engine_tag %>` before </body> in your layout.'
31
+ say "Browse submissions at /feedback (development only until you set config.authorize_admin).\n"
32
+ end
33
+
34
+ private
35
+
36
+ def migration_version
37
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateFeedbackEngineFeedbacks < ActiveRecord::Migration<%= migration_version %>
4
+ def change
5
+ create_table :feedback_engine_feedbacks do |t|
6
+ t.string :kind, null: false, default: 'other'
7
+ t.string :section
8
+ t.text :message, null: false
9
+ t.string :status, null: false, default: 'open'
10
+ t.string :page_url
11
+ t.string :user_agent
12
+ t.string :author_id
13
+ t.string :author_label
14
+
15
+ t.timestamps
16
+ end
17
+
18
+ add_index :feedback_engine_feedbacks, :status
19
+ add_index :feedback_engine_feedbacks, :kind
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ FeedbackEngine.configure do |config|
4
+ # Who can send feedback. Return false to hide the widget and reject
5
+ # submissions for this request. Defaults to everyone.
6
+ # config.enabled = ->(request) { true }
7
+
8
+ # Who can browse and triage feedback at the mount path. Defaults to
9
+ # development only — override before deploying.
10
+ # config.authorize_admin = ->(request) { request.env["warden"]&.user&.admin? }
11
+
12
+ # Attribute feedback to a user (optional). Return an object responding to
13
+ # #id, or nil. Receives the request.
14
+ # config.current_user = ->(request) { request.env["warden"]&.user }
15
+
16
+ # Label stored for the author and shown in the dashboard.
17
+ # config.author_label = ->(user) { user.try(:email) }
18
+
19
+ # Feedback types users can pick from. Labels come from I18n
20
+ # (feedback_engine.kinds.<kind>).
21
+ # config.kinds = %w[bug feature other]
22
+
23
+ # App areas shown as a select in the widget. Empty list hides the select.
24
+ # config.sections = ["Dashboard", "Billing", "Settings"]
25
+
26
+ # Screenshot uploads (requires Active Storage).
27
+ # config.screenshots = true
28
+ # config.max_screenshots = 3
29
+ # config.max_screenshot_size = 5.megabytes
30
+
31
+ # Show the floating feedback button. Set false and add
32
+ # `data-feedback-engine-open` to any element to trigger the form yourself.
33
+ # config.show_button = true
34
+
35
+ # Fixed button text; leave nil to use the localized default.
36
+ # config.button_label = nil
37
+
38
+ # Keep in sync with the `mount` in config/routes.rb.
39
+ # config.mount_path = "/feedback"
40
+
41
+ # Called with each saved feedback — notify Slack, send an email, etc.
42
+ # config.on_submit = ->(feedback) { FeedbackMailer.with(feedback:).new_feedback.deliver_later }
43
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: feedback_engine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yaroslav Shmarov
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.1'
26
+ description: |
27
+ A mountable Rails engine that adds a "Send feedback" widget to your app —
28
+ bug reports, feature requests, screenshots — and stores submissions in your
29
+ own database. Ships with a minimal built-in dashboard to browse and triage
30
+ what users send. Framework-agnostic: no CSS or JS framework required.
31
+ email:
32
+ - yaroslav.shmarov@clickfunnels.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - CHANGELOG.md
38
+ - MIT-LICENSE
39
+ - README.md
40
+ - Rakefile
41
+ - app/assets/feedback_engine/widget.js
42
+ - app/controllers/feedback_engine/application_controller.rb
43
+ - app/controllers/feedback_engine/feedbacks_controller.rb
44
+ - app/helpers/feedback_engine/widget_helper.rb
45
+ - app/models/feedback_engine/application_record.rb
46
+ - app/models/feedback_engine/feedback.rb
47
+ - app/views/feedback_engine/feedbacks/index.html.erb
48
+ - app/views/feedback_engine/feedbacks/show.html.erb
49
+ - app/views/layouts/feedback_engine/application.html.erb
50
+ - config/locales/feedback_engine.ar.yml
51
+ - config/locales/feedback_engine.bg.yml
52
+ - config/locales/feedback_engine.bn.yml
53
+ - config/locales/feedback_engine.de.yml
54
+ - config/locales/feedback_engine.el.yml
55
+ - config/locales/feedback_engine.en.yml
56
+ - config/locales/feedback_engine.es.yml
57
+ - config/locales/feedback_engine.fr.yml
58
+ - config/locales/feedback_engine.hi.yml
59
+ - config/locales/feedback_engine.hr.yml
60
+ - config/locales/feedback_engine.id.yml
61
+ - config/locales/feedback_engine.it.yml
62
+ - config/locales/feedback_engine.ja.yml
63
+ - config/locales/feedback_engine.ko.yml
64
+ - config/locales/feedback_engine.lb.yml
65
+ - config/locales/feedback_engine.nl.yml
66
+ - config/locales/feedback_engine.pl.yml
67
+ - config/locales/feedback_engine.pt.yml
68
+ - config/locales/feedback_engine.ro.yml
69
+ - config/locales/feedback_engine.ru.yml
70
+ - config/locales/feedback_engine.th.yml
71
+ - config/locales/feedback_engine.tr.yml
72
+ - config/locales/feedback_engine.uk.yml
73
+ - config/locales/feedback_engine.ur.yml
74
+ - config/locales/feedback_engine.vi.yml
75
+ - config/locales/feedback_engine.zh-CN.yml
76
+ - config/routes.rb
77
+ - lib/feedback_engine.rb
78
+ - lib/feedback_engine/configuration.rb
79
+ - lib/feedback_engine/engine.rb
80
+ - lib/feedback_engine/version.rb
81
+ - lib/feedback_engine/widget.rb
82
+ - lib/generators/feedback_engine/install/install_generator.rb
83
+ - lib/generators/feedback_engine/install/templates/create_feedback_engine_feedbacks.rb.tt
84
+ - lib/generators/feedback_engine/install/templates/initializer.rb
85
+ homepage: https://github.com/yshmarov/feedback-engine
86
+ licenses:
87
+ - MIT
88
+ metadata:
89
+ source_code_uri: https://github.com/yshmarov/feedback-engine
90
+ changelog_uri: https://github.com/yshmarov/feedback-engine/blob/main/CHANGELOG.md
91
+ rubygems_mfa_required: 'true'
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '3.2'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubygems_version: 4.0.6
107
+ specification_version: 4
108
+ summary: 'In-app product feedback collection for Rails: a drop-in widget and a built-in
109
+ triage dashboard.'
110
+ test_files: []