Improve table display in Spinner.
This commit is contained in:
parent
d6adfea9b1
commit
df96b05863
8 changed files with 1061 additions and 15 deletions
|
@ -38,7 +38,7 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Data Rows -->
|
<!-- Data Rows -->
|
||||||
<table>
|
<table id="data-table" class="invisible">
|
||||||
<tr>
|
<tr>
|
||||||
{{#each queryResult.columns}}
|
{{#each queryResult.columns}}
|
||||||
<th>{{this}}</th>
|
<th>{{this}}</th>
|
||||||
|
@ -55,6 +55,7 @@
|
||||||
{{else}}
|
{{else}}
|
||||||
<div>Select a table from above and click 'browse'.</div>
|
<div>Select a table from above and click 'browse'.</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
<div id="handson-table"></div>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
@ -70,6 +71,44 @@
|
||||||
<input type="submit" name="action" value="last" {{#if pagingData.lastPage}}disabled{{/if}} />
|
<input type="submit" name="action" value="last" {{#if pagingData.lastPage}}disabled{{/if}} />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="/js/lib/handsontable.full.min.js"></script>
|
||||||
|
|
||||||
{{> partials/suffix}}
|
{{> partials/suffix}}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function main() {
|
||||||
|
const table = document.getElementById('data-table')
|
||||||
|
if (!table) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = htmlToHandsonData(table)
|
||||||
|
table.remove()
|
||||||
|
|
||||||
|
const renderers = []
|
||||||
|
for (const header of data.headers) {
|
||||||
|
renderers.push({ renderer: 'nullRenderer' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const hot = new Handsontable(document.getElementById('handson-table'), {
|
||||||
|
data: data.rows,
|
||||||
|
colHeaders: data.headers,
|
||||||
|
columns: renderers,
|
||||||
|
readOnly: true,
|
||||||
|
filters: true,
|
||||||
|
columnSorting: true,
|
||||||
|
manualColumnResize: true,
|
||||||
|
manualColumnMove: true,
|
||||||
|
manualRowResize: true,
|
||||||
|
dropdownMenu: ['filter_by_condition', 'filter_by_value', 'filter_action_bar'],
|
||||||
|
viewportColumnRenderingOffset: 1000,
|
||||||
|
licenseKey: 'non-commercial-and-evaluation'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
47
spinner/lib/src/main/assets/css/lib/handsontable.full.min.css
vendored
Normal file
47
spinner/lib/src/main/assets/css/lib/handsontable.full.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -12,18 +12,12 @@ select, input {
|
||||||
}
|
}
|
||||||
|
|
||||||
table, th, td {
|
table, th, td {
|
||||||
border: 1px solid black;
|
font-family: 'JetBrains Mono', monospace;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
th, td {
|
.handsontable td.htDimmed {
|
||||||
padding: 8px;
|
color: #000;
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
background: #fff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.query-input {
|
.query-input {
|
||||||
|
@ -84,6 +78,10 @@ h2.collapse-header, h2.collapse-header+div {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.invisible {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
table.device-info {
|
table.device-info {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
889
spinner/lib/src/main/assets/js/lib/handsontable.full.min.js
vendored
Normal file
889
spinner/lib/src/main/assets/js/lib/handsontable.full.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -13,6 +13,45 @@ function init() {
|
||||||
document.querySelector('#database-selector').onchange = (e) => {
|
document.querySelector('#database-selector').onchange = (e) => {
|
||||||
window.location.href = window.location.href.split('?')[0] + '?db=' + e.target.value;
|
window.location.href = window.location.href.split('?')[0] + '?db=' + e.target.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Handsontable) {
|
||||||
|
Handsontable.renderers.registerRenderer('nullRenderer', nullRenderer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function htmlToHandsonData(table) {
|
||||||
|
const headers = []
|
||||||
|
const rows = []
|
||||||
|
|
||||||
|
for (const row of table.querySelectorAll('tr')) {
|
||||||
|
for (const th of row.querySelectorAll('th')) {
|
||||||
|
headers.push(th.innerText)
|
||||||
|
}
|
||||||
|
|
||||||
|
const cells = []
|
||||||
|
|
||||||
|
for (const td of row.querySelectorAll('td')) {
|
||||||
|
cells.push(td.innerText)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cells.length > 0) {
|
||||||
|
rows.push(cells)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
headers: headers,
|
||||||
|
rows: rows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nullRenderer(hot, td, row, column, props, value, cellProperties) {
|
||||||
|
if (value === 'null') {
|
||||||
|
td.innerHTML = `<em class="null">null</em>`
|
||||||
|
} else {
|
||||||
|
td.innerHTML = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- handsontable -->
|
||||||
|
<link href="/css/lib/handsontable.full.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Us -->
|
||||||
<link href="/css/main.css" rel="stylesheet">
|
<link href="/css/main.css" rel="stylesheet">
|
||||||
<style type="text/css">
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
{{queryResult.timeToFirstRow}} ms to read the first row. <br />
|
{{queryResult.timeToFirstRow}} ms to read the first row. <br />
|
||||||
{{queryResult.timeToReadRows}} ms to read the rest of the rows. <br />
|
{{queryResult.timeToReadRows}} ms to read the rest of the rows. <br />
|
||||||
<br />
|
<br />
|
||||||
<table>
|
<table id="data-table" class="invisible">
|
||||||
<tr>
|
<tr>
|
||||||
{{#each queryResult.columns}}
|
{{#each queryResult.columns}}
|
||||||
<th>{{this}}</th>
|
<th>{{this}}</th>
|
||||||
|
@ -43,10 +43,14 @@
|
||||||
</tr>
|
</tr>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<div id="handson-table"></div>
|
||||||
{{else}}
|
{{else}}
|
||||||
No data.
|
No data.
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
<script src="/js/lib/handsontable.full.min.js"></script>
|
||||||
|
|
||||||
{{> partials/suffix}}
|
{{> partials/suffix}}
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql-formatter/4.0.2/sql-formatter.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql-formatter/4.0.2/sql-formatter.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
@ -87,6 +91,34 @@
|
||||||
bindKey: {win: "Ctrl-Shift-F", mac: "Command-Shift-F"},
|
bindKey: {win: "Ctrl-Shift-F", mac: "Command-Shift-F"},
|
||||||
exec: formatSql
|
exec: formatSql
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const table = document.getElementById('data-table')
|
||||||
|
if (!table) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = htmlToHandsonData(table)
|
||||||
|
table.remove()
|
||||||
|
|
||||||
|
const renderers = []
|
||||||
|
for (const header of data.headers) {
|
||||||
|
renderers.push({ renderer: 'nullRenderer' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const hot = new Handsontable(document.getElementById('handson-table'), {
|
||||||
|
data: data.rows,
|
||||||
|
colHeaders: data.headers,
|
||||||
|
columns: renderers,
|
||||||
|
readOnly: true,
|
||||||
|
filters: true,
|
||||||
|
columnSorting: true,
|
||||||
|
manualColumnResize: true,
|
||||||
|
manualColumnMove: true,
|
||||||
|
manualRowResize: true,
|
||||||
|
dropdownMenu: ['filter_by_condition', 'filter_by_value', 'filter_action_bar'],
|
||||||
|
viewportColumnRenderingOffset: 1000,
|
||||||
|
licenseKey: 'non-commercial-and-evaluation'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function onFormatClicked(e) {
|
function onFormatClicked(e) {
|
||||||
|
|
|
@ -61,8 +61,8 @@ internal class SpinnerServer(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return when {
|
return when {
|
||||||
session.method == Method.GET && session.uri == "/css/main.css" -> newFileResponse("css/main.css", "text/css")
|
session.method == Method.GET && session.uri.startsWith("/css/") -> newFileResponse(session.uri.substring(1), "text/css")
|
||||||
session.method == Method.GET && session.uri == "/js/main.js" -> newFileResponse("js/main.js", "text/javascript")
|
session.method == Method.GET && session.uri.startsWith("/js/") -> newFileResponse(session.uri.substring(1), "text/javascript")
|
||||||
session.method == Method.GET && session.uri == "/" -> getIndex(dbParam, dbConfig.db())
|
session.method == Method.GET && session.uri == "/" -> getIndex(dbParam, dbConfig.db())
|
||||||
session.method == Method.GET && session.uri == "/browse" -> getBrowse(dbParam, dbConfig.db())
|
session.method == Method.GET && session.uri == "/browse" -> getBrowse(dbParam, dbConfig.db())
|
||||||
session.method == Method.POST && session.uri == "/browse" -> postBrowse(dbParam, dbConfig, session)
|
session.method == Method.POST && session.uri == "/browse" -> postBrowse(dbParam, dbConfig, session)
|
||||||
|
|
Loading…
Add table
Reference in a new issue