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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45285cfe6706fdfa5bae7abf73f1a287e0238709f2f83a18eda8386c71f4de63
4
- data.tar.gz: 9d3eacf4a4306697c4c34d91b51303dd88b376bec29526124d18ec5c4fbe43d7
3
+ metadata.gz: 3ba6df74cbbe88d22279ec0a6a7cc9bf1ed191d695b84fcf424ee9b03a6b64cb
4
+ data.tar.gz: a9f53957b16860755a7d6d21980e573af93054bff997a205d791553b8b8dae59
5
5
  SHA512:
6
- metadata.gz: f94e45bf232683013994f63a46eb18257aeaf9d81dd906ccffdbdced023be1743ebca28ff87f34a3b45932757b80516fae979d74a9ab1002affa78a7adb412dc
7
- data.tar.gz: 4151e2f3f7d795931abfee848f040e9b6066c4ef4ec9503d0f3cdb586e82d3ced59f50c3eb8744c2adc2847324d275d642e313c0ba825768e452e7a0f8af7b75
6
+ metadata.gz: d9375a77c825b5036079d8e3d4b5df74e4370be1966441bc3a8a4a887e878fd58d79500187116c2492e3d27358084c0aaa70bd45f48aba5e387ac37c0d51e678
7
+ data.tar.gz: ac699985a8459edb63c8aeeca34c861471d468b9680fd767d8c69f14610c27d04d55feeaa07d2c0256fa0ee6148e4f659f9060b399847173fc4cbe67d3c9b6ea
data/.release-version CHANGED
@@ -1 +1 @@
1
- 0.1.60
1
+ 0.1.62
@@ -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 /' unless @url_path.start_with?('/')
18
- raise ArgumentError, 'url_path should not end with a /' if @url_path.length > 1 && @url_path.end_with?('/')
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.list_url_path, 301
71
+ redirect config.base_url_path, 301
73
72
  end
74
73
 
75
- get '/favicon.svg' do
76
- headers 'Cache-Control' => 'max-age=31536000'
77
- send_file File.join(resources_dir, 'favicon.svg')
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.list_url_path}/?" do
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
- get "#{database.url_path}/sqlui.css" do
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
- list_url_path: config.list_url_path,
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(%r{#{Regexp.escape(database.url_path)}/(query|graph|structure|saved)}) do
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
- js_hash: js_hash,
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: { title: "SQLUI #{message}", message: message, stacktrace: stacktrace }
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, :list_url_path, :database_configs, :airbrake
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
- @list_url_path = Args.fetch_non_empty_string(config, :list_url_path).strip
23
- raise ArgumentError, 'list_url_path should start with a /' unless @list_url_path.start_with?('/')
24
- if @list_url_path.length > 1 && @list_url_path.end_with?('/')
25
- raise ArgumentError, 'list_url_path should not end with a /'
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)
@@ -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="/favicon.svg">
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 %>/query">query</a>
96
- <a class='saved-link' href="<%= database_config.url_path %>/saved">saved</a>
97
- <a class='structure-link' href="<%= database_config.url_path %>/structure">structure</a>
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="/favicon.svg">
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="/favicon.svg?<%= favicon_hash %>">
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?<%= js_hash %>"></script>
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?<%= css_hash %>">
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" class="cancel-button" type="button" value="cancel"></input>
47
- <div class="submit-fill"></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 class="submit-button-wrapper">
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>
@@ -120,27 +120,35 @@ p {
120
120
  padding: 5px;
121
121
  }
122
122
 
123
- .submit-fill {
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
- .cancel-button {
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
- .submit-button-wrapper {
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
- .cancel-button:active,
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;