mirror of
https://github.com/lana-k/sqliteviz.git
synced 2026-02-04 15:38:55 +08:00
change repo structure
This commit is contained in:
228
src/components/RunResult/Record/index.vue
Normal file
228
src/components/RunResult/Record/index.vue
Normal file
@@ -0,0 +1,228 @@
|
||||
<template>
|
||||
<div class="record-view">
|
||||
<div class="table-container">
|
||||
<table
|
||||
ref="table"
|
||||
class="sqliteviz-table"
|
||||
tabindex="0"
|
||||
@keydown="onTableKeydown"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th />
|
||||
<th>
|
||||
<div class="cell-data">Row #{{ currentRowIndex + 1 }}</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(col, index) in columns" :key="index">
|
||||
<th class="column-cell" :title="col">
|
||||
{{ col }}
|
||||
</th>
|
||||
<td
|
||||
:key="index"
|
||||
:data-col="index"
|
||||
:data-row="currentRowIndex"
|
||||
:data-isNull="isNull(getCellValue(col))"
|
||||
:data-isBlob="isBlob(getCellValue(col))"
|
||||
:aria-selected="false"
|
||||
@click="onCellClick"
|
||||
>
|
||||
<div class="cell-data">
|
||||
{{ getCellText(col) }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-footer">
|
||||
<div class="table-footer-count">
|
||||
{{ rowCount }} {{ rowCount === 1 ? 'row' : 'rows' }} retrieved
|
||||
<span v-if="time">in {{ time }}</span>
|
||||
</div>
|
||||
|
||||
<row-navigator v-model="currentRowIndex" :total="rowCount" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import RowNavigator from './RowNavigator.vue'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
export default {
|
||||
components: { RowNavigator },
|
||||
props: {
|
||||
dataSet: Object,
|
||||
time: String,
|
||||
rowIndex: { type: Number, default: 0 },
|
||||
selectedColumnIndex: Number
|
||||
},
|
||||
emits: ['updateSelectedCell'],
|
||||
data() {
|
||||
return {
|
||||
selectedCellElement: null,
|
||||
currentRowIndex: this.rowIndex
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
columns() {
|
||||
return this.dataSet.columns
|
||||
},
|
||||
rowCount() {
|
||||
return this.dataSet.values[this.columns[0]].length
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
async currentRowIndex() {
|
||||
await nextTick()
|
||||
if (this.selectedCellElement) {
|
||||
const previouslySelected = this.selectedCellElement
|
||||
this.selectCell(null)
|
||||
this.selectCell(previouslySelected)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const col = this.selectedColumnIndex
|
||||
const row = this.currentRowIndex
|
||||
const cell = this.$refs.table.querySelector(
|
||||
`td[data-col="${col}"][data-row="${row}"]`
|
||||
)
|
||||
if (cell) {
|
||||
this.selectCell(cell)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isBlob(value) {
|
||||
return value && ArrayBuffer.isView(value)
|
||||
},
|
||||
isNull(value) {
|
||||
return value === null
|
||||
},
|
||||
getCellValue(col) {
|
||||
return this.dataSet.values[col][this.currentRowIndex]
|
||||
},
|
||||
getCellText(col) {
|
||||
const value = this.getCellValue(col)
|
||||
if (this.isNull(value)) {
|
||||
return 'NULL'
|
||||
}
|
||||
if (this.isBlob(value)) {
|
||||
return 'BLOB'
|
||||
}
|
||||
return value
|
||||
},
|
||||
onTableKeydown(e) {
|
||||
const keyCodeMap = {
|
||||
38: 'up',
|
||||
40: 'down'
|
||||
}
|
||||
|
||||
if (
|
||||
!this.selectedCellElement ||
|
||||
!Object.keys(keyCodeMap).includes(e.keyCode.toString())
|
||||
) {
|
||||
return
|
||||
}
|
||||
e.preventDefault()
|
||||
|
||||
this.moveFocusInTable(this.selectedCellElement, keyCodeMap[e.keyCode])
|
||||
},
|
||||
onCellClick(e) {
|
||||
this.selectCell(e.target.closest('td'), false)
|
||||
},
|
||||
selectCell(cell, scrollTo = true) {
|
||||
if (!cell) {
|
||||
if (this.selectedCellElement) {
|
||||
this.selectedCellElement.ariaSelected = 'false'
|
||||
}
|
||||
this.selectedCellElement = cell
|
||||
} else if (!cell.ariaSelected || cell.ariaSelected === 'false') {
|
||||
if (this.selectedCellElement) {
|
||||
this.selectedCellElement.ariaSelected = 'false'
|
||||
}
|
||||
cell.ariaSelected = 'true'
|
||||
this.selectedCellElement = cell
|
||||
} else {
|
||||
cell.ariaSelected = 'false'
|
||||
this.selectedCellElement = null
|
||||
}
|
||||
|
||||
if (this.selectedCellElement && scrollTo) {
|
||||
this.selectedCellElement.scrollIntoView()
|
||||
this.selectedCellElement
|
||||
.closest('.table-container')
|
||||
.scrollTo({ left: 0 })
|
||||
}
|
||||
|
||||
this.$emit('updateSelectedCell', this.selectedCellElement)
|
||||
},
|
||||
moveFocusInTable(initialCell, direction) {
|
||||
const currentColIndex = +initialCell.dataset.col
|
||||
const newColIndex =
|
||||
direction === 'up' ? currentColIndex - 1 : currentColIndex + 1
|
||||
|
||||
const newCell = this.$refs.table.querySelector(
|
||||
`td[data-col="${newColIndex}"][data-row="${this.currentRowIndex}"]`
|
||||
)
|
||||
if (newCell) {
|
||||
this.selectCell(newCell)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
table.sqliteviz-table:focus {
|
||||
outline: none;
|
||||
}
|
||||
.sqliteviz-table tbody td:hover {
|
||||
background-color: var(--color-bg-light-3);
|
||||
}
|
||||
.sqliteviz-table tbody td[aria-selected='true'] {
|
||||
box-shadow: inset 0 0 0 1px var(--color-accent);
|
||||
}
|
||||
|
||||
table.sqliteviz-table {
|
||||
margin-top: 0;
|
||||
}
|
||||
.sqliteviz-table thead tr th {
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
text-align: left;
|
||||
}
|
||||
.sqliteviz-table tbody tr th {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--color-bg-dark);
|
||||
color: var(--color-text-light);
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
border-right: 1px solid var(--color-border-light);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.table-footer {
|
||||
align-items: center;
|
||||
}
|
||||
.record-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.column-cell {
|
||||
max-width: 150px;
|
||||
width: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user