1
0
mirror of https://github.com/lana-k/sqliteviz.git synced 2025-12-06 18:18:53 +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; \ RUN set -ex; \
echo 'deb http://deb.debian.org/debian unstable main' \ echo 'deb http://deb.debian.org/debian unstable main' \

View File

@@ -1,21 +1,44 @@
#!/bin/bash -e #!/bin/bash -e
cleanup () {
rm -rf lib/dist $flag_file
}
trap cleanup EXIT
if [ ! -f sample.csv ]; then if [ ! -f sample.csv ]; then
wget --header="accept-encoding: gzip" -q -O- \ wget --header="accept-encoding: gzip" -q -O- \
https://github.com/plotly/datasets/raw/547090bd/wellspublic.csv \ https://github.com/plotly/datasets/raw/547090bd/wellspublic.csv \
| gunzip -c > sample.csv | gunzip -c > sample.csv
fi 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 for d in lib/build-* ; do
rm -r lib/dist || true rm -rf lib/dist
cp -r $d lib/dist cp -r $d lib/dist
name=$(basename $d) name=$(basename $d)
docker build -t sqliteviz/sqljs-benchmark:$name . docker build -t sqliteviz/sqljs-benchmark:$name .
docker rm sqljs-benchmark-$name 2> /dev/null || true 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 cp sqljs-benchmark-$name:/tmp/build/suite-result.json ${name}-result.json
docker rm sqljs-benchmark-$name docker rm sqljs-benchmark-$name
done done
rm -r lib/dist

View File

@@ -21,7 +21,7 @@
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "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 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 # Extension-functions
# =================== # ===================
@@ -20,7 +20,7 @@ contrib_functions_url = 'https://sqlite.org/contrib/download/extension-functions
extension_urls = ( extension_urls = (
# Miscellaneous extensions # 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/dbfd8543?at=closure.c', 'sqlite3_closure_init'),
('https://sqlite.org/src/raw/5bb2264c?at=uuid.c', 'sqlite3_uuid_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'), ('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", "name": "sqliteviz",
"version": "0.18.0", "version": "0.19.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"private": true, "private": true,
"scripts": { "scripts": {

View File

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

View File

@@ -1,9 +1,35 @@
<template> <template>
<div id="app"> <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/> <router-view/>
</div> </div>
</template> </template>
<script>
import CloseIcon from '@/components/svg/close'
export default {
components: { CloseIcon },
data () {
return {
showBanner: true
}
}
}
</script>
<style> <style>
@font-face { @font-face {
font-family: "Open Sans"; font-family: "Open Sans";
@@ -63,4 +89,25 @@ body {
.CodeMirror-hints { .CodeMirror-hints {
z-index: 999 !important; 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> </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 Logs from '@/components/Logs'
import time from '@/lib/utils/time' import time from '@/lib/utils/time'
import fIo from '@/lib/utils/fileIo' import fIo from '@/lib/utils/fileIo'
import { send } from '@/lib/utils/events'
export default { export default {
name: 'CsvImport', name: 'CsvImport',
@@ -335,6 +336,7 @@ export default {
this.$store.commit('setCurrentTabId', tabId) this.$store.commit('setCurrentTabId', tabId)
this.importCsvCompleted = false this.importCsvCompleted = false
this.$emit('finish') 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 ChangeDbIcon from '@/components/svg/changeDb'
import database from '@/lib/database' import database from '@/lib/database'
import CsvImport from '@/components/CsvImport' import CsvImport from '@/components/CsvImport'
import { send } from '@/lib/utils/events'
export default { export default {
name: 'DbUploader', name: 'DbUploader',
@@ -127,6 +128,11 @@ export default {
if (fIo.isDatabase(file)) { if (fIo.isDatabase(file)) {
this.loadDb(file) this.loadDb(file)
} else { } else {
send('database.import', file.size, {
from: 'csv',
new_db: true
})
this.file = file this.file = file
await this.$nextTick() await this.$nextTick()
const csvImport = this.$refs.addCsv const csvImport = this.$refs.addCsv

View File

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

View File

@@ -1,5 +1,6 @@
import { nanoid } from 'nanoid' import { nanoid } from 'nanoid'
import fu from '@/lib/utils/fileIo' import fu from '@/lib/utils/fileIo'
import { send } from '@/lib/utils/events'
import migration from './_migrations' import migration from './_migrations'
const migrate = migration._migrate const migrate = migration._migrate
@@ -103,9 +104,19 @@ export default {
importInquiries () { importInquiries () {
return fu.importFile() return fu.importFile()
.then(str => { .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 () { async readPredefinedInquiries () {
const res = await fu.readFile('./inquiries.json') 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 let refresh = false
function invokeServiceWorkerUpdateFlow (registration) { 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> <style scoped>
#app-info-icon { #app-info-icon {
cursor: pointer; cursor: pointer;
width: 24px;
} }
#app-info-container { #app-info-container {
display: flex; display: flex;

View File

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

View File

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

View File

@@ -33,6 +33,7 @@
<script> <script>
import fIo from '@/lib/utils/fileIo' import fIo from '@/lib/utils/fileIo'
import { send } from '@/lib/utils/events'
import TableDescription from './TableDescription' import TableDescription from './TableDescription'
import TextField from '@/components/TextField' import TextField from '@/components/TextField'
import TreeChevron from '@/components/svg/treeChevron' import TreeChevron from '@/components/svg/treeChevron'
@@ -86,6 +87,11 @@ export default {
csvImport.reset() csvImport.reset()
await csvImport.previewCsv() await csvImport.previewCsv()
csvImport.open() 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 chartHelper from '@/lib/chartHelper'
import dereference from 'react-chart-editor/lib/lib/dereference' import dereference from 'react-chart-editor/lib/lib/dereference'
import fIo from '@/lib/utils/fileIo' import fIo from '@/lib/utils/fileIo'
import { send } from '@/lib/utils/events'
export default { export default {
name: 'Chart', name: 'Chart',
props: ['dataSources', 'initOptions', 'importToPngEnabled', 'importToSvgEnabled'], props: [
'dataSources', 'initOptions',
'importToPngEnabled', 'importToSvgEnabled',
'forPivot'
],
components: { components: {
PlotlyEditor PlotlyEditor
}, },
@@ -60,6 +65,18 @@ export default {
plotly.setPlotConfig({ plotly.setPlotConfig({
notifyOnLogging: 1 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 () { mounted () {
this.resizeObserver = new ResizeObserver(this.handleResize) 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 Chart from '@/views/Main/Workspace/Tabs/Tab/DataView/Chart'
import chartHelper from '@/lib/chartHelper' import chartHelper from '@/lib/chartHelper'
import Vue from 'vue' import Vue from 'vue'
import { send } from '@/lib/utils/events'
const ChartClass = Vue.extend(Chart) const ChartClass = Vue.extend(Chart)
export default { export default {
@@ -87,8 +88,17 @@ export default {
'pivotOptions.rendererName': { 'pivotOptions.rendererName': {
immediate: true, immediate: true,
handler () { handler () {
this.$emit('update:importToPngEnabled', this.pivotOptions.rendererName !== 'TSV Export') this.$emit(
this.$emit('update:importToSvgEnabled', this.viewStandartChart || this.viewCustomChart) '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 () { pivotOptions () {
@@ -179,11 +189,11 @@ export default {
async prepareCopy () { async prepareCopy () {
if (this.viewCustomChart) { if (this.viewCustomChart) {
return await this.pivotOptions.rendererOptions.customChartComponent.prepareCopy() 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 () { async saveAsSvg () {
@@ -198,20 +208,23 @@ export default {
saveAsHtml () { saveAsHtml () {
if (this.viewCustomChart) { if (this.viewCustomChart) {
this.pivotOptions.rendererOptions.customChartComponent.saveAsHtml() this.pivotOptions.rendererOptions.customChartComponent.saveAsHtml()
} else if (this.viewStandartChart) { return
}
if (this.viewStandartChart) {
const chartState = chartHelper.getChartData(this.$refs.pivotOutput) const chartState = chartHelper.getChartData(this.$refs.pivotOutput)
fIo.exportToFile( fIo.exportToFile(
chartHelper.getHtml(chartState), chartHelper.getHtml(chartState),
'chart.html', 'chart.html',
'text/html' 'text/html'
) )
} else { return
fIo.exportToFile(
pivotHelper.getPivotHtml(this.$refs.pivotOutput),
'pivot.html',
'text/html'
)
} }
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) { function customChartRenderer (data, options) {
options.customChartComponent.dataSources = _getDataSources(data) options.customChartComponent.dataSources = _getDataSources(data)
options.customChartComponent.forPivot = true
options.customChartComponent.$mount() options.customChartComponent.$mount()
return $(options.customChartComponent.$el) return $(options.customChartComponent.$el)

View File

@@ -95,6 +95,7 @@ import ClipboardIcon from '@/components/svg/clipboard'
import cIo from '@/lib/utils/clipboardIo' import cIo from '@/lib/utils/clipboardIo'
import loadingDialog from '@/components/LoadingDialog' import loadingDialog from '@/components/LoadingDialog'
import time from '@/lib/utils/time' import time from '@/lib/utils/time'
import { send } from '@/lib/utils/events'
export default { export default {
name: 'DataView', name: 'DataView',
@@ -123,6 +124,11 @@ export default {
dataToCopy: null dataToCopy: null
} }
}, },
computed: {
plotlyInPivot () {
return this.mode === 'pivot' && this.$refs.viewComponent.viewCustomChart
}
},
watch: { watch: {
mode () { mode () {
this.$emit('update') this.$emit('update')
@@ -148,6 +154,7 @@ export default {
*/ */
await time.sleep(0) await time.sleep(0)
this.$refs.viewComponent.saveAsPng() this.$refs.viewComponent.saveAsPng()
this.exportSignal('png')
}, },
getOptionsForSave () { getOptionsForSave () {
return this.$refs.viewComponent.getOptionsForSave() return this.$refs.viewComponent.getOptionsForSave()
@@ -178,6 +185,7 @@ export default {
async copyToClipboard () { async copyToClipboard () {
cIo.copyImage(this.dataToCopy) cIo.copyImage(this.dataToCopy)
this.$modal.hide('prepareCopy') this.$modal.hide('prepareCopy')
this.exportSignal('clipboard')
}, },
cancelCopy () { cancelCopy () {
this.dataToCopy = null this.dataToCopy = null
@@ -186,9 +194,26 @@ export default {
saveAsSvg () { saveAsSvg () {
this.$refs.viewComponent.saveAsSvg() this.$refs.viewComponent.saveAsSvg()
this.exportSignal('svg')
}, },
saveAsHtml () { saveAsHtml () {
this.$refs.viewComponent.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 cIo from '@/lib/utils/clipboardIo'
import time from '@/lib/utils/time' import time from '@/lib/utils/time'
import loadingDialog from '@/components/LoadingDialog' import loadingDialog from '@/components/LoadingDialog'
import { send } from '@/lib/utils/events'
export default { export default {
name: 'RunResult', name: 'RunResult',
@@ -117,10 +118,24 @@ export default {
}, },
exportToCsv () { 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') fIo.exportToFile(csv.serialize(this.result), 'result_set.csv', 'text/csv')
}, },
async prepareCopy () { 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) { if ('ClipboardItem' in window) {
this.preparingCopy = true this.preparingCopy = true
this.$modal.show('prepareCSVCopy') this.$modal.show('prepareCSVCopy')

View File

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

View File

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

View File

@@ -55,6 +55,7 @@ describe('Logs.vue', () => {
await wrapper.vm.$nextTick() await wrapper.vm.$nextTick()
messages.push({ type: 'error', message: 'msg 5' }) messages.push({ type: 'error', message: 'msg 5' })
await wrapper.vm.$nextTick()
await wrapper.vm.$nextTick() await wrapper.vm.$nextTick()
const height = wrapper.find('.logs-container').element.scrollHeight const height = wrapper.find('.logs-container').element.scrollHeight
expect(wrapper.find('.logs-container').element.scrollTop) 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[0].type).to.equal('N/A')
expect(schema[0].columns[1].name).to.equal('col2') 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 () => { it('creates schema with view', async () => {
@@ -68,12 +68,12 @@ describe('database.js', () => {
expect(schema[0].columns[1]).to.eql({ expect(schema[0].columns[1]).to.eql({
name: 'col2', name: 'col2',
type: 'integer' type: 'INTEGER'
}) })
expect(schema[1].columns).to.eql([{ expect(schema[1].columns).to.eql([{
name: 'amount', name: 'amount',
type: 'integer' type: 'INTEGER'
}]) }])
}) })

View File

@@ -29,12 +29,12 @@ describe('time.js', () => {
}) })
it('sleep resolves after n ms', async () => { it('sleep resolves after n ms', async () => {
let before = performance.now() let before = Date.now()
await time.sleep(10) 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) 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 () => { it('saveAsPng - table', async () => {
sinon.stub(pivotHelper, 'getPivotCanvas').returns(document.createElement('canvas'))
sinon.stub(HTMLCanvasElement.prototype, 'toDataURL').returns('canvas data url') sinon.stub(HTMLCanvasElement.prototype, 'toDataURL').returns('canvas data url')
sinon.stub(fIo, 'downloadFromUrl') sinon.stub(fIo, 'downloadFromUrl')

View File

@@ -1,6 +1,6 @@
import { expect } from 'chai' import { expect } from 'chai'
import { _getDataSources, getPivotCanvas, getPivotHtml } 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', () => { describe('pivotHelper.js', () => {
it('_getDataSources returns data sources', () => { it('_getDataSources returns data sources', () => {

View File

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