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
@@ -0,0 +1,138 @@
|
|
1
|
+
// Alpine.js Global Store for DBWatcher
|
2
|
+
// Provides centralized state management for sessions UI
|
3
|
+
|
4
|
+
document.addEventListener('alpine:init', () => {
|
5
|
+
Alpine.store('dbwatcher', {
|
6
|
+
// Session state
|
7
|
+
currentSession: null,
|
8
|
+
sessions: [],
|
9
|
+
|
10
|
+
// UI state
|
11
|
+
activeTab: 'changes',
|
12
|
+
loading: false,
|
13
|
+
error: null,
|
14
|
+
|
15
|
+
// Cache for API responses
|
16
|
+
cache: {
|
17
|
+
changes: new Map(),
|
18
|
+
summary: new Map(),
|
19
|
+
diagrams: new Map()
|
20
|
+
},
|
21
|
+
|
22
|
+
// Cache TTL in milliseconds (5 minutes)
|
23
|
+
cacheTtl: 5 * 60 * 1000,
|
24
|
+
|
25
|
+
// Initialize store
|
26
|
+
init() {
|
27
|
+
console.log('DBWatcher Alpine store initialized');
|
28
|
+
},
|
29
|
+
|
30
|
+
// Session management
|
31
|
+
setCurrentSession(session) {
|
32
|
+
this.currentSession = session;
|
33
|
+
},
|
34
|
+
|
35
|
+
// Tab navigation
|
36
|
+
setActiveTab(tab) {
|
37
|
+
this.activeTab = tab;
|
38
|
+
this.updateUrl(tab);
|
39
|
+
},
|
40
|
+
|
41
|
+
updateUrl(tab) {
|
42
|
+
if (typeof window !== 'undefined') {
|
43
|
+
const url = new URL(window.location);
|
44
|
+
url.searchParams.set('tab', tab);
|
45
|
+
window.history.pushState({}, '', url);
|
46
|
+
}
|
47
|
+
},
|
48
|
+
|
49
|
+
// Cache management
|
50
|
+
getCacheKey(type, sessionId, params = {}) {
|
51
|
+
const paramString = Object.keys(params)
|
52
|
+
.sort()
|
53
|
+
.map(key => `${key}=${params[key]}`)
|
54
|
+
.join('&');
|
55
|
+
return `${type}_${sessionId}_${paramString}`;
|
56
|
+
},
|
57
|
+
|
58
|
+
setCache(type, key, data) {
|
59
|
+
this.cache[type].set(key, {
|
60
|
+
data: data,
|
61
|
+
timestamp: Date.now()
|
62
|
+
});
|
63
|
+
},
|
64
|
+
|
65
|
+
getCache(type, key) {
|
66
|
+
const cached = this.cache[type].get(key);
|
67
|
+
if (!cached) return null;
|
68
|
+
|
69
|
+
// Check if cache is still valid
|
70
|
+
if (Date.now() - cached.timestamp > this.cacheTtl) {
|
71
|
+
this.cache[type].delete(key);
|
72
|
+
return null;
|
73
|
+
}
|
74
|
+
|
75
|
+
return cached.data;
|
76
|
+
},
|
77
|
+
|
78
|
+
clearCache(type = null) {
|
79
|
+
if (type) {
|
80
|
+
this.cache[type].clear();
|
81
|
+
} else {
|
82
|
+
Object.keys(this.cache).forEach(key => {
|
83
|
+
this.cache[key].clear();
|
84
|
+
});
|
85
|
+
}
|
86
|
+
},
|
87
|
+
|
88
|
+
// Error handling
|
89
|
+
setError(error) {
|
90
|
+
this.error = error;
|
91
|
+
console.error('DBWatcher error:', error);
|
92
|
+
},
|
93
|
+
|
94
|
+
clearError() {
|
95
|
+
this.error = null;
|
96
|
+
},
|
97
|
+
|
98
|
+
// Loading state
|
99
|
+
setLoading(loading) {
|
100
|
+
this.loading = loading;
|
101
|
+
}
|
102
|
+
});
|
103
|
+
});
|
104
|
+
|
105
|
+
// Session navigation component
|
106
|
+
function sessionNavigation(sessionId) {
|
107
|
+
return {
|
108
|
+
sessionId: sessionId,
|
109
|
+
|
110
|
+
init() {
|
111
|
+
// Set current session in store
|
112
|
+
Alpine.store('dbwatcher').setCurrentSession({ id: this.sessionId });
|
113
|
+
|
114
|
+
// Handle browser navigation
|
115
|
+
window.addEventListener('popstate', () => {
|
116
|
+
const params = new URLSearchParams(window.location.search);
|
117
|
+
const tab = params.get('tab') || 'changes';
|
118
|
+
Alpine.store('dbwatcher').setActiveTab(tab);
|
119
|
+
});
|
120
|
+
},
|
121
|
+
|
122
|
+
navigateToTab(tab) {
|
123
|
+
Alpine.store('dbwatcher').setActiveTab(tab);
|
124
|
+
},
|
125
|
+
|
126
|
+
get activeTab() {
|
127
|
+
return Alpine.store('dbwatcher').activeTab;
|
128
|
+
},
|
129
|
+
|
130
|
+
get loading() {
|
131
|
+
return Alpine.store('dbwatcher').loading;
|
132
|
+
},
|
133
|
+
|
134
|
+
get error() {
|
135
|
+
return Alpine.store('dbwatcher').error;
|
136
|
+
}
|
137
|
+
};
|
138
|
+
}
|
@@ -0,0 +1,162 @@
|
|
1
|
+
/**
|
2
|
+
* API Client for DBWatcher
|
3
|
+
*
|
4
|
+
* Centralized API communication with error handling,
|
5
|
+
* authentication, and response processing.
|
6
|
+
*/
|
7
|
+
|
8
|
+
const ApiClient = {
|
9
|
+
// Base configuration
|
10
|
+
baseURL: '/dbwatcher/api/v1',
|
11
|
+
timeout: 30000,
|
12
|
+
|
13
|
+
// Default headers
|
14
|
+
defaultHeaders: {
|
15
|
+
'Content-Type': 'application/json',
|
16
|
+
'Accept': 'application/json',
|
17
|
+
'X-Requested-With': 'XMLHttpRequest'
|
18
|
+
},
|
19
|
+
|
20
|
+
// Add CSRF token if available
|
21
|
+
getHeaders(additionalHeaders = {}) {
|
22
|
+
const headers = { ...this.defaultHeaders, ...additionalHeaders };
|
23
|
+
|
24
|
+
// Add CSRF token for Rails
|
25
|
+
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
26
|
+
if (csrfToken) {
|
27
|
+
headers['X-CSRF-Token'] = csrfToken;
|
28
|
+
}
|
29
|
+
|
30
|
+
return headers;
|
31
|
+
},
|
32
|
+
|
33
|
+
// Build full URL
|
34
|
+
buildURL(endpoint) {
|
35
|
+
if (endpoint.startsWith('http') || endpoint.startsWith('/')) {
|
36
|
+
return endpoint;
|
37
|
+
}
|
38
|
+
|
39
|
+
return `${this.baseURL}/${endpoint}`;
|
40
|
+
},
|
41
|
+
|
42
|
+
// Generic request method
|
43
|
+
async request(method, endpoint, options = {}) {
|
44
|
+
const {
|
45
|
+
body,
|
46
|
+
headers = {},
|
47
|
+
params = {},
|
48
|
+
timeout = this.timeout,
|
49
|
+
...fetchOptions
|
50
|
+
} = options;
|
51
|
+
|
52
|
+
const url = new URL(this.buildURL(endpoint), window.location.origin);
|
53
|
+
|
54
|
+
// Add query parameters
|
55
|
+
Object.entries(params).forEach(([key, value]) => {
|
56
|
+
if (value !== null && value !== undefined) {
|
57
|
+
url.searchParams.append(key, value);
|
58
|
+
}
|
59
|
+
});
|
60
|
+
|
61
|
+
const config = {
|
62
|
+
method,
|
63
|
+
headers: this.getHeaders(headers),
|
64
|
+
...fetchOptions
|
65
|
+
};
|
66
|
+
|
67
|
+
// Add body for non-GET requests
|
68
|
+
if (body && method !== 'GET') {
|
69
|
+
config.body = typeof body === 'string' ? body : JSON.stringify(body);
|
70
|
+
}
|
71
|
+
|
72
|
+
// Create timeout promise
|
73
|
+
const timeoutPromise = new Promise((_, reject) => {
|
74
|
+
setTimeout(() => reject(new Error('Request timeout')), timeout);
|
75
|
+
});
|
76
|
+
|
77
|
+
try {
|
78
|
+
const response = await Promise.race([
|
79
|
+
fetch(url, config),
|
80
|
+
timeoutPromise
|
81
|
+
]);
|
82
|
+
|
83
|
+
return await this.handleResponse(response);
|
84
|
+
} catch (error) {
|
85
|
+
return this.handleError(error);
|
86
|
+
}
|
87
|
+
},
|
88
|
+
|
89
|
+
// Handle response processing
|
90
|
+
async handleResponse(response) {
|
91
|
+
if (!response.ok) {
|
92
|
+
const error = new Error(`HTTP error ${response.status}: ${response.statusText}`);
|
93
|
+
error.status = response.status;
|
94
|
+
error.statusText = response.statusText;
|
95
|
+
|
96
|
+
try {
|
97
|
+
error.data = await response.json();
|
98
|
+
} catch (e) {
|
99
|
+
error.data = null;
|
100
|
+
}
|
101
|
+
|
102
|
+
throw error;
|
103
|
+
}
|
104
|
+
|
105
|
+
// Handle different content types
|
106
|
+
const contentType = response.headers.get('content-type');
|
107
|
+
|
108
|
+
if (contentType?.includes('application/json')) {
|
109
|
+
return await response.json();
|
110
|
+
} else if (contentType?.includes('text/')) {
|
111
|
+
return await response.text();
|
112
|
+
} else {
|
113
|
+
return response;
|
114
|
+
}
|
115
|
+
},
|
116
|
+
|
117
|
+
// Handle errors consistently
|
118
|
+
handleError(error) {
|
119
|
+
if (error.name === 'AbortError') {
|
120
|
+
console.error('Request aborted');
|
121
|
+
}
|
122
|
+
|
123
|
+
if (error.message === 'Request timeout') {
|
124
|
+
console.error('Request timeout');
|
125
|
+
}
|
126
|
+
|
127
|
+
if (error.status) {
|
128
|
+
console.error(`HTTP error: ${error.status} ${error.statusText}`);
|
129
|
+
}
|
130
|
+
|
131
|
+
throw error;
|
132
|
+
},
|
133
|
+
|
134
|
+
// Convenience methods
|
135
|
+
get(endpoint, params = {}, options = {}) {
|
136
|
+
return this.request('GET', endpoint, { params, ...options });
|
137
|
+
},
|
138
|
+
|
139
|
+
post(endpoint, body = {}, options = {}) {
|
140
|
+
return this.request('POST', endpoint, { body, ...options });
|
141
|
+
},
|
142
|
+
|
143
|
+
put(endpoint, body = {}, options = {}) {
|
144
|
+
return this.request('PUT', endpoint, { body, ...options });
|
145
|
+
},
|
146
|
+
|
147
|
+
patch(endpoint, body = {}, options = {}) {
|
148
|
+
return this.request('PATCH', endpoint, { body, ...options });
|
149
|
+
},
|
150
|
+
|
151
|
+
delete(endpoint, options = {}) {
|
152
|
+
return this.request('DELETE', endpoint, options);
|
153
|
+
}
|
154
|
+
};
|
155
|
+
|
156
|
+
// Register with DBWatcher if available
|
157
|
+
if (window.DBWatcher) {
|
158
|
+
window.DBWatcher.ApiClient = ApiClient;
|
159
|
+
}
|
160
|
+
|
161
|
+
// Make available globally
|
162
|
+
window.ApiClient = ApiClient;
|
@@ -0,0 +1,70 @@
|
|
1
|
+
/**
|
2
|
+
* DBWatcher Component Loader
|
3
|
+
* Handles component initialization and dependencies
|
4
|
+
*/
|
5
|
+
|
6
|
+
window.DBWatcher = window.DBWatcher || {};
|
7
|
+
|
8
|
+
DBWatcher.ComponentLoader = {
|
9
|
+
// Track loaded components to prevent duplicates
|
10
|
+
loadedComponents: new Set(),
|
11
|
+
|
12
|
+
// Map of component dependencies
|
13
|
+
componentDependencies: {
|
14
|
+
'diagrams': ['mermaid_service'],
|
15
|
+
'changes_table': [],
|
16
|
+
'summary': []
|
17
|
+
},
|
18
|
+
|
19
|
+
// Load a component and its dependencies
|
20
|
+
async load(componentName) {
|
21
|
+
if (this.loadedComponents.has(componentName)) {
|
22
|
+
console.log(`Component ${componentName} already loaded`);
|
23
|
+
return true;
|
24
|
+
}
|
25
|
+
|
26
|
+
// Check for dependencies
|
27
|
+
const dependencies = this.componentDependencies[componentName] || [];
|
28
|
+
|
29
|
+
// Load dependencies first
|
30
|
+
for (const dependency of dependencies) {
|
31
|
+
await this.load(dependency);
|
32
|
+
}
|
33
|
+
|
34
|
+
// Mark as loaded
|
35
|
+
this.loadedComponents.add(componentName);
|
36
|
+
console.log(`Loaded component: ${componentName}`);
|
37
|
+
return true;
|
38
|
+
},
|
39
|
+
|
40
|
+
// Initialize the component system
|
41
|
+
init(config = {}) {
|
42
|
+
// Setup auto-loading for Alpine.js components
|
43
|
+
document.addEventListener('alpine:init', () => {
|
44
|
+
// Register loader directive for on-demand loading
|
45
|
+
window.Alpine.directive('dbcomponent', (el, { value, expression }, { evaluate }) => {
|
46
|
+
const componentName = evaluate(expression);
|
47
|
+
this.load(componentName).then(() => {
|
48
|
+
console.log(`Component ${componentName} loaded via directive`);
|
49
|
+
});
|
50
|
+
});
|
51
|
+
|
52
|
+
// Auto-load components from data attributes
|
53
|
+
document.querySelectorAll('[data-component]').forEach(el => {
|
54
|
+
const componentName = el.dataset.component;
|
55
|
+
if (componentName) {
|
56
|
+
this.load(componentName);
|
57
|
+
}
|
58
|
+
});
|
59
|
+
});
|
60
|
+
|
61
|
+
return this;
|
62
|
+
}
|
63
|
+
};
|
64
|
+
|
65
|
+
// Auto-init if DBWatcher is available
|
66
|
+
if (window.DBWatcher && window.DBWatcher.init) {
|
67
|
+
document.addEventListener('DOMContentLoaded', () => {
|
68
|
+
DBWatcher.ComponentLoader.init();
|
69
|
+
});
|
70
|
+
}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
/**
|
2
|
+
* DBWatcher Component Registry
|
3
|
+
* Centralized system for component registration, initialization, and lifecycle management
|
4
|
+
*/
|
5
|
+
|
6
|
+
// Component Registry - Single source of truth for all components
|
7
|
+
window.DBWatcher = window.DBWatcher || {};
|
8
|
+
DBWatcher.ComponentRegistry = {
|
9
|
+
// Component storage
|
10
|
+
_components: {},
|
11
|
+
|
12
|
+
// Default configuration that applies to all components
|
13
|
+
defaultConfig: {
|
14
|
+
debugMode: false
|
15
|
+
},
|
16
|
+
|
17
|
+
// Register a component
|
18
|
+
register(name, factory) {
|
19
|
+
if (!name || typeof name !== 'string') {
|
20
|
+
console.error('Component name must be a non-empty string');
|
21
|
+
return false;
|
22
|
+
}
|
23
|
+
|
24
|
+
if (typeof factory !== 'function') {
|
25
|
+
console.error(`Component factory for '${name}' must be a function`);
|
26
|
+
return false;
|
27
|
+
}
|
28
|
+
|
29
|
+
this._components[name] = factory;
|
30
|
+
|
31
|
+
// Also store in DBWatcher.components for backward compatibility
|
32
|
+
if (window.DBWatcher) {
|
33
|
+
window.DBWatcher.components = window.DBWatcher.components || {};
|
34
|
+
window.DBWatcher.components[name] = factory;
|
35
|
+
}
|
36
|
+
|
37
|
+
// Auto-register with Alpine if available
|
38
|
+
if (window.Alpine && window.Alpine.data) {
|
39
|
+
this._registerWithAlpine(name, factory);
|
40
|
+
}
|
41
|
+
|
42
|
+
return true;
|
43
|
+
},
|
44
|
+
|
45
|
+
// Get component factory by name
|
46
|
+
get(name) {
|
47
|
+
return this._components[name] || null;
|
48
|
+
},
|
49
|
+
|
50
|
+
// Initialize all components
|
51
|
+
initAll(globalConfig = {}) {
|
52
|
+
if (!window.Alpine) {
|
53
|
+
console.warn('Alpine.js not found, components will not be initialized');
|
54
|
+
return;
|
55
|
+
}
|
56
|
+
|
57
|
+
// Register all components with Alpine
|
58
|
+
Object.keys(this._components).forEach(name => {
|
59
|
+
this._registerWithAlpine(name, this._components[name], globalConfig);
|
60
|
+
});
|
61
|
+
|
62
|
+
console.log(`Initialized ${Object.keys(this._components).length} components`);
|
63
|
+
},
|
64
|
+
|
65
|
+
// Private: Register component with Alpine.js
|
66
|
+
_registerWithAlpine(name, factory, globalConfig = {}) {
|
67
|
+
// Safety check
|
68
|
+
if (!window.Alpine || !window.Alpine.data) return;
|
69
|
+
|
70
|
+
try {
|
71
|
+
// Create Alpine data function that wraps our component factory
|
72
|
+
window.Alpine.data(name, (config = {}) => {
|
73
|
+
// Merge global config, default config, and instance config
|
74
|
+
const mergedConfig = {
|
75
|
+
...this.defaultConfig,
|
76
|
+
...globalConfig,
|
77
|
+
...config
|
78
|
+
};
|
79
|
+
|
80
|
+
// Create component instance
|
81
|
+
return factory(mergedConfig);
|
82
|
+
});
|
83
|
+
|
84
|
+
console.log(`✅ Registered ${name} with Alpine.js`);
|
85
|
+
} catch (error) {
|
86
|
+
console.error(`Failed to register ${name} with Alpine.js:`, error);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
};
|
90
|
+
|
91
|
+
// Export for module systems
|
92
|
+
if (typeof module !== 'undefined' && module.exports) {
|
93
|
+
module.exports = DBWatcher.ComponentRegistry;
|
94
|
+
}
|
@@ -0,0 +1,120 @@
|
|
1
|
+
/**
|
2
|
+
* DBWatcher - Main Entry Point
|
3
|
+
* Single entry point for the entire library with auto-binding functionality
|
4
|
+
* Version 2.0.0 - Optimized architecture
|
5
|
+
*/
|
6
|
+
window.DBWatcher = {
|
7
|
+
// Basic information
|
8
|
+
version: "2.0.0",
|
9
|
+
initialized: false,
|
10
|
+
debug: false,
|
11
|
+
|
12
|
+
// Dependencies and configuration
|
13
|
+
dependencies: {
|
14
|
+
required: ['alpine', 'alpine-collapse'],
|
15
|
+
optional: ['lodash', 'dateFns', 'mermaid', 'svgPanZoom']
|
16
|
+
},
|
17
|
+
|
18
|
+
// Component registry - will be initialized from core/component_registry.js
|
19
|
+
ComponentRegistry: null,
|
20
|
+
|
21
|
+
// Base Component - will be initialized from components/base.js
|
22
|
+
BaseComponent: null,
|
23
|
+
|
24
|
+
// Initialize the entire system
|
25
|
+
init(config = {}) {
|
26
|
+
if (this.initialized) {
|
27
|
+
console.warn('DBWatcher already initialized');
|
28
|
+
return this;
|
29
|
+
}
|
30
|
+
|
31
|
+
// Set debug mode
|
32
|
+
this.debug = config.debug || false;
|
33
|
+
|
34
|
+
// Validate dependencies
|
35
|
+
this._validateDependencies();
|
36
|
+
|
37
|
+
// Ensure critical parts are loaded
|
38
|
+
if (!this.ComponentRegistry) {
|
39
|
+
console.error('ComponentRegistry not loaded! Make sure core/component_registry.js is included before initialization.');
|
40
|
+
return this;
|
41
|
+
}
|
42
|
+
|
43
|
+
// Initialize component registry with global config
|
44
|
+
this.ComponentRegistry.initAll(config);
|
45
|
+
|
46
|
+
// Mark as initialized
|
47
|
+
this.initialized = true;
|
48
|
+
console.log(`DBWatcher ${this.version} initialized`);
|
49
|
+
|
50
|
+
// Setup auto-initialization for Alpine
|
51
|
+
document.addEventListener('alpine:initialized', () => {
|
52
|
+
console.log('Alpine.js initialized, binding components...');
|
53
|
+
this.ComponentRegistry.initAll(config);
|
54
|
+
});
|
55
|
+
|
56
|
+
return this;
|
57
|
+
},
|
58
|
+
|
59
|
+
// Shorthand for component registration
|
60
|
+
register(name, factory) {
|
61
|
+
if (this.ComponentRegistry) {
|
62
|
+
return this.ComponentRegistry.register(name, factory);
|
63
|
+
} else {
|
64
|
+
console.error('Cannot register component: ComponentRegistry not loaded');
|
65
|
+
return false;
|
66
|
+
}
|
67
|
+
},
|
68
|
+
|
69
|
+
// Validate that required dependencies are loaded
|
70
|
+
_validateDependencies() {
|
71
|
+
const missing = [];
|
72
|
+
|
73
|
+
// Check for Alpine.js
|
74
|
+
if (!window.Alpine) {
|
75
|
+
missing.push('Alpine.js');
|
76
|
+
} else if (!window.Alpine.directive('collapse')) {
|
77
|
+
missing.push('Alpine.js collapse plugin');
|
78
|
+
}
|
79
|
+
|
80
|
+
// Log warnings for missing dependencies
|
81
|
+
if (missing.length > 0) {
|
82
|
+
console.warn(`DBWatcher missing dependencies: ${missing.join(', ')}`);
|
83
|
+
}
|
84
|
+
|
85
|
+
return missing.length === 0;
|
86
|
+
},
|
87
|
+
|
88
|
+
// Create a new component instance
|
89
|
+
createComponent(name, config = {}) {
|
90
|
+
if (!this.ComponentRegistry) {
|
91
|
+
console.error('ComponentRegistry not loaded');
|
92
|
+
return null;
|
93
|
+
}
|
94
|
+
|
95
|
+
const factory = this.ComponentRegistry.get(name);
|
96
|
+
if (!factory) {
|
97
|
+
console.error(`Component '${name}' not registered`);
|
98
|
+
return null;
|
99
|
+
}
|
100
|
+
|
101
|
+
return factory(config);
|
102
|
+
},
|
103
|
+
|
104
|
+
// Register a component using the ComponentRegistry
|
105
|
+
register(name, factory) {
|
106
|
+
if (!this.ComponentRegistry) {
|
107
|
+
console.error('ComponentRegistry not loaded');
|
108
|
+
return false;
|
109
|
+
}
|
110
|
+
return this.ComponentRegistry.register(name, factory);
|
111
|
+
},
|
112
|
+
|
113
|
+
// Legacy support for old API
|
114
|
+
registerComponent(name, factory) {
|
115
|
+
return this.register(name, factory);
|
116
|
+
},
|
117
|
+
|
118
|
+
// Maintain compatibility with existing components
|
119
|
+
components: {}
|
120
|
+
};
|