mirror of
https://github.com/lana-k/sqliteviz.git
synced 2025-12-06 18:18:53 +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
|
||||
node_modules
|
||||
/dist
|
||||
/coverage
|
||||
|
||||
# local env files
|
||||
.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",
|
||||
"version": "0.6.0",
|
||||
"license" : "Apache-2.0",
|
||||
"version": "0.7.0",
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
@@ -32,7 +32,6 @@
|
||||
"@vue/cli-plugin-babel": "^4.4.0",
|
||||
"@vue/cli-plugin-eslint": "^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-service": "^4.4.0",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
@@ -45,6 +44,9 @@
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
<style>
|
||||
#app, * {
|
||||
#app {
|
||||
font-family: Open-Sans, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-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-weight: 600;
|
||||
cursor: pointer;
|
||||
font-family: Open-Sans, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
<template>
|
||||
<div class="db-upload-container">
|
||||
<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
|
||||
type="file"
|
||||
id="assetsFieldHandle"
|
||||
@@ -10,10 +15,34 @@
|
||||
accept=".db,.sqlite,.sqlite3"
|
||||
/>
|
||||
<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>
|
||||
</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>
|
||||
</template>
|
||||
@@ -21,30 +50,44 @@
|
||||
<script>
|
||||
export default {
|
||||
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: {
|
||||
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')
|
||||
this.state = 'drop'
|
||||
return Promise.all([this.$db.loadDb(this.$refs.file.files[0]), this.animationPromise])
|
||||
.then(([schema]) => {
|
||||
this.$store.commit('saveSchema', schema)
|
||||
if (this.$route.path !== '/editor') {
|
||||
this.$router.push('/editor')
|
||||
}
|
||||
})
|
||||
},
|
||||
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')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,4 +120,80 @@ label {
|
||||
input {
|
||||
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>
|
||||
|
||||
@@ -101,6 +101,7 @@ export default {
|
||||
const isFromScratch = !this.currentQuery.initName
|
||||
|
||||
if (isFromScratch || this.isPredefined) {
|
||||
this.name = ''
|
||||
this.$modal.show('save')
|
||||
} else {
|
||||
this.saveQuery()
|
||||
|
||||
@@ -76,6 +76,9 @@ export default {
|
||||
methods: {
|
||||
changeDb () {
|
||||
this.$db.loadDb(this.$refs.dbfile.files[0])
|
||||
.then((schema) => {
|
||||
this.$store.commit('saveSchema', schema)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,4 +98,8 @@ export default {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
>>> .CodeMirror-cursor {
|
||||
width: 1px;
|
||||
background: var(--color-text-base);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
import store from '@/store'
|
||||
import router from '@/router'
|
||||
const worker = new Worker('js/worker.sql-wasm.js')
|
||||
|
||||
export default {
|
||||
loadDb (file) {
|
||||
const dbName = file.name
|
||||
store.commit('saveDbName', dbName)
|
||||
const f = file
|
||||
const r = new FileReader()
|
||||
r.onload = () => {
|
||||
worker.onmessage = () => {
|
||||
const getSchemaSql = `
|
||||
SELECT name, sql
|
||||
FROM sqlite_master
|
||||
WHERE type='table' AND name NOT LIKE 'sqlite_%';`
|
||||
worker.onmessage = event => {
|
||||
store.commit('saveSchema', event.data.results[0].values)
|
||||
if (router.currentRoute.path !== '/editor') {
|
||||
router.push('/editor')
|
||||
return new Promise((resolve, reject) => {
|
||||
const dbName = file.name
|
||||
store.commit('saveDbName', dbName)
|
||||
const f = file
|
||||
const r = new FileReader()
|
||||
r.onload = () => {
|
||||
// on 'action: open' completed
|
||||
worker.onmessage = () => {
|
||||
const getSchemaSql = `
|
||||
SELECT name, sql
|
||||
FROM sqlite_master
|
||||
WHERE type='table' AND name NOT LIKE 'sqlite_%';`
|
||||
|
||||
// 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)
|
||||
try {
|
||||
worker.postMessage({ action: 'open', buffer: r.result }, [r.result])
|
||||
} catch (exception) {
|
||||
worker.postMessage({ action: 'open', buffer: r.result })
|
||||
}
|
||||
}
|
||||
r.readAsArrayBuffer(f)
|
||||
r.readAsArrayBuffer(f)
|
||||
})
|
||||
},
|
||||
execute (commands) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<schema v-if="$store.state.schema"/>
|
||||
<div v-else id="empty-schema-container">
|
||||
<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>
|
||||
<db-upload id="db-uploader"/>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div id="dbloader-container">
|
||||
<h1>Sqliteviz</h1>
|
||||
<db-upload />
|
||||
<db-upload illustrated />
|
||||
<div id="note">
|
||||
Sqliteviz is fully client-side. Your database never leaves your computer.
|
||||
</div>
|
||||
<button id ="skip" class="secondary" @click="$router.push('/editor')">
|
||||
Skip database connection for now
|
||||
Skip database loading
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -13,33 +15,7 @@ import dbUpload from '@/components/DbUpload'
|
||||
|
||||
export default {
|
||||
name: 'Home',
|
||||
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')
|
||||
}
|
||||
}
|
||||
components: { dbUpload }
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -53,18 +29,26 @@ export default {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--color-accent);
|
||||
#note {
|
||||
margin-top: 27px;
|
||||
font-size: 13px;
|
||||
color: var(--color-text-base);
|
||||
}
|
||||
|
||||
#skip {
|
||||
position: absolute;
|
||||
bottom: 50px;
|
||||
margin-top: 83px;
|
||||
}
|
||||
|
||||
>>>.drop-area {
|
||||
width: 628px;
|
||||
height: 490px;
|
||||
width: 706px;
|
||||
height: 482px;
|
||||
padding: 0 150px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
>>>.drop-area .text {
|
||||
position: absolute;
|
||||
bottom: 42px;
|
||||
max-width: 300px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
xhr.onload = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
resolve(JSON.parse(xhr.responseText))
|
||||
resolve(JSON.parse(xhr.responseText || '[]'))
|
||||
} else {
|
||||
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
|
||||
// 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/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