lesli_bell 1.0.1 → 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: 5a4dee8fc902a97c53747e95dae3ae04957ae41537bfd2e51212b641811a5dcc
4
- data.tar.gz: c1c5174fc3597fe9af63c560d16f3eb73abdf33b577a6e7453838ef5dfb0e1d8
3
+ metadata.gz: 230a04119c05f73f87f6fefcffc2f930301763388864f34fa6feb3bcf510598b
4
+ data.tar.gz: 654752028cdbe7d683f2c30a8060156f73b5e4a78de4d6dec07a5b1916cc3aa8
5
5
  SHA512:
6
- metadata.gz: b10b26e3092d91f6df492cb0157f0712c401cefb9867a53bd6f1301a5a2a20aae205782c84bc6823c41aa649d7d6bcc6ea2cea85475edc05b08e9071faeea037
7
- data.tar.gz: 53dbe5510e84c1d43e8b21088d5bec90d0cc74a57916a86d84dc40e60e8f315fdcd4dd074e5544eb2fcf13255eee0fe11eb469cbbdd35912d8f5efe794e2cd49
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}
@@ -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
@@ -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-symbols">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/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.1"
3
- BUILD = "1771710537"
2
+ VERSION = "1.1.1"
3
+ BUILD = "1791607001"
4
4
  end
data/readme.md CHANGED
@@ -1,14 +1,17 @@
1
1
  <div align="center">
2
- <img width="100" alt="LesliBell logo" src="./app/assets/images/lesli_bell/bell-logo.svg" />
3
- <h3 align="center">Notifications & Announcements for the Lesli Framework.</h3>
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
8
  <br />
7
- <hr/>
8
9
 
9
10
  <div align="center">
10
- <a target="_blank" href="https://github.com/LesliTech/LesliBell/actions">
11
- <img alt="Tests passing" src="https://img.shields.io/badge/Tests-passing-green?style=for-the-badge&logo=github">
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">
12
15
  </a>
13
16
  <a target="_blank" href="https://rubygems.org/gems/lesli_bell">
14
17
  <img alt="Gem Version" src="https://img.shields.io/gem/v/lesli_bell?style=for-the-badge&logo=ruby">
@@ -16,83 +19,200 @@
16
19
  <a target="_blank" href="https://codecov.io/github/LesliTech/LesliBell">
17
20
  <img alt="Codecov" src="https://img.shields.io/codecov/c/github/LesliTech/LesliBell?style=for-the-badge&logo=codecov">
18
21
  </a>
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">
24
+ </a>
19
25
  </div>
20
26
 
21
- <hr/>
22
27
  <br />
23
28
 
24
29
  <div align="center">
25
30
  <img
26
31
  style="width:100%;max-width:800px;border-radius:6px;"
27
- alt="Lesli screenshot" src="./docs/images/screenshot.png" />
32
+ alt="LesliBell notifications and announcements"
33
+ src="./docs/images/screenshot.png" />
28
34
  </div>
29
35
 
36
+ ---
37
+
30
38
  <br />
31
- <hr/>
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
+
32
46
  <br />
33
47
 
34
- ### Installation
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
67
+
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:
35
76
 
36
77
  ```shell
37
- # Add LesliBell engine gem
38
78
  bundle add lesli_bell
79
+ bin/rails lesli:db:prepare
80
+ ```
81
+
82
+ ### Mount the engine
39
83
 
40
- # Setup & initialize the database
41
- rake lesli:db:setup
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
42
91
  ```
43
92
 
93
+ If the application does not use the standard Lesli router, mount the engine directly:
94
+
44
95
  ```ruby
45
- # Load LesliBell engine
96
+ # config/routes.rb
46
97
  Rails.application.routes.draw do
47
98
  mount LesliBell::Engine => "/bell"
48
99
  end
49
100
  ```
50
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
+
51
108
  <br />
52
- <hr/>
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
+
53
147
  <br />
54
148
 
55
- ### Development
149
+ ## Development
150
+
151
+ Clone LesliBell into the host application's `engines` directory:
56
152
 
57
153
  ```shell
58
- # clone the lesli repo inside your engine folder: RailsApp/engines
59
- git clone https://github.com/LesliTech/LesliBell.git
154
+ cd RailsApp
155
+ mkdir -p engines
156
+ git clone https://github.com/LesliTech/LesliBell.git engines/LesliBell
157
+ ```
158
+
159
+ Reference the local engine from the host application's `Gemfile`:
160
+
161
+ ```ruby
162
+ gem "lesli_bell", path: "engines/LesliBell"
163
+ ```
60
164
 
61
- # Load LesliBell as a Gem
62
- gem "lesli", path: "engines/LesliBell"
165
+ Install dependencies, prepare the host database, and start Rails:
63
166
 
64
- # Install the necessary Gems to run LesliBell
167
+ ```shell
65
168
  bundle install
169
+ bin/rails lesli:db:prepare
170
+ bin/rails server
171
+ ```
66
172
 
67
- # Setup & initialize the database
68
- rake lesli:db:setup
173
+ ### Tests
69
174
 
175
+ From a complete Lesli development workspace, run the engine test suite from the LesliBell directory:
176
+
177
+ ```shell
178
+ cd engines/LesliBell
179
+ bin/rails test
70
180
  ```
71
181
 
72
- <br />
73
- <hr/>
74
- <br />
182
+ Run the same suite with the engine coverage profile enabled:
75
183
 
76
- ### Demo
184
+ ```shell
185
+ COVERAGE=true bin/rails test
186
+ ```
77
187
 
78
- * [online demo](https://demo.lesli.dev/)
79
- * [docker demo](https://github.com/LesliTech/lesli-docker-demo)
188
+ <br />
80
189
 
190
+ ## Documentation
81
191
 
82
- ### Documentation
83
- * [website](https://www.lesli.dev/)
84
- * [documentation](https://www.lesli.dev/engines/bell)
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)
85
203
 
204
+ <br />
86
205
 
87
- ### Connect with Lesli
206
+ ## Community
88
207
 
89
- * [X: @LesliTech](https://x.com/LesliTech)
90
- * [Email: hello@lesli.tech](hello@lesli.tech)
91
- * [Website: https://www.lesli.tech](https://www.lesli.tech)
208
+ - [X: @LesliTech](https://x.com/LesliTech)
209
+ - [hello@lesli.tech](mailto:hello@lesli.tech)
210
+ - [https://www.lesli.tech](https://www.lesli.tech)
92
211
 
212
+ <br />
213
+
214
+ ## License
93
215
 
94
- ### License
95
- -------
96
216
  Copyright (c) 2026, Lesli Technologies, S. A.
97
217
 
98
218
  This program is free software: you can redistribute it and/or modify
@@ -106,19 +226,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
106
226
  GNU General Public License for more details.
107
227
 
108
228
  You should have received a copy of the GNU General Public License
109
- 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/).
110
230
 
111
- <br />
112
- <hr />
113
- <br />
114
- <br />
231
+ The complete license text is available in the [license file](./license).
115
232
 
116
- <div align="center" class="has-text-centered">
117
- <img width="200" alt="Lesli logo" src="https://cdn.lesli.tech/lesli/brand/app-logo.svg" />
118
- <h3 align="center" class="mt-0">
119
- The Open-Source SaaS Development Framework for Ruby on Rails.
120
- </h3>
121
- </div>
233
+ ---
122
234
 
123
235
  <br />
124
236
  <br />
237
+
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>
241
+ </div>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lesli_bell
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Lesli Development Team
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '5.0'
18
+ version: 5.1.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '5.0'
25
+ version: 5.1.0
26
26
  description: Notifications & Announcements System for the Lesli Framework.
27
27
  email:
28
28
  - hello@lesli.tech
@@ -36,6 +36,7 @@ files:
36
36
  - app/assets/javascripts/lesli_bell/application.js
37
37
  - app/assets/javascripts/lesli_bell/application.js.LICENSE.txt
38
38
  - app/assets/stylesheets/lesli_bell/application.css
39
+ - app/assets/stylesheets/lesli_bell/application.tailwind.css
39
40
  - app/controllers/lesli_bell/accounts_controller.rb
40
41
  - app/controllers/lesli_bell/announcements_controller.rb
41
42
  - app/controllers/lesli_bell/application_controller.rb
@@ -91,18 +92,7 @@ files:
91
92
  - lib/lesli_bell.rb
92
93
  - lib/lesli_bell/engine.rb
93
94
  - lib/lesli_bell/version.rb
94
- - lib/scss/application.scss
95
95
  - lib/tasks/lesli_bell_tasks.rake
96
- - lib/vue/application.js
97
- - lib/vue/apps/announcements/components/form.vue
98
- - lib/vue/apps/announcements/index.vue
99
- - lib/vue/apps/announcements/new.vue
100
- - lib/vue/apps/notifications/components/notification-form.vue
101
- - lib/vue/apps/notifications/index.vue
102
- - lib/vue/apps/notifications/new.vue
103
- - lib/vue/stores/announcement.js
104
- - lib/vue/stores/notification.js
105
- - lib/vue/stores/translations.json
106
96
  - license
107
97
  - readme.md
108
98
  homepage: https://www.lesli.dev/
File without changes
@@ -1,73 +0,0 @@
1
- /*
2
-
3
- Lesli
4
-
5
- Copyright (c) 2023, 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
- */
32
-
33
-
34
- // · Import Lesli builders
35
- import application from "Lesli/vue/application"
36
- import translation from "Lesli/vue/translation"
37
-
38
-
39
- // · Import engine translations
40
- import translations from "LesliBell/vue/stores/translations.json"
41
-
42
-
43
- // · Import apps and components
44
- // import appDashboard from "Lesli/cloud-objects/dashboards/apps/show.vue"
45
-
46
- import appNotificationsIndex from "LesliBell/vue/apps/notifications/index.vue"
47
- import appNotificationsNew from "LesliBell/vue/apps/notifications/new.vue"
48
-
49
- import appAnnouncementsIndex from "LesliBell/vue/apps/announcements/index.vue"
50
- // import appAnnouncementsNew from "./apps/announcements/new.vue"
51
-
52
-
53
- // · Buil Lesli translations
54
- translation(translations)
55
-
56
-
57
- // · Build a new Lesli application
58
- application("LesliBell", [{
59
- path: "/notifications",
60
- component: appNotificationsIndex
61
- }, {
62
- path: "/notifications/new",
63
- component: appNotificationsNew
64
- }, {
65
- path: "/announcements",
66
- component: appAnnouncementsIndex
67
- }/*{
68
- path: "/",
69
- component: appDashboard
70
- }, {
71
- path: "/announcements/new",
72
- component: appAnnouncementsNew
73
- }*/])