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

adding and closing tabs; saving of queries

This commit is contained in:
lana-k
2020-10-07 16:03:36 +02:00
parent f898493d29
commit 4841e43a09
7 changed files with 191 additions and 27 deletions

View File

@@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z" fill="#A2B1C6"/>
</svg>

After

Width:  |  Height:  |  Size: 232 B

View File

@@ -28,5 +28,9 @@ button.primary:disabled {
color: var(--color-text-light-2);
text-shadow: none;
cursor: default;
}
}
button.primary:focus {
outline: none;
}

View File

@@ -22,7 +22,6 @@
--color-text-light: var(--color-white);
--color-text-light-2: var(--color-gray-medium);
--color-text-base: var(--color-gray-dark);
--color-text-medium: var(--color-gray-medium);
--color-text-active: var(--color-blue-dark-2);
--shadow: 0 1px 2px rgba(42, 63, 95, 0.7);

View File

@@ -5,15 +5,68 @@
<router-link to="/my-queries">My queries</router-link>
</div>
<div>
<button class="primary" disabled>Save</button>
<button class="primary">Create</button>
<button
v-if="$store.state.tabs.length > 0"
class="primary"
:disabled="!$store.state.currentTab.isUnsaved"
@click="saveQuery"
>
Save
</button>
<button class="primary" @click="createNewQuery">Create</button>
</div>
</nav>
</template>
<script>
export default {
name: 'MainMenu'
name: 'MainMenu',
methods: {
createNewQuery () {
const tab = {
id: Number(new Date()),
name: this.$store.state.untitledLastIndex === 3 ? 'Very good query' : null,
tempName: this.$store.state.untitledLastIndex
? `Untitled ${this.$store.state.untitledLastIndex}`
: 'Untitled',
isUnsaved: true
}
this.$store.commit('addTab', tab)
this.$store.commit('setCurrentTabId', tab.id)
this.$store.commit('updateUntitledLastIndex')
},
saveQuery () {
const currentQuery = this.$store.state.currentTab
const isFromScratch = !this.$store.state.currentTab.initName
const value = {
id: currentQuery.id,
query: currentQuery.query
// TODO: save plotly settings
}
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
}
let myQueries = JSON.parse(localStorage.getItem('myQueries'))
if (!myQueries) {
myQueries = [value]
} else if (isFromScratch) {
myQueries.push(value)
} else {
const queryIndex = myQueries.findIndex(query => query.id === currentQuery.id)
value.createdAt = myQueries[queryIndex].createdAt
myQueries[queryIndex] = value
}
localStorage.setItem('myQueries', JSON.stringify(myQueries))
currentQuery.isUnsaved = false
}
}
}
</script>
<style scoped>

View File

@@ -8,7 +8,7 @@
>
<div slot="left-pane" class="query-editor">
<div class="codemirror-container">
<codemirror v-model="code" :options="cmOptions" @changes="onCmChange" />
<codemirror v-model="query" :options="cmOptions" @changes="onCmChange" ref="codemirror" />
</div>
<div class="run-btn-container">
<button class="primary run-btn" @click="execEditorContents">Run</button>
@@ -59,7 +59,7 @@ import 'codemirror/addon/hint/sql-hint.js'
export default {
name: 'TabContent',
props: ['name', 'isActive'],
props: ['id', 'initName', 'initQuery', 'initPlotly', 'tabIndex'],
components: {
codemirror,
SqlTable,
@@ -74,7 +74,7 @@ export default {
layout: {},
frames: []
},
code: 'select * from albums',
query: 'select * from albums',
cmOptions: {
// codemirror options
tabSize: 4,
@@ -86,10 +86,14 @@ export default {
result: null,
view: 'table',
tableViewHeight: 0,
worker: this.$store.state.worker
worker: this.$store.state.worker,
isUnsaved: !this.name
}
},
computed: {
isActive () {
return this.id === this.$store.state.currentTabId
},
dataSources () {
if (!this.result) {
return {}
@@ -110,13 +114,30 @@ export default {
}))
}
},
created () {
this.$store.commit('setCurrentTab', this)
},
mounted () {
new ResizeObserver(this.calculateTableHeight).observe(this.$refs.bottomPane)
this.calculateTableHeight()
},
watch: {
isActive () {
if (this.isActive) {
this.$store.commit('setCurrentTab', this)
}
},
query () {
this.isUnsaved = true
},
isUnsaved () {
this.$store.commit('updateTabState', { index: this.tabIndex, newValue: this.isUnsaved })
}
},
methods: {
update (data, layout, frames) {
this.state = { data, layout, frames }
this.isUnsaved = true
console.log(this.state)
},
onCmChange (editor) {
@@ -154,7 +175,7 @@ export default {
// this.$refs.output.textContent = 'Fetching results...'
},
execEditorContents () {
this.execute(this.code + ';')
this.execute(this.query + ';')
},
calculateTableHeight () {
const bottomPane = this.$refs.bottomPane

View File

@@ -2,19 +2,39 @@
<div>
<div id="tabs__header">
<div
v-for="tab in tabs"
v-for="(tab, index) in tabs"
:key="tab.id"
@click="selectTab(tab.id)"
:class='{"tab__selected": (tab.id === selectedIndex)}'
:class="[{'tab__selected': (tab.id === selectedIndex)}, 'tab']"
>
{{ tab.name }}
<div class="tab-name">
<span v-show="tab.isUnsaved">*</span>
<span v-if="tab.name">{{ tab.name }}</span>
<span v-else class="tab-untitled">{{ tab.tempName }}</span>
</div>
<div>
<svg
class="close-icon"
@click.stop="closeTab(index)"
width="10"
height="10"
viewBox="0 0 14 14"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z"
fill="#A2B1C6"/>
</svg>
</div>
</div>
</div>
<tab-content
v-for="tab in tabs"
v-for="(tab, index) in tabs"
:key="tab.id"
:is-active="tab.isActive"
:name="tab.name"
:id="tab.id"
:init-name="tab.name"
:tab-index="index"
/>
</div>
</template>
@@ -28,19 +48,22 @@ export default {
},
data () {
return {
selectedIndex: 0,
tabs: [
{ id: 1, name: 'New query', isActive: true },
{ id: 2, name: 'New query 2', isActive: false }
]
}
},
computed: {
tabs () {
return this.$store.state.tabs
},
selectedIndex () {
return this.$store.state.currentTabId
}
},
methods: {
selectTab (id) {
this.selectedIndex = id
this.tabs.forEach(tab => {
tab.isActive = (tab.id === id)
})
this.$store.commit('setCurrentTabId', id)
},
closeTab (index) {
this.$store.commit('deleteTab', index)
}
}
}
@@ -50,8 +73,10 @@ export default {
#tabs__header {
display: flex;
margin: 0;
max-width: 100%;
overflow: hidden;
}
#tabs__header div {
#tabs__header .tab {
height: 36px;
background-color: var(--color-bg-light);
border-right: 1px solid var(--color-border-light);
@@ -62,7 +87,18 @@ export default {
padding: 0 12px;
box-sizing: border-box;
position: relative;
max-width: 200px;
display: flex;
flex-shrink: 1;
min-width: 0;
}
#tabs__header .tab-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-shrink: 1;
}
#tabs__header div:hover {
cursor: pointer;
}
@@ -84,4 +120,13 @@ export default {
top: 0;
left: 0;
}
.close-icon {
margin-left: 5px;
}
.close-icon:hover path {
fill: var(--color-text-base);
cursor: pointer;
}
</style>

View File

@@ -8,7 +8,11 @@ export default new Vuex.Store({
schema: null,
dbFile: null,
dbName: null,
worker: new Worker('/js/worker.sql-wasm.js')
worker: new Worker('/js/worker.sql-wasm.js'),
tabs: [],
currentTab: null,
currentTabId: null,
untitledLastIndex: 0
},
mutations: {
saveSchema (state, schema) {
@@ -19,6 +23,41 @@ export default new Vuex.Store({
},
saveDbName (state, name) {
state.dbName = name
},
addTab (state, tab) {
state.tabs.push(tab)
},
updateTabName (state, { index, newName }) {
const tab = state.tabs[index]
tab.name = newName
Vue.set(state.tabs, index, tab)
},
updateTabState (state, { index, newValue }) {
console.log(index, newValue)
const tab = state.tabs[index]
tab.isUnsaved = newValue
Vue.set(state.tabs, index, tab)
},
deleteTab (state, index) {
if (state.tabs[index].id !== state.currentTabId) {
} else if (index < state.tabs.length - 1) {
state.currentTabId = state.tabs[index + 1].id
} else if (index > 0) {
state.currentTabId = state.tabs[index - 1].id
} else {
state.currentTabId = null
state.untitledLastIndex = 0
}
state.tabs.splice(index, 1)
},
setCurrentTabId (state, id) {
state.currentTabId = id
},
setCurrentTab (state, tab) {
state.currentTab = tab
},
updateUntitledLastIndex (state) {
state.untitledLastIndex += 1
}
},
actions: {