dbwatcher 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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 +603 -0
- data/lib/dbwatcher/services/diagram_data/attribute.rb +154 -0
- data/lib/dbwatcher/services/diagram_data/dataset.rb +280 -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 +140 -0
- data/lib/dbwatcher/services/mermaid_syntax/class_diagram_helper.rb +48 -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 +118 -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,55 @@
|
|
1
|
+
/**
|
2
|
+
* Navigation Styles
|
3
|
+
* Sidebar, tabs, and navigation controls
|
4
|
+
*/
|
5
|
+
|
6
|
+
/* Sidebar styles */
|
7
|
+
.sidebar-item {
|
8
|
+
font-size: 13px;
|
9
|
+
padding: 6px 12px;
|
10
|
+
display: flex;
|
11
|
+
align-items: center;
|
12
|
+
gap: 8px;
|
13
|
+
border-radius: 3px;
|
14
|
+
transition: all 0.15s;
|
15
|
+
}
|
16
|
+
|
17
|
+
.sidebar-item:hover {
|
18
|
+
background: rgba(108, 173, 223, 0.1);
|
19
|
+
color: var(--blue-medium);
|
20
|
+
}
|
21
|
+
|
22
|
+
.sidebar-item.active {
|
23
|
+
background: var(--navy-dark);
|
24
|
+
color: white;
|
25
|
+
}
|
26
|
+
|
27
|
+
/* Tab styles */
|
28
|
+
.tab-bar {
|
29
|
+
background: var(--gray-100);
|
30
|
+
border-bottom: 1px solid var(--border-medium);
|
31
|
+
display: flex;
|
32
|
+
align-items: center;
|
33
|
+
height: 32px;
|
34
|
+
font-size: 12px;
|
35
|
+
}
|
36
|
+
|
37
|
+
.tab-item {
|
38
|
+
padding: 0 16px;
|
39
|
+
height: 100%;
|
40
|
+
display: flex;
|
41
|
+
align-items: center;
|
42
|
+
border-right: 1px solid var(--border-medium);
|
43
|
+
cursor: pointer;
|
44
|
+
transition: all 0.15s;
|
45
|
+
}
|
46
|
+
|
47
|
+
.tab-item:hover {
|
48
|
+
background: var(--border-medium);
|
49
|
+
}
|
50
|
+
|
51
|
+
.tab-item.active {
|
52
|
+
background: white;
|
53
|
+
color: var(--navy-dark);
|
54
|
+
font-weight: 500;
|
55
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
/**
|
2
|
+
* Base Styles
|
3
|
+
* Scrollbars, splitters, and utility styles
|
4
|
+
*/
|
5
|
+
|
6
|
+
/* Splitter */
|
7
|
+
.splitter {
|
8
|
+
width: 4px;
|
9
|
+
background: var(--border-medium);
|
10
|
+
cursor: col-resize;
|
11
|
+
}
|
12
|
+
|
13
|
+
.splitter:hover {
|
14
|
+
background: var(--blue-medium);
|
15
|
+
}
|
16
|
+
|
17
|
+
/* Scrollbar styling */
|
18
|
+
::-webkit-scrollbar {
|
19
|
+
width: 8px;
|
20
|
+
height: 8px;
|
21
|
+
}
|
22
|
+
|
23
|
+
::-webkit-scrollbar-track {
|
24
|
+
background: var(--gray-100);
|
25
|
+
}
|
26
|
+
|
27
|
+
::-webkit-scrollbar-thumb {
|
28
|
+
background: var(--gray-400);
|
29
|
+
border-radius: 4px;
|
30
|
+
}
|
31
|
+
|
32
|
+
::-webkit-scrollbar-thumb:hover {
|
33
|
+
background: var(--blue-medium);
|
34
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
/**
|
2
|
+
* DBWatcher CSS Variables
|
3
|
+
* Core color scheme and layout dimensions
|
4
|
+
*/
|
5
|
+
|
6
|
+
:root {
|
7
|
+
/* Brand colors */
|
8
|
+
--navy-dark: #00285D;
|
9
|
+
--blue-light: #96C1E7;
|
10
|
+
--blue-medium: #6CADDF;
|
11
|
+
--gold-dark: #D4A11E;
|
12
|
+
--gold-light: #FFC758;
|
13
|
+
|
14
|
+
/* Layout dimensions for diagram container */
|
15
|
+
--header-height: 64px;
|
16
|
+
--tab-bar-height: 32px;
|
17
|
+
--toolbar-height: 56px;
|
18
|
+
--footer-height: 0px;
|
19
|
+
|
20
|
+
/* Gray scale */
|
21
|
+
--gray-50: #f9fafb;
|
22
|
+
--gray-100: #f3f3f3;
|
23
|
+
--gray-200: #e8e8e8;
|
24
|
+
--gray-300: #d1d5db;
|
25
|
+
--gray-400: #c8c8c8;
|
26
|
+
--gray-500: #6b7280;
|
27
|
+
--gray-600: #4b5563;
|
28
|
+
--gray-700: #374151;
|
29
|
+
--gray-800: #1f2937;
|
30
|
+
--gray-900: #111827;
|
31
|
+
|
32
|
+
/* Border colors */
|
33
|
+
--border-light: #f0f0f0;
|
34
|
+
--border-medium: #e8e8e8;
|
35
|
+
--border-dark: #d1d5db;
|
36
|
+
|
37
|
+
/* Status colors */
|
38
|
+
--status-insert: #10b981;
|
39
|
+
--status-update: #6CADDF;
|
40
|
+
--status-delete: #ef4444;
|
41
|
+
--status-select: #6b7280;
|
42
|
+
|
43
|
+
/* Highlight colors */
|
44
|
+
--highlight-change: rgba(255, 199, 88, 0.3);
|
45
|
+
--highlight-new: rgba(16, 185, 129, 0.2);
|
46
|
+
--highlight-deleted: rgba(239, 68, 68, 0.2);
|
47
|
+
}
|
@@ -0,0 +1,2 @@
|
|
1
|
+
.tabulator{background-color:#888;border:1px solid #999;font-size:14px;overflow:hidden;position:relative;text-align:left;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}.tabulator[tabulator-layout=fitDataFill] .tabulator-tableholder .tabulator-table{min-width:100%}.tabulator[tabulator-layout=fitDataTable]{display:inline-block}.tabulator.tabulator-block-select,.tabulator.tabulator-ranges .tabulator-cell:not(.tabulator-editing){user-select:none}.tabulator .tabulator-header{background-color:#e6e6e6;border-bottom:1px solid #999;box-sizing:border-box;color:#555;font-weight:700;outline:none;overflow:hidden;position:relative;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;white-space:nowrap;width:100%}.tabulator .tabulator-header.tabulator-header-hidden{display:none}.tabulator .tabulator-header .tabulator-header-contents{overflow:hidden;position:relative}.tabulator .tabulator-header .tabulator-header-contents .tabulator-headers{display:inline-block}.tabulator .tabulator-header .tabulator-col{background:#e6e6e6;border-right:1px solid #aaa;box-sizing:border-box;display:inline-flex;flex-direction:column;justify-content:flex-start;overflow:hidden;position:relative;text-align:left;vertical-align:bottom}.tabulator .tabulator-header .tabulator-col.tabulator-moving{background:#cdcdcd;border:1px solid #999;pointer-events:none;position:absolute}.tabulator .tabulator-header .tabulator-col.tabulator-range-highlight{background-color:#d6d6d6;color:#000}.tabulator .tabulator-header .tabulator-col.tabulator-range-selected{background-color:#3876ca;color:#fff}.tabulator .tabulator-header .tabulator-col .tabulator-col-content{box-sizing:border-box;padding:4px;position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button{padding:0 8px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button:hover{cursor:pointer;opacity:.6}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title-holder{position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title{box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap;width:100%}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title.tabulator-col-title-wrap{text-overflow:clip;white-space:normal}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-title-editor{background:#fff;border:1px solid #999;box-sizing:border-box;padding:1px;width:100%}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-header-popup-button+.tabulator-title-editor{width:calc(100% - 22px)}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{align-items:center;bottom:0;display:flex;position:absolute;right:4px;top:0}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-bottom:6px solid #bbb;border-left:6px solid transparent;border-right:6px solid transparent;height:0;width:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{border-top:1px solid #aaa;display:flex;margin-right:-1px;overflow:hidden;position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter{box-sizing:border-box;margin-top:2px;position:relative;text-align:center;width:100%}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter textarea{height:auto!important}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter svg{margin-top:3px}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter input::-ms-clear{height:0;width:0}.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-right:25px}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover{background-color:#cdcdcd;cursor:pointer}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter{color:#bbb}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{border-bottom:6px solid #555;cursor:pointer}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-bottom:6px solid #bbb;border-top:none}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter{color:#666}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{border-bottom:6px solid #555;cursor:pointer}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-bottom:6px solid #666;border-top:none}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter{color:#666}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{border-top:6px solid #555;cursor:pointer}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-bottom:none;border-top:6px solid #666;color:#666}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical .tabulator-col-content .tabulator-col-title{align-items:center;display:flex;justify-content:center;text-orientation:mixed;writing-mode:vertical-rl}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-col-vertical-flip .tabulator-col-title{transform:rotate(180deg)}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-title{padding-right:0;padding-top:20px}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-vertical-flip .tabulator-col-title{padding-bottom:20px;padding-right:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-sorter{bottom:auto;justify-content:center;left:0;right:0;top:4px}.tabulator .tabulator-header .tabulator-frozen{left:0;position:sticky;z-index:11}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left{border-right:2px solid #aaa}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-right{border-left:2px solid #aaa}.tabulator .tabulator-header .tabulator-calcs-holder{background:#f3f3f3!important;border-bottom:1px solid #aaa;border-top:1px solid #aaa;box-sizing:border-box;display:inline-block}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row{background:#f3f3f3!important}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-header .tabulator-frozen-rows-holder{display:inline-block}.tabulator .tabulator-header .tabulator-frozen-rows-holder:empty{display:none}.tabulator .tabulator-tableholder{-webkit-overflow-scrolling:touch;overflow:auto;position:relative;white-space:nowrap;width:100%}.tabulator .tabulator-tableholder:focus{outline:none}.tabulator .tabulator-tableholder .tabulator-placeholder{align-items:center;box-sizing:border-box;display:flex;justify-content:center;min-width:100%;width:100%}.tabulator .tabulator-tableholder .tabulator-placeholder[tabulator-render-mode=virtual]{min-height:100%}.tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents{color:#ccc;display:inline-block;font-size:20px;font-weight:700;padding:10px;text-align:center;white-space:normal}.tabulator .tabulator-tableholder .tabulator-table{background-color:#fff;color:#333;display:inline-block;overflow:visible;position:relative;white-space:nowrap}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs{background:#e2e2e2!important;font-weight:700}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-top{border-bottom:2px solid #aaa}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-bottom{border-top:2px solid #aaa}.tabulator .tabulator-tableholder .tabulator-range-overlay{inset:0;pointer-events:none;position:absolute;z-index:10}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range{border:1px solid #2975dd;box-sizing:border-box;position:absolute}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active:after{background-color:#2975dd;border-radius:999px;bottom:-3px;content:"";height:6px;position:absolute;right:-3px;width:6px}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range-cell-active{border:2px solid #2975dd;box-sizing:border-box;position:absolute}.tabulator .tabulator-footer{background-color:#e6e6e6;border-top:1px solid #999;color:#555;font-weight:700;user-select:none;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;white-space:nowrap}.tabulator .tabulator-footer .tabulator-footer-contents{align-items:center;display:flex;flex-direction:row;justify-content:space-between;padding:5px 10px}.tabulator .tabulator-footer .tabulator-footer-contents:empty{display:none}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs{margin-top:-5px;overflow-x:auto}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab{border:1px solid #999;border-bottom-left-radius:5px;border-bottom-right-radius:5px;border-top:none;display:inline-block;font-size:.9em;padding:5px}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab:hover{cursor:pointer;opacity:.7}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab.tabulator-spreadsheet-tab-active{background:#fff}.tabulator .tabulator-footer .tabulator-calcs-holder{background:#f3f3f3!important;border-bottom:1px solid #aaa;border-top:1px solid #aaa;box-sizing:border-box;overflow:hidden;text-align:left;width:100%}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row{background:#f3f3f3!important;display:inline-block}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-footer .tabulator-calcs-holder:only-child{border-bottom:none;margin-bottom:-5px}.tabulator .tabulator-footer>*+.tabulator-page-counter{margin-left:10px}.tabulator .tabulator-footer .tabulator-page-counter{font-weight:400}.tabulator .tabulator-footer .tabulator-paginator{color:#555;flex:1;font-family:inherit;font-size:inherit;font-weight:inherit;text-align:right}.tabulator .tabulator-footer .tabulator-page-size{border:1px solid #aaa;border-radius:3px;display:inline-block;margin:0 5px;padding:2px 5px}.tabulator .tabulator-footer .tabulator-pages{margin:0 7px}.tabulator .tabulator-footer .tabulator-page{background:hsla(0,0%,100%,.2);border:1px solid #aaa;border-radius:3px;display:inline-block;margin:0 2px;padding:2px 5px}.tabulator .tabulator-footer .tabulator-page.active{color:#d00}.tabulator .tabulator-footer .tabulator-page:disabled{opacity:.5}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-footer .tabulator-page:not(disabled):hover{background:rgba(0,0,0,.2);color:#fff;cursor:pointer}}.tabulator .tabulator-col-resize-handle{display:inline-block;margin-left:-3px;margin-right:-3px;position:relative;vertical-align:middle;width:6px;z-index:11}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-col-resize-handle:hover{cursor:ew-resize}}.tabulator .tabulator-col-resize-handle:last-of-type{margin-right:0;width:3px}.tabulator .tabulator-col-resize-guide{background-color:#999;height:100%;margin-left:-.5px;opacity:.5;position:absolute;top:0;width:4px}.tabulator .tabulator-row-resize-guide{background-color:#999;height:4px;left:0;margin-top:-.5px;opacity:.5;position:absolute;width:100%}.tabulator .tabulator-alert{align-items:center;background:rgba(0,0,0,.4);display:flex;height:100%;left:0;position:absolute;text-align:center;top:0;width:100%;z-index:100}.tabulator .tabulator-alert .tabulator-alert-msg{background:#fff;border-radius:10px;display:inline-block;font-size:16px;font-weight:700;margin:0 auto;padding:10px 20px}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg{border:4px solid #333;color:#000}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error{border:4px solid #d00;color:#590000}.tabulator-row{background-color:#fff;box-sizing:border-box;min-height:22px;position:relative}.tabulator-row.tabulator-row-even{background-color:#efefef}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selectable:hover{background-color:#bbb;cursor:pointer}}.tabulator-row.tabulator-selected{background-color:#9abcea}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selected:hover{background-color:#769bcc;cursor:pointer}}.tabulator-row.tabulator-row-moving{background:#fff;border:1px solid #000}.tabulator-row.tabulator-moving{border-bottom:1px solid #aaa;border-top:1px solid #aaa;pointer-events:none;position:absolute;z-index:15}.tabulator-row.tabulator-range-highlight .tabulator-cell.tabulator-range-row-header{background-color:#d6d6d6;color:#000}.tabulator-row.tabulator-range-highlight.tabulator-range-selected .tabulator-cell.tabulator-range-row-header,.tabulator-row.tabulator-range-selected .tabulator-cell.tabulator-range-row-header{background-color:#3876ca;color:#fff}.tabulator-row .tabulator-row-resize-handle{bottom:0;height:5px;left:0;position:absolute;right:0}.tabulator-row .tabulator-row-resize-handle.prev{bottom:auto;top:0}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-row-resize-handle:hover{cursor:ns-resize}}.tabulator-row .tabulator-responsive-collapse{border-bottom:1px solid #aaa;border-top:1px solid #aaa;box-sizing:border-box;padding:5px}.tabulator-row .tabulator-responsive-collapse:empty{display:none}.tabulator-row .tabulator-responsive-collapse table{font-size:14px}.tabulator-row .tabulator-responsive-collapse table tr td{position:relative}.tabulator-row .tabulator-responsive-collapse table tr td:first-of-type{padding-right:10px}.tabulator-row .tabulator-cell{border-right:1px solid #aaa;box-sizing:border-box;display:inline-block;outline:none;overflow:hidden;padding:4px;position:relative;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap}.tabulator-row .tabulator-cell.tabulator-row-header{background:#e6e6e6;border-bottom:1px solid #aaa;border-right:1px solid #999}.tabulator-row .tabulator-cell.tabulator-frozen{background-color:inherit;display:inline-block;left:0;position:sticky;z-index:11}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-right:2px solid #aaa}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-left:2px solid #aaa}.tabulator-row .tabulator-cell.tabulator-editing{border:1px solid #1d68cd;outline:none;padding:0}.tabulator-row .tabulator-cell.tabulator-editing input,.tabulator-row .tabulator-cell.tabulator-editing select{background:transparent;border:1px;outline:none}.tabulator-row .tabulator-cell.tabulator-validation-fail{border:1px solid #d00}.tabulator-row .tabulator-cell.tabulator-validation-fail input,.tabulator-row .tabulator-cell.tabulator-validation-fail select{background:transparent;border:1px;color:#d00}.tabulator-row .tabulator-cell.tabulator-row-handle{align-items:center;display:inline-flex;justify-content:center;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box{width:80%}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box .tabulator-row-handle-bar{background:#666;height:3px;margin-top:2px;width:100%}.tabulator-row .tabulator-cell.tabulator-range-selected:not(.tabulator-range-only-cell-selected):not(.tabulator-range-row-header){background-color:#9abcea}.tabulator-row .tabulator-cell .tabulator-data-tree-branch-empty{display:inline-block;width:7px}.tabulator-row .tabulator-cell .tabulator-data-tree-branch{border-bottom:2px solid #aaa;border-bottom-left-radius:1px;border-left:2px solid #aaa;display:inline-block;height:9px;margin-right:5px;margin-top:-9px;vertical-align:middle;width:7px}.tabulator-row .tabulator-cell .tabulator-data-tree-control{align-items:center;background:rgba(0,0,0,.1);border:1px solid #333;border-radius:2px;display:inline-flex;height:11px;justify-content:center;margin-right:5px;overflow:hidden;vertical-align:middle;width:11px}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-cell .tabulator-data-tree-control:hover{background:rgba(0,0,0,.2);cursor:pointer}}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse{background:transparent;display:inline-block;height:7px;position:relative;width:1px}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{background:#333;content:"";height:1px;left:-3px;position:absolute;top:3px;width:7px}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand{background:#333;display:inline-block;height:7px;position:relative;width:1px}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{background:#333;content:"";height:1px;left:-3px;position:absolute;top:3px;width:7px}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle{align-items:center;background:#666;border-radius:20px;color:#fff;display:inline-flex;font-size:1.1em;font-weight:700;height:15px;justify-content:center;-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;width:15px}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle:hover{cursor:pointer;opacity:.7}}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-close{display:initial}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-open{display:none}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle svg{stroke:#fff}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle .tabulator-responsive-collapse-toggle-close{display:none}.tabulator-row .tabulator-cell .tabulator-traffic-light{border-radius:14px;display:inline-block;height:14px;width:14px}.tabulator-row.tabulator-group{background:#ccc;border-bottom:1px solid #999;border-right:1px solid #aaa;border-top:1px solid #999;box-sizing:border-box;font-weight:700;min-width:100%;padding:5px 5px 5px 10px}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-group:hover{background-color:rgba(0,0,0,.1);cursor:pointer}}.tabulator-row.tabulator-group.tabulator-group-visible .tabulator-arrow{border-bottom:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #666;margin-right:10px}.tabulator-row.tabulator-group.tabulator-group-level-1{padding-left:30px}.tabulator-row.tabulator-group.tabulator-group-level-2{padding-left:50px}.tabulator-row.tabulator-group.tabulator-group-level-3{padding-left:70px}.tabulator-row.tabulator-group.tabulator-group-level-4{padding-left:90px}.tabulator-row.tabulator-group.tabulator-group-level-5{padding-left:110px}.tabulator-row.tabulator-group .tabulator-group-toggle{display:inline-block}.tabulator-row.tabulator-group .tabulator-arrow{border-bottom:6px solid transparent;border-left:6px solid #666;border-right:0;border-top:6px solid transparent;display:inline-block;height:0;margin-right:16px;vertical-align:middle;width:0}.tabulator-row.tabulator-group span{color:#d00;margin-left:10px}.tabulator-toggle{background:#dcdcdc;border:1px solid #ccc;box-sizing:border-box;display:flex;flex-direction:row}.tabulator-toggle.tabulator-toggle-on{background:#1c6cc2}.tabulator-toggle .tabulator-toggle-switch{background:#fff;border:1px solid #ccc;box-sizing:border-box}.tabulator-popup-container{-webkit-overflow-scrolling:touch;background:#fff;border:1px solid #aaa;box-shadow:0 0 5px 0 rgba(0,0,0,.2);box-sizing:border-box;display:inline-block;font-size:14px;overflow-y:auto;position:absolute;z-index:10000}.tabulator-popup{border-radius:3px;padding:5px}.tabulator-tooltip{border-radius:2px;box-shadow:none;font-size:12px;max-width:Min(500px,100%);padding:3px 5px;pointer-events:none}.tabulator-menu .tabulator-menu-item{box-sizing:border-box;padding:5px 10px;position:relative;user-select:none}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-disabled{opacity:.5}@media (hover:hover) and (pointer:fine){.tabulator-menu .tabulator-menu-item:not(.tabulator-menu-item-disabled):hover{background:#efefef;cursor:pointer}}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu{padding-right:25px}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu:after{border-color:#aaa;border-style:solid;border-width:1px 1px 0 0;content:"";display:inline-block;height:7px;position:absolute;right:10px;top:calc(5px + .4em);transform:rotate(45deg);vertical-align:top;width:7px}.tabulator-menu .tabulator-menu-separator{border-top:1px solid #aaa}.tabulator-edit-list{-webkit-overflow-scrolling:touch;font-size:14px;max-height:200px;overflow-y:auto}.tabulator-edit-list .tabulator-edit-list-item{color:#333;outline:none;padding:4px}.tabulator-edit-list .tabulator-edit-list-item.active{background:#1d68cd;color:#fff}.tabulator-edit-list .tabulator-edit-list-item.active.focused{outline:1px solid hsla(0,0%,100%,.5)}.tabulator-edit-list .tabulator-edit-list-item.focused{outline:1px solid #1d68cd}@media (hover:hover) and (pointer:fine){.tabulator-edit-list .tabulator-edit-list-item:hover{background:#1d68cd;color:#fff;cursor:pointer}}.tabulator-edit-list .tabulator-edit-list-placeholder{color:#333;padding:4px;text-align:center}.tabulator-edit-list .tabulator-edit-list-group{border-bottom:1px solid #aaa;color:#333;font-weight:700;padding:6px 4px 4px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-2,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-2{padding-left:12px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-3,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-3{padding-left:20px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-4,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-4{padding-left:28px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-5,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-5{padding-left:36px}.tabulator.tabulator-ltr{direction:ltr}.tabulator.tabulator-rtl{direction:rtl;text-align:initial}.tabulator.tabulator-rtl .tabulator-header .tabulator-col{border-left:1px solid #aaa;border-right:initial;text-align:initial}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{margin-left:-1px;margin-right:0}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-left:25px;padding-right:0}.tabulator.tabulator-rtl .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{left:8px;right:auto}.tabulator.tabulator-rtl .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active:after{background-color:#2975dd;border-radius:999px;bottom:-3px;content:"";height:6px;left:-3px;position:absolute;right:auto;width:6px}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell{border-left:1px solid #aaa;border-right:initial}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-branch{border-bottom-left-radius:0;border-bottom-right-radius:1px;border-left:initial;border-right:2px solid #aaa;margin-left:5px;margin-right:0}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-control{margin-left:5px;margin-right:0}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-left:2px solid #aaa}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-right:2px solid #aaa}.tabulator.tabulator-rtl .tabulator-row .tabulator-col-resize-handle:last-of-type{margin-left:0;margin-right:-3px;width:3px}.tabulator.tabulator-rtl .tabulator-footer .tabulator-calcs-holder{text-align:initial}.tabulator-print-fullscreen{bottom:0;left:0;position:absolute;right:0;top:0;z-index:10000}body.tabulator-print-fullscreen-hide>:not(.tabulator-print-fullscreen){display:none!important}.tabulator-print-table{border-collapse:collapse}.tabulator-print-table .tabulator-data-tree-branch{border-bottom:2px solid #aaa;border-bottom-left-radius:1px;border-left:2px solid #aaa;display:inline-block;height:9px;margin-right:5px;margin-top:-9px;vertical-align:middle;width:7px}.tabulator-print-table .tabulator-print-table-group{background:#ccc;border-bottom:1px solid #999;border-right:1px solid #aaa;border-top:1px solid #999;box-sizing:border-box;font-weight:700;min-width:100%;padding:5px 5px 5px 10px}@media (hover:hover) and (pointer:fine){.tabulator-print-table .tabulator-print-table-group:hover{background-color:rgba(0,0,0,.1);cursor:pointer}}.tabulator-print-table .tabulator-print-table-group.tabulator-group-visible .tabulator-arrow{border-bottom:0;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #666;margin-right:10px}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-1 td{padding-left:30px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-2 td{padding-left:50px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-3 td{padding-left:70px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-4 td{padding-left:90px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-5 td{padding-left:110px!important}.tabulator-print-table .tabulator-print-table-group .tabulator-group-toggle{display:inline-block}.tabulator-print-table .tabulator-print-table-group .tabulator-arrow{border-bottom:6px solid transparent;border-left:6px solid #666;border-right:0;border-top:6px solid transparent;display:inline-block;height:0;margin-right:16px;vertical-align:middle;width:0}.tabulator-print-table .tabulator-print-table-group span{color:#d00;margin-left:10px}.tabulator-print-table .tabulator-data-tree-control{align-items:center;background:rgba(0,0,0,.1);border:1px solid #333;border-radius:2px;display:inline-flex;height:11px;justify-content:center;margin-right:5px;overflow:hidden;vertical-align:middle;width:11px}@media (hover:hover) and (pointer:fine){.tabulator-print-table .tabulator-data-tree-control:hover{background:rgba(0,0,0,.2);cursor:pointer}}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse{background:transparent;display:inline-block;height:7px;position:relative;width:1px}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{background:#333;content:"";height:1px;left:-3px;position:absolute;top:3px;width:7px}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand{background:#333;display:inline-block;height:7px;position:relative;width:1px}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{background:#333;content:"";height:1px;left:-3px;position:absolute;top:3px;width:7px}
|
2
|
+
/*# sourceMappingURL=tabulator.min.css.map */
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dbwatcher
|
4
|
+
module Api
|
5
|
+
module V1
|
6
|
+
class SessionsController < BaseController
|
7
|
+
before_action :find_session, except: [:diagram_types]
|
8
|
+
|
9
|
+
def changes_data
|
10
|
+
Rails.logger.info "API::V1::SessionsController#changes_data: Getting changes for session #{@session.id}"
|
11
|
+
|
12
|
+
# Paginated, filtered changes data
|
13
|
+
# Convert ActionController::Parameters to a hash before passing to service
|
14
|
+
service = Dbwatcher::Services::Api::ChangesDataService.new(@session, filter_params.to_h)
|
15
|
+
render json: service.call
|
16
|
+
end
|
17
|
+
|
18
|
+
def summary_data
|
19
|
+
Rails.logger.info "API::V1::SessionsController#summary_data: Getting summary for session #{@session.id}"
|
20
|
+
|
21
|
+
# Aggregated summary statistics
|
22
|
+
service = Dbwatcher::Services::Api::SummaryDataService.new(@session)
|
23
|
+
render json: service.call
|
24
|
+
end
|
25
|
+
|
26
|
+
def diagram_data
|
27
|
+
Rails.logger.info "API::V1::SessionsController#diagram_data: Getting diagram for session #{@session.id}"
|
28
|
+
|
29
|
+
# Generated diagram content with caching
|
30
|
+
# Convert ActionController::Parameters to a hash before passing to service
|
31
|
+
diagram_params = params.to_unsafe_h
|
32
|
+
service = Dbwatcher::Services::Api::DiagramDataService.new(@session, params[:type], diagram_params)
|
33
|
+
result = service.call
|
34
|
+
|
35
|
+
if result[:error]
|
36
|
+
render json: { error: result[:error] }, status: :unprocessable_entity
|
37
|
+
else
|
38
|
+
render json: result
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def diagram_types
|
43
|
+
Rails.logger.info "API::V1::SessionsController#diagram_types: Getting available diagram types"
|
44
|
+
|
45
|
+
render json: {
|
46
|
+
types: Dbwatcher::Services::Api::DiagramDataService.available_types_with_metadata,
|
47
|
+
default_type: "database_tables"
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def find_session
|
54
|
+
@session = Storage.sessions.find(params[:id])
|
55
|
+
render json: { error: "Session not found" }, status: :not_found unless @session
|
56
|
+
end
|
57
|
+
|
58
|
+
def filter_params
|
59
|
+
params.permit(:table, :operation, :page, :per_page)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -13,6 +13,11 @@ module Dbwatcher
|
|
13
13
|
# Common error handling
|
14
14
|
rescue_from StandardError, with: :handle_error
|
15
15
|
|
16
|
+
# Include helpers
|
17
|
+
helper Dbwatcher::ApplicationHelper
|
18
|
+
helper Dbwatcher::FormattingHelper
|
19
|
+
helper Dbwatcher::DiagramHelper if defined?(Dbwatcher::DiagramHelper)
|
20
|
+
|
16
21
|
protected
|
17
22
|
|
18
23
|
# Set current time for consistent timestamp usage across views
|
@@ -35,7 +40,8 @@ module Dbwatcher
|
|
35
40
|
respond_to do |format|
|
36
41
|
format.html do
|
37
42
|
flash[:error] = "An error occurred while processing your request."
|
38
|
-
|
43
|
+
# Avoid infinite redirect by using main app root or request referer
|
44
|
+
redirect_to(request.referer || main_app.root_path)
|
39
45
|
end
|
40
46
|
format.json do
|
41
47
|
render json: { error: "Internal server error" }, status: :internal_server_error
|
@@ -54,7 +60,7 @@ module Dbwatcher
|
|
54
60
|
def format_timestamp(timestamp_str)
|
55
61
|
return "N/A" unless timestamp_str
|
56
62
|
|
57
|
-
Time.parse(timestamp_str).strftime("%H:%M:%S")
|
63
|
+
Time.parse(timestamp_str).strftime("%Y-%m-%d %H:%M:%S")
|
58
64
|
rescue ArgumentError
|
59
65
|
"N/A"
|
60
66
|
end
|
@@ -8,5 +8,13 @@ module Dbwatcher
|
|
8
8
|
@active_tables = dashboard_data[:active_tables]
|
9
9
|
@query_stats = dashboard_data[:query_stats]
|
10
10
|
end
|
11
|
+
|
12
|
+
def clear_all
|
13
|
+
clear_storage_with_message(
|
14
|
+
-> { Storage.clear_all },
|
15
|
+
"All sessions and SQL logs",
|
16
|
+
root_path
|
17
|
+
)
|
18
|
+
end
|
11
19
|
end
|
12
20
|
end
|
@@ -2,24 +2,29 @@
|
|
2
2
|
|
3
3
|
module Dbwatcher
|
4
4
|
class SessionsController < BaseController
|
5
|
+
before_action :find_session, except: [:index]
|
6
|
+
|
5
7
|
def index
|
6
8
|
@sessions = Storage.sessions.all
|
7
9
|
end
|
8
10
|
|
9
11
|
def show
|
10
|
-
|
11
|
-
|
12
|
-
Rails.logger.info "SessionsController#show: Loaded session: #{@session.inspect}"
|
12
|
+
redirect_to changes_session_path(@session.id)
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
+
def changes
|
16
|
+
Rails.logger.info "SessionsController#changes: Loading changes for session #{@session.id}"
|
17
|
+
# No server-side data processing - API-first architecture
|
18
|
+
end
|
15
19
|
|
16
|
-
|
17
|
-
Rails.logger.info "SessionsController#
|
20
|
+
def summary
|
21
|
+
Rails.logger.info "SessionsController#summary: Loading summary for session #{@session.id}"
|
22
|
+
# No server-side data processing - API-first architecture
|
23
|
+
end
|
18
24
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
25
|
+
def diagrams
|
26
|
+
Rails.logger.info "SessionsController#diagrams: Loading diagrams for session #{@session.id}"
|
27
|
+
# No server-side data processing - API-first architecture
|
23
28
|
end
|
24
29
|
|
25
30
|
def clear
|
@@ -29,5 +34,15 @@ module Dbwatcher
|
|
29
34
|
sessions_path
|
30
35
|
)
|
31
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def find_session
|
41
|
+
@session = Storage.sessions.find(params[:id])
|
42
|
+
handle_not_found("Session", sessions_path) unless @session
|
43
|
+
end
|
44
|
+
|
45
|
+
# No longer needed with API-first architecture
|
46
|
+
# All data processing happens in API services and is loaded via JavaScript
|
32
47
|
end
|
33
48
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dbwatcher
|
4
|
+
module ComponentHelper
|
5
|
+
# Removed as part of API-first migration (Story 6.8)
|
6
|
+
# All data is now loaded directly from API endpoints
|
7
|
+
|
8
|
+
# Removed as part of API-first migration (Story 6.8)
|
9
|
+
# All data is now loaded directly from API endpoints
|
10
|
+
|
11
|
+
# Removed as part of API-first migration (Story 6.8)
|
12
|
+
# All data is now loaded directly from API endpoints
|
13
|
+
|
14
|
+
# Generate data attributes for component binding
|
15
|
+
def dbwatcher_component(component_name, config)
|
16
|
+
{
|
17
|
+
"data-dbwatcher" => component_name,
|
18
|
+
"data-config" => config.to_json
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Helper to render a DBWatcher component
|
23
|
+
def render_dbwatcher_component(component_name, config, html_options = {})
|
24
|
+
content_tag :div, dbwatcher_component(component_name, config).merge(html_options) do
|
25
|
+
yield if block_given?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dbwatcher
|
4
|
+
module DiagramHelper
|
5
|
+
# Generate diagram configuration for Alpine.js
|
6
|
+
def diagram_config(session, active_tab)
|
7
|
+
{
|
8
|
+
auto_generate: active_tab == "diagrams",
|
9
|
+
default_type: "database_tables",
|
10
|
+
endpoint: diagram_data_api_v1_session_path(session),
|
11
|
+
container_id: "diagram-container"
|
12
|
+
}.to_json
|
13
|
+
end
|
14
|
+
|
15
|
+
# Generate diagram type options dynamically from registry
|
16
|
+
def diagram_type_options
|
17
|
+
registry = Dbwatcher::Services::DiagramTypeRegistry.new
|
18
|
+
options = registry.available_types_with_metadata.map do |type, metadata|
|
19
|
+
[metadata[:display_name], type]
|
20
|
+
end
|
21
|
+
|
22
|
+
options_for_select(options)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Generate CSS variables for diagram container height calculation
|
26
|
+
def diagram_container_css_variables
|
27
|
+
{
|
28
|
+
"--header-height": "64px",
|
29
|
+
"--tab-bar-height": "40px",
|
30
|
+
"--toolbar-height": "72px",
|
31
|
+
"--footer-height": "0px",
|
32
|
+
"--diagram-height": "calc(100vh - var(--header-height) - var(--tab-bar-height) - " \
|
33
|
+
"var(--toolbar-height) - var(--footer-height) - 2rem)",
|
34
|
+
"--diagram-min-height": "500px"
|
35
|
+
}.map { |key, value| "#{key}: #{value}" }.join("; ")
|
36
|
+
end
|
37
|
+
|
38
|
+
# Generate button classes for diagram controls
|
39
|
+
def diagram_button_classes(type = :default)
|
40
|
+
base_classes = "compact-button text-xs rounded"
|
41
|
+
|
42
|
+
button_styles = {
|
43
|
+
primary: "bg-blue-medium text-white px-3 py-1 hover:bg-navy-dark",
|
44
|
+
secondary: "bg-navy-dark text-white px-2 py-1 hover:bg-blue-medium",
|
45
|
+
toggle: "bg-blue-medium text-white px-2 py-1 hover:bg-navy-dark flex items-center gap-1",
|
46
|
+
icon: "bg-white border border-gray-300 hover:bg-gray-50 p-1",
|
47
|
+
danger: "bg-red-500 text-white px-2 py-1 hover:bg-red-600",
|
48
|
+
success: "bg-green-500 text-white px-2 py-1 hover:bg-green-600"
|
49
|
+
}
|
50
|
+
|
51
|
+
style = button_styles[type] || button_styles[:primary]
|
52
|
+
"#{base_classes} #{style}"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Generate a code view with syntax highlighting for Mermaid code
|
56
|
+
def diagram_code_view(content)
|
57
|
+
content_tag(:div, class: "diagram-code-view") do
|
58
|
+
content_tag(:pre,
|
59
|
+
class: "text-xs font-mono p-4 bg-gray-50 rounded border border-gray-200 " \
|
60
|
+
"overflow-x-auto whitespace-pre-wrap",
|
61
|
+
style: "max-height: calc(100vh - 220px); overflow-y: auto;") do
|
62
|
+
content_tag(:code, content)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Generate copy to clipboard button
|
68
|
+
def copy_to_clipboard_button(target_id)
|
69
|
+
button_tag(
|
70
|
+
type: "button",
|
71
|
+
class: diagram_button_classes(:icon),
|
72
|
+
"x-on:click": "copyToClipboard('#{target_id}')",
|
73
|
+
title: "Copy to clipboard"
|
74
|
+
) do
|
75
|
+
copy_icon_svg
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Generate copy icon SVG
|
82
|
+
def copy_icon_svg
|
83
|
+
content_tag(:svg, class: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24") do
|
84
|
+
tag.path(
|
85
|
+
stroke_linecap: "round",
|
86
|
+
stroke_linejoin: "round",
|
87
|
+
stroke_width: "2",
|
88
|
+
d: "M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2" \
|
89
|
+
"M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"
|
90
|
+
)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Generate toggle view button
|
95
|
+
def toggle_view_button
|
96
|
+
button_tag(
|
97
|
+
type: "button",
|
98
|
+
class: diagram_button_classes(:toggle),
|
99
|
+
"x-on:click": "toggleViewMode()",
|
100
|
+
title: "Toggle between code and preview"
|
101
|
+
) do
|
102
|
+
concat(content_tag(:svg, class: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24") do
|
103
|
+
tag.path(stroke_linecap: "round", stroke_linejoin: "round", stroke_width: "2",
|
104
|
+
d: "M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4")
|
105
|
+
end)
|
106
|
+
concat(content_tag(:span, "x-text": "viewMode === 'preview' ? 'View Code' : 'View Preview'"))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -17,11 +17,12 @@ module Dbwatcher
|
|
17
17
|
name.to_s.gsub(/^HTTP \w+ /, "")
|
18
18
|
end
|
19
19
|
|
20
|
-
# Generate session ID display (
|
20
|
+
# Generate session ID display (wider format)
|
21
21
|
def display_session_id(id)
|
22
22
|
return "N/A" unless id
|
23
23
|
|
24
|
-
|
24
|
+
# Show more characters of the session ID for better readability
|
25
|
+
"#{id[0..15]}..."
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|