sqlui 0.1.25 → 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/views/databases.erb +5 -22
- data/client/resources/sqlui.css +21 -5
- data/client/resources/sqlui.html +2 -0
- data/client/resources/sqlui.js +112 -62
- 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/views/databases.erb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
<html lang="en">
|
2
2
|
<head>
|
3
|
-
<title
|
3
|
+
<title><%= config.name %> Databases</title>
|
4
4
|
|
5
5
|
<style>
|
6
6
|
body {
|
@@ -71,30 +71,13 @@
|
|
71
71
|
.database {
|
72
72
|
margin: 0;
|
73
73
|
padding: 10px;
|
74
|
-
cursor: pointer;
|
75
74
|
border-bottom: 1px solid #eeeeee;
|
76
75
|
}
|
77
76
|
|
78
77
|
.database:last-child {
|
79
78
|
border-bottom: none;
|
80
79
|
}
|
81
|
-
|
82
|
-
.database:hover {
|
83
|
-
background: #eee;
|
84
|
-
}
|
85
80
|
</style>
|
86
|
-
|
87
|
-
<script>
|
88
|
-
function openDatabase(event, url) {
|
89
|
-
if (event.shiftKey) {
|
90
|
-
window.open(url, '_blank').focus()
|
91
|
-
} else if (event.metaKey) {
|
92
|
-
window.open(url).focus()
|
93
|
-
} else {
|
94
|
-
window.location = url
|
95
|
-
}
|
96
|
-
}
|
97
|
-
</script>
|
98
81
|
</head>
|
99
82
|
|
100
83
|
<body>
|
@@ -103,12 +86,12 @@
|
|
103
86
|
<h1 class="server-name"><%= config.name %> Databases</h1>
|
104
87
|
</div>
|
105
88
|
<% config.database_configs.each do |database_config| %>
|
106
|
-
<div class="database"
|
89
|
+
<div class="database">
|
107
90
|
<div class="name-and-links">
|
108
91
|
<h2 class='name'><%= database_config.display_name %></h2>
|
109
|
-
<a class='query-link' href="<%= database_config.url_path %>/query"
|
110
|
-
<a class='saved-link' href="<%= database_config.url_path %>/saved"
|
111
|
-
<a class='structure-link' href="<%= database_config.url_path %>/structure"
|
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>
|
112
95
|
</div>
|
113
96
|
<p class='description'>
|
114
97
|
<%= database_config.description %>
|
data/client/resources/sqlui.css
CHANGED
@@ -113,7 +113,11 @@ p {
|
|
113
113
|
display: flex;
|
114
114
|
border-top: 1px solid #ddd;
|
115
115
|
border-bottom: 1px solid #ddd;
|
116
|
-
|
116
|
+
}
|
117
|
+
|
118
|
+
.submit-fill {
|
119
|
+
display: flex;
|
120
|
+
flex: 1
|
117
121
|
}
|
118
122
|
|
119
123
|
.submit-button {
|
@@ -243,18 +247,30 @@ thead {
|
|
243
247
|
}
|
244
248
|
|
245
249
|
.saved-list-item {
|
246
|
-
cursor: pointer;
|
247
250
|
border-bottom: 1px solid #eeeeee;
|
248
251
|
margin: 0;
|
249
252
|
padding: 10px;
|
250
253
|
}
|
251
254
|
|
252
255
|
.saved-list-item h2 {
|
253
|
-
margin: 0 0
|
256
|
+
margin: 0 10px 0 0;
|
254
257
|
}
|
255
258
|
|
256
|
-
.saved-
|
257
|
-
|
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;
|
258
274
|
}
|
259
275
|
|
260
276
|
.cm-editor.cm-focused {
|
data/client/resources/sqlui.html
CHANGED
@@ -26,6 +26,8 @@
|
|
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="cancel-button" class="submit-button" type="button" value="cancel"></input>
|
30
|
+
<div class="submit-fill"></div>
|
29
31
|
<input id="submit-current-button" class="submit-button" type="button" value="run selection (ctrl-enter)"></input>
|
30
32
|
<input id="submit-all-button" class="submit-button" type="button" value="run (ctrl-shift-enter)"></input>
|
31
33
|
</div>
|
data/client/resources/sqlui.js
CHANGED
@@ -23869,6 +23869,9 @@
|
|
23869
23869
|
document.getElementById('submit-current-button').addEventListener('click', function (event) {
|
23870
23870
|
submitCurrent(event.target, event);
|
23871
23871
|
});
|
23872
|
+
document.getElementById('cancel-button').addEventListener('click', function (event) {
|
23873
|
+
clearResult();
|
23874
|
+
});
|
23872
23875
|
|
23873
23876
|
const fixedHeightEditor = EditorView.theme({
|
23874
23877
|
'.cm-scroller': { height: '200px', overflow: 'auto', resize: 'vertical' }
|
@@ -24160,6 +24163,8 @@
|
|
24160
24163
|
document.getElementById('submit-box').style.display = 'flex';
|
24161
24164
|
document.getElementById('graph-box').style.display = 'flex';
|
24162
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';
|
24163
24168
|
maybeFetchResult();
|
24164
24169
|
|
24165
24170
|
const selection = getSelection();
|
@@ -24172,6 +24177,8 @@
|
|
24172
24177
|
document.getElementById('submit-box').style.display = 'flex';
|
24173
24178
|
document.getElementById('result-box').style.display = 'flex';
|
24174
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';
|
24175
24182
|
const selection = getSelection();
|
24176
24183
|
focus();
|
24177
24184
|
setSelection(selection);
|
@@ -24199,21 +24206,48 @@
|
|
24199
24206
|
setSavedStatus(`${saved.length} files`);
|
24200
24207
|
}
|
24201
24208
|
Object.values(saved).forEach(file => {
|
24202
|
-
const
|
24203
|
-
|
24204
|
-
|
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) {
|
24205
24218
|
clearResult();
|
24206
|
-
|
24207
|
-
setTabInUrl(url, 'query');
|
24208
|
-
url.searchParams.set('file', file.filename);
|
24209
|
-
route(event.target, event, url);
|
24219
|
+
route(event.target, event, viewUrl);
|
24210
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);
|
24234
|
+
});
|
24235
|
+
|
24211
24236
|
const nameElement = document.createElement('h2');
|
24212
24237
|
nameElement.innerText = file.filename;
|
24213
|
-
|
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);
|
24214
24244
|
|
24215
24245
|
const descriptionElement = document.createElement('p');
|
24216
24246
|
descriptionElement.innerText = file.description;
|
24247
|
+
|
24248
|
+
const divElement = document.createElement('div');
|
24249
|
+
divElement.classList.add('saved-list-item');
|
24250
|
+
divElement.appendChild(nameAndLinksElement);
|
24217
24251
|
divElement.appendChild(descriptionElement);
|
24218
24252
|
|
24219
24253
|
savedElement.appendChild(divElement);
|
@@ -24235,7 +24269,7 @@
|
|
24235
24269
|
let sql = getValue().trim();
|
24236
24270
|
sql = sql === '' ? null : sql;
|
24237
24271
|
|
24238
|
-
url.searchParams.
|
24272
|
+
url.searchParams.set('run', 'true');
|
24239
24273
|
|
24240
24274
|
if (url.searchParams.has('file')) {
|
24241
24275
|
if (window.metadata.saved[url.searchParams.get('file')].contents !== getValue()) {
|
@@ -24263,22 +24297,25 @@
|
|
24263
24297
|
url.searchParams.delete('selection');
|
24264
24298
|
url.searchParams.delete('sql');
|
24265
24299
|
url.searchParams.delete('file');
|
24300
|
+
url.searchParams.delete('run');
|
24266
24301
|
}
|
24267
24302
|
|
24268
24303
|
route(target, event, url);
|
24269
24304
|
}
|
24270
24305
|
|
24271
24306
|
function clearResult () {
|
24272
|
-
|
24273
|
-
|
24274
|
-
|
24275
|
-
|
24276
|
-
const existingRequest = window.sqlFetch;
|
24277
|
-
if (existingRequest?.state === 'pending') {
|
24278
|
-
existingRequest.state = 'aborted';
|
24279
|
-
existingRequest.fetchController.abort();
|
24307
|
+
const existingFetch = window.sqlFetch;
|
24308
|
+
if (existingFetch?.state === 'pending') {
|
24309
|
+
existingFetch.state = 'aborted';
|
24310
|
+
existingFetch.fetchController.abort();
|
24280
24311
|
}
|
24281
24312
|
window.sqlFetch = null;
|
24313
|
+
|
24314
|
+
clearGraphBox();
|
24315
|
+
clearGraphStatus();
|
24316
|
+
|
24317
|
+
clearResultBox();
|
24318
|
+
clearResultStatus();
|
24282
24319
|
}
|
24283
24320
|
|
24284
24321
|
function clearResultStatus () {
|
@@ -24303,7 +24340,7 @@
|
|
24303
24340
|
}
|
24304
24341
|
}
|
24305
24342
|
|
24306
|
-
function fetchSql (
|
24343
|
+
function fetchSql (sqlFetch, selection, callback) {
|
24307
24344
|
fetch('query', {
|
24308
24345
|
headers: {
|
24309
24346
|
Accept: 'application/json',
|
@@ -24311,64 +24348,65 @@
|
|
24311
24348
|
},
|
24312
24349
|
method: 'POST',
|
24313
24350
|
body: JSON.stringify({
|
24314
|
-
sql:
|
24351
|
+
sql: sqlFetch.sql,
|
24315
24352
|
selection
|
24316
24353
|
}),
|
24317
|
-
signal:
|
24354
|
+
signal: sqlFetch.fetchController.signal
|
24318
24355
|
})
|
24319
24356
|
.then((response) => {
|
24320
24357
|
const contentType = response.headers.get('content-type');
|
24321
24358
|
if (contentType && contentType.indexOf('application/json') !== -1) {
|
24322
24359
|
response.json().then((result) => {
|
24323
24360
|
if (result?.query) {
|
24324
|
-
|
24325
|
-
|
24361
|
+
sqlFetch.state = 'success';
|
24362
|
+
sqlFetch.result = result;
|
24326
24363
|
} else {
|
24327
|
-
|
24364
|
+
sqlFetch.state = 'error';
|
24328
24365
|
if (result?.error) {
|
24329
|
-
|
24330
|
-
|
24366
|
+
sqlFetch.error_message = result.error;
|
24367
|
+
sqlFetch.error_details = result.stacktrace;
|
24331
24368
|
} else if (result) {
|
24332
|
-
|
24333
|
-
|
24369
|
+
sqlFetch.error_message = 'failed to execute query';
|
24370
|
+
sqlFetch.error_details = result.toString();
|
24334
24371
|
} else {
|
24335
|
-
|
24372
|
+
sqlFetch.error_message = 'failed to execute query';
|
24336
24373
|
}
|
24337
24374
|
}
|
24338
|
-
callback(
|
24375
|
+
callback(sqlFetch);
|
24339
24376
|
});
|
24340
24377
|
} else {
|
24341
24378
|
response.text().then((result) => {
|
24342
|
-
|
24343
|
-
|
24344
|
-
|
24345
|
-
callback(
|
24379
|
+
sqlFetch.state = 'error';
|
24380
|
+
sqlFetch.error_message = 'failed to execute query';
|
24381
|
+
sqlFetch.error_details = result;
|
24382
|
+
callback(sqlFetch);
|
24346
24383
|
});
|
24347
24384
|
}
|
24348
24385
|
})
|
24349
24386
|
.catch(function (error) {
|
24350
|
-
if (
|
24351
|
-
|
24352
|
-
|
24353
|
-
|
24354
|
-
callback(request);
|
24387
|
+
if (sqlFetch.state === 'pending') {
|
24388
|
+
sqlFetch.state = 'error';
|
24389
|
+
sqlFetch.error_message = 'failed to execute query';
|
24390
|
+
sqlFetch.error_details = error;
|
24355
24391
|
}
|
24392
|
+
callback(sqlFetch);
|
24356
24393
|
});
|
24357
24394
|
}
|
24358
24395
|
|
24359
24396
|
function maybeFetchResult () {
|
24360
|
-
const
|
24397
|
+
const url = new URL(window.location);
|
24398
|
+
const params = url.searchParams;
|
24361
24399
|
const sql = params.get('sql');
|
24362
24400
|
const file = params.get('file');
|
24363
24401
|
const selection = params.get('selection');
|
24364
|
-
const run =
|
24402
|
+
const run = ['1', 'true'].includes(params.get('run')?.toLowerCase());
|
24365
24403
|
|
24366
24404
|
if (params.has('file') && params.has('sql')) {
|
24367
24405
|
// TODO: show an error.
|
24368
24406
|
throw new Error('You can only specify a file or sql, not both.')
|
24369
24407
|
}
|
24370
24408
|
|
24371
|
-
const
|
24409
|
+
const sqlFetch = {
|
24372
24410
|
fetchController: new AbortController(),
|
24373
24411
|
state: 'pending',
|
24374
24412
|
sql,
|
@@ -24381,10 +24419,10 @@
|
|
24381
24419
|
if (!fileDetails) {
|
24382
24420
|
throw new Error(`no such file: ${params.get('file')}`)
|
24383
24421
|
}
|
24384
|
-
|
24385
|
-
|
24422
|
+
sqlFetch.file = file;
|
24423
|
+
sqlFetch.sql = fileDetails.contents;
|
24386
24424
|
} else if (params.has('sql')) {
|
24387
|
-
|
24425
|
+
sqlFetch.sql = sql;
|
24388
24426
|
}
|
24389
24427
|
|
24390
24428
|
const existingRequest = window.sqlFetch;
|
@@ -24406,11 +24444,13 @@
|
|
24406
24444
|
clearResult();
|
24407
24445
|
|
24408
24446
|
if (params.has('sql') || params.has('file')) {
|
24409
|
-
setValue(
|
24447
|
+
setValue(sqlFetch.sql);
|
24410
24448
|
if (run) {
|
24411
|
-
|
24412
|
-
|
24413
|
-
|
24449
|
+
url.searchParams.delete('run');
|
24450
|
+
window.history.replaceState({}, '', url);
|
24451
|
+
window.sqlFetch = sqlFetch;
|
24452
|
+
displaySqlFetch(sqlFetch);
|
24453
|
+
fetchSql(sqlFetch, selection, displaySqlFetch);
|
24414
24454
|
}
|
24415
24455
|
}
|
24416
24456
|
if (params.has('selection')) {
|
@@ -24420,17 +24460,22 @@
|
|
24420
24460
|
}
|
24421
24461
|
|
24422
24462
|
function displaySqlFetchInResultTab (fetch) {
|
24423
|
-
const fetchSqlBoxElement = document.getElementById('fetch-sql-box');
|
24424
|
-
const resultBoxElement = document.getElementById('result-box');
|
24425
24463
|
if (fetch.state === 'pending') {
|
24426
24464
|
clearResultBox();
|
24427
|
-
|
24428
|
-
|
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';
|
24429
24468
|
return
|
24430
24469
|
}
|
24431
24470
|
|
24432
|
-
|
24433
|
-
|
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();
|
24477
|
+
return
|
24478
|
+
}
|
24434
24479
|
|
24435
24480
|
if (fetch.state === 'error') {
|
24436
24481
|
clearResultBox();
|
@@ -24458,7 +24503,7 @@
|
|
24458
24503
|
theadElement.appendChild(headerElement);
|
24459
24504
|
tableElement.appendChild(theadElement);
|
24460
24505
|
tableElement.appendChild(tbodyElement);
|
24461
|
-
|
24506
|
+
document.getElementById('result-box').appendChild(tableElement);
|
24462
24507
|
|
24463
24508
|
fetch.result.columns.forEach(column => {
|
24464
24509
|
const template = document.createElement('template');
|
@@ -24504,17 +24549,22 @@
|
|
24504
24549
|
}
|
24505
24550
|
|
24506
24551
|
function displaySqlFetchInGraphTab (fetch) {
|
24507
|
-
const graphBoxElement = document.getElementById('graph-box');
|
24508
|
-
const fetchSqlBoxElement = document.getElementById('fetch-sql-box');
|
24509
24552
|
if (fetch.state === 'pending') {
|
24510
24553
|
clearGraphBox();
|
24511
|
-
|
24512
|
-
|
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';
|
24513
24557
|
return
|
24514
24558
|
}
|
24515
24559
|
|
24516
|
-
|
24517
|
-
|
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
|
+
}
|
24518
24568
|
|
24519
24569
|
if (fetch.state === 'error') {
|
24520
24570
|
clearGraphBox();
|
@@ -24553,7 +24603,7 @@
|
|
24553
24603
|
dataTable.addRow(rowValues);
|
24554
24604
|
});
|
24555
24605
|
|
24556
|
-
const chart = new google.visualization.LineChart(
|
24606
|
+
const chart = new google.visualization.LineChart(document.getElementById('graph-box'));
|
24557
24607
|
const options = {
|
24558
24608
|
hAxis: {
|
24559
24609
|
title: fetch.result.columns[0]
|
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
|