sqlui 0.1.60 → 0.1.62
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/.release-version +1 -1
- data/app/database_config.rb +2 -2
- data/app/server.rb +40 -32
- data/app/sqlui_config.rb +5 -5
- data/app/views/databases.erb +4 -4
- data/app/views/error.erb +1 -1
- data/app/views/sqlui.erb +8 -6
- data/client/resources/sqlui.css +14 -10
- data/client/resources/sqlui.js +364 -212
- data/client/resources/vertical-resizer.svg +5 -0
- 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: 3ba6df74cbbe88d22279ec0a6a7cc9bf1ed191d695b84fcf424ee9b03a6b64cb
|
|
4
|
+
data.tar.gz: a9f53957b16860755a7d6d21980e573af93054bff997a205d791553b8b8dae59
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d9375a77c825b5036079d8e3d4b5df74e4370be1966441bc3a8a4a887e878fd58d79500187116c2492e3d27358084c0aaa70bd45f48aba5e387ac37c0d51e678
|
|
7
|
+
data.tar.gz: ac699985a8459edb63c8aeeca34c861471d468b9680fd767d8c69f14610c27d04d55feeaa07d2c0256fa0ee6148e4f659f9060b399847173fc4cbe67d3c9b6ea
|
data/.release-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.62
|
data/app/database_config.rb
CHANGED
|
@@ -14,8 +14,8 @@ class DatabaseConfig
|
|
|
14
14
|
@display_name = Args.fetch_non_empty_string(hash, :display_name).strip
|
|
15
15
|
@description = Args.fetch_non_empty_string(hash, :description).strip
|
|
16
16
|
@url_path = Args.fetch_non_empty_string(hash, :url_path).strip
|
|
17
|
-
raise ArgumentError, 'url_path should start with a /'
|
|
18
|
-
raise ArgumentError, 'url_path should not end with a /' if @url_path.
|
|
17
|
+
raise ArgumentError, 'url_path should not start with a /' if @url_path.start_with?('/')
|
|
18
|
+
raise ArgumentError, 'url_path should not end with a /' if @url_path.end_with?('/')
|
|
19
19
|
|
|
20
20
|
@saved_path = Args.fetch_non_empty_string(hash, :saved_path).strip
|
|
21
21
|
|
data/app/server.rb
CHANGED
|
@@ -25,6 +25,9 @@ class Server < Sinatra::Base
|
|
|
25
25
|
def self.init_and_run(config, resources_dir)
|
|
26
26
|
logger.info("Starting SQLUI v#{Version::SQLUI}")
|
|
27
27
|
logger.info("Airbrake enabled: #{config.airbrake[:server]&.[](:enabled) || false}")
|
|
28
|
+
|
|
29
|
+
WEBrick::HTTPRequest.const_set('MAX_URI_LENGTH', 2 * 1024 * 1024)
|
|
30
|
+
|
|
28
31
|
if config.airbrake[:server]&.[](:enabled)
|
|
29
32
|
require 'airbrake'
|
|
30
33
|
require 'airbrake/rack'
|
|
@@ -59,51 +62,53 @@ class Server < Sinatra::Base
|
|
|
59
62
|
set :raise_errors, false
|
|
60
63
|
set :show_exceptions, false
|
|
61
64
|
|
|
62
|
-
favicon_hash = Digest::MD5.hexdigest(File.read(File.join(resources_dir, 'favicon.svg')))
|
|
63
|
-
css_hash = Digest::MD5.hexdigest(File.read(File.join(resources_dir, 'sqlui.css')))
|
|
64
|
-
js_hash = Digest::MD5.hexdigest(File.read(File.join(resources_dir, 'sqlui.js')))
|
|
65
|
-
|
|
66
65
|
get '/-/health' do
|
|
67
66
|
status 200
|
|
68
67
|
body 'OK'
|
|
69
68
|
end
|
|
70
69
|
|
|
71
70
|
get '/?' do
|
|
72
|
-
redirect config.
|
|
71
|
+
redirect config.base_url_path, 301
|
|
73
72
|
end
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
resource_path_map = {}
|
|
75
|
+
Dir.glob(File.join(resources_dir, '*')).each do |file|
|
|
76
|
+
hash = Digest::MD5.hexdigest(File.read(file))
|
|
77
|
+
basename = File.basename(file)
|
|
78
|
+
url_path = "#{config.base_url_path}/#{basename}"
|
|
79
|
+
case File.extname(basename)
|
|
80
|
+
when '.svg'
|
|
81
|
+
content_type = 'image/svg+xml; charset=utf-8'
|
|
82
|
+
when '.css'
|
|
83
|
+
content_type = 'text/css; charset=utf-8'
|
|
84
|
+
when '.js'
|
|
85
|
+
content_type = 'text/javascript; charset=utf-8'
|
|
86
|
+
else
|
|
87
|
+
raise "unsupported resource file extension: #{File.extname(basename)}"
|
|
88
|
+
end
|
|
89
|
+
resource_path_map[basename] = "#{url_path}?#{hash}"
|
|
90
|
+
get url_path do
|
|
91
|
+
headers 'Content-Type' => content_type
|
|
92
|
+
headers 'Cache-Control' => 'max-age=31536000'
|
|
93
|
+
send_file file
|
|
94
|
+
end
|
|
78
95
|
end
|
|
79
96
|
|
|
80
|
-
get "#{config.
|
|
97
|
+
get "#{config.base_url_path}/?" do
|
|
81
98
|
headers 'Cache-Control' => 'no-cache'
|
|
82
|
-
erb :databases, locals: { config: config }
|
|
99
|
+
erb :databases, locals: { config: config, resource_path_map: resource_path_map }
|
|
83
100
|
end
|
|
84
101
|
|
|
85
102
|
config.database_configs.each do |database|
|
|
86
|
-
get "#{database.url_path}/?" do
|
|
103
|
+
get "#{config.base_url_path}/#{database.url_path}/?" do
|
|
87
104
|
redirect "#{database.url_path}/query", 301
|
|
88
105
|
end
|
|
89
106
|
|
|
90
|
-
|
|
91
|
-
headers 'Content-Type' => 'text/css; charset=utf-8'
|
|
92
|
-
headers 'Cache-Control' => 'max-age=31536000'
|
|
93
|
-
send_file File.join(resources_dir, 'sqlui.css')
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
get "#{database.url_path}/sqlui.js" do
|
|
97
|
-
headers 'Content-Type' => 'text/javascript; charset=utf-8'
|
|
98
|
-
headers 'Cache-Control' => 'max-age=31536000'
|
|
99
|
-
send_file File.join(resources_dir, 'sqlui.js')
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
post "#{database.url_path}/metadata" do
|
|
107
|
+
post "#{config.base_url_path}/#{database.url_path}/metadata" do
|
|
103
108
|
metadata = database.with_client do |client|
|
|
104
109
|
{
|
|
105
110
|
server: "#{config.name} - #{database.display_name}",
|
|
106
|
-
|
|
111
|
+
base_url_path: config.base_url_path,
|
|
107
112
|
schemas: DatabaseMetadata.lookup(client, database),
|
|
108
113
|
tables: database.tables,
|
|
109
114
|
columns: database.columns,
|
|
@@ -131,7 +136,7 @@ class Server < Sinatra::Base
|
|
|
131
136
|
body metadata.to_json
|
|
132
137
|
end
|
|
133
138
|
|
|
134
|
-
post "#{database.url_path}/query" do
|
|
139
|
+
post "#{config.base_url_path}/#{database.url_path}/query" do
|
|
135
140
|
data = request.body.read
|
|
136
141
|
request.body.rewind # since Airbrake will read the body on error
|
|
137
142
|
params.merge!(JSON.parse(data, symbolize_names: true))
|
|
@@ -215,7 +220,7 @@ class Server < Sinatra::Base
|
|
|
215
220
|
end
|
|
216
221
|
end
|
|
217
222
|
|
|
218
|
-
get "#{database.url_path}/download_csv" do
|
|
223
|
+
get "#{config.base_url_path}/#{database.url_path}/download_csv" do
|
|
219
224
|
break client_error('missing sql') unless params[:sql]
|
|
220
225
|
|
|
221
226
|
sql = Base64.decode64(params[:sql]).force_encoding('UTF-8')
|
|
@@ -250,7 +255,7 @@ class Server < Sinatra::Base
|
|
|
250
255
|
end
|
|
251
256
|
end
|
|
252
257
|
|
|
253
|
-
get(
|
|
258
|
+
get(/#{Regexp.escape("#{config.base_url_path}/#{database.url_path}/")}(query|graph|structure|saved)/) do
|
|
254
259
|
status 200
|
|
255
260
|
headers 'Cache-Control' => 'no-cache'
|
|
256
261
|
client_config = config.airbrake[:client] || {}
|
|
@@ -259,9 +264,7 @@ class Server < Sinatra::Base
|
|
|
259
264
|
airbrake_enabled: client_config[:enabled] || false,
|
|
260
265
|
airbrake_project_id: client_config[:project_id] || '',
|
|
261
266
|
airbrake_project_key: client_config[:project_key] || '',
|
|
262
|
-
|
|
263
|
-
css_hash: css_hash,
|
|
264
|
-
favicon_hash: favicon_hash
|
|
267
|
+
resource_path_map: resource_path_map
|
|
265
268
|
}
|
|
266
269
|
end
|
|
267
270
|
end
|
|
@@ -276,7 +279,12 @@ class Server < Sinatra::Base
|
|
|
276
279
|
body json
|
|
277
280
|
else
|
|
278
281
|
message = "#{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}"
|
|
279
|
-
erb :error, locals: {
|
|
282
|
+
erb :error, locals: {
|
|
283
|
+
resource_path_map: resource_path_map,
|
|
284
|
+
title: "SQLUI #{message}",
|
|
285
|
+
message: message,
|
|
286
|
+
stacktrace: stacktrace
|
|
287
|
+
}
|
|
280
288
|
end
|
|
281
289
|
end
|
|
282
290
|
|
data/app/sqlui_config.rb
CHANGED
|
@@ -8,7 +8,7 @@ require_relative 'deep'
|
|
|
8
8
|
|
|
9
9
|
# App config including database configs.
|
|
10
10
|
class SqluiConfig
|
|
11
|
-
attr_reader :name, :port, :environment, :
|
|
11
|
+
attr_reader :name, :port, :environment, :base_url_path, :database_configs, :airbrake
|
|
12
12
|
|
|
13
13
|
def initialize(filename, overrides = {})
|
|
14
14
|
config = YAML.safe_load(ERB.new(File.read(filename)).result, aliases: true).deep_merge!(overrides)
|
|
@@ -19,10 +19,10 @@ class SqluiConfig
|
|
|
19
19
|
@name = Args.fetch_non_empty_string(config, :name).strip
|
|
20
20
|
@port = Args.fetch_non_empty_int(config, :port)
|
|
21
21
|
@environment = Args.fetch_non_empty_string(config, :environment).strip
|
|
22
|
-
@
|
|
23
|
-
raise ArgumentError, '
|
|
24
|
-
if @
|
|
25
|
-
raise ArgumentError, '
|
|
22
|
+
@base_url_path = Args.fetch_non_empty_string(config, :base_url_path).strip
|
|
23
|
+
raise ArgumentError, 'base_url_path should start with a /' unless @base_url_path.start_with?('/')
|
|
24
|
+
if @base_url_path.length > 1 && @base_url_path.end_with?('/')
|
|
25
|
+
raise ArgumentError, 'base_url_path should not end with a /'
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
databases = Args.fetch_non_empty_hash(config, :databases)
|
data/app/views/databases.erb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<title>SQLUI <%= config.name %> Databases</title>
|
|
6
|
-
<link rel="icon" type="image/x-icon" href="
|
|
6
|
+
<link rel="icon" type="image/x-icon" href="<%= resource_path_map['favicon.svg'] %>">
|
|
7
7
|
|
|
8
8
|
<style>
|
|
9
9
|
body {
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
<div class="database">
|
|
93
93
|
<div class="name-and-links">
|
|
94
94
|
<h2 class='name'><%= database_config.display_name %></h2>
|
|
95
|
-
<a class='query-link' href="<%= database_config.url_path
|
|
96
|
-
<a class='saved-link' href="<%= database_config.url_path
|
|
97
|
-
<a class='structure-link' href="<%= database_config.url_path
|
|
95
|
+
<a class='query-link' href="<%= "#{config.base_url_path}/#{database_config.url_path}/query" %>">query</a>
|
|
96
|
+
<a class='saved-link' href="<%= "#{config.base_url_path}/#{database_config.url_path}/saved" %>">saved</a>
|
|
97
|
+
<a class='structure-link' href="<%= "#{config.base_url_path}/#{database_config.url_path}/structure" %>">structure</a>
|
|
98
98
|
</div>
|
|
99
99
|
<p class='description'>
|
|
100
100
|
<%= database_config.description %>
|
data/app/views/error.erb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="utf-8">
|
|
6
6
|
<title><%= title %></title>
|
|
7
|
-
<link rel="icon" type="image/x-icon" href="
|
|
7
|
+
<link rel="icon" type="image/x-icon" href="<%= resource_path_map['favicon.svg'] %>">
|
|
8
8
|
</head>
|
|
9
9
|
<body style="font-family: monospace; font-size: 16px;">
|
|
10
10
|
|
data/app/views/sqlui.erb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<title>SQLUI</title>
|
|
6
|
-
<link rel="icon" type="image/x-icon" href="
|
|
6
|
+
<link rel="icon" type="image/x-icon" href="<%= resource_path_map['favicon.svg'] %>">
|
|
7
7
|
<!-- Initialize Airbrake before loading the main app JS so that we can catch errors as early as possible. -->
|
|
8
8
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@airbrake/browser"></script>
|
|
9
9
|
<script type="text/javascript">
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
window.airbrake?.notify(error)
|
|
20
20
|
}
|
|
21
21
|
</script>
|
|
22
|
-
<script type="text/javascript" src="sqlui.js
|
|
22
|
+
<script type="text/javascript" src="<%= resource_path_map['sqlui.js'] %>"></script>
|
|
23
23
|
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
|
|
24
|
-
<link rel="stylesheet" href="sqlui.css
|
|
24
|
+
<link rel="stylesheet" href="<%= resource_path_map['sqlui.css'] %>">
|
|
25
25
|
</head>
|
|
26
26
|
|
|
27
27
|
<body>
|
|
@@ -43,10 +43,12 @@
|
|
|
43
43
|
</div>
|
|
44
44
|
|
|
45
45
|
<div id="submit-box" class="tab-content-element graph-element query-element" style="display: none;">
|
|
46
|
-
<input id="cancel-button"
|
|
47
|
-
<div
|
|
46
|
+
<input id="cancel-button" type="button" value="cancel"></input>
|
|
47
|
+
<div id="editor-resizer">
|
|
48
|
+
<img src="<%= resource_path_map['vertical-resizer.svg'] %>" />
|
|
49
|
+
</div>
|
|
48
50
|
<div style="position: relative;">
|
|
49
|
-
<div
|
|
51
|
+
<div id="submit-button-wrapper">
|
|
50
52
|
<input id="submit-button-all" class="submit-button" type="button"></input>
|
|
51
53
|
<input id="submit-button-current" class="submit-button submit-button-show" type="button"></input>
|
|
52
54
|
<input id="submit-dropdown-button" class="submit-dropdown-button" type="button", value="▼"></input>
|
data/client/resources/sqlui.css
CHANGED
|
@@ -120,27 +120,35 @@ p {
|
|
|
120
120
|
padding: 5px;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
#editor-resizer {
|
|
124
124
|
display: flex;
|
|
125
|
-
flex: 1
|
|
125
|
+
flex: 1;
|
|
126
|
+
cursor: row-resize;
|
|
127
|
+
flex-direction: column;
|
|
128
|
+
align-items: center;
|
|
126
129
|
}
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
#cancel-button {
|
|
129
132
|
cursor: pointer;
|
|
130
|
-
margin: 0;
|
|
131
133
|
background: none;
|
|
132
134
|
color: #333;
|
|
133
135
|
border: 1px solid #888;
|
|
134
136
|
height: 32px;
|
|
135
137
|
font-size: 18px;
|
|
138
|
+
margin: 0 220px 0 0; /* To center the resizer icon. Ok, it's a hack. Get over it. */
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
|
|
141
|
+
#cancel-button-spacer {
|
|
142
|
+
width: 150px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
#submit-button-wrapper {
|
|
139
146
|
cursor: pointer;
|
|
140
147
|
border: 1px solid #888;
|
|
141
148
|
height: 32px;
|
|
142
149
|
display: flex;
|
|
143
150
|
flex-direction: row;
|
|
151
|
+
background: white;
|
|
144
152
|
}
|
|
145
153
|
|
|
146
154
|
.submit-button, .submit-dropdown-button {
|
|
@@ -217,7 +225,7 @@ p {
|
|
|
217
225
|
|
|
218
226
|
.submit-dropdown-content-button:active,
|
|
219
227
|
.submit-button:active,
|
|
220
|
-
|
|
228
|
+
#cancel-button:active,
|
|
221
229
|
.submit-dropdown-button:active {
|
|
222
230
|
background-color: #e6e6e6;
|
|
223
231
|
outline: none
|
|
@@ -254,10 +262,6 @@ table tbody tr td {
|
|
|
254
262
|
height: 21px;
|
|
255
263
|
}
|
|
256
264
|
|
|
257
|
-
#result-table td, #result-table th {
|
|
258
|
-
cursor: default;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
265
|
#result-table tbody tr td abbr a {
|
|
262
266
|
color: #555;
|
|
263
267
|
cursor: pointer;
|