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.
- 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 +8 -2
- data/app/controllers/dbwatcher/dashboard_controller.rb +8 -0
- data/app/controllers/dbwatcher/sessions_controller.rb +25 -10
- data/app/helpers/dbwatcher/component_helper.rb +29 -0
- data/app/helpers/dbwatcher/diagram_helper.rb +110 -0
- data/app/helpers/dbwatcher/session_helper.rb +3 -2
- 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 +14 -10
- 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 -346
- data/app/views/dbwatcher/sessions/summary.html.erb +21 -0
- data/app/views/layouts/dbwatcher/application.html.erb +125 -247
- data/bin/compile_scss +49 -0
- data/config/routes.rb +26 -0
- data/lib/dbwatcher/configuration.rb +102 -8
- data/lib/dbwatcher/engine.rb +17 -7
- 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/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/storage/api/concerns/table_analyzer.rb +15 -128
- data/lib/dbwatcher/storage/api/session_api.rb +47 -0
- data/lib/dbwatcher/storage/base_storage.rb +7 -0
- data/lib/dbwatcher/version.rb +1 -1
- data/lib/dbwatcher.rb +58 -1
- 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
|
-
<!--
|
12
|
-
<script src="https://cdn.
|
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
|
-
|
198
|
-
|
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
|
-
|
205
|
-
|
206
|
-
|
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
|
-
|
211
|
-
|
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
|
-
|
215
|
-
|
216
|
-
|
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
|
-
|
220
|
-
|
221
|
-
font-family: monospace;
|
222
|
-
}
|
38
|
+
<!-- Alpine.js Component Registrations -->
|
39
|
+
<%= javascript_include_tag "dbwatcher/alpine_registrations" %>
|
223
40
|
|
224
|
-
|
225
|
-
|
226
|
-
font-family: monospace;
|
227
|
-
}
|
41
|
+
<!-- Auto-initialization -->
|
42
|
+
<%= javascript_include_tag "dbwatcher/auto_init" %>
|
228
43
|
|
229
|
-
|
230
|
-
.
|
231
|
-
|
232
|
-
|
233
|
-
|
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
|
-
|
237
|
-
.
|
238
|
-
|
239
|
-
|
240
|
-
|
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
|
-
|
244
|
-
|
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
|
-
|
251
|
-
|
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
|
-
<!--
|
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
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
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
|
-
|
6
|
-
|
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 =
|
29
|
+
@max_sessions = 50
|
13
30
|
@auto_clean_after_days = 7
|
14
|
-
@mount_path = "/dbwatcher"
|
15
31
|
|
16
|
-
#
|
32
|
+
# Query tracking configuration defaults
|
17
33
|
@track_queries = true
|
18
|
-
@slow_query_threshold =
|
19
|
-
@max_query_logs_per_day =
|
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
|
data/lib/dbwatcher/engine.rb
CHANGED
@@ -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
|
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
|