mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-30 13:53:59 +00:00
unsaved file marker
This commit is contained in:
31
packages/web/src/elements/TabCloseButton.svelte
Normal file
31
packages/web/src/elements/TabCloseButton.svelte
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
|
|
||||||
|
export let unsaved = false;
|
||||||
|
|
||||||
|
let mousein = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class="close-button tabCloseButton"
|
||||||
|
on:click
|
||||||
|
on:mouseenter={() => {
|
||||||
|
mousein = true;
|
||||||
|
}}
|
||||||
|
on:mouseleave={() => {
|
||||||
|
mousein = false;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FontIcon icon={unsaved && !mousein ? 'icon unsaved' : 'icon close'} />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.close-button {
|
||||||
|
margin-left: 5px;
|
||||||
|
color: var(--theme-font-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-button:hover {
|
||||||
|
color: var(--theme-font-1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
'icon file': 'mdi mdi-file',
|
'icon file': 'mdi mdi-file',
|
||||||
'icon loading': 'mdi mdi-loading mdi-spin',
|
'icon loading': 'mdi mdi-loading mdi-spin',
|
||||||
'icon close': 'mdi mdi-close',
|
'icon close': 'mdi mdi-close',
|
||||||
|
'icon unsaved': 'mdi mdi-record',
|
||||||
'icon stop': 'mdi mdi-close-octagon',
|
'icon stop': 'mdi mdi-close-octagon',
|
||||||
'icon filter': 'mdi mdi-filter',
|
'icon filter': 'mdi mdi-filter',
|
||||||
'icon filter-off': 'mdi mdi-filter-off',
|
'icon filter-off': 'mdi mdi-filter-off',
|
||||||
|
|||||||
@@ -554,6 +554,7 @@
|
|||||||
editor.on('focus', () => dispatch('focus'));
|
editor.on('focus', () => dispatch('focus'));
|
||||||
|
|
||||||
editor.setReadOnly(readOnly);
|
editor.setReadOnly(readOnly);
|
||||||
|
|
||||||
editor.on('change', () => {
|
editor.on('change', () => {
|
||||||
const content = editor.getValue();
|
const content = editor.getValue();
|
||||||
value = content;
|
value = content;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
import useEditorData from '../query/useEditorData';
|
import useEditorData from '../query/useEditorData';
|
||||||
import { extensions } from '../stores';
|
import { extensions } from '../stores';
|
||||||
import applyScriptTemplate from '../utility/applyScriptTemplate';
|
import applyScriptTemplate from '../utility/applyScriptTemplate';
|
||||||
import { changeTab } from '../utility/common';
|
import { changeTab, markTabUnsaved } from '../utility/common';
|
||||||
import { getDatabaseInfo, useConnectionInfo } from '../utility/metadataLoaders';
|
import { getDatabaseInfo, useConnectionInfo } from '../utility/metadataLoaders';
|
||||||
import SocketMessageView from '../query/SocketMessageView.svelte';
|
import SocketMessageView from '../query/SocketMessageView.svelte';
|
||||||
import useEffect from '../utility/useEffect';
|
import useEffect from '../utility/useEffect';
|
||||||
@@ -283,6 +283,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const quickExportHandlerRef = createQuickExportHandlerRef();
|
const quickExportHandlerRef = createQuickExportHandlerRef();
|
||||||
|
|
||||||
|
let isInitialized = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ToolStripContainer>
|
<ToolStripContainer>
|
||||||
@@ -298,11 +300,17 @@
|
|||||||
menu={createMenu()}
|
menu={createMenu()}
|
||||||
on:input={e => {
|
on:input={e => {
|
||||||
setEditorData(e.detail);
|
setEditorData(e.detail);
|
||||||
|
if (isInitialized) {
|
||||||
|
markTabUnsaved(tabid);
|
||||||
|
}
|
||||||
errorMessages = [];
|
errorMessages = [];
|
||||||
}}
|
}}
|
||||||
on:focus={() => {
|
on:focus={() => {
|
||||||
activator.activate();
|
activator.activate();
|
||||||
invalidateCommands();
|
invalidateCommands();
|
||||||
|
setTimeout(() => {
|
||||||
|
isInitialized = true;
|
||||||
|
}, 100);
|
||||||
}}
|
}}
|
||||||
bind:this={domEditor}
|
bind:this={domEditor}
|
||||||
onExecuteFragment={(sql, startLine) => executeCore(sql, startLine)}
|
onExecuteFragment={(sql, startLine) => executeCore(sql, startLine)}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { openedTabs } from '../stores';
|
import { getOpenedTabs, openedTabs } from '../stores';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import getElectron from './getElectron';
|
import getElectron from './getElectron';
|
||||||
|
|
||||||
@@ -18,6 +18,16 @@ export function changeTab(tabid, changeFunc) {
|
|||||||
openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? changeFunc(tab) : tab)));
|
openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? changeFunc(tab) : tab)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function markTabUnsaved(tabid) {
|
||||||
|
const tab = getOpenedTabs().find(x => x.tabid == tabid);
|
||||||
|
if (tab.unsaved) return;
|
||||||
|
openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? { ...tab, unsaved: true } : tab)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function markTabSaved(tabid) {
|
||||||
|
openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? { ...tab, unsaved: false } : tab)));
|
||||||
|
}
|
||||||
|
|
||||||
export function setSelectedTabFunc(files, tabid) {
|
export function setSelectedTabFunc(files, tabid) {
|
||||||
return [
|
return [
|
||||||
...(files || []).filter(x => x.tabid != tabid).map(x => ({ ...x, selected: false })),
|
...(files || []).filter(x => x.tabid != tabid).map(x => ({ ...x, selected: false })),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { derived, get } from 'svelte/store';
|
import { derived, get } from 'svelte/store';
|
||||||
import { showModal } from '../modals/modalTools';
|
import { showModal } from '../modals/modalTools';
|
||||||
import { openedTabs } from '../stores';
|
import { openedTabs } from '../stores';
|
||||||
import { changeTab } from './common';
|
import { changeTab, markTabSaved } from './common';
|
||||||
import SaveFileModal from '../modals/SaveFileModal.svelte';
|
import SaveFileModal from '../modals/SaveFileModal.svelte';
|
||||||
import registerCommand from '../commands/registerCommand';
|
import registerCommand from '../commands/registerCommand';
|
||||||
import { apiCall } from './api';
|
import { apiCall } from './api';
|
||||||
@@ -24,12 +24,14 @@ export default async function saveTabFile(editor, saveMode, folder, format, file
|
|||||||
if (savedFilePath) {
|
if (savedFilePath) {
|
||||||
await apiCall('files/save-as', { filePath: savedFilePath, data, format });
|
await apiCall('files/save-as', { filePath: savedFilePath, data, format });
|
||||||
}
|
}
|
||||||
|
markTabSaved(tabid);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSave = (title, newProps) => {
|
const onSave = (title, newProps) => {
|
||||||
changeTab(tabid, tab => ({
|
changeTab(tabid, tab => ({
|
||||||
...tab,
|
...tab,
|
||||||
title,
|
title,
|
||||||
|
unsaved: false,
|
||||||
props: {
|
props: {
|
||||||
...tab.props,
|
...tab.props,
|
||||||
savedFormat: format,
|
savedFormat: format,
|
||||||
|
|||||||
@@ -212,6 +212,7 @@
|
|||||||
import { getConnectionInfo, useConnectionList } from '../utility/metadataLoaders';
|
import { getConnectionInfo, useConnectionList } from '../utility/metadataLoaders';
|
||||||
import { duplicateTab, getTabDbKey, sortTabs, groupTabs } from '../utility/openNewTab';
|
import { duplicateTab, getTabDbKey, sortTabs, groupTabs } from '../utility/openNewTab';
|
||||||
import { useConnectionColorFactory } from '../utility/useConnectionColor';
|
import { useConnectionColorFactory } from '../utility/useConnectionColor';
|
||||||
|
import TabCloseButton from '../elements/TabCloseButton.svelte';
|
||||||
|
|
||||||
$: connectionList = useConnectionList();
|
$: connectionList = useConnectionList();
|
||||||
|
|
||||||
@@ -434,7 +435,7 @@
|
|||||||
<FontIcon icon="icon lock" />
|
<FontIcon icon="icon lock" />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
22
|
||||||
<div
|
<div
|
||||||
class="close-button-right tabCloseButton"
|
class="close-button-right tabCloseButton"
|
||||||
on:click={e => closeMultipleTabs(tab => tabGroup.tabs.find(x => x.tabid == tab.tabid))}
|
on:click={e => closeMultipleTabs(tab => tabGroup.tabs.find(x => x.tabid == tab.tabid))}
|
||||||
@@ -479,9 +480,7 @@
|
|||||||
<span class="file-name">
|
<span class="file-name">
|
||||||
{tab.title}
|
{tab.title}
|
||||||
</span>
|
</span>
|
||||||
<span class="close-button tabCloseButton" on:click={e => closeTab(tab.tabid)}>
|
<TabCloseButton unsaved={tab.unsaved} on:click={e => closeTab(tab.tabid)} />
|
||||||
<FontIcon icon="icon close" />
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
@@ -582,19 +581,12 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
.close-button {
|
|
||||||
margin-left: 5px;
|
|
||||||
color: var(--theme-font-3);
|
|
||||||
}
|
|
||||||
.close-button-right {
|
.close-button-right {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
color: var(--theme-font-3);
|
color: var(--theme-font-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-button:hover {
|
|
||||||
color: var(--theme-font-1);
|
|
||||||
}
|
|
||||||
.close-button-right:hover {
|
.close-button-right:hover {
|
||||||
color: var(--theme-font-1);
|
color: var(--theme-font-1);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user