mirror of
https://github.com/lana-k/sqliteviz.git
synced 2025-12-07 10:38:54 +08:00
add predefined queries
This commit is contained in:
@@ -35,11 +35,6 @@ export default {
|
||||
checked: this.init
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
checked () {
|
||||
this.$emit('change', this.checked)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick () {
|
||||
this.checked = !this.checked
|
||||
|
||||
@@ -8,21 +8,70 @@
|
||||
<button
|
||||
v-if="$store.state.tabs.length > 0"
|
||||
class="primary"
|
||||
:disabled="$store.state.currentTab && !$store.state.currentTab.isUnsaved"
|
||||
@click="saveQuery"
|
||||
:disabled="currentQuery && !currentQuery.isUnsaved"
|
||||
@click="checkQueryBeforeSave"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<button class="primary" @click="createNewQuery">Create</button>
|
||||
</div>
|
||||
|
||||
<!--Save Query dialog -->
|
||||
<modal name="save" classes="dialog" height="auto">
|
||||
<div class="dialog-header">
|
||||
Save query
|
||||
<close-icon @click="$modal.hide('save')"/>
|
||||
</div>
|
||||
<div class="dialog-body">
|
||||
<div v-show="isPredefined" id="save-note">
|
||||
<img :src="require('@/assets/images/info.svg')">
|
||||
Note: Predefined queries can't be edited.
|
||||
That's why your modifications will be saved as a new query. Enter the name for it.
|
||||
</div>
|
||||
<text-field
|
||||
label="Query name"
|
||||
:error-msg="errorMsg"
|
||||
v-model="name"
|
||||
width="100%"
|
||||
/>
|
||||
</div>
|
||||
<div class="dialog-buttons-container">
|
||||
<button class="secondary" @click="$modal.hide('save')">Cancel</button>
|
||||
<button class="primary" @click="saveQuery">Save</button>
|
||||
</div>
|
||||
</modal>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { nanoid } from 'nanoid'
|
||||
import TextField from '@/components/TextField'
|
||||
import CloseIcon from '@/components/svg/close'
|
||||
|
||||
export default {
|
||||
name: 'MainMenu',
|
||||
components: {
|
||||
TextField,
|
||||
CloseIcon
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
name: '',
|
||||
errorMsg: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentQuery () {
|
||||
return this.$store.state.currentTab
|
||||
},
|
||||
isPredefined () {
|
||||
if (this.currentQuery) {
|
||||
return this.currentQuery.isPredefined
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.$root.$on('createNewQuery', this.createNewQuery)
|
||||
},
|
||||
@@ -38,38 +87,69 @@ export default {
|
||||
}
|
||||
this.$store.commit('addTab', tab)
|
||||
this.$store.commit('setCurrentTabId', tab.id)
|
||||
this.$store.commit('updateUntitledLastIndex')
|
||||
},
|
||||
checkQueryBeforeSave () {
|
||||
this.errorMsg = null
|
||||
const isFromScratch = !this.currentQuery.initName
|
||||
|
||||
if (isFromScratch || this.isPredefined) {
|
||||
this.$modal.show('save')
|
||||
} else {
|
||||
this.saveQuery()
|
||||
}
|
||||
},
|
||||
saveQuery () {
|
||||
const currentQuery = this.$store.state.currentTab
|
||||
const isFromScratch = !this.$store.state.currentTab.initName
|
||||
const isFromScratch = !this.currentQuery.initName
|
||||
if ((isFromScratch || this.isPredefined) && !this.name) {
|
||||
this.errorMsg = 'Query name can\'t be empty'
|
||||
return
|
||||
}
|
||||
const dataSet = this.currentQuery.result
|
||||
const tabView = this.currentQuery.view
|
||||
// Prepare query
|
||||
const value = {
|
||||
id: currentQuery.id,
|
||||
query: currentQuery.query,
|
||||
chart: currentQuery.getChartSatateForSave()
|
||||
}
|
||||
|
||||
if (isFromScratch) {
|
||||
value.name = prompt('query name')
|
||||
// TODO: create dialog
|
||||
this.$store.commit('updateTabName', { index: currentQuery.tabIndex, newName: value.name })
|
||||
value.createdAt = new Date()
|
||||
} else {
|
||||
value.name = currentQuery.initName
|
||||
id: this.isPredefined ? nanoid() : this.currentQuery.id,
|
||||
query: this.currentQuery.query,
|
||||
chart: this.currentQuery.getChartSatateForSave(),
|
||||
name: (!this.isPredefined && this.currentQuery.initName) || this.name,
|
||||
createdAt: new Date()
|
||||
}
|
||||
|
||||
// Save query
|
||||
let myQueries = JSON.parse(localStorage.getItem('myQueries'))
|
||||
if (!myQueries) {
|
||||
myQueries = [value]
|
||||
} else if (isFromScratch) {
|
||||
} else if (isFromScratch || this.isPredefined) {
|
||||
myQueries.push(value)
|
||||
} else {
|
||||
const queryIndex = myQueries.findIndex(query => query.id === currentQuery.id)
|
||||
const queryIndex = myQueries.findIndex(query => query.id === this.currentQuery.id)
|
||||
value.createdAt = myQueries[queryIndex].createdAt
|
||||
myQueries[queryIndex] = value
|
||||
}
|
||||
localStorage.setItem('myQueries', JSON.stringify(myQueries))
|
||||
currentQuery.isUnsaved = false
|
||||
|
||||
// Update tab
|
||||
this.$store.commit('updateTab', {
|
||||
index: this.currentQuery.tabIndex,
|
||||
name: value.name,
|
||||
id: value.id,
|
||||
query: value.query,
|
||||
chart: value.chart,
|
||||
isUnsaved: false
|
||||
})
|
||||
|
||||
// Restore data:
|
||||
// e.g. if we save predefined query the tab will be created again
|
||||
// (because of new id) and
|
||||
// it will be without sql result and has default view - table.
|
||||
// That's why we need to restore data and view
|
||||
this.$nextTick(() => {
|
||||
this.currentQuery.result = dataSet
|
||||
this.currentQuery.view = tabView
|
||||
})
|
||||
|
||||
// Hide dialog
|
||||
this.$modal.hide('save')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +169,7 @@ nav {
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
padding: 0 52px;
|
||||
z-index: 999;
|
||||
}
|
||||
a {
|
||||
font-size: 18px;
|
||||
@@ -103,4 +184,13 @@ a.router-link-active {
|
||||
button {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
#save-note {
|
||||
margin-bottom: 24px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
#save-note img {
|
||||
margin: -3px 6px 0 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<table ref="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(th,index) in data.columns" :key="index" ref="th">
|
||||
<th v-for="(th,index) in dataSet.columns" :key="index" ref="th">
|
||||
<div class="cell-data" :style="cellStyle">{{ th }}</div>
|
||||
</th>
|
||||
</tr>
|
||||
@@ -39,7 +39,7 @@
|
||||
</div>
|
||||
<div class="table-footer">
|
||||
<div class="table-footer-count">
|
||||
{{ data.values.length}} {{data.values.length === 1 ? 'row' : 'rows'}} retrieved
|
||||
{{ dataSet.values.length}} {{dataSet.values.length === 1 ? 'row' : 'rows'}} retrieved
|
||||
</div>
|
||||
<pager v-show="pageCount > 1" :page-count="pageCount" v-model="currentPage" />
|
||||
</div>
|
||||
@@ -52,17 +52,18 @@ import Pager from '@/components/Pager'
|
||||
export default {
|
||||
name: 'SqlTable',
|
||||
components: { Pager },
|
||||
props: ['data', 'height'],
|
||||
props: ['dataSet', 'height'],
|
||||
data () {
|
||||
return {
|
||||
header: null,
|
||||
tableWidth: null,
|
||||
currentPage: 1
|
||||
currentPage: 1,
|
||||
resizeObserver: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
cellStyle () {
|
||||
const eq = this.tableWidth / this.data.columns.length
|
||||
const eq = this.tableWidth / this.dataSet.columns.length
|
||||
|
||||
return { maxWidth: `${Math.max(eq, 100)}px` }
|
||||
},
|
||||
@@ -70,11 +71,11 @@ export default {
|
||||
return Math.max(Math.floor(this.height / 40), 20)
|
||||
},
|
||||
pageCount () {
|
||||
return Math.ceil(this.data.values.length / this.pageSize)
|
||||
return Math.ceil(this.dataSet.values.length / this.pageSize)
|
||||
},
|
||||
currentPageData () {
|
||||
const start = (this.currentPage - 1) * this.pageSize
|
||||
return this.data.values.slice(start, start + this.pageSize)
|
||||
return this.dataSet.values.slice(start, start + this.pageSize)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -94,12 +95,16 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
new ResizeObserver(this.calculateHeadersWidth).observe(this.$refs.table)
|
||||
this.resizeObserver = new ResizeObserver(this.calculateHeadersWidth)
|
||||
this.resizeObserver.observe(this.$refs.table)
|
||||
this.calculateHeadersWidth()
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.resizeObserver.unobserve(this.$refs.table)
|
||||
},
|
||||
watch: {
|
||||
currentPageData: 'calculateHeadersWidth',
|
||||
data () {
|
||||
dataSet () {
|
||||
this.currentPage = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<div v-show="error" class="table-preview error">
|
||||
{{ error }}
|
||||
</div>
|
||||
<sql-table v-if="result" :data="result" :height="tableViewHeight" />
|
||||
<sql-table v-if="result" :data-set="result" :height="tableViewHeight" />
|
||||
</div>
|
||||
<chart
|
||||
:visible="view === 'chart'"
|
||||
@@ -59,8 +59,8 @@ import ViewSwitcher from '@/components/ViewSwitcher'
|
||||
import Chart from '@/components/Chart'
|
||||
|
||||
export default {
|
||||
name: 'TabContent',
|
||||
props: ['id', 'initName', 'initQuery', 'initChart', 'tabIndex'],
|
||||
name: 'Tab',
|
||||
props: ['id', 'initName', 'initQuery', 'initChart', 'tabIndex', 'isPredefined'],
|
||||
components: {
|
||||
SqlEditor,
|
||||
SqlTable,
|
||||
@@ -76,7 +76,8 @@ export default {
|
||||
tableViewHeight: 0,
|
||||
isUnsaved: !this.initName,
|
||||
isGettingResults: false,
|
||||
error: null
|
||||
error: null,
|
||||
resizeObserver: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -88,9 +89,13 @@ export default {
|
||||
this.$store.commit('setCurrentTab', this)
|
||||
},
|
||||
mounted () {
|
||||
new ResizeObserver(this.handleResize).observe(this.$refs.bottomPane)
|
||||
this.resizeObserver = new ResizeObserver(this.handleResize)
|
||||
this.resizeObserver.observe(this.$refs.bottomPane)
|
||||
this.calculateTableHeight()
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.resizeObserver.unobserve(this.$refs.bottomPane)
|
||||
},
|
||||
watch: {
|
||||
isActive () {
|
||||
if (this.isActive) {
|
||||
@@ -3,7 +3,7 @@
|
||||
<div id="tabs__header" v-if="tabs.length > 0">
|
||||
<div
|
||||
v-for="(tab, index) in tabs"
|
||||
:key="tab.id"
|
||||
:key="index"
|
||||
@click="selectTab(tab.id)"
|
||||
:class="[{'tab__selected': (tab.id === selectedIndex)}, 'tab']"
|
||||
>
|
||||
@@ -29,13 +29,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<tab-content
|
||||
<tab
|
||||
v-for="(tab, index) in tabs"
|
||||
:key="tab.id"
|
||||
:id="tab.id"
|
||||
:init-name="tab.name"
|
||||
:init-query="tab.query"
|
||||
:init-chart="tab.chart"
|
||||
:is-predefined="tab.isPredefined"
|
||||
:tab-index="index"
|
||||
/>
|
||||
<div v-if="tabs.length === 0" id="start-guide">
|
||||
@@ -47,11 +48,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TabContent from '@/components/TabContent'
|
||||
import Tab from '@/components/Tab'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TabContent
|
||||
Tab
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -153,5 +154,6 @@ export default {
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,7 +13,7 @@ export default {
|
||||
<style scoped>
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
margin: 0 0 0 12px;
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
.icon:hover path {
|
||||
|
||||
@@ -13,7 +13,7 @@ export default {
|
||||
<style scoped>
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
margin: 0 12px 0 6px;
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
.icon:hover path {
|
||||
|
||||
Reference in New Issue
Block a user