sqlui 0.1.70 → 0.1.72

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.
@@ -24443,7 +24443,6 @@
24443
24443
  const moveListener = (event) => {
24444
24444
  const y = event.clientY - startY;
24445
24445
  const height = Math.min(max, Math.max(min, startHeight + y));
24446
- console.log(`y: ${y}, height: ${height}`);
24447
24446
  resizableElement.style.height = `${height}px`;
24448
24447
  };
24449
24448
 
@@ -24465,12 +24464,10 @@
24465
24464
 
24466
24465
  const PAGE_SIZE = 100;
24467
24466
 
24467
+ const TABS = ['query', 'graph', 'saved', 'structure', 'help'];
24468
+
24468
24469
  function getSqlFromUrl (url) {
24469
24470
  const params = url.searchParams;
24470
- if (params.has('file') && params.has('sql')) {
24471
- // TODO: show an error.
24472
- throw new Error('You can only specify a file or sql param, not both.')
24473
- }
24474
24471
  if (params.has('sql')) {
24475
24472
  return params.get('sql')
24476
24473
  } else if (params.has('file')) {
@@ -24501,6 +24498,12 @@
24501
24498
  const runCurrentLabel = `run selection (${isMac ? '⌘' : 'Ctrl'}-Enter)`;
24502
24499
  const runAllLabel = `run all (${isMac ? '⌘' : 'Ctrl'}-Shift-Enter)`;
24503
24500
 
24501
+ const dismissFileButton = document.getElementById('dismiss-file-button');
24502
+ addEventListener(dismissFileButton, 'click', (event) => dismissFile());
24503
+
24504
+ const saveFileButton = document.getElementById('save-file-button');
24505
+ addEventListener(saveFileButton, 'click', (event) => saveFile());
24506
+
24504
24507
  const submitButtonCurrent = document.getElementById('submit-button-current');
24505
24508
  submitButtonCurrent.value = runCurrentLabel;
24506
24509
  addEventListener(submitButtonCurrent, 'click', (event) => submitCurrent(event.target, event));
@@ -24695,10 +24698,10 @@
24695
24698
  function selectTab (event, tab) {
24696
24699
  const url = new URL(window.location);
24697
24700
  setActionInUrl(url, tab);
24698
- route(event.target, event, url, true);
24701
+ route(event.target, event, url);
24699
24702
  }
24700
24703
 
24701
- function route (target = null, event = null, url = null, internal = false) {
24704
+ function route (target = null, event = null, url = null, run = false) {
24702
24705
  closePopup();
24703
24706
 
24704
24707
  if (url) {
@@ -24716,7 +24719,7 @@
24716
24719
  }
24717
24720
  }
24718
24721
  if (url.href !== window.location.href) {
24719
- window.history.pushState({}, '', url);
24722
+ pushState(url);
24720
24723
  }
24721
24724
  } else {
24722
24725
  url = new URL(window.location);
@@ -24740,10 +24743,10 @@
24740
24743
 
24741
24744
  switch (window.tab) {
24742
24745
  case 'query':
24743
- selectQueryTab(internal);
24746
+ selectQueryTab(run);
24744
24747
  break
24745
24748
  case 'graph':
24746
- selectGraphTab(internal);
24749
+ selectGraphTab(run);
24747
24750
  break
24748
24751
  case 'saved':
24749
24752
  selectSavedTab();
@@ -24932,7 +24935,7 @@
24932
24935
  setTimeout(() => { helpBoxElement.focus(); }, 0);
24933
24936
  }
24934
24937
 
24935
- function selectGraphTab (internal) {
24938
+ function selectGraphTab (run) {
24936
24939
  document.getElementById('query-box').style.display = 'flex';
24937
24940
  document.getElementById('submit-box').style.display = 'flex';
24938
24941
  document.getElementById('graph-box').style.display = 'flex';
@@ -24940,17 +24943,19 @@
24940
24943
  document.getElementById('cancel-button').style.visibility = 'hidden';
24941
24944
  updateDownloadButtons(window?.sqlFetch);
24942
24945
  focus(getSelection());
24943
- maybeFetchResult(internal);
24946
+ maybeFetchResult(run);
24947
+ updateFileBox();
24944
24948
  }
24945
24949
 
24946
- function selectQueryTab (internal) {
24950
+ function selectQueryTab (run) {
24947
24951
  document.getElementById('query-box').style.display = 'flex';
24948
24952
  document.getElementById('submit-box').style.display = 'flex';
24949
24953
  document.getElementById('result-box').style.display = 'flex';
24950
24954
  document.getElementById('fetch-sql-box').style.display = 'none';
24951
24955
  document.getElementById('cancel-button').style.visibility = 'hidden';
24952
24956
  focus(getSelection());
24953
- maybeFetchResult(internal);
24957
+ maybeFetchResult(run);
24958
+ updateFileBox();
24954
24959
  }
24955
24960
 
24956
24961
  function selectSavedTab () {
@@ -24959,7 +24964,12 @@
24959
24964
  });
24960
24965
 
24961
24966
  const savedElement = document.getElementById('saved-box');
24962
- setTimeout(() => { savedElement.focus(); }, 0);
24967
+ setTimeout(() => {
24968
+ // Little hack so that hitting tab after loading the saved tab will cause focus to go to the first file.
24969
+ savedElement.tabIndex = 0;
24970
+ savedElement.focus();
24971
+ savedElement.tabIndex = -1;
24972
+ }, 0);
24963
24973
 
24964
24974
  const saved = window.metadata.saved;
24965
24975
  const numFiles = Object.keys(saved).length;
@@ -24970,60 +24980,75 @@
24970
24980
  }
24971
24981
 
24972
24982
  Object.values(saved).forEach(file => {
24983
+ const gitHubElement = document.createElement('a');
24984
+ gitHubElement.classList.add('saved-github-link');
24985
+ gitHubElement.href = file.github_url;
24986
+ gitHubElement.target = '_blank';
24987
+ addEventListener(gitHubElement, 'click', (event) => {
24988
+ event.stopPropagation();
24989
+ });
24990
+ addEventListener(gitHubElement, 'keydown', (event) => {
24991
+ if (event.keyCode === 13) {
24992
+ event.stopPropagation();
24993
+ }
24994
+ });
24995
+
24996
+ const gitHubImageElement = document.createElement('img');
24997
+ gitHubImageElement.alt = 'GitHub';
24998
+ gitHubImageElement.src = window.resourcePathMap['github.svg'];
24999
+ gitHubElement.appendChild(gitHubImageElement);
25000
+
24973
25001
  const viewUrl = new URL(window.location.origin + window.location.pathname);
24974
25002
  setActionInUrl(viewUrl, 'query');
24975
25003
  viewUrl.searchParams.set('file', file.filename);
24976
25004
 
24977
- const viewLinkElement = document.createElement('a');
24978
- viewLinkElement.classList.add('link', 'view-link');
24979
- viewLinkElement.innerText = 'view';
24980
- viewLinkElement.href = viewUrl.pathname + viewUrl.search;
24981
- addEventListener(viewLinkElement, 'click', (event) => {
24982
- clearResult();
24983
- route(event.target, event, viewUrl, true);
24984
- });
25005
+ const nameElement = document.createElement('a');
25006
+ nameElement.classList.add('saved-name');
25007
+ nameElement.innerText = file.filename;
25008
+ nameElement.href = viewUrl.pathname + viewUrl.search;
24985
25009
 
24986
- const runUrl = new URL(window.location.origin + window.location.pathname);
24987
- setActionInUrl(runUrl, 'query');
24988
- runUrl.searchParams.set('file', file.filename);
24989
- runUrl.searchParams.set('run', 'true');
25010
+ const headerElement = document.createElement('div');
25011
+ headerElement.classList.add('saved-file-header');
25012
+ headerElement.appendChild(nameElement);
25013
+ headerElement.appendChild(gitHubElement);
24990
25014
 
24991
- const runLinkElement = document.createElement('a');
24992
- runLinkElement.classList.add('link', 'run-link');
24993
- runLinkElement.innerText = 'run';
24994
- runLinkElement.href = runUrl.pathname + runUrl.search;
24995
- addEventListener(runLinkElement, 'click', (event) => {
24996
- clearResult();
24997
- route(event.target, event, runUrl, true);
24998
- });
25015
+ const contentLines = file.contents.endsWith('\n') ? file.contents.slice(0, -1).split('\n') : file.contents.split('\n');
25016
+ let preview;
25017
+ if (contentLines.length > 5) {
25018
+ preview = contentLines.slice(0, 4).join('\n');
25019
+ } else {
25020
+ preview = contentLines.join('\n');
25021
+ }
24999
25022
 
25000
- const viewOnGithubLinkElement = document.createElement('a');
25001
- viewOnGithubLinkElement.classList.add('link', 'view-github-link');
25002
- viewOnGithubLinkElement.innerText = 'github';
25003
- viewOnGithubLinkElement.href = file.github_url;
25004
- viewOnGithubLinkElement.target = '_blank';
25023
+ const previewElement = document.createElement('a');
25024
+ previewElement.classList.add('saved-preview');
25025
+ previewElement.tabIndex = -1;
25026
+ previewElement.innerText = preview;
25027
+ previewElement.href = viewUrl.pathname + viewUrl.search;
25005
25028
 
25006
- const nameElement = document.createElement('h2');
25007
- nameElement.innerText = file.filename;
25008
- nameElement.classList.add('name');
25029
+ if (contentLines.length > 5) {
25030
+ const truncatedElement = document.createElement('div');
25031
+ truncatedElement.classList.add('saved-truncated');
25032
+ truncatedElement.innerText = `... ${contentLines.length - 4} more lines`;
25033
+ previewElement.appendChild(truncatedElement);
25034
+ }
25009
25035
 
25010
- const linksElement = document.createElement('div');
25011
- linksElement.classList.add('links');
25012
- linksElement.appendChild(viewLinkElement);
25013
- linksElement.appendChild(runLinkElement);
25014
- linksElement.appendChild(viewOnGithubLinkElement);
25015
-
25016
- const descriptionElement = document.createElement('p');
25017
- descriptionElement.innerText = file.description;
25018
- descriptionElement.classList.add('description');
25019
-
25020
- const divElement = document.createElement('div');
25021
- divElement.classList.add('saved-list-item');
25022
- divElement.appendChild(nameElement);
25023
- divElement.appendChild(linksElement);
25024
- divElement.appendChild(descriptionElement);
25025
-
25026
- savedElement.appendChild(divElement);
25036
+ const itemElement = document.createElement('div');
25037
+ itemElement.classList.add('saved-list-item');
25038
+ itemElement.appendChild(headerElement);
25039
+ itemElement.appendChild(previewElement);
25040
+ addEventListener(itemElement, 'click', (event) => {
25041
+ clearResult();
25042
+ route(event.target, event, viewUrl);
25043
+ });
25044
+ addEventListener(itemElement, 'keydown', (event) => {
25045
+ if (event.keyCode === 13) {
25046
+ clearResult();
25047
+ route(event.target, event, viewUrl);
25048
+ }
25049
+ });
25050
+
25051
+ savedElement.appendChild(itemElement);
25027
25052
  });
25028
25053
  }
25029
25054
 
@@ -25048,19 +25073,15 @@
25048
25073
  window.lastEditorValueSet = null;
25049
25074
 
25050
25075
  const url = new URL(window.location);
25051
- let sql = getEditorValue().trim();
25052
- sql = sql === '' ? null : sql;
25053
-
25054
- url.searchParams.set('run', 'true');
25076
+ let sql = getEditorValue();
25077
+ sql = sql.trim() === '' ? null : sql;
25055
25078
 
25056
25079
  if (url.searchParams.has('file')) {
25057
25080
  if (window.metadata.saved[url.searchParams.get('file')].contents !== getEditorValue()) {
25058
- url.searchParams.delete('file');
25059
25081
  url.searchParams.set('sql', sql);
25060
25082
  }
25061
25083
  } else {
25062
- let sqlParam = url.searchParams.get('sql')?.trim();
25063
- sqlParam = sqlParam === '' ? null : sqlParam;
25084
+ const sqlParam = url.searchParams.has('sql') ? url.searchParams.get('sql') : null;
25064
25085
 
25065
25086
  if (sqlParam !== sql && sql === null) {
25066
25087
  url.searchParams.delete('sql');
@@ -25079,7 +25100,6 @@
25079
25100
  url.searchParams.delete('selection');
25080
25101
  url.searchParams.delete('sql');
25081
25102
  url.searchParams.delete('file');
25082
- url.searchParams.delete('run');
25083
25103
  }
25084
25104
 
25085
25105
  route(target, event, url, true);
@@ -25225,31 +25245,18 @@
25225
25245
  )
25226
25246
  }
25227
25247
 
25228
- function maybeFetchResult (internal) {
25248
+ function maybeFetchResult (run) {
25229
25249
  const url = new URL(window.location);
25230
25250
  const params = url.searchParams;
25231
25251
  const sql = params.get('sql');
25232
25252
  const file = params.get('file');
25233
25253
  const selection = params.get('selection');
25234
- const hasSqluiReferrer = document.referrer && new URL(document.referrer).origin === url.origin;
25235
25254
  const variables = parseSqlVariables(params);
25236
25255
 
25237
- if (params.has('file') && params.has('sql')) {
25238
- // TODO: show an error.
25239
- throw new Error('You can only specify a file or sql, not both.')
25240
- }
25241
-
25242
- // Only allow auto-run if coming from another SQLUI page. The idea here is to let the app link to URLs with run=true
25243
- // but not other apps. This allows meta/shift-clicking to run a query.
25244
- if (params.has('run')) {
25245
- url.searchParams.delete('run');
25246
- window.history.replaceState({}, '', url);
25256
+ if (run) {
25257
+ replaceState(url);
25247
25258
  clearResult();
25248
25259
 
25249
- if (!internal && !hasSqluiReferrer) {
25250
- throw new Error('run only allowed for internal usage')
25251
- }
25252
-
25253
25260
  if (params.has('sql') || params.has('file')) {
25254
25261
  const sqlFetch = buildSqlFetch(sql, file, variables, selection);
25255
25262
  setEditorValue(sqlFetch.sql);
@@ -25269,10 +25276,13 @@
25269
25276
  const existingRequest = window.sqlFetch;
25270
25277
  if (existingRequest) {
25271
25278
  const selectionMatches = selection === existingRequest.selection;
25272
- const sqlMatches = params.has('sql') && sql === existingRequest.sql;
25273
- const fileMatches = params.has('file') && file === existingRequest.file;
25279
+ let queryMatches = false;
25280
+ if (params.has('sql')) {
25281
+ queryMatches = sql === existingRequest.sql;
25282
+ } else if (params.has('file')) {
25283
+ queryMatches = file === existingRequest.file;
25284
+ }
25274
25285
  const variablesMatch = JSON.stringify(variables) === JSON.stringify(existingRequest.variables);
25275
- const queryMatches = sqlMatches || fileMatches;
25276
25286
  if (selectionMatches && queryMatches && variablesMatch) {
25277
25287
  displaySqlFetch(existingRequest);
25278
25288
  if (params.has('selection') && window.lastSetSelectionValueFromUrlParam !== selection) {
@@ -25326,15 +25336,15 @@
25326
25336
  function buildSqlFetch (sql, file, variables, selection) {
25327
25337
  const sqlFetch = new SqlFetch(sql, file, variables, selection);
25328
25338
 
25329
- if (file) {
25339
+ if (sql) {
25340
+ sqlFetch.sql = sql;
25341
+ } else if (file) {
25330
25342
  const fileDetails = window.metadata.saved[file];
25331
25343
  if (!fileDetails) {
25332
25344
  throw new Error(`no such file: ${file}`)
25333
25345
  }
25334
25346
  sqlFetch.file = file;
25335
25347
  sqlFetch.sql = fileDetails.contents;
25336
- } else if (sql) {
25337
- sqlFetch.sql = sql;
25338
25348
  }
25339
25349
 
25340
25350
  return sqlFetch
@@ -25502,15 +25512,27 @@
25502
25512
  addEventListener(tableElement, 'mousedown', listener);
25503
25513
  }
25504
25514
  function disableDownloadButtons () {
25505
- document.getElementById('submit-dropdown-button-download-csv').classList.add('disabled');
25506
- document.getElementById('submit-dropdown-button-copy-csv').classList.add('disabled');
25507
- document.getElementById('submit-dropdown-button-copy-tsv').classList.add('disabled');
25515
+ const downloadCsvElement = document.getElementById('submit-dropdown-button-download-csv');
25516
+ downloadCsvElement.classList.add('disabled');
25517
+ downloadCsvElement.tabIndex = -1;
25518
+ const copyCsvElement = document.getElementById('submit-dropdown-button-copy-csv');
25519
+ copyCsvElement.classList.add('disabled');
25520
+ copyCsvElement.tabIndex = -1;
25521
+ const copyTsvElement = document.getElementById('submit-dropdown-button-copy-tsv');
25522
+ copyTsvElement.classList.add('disabled');
25523
+ copyTsvElement.tabIndex = -1;
25508
25524
  }
25509
25525
 
25510
25526
  function enableDownloadButtons () {
25511
- document.getElementById('submit-dropdown-button-download-csv').classList.remove('disabled');
25512
- document.getElementById('submit-dropdown-button-copy-csv').classList.remove('disabled');
25513
- document.getElementById('submit-dropdown-button-copy-tsv').classList.remove('disabled');
25527
+ const downloadCsvElement = document.getElementById('submit-dropdown-button-download-csv');
25528
+ downloadCsvElement.classList.remove('disabled');
25529
+ downloadCsvElement.tabIndex = 0;
25530
+ const copyCsvElement = document.getElementById('submit-dropdown-button-copy-csv');
25531
+ copyCsvElement.classList.remove('disabled');
25532
+ copyCsvElement.tabIndex = 0;
25533
+ const copyTsvElement = document.getElementById('submit-dropdown-button-copy-tsv');
25534
+ copyTsvElement.classList.remove('disabled');
25535
+ copyTsvElement.tabIndex = 0;
25514
25536
  }
25515
25537
 
25516
25538
  function updateDownloadButtons (fetch) {
@@ -25521,6 +25543,54 @@
25521
25543
  }
25522
25544
  }
25523
25545
 
25546
+ function updateFileBox () {
25547
+ const url = new URL(window.location);
25548
+ if (url.searchParams.has('file')) {
25549
+ document.getElementById('filename').innerText = url.searchParams.get('file');
25550
+ document.getElementById('filename-box').style.display = 'flex';
25551
+ } else {
25552
+ document.getElementById('filename-box').style.display = 'none';
25553
+ }
25554
+ }
25555
+
25556
+ function dismissFile () {
25557
+ const url = new URL(window.location);
25558
+ url.searchParams.set('sql', getSqlFromUrl(url));
25559
+ url.searchParams.delete('file');
25560
+ if (url.searchParams.has('selection')) {
25561
+ const selection = url.searchParams.get('selection');
25562
+ // Let's put selection after sql.
25563
+ url.searchParams.delete('selection');
25564
+ url.searchParams.set('selection', selection);
25565
+ }
25566
+ document.getElementById('filename-box').style.display = 'none';
25567
+ replaceState(url);
25568
+ }
25569
+
25570
+ function replaceState (url) {
25571
+ // Paths look so much better with slashes than with %2F. It seems to work even though it isn't technically valid.
25572
+ window.history.replaceState({}, '', url.href.replaceAll('%2F', '/'));
25573
+ }
25574
+
25575
+ function pushState (url) {
25576
+ // Paths look so much better with slashes than with %2F. It seems to work even though it isn't technically valid.
25577
+ window.history.pushState({}, '', url.href.replaceAll('%2F', '/'));
25578
+ }
25579
+
25580
+ function saveFile () {
25581
+ const url = new URL(window.location);
25582
+ if (!url.searchParams.has('file')) throw new Error('missing file param')
25583
+
25584
+ const file = url.searchParams.get('file');
25585
+ const fileDetails = window.metadata.saved[file];
25586
+ if (!fileDetails) throw new Error(`no such file: ${file}`)
25587
+
25588
+ document.getElementById('save-form-base-sha').value = fileDetails.tree_sha;
25589
+ document.getElementById('save-form-path').value = fileDetails.path;
25590
+ document.getElementById('save-form-content').value = getEditorValue();
25591
+ document.getElementById('save-form').submit();
25592
+ }
25593
+
25524
25594
  function displaySqlFetch (fetch) {
25525
25595
  updateDownloadButtons(fetch);
25526
25596
  if (window.tab === 'query') {
@@ -25721,6 +25791,14 @@
25721
25791
  selectTab(event, 'structure');
25722
25792
  } else if (isMac && event.code === 'Digit5' && event.ctrlKey) {
25723
25793
  selectTab(event, 'help');
25794
+ } else if (isMac && event.code === 'BracketLeft' && event.ctrlKey) {
25795
+ const currentTabIndex = TABS.indexOf(window.tab);
25796
+ const previousTabIndex = currentTabIndex === 0 ? TABS.length - 1 : currentTabIndex - 1;
25797
+ selectTab(event, TABS[previousTabIndex]);
25798
+ } else if (isMac && event.code === 'BracketRight' && event.ctrlKey) {
25799
+ const currentTabIndex = TABS.indexOf(window.tab);
25800
+ const nextTabIndex = (currentTabIndex + 1) % TABS.length;
25801
+ selectTab(event, TABS[nextTabIndex]);
25724
25802
  }
25725
25803
  });
25726
25804
 
@@ -25733,9 +25811,14 @@
25733
25811
  });
25734
25812
 
25735
25813
  window.onload = function () {
25814
+ const url = new URL(window.location);
25815
+ let requestUrl = 'metadata';
25816
+ if (url.searchParams.has('file')) {
25817
+ requestUrl += `?file=${url.searchParams.get('file')}`;
25818
+ }
25736
25819
  Promise.all([
25737
25820
  google.charts.load('current', { packages: ['corechart', 'line'] }),
25738
- fetch('metadata', {
25821
+ fetch(requestUrl, {
25739
25822
  headers: {
25740
25823
  Accept: 'application/json'
25741
25824
  },
@@ -25748,12 +25831,15 @@
25748
25831
  if (contentType && contentType.indexOf('application/json') !== -1) {
25749
25832
  return response.json().then((result) => {
25750
25833
  if (result.error) {
25751
- let error = '<div style="font-family: monospace; font-size: 16px;">\n';
25752
- error += `<div>${result.error}</div>\n`;
25834
+ let error = '<span style="font-family: monospace; color: #333; font-size: 16px;">\n';
25835
+ error += '<h2>Internal Error</h2>\n';
25836
+ error += '<h3>Message</h3>\n';
25837
+ error += `<p>${result.error}</p>\n`;
25753
25838
  if (result.stacktrace) {
25839
+ error += '<h3>Stacktrace</h3>\n';
25754
25840
  error += '<pre>\n' + result.stacktrace + '\n</pre>\n';
25755
25841
  }
25756
- error += '</div>\n';
25842
+ error += '</span>\n';
25757
25843
  document.getElementById('loading-box').innerHTML = error;
25758
25844
  } else if (!result.server) {
25759
25845
  document.getElementById('loading-box').innerHTML = `
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.70
4
+ version: 0.1.72
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Dower
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-03 00:00:00.000000000 Z
11
+ date: 2023-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -206,6 +206,20 @@ dependencies:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
208
  version: '4.0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: timecop
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: '0.0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '0.0'
209
223
  - !ruby/object:Gem::Dependency
210
224
  name: webmock
211
225
  requirement: !ruby/object:Gem::Requirement
@@ -242,6 +256,7 @@ files:
242
256
  - app/github/tree.rb
243
257
  - app/github/tree_client.rb
244
258
  - app/mysql_types.rb
259
+ - app/pigs.rb
245
260
  - app/saved_config.rb
246
261
  - app/server.rb
247
262
  - app/sql_parser.rb
@@ -250,10 +265,13 @@ files:
250
265
  - app/version.rb
251
266
  - app/views/databases.erb
252
267
  - app/views/error.erb
268
+ - app/views/redirect.erb
253
269
  - app/views/sqlui.erb
254
270
  - bin/sqlui
255
271
  - client/resources/favicon.svg
272
+ - client/resources/github.svg
256
273
  - client/resources/help.css
274
+ - client/resources/saved.css
257
275
  - client/resources/sqlui.css
258
276
  - client/resources/sqlui.js
259
277
  - client/resources/vertical-resizer.svg