rails_ui_guard 0.1.0 → 0.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: 1e4b34d4a068c77ba4fb3bbdc856a8991c7adba96234a9a657eb62a34baa1bf9
4
- data.tar.gz: cb7942f57e62aa72c62bda6051bc361c08ae50350a53455a980e15d8434fca2a
3
+ metadata.gz: b1d3f593e10f2bf16746f51585833c1498b43a021b60a02266b4882bf03e3663
4
+ data.tar.gz: 734f44236fe4bacf6ee8c0596ca5d6ca0274efe7c2688cf117fa6a31dc7ab3e6
5
5
  SHA512:
6
- metadata.gz: 9bc6825f8d65d7055a21cc4ad5f0070188c3ee563a2afb78efff416febfd7fda94cf248a77bb81d5081c7637f9302b1ffc3f158ee712817503d67fd619f18f0b
7
- data.tar.gz: 4bac57db93eb3c5d763c32ef856d164f918b1376e493a7dea74e4f52da20395300e989d3679831dcbf7615f476fcd801a54f492610cb1a42c62f770630d44fec
6
+ metadata.gz: 77118dc073830e7682eef8958f544c889ccc09cfb9e572059bbd89c39197ea68c03c04b7b6f714a0a2a3db4f1b057aaa2df07b71d83c81ada232f1f16feec8b5
7
+ data.tar.gz: a759443c0ba30faab1fb4b9604541c490f76bbebf65802f78088d4f7e4a34b21d0ed1bec28d707e59d0bae67c2e352482bc2356d553da54c94449c3778129bca
data/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.1] - 2024-12-28
9
+
10
+ ### Enhanced
11
+ - Improved overlay UI with better visual design
12
+ - Enhanced color-coded headers (red for locked, yellow for under work)
13
+ - Better icon display with rounded backgrounds
14
+ - Improved message formatting and readability
15
+ - Added action buttons (Go to Dashboard, Manage Access for admins)
16
+ - Enhanced CSS with animations (fade-in, slide-up)
17
+ - Better backdrop blur effects
18
+ - More user-friendly default messages
19
+ - Improved mobile responsiveness
20
+
21
+ ### Fixed
22
+ - Better handling of feature status records
23
+ - Improved variable scope in overlay partial
24
+
25
+ ## [0.1.0] - 2024-12-28
26
+
27
+ ### Added
28
+ - Initial release of Rails UI Guard
29
+ - Feature status management (Active, Locked, Under Work)
30
+ - UI blur/overlay system (no JavaScript required)
31
+ - Backend enforcement helpers
32
+ - Sidebar status badges with icons
33
+ - View helpers for rendering overlays
34
+ - Controller helpers for enforcing access
35
+ - Model concern for feature status management
36
+ - Rails Engine integration
37
+ - Migration generator
38
+ - Active Admin integration support
39
+ - Comprehensive documentation
40
+
41
+ ### Features
42
+ - Per-tenant feature locking
43
+ - Maintenance mode support
44
+ - Mobile-safe and accessible UI
45
+ - Rails 6/7/8 compatible
46
+ - Polymorphic statusable support
47
+
48
+ [0.1.1]: https://github.com/KapilDevPal/Rails-Ui-Guard/releases/tag/v0.1.1
49
+ [0.1.0]: https://github.com/KapilDevPal/Rails-Ui-Guard/releases/tag/v0.1.0
50
+
@@ -0,0 +1,156 @@
1
+ # ✅ Rails UI Guard Gem - Setup Complete!
2
+
3
+ Your gem is ready to be pushed to GitHub and published to RubyGems.
4
+
5
+ ## 📁 Gem Structure
6
+
7
+ ```
8
+ rails_ui_guard_gem/
9
+ ├── lib/
10
+ │ ├── rails_ui_guard.rb # Main entry point
11
+ │ └── rails_ui_guard/
12
+ │ ├── version.rb # Version number
13
+ │ ├── engine.rb # Rails Engine
14
+ │ ├── controller_helpers.rb # Controller helpers
15
+ │ ├── view_helpers.rb # View helpers
16
+ │ ├── concerns/
17
+ │ │ └── feature_statusable.rb # Model concern
18
+ │ ├── app/
19
+ │ │ ├── models/
20
+ │ │ │ └── rails_ui_guard/
21
+ │ │ │ └── feature_status.rb # FeatureStatus model
22
+ │ │ └── views/
23
+ │ │ └── rails_ui_guard/
24
+ │ │ └── shared/
25
+ │ │ └── _module_overlay.html.erb
26
+ │ └── generators/
27
+ │ └── rails_ui_guard/
28
+ │ └── install/ # Install generator
29
+ ├── rails_ui_guard.gemspec # Gem specification
30
+ ├── README.md # Documentation
31
+ ├── CHANGELOG.md # Version history
32
+ ├── LICENSE.txt # MIT License
33
+ ├── Gemfile # Development dependencies
34
+ ├── Rakefile # Rake tasks
35
+ ├── .gitignore # Git ignore rules
36
+ └── setup_gem.sh # Setup script
37
+ ```
38
+
39
+ ## 🚀 Quick Start - Push to GitHub
40
+
41
+ ### Option 1: Use the setup script
42
+
43
+ ```bash
44
+ cd rails_ui_guard_gem
45
+ ./setup_gem.sh
46
+ ```
47
+
48
+ Then follow the printed instructions.
49
+
50
+ ### Option 2: Manual steps
51
+
52
+ ```bash
53
+ cd rails_ui_guard_gem
54
+
55
+ # Initialize git (if not done)
56
+ git init
57
+ git branch -M main
58
+
59
+ # Add all files
60
+ git add .
61
+
62
+ # Commit
63
+ git commit -m "Initial commit: Rails UI Guard v0.1.0"
64
+
65
+ # Add remote
66
+ git remote add origin https://github.com/KapilDevPal/Rails-Ui-Guard.git
67
+
68
+ # Push
69
+ git push -u origin main
70
+ ```
71
+
72
+ ## 📦 Build and Test Gem
73
+
74
+ ```bash
75
+ # Build the gem
76
+ gem build rails_ui_guard.gemspec
77
+
78
+ # Install locally to test
79
+ gem install rails_ui_guard-0.1.0.gem --local
80
+
81
+ # Test in a Rails app
82
+ cd /path/to/test/app
83
+ # Add to Gemfile: gem 'rails_ui_guard', path: '/path/to/rails_ui_guard_gem'
84
+ bundle install
85
+ rails generate rails_ui_guard:install
86
+ rails db:migrate
87
+ ```
88
+
89
+ ## 📤 Publish to RubyGems
90
+
91
+ 1. **Sign up** at https://rubygems.org
92
+ 2. **Get your API key** from https://rubygems.org/profile/edit
93
+ 3. **Push the gem**:
94
+
95
+ ```bash
96
+ gem push rails_ui_guard-0.1.0.gem
97
+ ```
98
+
99
+ ## 📝 Using the Gem
100
+
101
+ ### From GitHub
102
+
103
+ ```ruby
104
+ # Gemfile
105
+ gem 'rails_ui_guard', git: 'https://github.com/KapilDevPal/Rails-Ui-Guard.git'
106
+ ```
107
+
108
+ ### From RubyGems (after publishing)
109
+
110
+ ```ruby
111
+ # Gemfile
112
+ gem 'rails_ui_guard'
113
+ ```
114
+
115
+ ### Installation
116
+
117
+ ```bash
118
+ bundle install
119
+ rails generate rails_ui_guard:install
120
+ rails db:migrate
121
+ ```
122
+
123
+ ## ✨ Features Included
124
+
125
+ - ✅ Complete gem structure
126
+ - ✅ Rails Engine integration
127
+ - ✅ Migration generator
128
+ - ✅ Model concern for feature status
129
+ - ✅ Controller helpers
130
+ - ✅ View helpers
131
+ - ✅ UI overlay partial
132
+ - ✅ Status badges
133
+ - ✅ Comprehensive README
134
+ - ✅ MIT License
135
+ - ✅ CHANGELOG
136
+ - ✅ GitHub Actions CI (optional)
137
+
138
+ ## 📚 Documentation
139
+
140
+ - **README.md** - Complete usage guide
141
+ - **PUSH_TO_GITHUB.md** - Step-by-step GitHub push instructions
142
+ - **CHANGELOG.md** - Version history
143
+
144
+ ## 🎉 Next Steps
145
+
146
+ 1. ✅ Review the gem structure
147
+ 2. ✅ Test building the gem
148
+ 3. ✅ Push to GitHub
149
+ 4. ✅ Test in a sample Rails app
150
+ 5. ✅ Publish to RubyGems (optional)
151
+ 6. ✅ Share with the community!
152
+
153
+ ---
154
+
155
+ **Happy coding! 🚀**
156
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Kapil Dev Pal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/PUSH_TO_GITHUB.md ADDED
@@ -0,0 +1,90 @@
1
+ # How to Push Rails UI Guard to GitHub
2
+
3
+ ## Step 1: Navigate to the gem directory
4
+
5
+ ```bash
6
+ cd rails_ui_guard_gem
7
+ ```
8
+
9
+ ## Step 2: Initialize Git (if not already done)
10
+
11
+ ```bash
12
+ git init
13
+ git branch -M main
14
+ ```
15
+
16
+ ## Step 3: Add all files
17
+
18
+ ```bash
19
+ git add .
20
+ ```
21
+
22
+ ## Step 4: Make initial commit
23
+
24
+ ```bash
25
+ git commit -m "Initial commit: Rails UI Guard v0.1.0 - Feature locking and status management system for Rails"
26
+ ```
27
+
28
+ ## Step 5: Add GitHub remote
29
+
30
+ ```bash
31
+ git remote add origin https://github.com/KapilDevPal/Rails-Ui-Guard.git
32
+ ```
33
+
34
+ ## Step 6: Push to GitHub
35
+
36
+ ```bash
37
+ git push -u origin main
38
+ ```
39
+
40
+ ## Step 7: Build and test the gem locally
41
+
42
+ ```bash
43
+ gem build rails_ui_guard.gemspec
44
+ gem install rails_ui_guard-0.1.0.gem --local
45
+ ```
46
+
47
+ ## Step 8: Publish to RubyGems (optional)
48
+
49
+ First, sign up at https://rubygems.org and get your API key.
50
+
51
+ ```bash
52
+ gem push rails_ui_guard-0.1.0.gem
53
+ ```
54
+
55
+ ## Quick Setup Script
56
+
57
+ You can also use the provided setup script:
58
+
59
+ ```bash
60
+ ./setup_gem.sh
61
+ ```
62
+
63
+ Then follow the instructions it prints.
64
+
65
+ ## Using the Gem
66
+
67
+ ### From GitHub
68
+
69
+ Add to your Gemfile:
70
+
71
+ ```ruby
72
+ gem 'rails_ui_guard', git: 'https://github.com/KapilDevPal/Rails-Ui-Guard.git'
73
+ ```
74
+
75
+ ### From RubyGems (after publishing)
76
+
77
+ Add to your Gemfile:
78
+
79
+ ```ruby
80
+ gem 'rails_ui_guard'
81
+ ```
82
+
83
+ Then:
84
+
85
+ ```bash
86
+ bundle install
87
+ rails generate rails_ui_guard:install
88
+ rails db:migrate
89
+ ```
90
+
data/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # Rails UI Guard
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/rails_ui_guard.svg)](https://badge.fury.io/rb/rails_ui_guard)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Feature locking and status management system for Rails multi-tenant applications.
7
+
8
+ Rails UI Guard provides a clean way to lock/unlock features, show maintenance overlays, and enforce backend security for modules in multi-tenant Rails applications.
9
+
10
+ ## Features
11
+
12
+ - ✅ **Per-tenant feature status management** (Active, Locked, Under Work)
13
+ - ✅ **UI blur/overlay system** (no JavaScript required)
14
+ - ✅ **Backend enforcement** for security
15
+ - ✅ **Sidebar status badges** with icons
16
+ - ✅ **Reusable view helpers and partials**
17
+ - ✅ **Rails 6/7/8 compatible**
18
+ - ✅ **Mobile-safe and accessible**
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ ```ruby
25
+ gem 'rails_ui_guard', git: 'https://github.com/KapilDevPal/Rails-Ui-Guard.git'
26
+ ```
27
+
28
+ Or if published to RubyGems:
29
+
30
+ ```ruby
31
+ gem 'rails_ui_guard'
32
+ ```
33
+
34
+ Then execute:
35
+
36
+ ```bash
37
+ $ bundle install
38
+ ```
39
+
40
+ Run the generator to create the migration and initializer:
41
+
42
+ ```bash
43
+ $ rails generate rails_ui_guard:install
44
+ $ rails db:migrate
45
+ ```
46
+
47
+ ## Quick Start
48
+
49
+ ### 1. Include in your model (e.g., School)
50
+
51
+ ```ruby
52
+ class School < ApplicationRecord
53
+ include RailsUiGuard::FeatureStatusable
54
+ has_feature_status
55
+ end
56
+ ```
57
+
58
+ ### 2. Include in ApplicationController
59
+
60
+ ```ruby
61
+ class ApplicationController < ActionController::Base
62
+ include RailsUiGuard::ControllerHelpers
63
+ end
64
+ ```
65
+
66
+ ### 3. Use in your controllers
67
+
68
+ ```ruby
69
+ class FeesController < ApplicationController
70
+ before_action :set_current_school
71
+ before_action -> { enforce_feature_access("fee_management") }
72
+
73
+ def index
74
+ @module_status = current_school.module_status("fee_management")
75
+ # ... rest of action
76
+ end
77
+ end
78
+ ```
79
+
80
+ ### 4. Add to your layout
81
+
82
+ ```erb
83
+ <!-- app/views/layouts/application.html.erb -->
84
+ <%= render_module_overlay(@module_status) %>
85
+ ```
86
+
87
+ ### 5. Add status badges to sidebar (optional)
88
+
89
+ ```erb
90
+ <!-- app/views/shared/_sidebar.html.erb -->
91
+ <% feature_key = app_module.name.parameterize(separator: '_') %>
92
+ <% module_status = current_school.module_status(feature_key) %>
93
+ <%= rails_ui_guard_status_badge(module_status) %>
94
+ ```
95
+
96
+ ## Feature States
97
+
98
+ ### Active (`:active`)
99
+ - Module is fully accessible and functional
100
+ - No restrictions or overlays
101
+
102
+ ### Locked (`:locked`)
103
+ - Module is not enabled for this tenant
104
+ - Page content is blurred with lock overlay
105
+ - All interactions blocked
106
+ - Backend actions are blocked
107
+
108
+ ### Under Work (`:under_work`)
109
+ - Module is temporarily unavailable (maintenance)
110
+ - Page content is blurred with maintenance overlay
111
+ - All interactions blocked
112
+ - Backend actions are blocked
113
+
114
+ ## Usage Examples
115
+
116
+ ### Setting Feature Status
117
+
118
+ ```ruby
119
+ # In Rails console or admin panel
120
+ school = School.find_by(name: "Demo School")
121
+
122
+ # Lock a feature
123
+ school.set_feature_status("fee_management", :locked,
124
+ message: "Fee Management is not available in your plan.",
125
+ help_text: "Contact sales@example.com to upgrade.")
126
+
127
+ # Set to under work
128
+ school.set_feature_status("fee_management", :under_work,
129
+ message: "Fee Management is under maintenance. Expected completion: 2:00 PM.")
130
+
131
+ # Set to active
132
+ school.set_feature_status("fee_management", :active)
133
+ ```
134
+
135
+ ### Checking Feature Status
136
+
137
+ ```ruby
138
+ school.module_status("fee_management") # => :active, :locked, or :under_work
139
+ school.feature_active?("fee_management") # => true/false
140
+ school.feature_locked?("fee_management") # => true/false
141
+ school.feature_under_work?("fee_management") # => true/false
142
+ ```
143
+
144
+ ### Controller Helpers
145
+
146
+ ```ruby
147
+ # Set feature status (for overlay display)
148
+ rails_ui_guard_set_feature!("fee_management")
149
+
150
+ # Enforce active status (blocks non-active)
151
+ rails_ui_guard_enforce_active!("fee_management")
152
+ ```
153
+
154
+ ### View Helpers
155
+
156
+ ```erb
157
+ <!-- Status badge -->
158
+ <%= rails_ui_guard_status_badge(module_status) %>
159
+
160
+ <!-- Wrap content with blur/overlay -->
161
+ <%= rails_ui_guard_wrap(status: @module_status, feature_key: "fee_management") do %>
162
+ <!-- Content here -->
163
+ <% end %>
164
+
165
+ <!-- Render overlay -->
166
+ <%= render_module_overlay(@module_status) %>
167
+ ```
168
+
169
+ ## Active Admin Integration
170
+
171
+ The gem includes an Active Admin resource for managing feature statuses. To use it, create:
172
+
173
+ ```ruby
174
+ # app/admin/feature_statuses.rb
175
+ ActiveAdmin.register RailsUiGuard::FeatureStatus, as: "FeatureStatus" do
176
+ menu label: "Module Lock & Status", priority: 5
177
+
178
+ permit_params :statusable_type, :statusable_id, :feature_key, :status, :message, :help_text
179
+
180
+ # ... rest of configuration
181
+ end
182
+ ```
183
+
184
+ See the [full documentation](https://github.com/KapilDevPal/Rails-Ui-Guard) for complete Active Admin setup.
185
+
186
+ ## Security
187
+
188
+ ⚠️ **Important**: The UI blur/overlay is **UX only**. Backend enforcement is **mandatory** and cannot be bypassed by disabling JavaScript or manipulating the DOM.
189
+
190
+ Always use `enforce_feature_access` in your controllers:
191
+
192
+ ```ruby
193
+ before_action -> { enforce_feature_access("fee_management") }
194
+ ```
195
+
196
+ ## Requirements
197
+
198
+ - Ruby >= 2.7.0
199
+ - Rails >= 6.0, < 9.0
200
+ - ActiveRecord >= 6.0, < 9.0
201
+
202
+ ## Development
203
+
204
+ After checking out the repo, run:
205
+
206
+ ```bash
207
+ $ bundle install
208
+ $ rake test
209
+ ```
210
+
211
+ To build and install the gem:
212
+
213
+ ```bash
214
+ $ gem build rails_ui_guard.gemspec
215
+ $ gem install rails_ui_guard-0.1.0.gem
216
+ ```
217
+
218
+ ## Contributing
219
+
220
+ Bug reports and pull requests are welcome on GitHub at https://github.com/KapilDevPal/Rails-Ui-Guard.
221
+
222
+ ## License
223
+
224
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
225
+
226
+ ## Author
227
+
228
+ **Kapil Dev Pal**
229
+
230
+ - GitHub: [@KapilDevPal](https://github.com/KapilDevPal)
231
+ - Email: kapildevpal@gmail.com
232
+
233
+ ## Support
234
+
235
+ For questions or issues:
236
+ 1. Check the [documentation](https://github.com/KapilDevPal/Rails-Ui-Guard)
237
+ 2. Open an [issue](https://github.com/KapilDevPal/Rails-Ui-Guard/issues)
238
+ 3. Contact the maintainer
239
+
240
+ ---
241
+
242
+ Made with ❤️ for the Rails community
243
+
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsUiGuard
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ desc "Creates Rails UI Guard migration and initializer"
9
+
10
+ def create_migration
11
+ migration_template(
12
+ "create_rails_ui_guard_feature_statuses.rb.erb",
13
+ "db/migrate/create_rails_ui_guard_feature_statuses.rb"
14
+ )
15
+ end
16
+
17
+ def create_initializer
18
+ copy_file "rails_ui_guard.rb", "config/initializers/rails_ui_guard.rb"
19
+ end
20
+
21
+ def show_readme
22
+ readme "README" if behavior == :invoke
23
+ end
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,32 @@
1
+ Rails UI Guard has been installed!
2
+
3
+ Next steps:
4
+
5
+ 1. Run the migration:
6
+ rails db:migrate
7
+
8
+ 2. Include in your model (e.g., School):
9
+ class School < ApplicationRecord
10
+ include RailsUiGuard::FeatureStatusable
11
+ has_feature_status
12
+ end
13
+
14
+ 3. Include in ApplicationController:
15
+ class ApplicationController < ActionController::Base
16
+ include RailsUiGuard::ControllerHelpers
17
+ end
18
+
19
+ 4. Use in your controllers:
20
+ class FeesController < ApplicationController
21
+ before_action -> { enforce_feature_access("fee_management") }
22
+
23
+ def index
24
+ @module_status = current_school.module_status("fee_management")
25
+ end
26
+ end
27
+
28
+ 5. Add to your layout (app/views/layouts/application.html.erb):
29
+ <%= render_module_overlay(@module_status) %>
30
+
31
+ For complete documentation, see: https://github.com/KapilDevPal/Rails-Ui-Guard
32
+
@@ -0,0 +1,21 @@
1
+ class CreateRailsUiGuardFeatureStatuses < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :rails_ui_guard_feature_statuses, id: :uuid do |t|
4
+ t.references :statusable, polymorphic: true, null: false, type: :uuid, index: true
5
+ t.string :feature_key, null: false
6
+ t.string :status, null: false, default: "active"
7
+ t.text :message
8
+ t.text :help_text
9
+
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :rails_ui_guard_feature_statuses,
14
+ [:statusable_type, :statusable_id, :feature_key],
15
+ unique: true,
16
+ name: "index_rails_ui_guard_feature_statuses_unique"
17
+ add_index :rails_ui_guard_feature_statuses, :feature_key
18
+ add_index :rails_ui_guard_feature_statuses, :status
19
+ end
20
+ end
21
+
@@ -0,0 +1,6 @@
1
+ # Load Rails UI Guard gem
2
+ # This ensures the gem is loaded early in the Rails boot process
3
+ if defined?(Rails)
4
+ require "rails_ui_guard"
5
+ end
6
+
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsUiGuard
4
+ # DB-backed feature status record.
5
+ #
6
+ # This is the source of truth for per-tenant module/sub-module availability.
7
+ #
8
+ # - statusable: typically School (multi-tenant), but polymorphic for extensibility.
9
+ # - feature_key: stable string key for the module/submodule (e.g. "Fee Management" or "fees_module")
10
+ # - status: :active | :locked | :under_work (extensible)
11
+ class FeatureStatus < ::ApplicationRecord
12
+ self.table_name = "rails_ui_guard_feature_statuses"
13
+
14
+ belongs_to :statusable, polymorphic: true
15
+
16
+ validates :feature_key, presence: true
17
+ validates :status, presence: true
18
+ validates :feature_key, uniqueness: { scope: %i[statusable_type statusable_id] }
19
+
20
+ # Keep statuses as strings for easy future expansion without migrations.
21
+ STATUSES = %w[active locked under_work].freeze
22
+
23
+ validates :status, inclusion: { in: STATUSES }
24
+
25
+ def active?
26
+ status == "active"
27
+ end
28
+
29
+ def locked?
30
+ status == "locked"
31
+ end
32
+
33
+ def under_work?
34
+ status == "under_work"
35
+ end
36
+
37
+ def self.ransackable_attributes(_auth_object = nil)
38
+ %w[id statusable_type statusable_id feature_key status message help_text created_at updated_at]
39
+ end
40
+
41
+ def self.ransackable_associations(_auth_object = nil)
42
+ %w[statusable]
43
+ end
44
+ end
45
+ end
46
+
47
+
@@ -0,0 +1,99 @@
1
+ <%# Enhanced user-friendly overlay with lock details %>
2
+ <%# This provides a transparent overlay with clear messaging when modules are locked or under maintenance %>
3
+
4
+ <%
5
+ status = module_status&.to_sym || :active
6
+ feature_key = feature_key&.to_s
7
+
8
+ # Determine icon, title, and colors based on status
9
+ case status
10
+ when :locked
11
+ icon = "🔒"
12
+ title = "Module Locked"
13
+ bg_color = "bg-red-500"
14
+ text_color = "text-red-700"
15
+ border_color = "border-red-300"
16
+ icon_bg = "bg-red-100"
17
+ when :under_work
18
+ icon = "🚧"
19
+ title = "Under Maintenance"
20
+ bg_color = "bg-yellow-500"
21
+ text_color = "text-yellow-700"
22
+ border_color = "border-yellow-300"
23
+ icon_bg = "bg-yellow-100"
24
+ else
25
+ # Should not render if active, but just in case
26
+ return
27
+ end
28
+
29
+ # Get custom message or use default
30
+ message = feature_status&.message.presence
31
+ if message.blank?
32
+ case status
33
+ when :locked
34
+ message = "This module is currently locked and not available for your school. Please contact your administrator for more information."
35
+ when :under_work
36
+ message = "This module is currently under maintenance. We're working hard to bring it back online soon. Please check back later."
37
+ else
38
+ message = "This module is currently unavailable."
39
+ end
40
+ end
41
+ help_text = feature_status&.help_text
42
+ %>
43
+
44
+ <div class="rails-ui-guard-overlay fixed inset-0 flex items-center justify-center z-[10000] pointer-events-auto"
45
+ style="background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);">
46
+ <div class="rails-ui-guard-overlay-content bg-white rounded-2xl shadow-2xl max-w-md w-full mx-4 transform transition-all duration-300 scale-100 <%= border_color %> border-2">
47
+ <!-- Header with Icon -->
48
+ <div class="<%= bg_color %> rounded-t-xl px-6 py-4 flex items-center space-x-4">
49
+ <div class="<%= icon_bg %> rounded-full p-3 flex items-center justify-center">
50
+ <span class="text-3xl"><%= icon %></span>
51
+ </div>
52
+ <div class="flex-1">
53
+ <h2 class="text-xl font-bold text-white"><%= title %></h2>
54
+ <% if feature_key.present? %>
55
+ <p class="text-sm text-white opacity-90 mt-1">
56
+ <%= feature_key.humanize %>
57
+ </p>
58
+ <% end %>
59
+ </div>
60
+ </div>
61
+
62
+ <!-- Content -->
63
+ <div class="px-6 py-6">
64
+ <div class="<%= text_color %> mb-4">
65
+ <p class="text-base leading-relaxed whitespace-pre-wrap"><%= message %></p>
66
+ </div>
67
+
68
+ <% if help_text.present? %>
69
+ <div class="mt-4 pt-4 border-t border-gray-200">
70
+ <p class="text-sm text-gray-600 leading-relaxed whitespace-pre-wrap">
71
+ <strong class="text-gray-800">Need Help?</strong><br>
72
+ <%= help_text %>
73
+ </p>
74
+ </div>
75
+ <% end %>
76
+
77
+ <!-- Action Buttons -->
78
+ <div class="mt-6 flex flex-col sm:flex-row gap-3">
79
+ <% if defined?(root_path) %>
80
+ <%= link_to root_path,
81
+ class: "flex-1 px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg font-medium text-center transition-colors duration-200" do %>
82
+ <i class="fas fa-home mr-2"></i>
83
+ Go to Dashboard
84
+ <% end %>
85
+ <% end %>
86
+
87
+ <% if defined?(current_user) && (current_user&.respond_to?(:super_admin?) && current_user&.super_admin?) || (current_user&.respond_to?(:school_head?) && current_user&.school_head?) %>
88
+ <% if defined?(admin_feature_statuses_path) %>
89
+ <%= link_to admin_feature_statuses_path,
90
+ class: "flex-1 px-4 py-2 #{bg_color} hover:opacity-90 text-white rounded-lg font-medium text-center transition-opacity duration-200" do %>
91
+ <i class="fas fa-cog mr-2"></i>
92
+ Manage Access
93
+ <% end %>
94
+ <% end %>
95
+ <% end %>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </div>
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Concern to add feature status methods to models (e.g., School)
4
+ # Provides module_status(feature_key) method that returns :active, :locked, or :under_work
5
+ module RailsUiGuard::FeatureStatusable
6
+ extend ActiveSupport::Concern
7
+
8
+ # Returns the FeatureStatus record (if present) for a given feature_key.
9
+ # Useful for retrieving message/help_text in the UI overlay.
10
+ def feature_status_record(feature_key)
11
+ feature_key = feature_key.to_s
12
+ feature_statuses.find_by(feature_key: feature_key)
13
+ end
14
+
15
+ # Returns the status of a feature/module for this record
16
+ # @param feature_key [String, Symbol] The key identifying the feature/module
17
+ # @return [Symbol] :active, :locked, or :under_work
18
+ def module_status(feature_key)
19
+ feature_key = feature_key.to_s
20
+
21
+ # Check if there's a feature_status record for this feature
22
+ status_record = feature_status_record(feature_key)
23
+ return status_record.status.to_sym if status_record
24
+
25
+ # Fallback: Check module_access if it exists (backward compatibility)
26
+ if respond_to?(:module_accesses)
27
+ module_access = module_accesses.joins(:app_module).find_by(app_modules: { name: feature_key })
28
+ if module_access
29
+ return module_access.granted? ? :active : :locked
30
+ end
31
+ end
32
+
33
+ # Default to active if no status is set
34
+ :active
35
+ end
36
+
37
+ # Check if a feature is active
38
+ def feature_active?(feature_key)
39
+ module_status(feature_key) == :active
40
+ end
41
+
42
+ # Check if a feature is locked
43
+ def feature_locked?(feature_key)
44
+ module_status(feature_key) == :locked
45
+ end
46
+
47
+ # Check if a feature is under work
48
+ def feature_under_work?(feature_key)
49
+ module_status(feature_key) == :under_work
50
+ end
51
+
52
+ # Set the status of a feature
53
+ def set_feature_status(feature_key, status, message: nil, help_text: nil)
54
+ status_record = feature_statuses.find_or_initialize_by(feature_key: feature_key.to_s)
55
+ status_record.status = status.to_s
56
+ status_record.message = message if message.present?
57
+ status_record.help_text = help_text if help_text.present?
58
+ status_record.save!
59
+ end
60
+
61
+ class_methods do
62
+ # Include this in your model to add feature status support
63
+ # Requires has_many :feature_statuses association
64
+ def has_feature_status
65
+ has_many :feature_statuses,
66
+ class_name: 'RailsUiGuard::FeatureStatus',
67
+ dependent: :destroy,
68
+ as: :statusable
69
+ end
70
+ end
71
+ end
72
+
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsUiGuard
4
+ # Controller helpers for enforcing feature/module access (backend security)
5
+ #
6
+ # Pattern:
7
+ # class FeesController < ApplicationController
8
+ # before_action -> { rails_ui_guard_set_feature!("Fee Management") }
9
+ # before_action -> { rails_ui_guard_enforce_active!("Fee Management") }, only: [:create, :update, :destroy]
10
+ # end
11
+ #
12
+ # Notes:
13
+ # - Read actions can render normally (UX overlay will blur/freeze if locked)
14
+ # - Write actions MUST be blocked server-side to prevent URL/API bypass
15
+ module ControllerHelpers
16
+ extend ActiveSupport::Concern
17
+
18
+ included do
19
+ helper_method :rails_ui_guard_current_school
20
+ end
21
+
22
+ # Override by defining `current_school` in ApplicationController (you already have this).
23
+ def rails_ui_guard_current_school
24
+ respond_to?(:current_school) ? current_school : nil
25
+ end
26
+
27
+ # Sets instance variables used by the layout overlay:
28
+ # - @feature_key
29
+ # - @module_status (:active | :locked | :under_work | ...)
30
+ # - @feature_status_record (optional, provides message/help_text)
31
+ def rails_ui_guard_set_feature!(feature_key)
32
+ @feature_key = feature_key.to_s
33
+ school = rails_ui_guard_current_school
34
+
35
+ if school&.respond_to?(:module_status)
36
+ @module_status = school.module_status(@feature_key)
37
+ if school.respond_to?(:feature_status_record)
38
+ @feature_status_record = school.feature_status_record(@feature_key)
39
+ end
40
+ else
41
+ @module_status = :active
42
+ @feature_status_record = nil
43
+ end
44
+ end
45
+
46
+ # Backend enforcement: blocks non-active access for critical actions.
47
+ #
48
+ # - For HTML: redirect back (or to root) with a clear flash
49
+ # - For JSON: returns 403
50
+ def rails_ui_guard_enforce_active!(feature_key, redirect_to: nil)
51
+ school = rails_ui_guard_current_school
52
+ status = school&.respond_to?(:module_status) ? school.module_status(feature_key) : :active
53
+ return if status.to_sym == :active
54
+
55
+ message =
56
+ case status.to_sym
57
+ when :locked
58
+ "This feature is not enabled for your school."
59
+ when :under_work
60
+ "This feature is temporarily unavailable (maintenance/under work)."
61
+ else
62
+ "This feature is currently unavailable."
63
+ end
64
+
65
+ respond_to do |format|
66
+ format.html do
67
+ flash[:alert] = message
68
+ target = redirect_to || (request.referer.presence || main_app.root_path)
69
+ redirect_to target
70
+ end
71
+ format.json { render json: { error: message, feature_status: status }, status: :forbidden }
72
+ format.any { head :forbidden }
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsUiGuard
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace RailsUiGuard
6
+ engine_name "rails_ui_guard"
7
+
8
+ # Configure paths for views, models, and assets
9
+ config.autoload_paths << root.join("app", "models")
10
+
11
+ paths["app/views"] = root.join("app", "views")
12
+ paths["app/models"] = root.join("app", "models")
13
+ paths["app/helpers"] = root.join("app", "helpers")
14
+ paths["app/assets"] = root.join("app", "assets")
15
+
16
+ # Load the FeatureStatus model after Rails is fully initialized
17
+ # This ensures ApplicationRecord is available
18
+ config.to_prepare do
19
+ require root.join("app", "models", "rails_ui_guard", "feature_status") unless defined?(RailsUiGuard::FeatureStatus)
20
+ end
21
+
22
+ # Make view helpers available globally
23
+ initializer "rails_ui_guard.view_helpers" do
24
+ ActiveSupport.on_load(:action_view) do
25
+ include RailsUiGuard::ViewHelpers
26
+ end
27
+ end
28
+
29
+ # Make controller helpers available and register view helpers
30
+ initializer "rails_ui_guard.controller_helpers" do
31
+ ActiveSupport.on_load(:action_controller_base) do
32
+ include RailsUiGuard::ControllerHelpers
33
+ end
34
+ end
35
+
36
+ # Register helpers so they're available in all views
37
+ initializer "rails_ui_guard.register_helpers" do
38
+ ActiveSupport.on_load(:action_controller) do
39
+ helper RailsUiGuard::ViewHelpers
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsUiGuard
4
+ VERSION = "0.1.1"
5
+ end
6
+
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsUiGuard
4
+ # View helpers for the blur + overlay UX.
5
+ #
6
+ # This is intentionally **no-JS**. The UI lock is UX only; backend enforcement
7
+ # must still be done with `rails_ui_guard_enforce_active!` for write actions.
8
+ module ViewHelpers
9
+ # Wrap arbitrary content with a blur/freeze overlay when status != :active.
10
+ #
11
+ # Usage (recommended in layout):
12
+ #
13
+ # <%= rails_ui_guard_wrap(status: @module_status, feature_key: @feature_key, feature_status: @feature_status_record) do %>
14
+ # <%= yield %>
15
+ # <% end %>
16
+ #
17
+ def rails_ui_guard_wrap(status:, feature_key: nil, feature_status: nil, &block)
18
+ status = status&.to_sym
19
+ content = capture(&block)
20
+
21
+ return content if status.nil? || status == :active
22
+
23
+ blurred_classes = "rails-ui-guard-blur rails-ui-guard-opacity rails-ui-guard-block-pointer"
24
+ # `inert` prevents focus/keyboard interaction in modern browsers (no JS needed).
25
+ inert_attr = "inert"
26
+
27
+ safe_join(
28
+ [
29
+ content_tag(:div, class: "relative") do
30
+ safe_join(
31
+ [
32
+ content_tag(:div, content, class: blurred_classes, **{ inert: inert_attr }),
33
+ render(
34
+ "rails_ui_guard/shared/module_overlay",
35
+ module_status: status,
36
+ feature_key: feature_key,
37
+ feature_status: feature_status
38
+ )
39
+ ]
40
+ )
41
+ end
42
+ ]
43
+ )
44
+ end
45
+
46
+ # Optional: show lock/maintenance badge for menu items.
47
+ def rails_ui_guard_status_badge(status)
48
+ status = status&.to_sym
49
+ return "" if status.nil? || status == :active
50
+
51
+ label, classes, icon =
52
+ case status
53
+ when :locked
54
+ ["Locked", "bg-gray-700 text-gray-200", "🔒"]
55
+ when :under_work
56
+ ["Under Work", "bg-yellow-700 text-yellow-100", "🚧"]
57
+ else
58
+ ["Unavailable", "bg-red-700 text-red-100", "⚠️"]
59
+ end
60
+
61
+ content_tag(:span, class: "ml-auto flex items-center gap-1 text-[10px] px-2 py-0.5 rounded #{classes}") do
62
+ safe_join([
63
+ content_tag(:span, icon, class: "text-xs"),
64
+ content_tag(:span, label)
65
+ ])
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rails_ui_guard
4
+ #
5
+ # Feature locking and status management system for Rails multi-tenant applications.
6
+ #
7
+ # This gem provides:
8
+ # - A DB-driven feature-status model (per-tenant)
9
+ # - Controller guards (backend enforcement)
10
+ # - View helpers + reusable overlay partial (UX blur/lock; no JS)
11
+ #
12
+ # See README.md for installation and usage instructions.
13
+
14
+ require "active_support"
15
+
16
+ # Ensure namespace exists even if files are loaded out-of-order.
17
+ module RailsUiGuard
18
+ end
19
+
20
+ # Core pieces (required early so models can safely `include RailsUiGuard::...`)
21
+ require_relative "rails_ui_guard/concerns/feature_statusable"
22
+ require_relative "rails_ui_guard/app/models/rails_ui_guard/feature_status"
23
+
24
+ require_relative "rails_ui_guard/version"
25
+ require_relative "rails_ui_guard/controller_helpers"
26
+ require_relative "rails_ui_guard/view_helpers"
27
+
28
+ # Engine hooks views/helpers into the host app and configures autoloading
29
+ require_relative "rails_ui_guard/engine" if defined?(Rails)
30
+
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/rails_ui_guard/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rails_ui_guard"
7
+ spec.version = RailsUiGuard::VERSION
8
+ spec.authors = ["Kapil Dev Pal"]
9
+ spec.email = ["kapildevpal@gmail.com"]
10
+
11
+ spec.summary = "Feature locking and status management system for Rails multi-tenant applications"
12
+ spec.description = <<~DESC
13
+ Rails UI Guard provides a clean way to lock/unlock features, show maintenance overlays,
14
+ and enforce backend security for modules in multi-tenant Rails applications.
15
+
16
+ Features:
17
+ - Per-tenant feature status management (Active, Locked, Under Work)
18
+ - UI blur/overlay system (no JavaScript required)
19
+ - Backend enforcement for security
20
+ - Sidebar status badges
21
+ - Reusable view helpers and partials
22
+ - Rails 6/7/8 compatible
23
+ DESC
24
+ spec.homepage = "https://github.com/KapilDevPal/Rails-Ui-Guard"
25
+ spec.license = "MIT"
26
+ spec.required_ruby_version = ">= 2.7.0"
27
+
28
+ spec.metadata["homepage_uri"] = spec.homepage
29
+ spec.metadata["source_code_uri"] = "#{spec.homepage}.git"
30
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
31
+ spec.metadata["rubygems_mfa_required"] = "false"
32
+
33
+ # Specify which files should be added to the gem when it is released.
34
+ spec.files = Dir.chdir(__dir__) do
35
+ `git ls-files -z`.split("\x0").reject do |f|
36
+ (File.expand_path(f) == __FILE__) ||
37
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile Rakefile])
38
+ end
39
+ rescue
40
+ # If git is not available, include all files
41
+ Dir.glob("**/*", File::FNM_DOTMATCH).reject do |f|
42
+ File.directory?(f) ||
43
+ f.start_with?("bin/", "test/", "spec/", ".git", "Gemfile", "Rakefile") ||
44
+ f.end_with?(".gem")
45
+ end
46
+ end
47
+
48
+ spec.bindir = "exe"
49
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
50
+ spec.require_paths = ["lib"]
51
+
52
+ spec.add_dependency "rails", ">= 6.0", "< 9.0"
53
+ spec.add_dependency "activerecord", ">= 6.0", "< 9.0"
54
+ end
55
+
data/setup_gem.sh ADDED
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+
3
+ # Rails UI Guard Gem Setup Script
4
+ # This script helps set up the gem for GitHub and RubyGems
5
+
6
+ set -e
7
+
8
+ echo "🚀 Setting up Rails UI Guard gem..."
9
+
10
+ # Check if git is initialized
11
+ if [ ! -d ".git" ]; then
12
+ echo "📦 Initializing git repository..."
13
+ git init
14
+ git branch -M main
15
+ fi
16
+
17
+ # Add all files
18
+ echo "📝 Adding files to git..."
19
+ git add .
20
+
21
+ # Build the gem
22
+ echo "🔨 Building gem..."
23
+ gem build rails_ui_guard.gemspec
24
+
25
+ echo "✅ Gem setup complete!"
26
+ echo ""
27
+ echo "Next steps:"
28
+ echo "1. Review the gem: gem install rails_ui_guard-*.gem --local"
29
+ echo "2. Add remote: git remote add origin https://github.com/KapilDevPal/Rails-Ui-Guard.git"
30
+ echo "3. Commit: git commit -m 'Initial commit: Rails UI Guard v0.1.0'"
31
+ echo "4. Push: git push -u origin main"
32
+ echo "5. Publish to RubyGems: gem push rails_ui_guard-*.gem"
33
+
metadata CHANGED
@@ -1,11 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_ui_guard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kapil Dev Pal
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
10
  date: 2025-12-28 00:00:00.000000000 Z
@@ -60,7 +59,26 @@ email:
60
59
  executables: []
61
60
  extensions: []
62
61
  extra_rdoc_files: []
63
- files: []
62
+ files:
63
+ - CHANGELOG.md
64
+ - GEM_SETUP_COMPLETE.md
65
+ - LICENSE.txt
66
+ - PUSH_TO_GITHUB.md
67
+ - README.md
68
+ - lib/generators/rails_ui_guard/install/install_generator.rb
69
+ - lib/generators/rails_ui_guard/install/templates/README
70
+ - lib/generators/rails_ui_guard/install/templates/create_rails_ui_guard_feature_statuses.rb.erb
71
+ - lib/generators/rails_ui_guard/install/templates/rails_ui_guard.rb
72
+ - lib/rails_ui_guard.rb
73
+ - lib/rails_ui_guard/app/models/rails_ui_guard/feature_status.rb
74
+ - lib/rails_ui_guard/app/views/rails_ui_guard/shared/_module_overlay.html.erb
75
+ - lib/rails_ui_guard/concerns/feature_statusable.rb
76
+ - lib/rails_ui_guard/controller_helpers.rb
77
+ - lib/rails_ui_guard/engine.rb
78
+ - lib/rails_ui_guard/version.rb
79
+ - lib/rails_ui_guard/view_helpers.rb
80
+ - rails_ui_guard.gemspec
81
+ - setup_gem.sh
64
82
  homepage: https://github.com/KapilDevPal/Rails-Ui-Guard
65
83
  licenses:
66
84
  - MIT
@@ -69,7 +87,6 @@ metadata:
69
87
  source_code_uri: https://github.com/KapilDevPal/Rails-Ui-Guard.git
70
88
  changelog_uri: https://github.com/KapilDevPal/Rails-Ui-Guard/blob/main/CHANGELOG.md
71
89
  rubygems_mfa_required: 'false'
72
- post_install_message:
73
90
  rdoc_options: []
74
91
  require_paths:
75
92
  - lib
@@ -84,8 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
101
  - !ruby/object:Gem::Version
85
102
  version: '0'
86
103
  requirements: []
87
- rubygems_version: 3.5.11
88
- signing_key:
104
+ rubygems_version: 3.6.3
89
105
  specification_version: 4
90
106
  summary: Feature locking and status management system for Rails multi-tenant applications
91
107
  test_files: []