dbwatcher 0.1.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +81 -210
- data/app/assets/config/dbwatcher_manifest.js +15 -0
- data/app/assets/javascripts/dbwatcher/alpine_registrations.js +39 -0
- data/app/assets/javascripts/dbwatcher/auto_init.js +23 -0
- data/app/assets/javascripts/dbwatcher/components/base.js +141 -0
- data/app/assets/javascripts/dbwatcher/components/changes_table_hybrid.js +1008 -0
- data/app/assets/javascripts/dbwatcher/components/diagrams.js +449 -0
- data/app/assets/javascripts/dbwatcher/components/summary.js +234 -0
- data/app/assets/javascripts/dbwatcher/core/alpine_store.js +138 -0
- data/app/assets/javascripts/dbwatcher/core/api_client.js +162 -0
- data/app/assets/javascripts/dbwatcher/core/component_loader.js +70 -0
- data/app/assets/javascripts/dbwatcher/core/component_registry.js +94 -0
- data/app/assets/javascripts/dbwatcher/dbwatcher.js +120 -0
- data/app/assets/javascripts/dbwatcher/services/mermaid.js +315 -0
- data/app/assets/javascripts/dbwatcher/services/mermaid_service.js +199 -0
- data/app/assets/javascripts/dbwatcher/vendor/date-fns-browser.js +99 -0
- data/app/assets/javascripts/dbwatcher/vendor/lodash.min.js +140 -0
- data/app/assets/javascripts/dbwatcher/vendor/tabulator.min.js +3 -0
- data/app/assets/stylesheets/dbwatcher/application.css +423 -0
- data/app/assets/stylesheets/dbwatcher/application.scss +15 -0
- data/app/assets/stylesheets/dbwatcher/components/_badges.scss +38 -0
- data/app/assets/stylesheets/dbwatcher/components/_compact_table.scss +162 -0
- data/app/assets/stylesheets/dbwatcher/components/_diagrams.scss +51 -0
- data/app/assets/stylesheets/dbwatcher/components/_forms.scss +27 -0
- data/app/assets/stylesheets/dbwatcher/components/_navigation.scss +55 -0
- data/app/assets/stylesheets/dbwatcher/core/_base.scss +34 -0
- data/app/assets/stylesheets/dbwatcher/core/_variables.scss +47 -0
- data/app/assets/stylesheets/dbwatcher/vendor/tabulator.min.css +2 -0
- data/app/controllers/dbwatcher/api/v1/sessions_controller.rb +64 -0
- data/app/controllers/dbwatcher/base_controller.rb +101 -0
- data/app/controllers/dbwatcher/dashboard_controller.rb +20 -0
- data/app/controllers/dbwatcher/queries_controller.rb +24 -0
- data/app/controllers/dbwatcher/sessions_controller.rb +30 -20
- data/app/controllers/dbwatcher/tables_controller.rb +38 -0
- data/app/helpers/dbwatcher/application_helper.rb +103 -0
- data/app/helpers/dbwatcher/component_helper.rb +29 -0
- data/app/helpers/dbwatcher/diagram_helper.rb +110 -0
- data/app/helpers/dbwatcher/formatting_helper.rb +108 -0
- data/app/helpers/dbwatcher/session_helper.rb +28 -0
- data/app/views/dbwatcher/dashboard/index.html.erb +177 -0
- data/app/views/dbwatcher/queries/index.html.erb +240 -0
- data/app/views/dbwatcher/sessions/_changes_tab.html.erb +265 -0
- data/app/views/dbwatcher/sessions/_diagrams_tab.html.erb +166 -0
- data/app/views/dbwatcher/sessions/_session_header.html.erb +11 -0
- data/app/views/dbwatcher/sessions/_summary_tab.html.erb +88 -0
- data/app/views/dbwatcher/sessions/_tab_navigation.html.erb +12 -0
- data/app/views/dbwatcher/sessions/changes.html.erb +21 -0
- data/app/views/dbwatcher/sessions/components/changes/_filters.html.erb +44 -0
- data/app/views/dbwatcher/sessions/components/changes/_table_list.html.erb +96 -0
- data/app/views/dbwatcher/sessions/diagrams.html.erb +21 -0
- data/app/views/dbwatcher/sessions/index.html.erb +124 -27
- data/app/views/dbwatcher/sessions/shared/_layout.html.erb +8 -0
- data/app/views/dbwatcher/sessions/shared/_navigation.html.erb +35 -0
- data/app/views/dbwatcher/sessions/shared/_session_header.html.erb +25 -0
- data/app/views/dbwatcher/sessions/show.html.erb +3 -149
- data/app/views/dbwatcher/sessions/summary.html.erb +21 -0
- data/app/views/dbwatcher/shared/_badge.html.erb +4 -0
- data/app/views/dbwatcher/shared/_data_table.html.erb +20 -0
- data/app/views/dbwatcher/shared/_header.html.erb +7 -0
- data/app/views/dbwatcher/shared/_page_layout.html.erb +20 -0
- data/app/views/dbwatcher/shared/_section_panel.html.erb +9 -0
- data/app/views/dbwatcher/shared/_stats_card.html.erb +11 -0
- data/app/views/dbwatcher/shared/_tab_bar.html.erb +6 -0
- data/app/views/dbwatcher/tables/changes.html.erb +225 -0
- data/app/views/dbwatcher/tables/index.html.erb +123 -0
- data/app/views/dbwatcher/tables/show.html.erb +86 -0
- data/app/views/layouts/dbwatcher/application.html.erb +252 -25
- data/bin/compile_scss +49 -0
- data/config/routes.rb +43 -3
- data/lib/dbwatcher/configuration.rb +103 -1
- data/lib/dbwatcher/engine.rb +28 -13
- data/lib/dbwatcher/logging.rb +72 -0
- data/lib/dbwatcher/services/analyzers/session_data_processor.rb +98 -0
- data/lib/dbwatcher/services/analyzers/table_summary_builder.rb +202 -0
- data/lib/dbwatcher/services/api/base_api_service.rb +100 -0
- data/lib/dbwatcher/services/api/changes_data_service.rb +112 -0
- data/lib/dbwatcher/services/api/diagram_data_service.rb +145 -0
- data/lib/dbwatcher/services/api/summary_data_service.rb +158 -0
- data/lib/dbwatcher/services/base_service.rb +64 -0
- data/lib/dbwatcher/services/dashboard_data_aggregator.rb +121 -0
- data/lib/dbwatcher/services/diagram_analyzers/base_analyzer.rb +162 -0
- data/lib/dbwatcher/services/diagram_analyzers/foreign_key_analyzer.rb +354 -0
- data/lib/dbwatcher/services/diagram_analyzers/inferred_relationship_analyzer.rb +502 -0
- data/lib/dbwatcher/services/diagram_analyzers/model_association_analyzer.rb +564 -0
- data/lib/dbwatcher/services/diagram_data/attribute.rb +154 -0
- data/lib/dbwatcher/services/diagram_data/dataset.rb +278 -0
- data/lib/dbwatcher/services/diagram_data/entity.rb +180 -0
- data/lib/dbwatcher/services/diagram_data/relationship.rb +188 -0
- data/lib/dbwatcher/services/diagram_data/relationship_params.rb +55 -0
- data/lib/dbwatcher/services/diagram_data.rb +65 -0
- data/lib/dbwatcher/services/diagram_error_handler.rb +239 -0
- data/lib/dbwatcher/services/diagram_generator.rb +154 -0
- data/lib/dbwatcher/services/diagram_strategies/base_diagram_strategy.rb +149 -0
- data/lib/dbwatcher/services/diagram_strategies/class_diagram_strategy.rb +49 -0
- data/lib/dbwatcher/services/diagram_strategies/erd_diagram_strategy.rb +52 -0
- data/lib/dbwatcher/services/diagram_strategies/flowchart_diagram_strategy.rb +52 -0
- data/lib/dbwatcher/services/diagram_system.rb +69 -0
- data/lib/dbwatcher/services/diagram_type_registry.rb +164 -0
- data/lib/dbwatcher/services/mermaid_syntax/base_builder.rb +127 -0
- data/lib/dbwatcher/services/mermaid_syntax/cardinality_mapper.rb +90 -0
- data/lib/dbwatcher/services/mermaid_syntax/class_diagram_builder.rb +136 -0
- data/lib/dbwatcher/services/mermaid_syntax/class_diagram_helper.rb +46 -0
- data/lib/dbwatcher/services/mermaid_syntax/erd_builder.rb +116 -0
- data/lib/dbwatcher/services/mermaid_syntax/flowchart_builder.rb +109 -0
- data/lib/dbwatcher/services/mermaid_syntax/sanitizer.rb +102 -0
- data/lib/dbwatcher/services/mermaid_syntax_builder.rb +155 -0
- data/lib/dbwatcher/services/query_filter_processor.rb +114 -0
- data/lib/dbwatcher/services/table_statistics_collector.rb +119 -0
- data/lib/dbwatcher/sql_logger.rb +107 -0
- data/lib/dbwatcher/storage/api/base_api.rb +134 -0
- data/lib/dbwatcher/storage/api/concerns/table_analyzer.rb +59 -0
- data/lib/dbwatcher/storage/api/query_api.rb +95 -0
- data/lib/dbwatcher/storage/api/session_api.rb +181 -0
- data/lib/dbwatcher/storage/api/table_api.rb +86 -0
- data/lib/dbwatcher/storage/base_storage.rb +120 -0
- data/lib/dbwatcher/storage/change_processor.rb +65 -0
- data/lib/dbwatcher/storage/concerns/data_normalizer.rb +134 -0
- data/lib/dbwatcher/storage/concerns/error_handler.rb +75 -0
- data/lib/dbwatcher/storage/concerns/timestampable.rb +74 -0
- data/lib/dbwatcher/storage/concerns/validatable.rb +117 -0
- data/lib/dbwatcher/storage/date_helper.rb +21 -0
- data/lib/dbwatcher/storage/errors.rb +86 -0
- data/lib/dbwatcher/storage/file_manager.rb +122 -0
- data/lib/dbwatcher/storage/null_session.rb +39 -0
- data/lib/dbwatcher/storage/query_storage.rb +338 -0
- data/lib/dbwatcher/storage/query_validator.rb +24 -0
- data/lib/dbwatcher/storage/session.rb +58 -0
- data/lib/dbwatcher/storage/session_operations.rb +37 -0
- data/lib/dbwatcher/storage/session_query.rb +71 -0
- data/lib/dbwatcher/storage/session_storage.rb +322 -0
- data/lib/dbwatcher/storage/table_storage.rb +237 -0
- data/lib/dbwatcher/storage.rb +112 -85
- data/lib/dbwatcher/tracker.rb +4 -55
- data/lib/dbwatcher/version.rb +1 -1
- data/lib/dbwatcher.rb +70 -3
- metadata +140 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f11adeaf76a428fbbcff3438549b7fe8f741836f79263649dd967956704b3df1
|
4
|
+
data.tar.gz: '0258691a02aa88778f0703c41c4af76ca4481c2fb61e3b0963463d1b97c7e198'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da0df8d4b8f3d435bc0912bc7d9450d8299753ab8da7a3dc36749bb910b6f471bdc1238428d8ff7c4301b38fc30037de6a466e4efb4b7d7bcb5c3bf26787b152
|
7
|
+
data.tar.gz: 53ad9a4c27aee0e5acebcc3c61a2b70ba82bfd21f2f3012aada133298bf03bd21e7532e2c962e1b86ed3c58815f5f131590679189ced4767c44a4d1c734423f9
|
data/README.md
CHANGED
@@ -1,21 +1,32 @@
|
|
1
|
-
# DBWatcher
|
1
|
+
# DBWatcher
|
2
2
|
|
3
|
-
|
3
|
+
[](https://badge.fury.io/rb/dbwatcher)
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
4
5
|
|
5
|
-
|
6
|
+
A Rails gem that tracks and visualizes database operations in your application. Built for developers who need to understand complex data flows and debug database interactions.
|
6
7
|
|
7
|
-
##
|
8
|
+
## Key Features
|
8
9
|
|
9
|
-
-
|
10
|
-
-
|
11
|
-
-
|
12
|
-
-
|
13
|
-
-
|
14
|
-
-
|
15
|
-
- **⚡ Zero Dependencies**: Works with any Rails application without complex setup
|
16
|
-
- **🔒 Development-focused**: Designed for development and testing environments
|
10
|
+
- **Database Operation Tracking** - Capture SQL operations (INSERT, UPDATE, DELETE)
|
11
|
+
- **Targeted Monitoring** - Track specific code blocks or entire HTTP requests
|
12
|
+
- **Interactive Dashboard** - Clean web interface for exploring captured data
|
13
|
+
- **Relationship Diagrams** - Visualize database relationships and model associations
|
14
|
+
- **Simple Setup** - File-based storage with zero additional database requirements
|
15
|
+
- **Development Ready** - Designed specifically for development environments
|
17
16
|
|
18
|
-
##
|
17
|
+
## Screenshots
|
18
|
+
|
19
|
+
### Dashboard Interface
|
20
|
+
|
21
|
+

|
22
|
+
|
23
|
+
### Session View
|
24
|
+
|
25
|
+

|
26
|
+
|
27
|
+
[View more screenshots in here →](docs/screenshots.md)
|
28
|
+
|
29
|
+
## Installation
|
19
30
|
|
20
31
|
Add to your Gemfile:
|
21
32
|
|
@@ -23,260 +34,120 @@ Add to your Gemfile:
|
|
23
34
|
gem 'dbwatcher', group: :development
|
24
35
|
```
|
25
36
|
|
26
|
-
|
37
|
+
Install the gem:
|
27
38
|
|
28
39
|
```bash
|
29
40
|
bundle install
|
30
41
|
```
|
31
42
|
|
32
|
-
The
|
43
|
+
The dashboard automatically becomes available at `/dbwatcher` in your Rails application.
|
33
44
|
|
34
|
-
|
45
|
+
## Usage
|
35
46
|
|
36
|
-
|
47
|
+
### Track Code Blocks
|
37
48
|
|
38
|
-
|
39
|
-
Rails.application.routes.draw do
|
40
|
-
mount Dbwatcher::Engine => "/dbwatcher" if Rails.env.development?
|
41
|
-
# ... your other routes
|
42
|
-
end
|
43
|
-
```
|
44
|
-
|
45
|
-
## 📖 Usage
|
46
|
-
|
47
|
-
### 🎯 Targeted Tracking
|
48
|
-
|
49
|
-
Track specific code blocks with detailed context:
|
49
|
+
Monitor specific operations:
|
50
50
|
|
51
51
|
```ruby
|
52
|
-
Dbwatcher.track(name: "User Registration
|
53
|
-
user = User.create!(
|
54
|
-
|
55
|
-
|
56
|
-
)
|
57
|
-
|
58
|
-
user.create_profile!(
|
59
|
-
bio: "Software Developer",
|
60
|
-
location: "San Francisco"
|
61
|
-
)
|
62
|
-
|
63
|
-
user.posts.create!(
|
64
|
-
title: "Welcome Post",
|
65
|
-
content: "Hello World!"
|
66
|
-
)
|
52
|
+
Dbwatcher.track(name: "User Registration") do
|
53
|
+
user = User.create!(name: "John", email: "john@example.com")
|
54
|
+
user.create_profile!(bio: "Developer")
|
55
|
+
user.posts.create!(title: "Hello World")
|
67
56
|
end
|
68
57
|
```
|
69
58
|
|
70
|
-
###
|
59
|
+
### Track HTTP Requests
|
71
60
|
|
72
|
-
|
61
|
+
Add `?dbwatch=true` to any URL:
|
73
62
|
|
74
63
|
```
|
75
|
-
# Track a user show page
|
76
64
|
GET /users/123?dbwatch=true
|
77
|
-
|
78
|
-
# Track a form submission
|
79
|
-
POST /users?dbwatch=true
|
80
|
-
|
81
|
-
# Track API endpoints
|
82
|
-
GET /api/posts?dbwatch=true
|
65
|
+
POST /api/users?dbwatch=true
|
83
66
|
```
|
84
67
|
|
85
|
-
###
|
68
|
+
### View Results
|
86
69
|
|
87
|
-
Visit `/dbwatcher` in your
|
88
|
-
- Browse all tracking sessions
|
89
|
-
- View detailed SQL queries and timing
|
90
|
-
- Analyze database operation patterns
|
91
|
-
- Monitor application performance
|
70
|
+
Visit `/dbwatcher` in your browser to explore tracked operations.
|
92
71
|
|
93
|
-
##
|
72
|
+
## Configuration
|
94
73
|
|
95
|
-
|
74
|
+
Optional configuration in `config/initializers/dbwatcher.rb`:
|
96
75
|
|
97
76
|
```ruby
|
98
|
-
# config/initializers/dbwatcher.rb
|
99
77
|
Dbwatcher.configure do |config|
|
100
|
-
# Storage location for tracking data
|
101
78
|
config.storage_path = Rails.root.join('tmp', 'dbwatcher')
|
102
|
-
|
103
|
-
# Enable/disable tracking (default: development only)
|
104
79
|
config.enabled = Rails.env.development?
|
105
|
-
|
106
|
-
# Maximum number of sessions to keep
|
107
80
|
config.max_sessions = 100
|
108
|
-
|
109
|
-
# Automatic cleanup after N days
|
110
81
|
config.auto_clean_after_days = 7
|
111
|
-
|
112
|
-
# Include query parameters in tracking
|
113
|
-
config.include_params = true
|
114
|
-
|
115
|
-
# Exclude certain SQL patterns
|
116
|
-
config.excluded_patterns = [
|
117
|
-
/SHOW TABLES/,
|
118
|
-
/DESCRIBE/
|
119
|
-
]
|
120
82
|
end
|
121
83
|
```
|
122
84
|
|
123
|
-
##
|
124
|
-
|
125
|
-
This project includes a comprehensive dummy Rails application for testing and development.
|
126
|
-
|
127
|
-
### Running Tests
|
128
|
-
|
129
|
-
```bash
|
130
|
-
# Run all tests
|
131
|
-
bundle exec rake test
|
132
|
-
|
133
|
-
# Run specific test suites
|
134
|
-
bundle exec rake unit # Unit tests
|
135
|
-
bundle exec rake acceptance # Feature tests
|
136
|
-
bundle exec cucumber -p chrome # Browser tests
|
137
|
-
```
|
138
|
-
|
139
|
-
### Development Server
|
140
|
-
|
141
|
-
```bash
|
142
|
-
# Start the dummy application
|
143
|
-
cd spec/dummy
|
144
|
-
bundle exec rails server -p 3001
|
145
|
-
|
146
|
-
# Visit the test interface
|
147
|
-
open http://localhost:3001
|
148
|
-
|
149
|
-
# Visit DBWatcher dashboard
|
150
|
-
open http://localhost:3001/dbwatcher
|
151
|
-
```
|
152
|
-
|
153
|
-
### Code Quality
|
154
|
-
|
155
|
-
```bash
|
156
|
-
# Run linter
|
157
|
-
bundle exec rubocop
|
158
|
-
|
159
|
-
# Auto-fix issues
|
160
|
-
bundle exec rubocop --autocorrect
|
161
|
-
|
162
|
-
# Security analysis
|
163
|
-
bundle exec brakeman
|
164
|
-
```
|
165
|
-
|
166
|
-
## 🛠️ Troubleshooting
|
167
|
-
|
168
|
-
### Route Helper Errors
|
169
|
-
|
170
|
-
If you encounter `undefined method 'dbwatcher_sessions_path'`:
|
171
|
-
|
172
|
-
1. **Restart your Rails server** after installing the gem
|
173
|
-
2. **Check Rails version** - requires Rails 6.0+
|
174
|
-
3. **Manual mounting** - add the mount line to your routes file
|
175
|
-
|
176
|
-
### Performance Considerations
|
177
|
-
|
178
|
-
- DBWatcher is designed for development environments
|
179
|
-
- Disable in production using `config.enabled = false`
|
180
|
-
- Use targeted tracking for performance-sensitive operations
|
181
|
-
- Regular cleanup prevents storage bloat
|
182
|
-
|
183
|
-
### Storage Location
|
184
|
-
|
185
|
-
- Default: `Rails.root/tmp/dbwatcher/`
|
186
|
-
- Files are JSON formatted for easy inspection
|
187
|
-
- Sessions auto-expire based on configuration
|
188
|
-
|
189
|
-
## 🔧 Advanced Usage
|
85
|
+
## Advanced Features
|
190
86
|
|
191
87
|
### Custom Metadata
|
192
88
|
|
193
|
-
Add context to your tracking
|
89
|
+
Add context to your tracking:
|
194
90
|
|
195
91
|
```ruby
|
196
92
|
Dbwatcher.track(
|
197
|
-
name: "
|
198
|
-
metadata: {
|
199
|
-
user_id: current_user.id,
|
200
|
-
feature_flag: "new_checkout",
|
201
|
-
version: "2.1.0"
|
202
|
-
}
|
93
|
+
name: "Order Processing",
|
94
|
+
metadata: { user_id: current_user.id, order_type: "premium" }
|
203
95
|
) do
|
204
|
-
#
|
96
|
+
# Database operations here
|
205
97
|
end
|
206
98
|
```
|
207
99
|
|
208
|
-
###
|
209
|
-
|
210
|
-
```ruby
|
211
|
-
Dbwatcher.track(name: "Admin Operations") do
|
212
|
-
# This will only track if DBWatcher is enabled
|
213
|
-
User.where(admin: true).update_all(last_seen: Time.current)
|
214
|
-
end if Dbwatcher.enabled?
|
215
|
-
```
|
100
|
+
### Testing Integration
|
216
101
|
|
217
|
-
|
102
|
+
Use in your test suite:
|
218
103
|
|
219
104
|
```ruby
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
Dbwatcher.track(name: "Test User Creation") do
|
226
|
-
user = create(:user)
|
227
|
-
expect(user.profile).to be_present
|
228
|
-
end
|
229
|
-
|
230
|
-
# Analyze the tracked operations
|
231
|
-
expect(Dbwatcher::Storage.last_session).to include_sql(/INSERT INTO users/)
|
105
|
+
it "creates user with associations" do
|
106
|
+
Dbwatcher.track(name: "User Creation Test") do
|
107
|
+
user = create(:user)
|
108
|
+
expect(user.profile).to be_present
|
232
109
|
end
|
233
110
|
end
|
234
111
|
```
|
235
112
|
|
236
|
-
##
|
113
|
+
## Development
|
237
114
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
│ └── routes.rb # Engine routes
|
245
|
-
├── lib/dbwatcher/
|
246
|
-
│ ├── configuration.rb # Configuration management
|
247
|
-
│ ├── engine.rb # Rails engine
|
248
|
-
│ ├── middleware.rb # Rack middleware
|
249
|
-
│ ├── storage.rb # File-based storage
|
250
|
-
│ └── tracker.rb # Core tracking logic
|
251
|
-
└── spec/
|
252
|
-
├── dummy/ # Test Rails application
|
253
|
-
├── acceptance/ # Feature tests
|
254
|
-
└── unit/ # Unit tests
|
115
|
+
### Running Tests
|
116
|
+
|
117
|
+
```bash
|
118
|
+
bundle exec rake test # All tests
|
119
|
+
bundle exec rake unit # Unit tests only
|
120
|
+
bundle exec rake acceptance # Feature tests only
|
255
121
|
```
|
256
122
|
|
257
|
-
|
123
|
+
### Local Development
|
258
124
|
|
259
|
-
|
125
|
+
```bash
|
126
|
+
cd spec/dummy
|
127
|
+
bundle exec rails server -p 3001
|
128
|
+
open http://localhost:3001/dbwatcher
|
129
|
+
```
|
260
130
|
|
261
|
-
|
262
|
-
2. Create a feature branch: `git checkout -b feature/amazing-feature`
|
263
|
-
3. Make your changes and add tests
|
264
|
-
4. Ensure all tests pass: `bundle exec rake test`
|
265
|
-
5. Run the linter: `bundle exec rubocop`
|
266
|
-
6. Commit your changes: `git commit -am 'Add amazing feature'`
|
267
|
-
7. Push to the branch: `git push origin feature/amazing-feature`
|
268
|
-
8. Open a Pull Request
|
131
|
+
### Code Quality
|
269
132
|
|
270
|
-
|
133
|
+
```bash
|
134
|
+
bundle exec rubocop # Linting
|
135
|
+
bundle exec brakeman # Security analysis
|
136
|
+
```
|
271
137
|
|
272
|
-
|
138
|
+
## Contributing
|
273
139
|
|
274
|
-
|
140
|
+
1. Fork the repository
|
141
|
+
2. Create a feature branch: `git checkout -b my-feature`
|
142
|
+
3. Make changes and add tests
|
143
|
+
4. Run tests: `bundle exec rake test`
|
144
|
+
5. Run linter: `bundle exec rubocop`
|
145
|
+
6. Commit changes: `git commit -am 'Add feature'`
|
146
|
+
7. Push branch: `git push origin my-feature`
|
147
|
+
8. Open a Pull Request
|
275
148
|
|
276
|
-
|
277
|
-
- UI powered by Alpine.js and Tailwind CSS
|
278
|
-
- Inspired by debugging needs in complex Rails applications
|
149
|
+
[Contributing guidelines →](CONTRIBUTING.md)
|
279
150
|
|
280
|
-
|
151
|
+
## License
|
281
152
|
|
282
|
-
|
153
|
+
Released under the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,15 @@
|
|
1
|
+
//= link_directory ../javascripts .js
|
2
|
+
//= link dbwatcher/dbwatcher.js
|
3
|
+
//= link dbwatcher/auto_init.js
|
4
|
+
//= link dbwatcher/alpine_registrations.js
|
5
|
+
//= link_tree ../javascripts/dbwatcher/components
|
6
|
+
//= link dbwatcher/components/changes_table_hybrid.js
|
7
|
+
//= link_tree ../javascripts/dbwatcher/core
|
8
|
+
//= link_tree ../javascripts/dbwatcher/services
|
9
|
+
//= link dbwatcher/vendor/lodash.min.js
|
10
|
+
//= link dbwatcher/vendor/date-fns-browser.js
|
11
|
+
//= link dbwatcher/vendor/tabulator.min.js
|
12
|
+
|
13
|
+
// Stylesheets
|
14
|
+
//= link dbwatcher/application.css
|
15
|
+
//= link dbwatcher/vendor/tabulator.min.css
|
@@ -0,0 +1,39 @@
|
|
1
|
+
/**
|
2
|
+
* Alpine Component Registrations
|
3
|
+
* Provides direct Alpine.js component registrations as a fallback
|
4
|
+
*/
|
5
|
+
|
6
|
+
document.addEventListener('alpine:init', function() {
|
7
|
+
if (!window.Alpine) {
|
8
|
+
console.error('Alpine.js not found');
|
9
|
+
return;
|
10
|
+
}
|
11
|
+
|
12
|
+
// Register changesTableHybrid component
|
13
|
+
if (window.DBWatcher && window.DBWatcher.components && window.DBWatcher.components.changesTableHybrid) {
|
14
|
+
window.Alpine.data('changesTableHybrid', function(config = {}) {
|
15
|
+
return window.DBWatcher.components.changesTableHybrid(config);
|
16
|
+
});
|
17
|
+
console.log('✅ Registered changesTableHybrid component with Alpine');
|
18
|
+
} else {
|
19
|
+
// Minimal fallback
|
20
|
+
console.warn('⚠️ changesTableHybrid component not found, using minimal fallback');
|
21
|
+
window.Alpine.data('changesTableHybrid', function(config = {}) {
|
22
|
+
return {
|
23
|
+
sessionId: config.sessionId || null,
|
24
|
+
tableData: {},
|
25
|
+
filters: { search: '', operation: '', table: '' },
|
26
|
+
showColumnSelector: false,
|
27
|
+
loading: false,
|
28
|
+
error: 'Component not loaded',
|
29
|
+
|
30
|
+
init() {
|
31
|
+
console.error('changesTableHybrid: Component failed to load');
|
32
|
+
}
|
33
|
+
};
|
34
|
+
});
|
35
|
+
}
|
36
|
+
|
37
|
+
// Register other components as needed
|
38
|
+
// diagrams, summary, etc.
|
39
|
+
});
|
@@ -0,0 +1,23 @@
|
|
1
|
+
/**
|
2
|
+
* DBWatcher Auto-Initializer
|
3
|
+
* This file is the main entry point for auto-initializing the DBWatcher system
|
4
|
+
* and its components when loaded into the browser.
|
5
|
+
*/
|
6
|
+
|
7
|
+
document.addEventListener('DOMContentLoaded', function() {
|
8
|
+
// Initialize DBWatcher
|
9
|
+
if (window.DBWatcher) {
|
10
|
+
window.DBWatcher.init({
|
11
|
+
debug: false
|
12
|
+
});
|
13
|
+
} else {
|
14
|
+
console.error('DBWatcher not loaded!');
|
15
|
+
}
|
16
|
+
|
17
|
+
// Initialize Alpine Store
|
18
|
+
if (window.Alpine) {
|
19
|
+
document.dispatchEvent(new Event('alpine:init'));
|
20
|
+
} else {
|
21
|
+
console.warn('Alpine.js not loaded!');
|
22
|
+
}
|
23
|
+
});
|
@@ -0,0 +1,141 @@
|
|
1
|
+
/**
|
2
|
+
* DBWatcher Base Component
|
3
|
+
* Provides standard lifecycle, utilities, and error handling for all components
|
4
|
+
* Optimized to leverage libraries for common utilities
|
5
|
+
*/
|
6
|
+
DBWatcher.BaseComponent = function(config = {}) {
|
7
|
+
return {
|
8
|
+
// Standard lifecycle properties
|
9
|
+
loading: false,
|
10
|
+
error: null,
|
11
|
+
config: config,
|
12
|
+
|
13
|
+
// Initialization - called automatically by Alpine.js
|
14
|
+
init() {
|
15
|
+
if (this.componentInit) {
|
16
|
+
try {
|
17
|
+
this.componentInit();
|
18
|
+
} catch (error) {
|
19
|
+
this.handleError(error);
|
20
|
+
}
|
21
|
+
}
|
22
|
+
},
|
23
|
+
|
24
|
+
// Cleanup - should be called when component is removed
|
25
|
+
destroy() {
|
26
|
+
if (this.componentDestroy) {
|
27
|
+
try {
|
28
|
+
this.componentDestroy();
|
29
|
+
} catch (error) {
|
30
|
+
console.error("Error during component cleanup:", error);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
},
|
34
|
+
|
35
|
+
// ==========================================
|
36
|
+
// Utility methods (directly use library methods)
|
37
|
+
// ==========================================
|
38
|
+
|
39
|
+
// Date and time formatting (using date-fns)
|
40
|
+
formatDate: (date, format) => window.dateFns?.format(date, format) || new Date(date).toISOString().split('T')[0],
|
41
|
+
formatTime: (date) => window.dateFns?.format(date, 'HH:mm:ss') || new Date(date).toTimeString().split(' ')[0],
|
42
|
+
|
43
|
+
// Collection utilities (using lodash)
|
44
|
+
isEmpty: (value) => window._ ? _.isEmpty(value) : (
|
45
|
+
Array.isArray(value) ? value.length === 0 :
|
46
|
+
typeof value === 'object' && value !== null ? Object.keys(value).length === 0 : !value
|
47
|
+
),
|
48
|
+
|
49
|
+
// Performance utilities (using lodash)
|
50
|
+
debounce: (fn, wait) => window._ ? _.debounce(fn, wait) : fn,
|
51
|
+
throttle: (fn, wait) => window._ ? _.throttle(fn, wait) : fn,
|
52
|
+
|
53
|
+
// ==========================================
|
54
|
+
// State management
|
55
|
+
// ==========================================
|
56
|
+
|
57
|
+
// Error handling with standardized pattern
|
58
|
+
handleError(error) {
|
59
|
+
this.error = error.message || "An unexpected error occurred";
|
60
|
+
console.error("Component error:", error);
|
61
|
+
|
62
|
+
// Dispatch error event for global tracking
|
63
|
+
if (this.$dispatch) {
|
64
|
+
this.$dispatch('dbwatcher:error', {
|
65
|
+
component: this.constructor.name,
|
66
|
+
error: this.error
|
67
|
+
});
|
68
|
+
}
|
69
|
+
},
|
70
|
+
|
71
|
+
// Clear error state
|
72
|
+
clearError() {
|
73
|
+
this.error = null;
|
74
|
+
},
|
75
|
+
|
76
|
+
// Loading state management
|
77
|
+
setLoading(loading) {
|
78
|
+
this.loading = loading;
|
79
|
+
|
80
|
+
// Dispatch loading state change event
|
81
|
+
if (this.$dispatch) {
|
82
|
+
this.$dispatch('dbwatcher:loading', { loading });
|
83
|
+
}
|
84
|
+
},
|
85
|
+
|
86
|
+
// ==========================================
|
87
|
+
// API integration (using ApiClient)
|
88
|
+
// ==========================================
|
89
|
+
|
90
|
+
// Fetch data with standardized error handling
|
91
|
+
async fetchData(endpoint, options = {}) {
|
92
|
+
this.setLoading(true);
|
93
|
+
this.clearError();
|
94
|
+
|
95
|
+
try {
|
96
|
+
// Use centralized API client if available
|
97
|
+
if (window.ApiClient) {
|
98
|
+
return await window.ApiClient.get(endpoint, options.params || {}, options);
|
99
|
+
}
|
100
|
+
|
101
|
+
// Fallback to standard fetch
|
102
|
+
const url = endpoint.startsWith('/') ? endpoint : `/dbwatcher/api/v1/${endpoint}`;
|
103
|
+
const response = await fetch(url, {
|
104
|
+
headers: {
|
105
|
+
'Content-Type': 'application/json',
|
106
|
+
'X-Requested-With': 'XMLHttpRequest',
|
107
|
+
...options.headers
|
108
|
+
},
|
109
|
+
...options
|
110
|
+
});
|
111
|
+
|
112
|
+
if (!response.ok) {
|
113
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
114
|
+
}
|
115
|
+
|
116
|
+
return await response.json();
|
117
|
+
} catch (error) {
|
118
|
+
this.handleError(error);
|
119
|
+
throw error;
|
120
|
+
} finally {
|
121
|
+
this.setLoading(false);
|
122
|
+
}
|
123
|
+
},
|
124
|
+
|
125
|
+
// ==========================================
|
126
|
+
// Event handling
|
127
|
+
// ==========================================
|
128
|
+
|
129
|
+
// Dispatch custom events
|
130
|
+
dispatchEvent(eventName, detail = {}) {
|
131
|
+
if (this.$dispatch) {
|
132
|
+
this.$dispatch(eventName, detail);
|
133
|
+
}
|
134
|
+
},
|
135
|
+
|
136
|
+
// Common UI helpers
|
137
|
+
toggleVisibility(property) {
|
138
|
+
this[property] = !this[property];
|
139
|
+
}
|
140
|
+
};
|
141
|
+
};
|