sqlui 0.1.24 → 0.1.26
Sign up to get free protection for your applications and to get access to all the features.
- 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
|