1
0
mirror of https://github.com/lana-k/sqliteviz.git synced 2025-12-06 18:18:53 +08:00

refactoring manipulations with My queries

This commit is contained in:
lana-k
2021-01-05 23:09:47 +01:00
parent 9035cae19f
commit 8d083a93c4
7 changed files with 207 additions and 176 deletions

View File

@@ -54,7 +54,7 @@
<script>
import TextField from '@/components/TextField'
import CloseIcon from '@/components/svg/close'
import queryTab from '@/queryTab'
import storedQueries from '@/storedQueries'
export default {
name: 'MainMenu',
@@ -100,9 +100,9 @@ export default {
},
methods: {
createNewQuery () {
const tab = queryTab.newBlankTab()
this.$store.commit('addTab', tab)
this.$store.commit('setCurrentTabId', tab.id)
this.$store.dispatch('addTab').then(id => {
this.$store.commit('setCurrentTabId', id)
})
},
cancelSave () {
this.$modal.hide('save')
@@ -112,14 +112,14 @@ export default {
this.errorMsg = null
this.name = ''
if (queryTab.isTabNeedName(this.currentQuery)) {
if (storedQueries.isTabNeedName(this.currentQuery)) {
this.$modal.show('save')
} else {
this.saveQuery()
}
},
saveQuery () {
const isNeedName = queryTab.isTabNeedName(this.currentQuery)
const isNeedName = storedQueries.isTabNeedName(this.currentQuery)
if (isNeedName && !this.name) {
this.errorMsg = 'Query name can\'t be empty'
return
@@ -128,7 +128,7 @@ export default {
const tabView = this.currentQuery.view
// Save query
const value = queryTab.save(this.currentQuery, this.name)
const value = storedQueries.save(this.currentQuery, this.name)
// Update tab in store
this.$store.commit('updateTab', {

View File

@@ -13,6 +13,7 @@ import 'codemirror/theme/neo.css'
import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/sql-hint.js'
import 'codemirror/addon/display/autorefresh.js'
import { debounce } from 'debounce'
const sqlHint = CM.hint.sql
@@ -42,7 +43,9 @@ export default {
mode: 'text/x-mysql',
theme: 'neo',
lineNumbers: true,
line: true
line: true,
autofocus: true,
autoRefresh: true
}
}
},

View File

@@ -1,58 +0,0 @@
import { nanoid } from 'nanoid'
import store from '@/store'
export default {
newBlankTab () {
return {
id: nanoid(),
name: null,
tempName: store.state.untitledLastIndex
? `Untitled ${store.state.untitledLastIndex}`
: 'Untitled',
isUnsaved: true
}
},
isTabNeedName (queryTab) {
const isFromScratch = !queryTab.initName
return isFromScratch || queryTab.isPredefined
},
getDataToSave (queryTab, newName) {
return {
id: queryTab.isPredefined ? nanoid() : queryTab.id,
query: queryTab.query,
chart: queryTab.getChartSatateForSave(),
name: newName || queryTab.initName
}
},
save (queryTab, newName) {
const value = this.getDataToSave(queryTab, newName)
const isNeedName = this.isTabNeedName(queryTab)
// Get queries from local storage
let myQueries = JSON.parse(localStorage.getItem('myQueries'))
// Set createdAt
if (isNeedName) {
value.createdAt = new Date()
} else {
var queryIndex = myQueries.findIndex(oldQuery => oldQuery.id === queryTab.id)
value.createdAt = myQueries[queryIndex].createdAt
}
// Insert in queries list
if (!myQueries) {
myQueries = [value]
} else if (isNeedName) {
myQueries.push(value)
} else {
myQueries[queryIndex] = value
}
// Save to local storage
localStorage.setItem('myQueries', JSON.stringify(myQueries))
return value
}
}

View File

@@ -1,5 +1,6 @@
import Vue from 'vue'
import Vuex from 'vuex'
import { nanoid } from 'nanoid'
Vue.use(Vuex)
@@ -19,15 +20,7 @@ export const mutations = {
state.dbName = dbName
state.schema = schema
},
addTab (state, tab) {
// add new tab only if was not already opened
if (!state.tabs.some(openedTab => openedTab.id === tab.id)) {
state.tabs.push(tab)
if (!tab.name) {
state.untitledLastIndex += 1
}
}
},
updateTab (state, { index, name, id, query, chart, isUnsaved }) {
const tab = state.tabs[index]
const oldId = tab.id
@@ -78,7 +71,34 @@ export const mutations = {
}
}
export const actions = {
async addTab ({ state }, tab) {
// If no tab then create a new blank one...
if (!tab) {
tab = {
id: nanoid(),
name: null,
tempName: state.untitledLastIndex
? `Untitled ${state.untitledLastIndex}`
: 'Untitled',
isUnsaved: true
}
}
// add new tab only if was not already opened
if (!state.tabs.some(openedTab => openedTab.id === tab.id)) {
state.tabs.push(tab)
if (!tab.name) {
state.untitledLastIndex += 1
}
}
return tab.id
}
}
export default new Vuex.Store({
state,
mutations
mutations,
actions
})

83
src/storedQueries.js Normal file
View File

@@ -0,0 +1,83 @@
import { nanoid } from 'nanoid'
export default {
getStoredQueries () {
return JSON.parse(localStorage.getItem('myQueries')) || []
},
duplicateQuery (baseQuery) {
const newQuery = JSON.parse(JSON.stringify(baseQuery))
newQuery.name = newQuery.name + ' Copy'
newQuery.id = nanoid()
newQuery.createdAt = new Date()
delete newQuery.isPredefined
return newQuery
},
isTabNeedName (queryTab) {
const isFromScratch = !queryTab.initName
return isFromScratch || queryTab.isPredefined
},
save (queryTab, newName) {
const value = {
id: queryTab.isPredefined ? nanoid() : queryTab.id,
query: queryTab.query,
chart: queryTab.getChartSatateForSave(),
name: newName || queryTab.initName
}
const isNeedName = this.isTabNeedName(queryTab)
// Get queries from local storage
let myQueries = this.getStoredQueries()
// Set createdAt
if (isNeedName) {
value.createdAt = new Date()
} else {
var queryIndex = myQueries.findIndex(oldQuery => oldQuery.id === queryTab.id)
value.createdAt = myQueries[queryIndex].createdAt
}
// Insert in queries list
if (!myQueries) {
myQueries = [value]
} else if (isNeedName) {
myQueries.push(value)
} else {
myQueries[queryIndex] = value
}
// Save to local storage
this.updateStorage(myQueries)
return value
},
updateStorage (value) {
localStorage.setItem('myQueries', JSON.stringify(value))
},
export (data) {
// Create downloader
const downloader = document.createElement('a')
downloader.style.display = 'none'
document.body.appendChild(downloader)
// Prepare data
const name = data.name || 'My sqlitevis queries'
const json = JSON.stringify(data, null, 4)
const blob = new Blob([json], { type: 'octet/stream' })
const url = window.URL.createObjectURL(blob)
downloader.href = url
downloader.download = `${name}.json`
// Trigger click
downloader.click()
// Clear
window.URL.revokeObjectURL(url)
downloader.remove()
}
}

View File

@@ -153,7 +153,6 @@
<button class="primary" @click="deleteQuery">Delete</button>
</div>
</modal>
<a ref="downloader" />
</div>
</template>
@@ -167,6 +166,7 @@ import TextField from '@/components/TextField'
import CheckBox from '@/components/CheckBox'
import tooltipMixin from '@/mixins/tooltips'
import { nanoid } from 'nanoid'
import storedQueries from '@/storedQueries'
export default {
name: 'MyQueries',
@@ -223,7 +223,7 @@ export default {
}
},
created () {
this.queries = JSON.parse(localStorage.getItem('myQueries')) || []
this.queries = storedQueries.getStoredQueries()
},
mounted () {
this.resizeObserver = new ResizeObserver(this.calcMaxTableHeight)
@@ -271,9 +271,10 @@ export default {
openQuery (index) {
const tab = JSON.parse(JSON.stringify(this.showedQueries[index]))
tab.isUnsaved = false
this.$store.commit('addTab', tab)
this.$store.commit('setCurrentTabId', tab.id)
this.$router.push('/editor')
this.$store.dispatch('addTab', tab).then(id => {
this.$store.commit('setCurrentTabId', id)
this.$router.push('/editor')
})
},
showRenameDialog (id) {
this.errorMsg = null
@@ -291,7 +292,7 @@ export default {
this.$set(this.queries, this.currentQueryIndex, currentQuery)
// update queries in local storage
this.saveQueriesInLocalStorage()
storedQueries.updateStorage(this.queries)
// update tab, if renamed query is opened
const tabIndex = this.findTabIndex(currentQuery.id)
@@ -306,17 +307,13 @@ export default {
this.$modal.hide('rename')
},
duplicateQuery (index) {
const newQuery = JSON.parse(JSON.stringify(this.showedQueries[index]))
newQuery.name = newQuery.name + ' Copy'
newQuery.id = nanoid()
newQuery.createdAt = new Date()
delete newQuery.isPredefined
const newQuery = storedQueries.duplicateQuery(this.showedQueries[index])
if (this.selectAll) {
this.selectedQueriesIds.add(newQuery.id)
this.selectedQueriesCount = this.selectedQueriesIds.size
}
this.queries.push(newQuery)
this.saveQueriesInLocalStorage()
storedQueries.updateStorage(this.queries)
},
showDeleteDialog (id) {
this.deleteGroup = typeof id !== 'string'
@@ -349,38 +346,28 @@ export default {
this.selectedQueriesIds.clear()
}
this.selectedQueriesCount = this.selectedQueriesIds.size
this.saveQueriesInLocalStorage()
storedQueries.updateStorage(this.queries)
},
findTabIndex (id) {
return this.$store.state.tabs.findIndex(tab => tab.id === id)
},
exportQuery (index) {
let data
let name
// single operation
if (typeof index === 'number') {
data = JSON.parse(JSON.stringify(this.showedQueries[index]))
name = data.name
delete data.isPredefined
} else {
// group operation
data = this.selectAll
? JSON.parse(JSON.stringify(this.allQueries))
: this.allQueries.filter(query => this.selectedQueriesIds.has(query.id))
name = 'My sqliteviz queries'
data.forEach(query => delete query.isPredefined)
}
// export data to file
const downloader = this.$refs.downloader
const json = JSON.stringify(data, null, 4)
const blob = new Blob([json], { type: 'octet/stream' })
const url = window.URL.createObjectURL(blob)
downloader.href = url
downloader.download = `${name}.json`
downloader.click()
window.URL.revokeObjectURL(url)
storedQueries.export(data)
},
importQueries () {
const file = this.$refs.importFile.files[0]
@@ -407,14 +394,11 @@ export default {
}
this.queries = this.queries.concat(importedQueries)
this.saveQueriesInLocalStorage()
storedQueries.updateStorage(this.queries)
this.$refs.importFile.value = null
}
reader.readAsText(file)
},
saveQueriesInLocalStorage () {
localStorage.setItem('myQueries', JSON.stringify(this.queries))
},
toggleSelectAll (checked) {
this.selectAll = checked
this.$refs.rowCheckBox.forEach(item => { item.checked = checked })
@@ -556,7 +540,7 @@ tbody tr:hover .icons-container {
.dialog input {
width: 100%;
}
a, #import-file {
#import-file {
display: none;
}
button.toolbar {

View File

@@ -1,8 +1,7 @@
import { expect } from 'chai'
import { mutations } from '@/store'
import { mutations, actions } from '@/store'
const {
saveSchema,
addTab,
updateTab,
deleteTab,
setCurrentTabId,
@@ -10,6 +9,8 @@ const {
updatePredefinedQueries
} = mutations
const { addTab } = actions
describe('mutations', () => {
it('saveSchema', () => {
// mock state
@@ -28,75 +29,6 @@ describe('mutations', () => {
expect(state.schema).to.eql(schema)
})
it('addTab (new)', () => {
// mock state
const state = {
tabs: [],
untitledLastIndex: 0
}
const tab = {
id: 1,
name: null,
tempName: 'Untitled',
query: 'SELECT * from foo',
chart: {},
isUnsaved: true
}
addTab(state, tab)
expect(state.tabs[0]).to.eql(tab)
expect(state.untitledLastIndex).to.equal(1)
})
it('addTab (saved)', () => {
// mock state
const state = {
tabs: [],
untitledLastIndex: 0
}
const tab = {
id: 1,
name: 'test',
tempName: null,
query: 'SELECT * from foo',
chart: {},
isUnsaved: false
}
addTab(state, tab)
expect(state.tabs[0]).to.eql(tab)
expect(state.untitledLastIndex).to.equal(0)
})
it('addTab (existed)', () => {
const tab1 = {
id: 1,
name: 'test',
tempName: null,
query: 'SELECT * from foo',
chart: {},
isUnsaved: false
}
const tab2 = {
id: 2,
name: 'bar',
tempName: null,
query: 'SELECT * from bar',
chart: {},
isUnsaved: false
}
// mock state
const state = {
tabs: [ tab1, tab2 ],
untitledLastIndex: 0,
}
addTab(state, tab1)
expect(state.tabs.length).to.equal(2)
expect(state.untitledLastIndex).to.equal(0)
})
it('updateTab (save)', () => {
const tab = {
id: 1,
@@ -438,4 +370,71 @@ describe('mutations', () => {
updatePredefinedQueries(state, queries)
expect(state.predefinedQueries).to.eql(queries)
})
})
describe('actions', () => {
it('addTab (new)', async () => {
// mock state
const state = {
tabs: [],
untitledLastIndex: 0
}
const id = await addTab({ state })
expect(state.tabs[0].id).to.eql(id)
expect(state.tabs[0].name).to.eql(null)
expect(state.tabs[0].tempName).to.eql('Untitled')
expect(state.tabs[0].isUnsaved).to.eql(true)
expect(state.untitledLastIndex).to.equal(1)
})
it('addTab (saved)', async () => {
// mock state
const state = {
tabs: [],
untitledLastIndex: 0
}
const tab = {
id: 1,
name: 'test',
tempName: null,
query: 'SELECT * from foo',
chart: {},
isUnsaved: false
}
await addTab({ state }, tab)
expect(state.tabs[0]).to.eql(tab)
expect(state.untitledLastIndex).to.equal(0)
})
it('addTab (existed)', async () => {
const tab1 = {
id: 1,
name: 'test',
tempName: null,
query: 'SELECT * from foo',
chart: {},
isUnsaved: false
}
const tab2 = {
id: 2,
name: 'bar',
tempName: null,
query: 'SELECT * from bar',
chart: {},
isUnsaved: false
}
// mock state
const state = {
tabs: [ tab1, tab2 ],
untitledLastIndex: 0,
}
await addTab({ state }, tab1)
expect(state.tabs.length).to.equal(2)
expect(state.untitledLastIndex).to.equal(0)
})
})