sqlui 0.1.24 → 0.1.26
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/.version +1 -1
- data/app/server.rb +39 -36
- data/app/views/databases.erb +25 -21
- data/client/resources/sqlui.css +43 -8
- data/client/resources/sqlui.html +14 -8
- data/client/resources/sqlui.js +375 -228
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 20b037b445c287b8e9586a2f5820d4be597bb977db8a9412721790a5239a2f87
|
|
4
|
+
data.tar.gz: '08e5d525245186d568bd2deb86f4a5d25adc9a57d3729651ff74d6fe90e22451'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 631086186d72bfe55f633e88a1017e911d53c4185b9139da4ebf0d462ec9fb48fbf639154fc014453285835c504b1ce8a18f20e9de9c78239a95566b2cde3177
|
|
7
|
+
data.tar.gz: 24cd3591e88d28785765b6add934a19458c19920cdd77c02f31f7356ca6cefdf4971e45df560c1e451a50ee4192c1ca4d9f8cae227cfe7daa87463b82f7ada6f
|
data/.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.26
|
data/app/server.rb
CHANGED
|
@@ -25,20 +25,17 @@ class Server < Sinatra::Base
|
|
|
25
25
|
body 'OK'
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
get '/?' do
|
|
29
|
+
redirect config.list_url_path, 301
|
|
30
|
+
end
|
|
31
|
+
|
|
28
32
|
get "#{config.list_url_path}/?" do
|
|
29
33
|
erb :databases, locals: { config: config }
|
|
30
34
|
end
|
|
31
35
|
|
|
32
36
|
config.database_configs.each do |database|
|
|
33
|
-
get database.url_path
|
|
34
|
-
redirect "#{database.url_path}/
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
get "#{database.url_path}/app" do
|
|
38
|
-
@html ||= File.read(File.join(resources_dir, 'sqlui.html'))
|
|
39
|
-
status 200
|
|
40
|
-
headers 'Content-Type': 'text/html'
|
|
41
|
-
body @html
|
|
37
|
+
get "#{database.url_path}/?" do
|
|
38
|
+
redirect "#{database.url_path}/query", 301
|
|
42
39
|
end
|
|
43
40
|
|
|
44
41
|
get "#{database.url_path}/sqlui.css" do
|
|
@@ -59,16 +56,23 @@ class Server < Sinatra::Base
|
|
|
59
56
|
metadata = database.with_client do |client|
|
|
60
57
|
{
|
|
61
58
|
server: "#{config.name} - #{database.display_name}",
|
|
59
|
+
list_url_path: config.list_url_path,
|
|
62
60
|
schemas: DatabaseMetadata.lookup(client, database),
|
|
63
|
-
saved: Dir.glob("#{database.saved_path}/*.sql").
|
|
64
|
-
|
|
61
|
+
saved: Dir.glob("#{database.saved_path}/*.sql").to_h do |path|
|
|
62
|
+
contents = File.read(path)
|
|
63
|
+
comment_lines = contents.split("\n").take_while do |l|
|
|
65
64
|
l.start_with?('--')
|
|
66
65
|
end
|
|
66
|
+
filename = File.basename(path)
|
|
67
67
|
description = comment_lines.map { |l| l.sub(/^-- */, '') }.join
|
|
68
|
-
|
|
69
|
-
filename
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
[
|
|
69
|
+
filename,
|
|
70
|
+
{
|
|
71
|
+
filename: filename,
|
|
72
|
+
description: description,
|
|
73
|
+
contents: contents.strip
|
|
74
|
+
}
|
|
75
|
+
]
|
|
72
76
|
end
|
|
73
77
|
}
|
|
74
78
|
end
|
|
@@ -77,36 +81,28 @@ class Server < Sinatra::Base
|
|
|
77
81
|
body metadata.to_json
|
|
78
82
|
end
|
|
79
83
|
|
|
80
|
-
get "#{database.url_path}/query_file" do
|
|
81
|
-
break client_error('missing file param') unless params[:file]
|
|
82
|
-
|
|
83
|
-
file = File.join(database.saved_path, params[:file])
|
|
84
|
-
break client_error('no such file') unless File.exist?(file)
|
|
85
|
-
|
|
86
|
-
sql = File.read(file)
|
|
87
|
-
result = database.with_client do |client|
|
|
88
|
-
execute_query(client, sql).tap { |r| r[:file] = params[:file] }
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
status 200
|
|
92
|
-
headers 'Content-Type': 'application/json'
|
|
93
|
-
body result.to_json
|
|
94
|
-
end
|
|
95
|
-
|
|
96
84
|
post "#{database.url_path}/query" do
|
|
97
85
|
params.merge!(JSON.parse(request.body.read, symbolize_names: true))
|
|
98
86
|
break client_error('missing sql') unless params[:sql]
|
|
99
87
|
|
|
88
|
+
full_sql = params[:sql]
|
|
100
89
|
sql = params[:sql]
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
if params[:selection]
|
|
91
|
+
selection = params[:selection]
|
|
92
|
+
if selection.include?('-')
|
|
93
|
+
# sort because the selection could be in either direction
|
|
94
|
+
selection = params[:selection].split('-').map { |v| Integer(v) }.sort
|
|
95
|
+
else
|
|
96
|
+
selection = Integer(selection)
|
|
97
|
+
selection = [selection, selection]
|
|
98
|
+
end
|
|
104
99
|
|
|
105
100
|
sql = if selection[0] == selection[1]
|
|
106
101
|
SqlParser.find_statement_at_cursor(params[:sql], selection[0])
|
|
107
102
|
else
|
|
108
|
-
|
|
103
|
+
full_sql[selection[0], selection[1]]
|
|
109
104
|
end
|
|
105
|
+
|
|
110
106
|
break client_error("can't find query at selection") unless sql
|
|
111
107
|
end
|
|
112
108
|
|
|
@@ -115,11 +111,19 @@ class Server < Sinatra::Base
|
|
|
115
111
|
end
|
|
116
112
|
|
|
117
113
|
result[:selection] = params[:selection]
|
|
114
|
+
result[:query] = full_sql
|
|
118
115
|
|
|
119
116
|
status 200
|
|
120
117
|
headers 'Content-Type': 'application/json'
|
|
121
118
|
body result.to_json
|
|
122
119
|
end
|
|
120
|
+
|
|
121
|
+
get(%r{#{Regexp.escape(database.url_path)}/(query|graph|structure|saved)}) do
|
|
122
|
+
@html ||= File.read(File.join(resources_dir, 'sqlui.html'))
|
|
123
|
+
status 200
|
|
124
|
+
headers 'Content-Type': 'text/html'
|
|
125
|
+
body @html
|
|
126
|
+
end
|
|
123
127
|
end
|
|
124
128
|
|
|
125
129
|
error do |e|
|
|
@@ -165,7 +169,6 @@ class Server < Sinatra::Base
|
|
|
165
169
|
columns = []
|
|
166
170
|
end
|
|
167
171
|
{
|
|
168
|
-
query: sql,
|
|
169
172
|
columns: columns,
|
|
170
173
|
column_types: column_types,
|
|
171
174
|
total_rows: rows.size,
|
data/app/views/databases.erb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
<html>
|
|
1
|
+
<html lang="en">
|
|
2
2
|
<head>
|
|
3
|
-
<title
|
|
3
|
+
<title><%= config.name %> Databases</title>
|
|
4
4
|
|
|
5
5
|
<style>
|
|
6
6
|
body {
|
|
7
|
-
font-family: Helvetica;
|
|
8
|
-
margin:
|
|
7
|
+
font-family: Helvetica, sans-serif;
|
|
8
|
+
margin: 0;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
h1 {
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
flex-direction: row;
|
|
26
26
|
border-bottom: 1px solid #ddd;
|
|
27
27
|
height: 36px;
|
|
28
|
-
font-family: Helvetica;
|
|
28
|
+
font-family: Helvetica, sans-serif;
|
|
29
|
+
padding: 5px;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
.header, .server-name {
|
|
@@ -41,40 +42,41 @@
|
|
|
41
42
|
font-weight: normal;
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
.name-and-links {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: row;
|
|
48
|
+
align-items: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
44
51
|
.header {
|
|
45
52
|
font-weight: bold;
|
|
46
53
|
padding-left: 5px;
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
.database a {
|
|
50
|
-
margin-right:
|
|
57
|
+
margin-right: 5px;
|
|
51
58
|
color: darkblue;
|
|
52
|
-
font-size: 16px
|
|
59
|
+
font-size: 16px;
|
|
60
|
+
text-decoration: none;
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
.database h2 {
|
|
56
|
-
margin:
|
|
64
|
+
margin: 0 10px 0 0;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
.database p {
|
|
60
|
-
margin:
|
|
61
|
-
margin-top: 10px;
|
|
68
|
+
margin: 10px 0 0;
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
.database {
|
|
65
|
-
margin:
|
|
72
|
+
margin: 0;
|
|
66
73
|
padding: 10px;
|
|
67
|
-
cursor: pointer;
|
|
68
74
|
border-bottom: 1px solid #eeeeee;
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
.database:last-child {
|
|
72
78
|
border-bottom: none;
|
|
73
79
|
}
|
|
74
|
-
|
|
75
|
-
.database:hover {
|
|
76
|
-
background: #eee;
|
|
77
|
-
}
|
|
78
80
|
</style>
|
|
79
81
|
</head>
|
|
80
82
|
|
|
@@ -84,11 +86,13 @@
|
|
|
84
86
|
<h1 class="server-name"><%= config.name %> Databases</h1>
|
|
85
87
|
</div>
|
|
86
88
|
<% config.database_configs.each do |database_config| %>
|
|
87
|
-
<div class="database"
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
<div class="database">
|
|
90
|
+
<div class="name-and-links">
|
|
91
|
+
<h2 class='name'><%= database_config.display_name %></h2>
|
|
92
|
+
<a class='query-link' href="<%= database_config.url_path %>/query">query</a>
|
|
93
|
+
<a class='saved-link' href="<%= database_config.url_path %>/saved">saved</a>
|
|
94
|
+
<a class='structure-link' href="<%= database_config.url_path %>/structure">structure</a>
|
|
95
|
+
</div>
|
|
92
96
|
<p class='description'>
|
|
93
97
|
<%= database_config.description %>
|
|
94
98
|
</p>
|
data/client/resources/sqlui.css
CHANGED
|
@@ -71,6 +71,7 @@ p {
|
|
|
71
71
|
.tab-button, .selected-tab-button {
|
|
72
72
|
border: none;
|
|
73
73
|
outline: none;
|
|
74
|
+
text-decoration: none;
|
|
74
75
|
cursor: pointer;
|
|
75
76
|
width: 150px;
|
|
76
77
|
padding: 2px;
|
|
@@ -79,6 +80,7 @@ p {
|
|
|
79
80
|
justify-content: center;
|
|
80
81
|
background-color: #fff;
|
|
81
82
|
font-size: 18px;
|
|
83
|
+
align-self: center;
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
.tab-button {
|
|
@@ -110,7 +112,12 @@ p {
|
|
|
110
112
|
.submit-box {
|
|
111
113
|
display: flex;
|
|
112
114
|
border-top: 1px solid #ddd;
|
|
113
|
-
|
|
115
|
+
border-bottom: 1px solid #ddd;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.submit-fill {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex: 1
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
.submit-button {
|
|
@@ -135,15 +142,16 @@ p {
|
|
|
135
142
|
color: #333;
|
|
136
143
|
}
|
|
137
144
|
|
|
138
|
-
.result-box, .saved-box, .graph-box, .structure-box {
|
|
145
|
+
.result-box, .fetch-sql-box, .saved-box, .graph-box, .structure-box {
|
|
139
146
|
flex: 1;
|
|
140
147
|
overflow: auto;
|
|
141
148
|
display: flex;
|
|
142
149
|
flex-direction: column;
|
|
143
150
|
}
|
|
144
151
|
|
|
145
|
-
.
|
|
146
|
-
|
|
152
|
+
.fetch-sql-box {
|
|
153
|
+
justify-content: center;
|
|
154
|
+
align-items: center;
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
.graph-box {
|
|
@@ -218,6 +226,7 @@ thead {
|
|
|
218
226
|
|
|
219
227
|
.tabs-box {
|
|
220
228
|
display: flex;
|
|
229
|
+
padding: 5px;
|
|
221
230
|
}
|
|
222
231
|
|
|
223
232
|
.saved-box {
|
|
@@ -238,18 +247,30 @@ thead {
|
|
|
238
247
|
}
|
|
239
248
|
|
|
240
249
|
.saved-list-item {
|
|
241
|
-
cursor: pointer;
|
|
242
250
|
border-bottom: 1px solid #eeeeee;
|
|
243
251
|
margin: 0;
|
|
244
252
|
padding: 10px;
|
|
245
253
|
}
|
|
246
254
|
|
|
247
255
|
.saved-list-item h2 {
|
|
248
|
-
margin: 0 0
|
|
256
|
+
margin: 0 10px 0 0;
|
|
249
257
|
}
|
|
250
258
|
|
|
251
|
-
.saved-
|
|
252
|
-
|
|
259
|
+
.saved-list-item p {
|
|
260
|
+
margin: 10px 0 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.name-and-links {
|
|
264
|
+
display: flex;
|
|
265
|
+
flex-direction: row;
|
|
266
|
+
align-items: center;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.name-and-links a {
|
|
270
|
+
margin-right: 5px;
|
|
271
|
+
color: darkblue;
|
|
272
|
+
font-size: 16px;
|
|
273
|
+
text-decoration: none;
|
|
253
274
|
}
|
|
254
275
|
|
|
255
276
|
.cm-editor.cm-focused {
|
|
@@ -287,3 +308,17 @@ select {
|
|
|
287
308
|
color: #333;
|
|
288
309
|
font-size: 18px;
|
|
289
310
|
}
|
|
311
|
+
|
|
312
|
+
.loader {
|
|
313
|
+
border: 8px solid #eee; /* Light grey */
|
|
314
|
+
border-top: 8px solid #888; /* Blue */
|
|
315
|
+
border-radius: 50%;
|
|
316
|
+
width: 40px;
|
|
317
|
+
height: 40px;
|
|
318
|
+
animation: spin 2s linear infinite;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
@keyframes spin {
|
|
322
|
+
0% { transform: rotate(0deg); }
|
|
323
|
+
100% { transform: rotate(360deg); }
|
|
324
|
+
}
|
data/client/resources/sqlui.html
CHANGED
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
|
|
14
14
|
<div id="main-box" class="main-box" style="display:none">
|
|
15
15
|
<div class="tabs-box">
|
|
16
|
-
<h1 class="header"><a
|
|
16
|
+
<h1 class="header"><a id="header-link">SQLUI</a></h1>
|
|
17
17
|
<h1 id="server-name" class="server-name"></h1>
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
<
|
|
18
|
+
<a id="query-tab-button" class="tab-button">Query</a>
|
|
19
|
+
<a id="graph-tab-button" class="tab-button">Graph</a>
|
|
20
|
+
<a id="saved-tab-button" class="tab-button">Saved</a>
|
|
21
|
+
<a id="structure-tab-button" class="tab-button">Structure</a>
|
|
22
22
|
</div>
|
|
23
23
|
|
|
24
24
|
<div id="query-box" class="query-box tab-content-element graph-element query-element" style="display: none;">
|
|
@@ -26,8 +26,10 @@
|
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
28
|
<div id="submit-box" class="submit-box tab-content-element graph-element query-element" style="display: none;">
|
|
29
|
-
<input id="
|
|
30
|
-
<
|
|
29
|
+
<input id="cancel-button" class="submit-button" type="button" value="cancel"></input>
|
|
30
|
+
<div class="submit-fill"></div>
|
|
31
|
+
<input id="submit-current-button" class="submit-button" type="button" value="run selection (ctrl-enter)"></input>
|
|
32
|
+
<input id="submit-all-button" class="submit-button" type="button" value="run (ctrl-shift-enter)"></input>
|
|
31
33
|
</div>
|
|
32
34
|
|
|
33
35
|
<div id="result-box" class="result-box tab-content-element query-element" style="display: none;">
|
|
@@ -36,6 +38,10 @@
|
|
|
36
38
|
<div id="graph-box" class="graph-box tab-content-element graph-element" style="display: none;">
|
|
37
39
|
</div>
|
|
38
40
|
|
|
41
|
+
<div id="fetch-sql-box" class="fetch-sql-box tab-content-element graph-element query-element" style="display: none;">
|
|
42
|
+
<div id="result-loader" class="loader"></div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
39
45
|
<div id="saved-box" class="saved-box tab-content-element saved-element" style="display: none;">
|
|
40
46
|
</div>
|
|
41
47
|
|
|
@@ -55,7 +61,7 @@
|
|
|
55
61
|
</div>
|
|
56
62
|
|
|
57
63
|
<div id="status-box" class="status-box">
|
|
58
|
-
<div id="
|
|
64
|
+
<div id="result-status" class="status tab-content-element query-element"></div>
|
|
59
65
|
<div id="graph-status" class="status tab-content-element graph-element"></div>
|
|
60
66
|
<div id="saved-status" class="status tab-content-element saved-element"></div>
|
|
61
67
|
</div>
|
data/client/resources/sqlui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
(function () {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -23851,6 +23851,28 @@ var sqlui = (function (exports) {
|
|
|
23851
23851
|
/* global google */
|
|
23852
23852
|
|
|
23853
23853
|
function init (parent, onSubmit, onShiftSubmit) {
|
|
23854
|
+
document.getElementById('query-tab-button').addEventListener('click', function (event) {
|
|
23855
|
+
selectTab(event, 'query');
|
|
23856
|
+
});
|
|
23857
|
+
document.getElementById('saved-tab-button').addEventListener('click', function (event) {
|
|
23858
|
+
selectTab(event, 'saved');
|
|
23859
|
+
});
|
|
23860
|
+
document.getElementById('structure-tab-button').addEventListener('click', function (event) {
|
|
23861
|
+
selectTab(event, 'structure');
|
|
23862
|
+
});
|
|
23863
|
+
document.getElementById('graph-tab-button').addEventListener('click', function (event) {
|
|
23864
|
+
selectTab(event, 'graph');
|
|
23865
|
+
});
|
|
23866
|
+
document.getElementById('submit-all-button').addEventListener('click', function (event) {
|
|
23867
|
+
submitAll(event.target, event);
|
|
23868
|
+
});
|
|
23869
|
+
document.getElementById('submit-current-button').addEventListener('click', function (event) {
|
|
23870
|
+
submitCurrent(event.target, event);
|
|
23871
|
+
});
|
|
23872
|
+
document.getElementById('cancel-button').addEventListener('click', function (event) {
|
|
23873
|
+
clearResult();
|
|
23874
|
+
});
|
|
23875
|
+
|
|
23854
23876
|
const fixedHeightEditor = EditorView.theme({
|
|
23855
23877
|
'.cm-scroller': { height: '200px', overflow: 'auto', resize: 'vertical' }
|
|
23856
23878
|
});
|
|
@@ -23872,18 +23894,27 @@ var sqlui = (function (exports) {
|
|
|
23872
23894
|
}
|
|
23873
23895
|
|
|
23874
23896
|
function getSelection () {
|
|
23875
|
-
|
|
23897
|
+
const anchor = window.editorView.state.selection.main.anchor;
|
|
23898
|
+
const head = window.editorView.state.selection.main.head;
|
|
23899
|
+
if (anchor === head) {
|
|
23900
|
+
return `${anchor}`
|
|
23901
|
+
} else {
|
|
23902
|
+
return `${anchor}-${head}`
|
|
23903
|
+
}
|
|
23876
23904
|
}
|
|
23877
23905
|
|
|
23878
23906
|
function setSelection (selection) {
|
|
23879
|
-
|
|
23880
|
-
|
|
23881
|
-
|
|
23882
|
-
|
|
23883
|
-
|
|
23884
|
-
|
|
23885
|
-
|
|
23886
|
-
|
|
23907
|
+
let anchor;
|
|
23908
|
+
let head;
|
|
23909
|
+
if (selection.includes('-')) {
|
|
23910
|
+
selection = selection.split('-').map(x => parseInt(x));
|
|
23911
|
+
anchor = Math.min(selection[0], window.editorView.state.doc.length);
|
|
23912
|
+
head = Math.min(selection[1], window.editorView.state.doc.length);
|
|
23913
|
+
} else {
|
|
23914
|
+
anchor = Math.min(parseInt(selection), window.editorView.state.doc.length);
|
|
23915
|
+
head = anchor;
|
|
23916
|
+
}
|
|
23917
|
+
window.editorView.dispatch({ selection: { anchor, head } });
|
|
23887
23918
|
}
|
|
23888
23919
|
|
|
23889
23920
|
function focus () {
|
|
@@ -23904,30 +23935,62 @@ var sqlui = (function (exports) {
|
|
|
23904
23935
|
});
|
|
23905
23936
|
}
|
|
23906
23937
|
|
|
23907
|
-
function
|
|
23908
|
-
|
|
23938
|
+
function setTabInUrl (url, tab) {
|
|
23939
|
+
url.pathname = url.pathname.replace(/\/[^/]+$/, `/${tab}`);
|
|
23940
|
+
}
|
|
23941
|
+
|
|
23942
|
+
function getTabFromUrl (url) {
|
|
23943
|
+
const match = url.pathname.match(/\/([^/]+)$/);
|
|
23944
|
+
if (match && ['query', 'graph', 'structure', 'saved'].includes(match[1])) {
|
|
23945
|
+
return match[1]
|
|
23946
|
+
} else {
|
|
23947
|
+
throw new Error(`invalid tab: ${url.pathname}`)
|
|
23948
|
+
}
|
|
23949
|
+
}
|
|
23950
|
+
|
|
23951
|
+
function updateTabs () {
|
|
23909
23952
|
const url = new URL(window.location);
|
|
23910
|
-
|
|
23911
|
-
|
|
23912
|
-
|
|
23913
|
-
|
|
23914
|
-
|
|
23915
|
-
|
|
23916
|
-
|
|
23917
|
-
|
|
23918
|
-
|
|
23919
|
-
|
|
23953
|
+
setTabInUrl(url, 'graph');
|
|
23954
|
+
document.getElementById('graph-tab-button').href = url.pathname + url.search;
|
|
23955
|
+
setTabInUrl(url, 'saved');
|
|
23956
|
+
document.getElementById('saved-tab-button').href = url.pathname + url.search;
|
|
23957
|
+
setTabInUrl(url, 'structure');
|
|
23958
|
+
document.getElementById('structure-tab-button').href = url.pathname + url.search;
|
|
23959
|
+
setTabInUrl(url, 'query');
|
|
23960
|
+
document.getElementById('query-tab-button').href = url.pathname + url.search;
|
|
23961
|
+
}
|
|
23962
|
+
|
|
23963
|
+
function selectTab (event, tab) {
|
|
23964
|
+
const url = new URL(window.location);
|
|
23965
|
+
setTabInUrl(url, tab);
|
|
23966
|
+
route(event.target, event, url);
|
|
23967
|
+
}
|
|
23968
|
+
|
|
23969
|
+
function route (target = null, event = null, url = null) {
|
|
23970
|
+
if (url) {
|
|
23971
|
+
if (event) {
|
|
23972
|
+
event.preventDefault();
|
|
23973
|
+
if (!(target instanceof EditorView && event instanceof KeyboardEvent)) {
|
|
23974
|
+
if (event.shiftKey) {
|
|
23975
|
+
window.open(url).focus();
|
|
23976
|
+
return
|
|
23977
|
+
}
|
|
23978
|
+
if (event.metaKey) {
|
|
23979
|
+
window.open(url, '_blank').focus();
|
|
23980
|
+
return
|
|
23981
|
+
}
|
|
23920
23982
|
}
|
|
23921
23983
|
}
|
|
23922
|
-
|
|
23923
|
-
if (tab !== 'query') {
|
|
23924
|
-
url.searchParams.set('tab', tab);
|
|
23984
|
+
if (url.href !== window.location.href) {
|
|
23925
23985
|
window.history.pushState({}, '', url);
|
|
23926
|
-
return route()
|
|
23927
23986
|
}
|
|
23987
|
+
} else {
|
|
23988
|
+
url = new URL(window.location);
|
|
23928
23989
|
}
|
|
23990
|
+
updateTabs();
|
|
23991
|
+
window.tab = getTabFromUrl(url);
|
|
23929
23992
|
|
|
23930
|
-
const tabElement = document.getElementById(`${tab}-tab-button`);
|
|
23993
|
+
const tabElement = document.getElementById(`${window.tab}-tab-button`);
|
|
23931
23994
|
Array.prototype.forEach.call(document.getElementsByClassName('selected-tab-button'), function (selected) {
|
|
23932
23995
|
selected.classList.remove('selected-tab-button');
|
|
23933
23996
|
selected.classList.add('tab-button');
|
|
@@ -23939,9 +24002,9 @@ var sqlui = (function (exports) {
|
|
|
23939
24002
|
selected.style.display = 'none';
|
|
23940
24003
|
});
|
|
23941
24004
|
|
|
23942
|
-
switch (tab) {
|
|
24005
|
+
switch (window.tab) {
|
|
23943
24006
|
case 'query':
|
|
23944
|
-
|
|
24007
|
+
selectResultTab();
|
|
23945
24008
|
break
|
|
23946
24009
|
case 'graph':
|
|
23947
24010
|
selectGraphTab();
|
|
@@ -23953,7 +24016,7 @@ var sqlui = (function (exports) {
|
|
|
23953
24016
|
selectStructureTab();
|
|
23954
24017
|
break
|
|
23955
24018
|
default:
|
|
23956
|
-
throw new Error(`Unexpected tab: ${tab}`)
|
|
24019
|
+
throw new Error(`Unexpected tab: ${window.tab}`)
|
|
23957
24020
|
}
|
|
23958
24021
|
}
|
|
23959
24022
|
|
|
@@ -24096,42 +24159,30 @@ var sqlui = (function (exports) {
|
|
|
24096
24159
|
}
|
|
24097
24160
|
|
|
24098
24161
|
function selectGraphTab () {
|
|
24099
|
-
|
|
24100
|
-
|
|
24101
|
-
|
|
24102
|
-
|
|
24103
|
-
|
|
24104
|
-
|
|
24105
|
-
|
|
24106
|
-
});
|
|
24162
|
+
document.getElementById('query-box').style.display = 'flex';
|
|
24163
|
+
document.getElementById('submit-box').style.display = 'flex';
|
|
24164
|
+
document.getElementById('graph-box').style.display = 'flex';
|
|
24165
|
+
document.getElementById('graph-status').style.display = 'flex';
|
|
24166
|
+
document.getElementById('fetch-sql-box').style.display = 'none';
|
|
24167
|
+
document.getElementById('cancel-button').style.display = 'none';
|
|
24168
|
+
maybeFetchResult();
|
|
24107
24169
|
|
|
24108
24170
|
const selection = getSelection();
|
|
24109
24171
|
focus();
|
|
24110
24172
|
setSelection(selection);
|
|
24111
24173
|
}
|
|
24112
24174
|
|
|
24113
|
-
function
|
|
24114
|
-
|
|
24115
|
-
|
|
24116
|
-
|
|
24117
|
-
|
|
24175
|
+
function selectResultTab () {
|
|
24176
|
+
document.getElementById('query-box').style.display = 'flex';
|
|
24177
|
+
document.getElementById('submit-box').style.display = 'flex';
|
|
24178
|
+
document.getElementById('result-box').style.display = 'flex';
|
|
24179
|
+
document.getElementById('result-status').style.display = 'flex';
|
|
24180
|
+
document.getElementById('fetch-sql-box').style.display = 'none';
|
|
24181
|
+
document.getElementById('cancel-button').style.display = 'none';
|
|
24118
24182
|
const selection = getSelection();
|
|
24119
24183
|
focus();
|
|
24120
24184
|
setSelection(selection);
|
|
24121
|
-
|
|
24122
|
-
loadQueryOrGraphTab(loadQueryResult, queryErrorCallback('query-status'));
|
|
24123
|
-
}
|
|
24124
|
-
|
|
24125
|
-
function queryErrorCallback (statusElementId) {
|
|
24126
|
-
const statusElement = document.getElementById(statusElementId);
|
|
24127
|
-
return function (message, error) {
|
|
24128
|
-
if (error) {
|
|
24129
|
-
console.log(`${message}\n${error}`);
|
|
24130
|
-
statusElement.innerText = `error: ${message} (check console)`;
|
|
24131
|
-
} else {
|
|
24132
|
-
statusElement.innerText = `error: ${message}`;
|
|
24133
|
-
}
|
|
24134
|
-
}
|
|
24185
|
+
maybeFetchResult();
|
|
24135
24186
|
}
|
|
24136
24187
|
|
|
24137
24188
|
function selectSavedTab () {
|
|
@@ -24149,29 +24200,54 @@ var sqlui = (function (exports) {
|
|
|
24149
24200
|
}
|
|
24150
24201
|
|
|
24151
24202
|
const saved = window.metadata.saved;
|
|
24152
|
-
if (saved
|
|
24203
|
+
if (Object.keys(saved).length === 1) {
|
|
24153
24204
|
setSavedStatus('1 file');
|
|
24154
24205
|
} else {
|
|
24155
24206
|
setSavedStatus(`${saved.length} files`);
|
|
24156
24207
|
}
|
|
24157
|
-
saved.forEach(file => {
|
|
24158
|
-
const
|
|
24159
|
-
|
|
24160
|
-
|
|
24208
|
+
Object.values(saved).forEach(file => {
|
|
24209
|
+
const viewUrl = new URL(window.location.origin + window.location.pathname);
|
|
24210
|
+
setTabInUrl(viewUrl, 'query');
|
|
24211
|
+
viewUrl.searchParams.set('file', file.filename);
|
|
24212
|
+
|
|
24213
|
+
const viewLinkElement = document.createElement('a');
|
|
24214
|
+
viewLinkElement.classList.add('view-link');
|
|
24215
|
+
viewLinkElement.innerText = 'view';
|
|
24216
|
+
viewLinkElement.href = viewUrl.pathname + viewUrl.search;
|
|
24217
|
+
viewLinkElement.addEventListener('click', function (event) {
|
|
24161
24218
|
clearResult();
|
|
24162
|
-
|
|
24163
|
-
|
|
24164
|
-
|
|
24165
|
-
|
|
24166
|
-
|
|
24167
|
-
|
|
24219
|
+
route(event.target, event, viewUrl);
|
|
24220
|
+
});
|
|
24221
|
+
|
|
24222
|
+
const runUrl = new URL(window.location.origin + window.location.pathname);
|
|
24223
|
+
setTabInUrl(runUrl, 'query');
|
|
24224
|
+
runUrl.searchParams.set('file', file.filename);
|
|
24225
|
+
runUrl.searchParams.set('run', 'true');
|
|
24226
|
+
|
|
24227
|
+
const runLinkElement = document.createElement('a');
|
|
24228
|
+
runLinkElement.classList.add('run-link');
|
|
24229
|
+
runLinkElement.innerText = 'run';
|
|
24230
|
+
runLinkElement.href = runUrl.pathname + runUrl.search;
|
|
24231
|
+
runLinkElement.addEventListener('click', function (event) {
|
|
24232
|
+
clearResult();
|
|
24233
|
+
route(event.target, event, runUrl);
|
|
24168
24234
|
});
|
|
24235
|
+
|
|
24169
24236
|
const nameElement = document.createElement('h2');
|
|
24170
24237
|
nameElement.innerText = file.filename;
|
|
24171
|
-
|
|
24238
|
+
|
|
24239
|
+
const nameAndLinksElement = document.createElement('div');
|
|
24240
|
+
nameAndLinksElement.classList.add('name-and-links');
|
|
24241
|
+
nameAndLinksElement.appendChild(nameElement);
|
|
24242
|
+
nameAndLinksElement.appendChild(viewLinkElement);
|
|
24243
|
+
nameAndLinksElement.appendChild(runLinkElement);
|
|
24172
24244
|
|
|
24173
24245
|
const descriptionElement = document.createElement('p');
|
|
24174
24246
|
descriptionElement.innerText = file.description;
|
|
24247
|
+
|
|
24248
|
+
const divElement = document.createElement('div');
|
|
24249
|
+
divElement.classList.add('saved-list-item');
|
|
24250
|
+
divElement.appendChild(nameAndLinksElement);
|
|
24175
24251
|
divElement.appendChild(descriptionElement);
|
|
24176
24252
|
|
|
24177
24253
|
savedElement.appendChild(divElement);
|
|
@@ -24179,59 +24255,71 @@ var sqlui = (function (exports) {
|
|
|
24179
24255
|
window.savedLoaded = true;
|
|
24180
24256
|
}
|
|
24181
24257
|
|
|
24182
|
-
function submitAll () {
|
|
24183
|
-
submit(
|
|
24258
|
+
function submitAll (target, event) {
|
|
24259
|
+
submit(target, event);
|
|
24184
24260
|
}
|
|
24185
24261
|
|
|
24186
|
-
function submitCurrent () {
|
|
24187
|
-
submit(getSelection());
|
|
24262
|
+
function submitCurrent (target, event) {
|
|
24263
|
+
submit(target, event, getSelection());
|
|
24188
24264
|
}
|
|
24189
24265
|
|
|
24190
|
-
function submit (selection) {
|
|
24266
|
+
function submit (target, event, selection = null) {
|
|
24267
|
+
clearResult();
|
|
24191
24268
|
const url = new URL(window.location);
|
|
24192
|
-
if (selection) {
|
|
24193
|
-
url.searchParams.set('selection', selection.join(':'));
|
|
24194
|
-
} else {
|
|
24195
|
-
url.searchParams.delete('selection');
|
|
24196
|
-
}
|
|
24197
|
-
|
|
24198
24269
|
let sql = getValue().trim();
|
|
24199
24270
|
sql = sql === '' ? null : sql;
|
|
24200
24271
|
|
|
24272
|
+
url.searchParams.set('run', 'true');
|
|
24273
|
+
|
|
24201
24274
|
if (url.searchParams.has('file')) {
|
|
24202
|
-
url.searchParams.
|
|
24203
|
-
|
|
24204
|
-
|
|
24275
|
+
if (window.metadata.saved[url.searchParams.get('file')].contents !== getValue()) {
|
|
24276
|
+
url.searchParams.delete('file');
|
|
24277
|
+
url.searchParams.set('sql', sql);
|
|
24278
|
+
}
|
|
24205
24279
|
} else {
|
|
24206
24280
|
let sqlParam = url.searchParams.get('sql')?.trim();
|
|
24207
24281
|
sqlParam = sqlParam === '' ? null : sqlParam;
|
|
24208
24282
|
|
|
24209
|
-
if (sqlParam !== sql) {
|
|
24210
|
-
|
|
24211
|
-
|
|
24212
|
-
|
|
24213
|
-
|
|
24214
|
-
|
|
24215
|
-
|
|
24216
|
-
|
|
24283
|
+
if (sqlParam !== sql && sql === null) {
|
|
24284
|
+
url.searchParams.delete('sql');
|
|
24285
|
+
} else if (sqlParam !== sql) {
|
|
24286
|
+
url.searchParams.set('sql', sql);
|
|
24287
|
+
}
|
|
24288
|
+
}
|
|
24289
|
+
|
|
24290
|
+
if (sql) {
|
|
24291
|
+
if (selection) {
|
|
24292
|
+
url.searchParams.set('selection', selection);
|
|
24217
24293
|
} else {
|
|
24218
|
-
|
|
24294
|
+
url.searchParams.delete('selection');
|
|
24219
24295
|
}
|
|
24296
|
+
} else {
|
|
24297
|
+
url.searchParams.delete('selection');
|
|
24298
|
+
url.searchParams.delete('sql');
|
|
24299
|
+
url.searchParams.delete('file');
|
|
24300
|
+
url.searchParams.delete('run');
|
|
24220
24301
|
}
|
|
24221
|
-
|
|
24222
|
-
route();
|
|
24302
|
+
|
|
24303
|
+
route(target, event, url);
|
|
24223
24304
|
}
|
|
24224
24305
|
|
|
24225
24306
|
function clearResult () {
|
|
24226
|
-
|
|
24227
|
-
|
|
24307
|
+
const existingFetch = window.sqlFetch;
|
|
24308
|
+
if (existingFetch?.state === 'pending') {
|
|
24309
|
+
existingFetch.state = 'aborted';
|
|
24310
|
+
existingFetch.fetchController.abort();
|
|
24311
|
+
}
|
|
24312
|
+
window.sqlFetch = null;
|
|
24313
|
+
|
|
24228
24314
|
clearGraphBox();
|
|
24315
|
+
clearGraphStatus();
|
|
24316
|
+
|
|
24229
24317
|
clearResultBox();
|
|
24230
|
-
|
|
24318
|
+
clearResultStatus();
|
|
24231
24319
|
}
|
|
24232
24320
|
|
|
24233
|
-
function
|
|
24234
|
-
document.getElementById('
|
|
24321
|
+
function clearResultStatus () {
|
|
24322
|
+
document.getElementById('result-status').innerText = '';
|
|
24235
24323
|
}
|
|
24236
24324
|
|
|
24237
24325
|
function clearGraphStatus () {
|
|
@@ -24252,7 +24340,7 @@ var sqlui = (function (exports) {
|
|
|
24252
24340
|
}
|
|
24253
24341
|
}
|
|
24254
24342
|
|
|
24255
|
-
function fetchSql (
|
|
24343
|
+
function fetchSql (sqlFetch, selection, callback) {
|
|
24256
24344
|
fetch('query', {
|
|
24257
24345
|
headers: {
|
|
24258
24346
|
Accept: 'application/json',
|
|
@@ -24260,137 +24348,173 @@ var sqlui = (function (exports) {
|
|
|
24260
24348
|
},
|
|
24261
24349
|
method: 'POST',
|
|
24262
24350
|
body: JSON.stringify({
|
|
24263
|
-
sql,
|
|
24351
|
+
sql: sqlFetch.sql,
|
|
24264
24352
|
selection
|
|
24265
|
-
})
|
|
24353
|
+
}),
|
|
24354
|
+
signal: sqlFetch.fetchController.signal
|
|
24266
24355
|
})
|
|
24267
24356
|
.then((response) => {
|
|
24268
24357
|
const contentType = response.headers.get('content-type');
|
|
24269
24358
|
if (contentType && contentType.indexOf('application/json') !== -1) {
|
|
24270
24359
|
response.json().then((result) => {
|
|
24271
24360
|
if (result?.query) {
|
|
24272
|
-
|
|
24273
|
-
|
|
24274
|
-
errorCallback(result.error, result.stacktrace);
|
|
24275
|
-
} else if (result) {
|
|
24276
|
-
errorCallback('failed to execute query', result.toString());
|
|
24361
|
+
sqlFetch.state = 'success';
|
|
24362
|
+
sqlFetch.result = result;
|
|
24277
24363
|
} else {
|
|
24278
|
-
|
|
24364
|
+
sqlFetch.state = 'error';
|
|
24365
|
+
if (result?.error) {
|
|
24366
|
+
sqlFetch.error_message = result.error;
|
|
24367
|
+
sqlFetch.error_details = result.stacktrace;
|
|
24368
|
+
} else if (result) {
|
|
24369
|
+
sqlFetch.error_message = 'failed to execute query';
|
|
24370
|
+
sqlFetch.error_details = result.toString();
|
|
24371
|
+
} else {
|
|
24372
|
+
sqlFetch.error_message = 'failed to execute query';
|
|
24373
|
+
}
|
|
24279
24374
|
}
|
|
24375
|
+
callback(sqlFetch);
|
|
24280
24376
|
});
|
|
24281
24377
|
} else {
|
|
24282
24378
|
response.text().then((result) => {
|
|
24283
|
-
|
|
24379
|
+
sqlFetch.state = 'error';
|
|
24380
|
+
sqlFetch.error_message = 'failed to execute query';
|
|
24381
|
+
sqlFetch.error_details = result;
|
|
24382
|
+
callback(sqlFetch);
|
|
24284
24383
|
});
|
|
24285
24384
|
}
|
|
24286
24385
|
})
|
|
24287
24386
|
.catch(function (error) {
|
|
24288
|
-
|
|
24289
|
-
|
|
24290
|
-
|
|
24291
|
-
|
|
24292
|
-
function fetchFile (name, successCallback, errorCallback) {
|
|
24293
|
-
fetch(`query_file?file=${name}`, {
|
|
24294
|
-
headers: {
|
|
24295
|
-
Accept: 'application/json'
|
|
24296
|
-
},
|
|
24297
|
-
method: 'GET'
|
|
24298
|
-
})
|
|
24299
|
-
.then((response) => {
|
|
24300
|
-
const contentType = response.headers.get('content-type');
|
|
24301
|
-
if (contentType && contentType.indexOf('application/json') !== -1) {
|
|
24302
|
-
response.json().then((result) => {
|
|
24303
|
-
if (result?.query) {
|
|
24304
|
-
successCallback(result);
|
|
24305
|
-
} else if (result?.error) {
|
|
24306
|
-
errorCallback(result.error, result.stacktrace);
|
|
24307
|
-
} else if (result) {
|
|
24308
|
-
errorCallback('failed to load file ', result.toString());
|
|
24309
|
-
} else {
|
|
24310
|
-
errorCallback('failed to load file');
|
|
24311
|
-
}
|
|
24312
|
-
});
|
|
24313
|
-
} else {
|
|
24314
|
-
errorCallback('failed to load file', response.toString());
|
|
24387
|
+
if (sqlFetch.state === 'pending') {
|
|
24388
|
+
sqlFetch.state = 'error';
|
|
24389
|
+
sqlFetch.error_message = 'failed to execute query';
|
|
24390
|
+
sqlFetch.error_details = error;
|
|
24315
24391
|
}
|
|
24316
|
-
|
|
24317
|
-
.catch(function (error) {
|
|
24318
|
-
errorCallback('failed to load file', error.stack);
|
|
24392
|
+
callback(sqlFetch);
|
|
24319
24393
|
});
|
|
24320
24394
|
}
|
|
24321
24395
|
|
|
24322
|
-
function
|
|
24323
|
-
const
|
|
24396
|
+
function maybeFetchResult () {
|
|
24397
|
+
const url = new URL(window.location);
|
|
24398
|
+
const params = url.searchParams;
|
|
24324
24399
|
const sql = params.get('sql');
|
|
24325
24400
|
const file = params.get('file');
|
|
24326
|
-
const selection = params.
|
|
24401
|
+
const selection = params.get('selection');
|
|
24402
|
+
const run = ['1', 'true'].includes(params.get('run')?.toLowerCase());
|
|
24327
24403
|
|
|
24328
|
-
if (params.has('
|
|
24329
|
-
callback();
|
|
24330
|
-
return
|
|
24331
|
-
} else if (params.has('file') && window.result && file === window.result.file) {
|
|
24332
|
-
callback();
|
|
24333
|
-
return
|
|
24334
|
-
}
|
|
24335
|
-
|
|
24336
|
-
if (params.has('file') && params.has('sql') && selection === window.result.selection) {
|
|
24404
|
+
if (params.has('file') && params.has('sql')) {
|
|
24337
24405
|
// TODO: show an error.
|
|
24338
24406
|
throw new Error('You can only specify a file or sql, not both.')
|
|
24339
24407
|
}
|
|
24340
24408
|
|
|
24409
|
+
const sqlFetch = {
|
|
24410
|
+
fetchController: new AbortController(),
|
|
24411
|
+
state: 'pending',
|
|
24412
|
+
sql,
|
|
24413
|
+
file,
|
|
24414
|
+
selection
|
|
24415
|
+
};
|
|
24416
|
+
|
|
24417
|
+
if (params.has('file')) {
|
|
24418
|
+
const fileDetails = window.metadata.saved[params.get('file')];
|
|
24419
|
+
if (!fileDetails) {
|
|
24420
|
+
throw new Error(`no such file: ${params.get('file')}`)
|
|
24421
|
+
}
|
|
24422
|
+
sqlFetch.file = file;
|
|
24423
|
+
sqlFetch.sql = fileDetails.contents;
|
|
24424
|
+
} else if (params.has('sql')) {
|
|
24425
|
+
sqlFetch.sql = sql;
|
|
24426
|
+
}
|
|
24427
|
+
|
|
24428
|
+
const existingRequest = window.sqlFetch;
|
|
24429
|
+
if (existingRequest) {
|
|
24430
|
+
const selectionMatches = selection === existingRequest.selection;
|
|
24431
|
+
const sqlMatches = params.has('sql') && sql === existingRequest.sql;
|
|
24432
|
+
const fileMatches = params.has('file') && file === existingRequest.file;
|
|
24433
|
+
const queryMatches = sqlMatches || fileMatches;
|
|
24434
|
+
if (selectionMatches && queryMatches) {
|
|
24435
|
+
displaySqlFetch(existingRequest);
|
|
24436
|
+
if (params.has('selection')) {
|
|
24437
|
+
focus();
|
|
24438
|
+
setSelection(selection);
|
|
24439
|
+
}
|
|
24440
|
+
return
|
|
24441
|
+
}
|
|
24442
|
+
}
|
|
24443
|
+
|
|
24341
24444
|
clearResult();
|
|
24342
24445
|
|
|
24343
|
-
if (params.has('sql')) {
|
|
24344
|
-
setValue(sql);
|
|
24345
|
-
|
|
24346
|
-
|
|
24347
|
-
|
|
24348
|
-
|
|
24349
|
-
|
|
24350
|
-
|
|
24351
|
-
|
|
24352
|
-
window.result = result;
|
|
24353
|
-
setValue(result.query);
|
|
24354
|
-
callback();
|
|
24355
|
-
}, errorCallback);
|
|
24446
|
+
if (params.has('sql') || params.has('file')) {
|
|
24447
|
+
setValue(sqlFetch.sql);
|
|
24448
|
+
if (run) {
|
|
24449
|
+
url.searchParams.delete('run');
|
|
24450
|
+
window.history.replaceState({}, '', url);
|
|
24451
|
+
window.sqlFetch = sqlFetch;
|
|
24452
|
+
displaySqlFetch(sqlFetch);
|
|
24453
|
+
fetchSql(sqlFetch, selection, displaySqlFetch);
|
|
24454
|
+
}
|
|
24356
24455
|
}
|
|
24357
24456
|
if (params.has('selection')) {
|
|
24358
24457
|
focus();
|
|
24359
|
-
setSelection(
|
|
24458
|
+
setSelection(selection);
|
|
24360
24459
|
}
|
|
24361
24460
|
}
|
|
24362
24461
|
|
|
24363
|
-
function
|
|
24364
|
-
|
|
24365
|
-
|
|
24462
|
+
function displaySqlFetchInResultTab (fetch) {
|
|
24463
|
+
if (fetch.state === 'pending') {
|
|
24464
|
+
clearResultBox();
|
|
24465
|
+
document.getElementById('cancel-button').style.display = 'flex';
|
|
24466
|
+
document.getElementById('result-box').style.display = 'none';
|
|
24467
|
+
document.getElementById('fetch-sql-box').style.display = 'flex';
|
|
24468
|
+
return
|
|
24469
|
+
}
|
|
24470
|
+
|
|
24471
|
+
document.getElementById('cancel-button').style.display = 'none';
|
|
24472
|
+
document.getElementById('fetch-sql-box').style.display = 'none';
|
|
24473
|
+
document.getElementById('result-box').style.display = 'flex';
|
|
24474
|
+
|
|
24475
|
+
if (fetch.state === 'aborted') {
|
|
24476
|
+
clearResultBox();
|
|
24366
24477
|
return
|
|
24367
24478
|
}
|
|
24368
24479
|
|
|
24369
|
-
|
|
24480
|
+
if (fetch.state === 'error') {
|
|
24481
|
+
clearResultBox();
|
|
24482
|
+
displaySqlFetchError('result-status', fetch.error_message, fetch.error_details);
|
|
24483
|
+
return
|
|
24484
|
+
}
|
|
24370
24485
|
|
|
24371
|
-
|
|
24372
|
-
|
|
24373
|
-
|
|
24486
|
+
if (fetch.state !== 'success') {
|
|
24487
|
+
throw new Error(`unexpected fetch sql request status: ${fetch.status}`)
|
|
24488
|
+
}
|
|
24489
|
+
|
|
24490
|
+
if (document.getElementById('result-table')) {
|
|
24491
|
+
// Results already displayed.
|
|
24492
|
+
return
|
|
24493
|
+
}
|
|
24494
|
+
|
|
24495
|
+
clearResultBox();
|
|
24496
|
+
displaySqlFetchResultStatus('result-status', fetch.result);
|
|
24374
24497
|
|
|
24375
24498
|
const tableElement = document.createElement('table');
|
|
24499
|
+
tableElement.id = 'result-table';
|
|
24376
24500
|
const theadElement = document.createElement('thead');
|
|
24377
24501
|
const headerElement = document.createElement('tr');
|
|
24378
24502
|
const tbodyElement = document.createElement('tbody');
|
|
24379
24503
|
theadElement.appendChild(headerElement);
|
|
24380
24504
|
tableElement.appendChild(theadElement);
|
|
24381
24505
|
tableElement.appendChild(tbodyElement);
|
|
24382
|
-
|
|
24506
|
+
document.getElementById('result-box').appendChild(tableElement);
|
|
24383
24507
|
|
|
24384
|
-
|
|
24508
|
+
fetch.result.columns.forEach(column => {
|
|
24385
24509
|
const template = document.createElement('template');
|
|
24386
24510
|
template.innerHTML = `<th class="cell">${column}</th>`;
|
|
24387
24511
|
headerElement.appendChild(template.content.firstChild);
|
|
24388
24512
|
});
|
|
24389
|
-
if (
|
|
24513
|
+
if (fetch.result.columns.length > 0) {
|
|
24390
24514
|
headerElement.appendChild(document.createElement('th'));
|
|
24391
24515
|
}
|
|
24392
24516
|
let highlight = false;
|
|
24393
|
-
|
|
24517
|
+
fetch.result.rows.forEach(function (row) {
|
|
24394
24518
|
const rowElement = document.createElement('tr');
|
|
24395
24519
|
if (highlight) {
|
|
24396
24520
|
rowElement.classList.add('highlighted-row');
|
|
@@ -24404,29 +24528,72 @@ var sqlui = (function (exports) {
|
|
|
24404
24528
|
});
|
|
24405
24529
|
rowElement.appendChild(document.createElement('td'));
|
|
24406
24530
|
});
|
|
24531
|
+
}
|
|
24407
24532
|
|
|
24408
|
-
|
|
24533
|
+
function displaySqlFetch (fetch) {
|
|
24534
|
+
if (window.tab === 'query') {
|
|
24535
|
+
displaySqlFetchInResultTab(fetch);
|
|
24536
|
+
} else if (window.tab === 'graph') {
|
|
24537
|
+
displaySqlFetchInGraphTab(fetch);
|
|
24538
|
+
}
|
|
24539
|
+
}
|
|
24540
|
+
|
|
24541
|
+
function displaySqlFetchError (statusElementId, message, details) {
|
|
24542
|
+
const statusElement = document.getElementById(statusElementId);
|
|
24543
|
+
if (details) {
|
|
24544
|
+
console.log(`${message}\n${details}`);
|
|
24545
|
+
statusElement.innerText = `error: ${message} (check console)`;
|
|
24546
|
+
} else {
|
|
24547
|
+
statusElement.innerText = `error: ${message}`;
|
|
24548
|
+
}
|
|
24409
24549
|
}
|
|
24410
24550
|
|
|
24411
|
-
function
|
|
24412
|
-
|
|
24551
|
+
function displaySqlFetchInGraphTab (fetch) {
|
|
24552
|
+
if (fetch.state === 'pending') {
|
|
24553
|
+
clearGraphBox();
|
|
24554
|
+
document.getElementById('cancel-button').style.display = 'flex';
|
|
24555
|
+
document.getElementById('graph-box').style.display = 'none';
|
|
24556
|
+
document.getElementById('fetch-sql-box').style.display = 'flex';
|
|
24557
|
+
return
|
|
24558
|
+
}
|
|
24559
|
+
|
|
24560
|
+
document.getElementById('cancel-button').style.display = 'none';
|
|
24561
|
+
document.getElementById('fetch-sql-box').style.display = 'none';
|
|
24562
|
+
document.getElementById('graph-box').style.display = 'flex';
|
|
24563
|
+
|
|
24564
|
+
if (fetch.state === 'aborted') {
|
|
24565
|
+
clearGraphBox();
|
|
24566
|
+
return
|
|
24567
|
+
}
|
|
24413
24568
|
|
|
24414
|
-
if (
|
|
24569
|
+
if (fetch.state === 'error') {
|
|
24570
|
+
clearGraphBox();
|
|
24571
|
+
displaySqlFetchError('graph-status', fetch.error_message, fetch.error_details);
|
|
24415
24572
|
return
|
|
24416
24573
|
}
|
|
24417
|
-
|
|
24574
|
+
|
|
24575
|
+
if (fetch.state !== 'success') {
|
|
24576
|
+
throw new Error(`unexpected fetch sql request status: ${fetch.status}`)
|
|
24577
|
+
}
|
|
24578
|
+
clearGraphBox();
|
|
24579
|
+
displaySqlFetchResultStatus('graph-status', fetch.result);
|
|
24580
|
+
|
|
24581
|
+
if (!fetch.result.rows) {
|
|
24582
|
+
return
|
|
24583
|
+
}
|
|
24584
|
+
if (fetch.result.rows.length === 0 || fetch.result.columns.length < 2) {
|
|
24418
24585
|
return
|
|
24419
24586
|
}
|
|
24420
24587
|
const dataTable = new google.visualization.DataTable();
|
|
24421
|
-
|
|
24422
|
-
dataTable.addColumn(
|
|
24588
|
+
fetch.result.columns.forEach((column, index) => {
|
|
24589
|
+
dataTable.addColumn(fetch.result.column_types[index], column);
|
|
24423
24590
|
});
|
|
24424
24591
|
|
|
24425
|
-
|
|
24592
|
+
fetch.result.rows.forEach((row) => {
|
|
24426
24593
|
const rowValues = row.map((value, index) => {
|
|
24427
|
-
if (
|
|
24594
|
+
if (fetch.result.column_types[index] === 'date' || fetch.result.column_types[index] === 'datetime') {
|
|
24428
24595
|
return new Date(value)
|
|
24429
|
-
} else if (
|
|
24596
|
+
} else if (fetch.result.column_types[index] === 'timeofday') {
|
|
24430
24597
|
// TODO: This should be hour, minute, second, milliseconds
|
|
24431
24598
|
return [0, 0, 0, 0]
|
|
24432
24599
|
} else {
|
|
@@ -24436,36 +24603,20 @@ var sqlui = (function (exports) {
|
|
|
24436
24603
|
dataTable.addRow(rowValues);
|
|
24437
24604
|
});
|
|
24438
24605
|
|
|
24439
|
-
const
|
|
24440
|
-
|
|
24441
|
-
const chart = new google.visualization.LineChart(graphBoxElement);
|
|
24606
|
+
const chart = new google.visualization.LineChart(document.getElementById('graph-box'));
|
|
24442
24607
|
const options = {
|
|
24443
24608
|
hAxis: {
|
|
24444
|
-
title:
|
|
24609
|
+
title: fetch.result.columns[0]
|
|
24445
24610
|
},
|
|
24446
24611
|
vAxis: {
|
|
24447
|
-
title:
|
|
24612
|
+
title: fetch.result.columns[1]
|
|
24448
24613
|
}
|
|
24449
24614
|
};
|
|
24450
24615
|
chart.draw(dataTable, options);
|
|
24451
24616
|
}
|
|
24452
24617
|
|
|
24453
|
-
function
|
|
24454
|
-
const statusElement = document.getElementById(
|
|
24455
|
-
|
|
24456
|
-
if (result.total_rows === 1) {
|
|
24457
|
-
statusElement.innerText = `${result.total_rows} row`;
|
|
24458
|
-
} else {
|
|
24459
|
-
statusElement.innerText = `${result.total_rows} rows`;
|
|
24460
|
-
}
|
|
24461
|
-
|
|
24462
|
-
if (result.total_rows > result.rows.length) {
|
|
24463
|
-
statusElement.innerText += ` (truncated to ${result.rows.length})`;
|
|
24464
|
-
}
|
|
24465
|
-
}
|
|
24466
|
-
|
|
24467
|
-
function setQueryStatus (result) {
|
|
24468
|
-
const statusElement = document.getElementById('query-status');
|
|
24618
|
+
function displaySqlFetchResultStatus (statusElementId, result) {
|
|
24619
|
+
const statusElement = document.getElementById(statusElementId);
|
|
24469
24620
|
|
|
24470
24621
|
if (result.total_rows === 1) {
|
|
24471
24622
|
statusElement.innerText = `${result.total_rows} row`;
|
|
@@ -24487,24 +24638,24 @@ var sqlui = (function (exports) {
|
|
|
24487
24638
|
});
|
|
24488
24639
|
|
|
24489
24640
|
window.addEventListener('resize', function (event) {
|
|
24490
|
-
if (window.tab === 'graph' && window.result) {
|
|
24641
|
+
if (window.tab === 'graph' && window.sqlFetch.result) {
|
|
24491
24642
|
clearGraphBox();
|
|
24492
|
-
|
|
24643
|
+
displaySqlFetchInGraphTab(window.sqlFetch);
|
|
24493
24644
|
}
|
|
24494
24645
|
});
|
|
24495
24646
|
|
|
24496
|
-
function route () {
|
|
24497
|
-
selectTab(new URLSearchParams(window.location.search).get('tab') || 'query');
|
|
24498
|
-
}
|
|
24499
|
-
|
|
24500
24647
|
window.onload = function () {
|
|
24501
|
-
|
|
24502
|
-
|
|
24503
|
-
|
|
24504
|
-
|
|
24505
|
-
|
|
24506
|
-
|
|
24507
|
-
|
|
24648
|
+
Promise.all([
|
|
24649
|
+
google.charts.load('current', { packages: ['corechart', 'line'] }),
|
|
24650
|
+
fetch('metadata', {
|
|
24651
|
+
headers: {
|
|
24652
|
+
Accept: 'application/json'
|
|
24653
|
+
},
|
|
24654
|
+
method: 'GET'
|
|
24655
|
+
})
|
|
24656
|
+
])
|
|
24657
|
+
.then((results) => {
|
|
24658
|
+
const response = results[1];
|
|
24508
24659
|
const contentType = response.headers.get('content-type');
|
|
24509
24660
|
if (contentType && contentType.indexOf('application/json') !== -1) {
|
|
24510
24661
|
return response.json().then((result) => {
|
|
@@ -24525,7 +24676,9 @@ var sqlui = (function (exports) {
|
|
|
24525
24676
|
window.metadata = result;
|
|
24526
24677
|
document.getElementById('loading-box').style.display = 'none';
|
|
24527
24678
|
document.getElementById('main-box').style.display = 'flex';
|
|
24528
|
-
document.getElementById('server-name').innerText =
|
|
24679
|
+
document.getElementById('server-name').innerText = window.metadata.server;
|
|
24680
|
+
document.title = `SQLUI ${window.metadata.server}`;
|
|
24681
|
+
document.getElementById('header-link').href = result.list_url_path;
|
|
24529
24682
|
const queryElement = document.getElementById('query');
|
|
24530
24683
|
|
|
24531
24684
|
init(queryElement, submitCurrent, submitAll);
|
|
@@ -24547,10 +24700,4 @@ var sqlui = (function (exports) {
|
|
|
24547
24700
|
});
|
|
24548
24701
|
};
|
|
24549
24702
|
|
|
24550
|
-
|
|
24551
|
-
exports.submitAll = submitAll;
|
|
24552
|
-
exports.submitCurrent = submitCurrent;
|
|
24553
|
-
|
|
24554
|
-
return exports;
|
|
24555
|
-
|
|
24556
|
-
})({});
|
|
24703
|
+
})();
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sqlui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.26
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nick Dower
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-10-
|
|
11
|
+
date: 2022-10-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: mysql2
|