dbviewer 0.9.2 → 0.9.3
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/app/assets/javascripts/dbviewer/layout.js +0 -5
- data/app/assets/stylesheets/dbviewer/table.css +11 -4
- data/app/helpers/dbviewer/datatable_ui_table_helper.rb +1 -1
- data/app/views/dbviewer/entity_relationship_diagrams/index.html.erb +2 -2
- data/app/views/dbviewer/logs/index.html.erb +0 -21
- data/app/views/dbviewer/tables/query.html.erb +3 -3
- data/app/views/dbviewer/tables/show.html.erb +13 -9
- data/lib/dbviewer/pii_configuration.rb +28 -0
- data/lib/dbviewer/version.rb +1 -1
- data/lib/dbviewer.rb +2 -27
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5835c049d579e6371f436079045d591582d15a007854de4e9fd8927f1f7f735
|
4
|
+
data.tar.gz: 119938578d1692bf4195069d6957e531704d991fe24f498683c124ad838ae64e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba52d4e64b255e6ff36d185704c679a8480aad2ef0e02793c58b714ee78e3646848db8039ba8cbd778768c2d330705c9a66f4691638e47f73a1c942fb70466b3
|
7
|
+
data.tar.gz: 8c9456585431b06ca68e56f4e91d603185e7637915b51f495add7452ea6bf4feb00880334b443939beb4c802d2a8cd94063fec6f781c2dbb26174e38d671c44a
|
@@ -24,7 +24,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
|
24
24
|
}
|
25
25
|
|
26
26
|
const toggleBtn = document.querySelector(".dbviewer-sidebar-toggle");
|
27
|
-
const closeBtn = document.querySelector(".dbviewer-sidebar-close");
|
28
27
|
const sidebar = document.querySelector(".dbviewer-sidebar");
|
29
28
|
const overlay = document.createElement("div");
|
30
29
|
|
@@ -61,10 +60,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
|
61
60
|
}
|
62
61
|
});
|
63
62
|
|
64
|
-
closeBtn.addEventListener("click", function () {
|
65
|
-
hideSidebar();
|
66
|
-
});
|
67
|
-
|
68
63
|
overlay.addEventListener("click", function () {
|
69
64
|
hideSidebar();
|
70
65
|
});
|
@@ -125,16 +125,23 @@ tbody tr td.action-column {
|
|
125
125
|
/* ========== ACTION COLUMN STYLING ========== */
|
126
126
|
/* Action column styling */
|
127
127
|
.action-column {
|
128
|
-
width: 100px; /*
|
129
|
-
min-width: 100px;
|
128
|
+
width: 100px; /* Default for desktop */
|
129
|
+
min-width: 100px;
|
130
130
|
white-space: nowrap;
|
131
131
|
position: sticky;
|
132
132
|
left: 0;
|
133
|
-
z-index: 30;
|
134
|
-
background-color: var(--bs-body-bg, #fff);
|
133
|
+
z-index: 30;
|
134
|
+
background-color: var(--bs-body-bg, #fff);
|
135
135
|
box-shadow: 2px 0 6px rgba(0, 0, 0, 0.04);
|
136
136
|
}
|
137
137
|
|
138
|
+
@media (max-width: 767.98px) {
|
139
|
+
.action-column {
|
140
|
+
width: 30px;
|
141
|
+
min-width: 30px;
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
138
145
|
.copy-factory-btn,
|
139
146
|
.view-record-btn {
|
140
147
|
padding: 0.1rem 0.4rem;
|
@@ -106,7 +106,7 @@ module Dbviewer
|
|
106
106
|
end
|
107
107
|
|
108
108
|
content_tag(:td, class: "text-center action-column") do
|
109
|
-
content_tag(:div, class: "d-flex gap-1 justify-content-center") do
|
109
|
+
content_tag(:div, class: "d-flex flex-column flex-md-row gap-1 justify-content-center") do
|
110
110
|
# View Record button (existing)
|
111
111
|
view_button = button_tag(
|
112
112
|
type: "button",
|
@@ -15,7 +15,7 @@
|
|
15
15
|
<div class="row h-100">
|
16
16
|
<div class="col-md-12 p-0">
|
17
17
|
<div class="card h-100">
|
18
|
-
<div class="card-header d-flex justify-content-between align-items-center">
|
18
|
+
<div class="card-header d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center gap-2">
|
19
19
|
<h5 class="mb-0">
|
20
20
|
<i class="bi bi-diagram-3"></i> Entity Relationship Diagram
|
21
21
|
</h5>
|
@@ -28,7 +28,7 @@
|
|
28
28
|
<i class="bi bi-zoom-out"></i>
|
29
29
|
</button>
|
30
30
|
<button id="resetView" class="btn btn-sm btn-outline-secondary me-1">
|
31
|
-
<i class="bi bi-arrow-counterclockwise"></i>
|
31
|
+
<i class="bi bi-arrow-counterclockwise"></i>
|
32
32
|
</button>
|
33
33
|
<div class="dropdown">
|
34
34
|
<button class="btn btn-sm btn-outline-primary dropdown-toggle" type="button" id="downloadButton" data-bs-toggle="dropdown" aria-expanded="false">
|
@@ -240,27 +240,6 @@
|
|
240
240
|
</div>
|
241
241
|
<% end %>
|
242
242
|
|
243
|
-
<!-- Table Access Chart -->
|
244
|
-
<% if @stats[:tables_queried].present? %>
|
245
|
-
<div class="row mb-4">
|
246
|
-
<div class="col-md-12">
|
247
|
-
<div class="card <%= 'border-info' if @filtered_stats %>">
|
248
|
-
<div class="card-header <%= @filtered_stats ? 'bg-info-subtle' : '' %>">
|
249
|
-
<div class="d-flex justify-content-between align-items-center">
|
250
|
-
<h5 class="card-title mb-0">Table Access Frequency</h5>
|
251
|
-
<% if @filtered_stats %>
|
252
|
-
<span class="badge bg-info text-dark">Filtered</span>
|
253
|
-
<% end %>
|
254
|
-
</div>
|
255
|
-
</div>
|
256
|
-
<div class="card-body">
|
257
|
-
<canvas id="tablesChart" width="400" height="150"></canvas>
|
258
|
-
</div>
|
259
|
-
</div>
|
260
|
-
</div>
|
261
|
-
</div>
|
262
|
-
<% end %>
|
263
|
-
|
264
243
|
<!-- Filters -->
|
265
244
|
<div class="card mb-4">
|
266
245
|
<div class="card-header">
|
@@ -22,7 +22,7 @@
|
|
22
22
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
23
23
|
<h1>Query: <%= @table_name %></h1>
|
24
24
|
<div>
|
25
|
-
<%= link_to table_path(@table_name), class: "btn btn-outline-primary" do %>
|
25
|
+
<%= link_to table_path(@table_name), class: "btn btn-outline-primary d-none d-md-inline-flex" do %>
|
26
26
|
<i class="bi bi-arrow-left me-1"></i> Back to Table
|
27
27
|
<% end %>
|
28
28
|
</div>
|
@@ -41,8 +41,8 @@
|
|
41
41
|
<%= form.hidden_field :query, id: "query-input", value: @query.to_s %>
|
42
42
|
</div>
|
43
43
|
|
44
|
-
<div class="d-flex justify-content-between align-items-start">
|
45
|
-
<div class="form-text">
|
44
|
+
<div class="d-md-flex justify-content-between align-items-start">
|
45
|
+
<div class="form-text mb-3 mb-md-0">
|
46
46
|
<strong>Examples:</strong><br>
|
47
47
|
<div class="example-queries">
|
48
48
|
<code class="example-query btn btn-sm btn-outline-secondary mb-1">SELECT * FROM <%= @table_name %> LIMIT 100</code>
|
@@ -18,18 +18,22 @@
|
|
18
18
|
</div>
|
19
19
|
<div class="d-flex flex-wrap gap-2">
|
20
20
|
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#tableStructureModal">
|
21
|
-
<i class="bi bi-table me-1"></i>
|
21
|
+
<i class="bi bi-table me-1"></i>
|
22
|
+
<span class="d-none d-sm-inline">Table Structure</span>
|
22
23
|
</button>
|
23
24
|
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#miniErdModal">
|
24
|
-
<i class="bi bi-diagram-3 me-1"></i>
|
25
|
+
<i class="bi bi-diagram-3 me-1"></i>
|
26
|
+
<span class="d-none d-sm-inline">View Relationships</span>
|
25
27
|
</button>
|
26
28
|
<% if Dbviewer.configuration.enable_data_export %>
|
27
29
|
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#csvExportModal">
|
28
|
-
|
30
|
+
<i class="bi bi-file-earmark-spreadsheet me-1"></i>
|
31
|
+
<span class="d-none d-sm-inline">Export CSV</span>
|
29
32
|
</button>
|
30
33
|
<% end %>
|
31
34
|
<%= link_to query_table_path(@table_name), class: "btn btn-primary" do %>
|
32
|
-
<i class="bi bi-code-square me-1"></i>
|
35
|
+
<i class="bi bi-code-square me-1"></i>
|
36
|
+
<span class="d-none d-sm-inline">Run SQL Query</span>
|
33
37
|
<% end %>
|
34
38
|
</div>
|
35
39
|
</div>
|
@@ -99,25 +103,25 @@
|
|
99
103
|
<div class="dbviewer-card card mb-4" id="table-section">
|
100
104
|
<div class="card-header d-flex justify-content-between align-items-center">
|
101
105
|
<h5 class="mb-0">
|
102
|
-
<select id="per-page-select" class="form-select form-select-sm" onchange="window.location.href='<%= table_path(@table_name) %>?<%= per_page_url_params(@table_name) %>'">
|
106
|
+
<select id="per-page-select" class="form-select form-select-sm pe-4" onchange="window.location.href='<%= table_path(@table_name) %>?<%= per_page_url_params(@table_name) %>'">
|
103
107
|
<% Dbviewer.configuration.per_page_options.each do |option| %>
|
104
108
|
<option value="<%= option %>" <%= 'selected' if @per_page == option %>><%= option %></option>
|
105
109
|
<% end %>
|
106
110
|
</select>
|
107
111
|
</h5>
|
108
|
-
<div class="d-flex align-items-center table-actions">
|
112
|
+
<div class="d-none d-md-flex align-items-center table-actions">
|
109
113
|
<% if @order_by.present? %>
|
110
114
|
<span class="badge bg-primary me-2" title="Sort order">
|
111
115
|
<i class="bi bi-sort-<%= @order_direction == "ASC" ? "up" : "down" %> me-1"></i>
|
112
116
|
<%= @order_by %> (<%= @order_direction == "ASC" ? "ascending" : "descending" %>)
|
113
117
|
</span>
|
114
118
|
<% end %>
|
115
|
-
<span class="badge bg-secondary">Total: <%= @total_count %> records</span>
|
116
|
-
<% active_filters = @column_filters.reject { |
|
119
|
+
<span class="d-none d-md-block badge bg-secondary">Total: <%= @total_count %> records</span>
|
120
|
+
<% active_filters = @column_filters.reject { |k, v| v.blank? || k.to_s.ends_with?('_operator') }.size %>
|
117
121
|
<% if active_filters > 0 %>
|
118
122
|
<span class="badge bg-info ms-2" title="Active filters"><i class="bi bi-funnel-fill me-1"></i><%= active_filters %></span>
|
119
123
|
<% end %>
|
120
|
-
<button type="button" class="btn btn-outline-secondary btn-sm ms-2" id="fullscreen-toggle" title="Toggle fullscreen">
|
124
|
+
<button type="button" class="d-none d-md-block btn btn-outline-secondary btn-sm ms-2" id="fullscreen-toggle" title="Toggle fullscreen">
|
121
125
|
<i class="bi bi-fullscreen" id="fullscreen-icon"></i>
|
122
126
|
</button>
|
123
127
|
</div>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Dbviewer
|
2
|
+
# Helper class for configuring PII masking rules
|
3
|
+
class PiiConfigurator
|
4
|
+
def initialize(configuration)
|
5
|
+
@configuration = configuration
|
6
|
+
end
|
7
|
+
|
8
|
+
# Define a PII masking rule
|
9
|
+
# @param column_spec [String] Table and column in format "table.column"
|
10
|
+
# @param with [Symbol, Proc] Masking rule - either built-in symbol or custom proc
|
11
|
+
def mask(column_spec, with:)
|
12
|
+
@configuration.pii_rules[column_spec] = with
|
13
|
+
end
|
14
|
+
|
15
|
+
# Define a custom masking function
|
16
|
+
# @param name [Symbol] Name of the custom mask
|
17
|
+
# @param block [Proc] The masking function
|
18
|
+
def custom_mask(name, block)
|
19
|
+
@configuration.custom_pii_masks[name] = block
|
20
|
+
end
|
21
|
+
|
22
|
+
# Enable or disable PII masking globally
|
23
|
+
# @param enabled [Boolean] Whether to enable PII masking
|
24
|
+
def enabled=(enabled)
|
25
|
+
@configuration.enable_pii_masking = enabled
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/dbviewer/version.rb
CHANGED
data/lib/dbviewer.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require "dbviewer/version"
|
2
2
|
require "dbviewer/configuration"
|
3
3
|
require "dbviewer/engine"
|
4
|
+
require "dbviewer/pii_configuration"
|
5
|
+
|
4
6
|
require "dbviewer/validator/sql"
|
5
7
|
require "dbviewer/security/sql_parser"
|
6
8
|
require "dbviewer/security/access_control"
|
@@ -32,33 +34,6 @@ require "propshaft"
|
|
32
34
|
module Dbviewer
|
33
35
|
# Main module for the database viewer
|
34
36
|
|
35
|
-
# Helper class for configuring PII masking rules
|
36
|
-
class PiiConfigurator
|
37
|
-
def initialize(configuration)
|
38
|
-
@configuration = configuration
|
39
|
-
end
|
40
|
-
|
41
|
-
# Define a PII masking rule
|
42
|
-
# @param column_spec [String] Table and column in format "table.column"
|
43
|
-
# @param with [Symbol, Proc] Masking rule - either built-in symbol or custom proc
|
44
|
-
def mask(column_spec, with:)
|
45
|
-
@configuration.pii_rules[column_spec] = with
|
46
|
-
end
|
47
|
-
|
48
|
-
# Define a custom masking function
|
49
|
-
# @param name [Symbol] Name of the custom mask
|
50
|
-
# @param block [Proc] The masking function
|
51
|
-
def custom_mask(name, block)
|
52
|
-
@configuration.custom_pii_masks[name] = block
|
53
|
-
end
|
54
|
-
|
55
|
-
# Enable or disable PII masking globally
|
56
|
-
# @param enabled [Boolean] Whether to enable PII masking
|
57
|
-
def enabled=(enabled)
|
58
|
-
@configuration.enable_pii_masking = enabled
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
37
|
class << self
|
63
38
|
# Module accessor for configuration
|
64
39
|
attr_writer :configuration
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dbviewer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wailan Tirajoh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-06-
|
11
|
+
date: 2025-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -152,6 +152,7 @@ files:
|
|
152
152
|
- lib/dbviewer/datatable/query_operations.rb
|
153
153
|
- lib/dbviewer/datatable/query_params.rb
|
154
154
|
- lib/dbviewer/engine.rb
|
155
|
+
- lib/dbviewer/pii_configuration.rb
|
155
156
|
- lib/dbviewer/query/analyzer.rb
|
156
157
|
- lib/dbviewer/query/executor.rb
|
157
158
|
- lib/dbviewer/query/logger.rb
|