lesli_bell 1.0.0 → 1.1.1

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: a314f359bb1e0ef4d971fc23128c7b57e6e02655f6ce248d26539331e10affcc
4
- data.tar.gz: 5a5f4327f3c7a2f34da5068746a0cec6648dca0579355eecb5f5f8bce5dfa0ed
3
+ metadata.gz: 230a04119c05f73f87f6fefcffc2f930301763388864f34fa6feb3bcf510598b
4
+ data.tar.gz: 654752028cdbe7d683f2c30a8060156f73b5e4a78de4d6dec07a5b1916cc3aa8
5
5
  SHA512:
6
- metadata.gz: 01d5550b5e3a873cd3046008189346601c5996528ca010ed2d16231a44e5a2ade357337022721c40df8cf48c9f41de587a889392665fc76e12a0f6d6f2d1e45f
7
- data.tar.gz: 90db0aad0cf9b93eabca7c42a597478a357e49bf94e11fdac550a7e04dee37f20b3be10bdaf52db6be69996b9b74cab49892e3dbd822a84065394ad9b4b80bb2
6
+ metadata.gz: f6d3dd2e9d2a37278dc122df57f2ab02b344f1c56d92167e4c4ae5eecef40badfda09cc39d8d4716ecccb72b144e111a7c0d54e9c95b300759f9784d630843fc
7
+ data.tar.gz: 77dbd210d847f72c9c923f1c010c73ee8453e83f544876a2df1a03edf3af3528530eccb881c0fb23a404fac81da316ea8b0821215818ff7f415af0422c58f8cd
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require "bundler/setup"
2
2
 
3
- load "rails/tasks/statistics.rake"
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
4
5
 
5
6
  require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer utilities{.absolute{position:absolute}.relative{position:relative}.top-3{top:calc(var(--spacing) * 3)}.right-3{right:calc(var(--spacing) * 3)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.block{display:block}.inline-flex{display:inline-flex}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.items-center{align-items:center}.justify-center{justify-content:center}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-danger-300{border-color:var(--lesli-color-danger-300)}.border-info-300{border-color:var(--lesli-color-info-300)}.border-neutral-300{border-color:var(--lesli-color-neutral-300)}.border-success-300{border-color:var(--lesli-color-success-300)}.border-warning-300{border-color:var(--lesli-color-warning-300)}.bg-danger-50{background-color:var(--lesli-color-danger-50)}.bg-info-50{background-color:var(--lesli-color-info-50)}.bg-neutral-50{background-color:var(--lesli-color-neutral-50)}.bg-success-50{background-color:var(--lesli-color-success-50)}.bg-warning-50{background-color:var(--lesli-color-warning-50)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-3{padding-block:calc(var(--spacing) * 3)}.pr-14{padding-right:calc(var(--spacing) * 14)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.break-all{word-break:break-all}.text-danger-700{color:var(--lesli-color-danger-700)}.text-danger-900{color:var(--lesli-color-danger-900)}.text-info-700{color:var(--lesli-color-info-700)}.text-info-900{color:var(--lesli-color-info-900)}.text-neutral-700{color:var(--lesli-color-neutral-700)}.text-neutral-900{color:var(--lesli-color-neutral-900)}.text-success-700{color:var(--lesli-color-success-700)}.text-success-900{color:var(--lesli-color-success-900)}.text-warning-700{color:var(--lesli-color-warning-700)}.text-warning-900{color:var(--lesli-color-warning-900)}.underline{text-decoration-line:underline}.decoration-current\/40{text-decoration-color:currentColor}@supports (color:color-mix(in lab, red, red)){.decoration-current\/40{-webkit-text-decoration-color:color-mix(in oklab, currentcolor 40%, transparent);-webkit-text-decoration-color:color-mix(in oklab, currentcolor 40%, transparent);text-decoration-color:color-mix(in oklab, currentcolor 40%, transparent)}}.underline-offset-2{text-underline-offset:2px}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.hover\:bg-danger-100:hover{background-color:var(--lesli-color-danger-100)}.hover\:bg-info-100:hover{background-color:var(--lesli-color-info-100)}.hover\:bg-neutral-100:hover{background-color:var(--lesli-color-neutral-100)}.hover\:bg-success-100:hover{background-color:var(--lesli-color-success-100)}.hover\:bg-warning-100:hover{background-color:var(--lesli-color-warning-100)}.hover\:decoration-current:hover{text-decoration-color:currentColor}}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-current\/40:focus-visible{--tw-ring-color:currentcolor}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-current\/40:focus-visible{--tw-ring-color:color-mix(in oklab, currentcolor 40%, transparent)}}.focus-visible\:ring-danger-500\/40:focus-visible{--tw-ring-color:var(--lesli-color-danger-500)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-danger-500\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--lesli-color-danger-500) 40%, transparent)}}.focus-visible\:ring-info-500\/40:focus-visible{--tw-ring-color:var(--lesli-color-info-500)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-info-500\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--lesli-color-info-500) 40%, transparent)}}.focus-visible\:ring-neutral-500\/40:focus-visible{--tw-ring-color:var(--lesli-color-neutral-500)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-neutral-500\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--lesli-color-neutral-500) 40%, transparent)}}.focus-visible\:ring-success-500\/40:focus-visible{--tw-ring-color:var(--lesli-color-success-500)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-success-500\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--lesli-color-success-500) 40%, transparent)}}.focus-visible\:ring-warning-500\/40:focus-visible{--tw-ring-color:var(--lesli-color-warning-500)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-warning-500\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--lesli-color-warning-500) 40%, transparent)}}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
@@ -4,7 +4,7 @@ module LesliBell
4
4
 
5
5
  # GET /notifications
6
6
  def index
7
- @notifications = respond_as_pagination(NotificationService.new(current_user, query).index)
7
+ @notifications = respond_with_pagination(NotificationService.new(current_user, query).index)
8
8
  end
9
9
 
10
10
  # GET /notifications/1
@@ -33,7 +33,7 @@ module LesliBell
33
33
  # PATCH/PUT /notifications/1
34
34
  def update
35
35
  NotificationService.new(current_user).read(params[:id])
36
- @notifications = respond_as_pagination(NotificationService.new(current_user, query).index)
36
+ @notifications = respond_with_pagination(NotificationService.new(current_user, query).index)
37
37
  render :index
38
38
  end
39
39
 
@@ -1,6 +1,6 @@
1
1
  module LesliBell
2
2
  class Announcement::User < ApplicationRecord
3
- belongs_to :announcement #, class_name: "CloudBell::Announcement", foreign_key: "cloud_bell_announcements_id", optional: false
4
- #belongs_to :user, class_name: "Lesli::User", foreign_key: "users_id"
3
+ belongs_to :announcement
4
+ belongs_to :user, class_name: "::Lesli::User"
5
5
  end
6
6
  end
@@ -4,7 +4,7 @@ module LesliBell
4
4
  belongs_to :user, class_name: "::Lesli::User"
5
5
  has_many :users #, class_name: "::Lesli::User"
6
6
 
7
- enum category: {
7
+ enum :category, {
8
8
  :info => 'info',
9
9
  :danger => 'danger',
10
10
  :warning => 'warning',
@@ -32,9 +32,6 @@ Building a better future, one line of code at a time.
32
32
 
33
33
  module LesliBell
34
34
  class Dashboard < Lesli::Shared::Dashboard
35
- self.table_name = "lesli_bell_dashboards"
36
- belongs_to :account
37
-
38
35
  COMPONENTS = %i[]
39
36
  end
40
37
  end
@@ -30,24 +30,6 @@ Building a better future, one line of code at a time.
30
30
  // ·
31
31
  %>
32
32
 
33
- <style>
34
- .notification.is-danger.is-light {
35
- border: 2px solid hsl(var(--bulma-notification-h), var(--bulma-notification-s), var(--bulma-notification-color-l))
36
- }
37
-
38
- .notification.is-warning.is-light {
39
- border: 2px solid hsl(var(--bulma-notification-h), var(--bulma-notification-s), var(--bulma-notification-color-l));
40
- }
41
-
42
- .notification.is-success.is-light {
43
- border: 2px solid hsl(var(--bulma-notification-h), var(--bulma-notification-s), var(--bulma-notification-color-l));
44
- }
45
-
46
- .notification.is-info.is-light {
47
- border: 2px solid hsl(var(--bulma-notification-h), var(--bulma-notification-s), var(--bulma-notification-color-l));
48
- }
49
- </style>
50
-
51
33
  <%= render(LesliView::Layout::Container.new("lesli-bell-notifications-index")) do %>
52
34
 
53
35
  <%= render(LesliView::Components::Header.new("Notifications")) do %>
@@ -56,41 +38,75 @@ border: 2px solid hsl(var(--bulma-notification-h), var(--bulma-notification-s),
56
38
 
57
39
  <%= render(LesliView::Components::Toolbar.new) %>
58
40
 
59
- <% if @notifications.size == 0 %>
41
+ <% if @notifications[:records].empty? %>
60
42
  <%= render(LesliView::Elements::Empty.new) %>
61
43
  <% else %>
62
- <section class="notifications">
44
+ <section class="space-y-2" aria-label="Notifications">
63
45
  <% @notifications[:records].each do |notification| %>
64
- <div class="notification is-<%= notification[:category] %> is-light mb-2">
46
+ <%
47
+ notification_classes, close_button_classes = case notification[:category].to_s
48
+ when "danger"
49
+ [
50
+ "border-danger-300 bg-danger-50 text-danger-900",
51
+ "text-danger-700 hover:bg-danger-100 focus-visible:ring-danger-500/40"
52
+ ]
53
+ when "warning"
54
+ [
55
+ "border-warning-300 bg-warning-50 text-warning-900",
56
+ "text-warning-700 hover:bg-warning-100 focus-visible:ring-warning-500/40"
57
+ ]
58
+ when "success"
59
+ [
60
+ "border-success-300 bg-success-50 text-success-900",
61
+ "text-success-700 hover:bg-success-100 focus-visible:ring-success-500/40"
62
+ ]
63
+ when "info"
64
+ [
65
+ "border-info-300 bg-info-50 text-info-900",
66
+ "text-info-700 hover:bg-info-100 focus-visible:ring-info-500/40"
67
+ ]
68
+ else
69
+ [
70
+ "border-neutral-300 bg-neutral-50 text-neutral-900",
71
+ "text-neutral-700 hover:bg-neutral-100 focus-visible:ring-neutral-500/40"
72
+ ]
73
+ end
74
+ %>
75
+
76
+ <article class="relative rounded-lg border-2 px-4 py-3 pr-14 shadow-sm <%= notification_classes %>">
65
77
 
66
78
  <!-- Close button -->
67
79
  <%= button_to(
68
- notification_path(notification[:id]),
69
- method: :put,
70
- class: "button is-small is-#{notification[:category]}",
71
- form: { class: "delete" }) do %>
72
- <span class="icon">
73
- <span class="material-icons">close</span>
74
- </span>
80
+ notification_path(notification[:id]),
81
+ method: :put,
82
+ class: "inline-flex size-8 items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2 #{close_button_classes}",
83
+ form: { class: "absolute right-3 top-3" },
84
+ aria: { label: "Mark notification as read" }) do %>
85
+ <span class="material-symbols text-xl" aria-hidden="true">close</span>
75
86
  <% end %>
76
87
 
77
88
  <!-- Notification subject -->
78
- <strong><%= notification[:subject] %></strong>
89
+ <strong class="block text-sm font-semibold"><%= notification[:subject] %></strong>
79
90
 
80
91
  <!-- Notification body (optional) -->
81
92
  <% if notification[:body].present? %>
82
- <p><%= notification[:body] %></p>
93
+ <p class="mt-1 text-sm leading-6"><%= notification[:body] %></p>
83
94
  <% end %>
84
95
 
85
96
  <!-- Notification URL (optional) -->
86
97
  <% if notification[:url].present? %>
87
- <p>
88
- <a href="<%= notification[:url] %>" target="_blank" rel="noopener noreferrer">
98
+ <p class="mt-2 text-sm">
99
+ <a
100
+ class="break-all font-medium underline decoration-current/40 underline-offset-2 hover:decoration-current focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current/40"
101
+ href="<%= notification[:url] %>"
102
+ target="_blank"
103
+ rel="noopener noreferrer"
104
+ >
89
105
  <%= notification[:url] %>
90
106
  </a>
91
107
  </p>
92
108
  <% end %>
93
- </div>
109
+ </article>
94
110
  <% end %>
95
111
  </section>
96
112
  <% end %>
data/config/routes.rb CHANGED
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
  LesliBell::Engine.routes.draw do
34
- Lesli::Routing.mount_dashboard_for(LesliBell)
34
+ Lesli::Router.mount_lesli_engine_routes(self)
35
35
  resources :notifications, only: [:index, :new, :update]
36
36
  resources :announcements, only: [:index]
37
37
  end
data/db/seeds.rb CHANGED
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
31
31
  =end
32
32
 
33
33
 
34
- L2.msg("LesliBell", "Version: #{LesliBell::VERSION}", "Build: #{LesliBell::BUILD}")
34
+ Termline.info("Loading seeds for: LesliBell #{LesliBell::VERSION} (#{LesliBell::BUILD})")
35
35
 
36
36
  # · load specific environment seeds
37
37
  if Rails.env.development? || Lesli.config.demo
@@ -4,9 +4,6 @@ module LesliBell
4
4
 
5
5
  initializer :lesli_bell do |app|
6
6
 
7
- # register assets manifest
8
- config.assets.precompile += %w[lesli_bell_manifest.js]
9
-
10
7
  # register engine migrations path
11
8
  unless app.root.to_s.match root.to_s
12
9
  config.paths["db/migrate"].expanded.each do |expanded_path|
@@ -1,4 +1,4 @@
1
1
  module LesliBell
2
- VERSION = "1.0.0"
3
- BUILD = "1752635550"
2
+ VERSION = "1.1.1"
3
+ BUILD = "1791607001"
4
4
  end
data/readme.md CHANGED
@@ -1,67 +1,219 @@
1
- <div align="center" class="documentation-header">
2
- <img width="100" alt="LesliBell logo" src="./app/assets/images/lesli_bell/bell-logo.svg" />
3
- <h3 align="center">Notifications & Announcements System for the Lesli Framework.</h3>
1
+ <div align="center">
2
+ <h1 align="center">
3
+ <img width="100" alt="LesliBell" src="./app/assets/images/lesli_bell/bell-logo.svg" />
4
+ </h1>
5
+ <h3 align="center">Notifications and announcements for the Lesli Framework.</h3>
4
6
  </div>
5
7
 
6
-
7
8
  <br />
8
- <hr/>
9
9
 
10
- <div align="center" class="documentation-statics">
11
- <a target="blank" href="https://rubygems.org/gems/lesli">
12
- <img height="22" alt="Gem Version" src="https://badge.fury.io/rb/lesli.svg"/>
10
+ <div align="center">
11
+ <a target="_blank" href="https://github.com/LesliTech/LesliBell/actions/workflows/lesli-ci-tests.yaml">
12
+ <img
13
+ alt="LesliBell test status"
14
+ src="https://img.shields.io/github/actions/workflow/status/LesliTech/LesliBell/lesli-ci-tests.yaml?branch=master&style=for-the-badge&logo=github&label=tests">
15
+ </a>
16
+ <a target="_blank" href="https://rubygems.org/gems/lesli_bell">
17
+ <img alt="Gem Version" src="https://img.shields.io/gem/v/lesli_bell?style=for-the-badge&logo=ruby">
13
18
  </a>
14
- <a class="mx-2" href="https://codecov.io/github/LesliTech/Lesli">
15
- <img height="22" src="https://codecov.io/github/LesliTech/Lesli/graph/badge.svg?token=2O12NENK5Y"/>
19
+ <a target="_blank" href="https://codecov.io/github/LesliTech/LesliBell">
20
+ <img alt="Codecov" src="https://img.shields.io/codecov/c/github/LesliTech/LesliBell?style=for-the-badge&logo=codecov">
16
21
  </a>
17
- <a href="https://codecov.io/github/LesliTech/LesliBabel">
18
- <img height="22" src="https://sonarcloud.io/api/project_badges/measure?project=LesliTech_LesliBabel&metric=sqale_rating"/>
22
+ <a target="_blank" href="https://sonarcloud.io/project/overview?id=LesliTech_LesliBell">
23
+ <img alt="Sonar Quality Gate" src="https://img.shields.io/sonar/quality_gate/LesliTech_LesliBell?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonarqubecloud&label=Quality">
19
24
  </a>
20
25
  </div>
21
26
 
22
- <hr/>
23
27
  <br />
24
28
 
29
+ <div align="center">
30
+ <img
31
+ style="width:100%;max-width:800px;border-radius:6px;"
32
+ alt="LesliBell notifications and announcements"
33
+ src="./docs/images/screenshot.png" />
34
+ </div>
35
+
36
+ ---
37
+
38
+ <br />
39
+
40
+ ## Introduction
41
+
42
+ LesliBell is the official notifications and announcements engine for the [Lesli Framework](https://github.com/LesliTech/Lesli).
43
+
44
+ It provides account-scoped communication tools that integrate with Lesli users, permissions, navigation, and shared application infrastructure.
45
+
46
+ <br />
47
+
48
+ ## Features
49
+
50
+ - User notification feeds with unread counts and read status
51
+ - Notification categories for informational, success, warning, and danger messages
52
+ - Delivery-channel metadata for web, push, email, dialog, and mobile notifications
53
+ - Account-scoped announcements
54
+ - Announcement metadata for paths, date ranges, links, and dismissible presentation
55
+ - Pagination and integration with the standard Lesli interface
56
+
57
+ <br />
58
+
59
+ ## Try LesliBell
60
+
61
+ - [Try the online demo](https://demo.lesli.dev/)
62
+ - [Run the Docker demo](https://github.com/LesliTech/lesli-docker-demo)
63
+
64
+ <br />
65
+
66
+ ## Quick Start
25
67
 
26
- ### Quick start
68
+ ### Requirements
69
+
70
+ - A Rails application with [Lesli](https://rubygems.org/gems/lesli) 5.1 or newer
71
+ - SQLite by default, or PostgreSQL when preferred by the host application
72
+
73
+ ### Install LesliBell
74
+
75
+ Add the engine to the host Rails application and prepare its database:
27
76
 
28
77
  ```shell
29
- # Add LesliBell engine gem
30
78
  bundle add lesli_bell
79
+ bin/rails lesli:db:prepare
31
80
  ```
32
81
 
33
- ```shell
34
- # Setup & initialize the database
35
- rake lesli:db:setup
82
+ ### Mount the engine
83
+
84
+ Applications using Lesli's standard router mount LesliBell automatically at `/bell`:
85
+
86
+ ```ruby
87
+ # config/routes.rb
88
+ Rails.application.routes.draw do
89
+ Lesli::Router.mount(self)
90
+ end
36
91
  ```
37
92
 
93
+ If the application does not use the standard Lesli router, mount the engine directly:
94
+
38
95
  ```ruby
39
- # Load LesliBell engine
96
+ # config/routes.rb
40
97
  Rails.application.routes.draw do
41
98
  mount LesliBell::Engine => "/bell"
42
99
  end
43
100
  ```
44
101
 
102
+ Start Rails and visit [http://127.0.0.1:3000/bell](http://127.0.0.1:3000/bell):
103
+
104
+ ```shell
105
+ bin/rails server
106
+ ```
107
+
108
+ <br />
109
+
110
+ ## Usage
111
+
112
+ ### Create a notification for the current user
113
+
114
+ LesliBell creates notifications through an account-scoped service. Pass a signed-in Lesli user to the service:
115
+
116
+ ```ruby
117
+ LesliBell::NotificationService.new(current_user).create_for_me(
118
+ subject: "Your report is ready",
119
+ body: "Open the report to review the latest results.",
120
+ category: :success,
121
+ channel: :web,
122
+ url: "/reports/weekly"
123
+ )
124
+ ```
125
+
126
+ ### Notify multiple users
127
+
128
+ Use user IDs that belong to the current account:
129
+
130
+ ```ruby
131
+ user_ids = current_user.account.users.pluck(:id)
132
+
133
+ LesliBell::NotificationService.new(current_user).create(
134
+ {
135
+ subject: "Scheduled maintenance",
136
+ category: :warning,
137
+ channel: :web
138
+ },
139
+ send_to_user_ids: user_ids
140
+ )
141
+ ```
142
+
143
+ Unknown categories fall back to `info`; unknown channels fall back to `web`. The notification feed displays `created`, `sent`, and legacy records without a status. Updating `/bell/notifications/:id` marks that notification as read for the current user.
144
+
145
+ See [Notifications](https://www.lesli.dev/engines/bell/notifications/overview/) and [Announcements](https://www.lesli.dev/engines/bell/announcements/overview/) for the data contracts, service behavior, and current route surface.
146
+
147
+ <br />
45
148
 
46
- ### Documentation
149
+ ## Development
47
150
 
151
+ Clone LesliBell into the host application's `engines` directory:
48
152
 
153
+ ```shell
154
+ cd RailsApp
155
+ mkdir -p engines
156
+ git clone https://github.com/LesliTech/LesliBell.git engines/LesliBell
157
+ ```
49
158
 
50
- ### Lesli Documentation
51
- * [website](https://www.lesli.dev/)
52
- * [documentation](https://www.lesli.dev/engines/bell/)
159
+ Reference the local engine from the host application's `Gemfile`:
160
+
161
+ ```ruby
162
+ gem "lesli_bell", path: "engines/LesliBell"
163
+ ```
53
164
 
165
+ Install dependencies, prepare the host database, and start Rails:
54
166
 
55
- ### Get in touch with Lesli
167
+ ```shell
168
+ bundle install
169
+ bin/rails lesli:db:prepare
170
+ bin/rails server
171
+ ```
56
172
 
57
- * [Email: hello@lesli.tech](hello@lesli.tech)
58
- * [Website: https://www.lesli.tech](https://www.lesli.tech)
59
- * [Twitter: @LesliTech](https://twitter.com/LesliTech)
173
+ ### Tests
60
174
 
175
+ From a complete Lesli development workspace, run the engine test suite from the LesliBell directory:
61
176
 
62
- ### License
63
- -------
64
- Copyright (c) 2025, Lesli Technologies, S. A.
177
+ ```shell
178
+ cd engines/LesliBell
179
+ bin/rails test
180
+ ```
181
+
182
+ Run the same suite with the engine coverage profile enabled:
183
+
184
+ ```shell
185
+ COVERAGE=true bin/rails test
186
+ ```
187
+
188
+ <br />
189
+
190
+ ## Documentation
191
+
192
+ - [Lesli website](https://www.lesli.dev/)
193
+ - [LesliBell documentation](https://www.lesli.dev/engines/bell/)
194
+ - [Installation](https://www.lesli.dev/engines/bell/about/installation/)
195
+ - [Notifications](https://www.lesli.dev/engines/bell/notifications/overview/)
196
+ - [Announcements](https://www.lesli.dev/engines/bell/announcements/overview/)
197
+ - [Database](https://www.lesli.dev/engines/bell/about/database/)
198
+ - [Translations](https://www.lesli.dev/engines/bell/about/translations/)
199
+ - [Frontend](https://www.lesli.dev/engines/bell/about/frontend/)
200
+ - [Release notes](https://github.com/LesliTech/LesliBell/releases)
201
+ - [Issue tracker](https://github.com/LesliTech/LesliBell/issues)
202
+ - [Source code](https://github.com/LesliTech/LesliBell)
203
+
204
+ <br />
205
+
206
+ ## Community
207
+
208
+ - [X: @LesliTech](https://x.com/LesliTech)
209
+ - [hello@lesli.tech](mailto:hello@lesli.tech)
210
+ - [https://www.lesli.tech](https://www.lesli.tech)
211
+
212
+ <br />
213
+
214
+ ## License
215
+
216
+ Copyright (c) 2026, Lesli Technologies, S. A.
65
217
 
66
218
  This program is free software: you can redistribute it and/or modify
67
219
  it under the terms of the GNU General Public License as published by
@@ -74,12 +226,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74
226
  GNU General Public License for more details.
75
227
 
76
228
  You should have received a copy of the GNU General Public License
77
- along with this program. If not, see http://www.gnu.org/licenses/.
229
+ along with this program. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/).
230
+
231
+ The complete license text is available in the [license file](./license).
78
232
 
79
- <hr />
233
+ ---
234
+
235
+ <br />
80
236
  <br />
81
237
 
82
- <div align="center" class="has-text-centered">
83
- <img width="200" alt="Lesli logo" src="https://cdn.lesli.tech/lesli/brand/app-logo.svg" />
84
- <h4 align="center" class="mt-0">Ruby on Rails SaaS Development Framework.</h4>
238
+ <div align="center">
239
+ <img width="80" alt="Lesli icon" src="https://cdn.lesli.tech/lesli/brand/app-icon.svg" />
240
+ <h3 align="center">The Open-Source SaaS Development Framework for Ruby on Rails.</h3>
85
241
  </div>
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lesli_bell
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Lesli Development Team
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-07-16 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: lesli
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '5'
18
+ version: 5.1.0
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '5'
25
+ version: 5.1.0
27
26
  description: Notifications & Announcements System for the Lesli Framework.
28
27
  email:
29
28
  - hello@lesli.tech
@@ -37,6 +36,7 @@ files:
37
36
  - app/assets/javascripts/lesli_bell/application.js
38
37
  - app/assets/javascripts/lesli_bell/application.js.LICENSE.txt
39
38
  - app/assets/stylesheets/lesli_bell/application.css
39
+ - app/assets/stylesheets/lesli_bell/application.tailwind.css
40
40
  - app/controllers/lesli_bell/accounts_controller.rb
41
41
  - app/controllers/lesli_bell/announcements_controller.rb
42
42
  - app/controllers/lesli_bell/application_controller.rb
@@ -81,7 +81,6 @@ files:
81
81
  - config/locales/translations.pt.yml
82
82
  - config/routes.rb
83
83
  - db/migrate/v1.0/0308000110_create_lesli_bell_accounts.rb
84
- - db/migrate/v1.0/0308003010_create_lesli_bell_dashboards.rb
85
84
  - db/migrate/v1.0/0308100110_create_lesli_bell_notifications.rb
86
85
  - db/migrate/v1.0/0308110110_create_lesli_bell_announcements.rb
87
86
  - db/migrate/v1.0/0308110210_create_lesli_bell_announcement_activities.rb
@@ -93,18 +92,7 @@ files:
93
92
  - lib/lesli_bell.rb
94
93
  - lib/lesli_bell/engine.rb
95
94
  - lib/lesli_bell/version.rb
96
- - lib/scss/application.scss
97
95
  - lib/tasks/lesli_bell_tasks.rake
98
- - lib/vue/application.js
99
- - lib/vue/apps/announcements/components/form.vue
100
- - lib/vue/apps/announcements/index.vue
101
- - lib/vue/apps/announcements/new.vue
102
- - lib/vue/apps/notifications/components/notification-form.vue
103
- - lib/vue/apps/notifications/index.vue
104
- - lib/vue/apps/notifications/new.vue
105
- - lib/vue/stores/announcement.js
106
- - lib/vue/stores/notification.js
107
- - lib/vue/stores/translations.json
108
96
  - license
109
97
  - readme.md
110
98
  homepage: https://www.lesli.dev/
@@ -114,7 +102,6 @@ metadata:
114
102
  homepage_uri: https://www.lesli.dev/
115
103
  changelog_uri: https://github.com/LesliTech/LesliBell
116
104
  source_code_uri: https://github.com/LesliTech/LesliBell
117
- post_install_message:
118
105
  rdoc_options: []
119
106
  require_paths:
120
107
  - lib
@@ -122,15 +109,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
109
  requirements:
123
110
  - - ">="
124
111
  - !ruby/object:Gem::Version
125
- version: '2.7'
112
+ version: '0'
126
113
  required_rubygems_version: !ruby/object:Gem::Requirement
127
114
  requirements:
128
115
  - - ">="
129
116
  - !ruby/object:Gem::Version
130
117
  version: '0'
131
118
  requirements: []
132
- rubygems_version: 3.4.19
133
- signing_key:
119
+ rubygems_version: 3.7.1
134
120
  specification_version: 4
135
121
  summary: Notifications & Announcements System for the Lesli Framework.
136
122
  test_files: []
@@ -1,37 +0,0 @@
1
- =begin
2
-
3
- Lesli
4
-
5
- Copyright (c) 2025, Lesli Technologies, S. A.
6
-
7
- This program is free software: you can redistribute it and/or modify
8
- it under the terms of the GNU General Public License as published by
9
- the Free Software Foundation, either version 3 of the License, or
10
- (at your option) any later version.
11
-
12
- This program is distributed in the hope that it will be useful,
13
- but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- GNU General Public License for more details.
16
-
17
- You should have received a copy of the GNU General Public License
18
- along with this program. If not, see http://www.gnu.org/licenses/.
19
-
20
- Lesli · Ruby on Rails SaaS Development Framework.
21
-
22
- Made with ♥ by LesliTech
23
- Building a better future, one line of code at a time.
24
-
25
- @contact hello@lesli.tech
26
- @website https://www.lesli.tech
27
- @license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
28
-
29
- // · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
30
- // ·
31
- =end
32
-
33
- class CreateLesliBellDashboards < ActiveRecord::Migration[6.1]
34
- def change
35
- create_table_lesli_shared_dashboards_10(:lesli_bell)
36
- end
37
- end
File without changes