1
0
mirror of https://github.com/lana-k/sqliteviz.git synced 2025-12-06 18:18:53 +08:00
This commit is contained in:
lana-k
2025-03-20 22:04:15 +01:00
parent 5e2b34a856
commit 0c1b91ab2f
146 changed files with 3317 additions and 2438 deletions

View File

@@ -1,6 +1,10 @@
<template>
<div
:class="['checkbox-container', { 'checked': checked }, {'disabled': disabled}]"
:class="[
'checkbox-container',
{ checked: checked },
{ disabled: disabled }
]"
@click.stop="onClick"
>
<div v-show="!checked" class="unchecked" />
@@ -31,7 +35,7 @@ export default {
type: String,
required: false,
default: 'accent',
validator: (value) => {
validator: value => {
return ['accent', 'light'].includes(value)
}
},
@@ -52,13 +56,13 @@ export default {
}
},
emits: ['click'],
data () {
data() {
return {
checked: this.init
}
},
methods: {
onClick () {
onClick() {
if (!this.disabled) {
this.checked = !this.checked
this.$emit('click', this.checked)
@@ -86,7 +90,7 @@ export default {
}
img {
display: block;
display: block;
}
.label {
margin-left: 6px;
@@ -106,6 +110,6 @@ img {
.disabled .unchecked,
.disabled .unchecked:hover {
background-color: var(--color-bg-light-2);
background-color: var(--color-bg-light-2);
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div :class="{ 'disabled': disabled }">
<div :class="{ disabled: disabled }">
<div class="text-field-label">Delimiter</div>
<div
class="delimiter-selector-container"
@@ -8,7 +8,7 @@
>
<div class="value">
<input
:class="{ 'filled': filled }"
:class="{ filled: filled }"
ref="delimiterInput"
type="text"
maxlength="1"
@@ -19,7 +19,7 @@
<div class="name">{{ getSymbolName(modelValue) }}</div>
</div>
<div class="controls" @click.stop>
<clear-icon @click="clear" :disabled="disabled"/>
<clear-icon @click="clear" :disabled="disabled" />
<drop-down-chevron
:disabled="disabled"
@click="!disabled && (showOptions = !showOptions)"
@@ -33,7 +33,8 @@
@click="chooseOption(option)"
class="option"
>
<pre>{{option}}</pre><div>{{ getSymbolName(option) }}</div>
<pre>{{ option }}</pre>
<div>{{ getSymbolName(option) }}</div>
</div>
</div>
</div>
@@ -49,7 +50,7 @@ export default {
props: ['modelValue', 'width', 'disabled'],
emits: ['update:modelValue'],
components: { DropDownChevron, ClearIcon },
data () {
data() {
return {
showOptions: false,
options: [',', '\t', ' ', '|', ';', '\u001F', '\u001E'],
@@ -58,7 +59,7 @@ export default {
}
},
watch: {
inputValue () {
inputValue() {
if (this.inputValue) {
this.filled = true
if (this.inputValue !== this.modelValue) {
@@ -69,25 +70,25 @@ export default {
}
}
},
created () {
created() {
this.inputValue = this.modelValue
},
methods: {
getSymbolName (str) {
getSymbolName(str) {
if (!str) {
return ''
}
return ascii[str.charCodeAt(0).toString()].name
},
chooseOption (option) {
chooseOption(option) {
this.inputValue = option
this.showOptions = false
},
onContainerClick (event) {
onContainerClick(event) {
this.$refs.delimiterInput.focus()
},
clear () {
clear() {
if (!this.disabled) {
this.inputValue = ''
this.$refs.delimiterInput.focus()

View File

@@ -8,7 +8,7 @@
>
<div class="dialog-header">
{{ typeName }} import
<close-icon @click="cancelImport" :disabled="disableDialog"/>
<close-icon @click="cancelImport" :disabled="disableDialog" />
</div>
<div class="dialog-body">
<text-field
@@ -66,10 +66,7 @@
class="preview-table"
/>
<div v-else class="no-data">No data</div>
<logs
class="import-errors"
:messages="importMessages"
/>
<logs class="import-errors" :messages="importMessages" />
</div>
<div class="dialog-buttons-container">
<button
@@ -130,7 +127,7 @@ export default {
dialogName: String
},
emits: ['cancel', 'finish'],
data () {
data() {
return {
disableDialog: false,
disableImport: false,
@@ -147,24 +144,24 @@ export default {
}
},
computed: {
isJson () {
isJson() {
return fIo.isJSON(this.file)
},
isNdJson () {
isNdJson() {
return fIo.isNDJSON(this.file)
},
typeName () {
typeName() {
return this.isJson || this.isNdJson ? 'JSON' : 'CSV'
}
},
watch: {
isJson () {
isJson() {
if (this.isJson) {
this.delimiter = '\u001E'
this.header = false
}
},
isNdJson () {
isNdJson() {
if (this.isNdJson) {
this.delimiter = '\u001E'
this.header = false
@@ -175,18 +172,17 @@ export default {
if (!this.tableName) {
return
}
this.db.validateTableName(this.tableName)
.catch(err => {
this.tableNameError = err.message + '. Try another table name.'
})
this.db.validateTableName(this.tableName).catch(err => {
this.tableNameError = err.message + '. Try another table name.'
})
}, 400)
},
methods: {
changeHeaderDisplaying (e) {
changeHeaderDisplaying(e) {
this.header = e
this.preview()
},
cancelImport () {
cancelImport() {
if (!this.disableDialog) {
if (this.addedTable) {
this.db.execute(`DROP TABLE "${this.addedTable}"`)
@@ -196,7 +192,7 @@ export default {
this.$emit('cancel')
}
},
reset () {
reset() {
this.header = !this.isJson && !this.isNdJson
this.quoteChar = '"'
this.escapeChar = '"'
@@ -210,11 +206,11 @@ export default {
this.addedTable = null
this.tableNameError = ''
},
open () {
open() {
this.tableName = this.db.sanitizeTableName(fIo.getFileName(this.file))
this.$modal.show(this.dialogName)
},
async preview () {
async preview() {
this.disableImport = false
if (!this.file) {
return
@@ -257,13 +253,15 @@ export default {
}
} catch (err) {
console.error(err)
this.importMessages = [{
message: err,
type: 'error'
}]
this.importMessages = [
{
message: err,
type: 'error'
}
]
}
},
async getJsonParseResult (file) {
async getJsonParseResult(file) {
const jsonContent = await fIo.getFileContent(file)
const isEmpty = !jsonContent.trim()
return {
@@ -273,10 +271,10 @@ export default {
},
hasErrors: false,
messages: [],
rowCount: +(!isEmpty)
rowCount: +!isEmpty
}
},
async loadToDb (file) {
async loadToDb(file) {
if (!this.tableName) {
this.tableNameError = "Table name can't be empty"
return
@@ -297,7 +295,9 @@ export default {
})
// Get *reactive* link to parsing message for later updates
parsingMsg = this.importMessages[this.importMessages.length - 1]
const parsingLoadingIndicator = setTimeout(() => { parsingMsg.type = 'loading' }, 1000)
const parsingLoadingIndicator = setTimeout(() => {
parsingMsg.type = 'loading'
}, 1000)
let importMsg = {}
let importLoadingIndicator = null
@@ -321,7 +321,9 @@ export default {
parsingMsg.type = 'success'
if (parseResult.messages.length > 0) {
this.importMessages = this.importMessages.concat(parseResult.messages)
this.importMessages = this.importMessages.concat(
parseResult.messages
)
parsingMsg.message = `${rowCount} rows are parsed in ${period}.`
} else {
// Inform about parsing success
@@ -345,14 +347,19 @@ export default {
// Add table
start = new Date()
await this.db.addTableFromCsv(this.tableName, parseResult.data, progressCounterId)
await this.db.addTableFromCsv(
this.tableName,
parseResult.data,
progressCounterId
)
end = new Date()
this.addedTable = this.tableName
// Inform about import success
period = time.getPeriod(start, end)
importMsg.message = `Importing ${this.typeName} ` +
`into a SQLite database is completed in ${period}.`
importMsg.message =
`Importing ${this.typeName} ` +
`into a SQLite database is completed in ${period}.`
importMsg.type = 'success'
// Loading indicator for import is not needed anymore
@@ -385,7 +392,7 @@ export default {
this.db.deleteProgressCounter(progressCounterId)
this.disableDialog = false
},
async finish () {
async finish() {
this.$modal.hide(this.dialogName)
const stmt = this.getQueryExample()
const tabId = await this.$store.dispatch('addTab', { query: stmt })
@@ -394,20 +401,20 @@ export default {
this.$emit('finish')
events.send('inquiry.create', null, { auto: true })
},
getQueryExample () {
getQueryExample() {
return this.isNdJson
? this.getNdJsonQueryExample()
: this.isJson
? this.getJsonQueryExample()
: [
'/*',
` * Your CSV file has been imported into ${this.addedTable} table.`,
' * You can run this SQL query to make all CSV records available for charting.',
' */',
`SELECT * FROM "${this.addedTable}"`
` * Your CSV file has been imported into ${this.addedTable} table.`,
' * You can run this SQL query to make all CSV records available for charting.',
' */',
`SELECT * FROM "${this.addedTable}"`
].join('\n')
},
getNdJsonQueryExample () {
getNdJsonQueryExample() {
try {
const firstRowJson = JSON.parse(this.previewData.values.doc[0])
const firstKey = Object.keys(firstRowJson)[0]
@@ -415,7 +422,7 @@ export default {
'/*',
` * Your NDJSON file has been imported into ${this.addedTable} table.`,
` * Run this SQL query to get values of property ${firstKey} ` +
'and make them available for charting.',
'and make them available for charting.',
' */',
`SELECT doc->>'${firstKey}'`,
`FROM "${this.addedTable}"`
@@ -431,7 +438,7 @@ export default {
].join('\n')
}
},
getJsonQueryExample () {
getJsonQueryExample() {
try {
const firstRowJson = JSON.parse(this.previewData.values.doc[0])
const firstKey = Object.keys(firstRowJson)[0]
@@ -439,7 +446,7 @@ export default {
'/*',
` * Your JSON file has been imported into ${this.addedTable} table.`,
` * Run this SQL query to get values of property ${firstKey} ` +
'and make them available for charting.',
'and make them available for charting.',
' */',
'SELECT *',
`FROM "${this.addedTable}"`,
@@ -475,7 +482,7 @@ export default {
}
#csv-json-table-name {
margin-bottom: 24px;
margin-bottom: 24px;
}
.chars {
@@ -508,5 +515,4 @@ margin-bottom: 24px;
justify-content: center;
align-items: center;
}
</style>

View File

@@ -1,17 +1,17 @@
<template>
<div class="db-uploader-container" :style="{ width }">
<change-db-icon v-if="type === 'small'" @click="browse"/>
<change-db-icon v-if="type === 'small'" @click="browse" />
<div v-if="type === 'illustrated'" class="drop-area-container">
<div
class="drop-area"
@dragover.prevent="state = 'dragover'"
@dragleave.prevent="state=''"
@dragleave.prevent="state = ''"
@drop.prevent="drop"
@click="browse"
>
<div class="text">
Drop the database, CSV, JSON or NDJSON file here
or click to choose a file from your computer.
Drop the database, CSV, JSON or NDJSON file here or click to choose a
file from your computer.
</div>
</div>
</div>
@@ -19,16 +19,16 @@
<img id="drop-file-top-img" src="~@/assets/images/top.svg" />
<img
id="left-arm-img"
:class="{'swing': state === 'dragover'}"
:class="{ swing: state === 'dragover' }"
src="~@/assets/images/leftArm.svg"
/>
<img
id="file-img"
ref="fileImg"
:class="{
'swing': state === 'dragover',
'fly': state === 'dropping',
'hidden': state === 'dropped'
swing: state === 'dragover',
fly: state === 'dropping',
hidden: state === 'dropped'
}"
src="~@/assets/images/file.png"
/>
@@ -36,7 +36,7 @@
<img id="body-img" src="~@/assets/images/body.svg" />
<img
id="right-arm-img"
:class="{'swing': state === 'dragover'}"
:class="{ swing: state === 'dragover' }"
src="~@/assets/images/rightArm.svg"
/>
</div>
@@ -68,7 +68,7 @@ export default {
type: String,
required: false,
default: 'small',
validator: (value) => {
validator: value => {
return ['illustrated', 'small'].includes(value)
}
},
@@ -83,7 +83,7 @@ export default {
ChangeDbIcon,
CsvJsonImport
},
data () {
data() {
return {
state: '',
animationPromise: Promise.resolve(),
@@ -91,9 +91,9 @@ export default {
newDb: null
}
},
mounted () {
mounted() {
if (this.type === 'illustrated') {
this.animationPromise = new Promise((resolve) => {
this.animationPromise = new Promise(resolve => {
this.$refs.fileImg.addEventListener('animationend', event => {
if (event.animationName.startsWith('fly')) {
this.state = 'dropped'
@@ -104,26 +104,27 @@ export default {
}
},
methods: {
cancelImport () {
cancelImport() {
if (this.newDb) {
this.newDb.shutDown()
this.newDb = null
}
},
async finish () {
async finish() {
this.$store.commit('setDb', this.newDb)
if (this.$route.path !== '/workspace') {
this.$router.push('/workspace')
}
},
loadDb (file) {
return Promise.all([this.newDb.loadDb(file), this.animationPromise])
.then(this.finish)
loadDb(file) {
return Promise.all([this.newDb.loadDb(file), this.animationPromise]).then(
this.finish
)
},
async checkFile (file) {
async checkFile(file) {
this.state = 'dropping'
this.newDb = database.getNewDatabase()
@@ -140,16 +141,19 @@ export default {
await this.$nextTick()
const csvJsonImportModal = this.$refs.addCsvJson
csvJsonImportModal.reset()
return Promise.all([csvJsonImportModal.preview(), this.animationPromise])
.then(csvJsonImportModal.open)
return Promise.all([
csvJsonImportModal.preview(),
this.animationPromise
]).then(csvJsonImportModal.open)
}
},
browse () {
fIo.getFileFromUser('.db,.sqlite,.sqlite3,.csv,.json,.ndjson')
browse() {
fIo
.getFileFromUser('.db,.sqlite,.sqlite3,.csv,.json,.ndjson')
.then(this.checkFile)
},
drop (event) {
drop(event) {
this.checkFile(event.dataTransfer.files[0])
}
}
@@ -243,11 +247,15 @@ export default {
transform-origin: 0 56px;
}
#file-img.swing {
transform-origin: -74px 139px;
transform-origin: -74px 139px;
}
@keyframes swing {
0% { transform: rotate(0deg); }
100% { transform: rotate(-7deg); }
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-7deg);
}
}
#file-img.fly {

View File

@@ -10,7 +10,12 @@
<div v-show="loading" class="icon-in-progress">
<loading-indicator />
</div>
<span v-if="tooltip" class="icon-tooltip" :style="tooltipStyle" ref="tooltip">
<span
v-if="tooltip"
class="icon-tooltip"
:style="tooltipStyle"
ref="tooltip"
>
{{ tooltip }}
</span>
</button>
@@ -27,7 +32,7 @@ export default {
components: { LoadingIndicator },
mixins: [tooltipMixin],
methods: {
onClick () {
onClick() {
this.hideTooltip()
this.$emit('click')
}
@@ -59,8 +64,8 @@ export default {
fill: var(--color-accent);
}
.icon-btn:disabled .icon :deep(path),
.icon-btn:disabled .icon :deep(circle) {
.icon-btn:disabled .icon :deep(path),
.icon-btn:disabled .icon :deep(circle) {
fill: var(--color-border);
}

View File

@@ -3,20 +3,23 @@
:modal-id="name"
class="dialog"
:clickToClose="false"
:contentTransition="{name: 'loading-dialog'}"
:overlayTransition="{name: 'loading-dialog'}"
:contentTransition="{ name: 'loading-dialog' }"
:overlayTransition="{ name: 'loading-dialog' }"
>
<div class="dialog-header">
{{ title }}
<close-icon @click="$emit('cancel')" :disabled="loading"/>
<close-icon @click="$emit('cancel')" :disabled="loading" />
</div>
<div class="dialog-body">
<div v-if="loading" class="loading-dialog-body">
<loading-indicator :size="30" class="state-icon"/>
<loading-indicator :size="30" class="state-icon" />
{{ loadingMsg }}
</div>
<div v-else class="loading-dialog-body">
<img src="~@/assets/images/success.svg" class="success-icon state-icon" />
<img
src="~@/assets/images/success.svg"
class="success-icon state-icon"
/>
{{ successMsg }}
</div>
</div>
@@ -57,7 +60,7 @@ export default {
},
emits: ['cancel', 'action'],
watch: {
loading () {
loading() {
if (this.loading) {
this.$modal.show(this.name)
}
@@ -65,7 +68,7 @@ export default {
},
components: { LoadingIndicator, CloseIcon },
methods: {
cancel () {
cancel() {
this.$emit('cancel')
}
}

View File

@@ -1,5 +1,10 @@
<template>
<svg :class="animationClass" :height="size" :width="size" :viewBox="`0 0 ${size} ${size}`">
<svg
:class="animationClass"
:height="size"
:width="size"
:viewBox="`0 0 ${size} ${size}`"
>
<circle
class="loader-svg bg"
:style="{ strokeWidth }"
@@ -9,7 +14,11 @@
/>
<circle
class="loader-svg front"
:style="{ strokeDasharray: circleProgress, strokeDashoffset: offset, strokeWidth }"
:style="{
strokeDasharray: circleProgress,
strokeDashoffset: offset,
strokeWidth
}"
:cx="size / 2"
:cy="size / 2"
:r="radius"
@@ -33,22 +42,24 @@ export default {
},
emits: [],
computed: {
circleProgress () {
circleProgress() {
const circle = this.radius * 3.14 * 2
const dash = this.progress ? (circle * this.progress) / 100 : circle * 1 / 3
const dash = this.progress
? (circle * this.progress) / 100
: (circle * 1) / 3
const space = circle - dash
return `${dash}px, ${space}px`
},
animationClass () {
animationClass() {
return this.progress === undefined ? 'loading' : 'progress'
},
radius () {
radius() {
return this.size / 2 - this.strokeWidth
},
offset () {
return this.radius * 3.14 / 2
offset() {
return (this.radius * 3.14) / 2
},
strokeWidth () {
strokeWidth() {
return this.size / 10
}
}
@@ -58,7 +69,10 @@ export default {
<style scoped>
.loader-svg {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
left: 0;
right: 0;
top: 0;
bottom: 0;
fill: none;
stroke-linecap: round;
stroke: var(--color-accent);
@@ -70,7 +84,7 @@ export default {
.loading .loader-svg.front {
will-change: transform;
animation: fill-animation-loading 1s cubic-bezier(1,1,1,1) 0s infinite;
animation: fill-animation-loading 1s cubic-bezier(1, 1, 1, 1) 0s infinite;
transform-origin: center;
}
@@ -97,10 +111,10 @@ export default {
}
.progress .loader-svg.bg {
animation: bg-animation 1.5s cubic-bezier(1,1,1,1) 0s infinite;
animation: bg-animation 1.5s cubic-bezier(1, 1, 1, 1) 0s infinite;
}
@keyframes bg-animation{
@keyframes bg-animation {
0% {
r: 8;
}
@@ -109,8 +123,7 @@ export default {
r: 9;
}
100% {
r: 8;
r: 8;
}
}
</style>

View File

@@ -1,10 +1,17 @@
<template>
<div class="logs-container" ref="logsContainer">
<div v-for="(msg, index) in messages" :key="index" class="msg">
<img v-if="msg.type === 'error'" src="~@/assets/images/error.svg">
<img v-if="msg.type === 'info'" src="~@/assets/images/info.svg" width="20px">
<img v-if="msg.type === 'success'" src="~@/assets/images/success.svg">
<loading-indicator v-if="msg.type === 'loading'" :progress="msg.progress" />
<img v-if="msg.type === 'error'" src="~@/assets/images/error.svg" />
<img
v-if="msg.type === 'info'"
src="~@/assets/images/info.svg"
width="20px"
/>
<img v-if="msg.type === 'success'" src="~@/assets/images/success.svg" />
<loading-indicator
v-if="msg.type === 'loading'"
:progress="msg.progress"
/>
<span class="msg-text">{{ serializeMessage(msg) }}</span>
</div>
</div>
@@ -21,11 +28,11 @@ export default {
watch: {
'messages.length': 'scrollToBottom'
},
mounted () {
mounted() {
this.scrollToBottom()
},
methods: {
async scrollToBottom () {
async scrollToBottom() {
const container = this.$refs.logsContainer
if (container) {
await this.$nextTick()
@@ -33,7 +40,7 @@ export default {
}
},
serializeMessage (msg) {
serializeMessage(msg) {
let result = ''
if (msg.row !== null && msg.row !== undefined) {
if (msg.type === 'error') {
@@ -44,7 +51,7 @@ export default {
}
result += msg.message
if (!(/(\.|!|\?)$/.test(result))) {
if (!/(\.|!|\?)$/.test(result)) {
result += '.'
}

View File

@@ -7,7 +7,11 @@
{ 'splitpanes-dragging': dragging }
]"
>
<div class="movable-splitter" ref="movableSplitter" :style="movableSplitterStyle" />
<div
class="movable-splitter"
ref="movableSplitter"
:style="movableSplitterStyle"
/>
<div
class="splitpanes-pane"
ref="left"
@@ -27,8 +31,11 @@
:class="[
'toggle-btns',
{
'both': after.max === 100 && before.max === 100 &&
paneAfter.size > 0 && paneBefore.size > 0
both:
after.max === 100 &&
before.max === 100 &&
paneAfter.size > 0 &&
paneBefore.size > 0
}
]"
>
@@ -41,7 +48,7 @@
class="direction-icon"
src="~@/assets/images/chevron.svg"
:style="directionBeforeIconStyle"
>
/>
</div>
<div
v-if="before.max === 100 && paneBefore.size > 0"
@@ -52,16 +59,12 @@
class="direction-icon"
src="~@/assets/images/chevron.svg"
:style="directionAfterIconStyle"
>
/>
</div>
</div>
</div>
<!-- splitter end -->
<div
class="splitpanes-pane"
ref="right"
:style="styles.after"
>
<div class="splitpanes-pane" ref="right" :style="styles.after">
<slot name="right-pane" />
</div>
</div>
@@ -87,17 +90,18 @@ export default {
}
},
emits: [],
data () {
data() {
return {
container: null,
paneBefore: this.before,
paneAfter: this.after,
beforeMinimising: !this.after.size || !this.before.size
? this.default
: {
before: this.before.size,
after: this.after.size
},
beforeMinimising:
!this.after.size || !this.before.size
? this.default
: {
before: this.before.size,
after: this.after.size
},
dragging: false,
movableSplitter: {
top: 0,
@@ -107,19 +111,23 @@ export default {
}
},
computed: {
styles () {
styles() {
return {
before: { [this.horizontal ? 'height' : 'width']: `${this.paneBefore.size}%` },
after: { [this.horizontal ? 'height' : 'width']: `${this.paneAfter.size}%` }
before: {
[this.horizontal ? 'height' : 'width']: `${this.paneBefore.size}%`
},
after: {
[this.horizontal ? 'height' : 'width']: `${this.paneAfter.size}%`
}
}
},
movableSplitterStyle () {
movableSplitterStyle() {
const style = { ...this.movableSplitter }
style.top += '%'
style.left += '%'
return style
},
directionBeforeIconStyle () {
directionBeforeIconStyle() {
const expanded = this.paneBefore.size !== 0
const translation = 'translate(-50%, -50%) '
let rotation = ''
@@ -134,7 +142,7 @@ export default {
transform: translation + rotation
}
},
directionAfterIconStyle () {
directionAfterIconStyle() {
const expanded = this.paneAfter.size !== 0
const translation = 'translate(-50%, -50%)'
let rotation = ''
@@ -152,35 +160,43 @@ export default {
},
methods: {
bindEvents () {
bindEvents() {
// Passive: false to prevent scrolling while touch dragging.
document.addEventListener('mousemove', this.onMouseMove, { passive: false })
document.addEventListener('mousemove', this.onMouseMove, {
passive: false
})
document.addEventListener('mouseup', this.onMouseUp)
if ('ontouchstart' in window) {
document.addEventListener('touchmove', this.onMouseMove, { passive: false })
document.addEventListener('touchmove', this.onMouseMove, {
passive: false
})
document.addEventListener('touchend', this.onMouseUp)
}
},
unbindEvents () {
document.removeEventListener('mousemove', this.onMouseMove, { passive: false })
unbindEvents() {
document.removeEventListener('mousemove', this.onMouseMove, {
passive: false
})
document.removeEventListener('mouseup', this.onMouseUp)
if ('ontouchstart' in window) {
document.removeEventListener('touchmove', this.onMouseMove, { passive: false })
document.removeEventListener('touchmove', this.onMouseMove, {
passive: false
})
document.removeEventListener('touchend', this.onMouseUp)
}
},
onMouseMove (event) {
onMouseMove(event) {
event.preventDefault()
this.dragging = true
this.movableSplitter.visibility = 'visible'
this.moveSplitter(event)
},
onMouseUp () {
onMouseUp() {
if (this.dragging) {
const dragPercentage = this.horizontal
? this.movableSplitter.top
@@ -201,7 +217,7 @@ export default {
this.unbindEvents()
},
moveSplitter (event) {
moveSplitter(event) {
const splitterInfo = {
container: this.container,
paneBeforeMax: this.paneBefore.max,
@@ -213,12 +229,13 @@ export default {
this.movableSplitter[dir] = offset
},
togglePane (pane) {
togglePane(pane) {
if (pane.size > 0) {
this.beforeMinimising.before = this.paneBefore.size
this.beforeMinimising.after = this.paneAfter.size
pane.size = 0
const otherPane = pane === this.paneBefore ? this.paneAfter : this.paneBefore
const otherPane =
pane === this.paneBefore ? this.paneAfter : this.paneBefore
otherPane.size = 100 - pane.size
} else {
this.paneBefore.size = this.beforeMinimising.before
@@ -226,7 +243,7 @@ export default {
}
}
},
mounted () {
mounted() {
this.container = this.$refs.container
}
}
@@ -239,9 +256,15 @@ export default {
position: relative;
}
.splitpanes-vertical {flex-direction: row;}
.splitpanes-horizontal {flex-direction: column;}
.splitpanes-dragging * {user-select: none;}
.splitpanes-vertical {
flex-direction: row;
}
.splitpanes-horizontal {
flex-direction: column;
}
.splitpanes-dragging * {
user-select: none;
}
.splitpanes-pane {
width: 100%;
@@ -281,14 +304,14 @@ export default {
.movable-splitter {
position: absolute;
background-color:rgba(162, 177, 198, 0.5);
background-color: rgba(162, 177, 198, 0.5);
}
.splitpanes-vertical > .splitpanes-splitter,
.splitpanes-vertical > .movable-splitter {
width: 8px;
z-index: 5;
height: 100%
height: 100%;
}
.splitpanes-horizontal > .splitpanes-splitter,
@@ -339,20 +362,32 @@ export default {
left: 50%;
}
.splitpanes-horizontal > .splitpanes-splitter .toggle-btns.both .toggle-btn:first-child {
.splitpanes-horizontal
> .splitpanes-splitter
.toggle-btns.both
.toggle-btn:first-child {
border-radius: var(--border-radius-small) 0 0 var(--border-radius-small);
}
.splitpanes-horizontal > .splitpanes-splitter .toggle-btns.both .toggle-btn:last-child {
.splitpanes-horizontal
> .splitpanes-splitter
.toggle-btns.both
.toggle-btn:last-child {
border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0;
margin-left: -1px;
}
.splitpanes-vertical > .splitpanes-splitter .toggle-btns.both .toggle-btn:first-child {
.splitpanes-vertical
> .splitpanes-splitter
.toggle-btns.both
.toggle-btn:first-child {
border-radius: var(--border-radius-small) var(--border-radius-small) 0 0;
}
.splitpanes-vertical > .splitpanes-splitter .toggle-btns.both .toggle-btn:last-child {
.splitpanes-vertical
> .splitpanes-splitter
.toggle-btns.both
.toggle-btn:last-child {
border-radius: 0 0 var(--border-radius-small) var(--border-radius-small);
margin-top: -1px;
}

View File

@@ -1,10 +1,9 @@
export default {
// Get the cursor position relative to the splitpane container.
getCurrentMouseDrag (event, container) {
getCurrentMouseDrag(event, container) {
const rect = container.getBoundingClientRect()
const { clientX, clientY } = ('ontouchstart' in window && event.touches)
? event.touches[0]
: event
const { clientX, clientY } =
'ontouchstart' in window && event.touches ? event.touches[0] : event
return {
x: clientX - rect.left,
y: clientY - rect.top
@@ -12,23 +11,35 @@ export default {
},
// Returns the drag percentage of the splitter relative to the 2 panes it's inbetween.
getCurrentDragPercentage (event, container, isHorisontal) {
getCurrentDragPercentage(event, container, isHorisontal) {
let drag = this.getCurrentMouseDrag(event, container)
drag = drag[isHorisontal ? 'y' : 'x']
const containerSize = container[isHorisontal ? 'clientHeight' : 'clientWidth']
return drag * 100 / containerSize
const containerSize =
container[isHorisontal ? 'clientHeight' : 'clientWidth']
return (drag * 100) / containerSize
},
// Returns the new position in percents.
calculateOffset (event, { container, isHorisontal, paneBeforeMax, paneAfterMax }) {
const dragPercentage = this.getCurrentDragPercentage(event, container, isHorisontal)
calculateOffset(
event,
{ container, isHorisontal, paneBeforeMax, paneAfterMax }
) {
const dragPercentage = this.getCurrentDragPercentage(
event,
container,
isHorisontal
)
const paneBeforeMaxReached = paneBeforeMax < 100 && (dragPercentage >= paneBeforeMax)
const paneAfterMaxReached = paneAfterMax < 100 && (dragPercentage <= 100 - paneAfterMax)
const paneBeforeMaxReached =
paneBeforeMax < 100 && dragPercentage >= paneBeforeMax
const paneAfterMaxReached =
paneAfterMax < 100 && dragPercentage <= 100 - paneAfterMax
// Prevent dragging beyond pane max.
if (paneBeforeMaxReached || paneAfterMaxReached) {
return paneBeforeMaxReached ? paneBeforeMax : Math.max(100 - paneAfterMax, 0)
return paneBeforeMaxReached
? paneBeforeMax
: Math.max(100 - paneAfterMax, 0)
} else {
return Math.min(Math.max(dragPercentage, 0), paneBeforeMax)
}

View File

@@ -25,7 +25,7 @@ export default {
components: { Paginate },
props: ['pageCount', 'modelValue'],
emits: ['update:modelValue'],
data () {
data() {
return {
page: this.modelValue,
chevron: `
@@ -39,10 +39,10 @@ export default {
}
},
watch: {
page () {
page() {
this.$emit('update:modelValue', this.page)
},
modelValue () {
modelValue() {
this.page = this.modelValue
}
}
@@ -93,7 +93,7 @@ export default {
:deep(.paginator-next:hover path),
:deep(.paginator-prev:hover path) {
fill: var(--color-text-active);
fill: var(--color-text-active);
}
:deep(.paginator-disabled path),
:deep(.paginator-disabled:hover path) {

View File

@@ -11,50 +11,50 @@
>
{{ th.name }}
</div>
</div>
</div>
</div>
<div
class="table-container"
ref="table-container"
@scroll="onScrollTable"
>
<table
ref="table"
class="sqliteviz-table"
tabindex="0"
@keydown="onTableKeydown"
>
<thead>
<tr>
<th v-for="(th, index) in columns" :key="index" ref="th">
<div class="cell-data" :style="cellStyle">{{ th }}</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="rowIndex in currentPageData.count" :key="rowIndex">
<td
v-for="(col, colIndex) in columns"
:data-col="colIndex"
:data-row="pageSize * (currentPage - 1) + rowIndex - 1"
:data-isNull="isNull(getCellValue(col, rowIndex))"
:data-isBlob="isBlob(getCellValue(col, rowIndex))"
:key="colIndex"
:aria-selected="false"
@click="onCellClick"
>
<div class="cell-data" :style="cellStyle">
{{ getCellText(col, rowIndex) }}
</div>
</td>
</tr>
</tbody>
</table>
<table
ref="table"
class="sqliteviz-table"
tabindex="0"
@keydown="onTableKeydown"
>
<thead>
<tr>
<th v-for="(th, index) in columns" :key="index" ref="th">
<div class="cell-data" :style="cellStyle">{{ th }}</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="rowIndex in currentPageData.count" :key="rowIndex">
<td
v-for="(col, colIndex) in columns"
:data-col="colIndex"
:data-row="pageSize * (currentPage - 1) + rowIndex - 1"
:data-isNull="isNull(getCellValue(col, rowIndex))"
:data-isBlob="isBlob(getCellValue(col, rowIndex))"
:key="colIndex"
:aria-selected="false"
@click="onCellClick"
>
<div class="cell-data" :style="cellStyle">
{{ getCellText(col, rowIndex) }}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="table-footer">
<div class="table-footer-count">
{{ rowCount }} {{rowCount === 1 ? 'row' : 'rows'}} retrieved
{{ rowCount }} {{ rowCount === 1 ? 'row' : 'rows' }} retrieved
<span v-if="preview">for preview</span>
<span v-if="time">in {{ time }}</span>
</div>
@@ -88,7 +88,7 @@ export default {
selectedCellCoordinates: Object
},
emits: ['updateSelectedCell'],
data () {
data() {
return {
header: null,
tableWidth: null,
@@ -98,20 +98,20 @@ export default {
}
},
computed: {
columns () {
columns() {
return this.dataSet.columns
},
rowCount () {
rowCount() {
return this.dataSet.values[this.columns[0]].length
},
cellStyle () {
cellStyle() {
const eq = this.tableWidth / this.columns.length
return { maxWidth: `${Math.max(eq, 100)}px` }
},
pageCount () {
pageCount() {
return Math.ceil(this.rowCount / this.pageSize)
},
currentPageData () {
currentPageData() {
const start = (this.currentPage - 1) * this.pageSize
let end = start + this.pageSize
if (end > this.rowCount - 1) {
@@ -124,31 +124,32 @@ export default {
}
}
},
mounted () {
mounted() {
this.resizeObserver = new ResizeObserver(this.calculateHeadersWidth)
this.resizeObserver.observe(this.$refs.table)
this.calculateHeadersWidth()
if (this.selectedCellCoordinates) {
const { row, col } = this.selectedCellCoordinates
const cell = this.$refs.table
.querySelector(`td[data-col="${col}"][data-row="${row}"]`)
const cell = this.$refs.table.querySelector(
`td[data-col="${col}"][data-row="${row}"]`
)
if (cell) {
this.selectCell(cell)
}
}
},
methods: {
isBlob (value) {
isBlob(value) {
return value && ArrayBuffer.isView(value)
},
isNull (value) {
isNull(value) {
return value === null
},
getCellValue (col, rowIndex) {
getCellValue(col, rowIndex) {
return this.dataSet.values[col][rowIndex - 1 + this.currentPageData.start]
},
getCellText (col, rowIndex) {
getCellText(col, rowIndex) {
const value = this.getCellValue(col, rowIndex)
if (this.isNull(value)) {
return 'NULL'
@@ -158,7 +159,7 @@ export default {
}
return value
},
calculateHeadersWidth () {
calculateHeadersWidth() {
this.tableWidth = this.$refs['table-container'].offsetWidth
this.$nextTick(() => {
this.header = this.$refs.th.map(th => {
@@ -166,10 +167,11 @@ export default {
})
})
},
onScrollTable () {
this.$refs['header-container'].scrollLeft = this.$refs['table-container'].scrollLeft
onScrollTable() {
this.$refs['header-container'].scrollLeft =
this.$refs['table-container'].scrollLeft
},
onTableKeydown (e) {
onTableKeydown(e) {
const keyCodeMap = {
37: 'left',
39: 'right',
@@ -187,10 +189,10 @@ export default {
this.moveFocusInTable(this.selectedCellElement, keyCodeMap[e.keyCode])
},
onCellClick (e) {
onCellClick(e) {
this.selectCell(e.target.closest('td'), false)
},
selectCell (cell, scrollTo = true) {
selectCell(cell, scrollTo = true) {
if (!cell) {
if (this.selectedCellElement) {
this.selectedCellElement.ariaSelected = 'false'
@@ -213,7 +215,7 @@ export default {
this.$emit('updateSelectedCell', this.selectedCellElement)
},
moveFocusInTable (initialCell, direction) {
moveFocusInTable(initialCell, direction) {
const currentRowIndex = +initialCell.dataset.row
const currentColIndex = +initialCell.dataset.col
let newRowIndex, newColIndex
@@ -242,22 +244,23 @@ export default {
newColIndex = currentColIndex
}
const newCell = this.$refs.table
.querySelector(`td[data-col="${newColIndex}"][data-row="${newRowIndex}"]`)
const newCell = this.$refs.table.querySelector(
`td[data-col="${newColIndex}"][data-row="${newRowIndex}"]`
)
if (newCell) {
this.selectCell(newCell)
}
}
},
beforeUnmount () {
beforeUnmount() {
this.resizeObserver.unobserve(this.$refs.table)
},
watch: {
currentPageData () {
currentPageData() {
this.calculateHeadersWidth()
this.selectCell(null)
},
dataSet () {
dataSet() {
this.currentPage = 1
}
}
@@ -271,7 +274,7 @@ table.sqliteviz-table:focus {
.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);
.sqliteviz-table tbody td[aria-selected='true'] {
box-shadow: inset 0 0 0 1px var(--color-accent);
}
</style>

View File

@@ -1,8 +1,16 @@
<template>
<div>
<div v-if="label" :class="['text-field-label', { error: errorMsg }, {'disabled': disabled}]">
<div
v-if="label"
:class="['text-field-label', { error: errorMsg }, { disabled: disabled }]"
>
{{ label }}
<hint-icon class="hint" v-if="hint" :hint="hint" :max-width="maxHintWidth || '149px'"/>
<hint-icon
class="hint"
v-if="hint"
:hint="hint"
:max-width="maxHintWidth || '149px'"
/>
</div>
<input
type="text"
@@ -75,7 +83,7 @@ input.error {
position: relative;
}
.text-field-label .hint{
.text-field-label .hint {
position: absolute;
top: -2px;
right: -22px;

View File

@@ -29,7 +29,7 @@
</g>
<defs>
<clipPath id="clip0">
<rect width="18" height="18" fill="white"/>
<rect width="18" height="18" fill="white" />
</clipPath>
</defs>
</svg>
@@ -48,7 +48,7 @@ export default {
props: ['tooltip'],
emits: ['click'],
methods: {
onClick () {
onClick() {
this.hideTooltip()
this.$emit('click')
}

View File

@@ -11,10 +11,9 @@
13.5L16.35 6.75L17.9475 8.33625Z"
fill="#506784"
/>
</svg>
</svg>
</template>
<script>
export default {
}
export default {}
</script>

View File

@@ -1,30 +1,30 @@
<template>
<div>
<svg
class="db-edit-icon"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
@click.stop="onClick"
@mouseenter="showTooltip"
@mouseleave="hideTooltip"
>
<path
d="M3 10.5V12.75C3 14.25 5.2875 15.54 8.25 15.75V13.5825L8.3475 13.5C5.34 13.32 3 12.045 3
<div>
<svg
class="db-edit-icon"
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
@click.stop="onClick"
@mouseenter="showTooltip"
@mouseleave="hideTooltip"
>
<path
d="M3 10.5V12.75C3 14.25 5.2875 15.54 8.25 15.75V13.5825L8.3475 13.5C5.34 13.32 3 12.045 3
10.5ZM9 9.75C5.685 9.75 3 8.4075 3 6.75V9C3 10.6575 5.685 12 9 12C9.2925 12 9.5775 12
9.87 12L12.75 9.09C11.55 9.54 10.2825 9.75 9 9.75ZM9 2.25C5.685 2.25 3 3.5925 3 5.25C3
6.9075 5.685 8.25 9 8.25C12.315 8.25 15 6.9075 15 5.25C15 3.5925 12.315 2.25 9 2.25ZM15.75
8.3475C15.6375 8.3475 15.5325 8.3925 15.4575 8.475L14.7075 9.225L16.245 10.725L16.995
9.975C17.1525 9.825 17.16 9.57 16.995 9.3975L16.065 8.475C15.99 8.3925 15.885 8.3475 15.78
8.3475H15.75ZM14.28 9.66L9.75 14.205V15.75H11.295L15.84 11.1975L14.28 9.66Z"
fill="#A2B1C6"
/>
</svg>
<span class="icon-tooltip" :style="tooltipStyle" ref="tooltip">
Load another database, CSV, JSON or NDJSON
</span>
</div>
fill="#A2B1C6"
/>
</svg>
<span class="icon-tooltip" :style="tooltipStyle" ref="tooltip">
Load another database, CSV, JSON or NDJSON
</span>
</div>
</template>
<script>
@@ -35,7 +35,7 @@ export default {
mixins: [tooltipMixin],
emits: ['click'],
methods: {
onClick () {
onClick() {
this.hideTooltip()
this.$emit('click')
}

View File

@@ -1,10 +1,5 @@
<template>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none">
<path
fill-rule="evenodd"
clip-rule="evenodd"
@@ -46,7 +41,6 @@
</template>
<script>
export default {
name: 'ChartIcon'
}

View File

@@ -1,6 +1,6 @@
<template>
<svg
:class="['clear-icon', {'disabled': disabled}]"
:class="['clear-icon', { disabled: disabled }]"
width="20"
height="20"
viewBox="0 0 20 20"
@@ -21,7 +21,6 @@
</template>
<script>
export default {
name: 'ClearIcon',
props: ['disabled']
@@ -42,6 +41,6 @@ export default {
}
.disabled.clear-icon:hover path {
fill: #C8D4E3;
fill: #c8d4e3;
}
</style>

View File

@@ -1,10 +1,5 @@
<template>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none">
<path
d="M14.1917 1.3851H12.4806V0.703125C12.4806 0.314758 12.1658 0 11.7775 0H6.246C5.85764 0
5.54288 0.314758 5.54288 0.703125V1.3851H3.83203C2.86276 1.3851 2.07422 2.17365 2.07422
@@ -26,7 +21,6 @@
</template>
<script>
export default {
name: 'ClipboardIcon'
}

View File

@@ -1,7 +1,7 @@
<template>
<svg
@click.stop="$emit('click')"
:class="['icon', {'disabled': disabled }]"
:class="['icon', { disabled: disabled }]"
:width="size"
:height="size"
viewBox="0 0 14 14"

View File

@@ -1,10 +1,5 @@
<template>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none">
<path
fill-rule="evenodd"
clip-rule="evenodd"
@@ -17,7 +12,7 @@
6.91686 13.5552 6.91522Z"
fill="#A2B1C6"
/>
<circle cx="5.50049" cy="6.00339" r="1.5" fill="#A2B1C6"/>
<circle cx="5.50049" cy="6.00339" r="1.5" fill="#A2B1C6" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
@@ -27,11 +22,10 @@
1.21788ZM16.0374 2.71788L1.96424 2.713L1.96289 15.2773L16.036 15.2821L16.0374 2.71788Z"
fill="#A2B1C6"
/>
</svg>
</svg>
</template>
<script>
export default {
name: 'DataViewIcon'
}

View File

@@ -1,6 +1,6 @@
<template>
<svg
:class="['chevron-icon', {'disabled': disabled}]"
:class="['chevron-icon', { disabled: disabled }]"
width="20"
height="20"
viewBox="0 0 20 20"
@@ -15,7 +15,6 @@
</template>
<script>
export default {
name: 'DropDownChevron',
props: ['disabled']
@@ -36,6 +35,6 @@ export default {
}
.disabled.chevron-icon:hover path {
fill: #C8D4E3;
fill: #c8d4e3;
}
</style>

View File

@@ -21,6 +21,5 @@
</template>
<script>
export default {
}
export default {}
</script>

View File

@@ -32,7 +32,7 @@ export default {
props: ['tooltip', 'tooltipPosition'],
emits: ['click'],
methods: {
onClick () {
onClick() {
this.hideTooltip()
this.$emit('click')
}

View File

@@ -1,10 +1,5 @@
<template>
<svg
width="19"
height="18"
viewBox="0 0 19 18"
fill="none"
>
<svg width="19" height="18" viewBox="0 0 19 18" fill="none">
<path
d="M6.07959 13.5756C6.05908 14.0209 5.93896 14.415 5.71924 14.7578C5.49951 15.0976 5.19043
15.3613 4.79199 15.5488C4.39648 15.7363 3.94385 15.83 3.43408 15.83C2.59326 15.83
@@ -34,7 +29,7 @@
14.6699C9.53809 14.6699 9.73877 14.6157 9.88525 14.5073C10.0347 14.3959 10.1094 14.2407
10.1094 14.0414ZM14.9258 14.0019L16.2002 9.34369H17.9229L15.7695 15.7421H14.082L11.9463
9.34369H13.6558L14.9258 14.0019Z"
fill="#A2B1C6"
fill="#A2B1C6"
/>
<path
d="M3.03345 0.991333H4.89869V2.49133H3.03345V7.93074H1.53345V2.49133C1.53345 1.66633
@@ -55,7 +50,6 @@
</template>
<script>
export default {
name: 'ExportToCsvIcon'
}

View File

@@ -1,10 +1,5 @@
<template>
<svg
width="19"
height="18"
viewBox="0 0 19 18"
fill="none"
>
<svg width="19" height="18" viewBox="0 0 19 18" fill="none">
<path
d="M4.28369 13.9966C4.28369 13.7711 4.20312 13.5953 4.04199 13.4693C3.88379 13.3433 3.604
13.213 3.20264 13.0782C2.80127 12.9434 2.47314 12.813 2.21826 12.6871C1.38916 12.2798
@@ -54,7 +49,6 @@
</template>
<script>
export default {
name: 'ExportToSvgIcon'
}

View File

@@ -33,7 +33,11 @@
fill="#A2B1C6"
/>
</svg>
<span class="icon-tooltip" :style="{...tooltipStyle, maxWidth: maxWidth }" ref="tooltip">
<span
class="icon-tooltip"
:style="{ ...tooltipStyle, maxWidth: maxWidth }"
ref="tooltip"
>
{{ hint }}
</span>
</div>
@@ -48,7 +52,7 @@ export default {
emits: ['click'],
mixins: [tooltipMixin],
methods: {
onClick () {
onClick() {
this.hideTooltip()
this.$emit('click')
}

View File

@@ -11,8 +11,8 @@
7.89917V9.2439L5.1626 10.0745ZM8.99023 13.3H7.93994L10.124 6.35229H11.1787L8.99023
13.3ZM14.1099 10.0613L11.7192 9.24829V7.90356L15.582 9.4856V10.6545L11.7192
12.2366V10.8918L14.1099 10.0613Z"
fill="#A2B1C6"
/>
fill="#A2B1C6"
/>
<path
d="M2.17041 0.0637207H16.2185V1.56372H2.17041V9.30354H0.67041V1.56372C0.67041 0.73872
1.34541 0.0637207 2.17041 0.0637207Z"

View File

@@ -1,10 +1,5 @@
<template>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none">
<path
fill-rule="evenodd"
clip-rule="evenodd"
@@ -14,14 +9,13 @@
14.1914C14.8372 13.965 15.0161 13.5645 15.0161 12.8467V9.43008H13.1914L15.7661 5.13901Z"
fill="#A2B1C6"
/>
<path d="M6.41943 0H18.4194V4H6.41943V0Z" fill="#A2B1C6"/>
<path d="M0.419434 6H4.41943V18H0.419434V6Z" fill="#A2B1C6"/>
<path d="M0.419434 0H4.41943V4H0.419434V0Z" fill="#A2B1C6"/>
<path d="M6.41943 0H18.4194V4H6.41943V0Z" fill="#A2B1C6" />
<path d="M0.419434 6H4.41943V18H0.419434V6Z" fill="#A2B1C6" />
<path d="M0.419434 0H4.41943V4H0.419434V0Z" fill="#A2B1C6" />
</svg>
</template>
<script>
export default {
name: 'PivotIcon'
}

View File

@@ -1,10 +1,5 @@
<template>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none">
<path
d="M9 5.51953C6.57686 5.51953 4.60547 7.49092 4.60547 9.91406C4.60547 12.3372 6.57686
14.3086 9 14.3086C11.4231 14.3086 13.3945 12.3372 13.3945 9.91406C13.3945 7.49092 11.4231
@@ -30,7 +25,10 @@
5.5195V15.0117Z"
fill="#A2B1C6"
/>
<path d="M15.1875 6.22266H13.7812V7.62891H15.1875V6.22266Z" fill="#A2B1C6"/>
<path
d="M15.1875 6.22266H13.7812V7.62891H15.1875V6.22266Z"
fill="#A2B1C6"
/>
</svg>
</template>

View File

@@ -1,15 +1,10 @@
<template>
<svg
width="19"
height="19"
viewBox="0 0 19 19"
fill="none"
>
<svg width="19" height="19" viewBox="0 0 19 19" fill="none">
<g clip-path="url(#clip0_2130_5292)">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M1.85303 11.3794L1.85303 7.80371L5.86304 7.80371L5.86304
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M1.85303 11.3794L1.85303 7.80371L5.86304 7.80371L5.86304
11.3794L1.85303 11.3794ZM7.36304 11.3794L7.36304 7.80371L11.3428
7.80371L11.3428 11.3794L7.36304 11.3794ZM12.8428 11.3794L16.853
11.3794L16.853 7.80371L12.8428 7.80371L12.8428 11.3794ZM15.353
@@ -29,24 +24,23 @@
14.3121L6.76685 12.8794L4.67027 12.8794ZM8.26685 12.8794L8.26685
14.3121L10.387 14.3121L10.387 12.8794L8.26685 12.8794ZM11.887
12.8794L11.887 14.3121L14.0315 14.3121L14.0315 12.8794L11.887 12.8794Z"
fill="#A2B1C6"
/>
fill="#A2B1C6"
/>
</g>
<defs>
<clipPath id="clip0_2130_5292">
<rect
width="18"
height="18"
fill="white"
transform="translate(0.353027 18.5916) rotate(-90)"
/>
width="18"
height="18"
fill="white"
transform="translate(0.353027 18.5916) rotate(-90)"
/>
</clipPath>
</defs>
</svg>
</svg>
</template>
<script>
export default {
name: 'RowIcon'
}

View File

@@ -1,16 +1,13 @@
<template>
<svg
width="12"
height="13"
viewBox="0 0 12 13"
fill="none"
>
<path d="M11.1624 6.94358L0.770043 12.9436L0.770043 0.943573L11.1624 6.94358Z" fill="#A2B1C6"/>
<svg width="12" height="13" viewBox="0 0 12 13" fill="none">
<path
d="M11.1624 6.94358L0.770043 12.9436L0.770043 0.943573L11.1624 6.94358Z"
fill="#A2B1C6"
/>
</svg>
</template>
<script>
export default {
name: 'RunIcon'
}

View File

@@ -24,7 +24,6 @@
</template>
<script>
export default {
name: 'SortIcon',
props: {

View File

@@ -1,10 +1,5 @@
<template>
<svg
width="18"
height="19"
viewBox="0 0 18 19"
fill="none"
>
<svg width="18" height="19" viewBox="0 0 18 19" fill="none">
<g clip-path="url(#clip0)">
<path
d="M4.5 1.51343H10.5L15 6.01343V8.45284H13.5V6.76343H9.75V3.01343H4.5V8.45284H3V3.01343C3
@@ -47,14 +42,18 @@
</g>
<defs>
<clipPath id="clip0">
<rect width="18" height="18" fill="white" transform="translate(0 0.0134277)"/>
<rect
width="18"
height="18"
fill="white"
transform="translate(0 0.0134277)"
/>
</clipPath>
</defs>
</svg>
</template>
<script>
export default {
name: 'SqlEditorIcon'
}

View File

@@ -1,10 +1,5 @@
<template>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none">
<path
fill-rule="evenodd"
clip-rule="evenodd"
@@ -41,7 +36,6 @@
</template>
<script>
export default {
name: 'TableIcon'
}

View File

@@ -17,7 +17,6 @@
</template>
<script>
export default {
name: 'treeChevron',
props: {
@@ -31,7 +30,7 @@ export default {
<style scoped>
.chevron-icon {
-webkit-transition: transform .15s ease-in-out;
transition: transform .15s ease-in-out;
-webkit-transition: transform 0.15s ease-in-out;
transition: transform 0.15s ease-in-out;
}
</style>

View File

@@ -1,24 +1,19 @@
<template>
<svg
width="19"
height="19"
viewBox="0 0 19 19"
fill="none"
>
<svg width="19" height="19" viewBox="0 0 19 19" fill="none">
<g clip-path="url(#clip0_2131_6054)">
<path
d="M3.53784 11.5846L3.53784 3.14734L11.9751 3.14734V7.676C12.4655 7.51991
<path
d="M3.53784 11.5846L3.53784 3.14734L11.9751 3.14734V7.676C12.4655 7.51991
12.9771 7.47439 13.4751 7.53264V3.14734C13.4751 2.31891 12.8035 1.64734
11.9751 1.64734L3.53784 1.64734C2.70941 1.64734 2.03784 2.31891 2.03784
3.14734L2.03784 11.5846C2.03784 12.413 2.70942 13.0846 3.53784
13.0846H10.0831C9.771 12.6184 9.58279 12.1055 9.51083
11.5846H3.53784Z"
fill="#A2B1C6"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M14.7887 9.9291C15.4307 10.8837 15.1773 12.1779 14.2228
fill="#A2B1C6"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M14.7887 9.9291C15.4307 10.8837 15.1773 12.1779 14.2228
12.8199C13.2682 13.4618 11.974 13.2084 11.332 12.2539C10.69 11.2993
10.9434 10.0051 11.898 9.3631C12.8525 8.72113 14.1468 8.97454 14.7887
9.9291ZM14.4606 14.3901L16.6181 17.5982C16.8492 17.9419 17.3153 18.0331
@@ -26,24 +21,23 @@
13.5279C16.7949 12.3365 16.9801 10.4996 16.0334 9.092C14.9292 7.45002
12.7029 7.01412 11.0609 8.1184C9.41891 9.22268 8.98302 11.449 10.0873
13.0909C11.062 14.5403 12.9109 15.05 14.4606 14.3901Z"
fill="#A2B1C6"
/>
</g>
<defs>
<clipPath id="clip0_2131_6054">
<rect
width="18"
height="18"
fill="white"
transform="translate(0.5 18.5916) rotate(-90)"
/>
</clipPath>
</defs>
</svg>
fill="#A2B1C6"
/>
</g>
<defs>
<clipPath id="clip0_2131_6054">
<rect
width="18"
height="18"
fill="white"
transform="translate(0.5 18.5916) rotate(-90)"
/>
</clipPath>
</defs>
</svg>
</template>
<script>
export default {
name: 'ViewCellValueIcon'
}