dbwatcher 1.0.0 → 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.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +81 -210
  3. data/app/assets/config/dbwatcher_manifest.js +15 -0
  4. data/app/assets/javascripts/dbwatcher/alpine_registrations.js +39 -0
  5. data/app/assets/javascripts/dbwatcher/auto_init.js +23 -0
  6. data/app/assets/javascripts/dbwatcher/components/base.js +141 -0
  7. data/app/assets/javascripts/dbwatcher/components/changes_table_hybrid.js +1008 -0
  8. data/app/assets/javascripts/dbwatcher/components/diagrams.js +449 -0
  9. data/app/assets/javascripts/dbwatcher/components/summary.js +234 -0
  10. data/app/assets/javascripts/dbwatcher/core/alpine_store.js +138 -0
  11. data/app/assets/javascripts/dbwatcher/core/api_client.js +162 -0
  12. data/app/assets/javascripts/dbwatcher/core/component_loader.js +70 -0
  13. data/app/assets/javascripts/dbwatcher/core/component_registry.js +94 -0
  14. data/app/assets/javascripts/dbwatcher/dbwatcher.js +120 -0
  15. data/app/assets/javascripts/dbwatcher/services/mermaid.js +315 -0
  16. data/app/assets/javascripts/dbwatcher/services/mermaid_service.js +199 -0
  17. data/app/assets/javascripts/dbwatcher/vendor/date-fns-browser.js +99 -0
  18. data/app/assets/javascripts/dbwatcher/vendor/lodash.min.js +140 -0
  19. data/app/assets/javascripts/dbwatcher/vendor/tabulator.min.js +3 -0
  20. data/app/assets/stylesheets/dbwatcher/application.css +423 -0
  21. data/app/assets/stylesheets/dbwatcher/application.scss +15 -0
  22. data/app/assets/stylesheets/dbwatcher/components/_badges.scss +38 -0
  23. data/app/assets/stylesheets/dbwatcher/components/_compact_table.scss +162 -0
  24. data/app/assets/stylesheets/dbwatcher/components/_diagrams.scss +51 -0
  25. data/app/assets/stylesheets/dbwatcher/components/_forms.scss +27 -0
  26. data/app/assets/stylesheets/dbwatcher/components/_navigation.scss +55 -0
  27. data/app/assets/stylesheets/dbwatcher/core/_base.scss +34 -0
  28. data/app/assets/stylesheets/dbwatcher/core/_variables.scss +47 -0
  29. data/app/assets/stylesheets/dbwatcher/vendor/tabulator.min.css +2 -0
  30. data/app/controllers/dbwatcher/api/v1/sessions_controller.rb +64 -0
  31. data/app/controllers/dbwatcher/base_controller.rb +8 -2
  32. data/app/controllers/dbwatcher/dashboard_controller.rb +8 -0
  33. data/app/controllers/dbwatcher/sessions_controller.rb +25 -10
  34. data/app/helpers/dbwatcher/component_helper.rb +29 -0
  35. data/app/helpers/dbwatcher/diagram_helper.rb +110 -0
  36. data/app/helpers/dbwatcher/session_helper.rb +3 -2
  37. data/app/views/dbwatcher/sessions/_changes_tab.html.erb +265 -0
  38. data/app/views/dbwatcher/sessions/_diagrams_tab.html.erb +166 -0
  39. data/app/views/dbwatcher/sessions/_session_header.html.erb +11 -0
  40. data/app/views/dbwatcher/sessions/_summary_tab.html.erb +88 -0
  41. data/app/views/dbwatcher/sessions/_tab_navigation.html.erb +12 -0
  42. data/app/views/dbwatcher/sessions/changes.html.erb +21 -0
  43. data/app/views/dbwatcher/sessions/components/changes/_filters.html.erb +44 -0
  44. data/app/views/dbwatcher/sessions/components/changes/_table_list.html.erb +96 -0
  45. data/app/views/dbwatcher/sessions/diagrams.html.erb +21 -0
  46. data/app/views/dbwatcher/sessions/index.html.erb +14 -10
  47. data/app/views/dbwatcher/sessions/shared/_layout.html.erb +8 -0
  48. data/app/views/dbwatcher/sessions/shared/_navigation.html.erb +35 -0
  49. data/app/views/dbwatcher/sessions/shared/_session_header.html.erb +25 -0
  50. data/app/views/dbwatcher/sessions/show.html.erb +3 -346
  51. data/app/views/dbwatcher/sessions/summary.html.erb +21 -0
  52. data/app/views/layouts/dbwatcher/application.html.erb +125 -247
  53. data/bin/compile_scss +49 -0
  54. data/config/routes.rb +26 -0
  55. data/lib/dbwatcher/configuration.rb +102 -8
  56. data/lib/dbwatcher/engine.rb +17 -7
  57. data/lib/dbwatcher/services/analyzers/session_data_processor.rb +98 -0
  58. data/lib/dbwatcher/services/analyzers/table_summary_builder.rb +202 -0
  59. data/lib/dbwatcher/services/api/base_api_service.rb +100 -0
  60. data/lib/dbwatcher/services/api/changes_data_service.rb +112 -0
  61. data/lib/dbwatcher/services/api/diagram_data_service.rb +145 -0
  62. data/lib/dbwatcher/services/api/summary_data_service.rb +158 -0
  63. data/lib/dbwatcher/services/base_service.rb +64 -0
  64. data/lib/dbwatcher/services/diagram_analyzers/base_analyzer.rb +162 -0
  65. data/lib/dbwatcher/services/diagram_analyzers/foreign_key_analyzer.rb +354 -0
  66. data/lib/dbwatcher/services/diagram_analyzers/inferred_relationship_analyzer.rb +502 -0
  67. data/lib/dbwatcher/services/diagram_analyzers/model_association_analyzer.rb +564 -0
  68. data/lib/dbwatcher/services/diagram_data/attribute.rb +154 -0
  69. data/lib/dbwatcher/services/diagram_data/dataset.rb +278 -0
  70. data/lib/dbwatcher/services/diagram_data/entity.rb +180 -0
  71. data/lib/dbwatcher/services/diagram_data/relationship.rb +188 -0
  72. data/lib/dbwatcher/services/diagram_data/relationship_params.rb +55 -0
  73. data/lib/dbwatcher/services/diagram_data.rb +65 -0
  74. data/lib/dbwatcher/services/diagram_error_handler.rb +239 -0
  75. data/lib/dbwatcher/services/diagram_generator.rb +154 -0
  76. data/lib/dbwatcher/services/diagram_strategies/base_diagram_strategy.rb +149 -0
  77. data/lib/dbwatcher/services/diagram_strategies/class_diagram_strategy.rb +49 -0
  78. data/lib/dbwatcher/services/diagram_strategies/erd_diagram_strategy.rb +52 -0
  79. data/lib/dbwatcher/services/diagram_strategies/flowchart_diagram_strategy.rb +52 -0
  80. data/lib/dbwatcher/services/diagram_system.rb +69 -0
  81. data/lib/dbwatcher/services/diagram_type_registry.rb +164 -0
  82. data/lib/dbwatcher/services/mermaid_syntax/base_builder.rb +127 -0
  83. data/lib/dbwatcher/services/mermaid_syntax/cardinality_mapper.rb +90 -0
  84. data/lib/dbwatcher/services/mermaid_syntax/class_diagram_builder.rb +136 -0
  85. data/lib/dbwatcher/services/mermaid_syntax/class_diagram_helper.rb +46 -0
  86. data/lib/dbwatcher/services/mermaid_syntax/erd_builder.rb +116 -0
  87. data/lib/dbwatcher/services/mermaid_syntax/flowchart_builder.rb +109 -0
  88. data/lib/dbwatcher/services/mermaid_syntax/sanitizer.rb +102 -0
  89. data/lib/dbwatcher/services/mermaid_syntax_builder.rb +155 -0
  90. data/lib/dbwatcher/storage/api/concerns/table_analyzer.rb +15 -128
  91. data/lib/dbwatcher/storage/api/session_api.rb +47 -0
  92. data/lib/dbwatcher/storage/base_storage.rb +7 -0
  93. data/lib/dbwatcher/version.rb +1 -1
  94. data/lib/dbwatcher.rb +58 -1
  95. metadata +94 -2
@@ -5,254 +5,87 @@
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1">
6
6
  <%= csrf_meta_tags %>
7
7
 
8
- <!-- Alpine.js -->
8
+ <!-- Alpine.js and Plugins - ensure plugins load BEFORE Alpine.js core -->
9
+ <script defer src="https://unpkg.com/@alpinejs/collapse@3.x.x/dist/cdn.min.js"></script>
9
10
  <script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
10
11
 
11
- <!-- Tailwind CSS -->
12
- <script src="https://cdn.tailwindcss.com"></script>
13
-
14
- <!-- Custom styles for compact theme -->
15
- <style>
16
- :root {
17
- --navy-dark: #00285D;
18
- --blue-light: #96C1E7;
19
- --blue-medium: #6CADDF;
20
- --gold-dark: #D4A11E;
21
- --gold-light: #FFC758;
22
- }
23
-
24
- /* Compact table styles */
25
- .compact-table {
26
- font-family: 'Consolas', 'Monaco', 'Lucida Console', monospace;
27
- font-size: 12px;
28
- line-height: 1.2;
29
- }
30
-
31
- .compact-table th {
32
- padding: 4px 8px;
33
- font-weight: 500;
34
- text-transform: none;
35
- font-size: 11px;
36
- background: #f3f3f3;
37
- border-bottom: 2px solid #e8e8e8;
38
- border-right: 1px solid #e8e8e8;
39
- position: sticky;
40
- top: 0;
41
- z-index: 10;
42
- }
43
-
44
- .compact-table td {
45
- padding: 2px 8px;
46
- border-right: 1px solid #f0f0f0;
47
- border-bottom: 1px solid #f0f0f0;
48
- max-width: 200px;
49
- overflow: hidden;
50
- text-overflow: ellipsis;
51
- white-space: nowrap;
52
- }
53
-
54
- .compact-table tr:hover {
55
- background: #f8f8f8;
56
- }
57
-
58
- .compact-table tr.selected {
59
- background: #e6f3ff;
60
- }
61
-
62
- /* Sidebar styles */
63
- .sidebar-item {
64
- font-size: 13px;
65
- padding: 6px 12px;
66
- display: flex;
67
- align-items: center;
68
- gap: 8px;
69
- border-radius: 3px;
70
- transition: all 0.15s;
71
- }
72
-
73
- .sidebar-item:hover {
74
- background: rgba(108, 173, 223, 0.1);
75
- color: #6CADDF;
76
- }
77
-
78
- .sidebar-item.active {
79
- background: #00285D;
80
- color: white;
81
- }
82
-
83
- /* Compact form controls */
84
- .compact-input {
85
- padding: 3px 8px;
86
- font-size: 12px;
87
- border: 1px solid #d1d5db;
88
- border-radius: 3px;
89
- }
90
-
91
- .compact-select {
92
- padding: 3px 24px 3px 8px;
93
- font-size: 12px;
94
- border: 1px solid #d1d5db;
95
- border-radius: 3px;
96
- background-size: 16px;
97
- }
98
-
99
- .compact-button {
100
- padding: 4px 12px;
101
- font-size: 12px;
102
- border-radius: 3px;
103
- font-weight: 500;
104
- }
105
-
106
- /* Tab styles */
107
- .tab-bar {
108
- background: #f3f3f3;
109
- border-bottom: 1px solid #e8e8e8;
110
- display: flex;
111
- align-items: center;
112
- height: 32px;
113
- font-size: 12px;
114
- }
115
-
116
- .tab-item {
117
- padding: 0 16px;
118
- height: 100%;
119
- display: flex;
120
- align-items: center;
121
- border-right: 1px solid #e8e8e8;
122
- cursor: pointer;
123
- transition: all 0.15s;
124
- }
125
-
126
- .tab-item:hover {
127
- background: #e8e8e8;
128
- }
129
-
130
- .tab-item.active {
131
- background: white;
132
- color: #00285D;
133
- font-weight: 500;
134
- }
135
-
136
- /* Status badges */
137
- .badge-insert { background: #10b981; color: white; }
138
- .badge-update { background: #6CADDF; color: white; }
139
- .badge-delete { background: #ef4444; color: white; }
140
- .badge-select { background: #6b7280; color: white; }
141
-
142
- .badge {
143
- padding: 1px 6px;
144
- font-size: 10px;
145
- border-radius: 2px;
146
- font-weight: 500;
147
- text-transform: uppercase;
148
- }
149
-
150
- /* Highlight colors */
151
- .highlight-change { background: rgba(255, 199, 88, 0.3); }
152
- .highlight-new { background: rgba(16, 185, 129, 0.2); }
153
- .highlight-deleted { background: rgba(239, 68, 68, 0.2); }
154
-
155
- /* Splitter */
156
- .splitter {
157
- width: 4px;
158
- background: #e8e8e8;
159
- cursor: col-resize;
160
- }
161
-
162
- .splitter:hover {
163
- background: #6CADDF;
164
- }
165
-
166
- /* Scrollbar styling */
167
- ::-webkit-scrollbar {
168
- width: 8px;
169
- height: 8px;
170
- }
171
-
172
- ::-webkit-scrollbar-track {
173
- background: #f3f3f3;
174
- }
175
-
176
- ::-webkit-scrollbar-thumb {
177
- background: #c8c8c8;
178
- border-radius: 4px;
179
- }
180
-
181
- ::-webkit-scrollbar-thumb:hover {
182
- background: #6CADDF;
183
- }
184
-
185
- /* Enhanced table styles for data readability */
186
- .table-detailed .compact-table td {
187
- max-width: 300px;
188
- padding: 4px 8px;
189
- }
190
-
191
- .cell-content {
192
- position: relative;
193
- display: inline-block;
194
- max-width: 100%;
195
- }
12
+ <!-- Mermaid.js for database diagrams -->
13
+ <script src="https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js" crossorigin="anonymous"></script>
196
14
 
197
- .cell-compact {
198
- max-width: 150px;
199
- overflow: hidden;
200
- text-overflow: ellipsis;
201
- white-space: nowrap;
202
- }
15
+ <!-- SVG Pan Zoom Library -->
16
+ <script src="https://cdn.jsdelivr.net/npm/svg-pan-zoom@3.6.1/dist/svg-pan-zoom.min.js"></script>
203
17
 
204
- .cell-detailed {
205
- max-width: 300px;
206
- white-space: pre-wrap;
207
- word-break: break-word;
208
- }
18
+ <!-- Tabulator.js for table library -->
19
+ <%= javascript_include_tag "dbwatcher/vendor/tabulator.min" %>
20
+ <%= stylesheet_link_tag "dbwatcher/vendor/tabulator.min", media: "all" %>
209
21
 
210
- .cell-value {
211
- cursor: help;
212
- }
22
+ <!-- DBWatcher Core Architecture -->
23
+ <%= javascript_include_tag "dbwatcher/vendor/lodash.min" %>
24
+ <%= javascript_include_tag "dbwatcher/vendor/date-fns-browser" %>
25
+ <%= javascript_include_tag "dbwatcher/dbwatcher" %>
26
+ <%= javascript_include_tag "dbwatcher/core/component_registry" %>
27
+ <%= javascript_include_tag "dbwatcher/core/component_loader" %>
28
+ <%= javascript_include_tag "dbwatcher/components/base" %>
29
+ <%= javascript_include_tag "dbwatcher/components/changes_table_hybrid" %>
30
+ <%= javascript_include_tag "dbwatcher/components/diagrams" %>
31
+ <%= javascript_include_tag "dbwatcher/components/summary" %>
213
32
 
214
- /* Column type styling */
215
- .column-meta {
216
- background-color: rgba(156, 163, 175, 0.1);
217
- }
33
+ <!-- DBWatcher Services -->
34
+ <%= javascript_include_tag "dbwatcher/core/alpine_store" %>
35
+ <%= javascript_include_tag "dbwatcher/core/api_client" %>
36
+ <%= javascript_include_tag "dbwatcher/services/mermaid" %>
218
37
 
219
- .column-timestamp {
220
- background-color: rgba(59, 130, 246, 0.1);
221
- font-family: monospace;
222
- }
38
+ <!-- Alpine.js Component Registrations -->
39
+ <%= javascript_include_tag "dbwatcher/alpine_registrations" %>
223
40
 
224
- .column-id {
225
- background-color: rgba(245, 158, 11, 0.1);
226
- font-family: monospace;
227
- }
41
+ <!-- Auto-initialization -->
42
+ <%= javascript_include_tag "dbwatcher/auto_init" %>
228
43
 
229
- /* Tooltip improvements */
230
- .tooltip-content {
231
- max-height: 200px;
232
- overflow-y: auto;
233
- font-family: 'Consolas', 'Monaco', 'Lucida Console', monospace;
234
- }
44
+ <script>
45
+ // Initialize DBWatcher before Alpine.js starts
46
+ document.addEventListener('alpine:init', () => {
47
+ try {
48
+ if (window.DBWatcher) {
49
+ DBWatcher.init();
50
+ console.log('✅ DBWatcher initialized with optimized architecture');
51
+ } else {
52
+ console.error('❌ DBWatcher not loaded');
53
+ }
54
+ } catch (error) {
55
+ console.error('❌ Error during DBWatcher initialization:', error);
56
+ }
57
+ });
235
58
 
236
- /* Essential mode adjustments */
237
- .view-essential .compact-table th,
238
- .view-essential .compact-table td {
239
- font-size: 11px;
240
- padding: 2px 6px;
241
- }
59
+ // Fallback initialization with better error handling
60
+ document.addEventListener('DOMContentLoaded', function() {
61
+ // Small delay to ensure Alpine is available
62
+ setTimeout(() => {
63
+ try {
64
+ if (window.DBWatcher && !DBWatcher.initialized) {
65
+ DBWatcher.init();
66
+ console.log('✅ DBWatcher initialized (fallback)');
67
+ }
68
+ } catch (error) {
69
+ console.error('❌ Error during DBWatcher fallback initialization:', error);
70
+ }
71
+ }, 100);
72
+
73
+ // Plugin verification
74
+ setTimeout(() => {
75
+ if (window.Alpine && !window.Alpine.directive('collapse')) {
76
+ console.warn('⚠️ Alpine.js Collapse plugin may not be properly loaded');
77
+ } else if (window.Alpine && window.Alpine.directive('collapse')) {
78
+ console.log('✅ Alpine.js Collapse plugin verified');
79
+ }
80
+ }, 200);
81
+ });
82
+ </script>
242
83
 
243
- /* JSON/Array content indicators */
244
- .json-indicator {
245
- color: #6366f1;
246
- font-style: italic;
247
- font-size: 10px;
248
- }
84
+ <!-- Tailwind CSS -->
85
+ <script src="https://cdn.tailwindcss.com"></script>
249
86
 
250
- .array-indicator {
251
- color: #059669;
252
- font-style: italic;
253
- font-size: 10px;
254
- }
255
- </style>
87
+ <!-- DBWatcher Styles -->
88
+ <%= stylesheet_link_tag 'dbwatcher/application.css', 'data-turbolinks-track': 'reload' %>
256
89
 
257
90
  <script>
258
91
  tailwind.config = {
@@ -331,7 +164,17 @@
331
164
 
332
165
  <!-- Actions -->
333
166
  <div class="p-2 border-t border-gray-700">
334
- <!-- TODO: Add more action later -->
167
+ <!-- Clear All Action -->
168
+ <%= button_to clear_all_path,
169
+ method: :delete,
170
+ data: { confirm: "Clear all data?" },
171
+ class: "sidebar-item w-full justify-center bg-red-900 hover:bg-red-800 text-red-200" do %>
172
+ <svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
173
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
174
+ d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
175
+ </svg>
176
+ <span x-show="!sidebarCollapsed" class="text-xs">Clear All</span>
177
+ <% end %>
335
178
  </div>
336
179
  </div>
337
180
  </aside>
@@ -365,17 +208,52 @@
365
208
  </main>
366
209
  </div>
367
210
 
211
+ <!-- Initialize DBWatcher system -->
368
212
  <script>
369
- mermaid.initialize({
370
- startOnLoad: true,
371
- theme: 'neutral',
372
- themeVariables: {
373
- primaryColor: '#00285D',
374
- primaryTextColor: '#fff',
375
- primaryBorderColor: '#6CADDF',
376
- lineColor: '#96C1E7',
377
- secondaryColor: '#FFC758',
378
- tertiaryColor: '#D4A11E'
213
+ document.addEventListener('DOMContentLoaded', function() {
214
+ // Initialize DBWatcher if available
215
+ if (window.DBWatcher) {
216
+ // Ensure BaseComponent is available
217
+ if (!window.DBWatcher.BaseComponent && typeof DBWatcher.BaseComponent !== 'function') {
218
+ window.DBWatcher.BaseComponent = function(config = {}) {
219
+ return {
220
+ init() {
221
+ if (this.componentInit) {
222
+ try {
223
+ this.componentInit();
224
+ } catch (error) {
225
+ console.error("Error during component initialization:", error);
226
+ }
227
+ }
228
+ }
229
+ };
230
+ };
231
+ console.log('Added fallback BaseComponent');
232
+ }
233
+
234
+ // Register legacy components with Alpine directly if ComponentRegistry isn't available
235
+ if (!window.DBWatcher.ComponentRegistry) {
236
+ console.log('ComponentRegistry not available, using direct Alpine registration');
237
+
238
+ // Ensure Alpine is available
239
+ if (window.Alpine) {
240
+ // Direct registration of components with Alpine
241
+ if (!window.Alpine.data('changesTable') && window.DBWatcher.components && window.DBWatcher.components.changesTable) {
242
+ window.Alpine.data('changesTable', (config = {}) => {
243
+ const component = window.DBWatcher.components.changesTable(config);
244
+ return component;
245
+ });
246
+ console.log('Registered changesTable component with Alpine');
247
+ }
248
+ }
249
+ }
250
+
251
+ console.log('✅ DBWatcher initialized (fallback)');
252
+ }
253
+
254
+ // Verify Alpine.js plugins
255
+ if (window.Alpine && window.Alpine.directive && window.Alpine.directive('collapse')) {
256
+ console.log('✅ Alpine.js Collapse plugin verified');
379
257
  }
380
258
  });
381
259
  </script>
data/bin/compile_scss ADDED
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Script to compile SCSS to CSS for DBWatcher
5
+
6
+ require 'rubygems'
7
+ require 'bundler/setup'
8
+ require 'sassc'
9
+ require 'fileutils'
10
+
11
+ # Get the root directory
12
+ root_dir = File.expand_path('..', __dir__)
13
+
14
+ # Path to the main SCSS file
15
+ scss_dir = File.join(root_dir, 'app', 'assets', 'stylesheets', 'dbwatcher')
16
+ scss_file = File.join(scss_dir, 'application.scss')
17
+ css_file = File.join(scss_dir, 'application.css')
18
+
19
+ puts "Compiling DBWatcher SCSS files to CSS..."
20
+ puts "SCSS file: #{scss_file}"
21
+ puts "CSS file: #{css_file}"
22
+
23
+ # Read the SCSS content
24
+ scss_content = File.read(scss_file)
25
+
26
+ # Create a list of import paths
27
+ load_paths = [scss_dir]
28
+
29
+ # Compile SCSS to CSS
30
+ begin
31
+ css_content = SassC::Engine.new(
32
+ scss_content,
33
+ style: :expanded,
34
+ load_paths: load_paths,
35
+ syntax: :scss
36
+ ).render
37
+
38
+ # Add a header comment
39
+ css_content = "/**\n * DBWatcher Application Styles\n * Compiled CSS for all components\n * Generated at #{Time.now}\n */\n\n" + css_content
40
+
41
+ # Write to file
42
+ File.write(css_file, css_content)
43
+
44
+ puts "SCSS compilation complete! CSS written to #{css_file}"
45
+ rescue => e
46
+ puts "Error compiling SCSS: #{e.message}"
47
+ puts e.backtrace.join("\n")
48
+ exit 1
49
+ end
data/config/routes.rb CHANGED
@@ -3,12 +3,38 @@
3
3
  Dbwatcher::Engine.routes.draw do
4
4
  root to: "dashboard#index"
5
5
 
6
+ # Dashboard clear all action
7
+ delete :clear_all, to: "dashboard#clear_all"
8
+
6
9
  resources :sessions do
10
+ member do
11
+ get :changes
12
+ get :summary
13
+ get :diagrams
14
+ end
15
+
7
16
  collection do
8
17
  delete :clear
9
18
  end
10
19
  end
11
20
 
21
+ # API namespace for JSON-only endpoints
22
+ namespace :api do
23
+ namespace :v1 do
24
+ resources :sessions, only: [] do
25
+ member do
26
+ get :changes_data
27
+ get :summary_data
28
+ get :diagram_data
29
+ end
30
+
31
+ collection do
32
+ get :diagram_types
33
+ end
34
+ end
35
+ end
36
+ end
37
+
12
38
  resources :tables, only: %i[index show] do
13
39
  member do
14
40
  get :changes
@@ -1,26 +1,78 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dbwatcher
4
+ # Configuration class for DBWatcher
5
+ #
6
+ # This class manages all configuration options for DBWatcher, including
7
+ # storage, tracking, and diagram visualization settings.
4
8
  class Configuration
5
- attr_accessor :storage_path, :enabled, :max_sessions, :auto_clean_after_days,
6
- :track_queries, :slow_query_threshold, :max_query_logs_per_day,
7
- :mount_path
9
+ # Storage configuration
10
+ attr_accessor :storage_path, :enabled, :max_sessions, :auto_clean_after_days
8
11
 
12
+ # Query tracking configuration
13
+ attr_accessor :track_queries, :slow_query_threshold, :max_query_logs_per_day
14
+
15
+ # Routing configuration
16
+ attr_accessor :mount_path
17
+
18
+ # Diagram configuration
19
+ attr_accessor :diagram_show_attributes, :diagram_show_methods, :diagram_show_cardinality,
20
+ :diagram_max_attributes, :diagram_attribute_types, :diagram_relationship_labels,
21
+ :diagram_preserve_table_case, :diagram_direction, :diagram_cardinality_format,
22
+ :diagram_show_attribute_count, :diagram_show_method_count
23
+
24
+ # Initialize with default values
9
25
  def initialize
26
+ # Storage configuration defaults
10
27
  @storage_path = default_storage_path
11
28
  @enabled = true
12
- @max_sessions = 100
29
+ @max_sessions = 50
13
30
  @auto_clean_after_days = 7
14
- @mount_path = "/dbwatcher"
15
31
 
16
- # SQL Query tracking
32
+ # Query tracking configuration defaults
17
33
  @track_queries = true
18
- @slow_query_threshold = 100.0 # milliseconds
19
- @max_query_logs_per_day = 10_000
34
+ @slow_query_threshold = 200 # milliseconds
35
+ @max_query_logs_per_day = 1000
36
+
37
+ # Routing configuration defaults
38
+ @mount_path = "/dbwatcher"
39
+
40
+ # Initialize diagram configuration with defaults
41
+ initialize_diagram_config
42
+ end
43
+
44
+ # Initialize diagram configuration with default values
45
+ def initialize_diagram_config
46
+ @diagram_show_attributes = true
47
+ @diagram_show_methods = false # Hide methods by default
48
+ @diagram_show_cardinality = true
49
+ @diagram_max_attributes = 10
50
+ @diagram_attribute_types = true # Changed from array to boolean
51
+ @diagram_relationship_labels = true # Changed from symbol to boolean
52
+ @diagram_preserve_table_case = false # Changed from true to false
53
+ @diagram_direction = "LR" # Left to right by default
54
+ @diagram_cardinality_format = :simple # Use simpler 1:N format
55
+ @diagram_show_attribute_count = true
56
+ @diagram_show_method_count = true
57
+ end
58
+
59
+ # Validate configuration
60
+ #
61
+ # @return [Boolean] true if configuration is valid
62
+ def valid?
63
+ validate_storage_path
64
+ validate_max_sessions
65
+ validate_auto_clean_after_days
66
+ validate_slow_query_threshold
67
+ validate_max_query_logs_per_day
68
+ true
20
69
  end
21
70
 
22
71
  private
23
72
 
73
+ # Default storage path based on Rails or current directory
74
+ #
75
+ # @return [String] default storage path
24
76
  def default_storage_path
25
77
  if defined?(Rails) && Rails.respond_to?(:root) && Rails.root
26
78
  Rails.root.join("tmp", "dbwatcher").to_s
@@ -28,5 +80,47 @@ module Dbwatcher
28
80
  File.join(Dir.pwd, "tmp", "dbwatcher")
29
81
  end
30
82
  end
83
+
84
+ # Validate storage path
85
+ def validate_storage_path
86
+ return if storage_path.nil? || Dir.exist?(storage_path)
87
+
88
+ begin
89
+ FileUtils.mkdir_p(storage_path)
90
+ rescue StandardError => e
91
+ raise ConfigurationError, "Failed to create storage path: #{e.message}"
92
+ end
93
+ end
94
+
95
+ # Validate max sessions
96
+ def validate_max_sessions
97
+ return if max_sessions.is_a?(Integer) && max_sessions.positive?
98
+
99
+ raise ConfigurationError, "max_sessions must be a positive integer"
100
+ end
101
+
102
+ # Validate auto clean after days
103
+ def validate_auto_clean_after_days
104
+ return if auto_clean_after_days.is_a?(Integer) && auto_clean_after_days.positive?
105
+
106
+ raise ConfigurationError, "auto_clean_after_days must be a positive integer"
107
+ end
108
+
109
+ # Validate slow query threshold
110
+ def validate_slow_query_threshold
111
+ return if slow_query_threshold.is_a?(Integer) && slow_query_threshold.positive?
112
+
113
+ raise ConfigurationError, "slow_query_threshold must be a positive integer"
114
+ end
115
+
116
+ # Validate max query logs per day
117
+ def validate_max_query_logs_per_day
118
+ return if max_query_logs_per_day.is_a?(Integer) && max_query_logs_per_day.positive?
119
+
120
+ raise ConfigurationError, "max_query_logs_per_day must be a positive integer"
121
+ end
31
122
  end
123
+
124
+ # Configuration error class
125
+ class ConfigurationError < StandardError; end
32
126
  end
@@ -4,8 +4,24 @@ module Dbwatcher
4
4
  class Engine < ::Rails::Engine
5
5
  isolate_namespace Dbwatcher
6
6
 
7
+ # Configure autoload paths
8
+ config.autoload_paths += %W[
9
+ #{root}/lib
10
+ ]
11
+
12
+ # Serve static assets
13
+ initializer "dbwatcher.assets", before: :add_to_load_path do |app|
14
+ # Define asset paths
15
+ app.config.assets.paths << root.join("app", "assets", "stylesheets")
16
+ app.config.assets.paths << root.join("app", "assets", "javascripts")
17
+ app.config.assets.paths << root.join("app", "assets", "config")
18
+
19
+ # Load engine's manifest file
20
+ app.config.assets.precompile << "dbwatcher_manifest.js"
21
+ end
22
+
7
23
  initializer "dbwatcher.setup" do |app|
8
- if Dbwatcher.configuration.enabled && !Rails.env.production?
24
+ if Dbwatcher.configuration.enabled
9
25
  # Auto-include in all models
10
26
  ActiveSupport.on_load(:active_record) do
11
27
  include Dbwatcher::ModelExtension
@@ -25,11 +41,5 @@ module Dbwatcher
25
41
  mount Dbwatcher::Engine => "/dbwatcher", as: :dbwatcher
26
42
  end
27
43
  end
28
-
29
- # Serve static assets
30
- initializer "dbwatcher.assets" do |app|
31
- app.config.assets.paths << root.join("app", "assets", "stylesheets")
32
- app.config.assets.paths << root.join("app", "assets", "javascripts")
33
- end
34
44
  end
35
45
  end