mirror of
https://github.com/lana-k/sqliteviz.git
synced 2025-12-07 02:28:54 +08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2db4e2634 | ||
|
|
6e29791892 | ||
|
|
068195589a | ||
|
|
6b72a937ea | ||
|
|
43e357de5b | ||
|
|
00c2fb86c5 | ||
|
|
085813ec50 | ||
|
|
0339aafe14 | ||
|
|
c2a155c561 | ||
|
|
5dbffe0c56 | ||
|
|
00d671fac0 | ||
|
|
18c8b30bef | ||
|
|
0df9a7b982 | ||
|
|
0c777b9f30 | ||
|
|
2aac74fba2 | ||
|
|
6a1dcfc187 | ||
|
|
cb49b7b6cb | ||
|
|
a1a330986d | ||
|
|
3b43fcddb4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
/dist
|
/dist
|
||||||
|
/coverage
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env.local
|
.env.local
|
||||||
|
|||||||
173
karma.conf.js
Normal file
173
karma.conf.js
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
// Karma configuration
|
||||||
|
"use strict";
|
||||||
|
const path = require("path");
|
||||||
|
const VueLoaderPlugin = require("vue-loader/lib/plugin");
|
||||||
|
|
||||||
|
function resolve(dir) {
|
||||||
|
return path.join(__dirname, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function(config) {
|
||||||
|
config.set({
|
||||||
|
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||||
|
basePath: "",
|
||||||
|
|
||||||
|
// frameworks to use
|
||||||
|
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||||
|
frameworks: ["mocha", "sinon-chai"],
|
||||||
|
|
||||||
|
// list of files / patterns to load in the browser
|
||||||
|
files: [
|
||||||
|
"tests/unit/*.spec.js",
|
||||||
|
{ pattern: 'node_modules/sql.js/dist/sql-wasm.wasm',
|
||||||
|
watched: false,
|
||||||
|
included: false,
|
||||||
|
served: true,
|
||||||
|
nocache: false
|
||||||
|
},
|
||||||
|
{ pattern: 'node_modules/sql.js/dist/worker.sql-wasm.js',
|
||||||
|
watched: false,
|
||||||
|
included: false,
|
||||||
|
served: true,
|
||||||
|
nocache: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// list of files / patterns to exclude
|
||||||
|
exclude: [],
|
||||||
|
|
||||||
|
// preprocess matching files before serving them to the browser
|
||||||
|
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
||||||
|
preprocessors: {
|
||||||
|
"tests/unit/*.spec.js": ["webpack"]
|
||||||
|
},
|
||||||
|
|
||||||
|
// test results reporter to use
|
||||||
|
// possible values: 'dots', 'progress'
|
||||||
|
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||||
|
reporters: ["spec", "coverage"],
|
||||||
|
|
||||||
|
coverageReporter: {
|
||||||
|
dir: "coverage",
|
||||||
|
reporters: [{ type: "lcov", subdir: "." }, { type: "text-summary" }]
|
||||||
|
},
|
||||||
|
|
||||||
|
// !!DONOT delete this reporter, or vue-cli-addon-ui-karma doesnot work
|
||||||
|
jsonResultReporter: {
|
||||||
|
outputFile: "report/karma-result.json",
|
||||||
|
isSynchronous: true
|
||||||
|
},
|
||||||
|
|
||||||
|
junitReporter: {
|
||||||
|
outputDir: "report", // results will be saved as $outputDir/$browserName.xml
|
||||||
|
outputFile: undefined, // if included, results will be saved as $outputDir/$browserName/$outputFile
|
||||||
|
suite: "", // suite will become the package name attribute in xml testsuite element
|
||||||
|
useBrowserName: true, // add browser name to report and classes names
|
||||||
|
nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element
|
||||||
|
classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element
|
||||||
|
properties: {} // key value pair of properties to add to the <properties> section of the report
|
||||||
|
},
|
||||||
|
|
||||||
|
// web server port
|
||||||
|
port: 9876,
|
||||||
|
|
||||||
|
// enable / disable colors in the output (reporters and logs)
|
||||||
|
colors: true,
|
||||||
|
|
||||||
|
// level of logging
|
||||||
|
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
|
||||||
|
// enable / disable watching file and executing tests whenever any file changes
|
||||||
|
autoWatch: true,
|
||||||
|
|
||||||
|
// start these browsers
|
||||||
|
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||||
|
browsers: ["ChromiumHeadless"],
|
||||||
|
|
||||||
|
// Continuous Integration mode
|
||||||
|
// if true, Karma captures browsers, runs the tests and exits
|
||||||
|
singleRun: true,
|
||||||
|
|
||||||
|
// Concurrency level
|
||||||
|
// how many browser should be started simultaneous
|
||||||
|
concurrency: Infinity,
|
||||||
|
|
||||||
|
client: {
|
||||||
|
captureConsole: true
|
||||||
|
},
|
||||||
|
browserConsoleLogOptions: {
|
||||||
|
terminal: true,
|
||||||
|
level: ""
|
||||||
|
},
|
||||||
|
webpack: {
|
||||||
|
mode: "development",
|
||||||
|
entry: "./src/main.js",
|
||||||
|
resolve: {
|
||||||
|
extensions: [".js", ".vue", ".json"],
|
||||||
|
alias: {
|
||||||
|
vue$: "vue/dist/vue.esm.js",
|
||||||
|
"@": resolve("src")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
exclude: /(node_modules|bower_components)/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "babel-loader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: "istanbul-instrumenter-loader",
|
||||||
|
options: {
|
||||||
|
esModules: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
|
loader: "url-loader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
loader: "vue-loader",
|
||||||
|
options: {
|
||||||
|
loaders: {
|
||||||
|
js: "babel-loader"
|
||||||
|
},
|
||||||
|
postLoaders: {
|
||||||
|
js: "istanbul-instrumenter-loader?esModules=true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ["vue-style-loader", "css-loader"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: ["vue-style-loader", "css-loader", "sass-loader"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||||
|
loader: "url-loader",
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: resolve("fonts/[name].[hash:7].[ext]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [new VueLoaderPlugin()],
|
||||||
|
node: {
|
||||||
|
fs: 'empty'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
proxies: {
|
||||||
|
"/js/": "/base/node_modules/sql.js/dist/"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
25903
package-lock.json
generated
25903
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "sqliteviz",
|
"name": "sqliteviz",
|
||||||
"version": "0.6.0",
|
"version": "0.7.0",
|
||||||
"license" : "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
@@ -32,7 +32,6 @@
|
|||||||
"@vue/cli-plugin-babel": "^4.4.0",
|
"@vue/cli-plugin-babel": "^4.4.0",
|
||||||
"@vue/cli-plugin-eslint": "^4.4.0",
|
"@vue/cli-plugin-eslint": "^4.4.0",
|
||||||
"@vue/cli-plugin-router": "^4.4.0",
|
"@vue/cli-plugin-router": "^4.4.0",
|
||||||
"@vue/cli-plugin-unit-mocha": "^4.4.0",
|
|
||||||
"@vue/cli-plugin-vuex": "^4.4.0",
|
"@vue/cli-plugin-vuex": "^4.4.0",
|
||||||
"@vue/cli-service": "^4.4.0",
|
"@vue/cli-service": "^4.4.0",
|
||||||
"@vue/eslint-config-standard": "^5.1.2",
|
"@vue/eslint-config-standard": "^5.1.2",
|
||||||
@@ -45,6 +44,9 @@
|
|||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"eslint-plugin-standard": "^4.0.0",
|
"eslint-plugin-standard": "^4.0.0",
|
||||||
"eslint-plugin-vue": "^6.2.2",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
|
"karma": "^3.1.4",
|
||||||
|
"karma-webpack": "^4.0.2",
|
||||||
|
"vue-cli-plugin-ui-karma": "^0.2.5",
|
||||||
"vue-template-compiler": "^2.6.11"
|
"vue-template-compiler": "^2.6.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"query": "select * from invoices",
|
|
||||||
"chart": {
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"type": "scatter",
|
|
||||||
"mode": "lines",
|
|
||||||
"x": null,
|
|
||||||
"xsrc": "InvoiceId",
|
|
||||||
"meta": {
|
|
||||||
"columnNames": {
|
|
||||||
"x": "InvoiceId",
|
|
||||||
"y": "Total"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"y": null,
|
|
||||||
"ysrc": "Total"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"layout": {
|
|
||||||
"xaxis": {
|
|
||||||
"range": [
|
|
||||||
1,
|
|
||||||
412
|
|
||||||
],
|
|
||||||
"autorange": true,
|
|
||||||
"type": "linear"
|
|
||||||
},
|
|
||||||
"yaxis": {
|
|
||||||
"range": [
|
|
||||||
-0.39166666666666683,
|
|
||||||
27.241666666666667
|
|
||||||
],
|
|
||||||
"autorange": true,
|
|
||||||
"type": "linear"
|
|
||||||
},
|
|
||||||
"autosize": true,
|
|
||||||
"mapbox": {
|
|
||||||
"style": "open-street-map"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"frames": []
|
|
||||||
},
|
|
||||||
"name": "Invoices",
|
|
||||||
"id": "ieZfcITwDUTADwOmQlYyL",
|
|
||||||
"createdAt": "2020-11-03T14:17:49.524Z"
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#app, * {
|
#app {
|
||||||
font-family: Open-Sans, Helvetica, Arial, sans-serif;
|
font-family: Open-Sans, Helvetica, Arial, sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|||||||
BIN
src/assets/images/body.png
Normal file
BIN
src/assets/images/body.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
BIN
src/assets/images/dropFileBottom.png
Normal file
BIN
src/assets/images/dropFileBottom.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
src/assets/images/dropFileTop.png
Normal file
BIN
src/assets/images/dropFileTop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
src/assets/images/file.png
Normal file
BIN
src/assets/images/file.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.9 KiB |
BIN
src/assets/images/leftArm.png
Normal file
BIN
src/assets/images/leftArm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
BIN
src/assets/images/rightArm.png
Normal file
BIN
src/assets/images/rightArm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
@@ -5,6 +5,7 @@ button {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
font-family: Open-Sans, Helvetica, Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:focus {
|
button:focus {
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="db-upload-container">
|
<div class="db-upload-container">
|
||||||
<label for="assetsFieldHandle">
|
<label for="assetsFieldHandle">
|
||||||
<div class="drop-area" @dragover="dragover" @dragleave="dragleave" @drop="drop">
|
<div
|
||||||
|
class="drop-area"
|
||||||
|
@dragover.prevent="state = 'dragover'"
|
||||||
|
@dragleave.prevent="state=''"
|
||||||
|
@drop.prevent="drop"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
id="assetsFieldHandle"
|
id="assetsFieldHandle"
|
||||||
@@ -10,10 +15,34 @@
|
|||||||
accept=".db,.sqlite,.sqlite3"
|
accept=".db,.sqlite,.sqlite3"
|
||||||
/>
|
/>
|
||||||
<div class="text">
|
<div class="text">
|
||||||
Drop the database file to upload here or click to choose a file from your computer.
|
Drop the database file here or click to choose a file from your computer.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
<div v-if="illustrated" id="img-container">
|
||||||
|
<img id="drop-file-top-img" :src="require('@/assets/images/dropFileTop.png')" />
|
||||||
|
<img
|
||||||
|
id="left-arm-img"
|
||||||
|
:class="{'swing': state === 'dragover'}"
|
||||||
|
:src="require('@/assets/images/leftArm.png')"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
id="file-img"
|
||||||
|
ref="fileImg"
|
||||||
|
:class="{
|
||||||
|
'swing': state === 'dragover',
|
||||||
|
'fly': state === 'drop'
|
||||||
|
}"
|
||||||
|
:src="require('@/assets/images/file.png')"
|
||||||
|
/>
|
||||||
|
<img id="drop-file-bottom-img" :src="require('@/assets/images/dropFileBottom.png')" />
|
||||||
|
<img id="body-img" :src="require('@/assets/images/body.png')" />
|
||||||
|
<img
|
||||||
|
id="right-arm-img"
|
||||||
|
:class="{'swing': state === 'dragover'}"
|
||||||
|
:src="require('@/assets/images/rightArm.png')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div id="error" class="error"></div>
|
<div id="error" class="error"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -21,30 +50,44 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'DbUpload',
|
name: 'DbUpload',
|
||||||
|
props: {
|
||||||
|
illustrated: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
state: '',
|
||||||
|
animationPromise: Promise.resolve()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
if (this.illustrated) {
|
||||||
|
this.animationPromise = new Promise((resolve) => {
|
||||||
|
this.$refs.fileImg.addEventListener('animationend', event => {
|
||||||
|
if (event.animationName.startsWith('fly')) {
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
loadDb () {
|
loadDb () {
|
||||||
this.$db.loadDb(this.$refs.file.files[0])
|
this.state = 'drop'
|
||||||
},
|
return Promise.all([this.$db.loadDb(this.$refs.file.files[0]), this.animationPromise])
|
||||||
dragover (event) {
|
.then(([schema]) => {
|
||||||
event.preventDefault()
|
this.$store.commit('saveSchema', schema)
|
||||||
// TODO: Add some visual stuff to show the user can drop its files
|
if (this.$route.path !== '/editor') {
|
||||||
if (!event.currentTarget.classList.contains('bg-green-300')) {
|
this.$router.push('/editor')
|
||||||
event.currentTarget.classList.remove('bg-gray-100')
|
}
|
||||||
event.currentTarget.classList.add('bg-green-300')
|
})
|
||||||
}
|
|
||||||
},
|
|
||||||
dragleave (event) {
|
|
||||||
// Clean up
|
|
||||||
event.currentTarget.classList.add('bg-gray-100')
|
|
||||||
event.currentTarget.classList.remove('bg-green-300')
|
|
||||||
},
|
},
|
||||||
drop (event) {
|
drop (event) {
|
||||||
event.preventDefault()
|
|
||||||
this.$refs.file.files = event.dataTransfer.files
|
this.$refs.file.files = event.dataTransfer.files
|
||||||
this.loadDb()
|
this.loadDb()
|
||||||
// Clean up
|
|
||||||
event.currentTarget.classList.add('bg-gray-100')
|
|
||||||
event.currentTarget.classList.remove('bg-green-300')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,4 +120,80 @@ label {
|
|||||||
input {
|
input {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#img-container {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(50% - 120px);
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 450px;
|
||||||
|
height: 338px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
#drop-file-top-img {
|
||||||
|
width: 450px;
|
||||||
|
height: 171px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
#drop-file-bottom-img {
|
||||||
|
width: 450px;
|
||||||
|
height: 167px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
#body-img {
|
||||||
|
width: 74px;
|
||||||
|
position: absolute;
|
||||||
|
top: 94.05px;
|
||||||
|
left: 46px;
|
||||||
|
}
|
||||||
|
#right-arm-img {
|
||||||
|
width: 106px;
|
||||||
|
position: absolute;
|
||||||
|
top: 110.05px;
|
||||||
|
left: 78px;
|
||||||
|
}
|
||||||
|
#left-arm-img {
|
||||||
|
width: 114px;
|
||||||
|
position: absolute;
|
||||||
|
top: 69.05px;
|
||||||
|
left: 69px;
|
||||||
|
}
|
||||||
|
#file-img {
|
||||||
|
width: 125px;
|
||||||
|
position: absolute;
|
||||||
|
top: 15.66px;
|
||||||
|
left: 152px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swing {
|
||||||
|
animation: swing ease-in-out 0.6s infinite alternate;
|
||||||
|
}
|
||||||
|
#left-arm-img.swing {
|
||||||
|
transform-origin: 9px 83px;
|
||||||
|
}
|
||||||
|
#right-arm-img.swing {
|
||||||
|
transform-origin: 0 56px;
|
||||||
|
}
|
||||||
|
#file-img.swing {
|
||||||
|
transform-origin: -74px 139px;
|
||||||
|
}
|
||||||
|
@keyframes swing {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(-7deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
#file-img.fly {
|
||||||
|
animation: fly ease-in-out 1s 1 normal;
|
||||||
|
transform-origin: center center;
|
||||||
|
top: 183px;
|
||||||
|
left: 225px;
|
||||||
|
transition: top 1s ease-in-out, left 1s ease-in-out;
|
||||||
|
}
|
||||||
|
@keyframes fly {
|
||||||
|
100% { transform: rotate(360deg) scale(0.5); }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ export default {
|
|||||||
const isFromScratch = !this.currentQuery.initName
|
const isFromScratch = !this.currentQuery.initName
|
||||||
|
|
||||||
if (isFromScratch || this.isPredefined) {
|
if (isFromScratch || this.isPredefined) {
|
||||||
|
this.name = ''
|
||||||
this.$modal.show('save')
|
this.$modal.show('save')
|
||||||
} else {
|
} else {
|
||||||
this.saveQuery()
|
this.saveQuery()
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
changeDb () {
|
changeDb () {
|
||||||
this.$db.loadDb(this.$refs.dbfile.files[0])
|
this.$db.loadDb(this.$refs.dbfile.files[0])
|
||||||
|
.then((schema) => {
|
||||||
|
this.$store.commit('saveSchema', schema)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,4 +98,8 @@ export default {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
|
>>> .CodeMirror-cursor {
|
||||||
|
width: 1px;
|
||||||
|
background: var(--color-text-base);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,35 +1,36 @@
|
|||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import router from '@/router'
|
|
||||||
const worker = new Worker('js/worker.sql-wasm.js')
|
const worker = new Worker('js/worker.sql-wasm.js')
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
loadDb (file) {
|
loadDb (file) {
|
||||||
const dbName = file.name
|
return new Promise((resolve, reject) => {
|
||||||
store.commit('saveDbName', dbName)
|
const dbName = file.name
|
||||||
const f = file
|
store.commit('saveDbName', dbName)
|
||||||
const r = new FileReader()
|
const f = file
|
||||||
r.onload = () => {
|
const r = new FileReader()
|
||||||
worker.onmessage = () => {
|
r.onload = () => {
|
||||||
const getSchemaSql = `
|
// on 'action: open' completed
|
||||||
SELECT name, sql
|
worker.onmessage = () => {
|
||||||
FROM sqlite_master
|
const getSchemaSql = `
|
||||||
WHERE type='table' AND name NOT LIKE 'sqlite_%';`
|
SELECT name, sql
|
||||||
worker.onmessage = event => {
|
FROM sqlite_master
|
||||||
store.commit('saveSchema', event.data.results[0].values)
|
WHERE type='table' AND name NOT LIKE 'sqlite_%';`
|
||||||
if (router.currentRoute.path !== '/editor') {
|
|
||||||
router.push('/editor')
|
// on 'action: exec' completed
|
||||||
|
worker.onmessage = event => {
|
||||||
|
resolve(event.data.results[0].values)
|
||||||
}
|
}
|
||||||
|
worker.postMessage({ action: 'exec', sql: getSchemaSql })
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
worker.postMessage({ action: 'open', buffer: r.result }, [r.result])
|
||||||
|
} catch (exception) {
|
||||||
|
worker.postMessage({ action: 'open', buffer: r.result })
|
||||||
}
|
}
|
||||||
worker.postMessage({ action: 'exec', sql: getSchemaSql })
|
|
||||||
}
|
}
|
||||||
store.commit('saveDbFile', r.result)
|
r.readAsArrayBuffer(f)
|
||||||
try {
|
})
|
||||||
worker.postMessage({ action: 'open', buffer: r.result }, [r.result])
|
|
||||||
} catch (exception) {
|
|
||||||
worker.postMessage({ action: 'open', buffer: r.result })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r.readAsArrayBuffer(f)
|
|
||||||
},
|
},
|
||||||
execute (commands) {
|
execute (commands) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<schema v-if="$store.state.schema"/>
|
<schema v-if="$store.state.schema"/>
|
||||||
<div v-else id="empty-schema-container">
|
<div v-else id="empty-schema-container">
|
||||||
<div class="warning">
|
<div class="warning">
|
||||||
Database is not uploaded. Queries can’t be run without database.
|
Database is not loaded. Queries can’t be run without database.
|
||||||
</div>
|
</div>
|
||||||
<db-upload id="db-uploader"/>
|
<db-upload id="db-uploader"/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="dbloader-container">
|
<div id="dbloader-container">
|
||||||
<h1>Sqliteviz</h1>
|
<db-upload illustrated />
|
||||||
<db-upload />
|
<div id="note">
|
||||||
|
Sqliteviz is fully client-side. Your database never leaves your computer.
|
||||||
|
</div>
|
||||||
<button id ="skip" class="secondary" @click="$router.push('/editor')">
|
<button id ="skip" class="secondary" @click="$router.push('/editor')">
|
||||||
Skip database connection for now
|
Skip database loading
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -13,33 +15,7 @@ import dbUpload from '@/components/DbUpload'
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
components: { dbUpload },
|
components: { dbUpload }
|
||||||
methods: {
|
|
||||||
loadDb () {
|
|
||||||
this.$db.loadDb(this.$refs.file.files[0])
|
|
||||||
},
|
|
||||||
dragover (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
// TODO: Add some visual stuff to show the user can drop its files
|
|
||||||
if (!event.currentTarget.classList.contains('bg-green-300')) {
|
|
||||||
event.currentTarget.classList.remove('bg-gray-100')
|
|
||||||
event.currentTarget.classList.add('bg-green-300')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dragleave (event) {
|
|
||||||
// Clean up
|
|
||||||
event.currentTarget.classList.add('bg-gray-100')
|
|
||||||
event.currentTarget.classList.remove('bg-green-300')
|
|
||||||
},
|
|
||||||
drop (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
this.$refs.file.files = event.dataTransfer.files
|
|
||||||
this.loadDb()
|
|
||||||
// Clean up
|
|
||||||
event.currentTarget.classList.add('bg-gray-100')
|
|
||||||
event.currentTarget.classList.remove('bg-green-300')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -53,18 +29,26 @@ export default {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
#note {
|
||||||
color: var(--color-accent);
|
margin-top: 27px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-base);
|
||||||
}
|
}
|
||||||
|
|
||||||
#skip {
|
#skip {
|
||||||
position: absolute;
|
margin-top: 83px;
|
||||||
bottom: 50px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
>>>.drop-area {
|
>>>.drop-area {
|
||||||
width: 628px;
|
width: 706px;
|
||||||
height: 490px;
|
height: 482px;
|
||||||
padding: 0 150px;
|
padding: 0 150px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
>>>.drop-area .text {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 42px;
|
||||||
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default {
|
|||||||
xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
if (xhr.readyState === 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
resolve(JSON.parse(xhr.responseText))
|
resolve(JSON.parse(xhr.responseText || '[]'))
|
||||||
} else {
|
} else {
|
||||||
reject(xhr.statusText)
|
reject(xhr.statusText)
|
||||||
}
|
}
|
||||||
|
|||||||
39
tests/unit/dataBase.spec.js
Normal file
39
tests/unit/dataBase.spec.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/* import { expect } from 'chai'
|
||||||
|
import { shallowMount } from '@vue/test-utils'
|
||||||
|
import HelloWorld from '@/components/HelloWorld.vue'
|
||||||
|
|
||||||
|
describe('HelloWorld.vue', () => {
|
||||||
|
it('renders props.msg when passed', () => {
|
||||||
|
const msg = 'new message'
|
||||||
|
const wrapper = shallowMount(HelloWorld, {
|
||||||
|
propsData: { msg }
|
||||||
|
})
|
||||||
|
expect(wrapper.text()).to.include(msg)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
import { expect } from 'chai'
|
||||||
|
import initSqlJs from 'sql.js'
|
||||||
|
import db from '@/dataBase.js'
|
||||||
|
|
||||||
|
describe('dataBase.js', () => {
|
||||||
|
it('creates schema', () => {
|
||||||
|
const config = {
|
||||||
|
locateFile: filename => `js/sql-wasm.wasm`
|
||||||
|
}
|
||||||
|
return initSqlJs(config)
|
||||||
|
.then(SQL => {
|
||||||
|
const dataBase = new SQL.Database()
|
||||||
|
dataBase.run('CREATE TABLE test (col1, col2);')
|
||||||
|
|
||||||
|
const data = dataBase.export()
|
||||||
|
const buffer = new Blob([data])
|
||||||
|
return db.loadDb(buffer)
|
||||||
|
})
|
||||||
|
.then(schema => {
|
||||||
|
expect(schema.length).to.equal(1)
|
||||||
|
expect(schema[0][0]).to.equal('test')
|
||||||
|
expect(schema[0][1]).to.equal('CREATE TABLE test (col1, col2)')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { expect } from 'chai'
|
|
||||||
import { shallowMount } from '@vue/test-utils'
|
|
||||||
import HelloWorld from '@/components/HelloWorld.vue'
|
|
||||||
|
|
||||||
describe('HelloWorld.vue', () => {
|
|
||||||
it('renders props.msg when passed', () => {
|
|
||||||
const msg = 'new message'
|
|
||||||
const wrapper = shallowMount(HelloWorld, {
|
|
||||||
propsData: { msg }
|
|
||||||
})
|
|
||||||
expect(wrapper.text()).to.include(msg)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -8,7 +8,8 @@ module.exports = {
|
|||||||
// This wasm file will be fetched dynamically when we initialize sql.js
|
// This wasm file will be fetched dynamically when we initialize sql.js
|
||||||
// It is important that we do not change its name, and that it is in the same folder as the js
|
// It is important that we do not change its name, and that it is in the same folder as the js
|
||||||
{ from: 'node_modules/sql.js/dist/sql-wasm.wasm', to: 'js/' },
|
{ from: 'node_modules/sql.js/dist/sql-wasm.wasm', to: 'js/' },
|
||||||
{ from: 'node_modules/sql.js/dist/worker.sql-wasm.js', to: 'js/' }
|
{ from: 'node_modules/sql.js/dist/worker.sql-wasm.js', to: 'js/' },
|
||||||
|
{ from: 'LICENSE', to: './' }
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user