sqlui 0.1.60 → 0.1.61

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45285cfe6706fdfa5bae7abf73f1a287e0238709f2f83a18eda8386c71f4de63
4
- data.tar.gz: 9d3eacf4a4306697c4c34d91b51303dd88b376bec29526124d18ec5c4fbe43d7
3
+ metadata.gz: ec12b1d88bc2adff9dba6ff91b01e66b123d17cb8b042e142c24f71303a27a92
4
+ data.tar.gz: df939b59b2bae004270ea1907a6be52352e7c81e6050405bc4534a6faaae0567
5
5
  SHA512:
6
- metadata.gz: f94e45bf232683013994f63a46eb18257aeaf9d81dd906ccffdbdced023be1743ebca28ff87f34a3b45932757b80516fae979d74a9ab1002affa78a7adb412dc
7
- data.tar.gz: 4151e2f3f7d795931abfee848f040e9b6066c4ef4ec9503d0f3cdb586e82d3ced59f50c3eb8744c2adc2847324d275d642e313c0ba825768e452e7a0f8af7b75
6
+ metadata.gz: fd504e8ba6cf53b06b30b21867a7925ef7fda8055690eefb7759dd8ed745dd28088ca6c2f257eef1073aa976b67548c155bc26eb4f334750df6a059e9abdf6db
7
+ data.tar.gz: 96584bb97da39f508542a861d16d1bb2196238ab4d12c99528937704f6b29aefee9563c837921dbee1a72fe5113b3a8dfb39b4c74a5951ffc6fb8be697d535cb
data/.release-version CHANGED
@@ -1 +1 @@
1
- 0.1.60
1
+ 0.1.61
@@ -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. */
139
+ }
140
+
141
+ #cancel-button-spacer {
142
+ width: 150px;
136
143
  }
137
144
 
138
- .submit-button-wrapper {
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