mirror of
https://github.com/lana-k/sqliteviz.git
synced 2025-12-06 10:08:52 +08:00
#63 migrate to Vue 3
This commit is contained in:
@@ -8,13 +8,17 @@ module.exports = {
|
||||
'@vue/standard'
|
||||
],
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
parser: '@babel/eslint-parser'
|
||||
},
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-case-declarations': 'off',
|
||||
'max-len': [2, 100, 4, { ignoreUrls: true }]
|
||||
'max-len': [2, 100, 4, { ignoreUrls: true }],
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/no-mutating-props': 'warn',
|
||||
'vue/no-reserved-component-names': 'warn',
|
||||
'vue/no-v-model-argument': 'off'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Vue from 'vue'
|
||||
import { VuePlugin } from 'vuera'
|
||||
import VModal from 'vue-js-modal'
|
||||
// import { VuePlugin } from 'vuera'
|
||||
// import VModal from 'vue-js-modal'
|
||||
|
||||
Vue.use(VuePlugin)
|
||||
Vue.use(VModal)
|
||||
// Vue.use(VuePlugin)
|
||||
// Vue.use(VModal)
|
||||
Vue.config.productionTip = false
|
||||
|
||||
// require all test files (files that ends with .spec.js)
|
||||
|
||||
33001
package-lock.json
generated
33001
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
46
package.json
46
package.json
@@ -10,7 +10,9 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"assert": "^2.1.0",
|
||||
"codemirror": "^5.65.18",
|
||||
"codemirror-editor-vue3": "^2.8.0",
|
||||
"core-js": "^3.6.5",
|
||||
"dataurl-to-blob": "^0.0.1",
|
||||
"html2canvas": "^1.1.4",
|
||||
@@ -24,39 +26,41 @@
|
||||
"react-chart-editor": "^0.46.1",
|
||||
"react-dom": "^16.14.0",
|
||||
"sql.js": "file:./lib/sql-js",
|
||||
"vue": "^2.6.11",
|
||||
"vue-codemirror": "^4.0.6",
|
||||
"vue-js-modal": "^2.0.0-rc.6",
|
||||
"vue-multiselect": "^2.1.6",
|
||||
"vue-router": "^3.2.0",
|
||||
"vue2-teleport": "^1.0.1",
|
||||
"vuejs-paginate": "^2.1.0",
|
||||
"vuera": "^0.2.7",
|
||||
"vuex": "^3.4.0"
|
||||
"stream-browserify": "^3.0.0",
|
||||
"tiny-emitter": "^2.1.0",
|
||||
"url-loader": "^4.1.1",
|
||||
"veaury": "^2.5.1",
|
||||
"vue": "^3.5.11",
|
||||
"vue-final-modal": "^4.5.5",
|
||||
"vue-multiselect": "^3.0.0-beta.3",
|
||||
"vue-router": "^4.4.5",
|
||||
"vuejs-paginate-next": "^1.0.2",
|
||||
"vuex": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.4.0",
|
||||
"@vue/cli-plugin-eslint": "^4.4.0",
|
||||
"@vue/cli-plugin-router": "^4.4.0",
|
||||
"@vue/cli-plugin-vuex": "^4.4.0",
|
||||
"@vue/cli-service": "^4.4.0",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"@vue/test-utils": "^1.1.2",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"@babel/core": "^7.25.7",
|
||||
"@babel/eslint-parser": "^7.25.7",
|
||||
"@vue/cli-plugin-babel": "^5.0.8",
|
||||
"@vue/cli-plugin-eslint": "^5.0.8",
|
||||
"@vue/cli-plugin-router": "^5.0.8",
|
||||
"@vue/cli-plugin-vuex": "^5.0.8",
|
||||
"@vue/cli-service": "^5.0.8",
|
||||
"@vue/eslint-config-standard": "^8.0.1",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"chai": "^4.1.2",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"eslint": "^6.7.2",
|
||||
"copy-webpack-plugin": "^6.4.1",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"eslint-plugin-vue": "^9.28.0",
|
||||
"flush-promises": "^1.0.2",
|
||||
"karma": "^3.1.4",
|
||||
"karma-firefox-launcher": "^2.1.0",
|
||||
"karma-webpack": "^4.0.2",
|
||||
"karma-webpack": "^5.0.1",
|
||||
"vue-cli-plugin-ui-karma": "^0.2.5",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"workbox-webpack-plugin": "^6.1.5",
|
||||
"worker-loader": "^3.0.8"
|
||||
}
|
||||
|
||||
13
src/App.vue
13
src/App.vue
@@ -1,9 +1,18 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view/>
|
||||
<modals-container/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ModalsContainer } from 'vue-final-modal'
|
||||
|
||||
export default {
|
||||
components: { ModalsContainer }
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: "Open Sans";
|
||||
@@ -48,10 +57,12 @@
|
||||
}
|
||||
|
||||
#app,
|
||||
.dialog,
|
||||
input,
|
||||
label,
|
||||
button,
|
||||
.plotly_editor * {
|
||||
.plotly_editor *,
|
||||
.CodeMirror pre.CodeMirror-line {
|
||||
font-family: "Open Sans", Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
.dialog {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.dialog .vfm__content {
|
||||
border-radius: var(--border-radius-big);
|
||||
box-shadow: 0px 2px 9px rgba(80, 103, 132, 0.8);
|
||||
background-color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
@@ -35,6 +42,6 @@
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.vm--overlay {
|
||||
.vfm__overlay.vfm--overlay {
|
||||
background-color: rgba(162, 177, 198, 0.5);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ export default {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['click'],
|
||||
data () {
|
||||
return {
|
||||
checked: this.init
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
@click.stop
|
||||
:disabled="disabled"
|
||||
/>
|
||||
<div class="name">{{ getSymbolName(value) }}</div>
|
||||
<div class="name">{{ getSymbolName(modelValue) }}</div>
|
||||
</div>
|
||||
<div class="controls" @click.stop>
|
||||
<clear-icon @click.native="clear" :disabled="disabled"/>
|
||||
<clear-icon @click="clear" :disabled="disabled"/>
|
||||
<drop-down-chevron
|
||||
:disabled="disabled"
|
||||
@click.native="!disabled && (showOptions = !showOptions)"
|
||||
@click="!disabled && (showOptions = !showOptions)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -46,7 +46,7 @@ import ClearIcon from '@/components/svg/clear'
|
||||
|
||||
export default {
|
||||
name: 'DelimiterSelector',
|
||||
props: ['value', 'width', 'disabled'],
|
||||
props: ['modelValue', 'width', 'disabled'],
|
||||
components: { DropDownChevron, ClearIcon },
|
||||
data () {
|
||||
return {
|
||||
@@ -60,8 +60,8 @@ export default {
|
||||
inputValue () {
|
||||
if (this.inputValue) {
|
||||
this.filled = true
|
||||
if (this.inputValue !== this.value) {
|
||||
this.$emit('input', this.inputValue)
|
||||
if (this.inputValue !== this.modelValue) {
|
||||
this.$emit('update:modelValue', this.inputValue)
|
||||
}
|
||||
} else {
|
||||
this.filled = false
|
||||
@@ -69,7 +69,7 @@ export default {
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.inputValue = this.value
|
||||
this.inputValue = this.modelValue
|
||||
},
|
||||
methods: {
|
||||
getSymbolName (str) {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<template>
|
||||
<modal
|
||||
:name="dialogName"
|
||||
classes="dialog"
|
||||
height="auto"
|
||||
width="80%"
|
||||
:modal-id="dialogName"
|
||||
class="dialog"
|
||||
content-class="import-modal"
|
||||
scrollable
|
||||
:clickToClose="false"
|
||||
>
|
||||
@@ -130,6 +129,7 @@ export default {
|
||||
db: Object,
|
||||
dialogName: String
|
||||
},
|
||||
emits: ['cancel', 'finish'],
|
||||
data () {
|
||||
return {
|
||||
disableDialog: false,
|
||||
@@ -304,7 +304,7 @@ export default {
|
||||
let importLoadingIndicator = null
|
||||
|
||||
const updateProgress = progress => {
|
||||
this.$set(importMsg, 'progress', progress)
|
||||
importMsg.progress = progress
|
||||
}
|
||||
const progressCounterId = this.db.createProgressCounter(updateProgress)
|
||||
|
||||
@@ -392,8 +392,10 @@ export default {
|
||||
events.send('inquiry.create', null, { auto: true })
|
||||
},
|
||||
getQueryExample () {
|
||||
return this.isNdJson ? this.getNdJsonQueryExample()
|
||||
: this.isJson ? this.getJsonQueryExample()
|
||||
return this.isNdJson
|
||||
? this.getNdJsonQueryExample()
|
||||
: this.isJson
|
||||
? this.getJsonQueryExample()
|
||||
: [
|
||||
'/*',
|
||||
` * Your CSV file has been imported into ${this.addedTable} table.`,
|
||||
@@ -455,6 +457,15 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.import-modal {
|
||||
width: 80%;
|
||||
max-width: 1152px;
|
||||
margin: auto;
|
||||
left: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.dialog-body {
|
||||
padding-bottom: 0;
|
||||
@@ -495,10 +506,4 @@ margin-bottom: 24px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* https://github.com/euvl/vue-js-modal/issues/623 */
|
||||
>>> .vm--modal {
|
||||
max-width: 1152px;
|
||||
margin: auto;
|
||||
left: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -78,6 +78,7 @@ export default {
|
||||
default: 'unset'
|
||||
}
|
||||
},
|
||||
emits: [],
|
||||
components: {
|
||||
ChangeDbIcon,
|
||||
CsvJsonImport
|
||||
|
||||
@@ -23,6 +23,7 @@ import LoadingIndicator from '@/components/LoadingIndicator'
|
||||
export default {
|
||||
name: 'SideBarButton',
|
||||
props: ['active', 'disabled', 'tooltip', 'tooltipPosition', 'loading'],
|
||||
emits: ['click'],
|
||||
components: { LoadingIndicator },
|
||||
mixins: [tooltipMixin],
|
||||
methods: {
|
||||
@@ -51,15 +52,15 @@ export default {
|
||||
border-radius: var(--border-radius-medium-2);
|
||||
}
|
||||
|
||||
.icon-btn:hover .icon >>> path,
|
||||
.icon-btn.active .icon >>> path,
|
||||
.icon-btn:hover .icon >>> circle,
|
||||
.icon-btn.active .icon >>> circle {
|
||||
.icon-btn:hover .icon :deep(path),
|
||||
.icon-btn.active .icon :deep(path),
|
||||
.icon-btn:hover .icon :deep(circle),
|
||||
.icon-btn.active .icon :deep(circle) {
|
||||
fill: var(--color-accent);
|
||||
}
|
||||
|
||||
.icon-btn:disabled .icon >>> path,
|
||||
.icon-btn:disabled .icon >>> circle {
|
||||
.icon-btn:disabled .icon :deep(path),
|
||||
.icon-btn:disabled .icon :deep(circle) {
|
||||
fill: var(--color-border);
|
||||
}
|
||||
|
||||
@@ -68,7 +69,7 @@ export default {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.disabled.icon-btn:hover .icon >>> path {
|
||||
.disabled.icon-btn:hover .icon :deep(path) {
|
||||
fill: var(--color-border);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<template>
|
||||
<modal
|
||||
:name="name"
|
||||
classes="dialog"
|
||||
height="auto"
|
||||
:modal-id="name"
|
||||
class="dialog"
|
||||
:clickToClose="false"
|
||||
>
|
||||
<div class="dialog-header">
|
||||
@@ -52,6 +51,7 @@ export default {
|
||||
title: String,
|
||||
loading: Boolean
|
||||
},
|
||||
emits: ['cancel', 'action'],
|
||||
watch: {
|
||||
loading () {
|
||||
if (this.loading) {
|
||||
|
||||
@@ -31,6 +31,7 @@ export default {
|
||||
default: 20
|
||||
}
|
||||
},
|
||||
emits: [],
|
||||
computed: {
|
||||
circleProgress () {
|
||||
const circle = this.radius * 3.14 * 2
|
||||
|
||||
@@ -16,6 +16,7 @@ import LoadingIndicator from '@/components/LoadingIndicator'
|
||||
export default {
|
||||
name: 'logs',
|
||||
props: ['messages'],
|
||||
emits: [],
|
||||
components: { LoadingIndicator },
|
||||
watch: {
|
||||
'messages.length': 'scrollToBottom'
|
||||
|
||||
@@ -86,12 +86,15 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
emits: [],
|
||||
data () {
|
||||
return {
|
||||
container: null,
|
||||
paneBefore: this.before,
|
||||
paneAfter: this.after,
|
||||
beforeMinimising: !this.after.size || !this.before.size ? this.default : {
|
||||
beforeMinimising: !this.after.size || !this.before.size
|
||||
? this.default
|
||||
: {
|
||||
before: this.before.size,
|
||||
after: this.after.size
|
||||
},
|
||||
|
||||
@@ -18,15 +18,16 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Paginate from 'vuejs-paginate'
|
||||
import Paginate from 'vuejs-paginate-next'
|
||||
|
||||
export default {
|
||||
name: 'Pager',
|
||||
components: { Paginate },
|
||||
props: ['pageCount', 'value'],
|
||||
props: ['pageCount', 'modelValue'],
|
||||
emits: ['update:modelValue'],
|
||||
data () {
|
||||
return {
|
||||
page: this.value,
|
||||
page: this.modelValue,
|
||||
chevron: `
|
||||
<svg width="9" height="9" viewBox="0 0 8 12" fill="none">
|
||||
<path
|
||||
@@ -39,10 +40,10 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
page () {
|
||||
this.$emit('input', this.page)
|
||||
this.$emit('update:modelValue', this.page)
|
||||
},
|
||||
value () {
|
||||
this.page = this.value
|
||||
modelValue () {
|
||||
this.page = this.modelValue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,48 +55,48 @@ export default {
|
||||
align-items: center;
|
||||
line-height: 10px;
|
||||
}
|
||||
>>> .paginator-page-link {
|
||||
:deep(.paginator-page-link) {
|
||||
padding: 2px 3px;
|
||||
margin: 0 5px;
|
||||
display: block;
|
||||
color: var(--color-text-base);
|
||||
font-size: 11px;
|
||||
}
|
||||
>>> .paginator-page-link:hover {
|
||||
:deep(.paginator-page-link:hover) {
|
||||
color: var(--color-text-active);
|
||||
}
|
||||
>>> .paginator-page-link:active,
|
||||
>>> .paginator-page-link:visited,
|
||||
>>> .paginator-page-link:focus,
|
||||
>>> .paginator-next:active,
|
||||
>>> .paginator-next:visited,
|
||||
>>> .paginator-next:focus,
|
||||
>>> .paginator-prev:active,
|
||||
>>> .paginator-prev:visited,
|
||||
>>> .paginator-prev:focus {
|
||||
:deep(.paginator-page-link:active),
|
||||
:deep(.paginator-page-link:visited),
|
||||
:deep(.paginator-page-link:focus),
|
||||
:deep(.paginator-next:active),
|
||||
:deep(.paginator-next:visited),
|
||||
:deep(.paginator-next:focus),
|
||||
:deep(.paginator-prev:active),
|
||||
:deep(.paginator-prev:visited),
|
||||
:deep(.paginator-prev:focus) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
>>> .paginator-active-page,
|
||||
>>> .paginator-active-page:hover {
|
||||
:deep(.paginator-active-page),
|
||||
:deep(.paginator-active-page:hover) {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
>>> .paginator-break:hover,
|
||||
>>> .paginator-disabled:hover {
|
||||
:deep(.paginator-break:hover),
|
||||
:deep(.paginator-disabled:hover) {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
>>> .paginator-prev svg {
|
||||
:deep(.paginator-prev svg) {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
>>> .paginator-next:hover path,
|
||||
>>> .paginator-prev:hover path {
|
||||
:deep(.paginator-next:hover path),
|
||||
:deep(.paginator-prev:hover path) {
|
||||
fill: var(--color-text-active);
|
||||
}
|
||||
>>> .paginator-disabled path,
|
||||
>>> .paginator-disabled:hover path {
|
||||
:deep(.paginator-disabled path),
|
||||
:deep(.paginator-disabled:hover path) {
|
||||
fill: var(--color-text-light-2);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -87,6 +87,7 @@ export default {
|
||||
preview: Boolean,
|
||||
selectedCellCoordinates: Object
|
||||
},
|
||||
emits: ['updateSelectedCell'],
|
||||
data () {
|
||||
return {
|
||||
header: null,
|
||||
@@ -248,7 +249,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
this.resizeObserver.unobserve(this.$refs.table)
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
:placeholder="placeholder"
|
||||
:class="{ error: errorMsg }"
|
||||
:style="{ width: width }"
|
||||
:value="value"
|
||||
:value="modelValue"
|
||||
:disabled="disabled"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
@input="$emit('update:modelValue', $event.target.value)"
|
||||
/>
|
||||
<div v-show="errorMsg" class="text-field-error">{{ errorMsg }}</div>
|
||||
</div>
|
||||
@@ -21,7 +21,16 @@
|
||||
import HintIcon from '@/components/svg/hint'
|
||||
export default {
|
||||
name: 'textField',
|
||||
props: ['placeholder', 'label', 'errorMsg', 'value', 'width', 'hint', 'maxHintWidth', 'disabled'],
|
||||
props: [
|
||||
'placeholder',
|
||||
'label',
|
||||
'errorMsg',
|
||||
'modelValue',
|
||||
'width',
|
||||
'hint',
|
||||
'maxHintWidth',
|
||||
'disabled'
|
||||
],
|
||||
components: { HintIcon }
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -46,6 +46,7 @@ export default {
|
||||
name: 'AddTableIcon',
|
||||
mixins: [tooltipMixin],
|
||||
props: ['tooltip'],
|
||||
emits: ['click'],
|
||||
methods: {
|
||||
onClick () {
|
||||
this.hideTooltip()
|
||||
|
||||
@@ -33,6 +33,7 @@ import tooltipMixin from '@/tooltipMixin'
|
||||
export default {
|
||||
name: 'changeDbIcon',
|
||||
mixins: [tooltipMixin],
|
||||
emits: ['click'],
|
||||
methods: {
|
||||
onClick () {
|
||||
this.hideTooltip()
|
||||
|
||||
@@ -30,7 +30,8 @@ export default {
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
},
|
||||
emits: ['click']
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ export default {
|
||||
name: 'ExportIcon',
|
||||
mixins: [tooltipMixin],
|
||||
props: ['tooltip', 'tooltipPosition'],
|
||||
emits: ['click'],
|
||||
methods: {
|
||||
onClick () {
|
||||
this.hideTooltip()
|
||||
|
||||
@@ -45,6 +45,7 @@ import tooltipMixin from '@/tooltipMixin'
|
||||
export default {
|
||||
name: 'HintIcon',
|
||||
props: ['hint', 'maxWidth'],
|
||||
emits: ['click'],
|
||||
mixins: [tooltipMixin],
|
||||
methods: {
|
||||
onClick () {
|
||||
|
||||
8
src/lib/eventBus.js
Normal file
8
src/lib/eventBus.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import emitter from 'tiny-emitter/instance'
|
||||
|
||||
export default {
|
||||
$on: (...args) => emitter.on(...args),
|
||||
$once: (...args) => emitter.once(...args),
|
||||
$off: (...args) => emitter.off(...args),
|
||||
$emit: (...args) => emitter.emit(...args)
|
||||
}
|
||||
@@ -48,11 +48,13 @@ export default {
|
||||
// Get inquiries from local storage
|
||||
const myInquiries = this.getStoredInquiries()
|
||||
|
||||
let inquiryIndex
|
||||
// Set createdAt
|
||||
if (newName) {
|
||||
value.createdAt = new Date()
|
||||
} else {
|
||||
var inquiryIndex = myInquiries.findIndex(oldInquiry => oldInquiry.id === inquiryTab.id)
|
||||
inquiryIndex = myInquiries
|
||||
.findIndex(oldInquiry => oldInquiry.id === inquiryTab.id)
|
||||
value.createdAt = myInquiries[inquiryIndex].createdAt
|
||||
}
|
||||
|
||||
|
||||
28
src/main.js
28
src/main.js
@@ -1,9 +1,8 @@
|
||||
import Vue from 'vue'
|
||||
import { createApp } from 'vue'
|
||||
import App from '@/App.vue'
|
||||
import router from '@/router'
|
||||
import store from '@/store'
|
||||
import { VuePlugin } from 'vuera'
|
||||
import VModal from 'vue-js-modal'
|
||||
import { createVfm, VueFinalModal, useVfm } from 'vue-final-modal'
|
||||
|
||||
import '@/assets/styles/variables.css'
|
||||
import '@/assets/styles/buttons.css'
|
||||
@@ -11,20 +10,23 @@ import '@/assets/styles/tables.css'
|
||||
import '@/assets/styles/dialogs.css'
|
||||
import '@/assets/styles/tooltips.css'
|
||||
import '@/assets/styles/messages.css'
|
||||
import 'vue-multiselect/dist/vue-multiselect.min.css'
|
||||
import 'vue-multiselect/dist/vue-multiselect.css'
|
||||
import '@/assets/styles/multiselect.css'
|
||||
import 'vue-final-modal/style.css'
|
||||
|
||||
if (!['localhost', '127.0.0.1'].includes(location.hostname)) {
|
||||
import('./registerServiceWorker') // eslint-disable-line no-unused-expressions
|
||||
}
|
||||
|
||||
Vue.use(VuePlugin)
|
||||
Vue.use(VModal)
|
||||
const app = createApp(App)
|
||||
.use(router)
|
||||
.use(store)
|
||||
.use(createVfm())
|
||||
.component('modal', VueFinalModal)
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
const vfm = useVfm()
|
||||
app.config.globalProperties.$modal = {
|
||||
show: modalId => vfm.open(modalId),
|
||||
hide: modalId => vfm.close(modalId)
|
||||
}
|
||||
app.mount('#app')
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
import Workspace from '@/views/Main/Workspace'
|
||||
import Inquiries from '@/views/Main/Inquiries'
|
||||
import Welcome from '@/views/Welcome'
|
||||
@@ -8,8 +7,6 @@ import LoadView from '@/views/LoadView'
|
||||
import store from '@/store'
|
||||
import database from '@/lib/database'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
@@ -40,7 +37,8 @@ const routes = [
|
||||
}
|
||||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes
|
||||
})
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import { createStore } from 'vuex'
|
||||
import state from '@/store/state'
|
||||
import mutations from '@/store/mutations'
|
||||
import actions from '@/store/actions'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
export default createStore({
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
|
||||
@@ -60,5 +60,8 @@ export default {
|
||||
},
|
||||
setPredefinedInquiriesLoaded (state, value) {
|
||||
state.predefinedInquiriesLoaded = value
|
||||
},
|
||||
setIsWorkspaceVisible (state, value) {
|
||||
state.isWorkspaceVisible = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,6 @@ export default {
|
||||
predefinedInquiries: [],
|
||||
loadingPredefinedInquiries: false,
|
||||
predefinedInquiriesLoaded: false,
|
||||
db: null
|
||||
db: null,
|
||||
isWorkspaceVisible: false
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
:src="require('@/assets/images/info.svg')"
|
||||
@click="$modal.show('app-info')"
|
||||
/>
|
||||
<modal name="app-info" classes="dialog" height="auto" width="400px">
|
||||
<modal
|
||||
modal-id="app-info"
|
||||
class="dialog"
|
||||
content-class="app-info-modal"
|
||||
>
|
||||
<div class="dialog-header">
|
||||
App info
|
||||
<close-icon @click="$modal.hide('app-info')"/>
|
||||
@@ -59,6 +63,12 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.app-info-modal {
|
||||
width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
#app-info-icon {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div id="my-inquiries-container">
|
||||
<div id="start-guide" v-if="allInquiries.length === 0">
|
||||
You don't have saved inquiries so far.
|
||||
<span class="link" @click="$root.$emit('createNewInquiry')">Create</span>
|
||||
<span class="link" @click="emitCreateTabEvent">Create</span>
|
||||
the one from scratch or
|
||||
<span @click="importInquiries" class="link">import</span> from a file.
|
||||
</div>
|
||||
@@ -89,7 +89,9 @@
|
||||
</td>
|
||||
<td>
|
||||
<div class="second-column">
|
||||
<div class="date-container">{{ inquiry.createdAt | date }}</div>
|
||||
<div class="date-container">
|
||||
{{ createdAtFormatted(inquiry.createdAt) }}
|
||||
</div>
|
||||
<div class="icons-container">
|
||||
<rename-icon
|
||||
v-if="!inquiry.isPredefined"
|
||||
@@ -116,7 +118,7 @@
|
||||
</div>
|
||||
|
||||
<!--Rename Inquiry dialog -->
|
||||
<modal name="rename" classes="dialog" height="auto">
|
||||
<modal modal-id="rename" class="dialog">
|
||||
<div class="dialog-header">
|
||||
Rename inquiry
|
||||
<close-icon @click="$modal.hide('rename')"/>
|
||||
@@ -136,7 +138,7 @@
|
||||
</modal>
|
||||
|
||||
<!--Delete Inquiry dialog -->
|
||||
<modal name="delete" classes="dialog" height="auto">
|
||||
<modal modal-id="delete" class="dialog">
|
||||
<div class="dialog-header">
|
||||
Delete {{ deleteGroup ? 'inquiries' : 'inquiry' }}
|
||||
<close-icon @click="$modal.hide('delete')"/>
|
||||
@@ -167,6 +169,7 @@ import CheckBox from '@/components/CheckBox'
|
||||
import LoadingIndicator from '@/components/LoadingIndicator'
|
||||
import tooltipMixin from '@/tooltipMixin'
|
||||
import storedInquiries from '@/lib/storedInquiries'
|
||||
import eventBus from '@/lib/eventBus'
|
||||
|
||||
export default {
|
||||
name: 'Inquiries',
|
||||
@@ -242,7 +245,8 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
showedInquiries () {
|
||||
showedInquiries: {
|
||||
handler () {
|
||||
this.selectedInquiriesIds = new Set(this.showedInquiries
|
||||
.filter(inquiry => this.selectedInquiriesIds.has(inquiry.id))
|
||||
.map(inquiry => inquiry.id)
|
||||
@@ -252,9 +256,13 @@ export default {
|
||||
.filter(id => !this.predefinedInquiriesIds.has(id))).length
|
||||
|
||||
if (this.selectedInquiriesIds.size < this.showedInquiries.length) {
|
||||
if (this.$refs.mainCheckBox) {
|
||||
this.$refs.mainCheckBox.checked = false
|
||||
}
|
||||
this.selectAll = false
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
@@ -282,12 +290,15 @@ export default {
|
||||
this.calcNameWidth()
|
||||
this.calcMaxTableHeight()
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
this.resizeObserver.unobserve(this.$refs['my-inquiries-content'])
|
||||
this.tableResizeObserver.unobserve(this.$refs.table)
|
||||
},
|
||||
filters: {
|
||||
date (value) {
|
||||
methods: {
|
||||
emitCreateTabEvent () {
|
||||
eventBus.$emit('createNewInquiry')
|
||||
},
|
||||
createdAtFormatted (value) {
|
||||
if (!value) {
|
||||
return ''
|
||||
}
|
||||
@@ -299,9 +310,7 @@ export default {
|
||||
}
|
||||
return new Date(value).toLocaleDateString('en-GB', dateOptions) + ' ' +
|
||||
new Date(value).toLocaleTimeString('en-GB', timeOptions)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
calcNameWidth () {
|
||||
const nameWidth = this.$refs['name-td'] && this.$refs['name-td'][0]
|
||||
? this.$refs['name-td'][0].getBoundingClientRect().width
|
||||
@@ -314,10 +323,12 @@ export default {
|
||||
},
|
||||
openInquiry (index) {
|
||||
const tab = this.showedInquiries[index]
|
||||
setTimeout(() => {
|
||||
this.$store.dispatch('addTab', tab).then(id => {
|
||||
this.$store.commit('setCurrentTabId', id)
|
||||
this.$router.push('/workspace')
|
||||
})
|
||||
})
|
||||
},
|
||||
showRenameDialog (id) {
|
||||
this.errorMsg = null
|
||||
@@ -332,7 +343,7 @@ export default {
|
||||
}
|
||||
const processedInquiry = this.inquiries[this.processedInquiryIndex]
|
||||
processedInquiry.name = this.newName
|
||||
this.$set(this.inquiries, this.processedInquiryIndex, processedInquiry)
|
||||
this.inquiries[this.processedInquiryIndex] = processedInquiry
|
||||
|
||||
// update inquiries in local storage
|
||||
storedInquiries.updateStorage(this.inquiries)
|
||||
|
||||
@@ -31,6 +31,7 @@ import tooltipMixin from '@/tooltipMixin'
|
||||
|
||||
export default {
|
||||
name: 'CopyIcon',
|
||||
emits: ['click'],
|
||||
mixins: [tooltipMixin],
|
||||
methods: {
|
||||
onClick () {
|
||||
|
||||
@@ -29,6 +29,7 @@ import tooltipMixin from '@/tooltipMixin'
|
||||
|
||||
export default {
|
||||
name: 'DeleteIcon',
|
||||
emits: ['click'],
|
||||
mixins: [tooltipMixin],
|
||||
methods: {
|
||||
onClick () {
|
||||
|
||||
@@ -29,6 +29,7 @@ import tooltipMixin from '@/tooltipMixin'
|
||||
|
||||
export default {
|
||||
name: 'RenameIcon',
|
||||
emits: ['click'],
|
||||
mixins: [tooltipMixin],
|
||||
methods: {
|
||||
onClick () {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</div>
|
||||
|
||||
<!--Save Inquiry dialog -->
|
||||
<modal name="save" classes="dialog" height="auto">
|
||||
<modal modal-id="save" class="dialog">
|
||||
<div class="dialog-header">
|
||||
Save inquiry
|
||||
<close-icon @click="cancelSave"/>
|
||||
@@ -61,6 +61,7 @@ import CloseIcon from '@/components/svg/close'
|
||||
import storedInquiries from '@/lib/storedInquiries'
|
||||
import AppDiagnosticInfo from './AppDiagnosticInfo'
|
||||
import events from '@/lib/utils/events'
|
||||
import eventBus from '@/lib/eventBus'
|
||||
|
||||
export default {
|
||||
name: 'MainMenu',
|
||||
@@ -90,11 +91,11 @@ export default {
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$root.$on('createNewInquiry', this.createNewInquiry)
|
||||
this.$root.$on('saveInquiry', this.checkInquiryBeforeSave)
|
||||
eventBus.$on('createNewInquiry', this.createNewInquiry)
|
||||
eventBus.$on('saveInquiry', this.checkInquiryBeforeSave)
|
||||
document.addEventListener('keydown', this._keyListener)
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
document.removeEventListener('keydown', this._keyListener)
|
||||
},
|
||||
methods: {
|
||||
@@ -110,7 +111,7 @@ export default {
|
||||
},
|
||||
cancelSave () {
|
||||
this.$modal.hide('save')
|
||||
this.$root.$off('inquirySaved')
|
||||
eventBus.$off('inquirySaved')
|
||||
},
|
||||
checkInquiryBeforeSave () {
|
||||
this.errorMsg = null
|
||||
@@ -161,7 +162,7 @@ export default {
|
||||
this.$modal.hide('save')
|
||||
|
||||
// Signal about saving
|
||||
this.$root.$emit('inquirySaved')
|
||||
eventBus.$emit('inquirySaved')
|
||||
events.send('inquiry.save')
|
||||
},
|
||||
_keyListener (e) {
|
||||
|
||||
@@ -141,7 +141,7 @@ export default {
|
||||
}
|
||||
|
||||
.db-name:hover .chevron-icon path,
|
||||
>>> .table-name:hover .chevron-icon path {
|
||||
:deep(.table-name:hover .chevron-icon path) {
|
||||
fill: var(--color-gray-dark);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,23 +11,24 @@
|
||||
:dataSources="dataSources"
|
||||
:dataSourceOptions="dataSourceOptions"
|
||||
:plotly="plotly"
|
||||
@onUpdate="update"
|
||||
@onRender="onRender"
|
||||
:useResizeHandler="true"
|
||||
:useResizeHandler="useResizeHandler"
|
||||
:debug="true"
|
||||
:advancedTraceTypeSelector="true"
|
||||
class="chart"
|
||||
ref="plotlyEditor"
|
||||
:style="{ height: !dataSources ? 'calc(100% - 40px)' : '100%' }"
|
||||
@update="update"
|
||||
@render="onRender"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { applyPureReactInVue } from 'veaury'
|
||||
import plotly from 'plotly.js'
|
||||
import 'react-chart-editor/lib/react-chart-editor.css'
|
||||
|
||||
import PlotlyEditor from 'react-chart-editor'
|
||||
import ReactPlotlyEditor from 'react-chart-editor'
|
||||
import chartHelper from '@/lib/chartHelper'
|
||||
import dereference from 'react-chart-editor/lib/lib/dereference'
|
||||
import fIo from '@/lib/utils/fileIo'
|
||||
@@ -40,19 +41,21 @@ export default {
|
||||
'importToPngEnabled', 'importToSvgEnabled',
|
||||
'forPivot'
|
||||
],
|
||||
emits: ['update:importToSvgEnabled', 'update', 'loadingImageCompleted'],
|
||||
components: {
|
||||
PlotlyEditor
|
||||
PlotlyEditor: applyPureReactInVue(ReactPlotlyEditor)
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
plotly: plotly,
|
||||
plotly,
|
||||
state: this.initOptions || {
|
||||
data: [],
|
||||
layout: {},
|
||||
frames: []
|
||||
},
|
||||
visible: true,
|
||||
resizeObserver: null
|
||||
resizeObserver: null,
|
||||
useResizeHandler: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -83,7 +86,13 @@ export default {
|
||||
this.resizeObserver = new ResizeObserver(this.handleResize)
|
||||
this.resizeObserver.observe(this.$refs.chartContainer)
|
||||
},
|
||||
beforeDestroy () {
|
||||
activated () {
|
||||
this.useResizeHandler = true
|
||||
},
|
||||
deactivated () {
|
||||
this.useResizeHandler = false
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.resizeObserver.unobserve(this.$refs.chartContainer)
|
||||
},
|
||||
watch: {
|
||||
@@ -153,7 +162,7 @@ export default {
|
||||
min-height: 242px;
|
||||
}
|
||||
|
||||
>>> .editor_controls .sidebar__item:before {
|
||||
:deep(.editor_controls .sidebar__item:before) {
|
||||
width: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div :class="['pivot-sort-btn', direction] " @click="changeSorting">
|
||||
{{ value.includes('key') ? 'key' : 'value' }}
|
||||
{{ modelValue.includes('key') ? 'key' : 'value' }}
|
||||
<sort-icon
|
||||
class="sort-icon"
|
||||
:horizontal="direction === 'col'"
|
||||
:asc="value.includes('a_to_z')"
|
||||
:asc="modelValue.includes('a_to_z')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -14,18 +14,18 @@ import SortIcon from '@/components/svg/sort'
|
||||
|
||||
export default {
|
||||
name: 'PivotSortBtn',
|
||||
props: ['direction', 'value'],
|
||||
props: ['direction', 'modelValue'],
|
||||
components: {
|
||||
SortIcon
|
||||
},
|
||||
methods: {
|
||||
changeSorting () {
|
||||
if (this.value === 'key_a_to_z') {
|
||||
this.$emit('input', 'value_a_to_z')
|
||||
} else if (this.value === 'value_a_to_z') {
|
||||
this.$emit('input', 'value_z_to_a')
|
||||
if (this.modelValue === 'key_a_to_z') {
|
||||
this.$emit('update:modelValue', 'value_a_to_z')
|
||||
} else if (this.modelValue === 'value_a_to_z') {
|
||||
this.$emit('update:modelValue', 'value_z_to_a')
|
||||
} else {
|
||||
this.$emit('input', 'key_a_to_z')
|
||||
this.$emit('update:modelValue', 'key_a_to_z')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ export default {
|
||||
color: var(--color-text-active);
|
||||
border-color: var(--color-border-dark);
|
||||
}
|
||||
.pivot-sort-btn:hover >>> .sort-icon path {
|
||||
.pivot-sort-btn:hover deep(.sort-icon path) {
|
||||
fill: var(--color-text-active);
|
||||
}
|
||||
|
||||
|
||||
@@ -141,35 +141,35 @@ import Multiselect from 'vue-multiselect'
|
||||
import PivotSortBtn from './PivotSortBtn'
|
||||
import { renderers, aggregators, zeroValAggregators, twoValAggregators } from '../pivotHelper'
|
||||
import Chart from '@/views/Main/Workspace/Tabs/Tab/DataView/Chart'
|
||||
import Vue from 'vue'
|
||||
const ChartClass = Vue.extend(Chart)
|
||||
import { createApp } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'pivotUi',
|
||||
props: ['keyNames', 'value'],
|
||||
props: ['keyNames', 'modelValue'],
|
||||
emits: ['loadingCustomChartImageCompleted', 'update:modelValue', 'update'],
|
||||
components: {
|
||||
Multiselect,
|
||||
PivotSortBtn
|
||||
},
|
||||
data () {
|
||||
const aggregatorName = (this.value && this.value.aggregatorName) || 'Count'
|
||||
const rendererName = (this.value && this.value.rendererName) || 'Table'
|
||||
const aggregatorName = (this.modelValue && this.modelValue.aggregatorName) || 'Count'
|
||||
const rendererName = (this.modelValue && this.modelValue.rendererName) || 'Table'
|
||||
return {
|
||||
collapsed: false,
|
||||
renderer: { name: rendererName, fun: $.pivotUtilities.renderers[rendererName] },
|
||||
aggregator: { name: aggregatorName, fun: $.pivotUtilities.aggregators[aggregatorName] },
|
||||
rows: (this.value && this.value.rows) || [],
|
||||
cols: (this.value && this.value.cols) || [],
|
||||
val1: (this.value && this.value.vals && this.value.vals[0]) || '',
|
||||
val2: (this.value && this.value.vals && this.value.vals[1]) || '',
|
||||
colOrder: (this.value && this.value.colOrder) || 'key_a_to_z',
|
||||
rowOrder: (this.value && this.value.rowOrder) || 'key_a_to_z',
|
||||
rows: (this.modelValue && this.modelValue.rows) || [],
|
||||
cols: (this.modelValue && this.modelValue.cols) || [],
|
||||
val1: (this.modelValue && this.modelValue.vals && this.modelValue.vals[0]) || '',
|
||||
val2: (this.modelValue && this.modelValue.vals && this.modelValue.vals[1]) || '',
|
||||
colOrder: (this.modelValue && this.modelValue.colOrder) || 'key_a_to_z',
|
||||
rowOrder: (this.modelValue && this.modelValue.rowOrder) || 'key_a_to_z',
|
||||
customChartComponent:
|
||||
(
|
||||
this.value &&
|
||||
this.value.rendererOptions &&
|
||||
this.value.rendererOptions.customChartComponent
|
||||
) || new ChartClass()
|
||||
this.modelValue &&
|
||||
this.modelValue.rendererOptions &&
|
||||
this.modelValue.rendererOptions.customChartComponent
|
||||
) || createApp(Chart)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -224,11 +224,10 @@ export default {
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.customChartComponent.$on('update', () => { this.$emit('update') })
|
||||
this.customChartComponent.$on(
|
||||
'loadingImageCompleted',
|
||||
value => { this.$emit('loadingCustomChartImageCompleted') }
|
||||
)
|
||||
this.customChartComponent.onUpdate = () => { this.$emit('update') }
|
||||
this.customChartComponent.onLoadingImageCompleted = () => {
|
||||
this.$emit('loadingCustomChartImageCompleted')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
returnValue () {
|
||||
@@ -237,7 +236,7 @@ export default {
|
||||
vals.push(this[`val${i}`])
|
||||
}
|
||||
this.$emit('update')
|
||||
this.$emit('input', {
|
||||
this.$emit('update:modelValue', {
|
||||
rows: this.rows,
|
||||
cols: this.cols,
|
||||
colOrder: this.colOrder,
|
||||
@@ -246,7 +245,9 @@ export default {
|
||||
aggregatorName: this.aggregator.name,
|
||||
renderer: this.renderer.fun,
|
||||
rendererName: this.renderer.name,
|
||||
rendererOptions: this.renderer.name !== 'Custom chart' ? undefined : {
|
||||
rendererOptions: this.renderer.name !== 'Custom chart'
|
||||
? undefined
|
||||
: {
|
||||
customChartComponent: this.customChartComponent
|
||||
},
|
||||
vals
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createApp } from 'vue'
|
||||
import fIo from '@/lib/utils/fileIo'
|
||||
import $ from 'jquery'
|
||||
import 'pivottable'
|
||||
@@ -22,13 +23,17 @@ import PivotUi from './PivotUi'
|
||||
import pivotHelper from './pivotHelper'
|
||||
import Chart from '@/views/Main/Workspace/Tabs/Tab/DataView/Chart'
|
||||
import chartHelper from '@/lib/chartHelper'
|
||||
import Vue from 'vue'
|
||||
import events from '@/lib/utils/events'
|
||||
const ChartClass = Vue.extend(Chart)
|
||||
|
||||
export default {
|
||||
name: 'pivot',
|
||||
props: ['dataSources', 'initOptions', 'importToPngEnabled', 'importToSvgEnabled'],
|
||||
emits: [
|
||||
'loadingImageCompleted',
|
||||
'update',
|
||||
'update:importToSvgEnabled',
|
||||
'update:importToPngEnabled'
|
||||
],
|
||||
components: {
|
||||
PivotUi
|
||||
},
|
||||
@@ -60,9 +65,12 @@ export default {
|
||||
vals: this.initOptions.vals,
|
||||
rendererName: this.initOptions.rendererName,
|
||||
renderer: $.pivotUtilities.renderers[this.initOptions.rendererName],
|
||||
rendererOptions: !this.initOptions.rendererOptions ? undefined : {
|
||||
customChartComponent: new ChartClass({
|
||||
propsData: { initOptions: this.initOptions.rendererOptions.customChartOptions }
|
||||
rendererOptions: !this.initOptions.rendererOptions
|
||||
? undefined
|
||||
: {
|
||||
customChartComponent: createApp(Chart, {
|
||||
initOptions: this.initOptions
|
||||
.rendererOptions.customChartOptions
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -112,7 +120,7 @@ export default {
|
||||
this.resizeObserver = new ResizeObserver(this.handleResize)
|
||||
this.resizeObserver.observe(this.$refs.pivotOutput)
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
this.resizeObserver.unobserve(this.$refs.pivotOutput)
|
||||
},
|
||||
methods: {
|
||||
@@ -249,26 +257,26 @@ export default {
|
||||
line-height: 40px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
>>> .pvtTable {
|
||||
:deep(.pvtTable) {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
>>> table.pvtTable tbody tr td,
|
||||
>>> table.pvtTable thead tr th,
|
||||
>>> table.pvtTable tbody tr th {
|
||||
:deep(table.pvtTable tbody tr td),
|
||||
:deep(table.pvtTable thead tr th),
|
||||
:deep(table.pvtTable tbody tr th) {
|
||||
border-color: var(--color-border-light);
|
||||
}
|
||||
>>> table.pvtTable thead tr th,
|
||||
>>> table.pvtTable tbody tr th {
|
||||
:deep(table.pvtTable thead tr th),
|
||||
:deep(table.pvtTable tbody tr th) {
|
||||
background-color: var(--color-bg-dark);
|
||||
color: var(--color-text-light);
|
||||
}
|
||||
|
||||
>>> table.pvtTable tbody tr td {
|
||||
:deep(table.pvtTable tbody tr td) {
|
||||
color: var(--color-text-base);
|
||||
}
|
||||
|
||||
.pivot-output >>> textarea {
|
||||
.pivot-output :deep(textarea) {
|
||||
color: var(--color-text-base);
|
||||
min-width: 100%;
|
||||
height: 100% !important;
|
||||
@@ -277,7 +285,7 @@ export default {
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.pivot-output >>> textarea:focus-visible {
|
||||
.pivot-output :deep(textarea:focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -53,9 +53,11 @@ function customChartRenderer (data, options) {
|
||||
options.customChartComponent.dataSources = _getDataSources(data)
|
||||
options.customChartComponent.forPivot = true
|
||||
|
||||
options.customChartComponent.$mount()
|
||||
const container = document.createElement('div')
|
||||
|
||||
return $(options.customChartComponent.$el)
|
||||
options.customChartComponent.mount(container)
|
||||
|
||||
return $(container)
|
||||
}
|
||||
|
||||
$.extend(
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
:is="mode"
|
||||
:init-options="mode === initMode ? initOptions : undefined"
|
||||
:data-sources="dataSource"
|
||||
:import-to-png-enabled.sync="importToPngEnabled"
|
||||
:import-to-svg-enabled.sync="importToSvgEnabled"
|
||||
v-model:import-to-png-enabled="importToPngEnabled"
|
||||
v-model:import-to-svg-enabled="importToSvgEnabled"
|
||||
@loadingImageCompleted="loadingImage = false"
|
||||
ref="viewComponent"
|
||||
@update="$emit('update')"
|
||||
@@ -99,6 +99,7 @@ import events from '@/lib/utils/events'
|
||||
export default {
|
||||
name: 'DataView',
|
||||
props: ['dataSource', 'initOptions', 'initMode'],
|
||||
emits: ['update', 'switchTo'],
|
||||
components: {
|
||||
Chart,
|
||||
Pivot,
|
||||
@@ -233,7 +234,7 @@ export default {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
>>>.vm--container {
|
||||
:deep(.vm--container) {
|
||||
animation: show-modal 1s linear 0s 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
<template>
|
||||
<div class="record-navigator">
|
||||
<icon-button
|
||||
:disabled="value === 0"
|
||||
:disabled="modelValue === 0"
|
||||
tooltip="First row"
|
||||
tooltip-position="top-left"
|
||||
class="first"
|
||||
@click="$emit('input', 0)"
|
||||
@click="$emit('update:modelValue', 0)"
|
||||
>
|
||||
<edge-arrow-icon :disabled="false" />
|
||||
</icon-button>
|
||||
<icon-button
|
||||
:disabled="value === 0"
|
||||
:disabled="modelValue === 0"
|
||||
tooltip="Previous row"
|
||||
tooltip-position="top-left"
|
||||
class="prev"
|
||||
@click="$emit('input', value - 1)"
|
||||
@click="$emit('update:modelValue', modelValue - 1)"
|
||||
>
|
||||
<arrow-icon :disabled="false" />
|
||||
</icon-button>
|
||||
<icon-button
|
||||
:disabled="value === total - 1"
|
||||
:disabled="modelValue === total - 1"
|
||||
tooltip="Next row"
|
||||
tooltip-position="top-left"
|
||||
class="next"
|
||||
@click="$emit('input', value + 1)"
|
||||
@click="$emit('update:modelValue', modelValue + 1)"
|
||||
>
|
||||
<arrow-icon :disabled="false" />
|
||||
</icon-button>
|
||||
<icon-button
|
||||
:disabled="value === total - 1"
|
||||
:disabled="modelValue === total - 1"
|
||||
tooltip="Last row"
|
||||
tooltip-position="top-left"
|
||||
class="last"
|
||||
@click="$emit('input', total - 1)"
|
||||
@click="$emit('update:modelValue', total - 1)"
|
||||
>
|
||||
<edge-arrow-icon :disabled="false" />
|
||||
</icon-button>
|
||||
@@ -51,7 +51,7 @@ export default {
|
||||
EdgeArrowIcon
|
||||
},
|
||||
props: {
|
||||
value: Number,
|
||||
modelValue: Number,
|
||||
total: Number
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
|
||||
<script>
|
||||
import RowNavigator from './RowNavigator.vue'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
export default {
|
||||
components: { RowNavigator },
|
||||
@@ -59,6 +60,7 @@ export default {
|
||||
rowIndex: { type: Number, default: 0 },
|
||||
selectedColumnIndex: Number
|
||||
},
|
||||
emits: ['updateSelectedCell'],
|
||||
data () {
|
||||
return {
|
||||
selectedCellElement: null,
|
||||
@@ -84,7 +86,7 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
async currentRowIndex () {
|
||||
await this.$nextTick()
|
||||
await nextTick()
|
||||
if (this.selectedCellElement) {
|
||||
const previouslySelected = this.selectedCellElement
|
||||
this.selectCell(null)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { codemirror } from 'vue-codemirror'
|
||||
import Codemirror from 'codemirror-editor-vue3'
|
||||
import 'codemirror/lib/codemirror.css'
|
||||
import 'codemirror/mode/javascript/javascript.js'
|
||||
import 'codemirror/addon/fold/foldcode.js'
|
||||
@@ -54,7 +54,7 @@ import Logs from '@/components/Logs'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
codemirror,
|
||||
Codemirror,
|
||||
Logs
|
||||
},
|
||||
props: {
|
||||
@@ -192,15 +192,15 @@ export default {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
>>> .vue-codemirror {
|
||||
:deep(.vue-codemirror) {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
>>> .CodeMirror {
|
||||
:deep(.CodeMirror) {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
>>> .CodeMirror-cursor {
|
||||
:deep(.CodeMirror-cursor) {
|
||||
width: 1px;
|
||||
background: var(--color-text-base);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,11 @@
|
||||
@cancel="cancelCopy"
|
||||
/>
|
||||
|
||||
<teleport :to="resultSetTeleportTarget">
|
||||
<teleport
|
||||
defer
|
||||
:to="resultSetTeleportTarget"
|
||||
:disabled="!enableTeleport"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
v-show="result === null && !isGettingResults && !error"
|
||||
@@ -138,7 +142,6 @@ import cIo from '@/lib/utils/clipboardIo'
|
||||
import time from '@/lib/utils/time'
|
||||
import loadingDialog from '@/components/LoadingDialog'
|
||||
import events from '@/lib/utils/events'
|
||||
import Teleport from 'vue2-teleport'
|
||||
import ValueViewer from './ValueViewer'
|
||||
import Record from './Record/index.vue'
|
||||
|
||||
@@ -151,6 +154,7 @@ export default {
|
||||
error: Object,
|
||||
time: [String, Number]
|
||||
},
|
||||
emits: ['switchTo'],
|
||||
data () {
|
||||
return {
|
||||
resizeObserver: null,
|
||||
@@ -161,7 +165,8 @@ export default {
|
||||
selectedCell: null,
|
||||
viewRecord: false,
|
||||
defaultPage: 1,
|
||||
defaultSelectedCell: null
|
||||
defaultSelectedCell: null,
|
||||
enableTeleport: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -177,11 +182,13 @@ export default {
|
||||
loadingDialog,
|
||||
ValueViewer,
|
||||
Record,
|
||||
Splitpanes,
|
||||
Teleport
|
||||
Splitpanes
|
||||
},
|
||||
computed: {
|
||||
resultSetTeleportTarget () {
|
||||
if (!this.enableTeleport) {
|
||||
return undefined
|
||||
}
|
||||
const base = `#${this.viewValuePanelVisible
|
||||
? 'run-result-left-pane'
|
||||
: 'run-result-result-set'
|
||||
@@ -190,12 +197,21 @@ export default {
|
||||
return base + tabIdPostfix
|
||||
}
|
||||
},
|
||||
activated () {
|
||||
this.enableTeleport = true
|
||||
},
|
||||
deactivated () {
|
||||
this.enableTeleport = false
|
||||
},
|
||||
mounted () {
|
||||
if (this.$store.state.isWorkspaceVisible) {
|
||||
this.enableTeleport = true
|
||||
}
|
||||
this.resizeObserver = new ResizeObserver(this.handleResize)
|
||||
this.resizeObserver.observe(this.$refs.runResultPanel)
|
||||
this.calculatePageSize()
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
this.resizeObserver.unobserve(this.$refs.runResultPanel)
|
||||
},
|
||||
watch: {
|
||||
@@ -361,7 +377,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
>>>.vm--container {
|
||||
:deep(.vm--container) {
|
||||
animation: show-modal 1s linear 0s 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
:active="panel === 'sqlEditor'"
|
||||
tooltip="Switch panel to SQL editor"
|
||||
tooltip-position="top-left"
|
||||
@click.native="$emit('switchTo', 'sqlEditor')"
|
||||
@click="$emit('switchTo', 'sqlEditor')"
|
||||
>
|
||||
<sql-editor-icon />
|
||||
</icon-button>
|
||||
@@ -13,7 +13,7 @@
|
||||
:active="panel === 'table'"
|
||||
tooltip="Switch panel to result set"
|
||||
tooltip-position="top-left"
|
||||
@click.native="$emit('switchTo', 'table')"
|
||||
@click="$emit('switchTo', 'table')"
|
||||
>
|
||||
<table-icon/>
|
||||
</icon-button>
|
||||
@@ -22,7 +22,7 @@
|
||||
:active="panel === 'dataView'"
|
||||
tooltip="Switch panel to data view"
|
||||
tooltip-position="top-left"
|
||||
@click.native="$emit('switchTo', 'dataView')"
|
||||
@click="$emit('switchTo', 'dataView')"
|
||||
>
|
||||
<data-view-icon />
|
||||
</icon-button>
|
||||
@@ -42,6 +42,7 @@ import DataViewIcon from '@/components/svg/dataView'
|
||||
export default {
|
||||
name: 'SideToolBar',
|
||||
props: ['panel'],
|
||||
emits: ['switchTo'],
|
||||
components: {
|
||||
IconButton,
|
||||
SqlEditorIcon,
|
||||
|
||||
@@ -43,7 +43,7 @@ export function showHintOnDemand (editor) {
|
||||
CM.showHint(editor, getHints, hintOptions)
|
||||
}
|
||||
|
||||
export default function showHint (editor) {
|
||||
export default function showHint (value, editor) {
|
||||
// Don't show autocomplete after a space or semicolon or in string literals
|
||||
const token = editor.getTokenAt(editor.getCursor())
|
||||
const ch = token.string.slice(-1)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div class="sql-editor-panel">
|
||||
<div class="codemirror-container">
|
||||
<div class="codemirror-container original-style">
|
||||
<codemirror
|
||||
ref="cm"
|
||||
v-model="query"
|
||||
v-model:value="query"
|
||||
:options="cmOptions"
|
||||
@changes="onChange"
|
||||
:original-style="true"
|
||||
@change="onChange"
|
||||
/>
|
||||
</div>
|
||||
<side-tool-bar panel="sqlEditor" @switchTo="$emit('switchTo', $event)">
|
||||
@@ -25,7 +26,7 @@
|
||||
<script>
|
||||
import showHint, { showHintOnDemand } from './hint'
|
||||
import time from '@/lib/utils/time'
|
||||
import { codemirror } from 'vue-codemirror'
|
||||
import Codemirror from 'codemirror-editor-vue3'
|
||||
import 'codemirror/lib/codemirror.css'
|
||||
import 'codemirror/mode/sql/sql.js'
|
||||
import 'codemirror/theme/neo.css'
|
||||
@@ -37,16 +38,17 @@ import RunIcon from '@/components/svg/run'
|
||||
|
||||
export default {
|
||||
name: 'SqlEditor',
|
||||
props: ['value', 'isGettingResults'],
|
||||
props: ['modelValue', 'isGettingResults'],
|
||||
emits: ['update:modelValue', 'run', 'switchTo'],
|
||||
components: {
|
||||
codemirror,
|
||||
Codemirror,
|
||||
SideToolBar,
|
||||
IconButton,
|
||||
RunIcon
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
query: this.value,
|
||||
query: this.modelValue,
|
||||
cmOptions: {
|
||||
tabSize: 4,
|
||||
mode: 'text/x-mysql',
|
||||
@@ -54,6 +56,7 @@ export default {
|
||||
lineNumbers: true,
|
||||
line: true,
|
||||
autoRefresh: true,
|
||||
styleActiveLine: false,
|
||||
extraKeys: { 'Ctrl-Space': showHintOnDemand }
|
||||
}
|
||||
}
|
||||
@@ -65,13 +68,13 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
query () {
|
||||
this.$emit('input', this.query)
|
||||
this.$emit('update:modelValue', this.query)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange: time.debounce(showHint, 400),
|
||||
focus () {
|
||||
this.$refs.cm.codemirror.focus()
|
||||
this.$refs.cm.cminstance.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,15 +95,15 @@ export default {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
>>> .vue-codemirror {
|
||||
:deep(.vue-codemirror) {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
>>> .CodeMirror {
|
||||
:deep(.CodeMirror) {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
>>> .CodeMirror-cursor {
|
||||
:deep(.CodeMirror-cursor) {
|
||||
width: 1px;
|
||||
background: var(--color-text-base);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
|
||||
<div :id="'hidden-'+ tab.id" class="hidden-part" />
|
||||
|
||||
<teleport :to="`#${tab.layout.sqlEditor}-${tab.id}`">
|
||||
<teleport
|
||||
defer
|
||||
:to="enableTeleport ? `#${tab.layout.sqlEditor}-${tab.id}`: undefined"
|
||||
:disabled="!enableTeleport"
|
||||
>
|
||||
<sql-editor
|
||||
ref="sqlEditor"
|
||||
v-model="tab.query"
|
||||
@@ -27,7 +31,11 @@
|
||||
/>
|
||||
</teleport>
|
||||
|
||||
<teleport :to="`#${tab.layout.table}-${tab.id}`">
|
||||
<teleport
|
||||
defer
|
||||
:to="enableTeleport ? `#${tab.layout.table}-${tab.id}`: undefined"
|
||||
:disabled="!enableTeleport"
|
||||
>
|
||||
<run-result
|
||||
:tab="tab"
|
||||
:result="tab.result"
|
||||
@@ -38,7 +46,11 @@
|
||||
/>
|
||||
</teleport>
|
||||
|
||||
<teleport :to="`#${tab.layout.dataView}-${tab.id}`">
|
||||
<teleport
|
||||
defer
|
||||
:to="enableTeleport ? `#${tab.layout.dataView}-${tab.id}` : undefined"
|
||||
:disabled="!enableTeleport"
|
||||
>
|
||||
<data-view
|
||||
:data-source="(tab.result && tab.result.values) || null"
|
||||
:init-options="tab.viewOptions"
|
||||
@@ -56,8 +68,8 @@ import Splitpanes from '@/components/Splitpanes'
|
||||
import SqlEditor from './SqlEditor'
|
||||
import DataView from './DataView'
|
||||
import RunResult from './RunResult'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
import Teleport from 'vue2-teleport'
|
||||
import events from '@/lib/utils/events'
|
||||
|
||||
export default {
|
||||
@@ -65,18 +77,19 @@ export default {
|
||||
props: {
|
||||
tab: Object
|
||||
},
|
||||
emits: [],
|
||||
components: {
|
||||
SqlEditor,
|
||||
DataView,
|
||||
RunResult,
|
||||
Splitpanes,
|
||||
Teleport
|
||||
Splitpanes
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
topPaneSize: this.tab.maximize
|
||||
? this.tab.layout[this.tab.maximize] === 'above' ? 100 : 0
|
||||
: 50
|
||||
: 50,
|
||||
enableTeleport: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -89,7 +102,7 @@ export default {
|
||||
immediate: true,
|
||||
async handler () {
|
||||
if (this.isActive) {
|
||||
await this.$nextTick()
|
||||
await nextTick()
|
||||
this.$refs.sqlEditor.focus()
|
||||
}
|
||||
}
|
||||
@@ -101,7 +114,16 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
activated () {
|
||||
this.enableTeleport = true
|
||||
},
|
||||
deactivated () {
|
||||
this.enableTeleport = false
|
||||
},
|
||||
mounted () {
|
||||
if (this.$store.state.isWorkspaceVisible) {
|
||||
this.enableTeleport = true
|
||||
}
|
||||
this.tab.dataView = this.$refs.dataView
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
:tab="tab"
|
||||
/>
|
||||
<div v-show="tabs.length === 0" id="start-guide">
|
||||
<span class="link" @click="$root.$emit('createNewInquiry')">Create</span>
|
||||
<span class="link" @click="emitCreateTabEvent">Create</span>
|
||||
new inquiry from scratch or open one from
|
||||
<router-link class="link" to="/inquiries">Inquiries</router-link>
|
||||
</div>
|
||||
|
||||
<!--Close tab warning dialog -->
|
||||
<modal name="close-warn" classes="dialog" height="auto">
|
||||
<modal modal-id="close-warn" class="dialog">
|
||||
<div class="dialog-header">
|
||||
Close tab {{
|
||||
closingTab !== null
|
||||
@@ -59,8 +59,10 @@
|
||||
<script>
|
||||
import Tab from './Tab'
|
||||
import CloseIcon from '@/components/svg/close'
|
||||
import eventBus from '@/lib/eventBus'
|
||||
|
||||
export default {
|
||||
emits: [],
|
||||
components: {
|
||||
Tab,
|
||||
CloseIcon
|
||||
@@ -82,6 +84,9 @@ export default {
|
||||
window.addEventListener('beforeunload', this.leavingSqliteviz)
|
||||
},
|
||||
methods: {
|
||||
emitCreateTabEvent () {
|
||||
eventBus.$emit('createNewInquiry')
|
||||
},
|
||||
leavingSqliteviz (event) {
|
||||
if (this.tabs.some(tab => !tab.isSaved)) {
|
||||
event.preventDefault()
|
||||
@@ -104,14 +109,14 @@ export default {
|
||||
this.$store.commit('deleteTab', tab)
|
||||
},
|
||||
saveAndClose (tab) {
|
||||
this.$root.$on('inquirySaved', () => {
|
||||
eventBus.$on('inquirySaved', () => {
|
||||
this.closeTab(tab)
|
||||
this.$root.$off('inquirySaved')
|
||||
eventBus.$off('inquirySaved')
|
||||
})
|
||||
this.selectTab(tab.id)
|
||||
this.$modal.hide('close-warn')
|
||||
this.$nextTick(() => {
|
||||
this.$root.$emit('saveInquiry')
|
||||
eventBus.$emit('saveInquiry')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,12 @@ export default {
|
||||
|
||||
events.send('inquiry.create', null, { auto: true })
|
||||
}
|
||||
},
|
||||
activated () {
|
||||
this.$store.commit('setIsWorkspaceVisible', true)
|
||||
},
|
||||
deactivated () {
|
||||
this.$store.commit('setIsWorkspaceVisible', false)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<main-menu />
|
||||
<router-view id="main-view" v-slot="{ Component }">
|
||||
<keep-alive include="Workspace,Inquiries">
|
||||
<router-view id="main-view" />
|
||||
<component :is="Component"/>
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -39,14 +39,14 @@ export default {
|
||||
margin-top: 42px;
|
||||
}
|
||||
|
||||
>>>.drop-area {
|
||||
:deep(.drop-area) {
|
||||
width: 706px;
|
||||
height: 482px;
|
||||
padding: 0 150px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
>>>.drop-area .text {
|
||||
:deep(.drop-area .text) {
|
||||
position: absolute;
|
||||
bottom: 42px;
|
||||
max-width: 300px;
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('tab.js', () => {
|
||||
error: null,
|
||||
time: 0,
|
||||
isSaved: false,
|
||||
state: state
|
||||
state
|
||||
})
|
||||
expect(newTab.layout).to.include({
|
||||
sqlEditor: 'above',
|
||||
@@ -59,7 +59,7 @@ describe('tab.js', () => {
|
||||
error: null,
|
||||
time: 0,
|
||||
isSaved: true,
|
||||
state: state
|
||||
state
|
||||
})
|
||||
expect(newTab.layout).to.include({
|
||||
sqlEditor: 'above',
|
||||
|
||||
@@ -12,7 +12,7 @@ describe('actions', () => {
|
||||
|
||||
let id = await addTab({ state })
|
||||
expect(state.tabs[0]).to.include({
|
||||
id: id,
|
||||
id,
|
||||
name: null,
|
||||
tempName: 'Untitled',
|
||||
viewType: 'chart',
|
||||
@@ -23,7 +23,7 @@ describe('actions', () => {
|
||||
|
||||
id = await addTab({ state })
|
||||
expect(state.tabs[1]).to.include({
|
||||
id: id,
|
||||
id,
|
||||
name: null,
|
||||
tempName: 'Untitled 1',
|
||||
viewType: 'chart',
|
||||
|
||||
@@ -11,7 +11,7 @@ describe('MainMenu.vue', () => {
|
||||
afterEach(() => {
|
||||
sinon.restore()
|
||||
|
||||
// We need explicitly destroy the component, so that beforeDestroy hook was called
|
||||
// We need explicitly destroy the component, so that beforeUnmount hook was called
|
||||
// It's important because in this hook MainMenu component removes keydown event listener.
|
||||
wrapper.destroy()
|
||||
})
|
||||
@@ -497,7 +497,7 @@ describe('MainMenu.vue', () => {
|
||||
|
||||
// check that the tab was updated
|
||||
expect(mutations.updateTab.calledOnceWith(state, sinon.match({
|
||||
tab: tab,
|
||||
tab,
|
||||
newValues: {
|
||||
name: 'foo',
|
||||
id: 1,
|
||||
|
||||
@@ -1,36 +1,45 @@
|
||||
const { defineConfig } = require('@vue/cli-service')
|
||||
const CopyPlugin = require('copy-webpack-plugin')
|
||||
const WorkboxPlugin = require('workbox-webpack-plugin')
|
||||
|
||||
module.exports = {
|
||||
module.exports = defineConfig({
|
||||
transpileDependencies: true,
|
||||
publicPath: '',
|
||||
// Workaround for https://github.com/vuejs/vue-cli/issues/5399 as described
|
||||
// in https://stackoverflow.com/a/63185174
|
||||
lintOnSave: process.env.NODE_ENV === 'development',
|
||||
configureWebpack: {
|
||||
plugins: [
|
||||
new CopyPlugin([
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
// 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: 'LICENSE', to: './' }
|
||||
]),
|
||||
]
|
||||
}),
|
||||
new WorkboxPlugin.GenerateSW({
|
||||
exclude: [/\.map$/, 'LICENSE', 'inquiries.json'],
|
||||
clientsClaim: true,
|
||||
skipWaiting: false,
|
||||
maximumFileSizeToCacheInBytes: 40000000
|
||||
})
|
||||
]
|
||||
],
|
||||
resolve: {
|
||||
fallback: {
|
||||
asset: require.resolve('assert'),
|
||||
stream: require.resolve('stream-browserify')
|
||||
}
|
||||
}
|
||||
},
|
||||
chainWebpack: config => {
|
||||
const svgRule = config.module.rule('svg')
|
||||
svgRule.uses.clear()
|
||||
svgRule
|
||||
.use('url-loader')
|
||||
.loader('url-loader')
|
||||
.options({
|
||||
limit: 10000
|
||||
config.module
|
||||
.rule('images')
|
||||
.set('parser', {
|
||||
dataUrlCondition: {
|
||||
maxSize: 10000
|
||||
}
|
||||
})
|
||||
|
||||
config.module
|
||||
@@ -49,4 +58,4 @@ module.exports = {
|
||||
return args
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user