1
0
mirror of https://github.com/lana-k/sqliteviz.git synced 2025-12-06 10:08:52 +08:00

15 Commits

Author SHA1 Message Date
lana-k
c674bf11e3 update version number 2022-07-10 22:29:20 +02:00
lana-k
2d8a91675e Remove console.log 2022-07-10 22:25:11 +02:00
lana-k
45b1021559 links to website 2022-07-10 21:26:26 +02:00
lana-k
7216e996d1 add banner 2022-07-10 21:25:51 +02:00
lana-k
6eae9a0f2d remove empty lines 2022-07-10 16:02:04 +02:00
lana-k
7486b32bd1 add head extention slot 2022-07-03 15:38:41 +02:00
lana-k
2c564767f8 Merge branch 'master' of github.com:lana-k/sqliteviz 2022-07-01 21:01:07 +02:00
lana-k
289a727cbe fix icon width 2022-07-01 21:01:02 +02:00
saaj
5f2b8ba5a9 Upgrade to SQLite 3.38.5 (#91)
* Update to SQLite 3.37 and latest generate_series extension

* Expect column types in upper case

* Rebuild newer SQLite, 3.38.5
2022-06-27 17:35:40 +02:00
lana-k
f0a4212e2b fix tests 2022-06-26 21:06:24 +02:00
lana-k
c8deff32c1 fix lint 2022-06-25 22:38:22 +02:00
lana-k
d56604a7d6 events refactor 2022-06-25 22:37:09 +02:00
lana-k
48e311bff8 minor change 2022-06-24 22:58:43 +02:00
lana-k
518b22b489 events 2022-06-24 21:29:40 +02:00
lana-k
a20dd7f849 forbid index minifying 2022-06-11 19:29:42 +02:00
34 changed files with 14747 additions and 11899 deletions

View File

@@ -1,4 +1,4 @@
FROM node:12-buster
FROM node:14-bullseye
RUN set -ex; \
echo 'deb http://deb.debian.org/debian unstable main' \

View File

@@ -1,21 +1,44 @@
#!/bin/bash -e
cleanup () {
rm -rf lib/dist $flag_file
}
trap cleanup EXIT
if [ ! -f sample.csv ]; then
wget --header="accept-encoding: gzip" -q -O- \
https://github.com/plotly/datasets/raw/547090bd/wellspublic.csv \
| gunzip -c > sample.csv
fi
# for renice to work run like "sudo -E env PATH=$PATH ./make.sh"
test_ni=$(nice -n -1 nice)
if [ $test_ni == -1 ]; then
flag_file=$(mktemp)
fi
(
while [ -f $flag_file ]; do
root_pid=$(
docker ps -f status=running -f name='^sqljs-benchmark-' -q \
| xargs -r -I{} -- docker inspect -f '{{.State.Pid}}' {}
)
if [ ! -z $root_pid ]; then
procpath query -d $'\n' "$..children[?(@.stat.pid == $root_pid)]..pid" \
| xargs -I{} -- renice -n -1 -p {} > /dev/null
fi
sleep 1
done &
)
shopt -s nullglob
for d in lib/build-* ; do
rm -r lib/dist || true
rm -rf lib/dist
cp -r $d lib/dist
name=$(basename $d)
docker build -t sqliteviz/sqljs-benchmark:$name .
docker rm sqljs-benchmark-$name 2> /dev/null || true
docker run -it --name sqljs-benchmark-$name sqliteviz/sqljs-benchmark:$name
docker run -it --cpus 2 --name sqljs-benchmark-$name sqliteviz/sqljs-benchmark:$name
docker cp sqljs-benchmark-$name:/tmp/build/suite-result.json ${name}-result.json
docker rm sqljs-benchmark-$name
done
rm -r lib/dist

View File

@@ -21,7 +21,7 @@
"metadata": {},
"outputs": [],
"source": [
"benchmark_path = Path('/path/to/sqliteviz/project/sqliteviz/lib/sql-js/benchmark')"
"benchmark_path = Path()"
]
},
{

View File

@@ -8,7 +8,7 @@ from pathlib import Path
from urllib import request
amalgamation_url = 'https://sqlite.org/2021/sqlite-amalgamation-3360000.zip'
amalgamation_url = 'https://sqlite.org/2022/sqlite-amalgamation-3380500.zip'
# Extension-functions
# ===================
@@ -20,7 +20,7 @@ contrib_functions_url = 'https://sqlite.org/contrib/download/extension-functions
extension_urls = (
# Miscellaneous extensions
# ========================
('https://sqlite.org/src/raw/c6bd5d24?at=series.c', 'sqlite3_series_init'),
('https://sqlite.org/src/raw/8d79354f?at=series.c', 'sqlite3_series_init'),
('https://sqlite.org/src/raw/dbfd8543?at=closure.c', 'sqlite3_closure_init'),
('https://sqlite.org/src/raw/5bb2264c?at=uuid.c', 'sqlite3_uuid_init'),
('https://sqlite.org/src/raw/5853b0e5?at=regexp.c', 'sqlite3_regexp_init'),

File diff suppressed because one or more lines are too long

Binary file not shown.

26334
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "sqliteviz",
"version": "0.18.0",
"version": "0.19.0",
"license": "Apache-2.0",
"private": true,
"scripts": {

View File

@@ -69,6 +69,8 @@
}
}
</style>
<!-- head extention slot start -->
<!-- head extention slot end -->
</head>
<body>
<noscript>
@@ -93,6 +95,8 @@
</svg>
</div>
</div>
<!-- extention slot start -->
<!-- extention slot end -->
<!-- built files will be auto injected -->
</body>
</html>

View File

@@ -1,9 +1,35 @@
<template>
<div id="app">
<div v-if="showBanner" id="banner" class="warning">
<close-icon @click="showBanner = false"/>
Sqliteviz has got own space on the web,
<a href="https://sqliteviz.com/" target="_blank">sqliteviz.com</a>!
New builds will be published there, so we recommend you to switch to the
<a href="https://sqliteviz.com/app/#" target="_blank">
new link</a> to not miss new features.
This
<a
href="https://sqliteviz.com/docs/how-to-migrate-to-sqliteviz-dot-com/"
target="_blank"
>migration guide</a> will help if you're not sure how to migrate.
</div>
<router-view/>
</div>
</template>
<script>
import CloseIcon from '@/components/svg/close'
export default {
components: { CloseIcon },
data () {
return {
showBanner: true
}
}
}
</script>
<style>
@font-face {
font-family: "Open Sans";
@@ -63,4 +89,25 @@ body {
.CodeMirror-hints {
z-index: 999 !important;
}
#banner {
position: fixed;
max-width: 500px;
box-sizing: border-box;
z-index: 1000;
top: 8px;
left: 50%;
transform: translateX(-50%);
padding: 32px;
border-radius: var(--border-radius-big);
box-shadow: 0px 2px 9px rgba(80, 103, 132, 0.4);
}
#banner svg {
padding: 4px;
position: absolute;
top: 12px;
right: 12px;
}
#banner a {
color: var(--color-text-active);
}
</style>

View File

@@ -0,0 +1,3 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M26.8311 34.6554C25.4675 33.8178 24.177 32.8655 22.9735 31.8086V14.3616H30.5728V36.753C29.3146 36.0982 28.0673 35.399 26.8311 34.6554ZM41.4669 25.8486H33.8675V38.1514C36.3477 39.3055 38.884 40.3334 41.4669 41.2313V25.8486ZM22.9735 35.3046L22.4768 34.9051C21.7152 34.2725 21.0033 33.6232 20.3245 32.9739L2.2947 30.8763L5.60596 37.3024L28.7848 39.2002C26.7511 38.0537 24.8082 36.7513 22.9735 35.3046ZM41.0695 44.6441C38.4829 43.7946 35.9458 42.7997 33.4702 41.6641L32.543 41.198L17.2616 40.1825L19.8444 45.593L46.5 46.209C44.6788 45.7761 42.8411 45.2434 41.0695 44.6441ZM9.34768 14.3616C12.2649 19.4905 15.735 24.2807 19.6954 28.6455V11.2651L2.99007 2.99115L1.5 22.3859L18.702 31.2592C14.1919 26.5283 10.9703 20.7087 9.34768 14.3616Z" fill="#119DFF"/>
</svg>

After

Width:  |  Height:  |  Size: 862 B

View File

@@ -112,6 +112,7 @@ import SqlTable from '@/components/SqlTable'
import Logs from '@/components/Logs'
import time from '@/lib/utils/time'
import fIo from '@/lib/utils/fileIo'
import { send } from '@/lib/utils/events'
export default {
name: 'CsvImport',
@@ -335,6 +336,7 @@ export default {
this.$store.commit('setCurrentTabId', tabId)
this.importCsvCompleted = false
this.$emit('finish')
send('inquiry.create', undefined, { auto: true })
}
}
}

View File

@@ -58,6 +58,7 @@ import fIo from '@/lib/utils/fileIo'
import ChangeDbIcon from '@/components/svg/changeDb'
import database from '@/lib/database'
import CsvImport from '@/components/CsvImport'
import { send } from '@/lib/utils/events'
export default {
name: 'DbUploader',
@@ -127,6 +128,11 @@ export default {
if (fIo.isDatabase(file)) {
this.loadDb(file)
} else {
send('database.import', file.size, {
from: 'csv',
new_db: true
})
this.file = file
await this.$nextTick()
const csvImport = this.$refs.addCsv

View File

@@ -7,6 +7,8 @@ import Worker from './_worker.js'
// https://github.com/nolanlawson/promise-worker
import PromiseWorker from 'promise-worker'
import { send } from '@/lib/utils/events'
function getNewDatabase () {
const worker = new Worker()
return new Database(worker)
@@ -76,6 +78,11 @@ class Database {
this.dbName = file ? fu.getFileName(file) : 'database'
this.refreshSchema()
send('database.import', file ? file.size : 0, {
from: file ? 'sqlite' : 'none',
new_db: true
})
}
async refreshSchema () {
@@ -114,6 +121,7 @@ class Database {
throw new Error(data.error)
}
fu.exportToFile(data, fileName)
send('database.export', data.byteLength, { to: 'sqlite' })
}
async validateTableName (name) {

View File

@@ -1,5 +1,6 @@
import { nanoid } from 'nanoid'
import fu from '@/lib/utils/fileIo'
import { send } from '@/lib/utils/events'
import migration from './_migrations'
const migrate = migration._migrate
@@ -103,9 +104,19 @@ export default {
importInquiries () {
return fu.importFile()
.then(str => {
return this.deserialiseInquiries(str)
const inquires = this.deserialiseInquiries(str)
send('inquiry.import', inquires.length)
return inquires
})
},
export (inquiryList, fileName) {
const jsonStr = this.serialiseInquiries(inquiryList)
fu.exportToFile(jsonStr, fileName)
send('inquiry.export', inquiryList.length)
},
async readPredefinedInquiries () {
const res = await fu.readFile('./inquiries.json')

10
src/lib/utils/events.js Normal file
View File

@@ -0,0 +1,10 @@
export function send (name, value, labels) {
const event = new CustomEvent('sqliteviz-app-event', {
detail: {
name,
value,
labels
}
})
window.dispatchEvent(event)
}

View File

@@ -1,3 +1,4 @@
import { send } from '@/lib/utils/events'
let refresh = false
function invokeServiceWorkerUpdateFlow (registration) {
@@ -41,4 +42,8 @@ if ('serviceWorker' in navigator) {
}
})
})
window.addEventListener('appinstalled', () => {
send('pwa.install')
})
}

View File

@@ -62,6 +62,7 @@ export default {
<style scoped>
#app-info-icon {
cursor: pointer;
width: 24px;
}
#app-info-container {
display: flex;

View File

@@ -159,7 +159,6 @@ import TextField from '@/components/TextField'
import CheckBox from '@/components/CheckBox'
import tooltipMixin from '@/tooltipMixin'
import storedInquiries from '@/lib/storedInquiries'
import fu from '@/lib/utils/fileIo'
export default {
name: 'Inquiries',
@@ -385,8 +384,7 @@ export default {
return this.$store.state.tabs.findIndex(tab => tab.id === id)
},
exportToFile (inquiryList, fileName) {
const jsonStr = storedInquiries.serialiseInquiries(inquiryList)
fu.exportToFile(jsonStr, fileName)
storedInquiries.export(inquiryList, fileName)
},
exportSelectedInquiries () {
const inquiryList = this.allInquiries.filter(

View File

@@ -1,9 +1,12 @@
<template>
<nav>
<div>
<div id="nav-links">
<a href="https://sqliteviz.com">
<img :src="require('@/assets/images/logo_simple.svg')">
</a>
<router-link to="/workspace">Workspace</router-link>
<router-link to="/inquiries">Inquiries</router-link>
<a href="https://github.com/lana-k/sqliteviz/wiki" target="_blank">Help</a>
<a href="https://sqliteviz.com/docs" target="_blank">Help</a>
</div>
<div id="nav-buttons">
<button
@@ -57,6 +60,7 @@ import TextField from '@/components/TextField'
import CloseIcon from '@/components/svg/close'
import storedInquiries from '@/lib/storedInquiries'
import AppDiagnosticInfo from './AppDiagnosticInfo'
import { send } from '@/lib/utils/events'
export default {
name: 'MainMenu',
@@ -110,6 +114,8 @@ export default {
this.$router.push('/workspace')
}
})
send('inquiry.create', undefined, { auto: false })
},
cancelSave () {
this.$modal.hide('save')
@@ -163,6 +169,7 @@ export default {
// Signal about saving
this.$root.$emit('inquirySaved')
send('inquiry.save')
},
_keyListener (e) {
if (this.$route.path === '/workspace') {
@@ -237,4 +244,12 @@ button {
#nav-buttons {
display: flex;
}
#nav-links {
display: flex;
align-items: center;
}
#nav-links img {
width: 32px;
}
</style>

View File

@@ -33,6 +33,7 @@
<script>
import fIo from '@/lib/utils/fileIo'
import { send } from '@/lib/utils/events'
import TableDescription from './TableDescription'
import TextField from '@/components/TextField'
import TreeChevron from '@/components/svg/treeChevron'
@@ -86,6 +87,11 @@ export default {
csvImport.reset()
await csvImport.previewCsv()
csvImport.open()
send('database.import', this.file.size, {
from: 'csv',
new_db: false
})
}
}
}

View File

@@ -31,10 +31,15 @@ import PlotlyEditor from 'react-chart-editor'
import chartHelper from '@/lib/chartHelper'
import dereference from 'react-chart-editor/lib/lib/dereference'
import fIo from '@/lib/utils/fileIo'
import { send } from '@/lib/utils/events'
export default {
name: 'Chart',
props: ['dataSources', 'initOptions', 'importToPngEnabled', 'importToSvgEnabled'],
props: [
'dataSources', 'initOptions',
'importToPngEnabled', 'importToSvgEnabled',
'forPivot'
],
components: {
PlotlyEditor
},
@@ -60,6 +65,18 @@ export default {
plotly.setPlotConfig({
notifyOnLogging: 1
})
this.$watch(
() => JSON.stringify(
this.state.data.map(trace => `${trace.type}-${trace.mode}`)
),
(value) => {
send('viz_plotly.render', undefined, {
type: value,
pivot: !!this.forPivot
})
},
{ deep: true }
)
},
mounted () {
this.resizeObserver = new ResizeObserver(this.handleResize)

View File

@@ -23,6 +23,7 @@ import pivotHelper from './pivotHelper'
import Chart from '@/views/Main/Workspace/Tabs/Tab/DataView/Chart'
import chartHelper from '@/lib/chartHelper'
import Vue from 'vue'
import { send } from '@/lib/utils/events'
const ChartClass = Vue.extend(Chart)
export default {
@@ -87,8 +88,17 @@ export default {
'pivotOptions.rendererName': {
immediate: true,
handler () {
this.$emit('update:importToPngEnabled', this.pivotOptions.rendererName !== 'TSV Export')
this.$emit('update:importToSvgEnabled', this.viewStandartChart || this.viewCustomChart)
this.$emit(
'update:importToPngEnabled',
this.pivotOptions.rendererName !== 'TSV Export'
)
this.$emit(
'update:importToSvgEnabled',
this.viewStandartChart || this.viewCustomChart
)
send('viz_pivot.render', undefined, {
type: this.pivotOptions.rendererName
})
}
},
pivotOptions () {
@@ -179,11 +189,11 @@ export default {
async prepareCopy () {
if (this.viewCustomChart) {
return await this.pivotOptions.rendererOptions.customChartComponent.prepareCopy()
} else if (this.viewStandartChart) {
return await chartHelper.getImageDataUrl(this.$refs.pivotOutput, 'png')
} else {
return await pivotHelper.getPivotCanvas(this.$refs.pivotOutput)
}
if (this.viewStandartChart) {
return await chartHelper.getImageDataUrl(this.$refs.pivotOutput, 'png')
}
return await pivotHelper.getPivotCanvas(this.$refs.pivotOutput)
},
async saveAsSvg () {
@@ -198,20 +208,23 @@ export default {
saveAsHtml () {
if (this.viewCustomChart) {
this.pivotOptions.rendererOptions.customChartComponent.saveAsHtml()
} else if (this.viewStandartChart) {
return
}
if (this.viewStandartChart) {
const chartState = chartHelper.getChartData(this.$refs.pivotOutput)
fIo.exportToFile(
chartHelper.getHtml(chartState),
'chart.html',
'text/html'
)
} else {
fIo.exportToFile(
pivotHelper.getPivotHtml(this.$refs.pivotOutput),
'pivot.html',
'text/html'
)
return
}
fIo.exportToFile(
pivotHelper.getPivotHtml(this.$refs.pivotOutput),
'pivot.html',
'text/html'
)
}
}
}

View File

@@ -51,6 +51,8 @@ export function _getDataSources (pivotData) {
function customChartRenderer (data, options) {
options.customChartComponent.dataSources = _getDataSources(data)
options.customChartComponent.forPivot = true
options.customChartComponent.$mount()
return $(options.customChartComponent.$el)

View File

@@ -95,6 +95,7 @@ import ClipboardIcon from '@/components/svg/clipboard'
import cIo from '@/lib/utils/clipboardIo'
import loadingDialog from '@/components/LoadingDialog'
import time from '@/lib/utils/time'
import { send } from '@/lib/utils/events'
export default {
name: 'DataView',
@@ -123,6 +124,11 @@ export default {
dataToCopy: null
}
},
computed: {
plotlyInPivot () {
return this.mode === 'pivot' && this.$refs.viewComponent.viewCustomChart
}
},
watch: {
mode () {
this.$emit('update')
@@ -148,6 +154,7 @@ export default {
*/
await time.sleep(0)
this.$refs.viewComponent.saveAsPng()
this.exportSignal('png')
},
getOptionsForSave () {
return this.$refs.viewComponent.getOptionsForSave()
@@ -178,6 +185,7 @@ export default {
async copyToClipboard () {
cIo.copyImage(this.dataToCopy)
this.$modal.hide('prepareCopy')
this.exportSignal('clipboard')
},
cancelCopy () {
this.dataToCopy = null
@@ -186,9 +194,26 @@ export default {
saveAsSvg () {
this.$refs.viewComponent.saveAsSvg()
this.exportSignal('svg')
},
saveAsHtml () {
this.$refs.viewComponent.saveAsHtml()
this.exportSignal('html')
},
exportSignal (to) {
const eventLabels = { type: to }
if (this.mode === 'chart' || this.plotlyInPivot) {
eventLabels.pivot = this.plotlyInPivot
}
send(
this.mode === 'chart' || this.plotlyInPivot
? 'viz_plotly.export'
: 'viz_pivot.export',
undefined,
eventLabels
)
}
}
}

View File

@@ -72,6 +72,7 @@ import fIo from '@/lib/utils/fileIo'
import cIo from '@/lib/utils/clipboardIo'
import time from '@/lib/utils/time'
import loadingDialog from '@/components/LoadingDialog'
import { send } from '@/lib/utils/events'
export default {
name: 'RunResult',
@@ -117,10 +118,24 @@ export default {
},
exportToCsv () {
if (this.result && this.result.values) {
send('resultset.export',
this.result.values[this.result.columns[0]].length,
{ to: 'csv' }
)
}
fIo.exportToFile(csv.serialize(this.result), 'result_set.csv', 'text/csv')
},
async prepareCopy () {
if (this.result && this.result.values) {
send('resultset.export',
this.result.values[this.result.columns[0]].length,
{ to: 'clipboard' }
)
}
if ('ClipboardItem' in window) {
this.preparingCopy = true
this.$modal.show('prepareCSVCopy')

View File

@@ -56,6 +56,7 @@ import DataView from './DataView'
import RunResult from './RunResult'
import time from '@/lib/utils/time'
import Teleport from 'vue2-teleport'
import { send } from '@/lib/utils/events'
export default {
name: 'Tab',
@@ -108,6 +109,8 @@ export default {
const fromPosition = this.layout[from]
this.layout[from] = this.layout[to]
this.layout[to] = fromPosition
send('inquiry.panel', undefined, { panel: to })
},
onDataViewUpdate () {
this.$store.commit('updateTab', { index: this.tabIndex, isSaved: false })
@@ -121,11 +124,21 @@ export default {
const start = new Date()
this.result = await state.db.execute(this.query + ';')
this.time = time.getPeriod(start, new Date())
if (this.result && this.result.values) {
send('resultset.create',
this.result.values[this.result.columns[0]].length
)
}
send('query.run', parseFloat(this.time), { status: 'success' })
} catch (err) {
this.error = {
type: 'error',
message: err
}
send('query.run', 0, { status: 'error' })
}
state.db.refreshSchema()
this.isGettingResults = false

View File

@@ -19,6 +19,7 @@
import Splitpanes from '@/components/Splitpanes'
import Schema from './Schema'
import Tabs from './Tabs'
import { send } from '@/lib/utils/events'
export default {
name: 'Workspace',
@@ -49,6 +50,8 @@ export default {
const tabId = await this.$store.dispatch('addTab', { query: stmt })
this.$store.commit('setCurrentTabId', tabId)
send('inquiry.create', undefined, { auto: true })
}
}
}

View File

@@ -55,6 +55,7 @@ describe('Logs.vue', () => {
await wrapper.vm.$nextTick()
messages.push({ type: 'error', message: 'msg 5' })
await wrapper.vm.$nextTick()
await wrapper.vm.$nextTick()
const height = wrapper.find('.logs-container').element.scrollHeight
expect(wrapper.find('.logs-container').element.scrollTop)

View File

@@ -44,7 +44,7 @@ describe('database.js', () => {
expect(schema[0].columns[0].type).to.equal('N/A')
expect(schema[0].columns[1].name).to.equal('col2')
expect(schema[0].columns[1].type).to.equal('integer')
expect(schema[0].columns[1].type).to.equal('INTEGER')
})
it('creates schema with view', async () => {
@@ -68,12 +68,12 @@ describe('database.js', () => {
expect(schema[0].columns[1]).to.eql({
name: 'col2',
type: 'integer'
type: 'INTEGER'
})
expect(schema[1].columns).to.eql([{
name: 'amount',
type: 'integer'
type: 'INTEGER'
}])
})

View File

@@ -29,12 +29,12 @@ describe('time.js', () => {
})
it('sleep resolves after n ms', async () => {
let before = performance.now()
let before = Date.now()
await time.sleep(10)
expect(performance.now() - before).to.be.least(10)
expect(Date.now() - before).to.be.least(10)
before = performance.now()
before = Date.now()
await time.sleep(30)
expect(performance.now() - before).to.be.least(30)
expect(Date.now() - before).to.be.least(30)
})
})

View File

@@ -461,6 +461,7 @@ describe('Pivot.vue', () => {
})
it('saveAsPng - table', async () => {
sinon.stub(pivotHelper, 'getPivotCanvas').returns(document.createElement('canvas'))
sinon.stub(HTMLCanvasElement.prototype, 'toDataURL').returns('canvas data url')
sinon.stub(fIo, 'downloadFromUrl')

View File

@@ -1,6 +1,6 @@
import { expect } from 'chai'
import { _getDataSources, getPivotCanvas, getPivotHtml }
from '@/views/Main/Workspace/Tabs/Tab/DataView/Pivot/pivotHelper'
from '@/views/Main/Workspace/Tabs/Tab/DataView/Pivot/pivotHelper'
describe('pivotHelper.js', () => {
it('_getDataSources returns data sources', () => {

View File

@@ -41,5 +41,12 @@ module.exports = {
.end()
config.module.rule('js').exclude.add(/worker\.js$/)
config
.plugin('html')
.tap(args => {
args[0].minify = false
return args
})
}
}