mirror of
https://github.com/Fabio286/antares.git
synced 2025-06-05 21:59:22 +02:00
feat: initial console implementation
This commit is contained in:
@ -11,14 +11,30 @@
|
||||
|
||||
<div class="footer-right-elements">
|
||||
<ul class="footer-elements">
|
||||
<li
|
||||
v-if="workspace !== 'NEW'"
|
||||
class="footer-element footer-link"
|
||||
@click="toggleConsole"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-console-line mr-1" />
|
||||
<small>{{ t('word.console') }}</small>
|
||||
</li>
|
||||
<li class="footer-element footer-link" @click="openOutside('https://www.paypal.com/paypalme/fabiodistasio')">
|
||||
<i class="mdi mdi-18px mdi-coffee mr-1" />
|
||||
<small>{{ $t('word.donate') }}</small>
|
||||
<small>{{ t('word.donate') }}</small>
|
||||
</li>
|
||||
<li class="footer-element footer-link" @click="openOutside('https://github.com/antares-sql/antares/issues')">
|
||||
<li
|
||||
class="footer-element footer-link"
|
||||
:title="t('message.reportABug')"
|
||||
@click="openOutside('https://github.com/antares-sql/antares/issues')"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-bug" />
|
||||
</li>
|
||||
<li class="footer-element footer-link" @click="showSettingModal('about')">
|
||||
<li
|
||||
class="footer-element footer-link"
|
||||
:title="t('word.about')"
|
||||
@click="showSettingModal('about')"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-information-outline" />
|
||||
</li>
|
||||
</ul>
|
||||
@ -29,9 +45,13 @@
|
||||
<script setup lang="ts">
|
||||
import { shell } from 'electron';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { computed, ComputedRef } from 'vue';
|
||||
import { useConsoleStore } from '@/stores/console';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
interface DatabaseInfos {// TODO: temp
|
||||
name: string;
|
||||
@ -44,6 +64,7 @@ const applicationStore = useApplicationStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: workspace } = storeToRefs(workspacesStore);
|
||||
const { toggleConsole } = useConsoleStore();
|
||||
|
||||
const { showSettingModal } = applicationStore;
|
||||
const { getWorkspace } = workspacesStore;
|
||||
|
@ -451,9 +451,11 @@
|
||||
:schema="tab.schema"
|
||||
/>
|
||||
</template>
|
||||
<WorkspaceQueryConsole v-if="isConsoleOpen" :uid="workspace.uid" />
|
||||
</div>
|
||||
<div v-else class="connection-panel-wrapper">
|
||||
<div v-else class="connection-panel-wrapper p-relative">
|
||||
<WorkspaceEditConnectionPanel :connection="connection" />
|
||||
<WorkspaceQueryConsole v-if="isConsoleOpen" :uid="workspace.uid" />
|
||||
</div>
|
||||
<ModalProcessesList
|
||||
v-if="isProcessesModal"
|
||||
@ -476,6 +478,7 @@ import { storeToRefs } from 'pinia';
|
||||
import * as Draggable from 'vuedraggable';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import { useWorkspacesStore, WorkspaceTab } from '@/stores/workspaces';
|
||||
import { useConsoleStore } from '@/stores/console';
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
|
||||
import WorkspaceEmptyState from '@/components/WorkspaceEmptyState.vue';
|
||||
@ -483,6 +486,7 @@ import WorkspaceExploreBar from '@/components/WorkspaceExploreBar.vue';
|
||||
import WorkspaceEditConnectionPanel from '@/components/WorkspaceEditConnectionPanel.vue';
|
||||
import WorkspaceTabQuery from '@/components/WorkspaceTabQuery.vue';
|
||||
import WorkspaceTabTable from '@/components/WorkspaceTabTable.vue';
|
||||
import WorkspaceQueryConsole from '@/components/WorkspaceQueryConsole.vue';
|
||||
|
||||
import WorkspaceTabNewTable from '@/components/WorkspaceTabNewTable.vue';
|
||||
import WorkspaceTabNewView from '@/components/WorkspaceTabNewView.vue';
|
||||
@ -518,6 +522,8 @@ const {
|
||||
selectPrevTab
|
||||
} = workspacesStore;
|
||||
|
||||
const { isConsoleOpen } = storeToRefs(useConsoleStore());
|
||||
|
||||
const props = defineProps({
|
||||
connection: Object as Prop<ConnectionParams>
|
||||
});
|
||||
@ -680,8 +686,9 @@ onMounted(() => {
|
||||
margin: 0;
|
||||
|
||||
.workspace-tabs {
|
||||
overflow: hidden;
|
||||
overflow-y: hidden;
|
||||
height: calc(100vh - #{$excluding-size});
|
||||
position: relative;
|
||||
|
||||
.tab-block {
|
||||
margin-top: 0;
|
||||
|
147
src/renderer/components/WorkspaceQueryConsole.vue
Normal file
147
src/renderer/components/WorkspaceQueryConsole.vue
Normal file
@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div
|
||||
ref="wrapper"
|
||||
class="query-console-wrapper"
|
||||
@mouseenter="isHover = true"
|
||||
@mouseleave="isHover = false"
|
||||
>
|
||||
<div ref="resizer" class="query-console-resizer" />
|
||||
<div
|
||||
id="query-console"
|
||||
ref="queryConsole"
|
||||
class="query-console column col-12"
|
||||
:style="{height: localHeight ? localHeight+'px' : ''}"
|
||||
>
|
||||
<div class="query-console-header">
|
||||
<div>{{ t('word.console') }}</div>
|
||||
<i class="mdi mdi-close c-hand" @click="resizeConsole(0)" />
|
||||
</div>
|
||||
<div ref="queryConsoleBody" class="query-console-body">
|
||||
<div
|
||||
v-for="(wLog, i) in workspaceLogs"
|
||||
:key="i"
|
||||
class="query-console-log"
|
||||
>
|
||||
<span class="type-datetime">{{ moment(wLog.date).format('YYYY-MM-DD HH:mm:ss') }}</span>: <span class="type-string">{{ wLog.sql }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, ref, Ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import * as moment from 'moment';
|
||||
import { useConsoleStore } from '@/stores/console';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const consoleStore = useConsoleStore();
|
||||
|
||||
const { resizeConsole, getLogsByWorkspace } = consoleStore;
|
||||
const { consoleHeight } = storeToRefs(consoleStore);
|
||||
|
||||
const props = defineProps({
|
||||
uid: String
|
||||
});
|
||||
|
||||
const wrapper: Ref<HTMLInputElement> = ref(null);
|
||||
const queryConsole: Ref<HTMLInputElement> = ref(null);
|
||||
const queryConsoleBody: Ref<HTMLInputElement> = ref(null);
|
||||
const resizer: Ref<HTMLInputElement> = ref(null);
|
||||
const localHeight = ref(250);
|
||||
const isHover = ref(false);
|
||||
|
||||
const resize = (e: MouseEvent) => {
|
||||
const el = queryConsole.value;
|
||||
let consoleHeight = el.getBoundingClientRect().bottom - e.pageY;
|
||||
if (consoleHeight > 400) consoleHeight = 400;
|
||||
localHeight.value = consoleHeight;
|
||||
};
|
||||
|
||||
const workspaceLogs = computed(() => {
|
||||
return getLogsByWorkspace(props.uid);
|
||||
});
|
||||
|
||||
const stopResize = () => {
|
||||
if (localHeight.value < 0) localHeight.value = 0;
|
||||
resizeConsole(localHeight.value);
|
||||
window.removeEventListener('mousemove', resize);
|
||||
window.removeEventListener('mouseup', stopResize);
|
||||
};
|
||||
|
||||
watch(workspaceLogs, async () => {
|
||||
if (!isHover.value) {
|
||||
await nextTick();
|
||||
queryConsoleBody.value.scrollTop = queryConsoleBody.value.scrollHeight;
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
localHeight.value = consoleHeight.value;
|
||||
queryConsoleBody.value.scrollTop = queryConsoleBody.value.scrollHeight;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
resizer.value.addEventListener('mousedown', (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
window.addEventListener('mousemove', resize);
|
||||
window.addEventListener('mouseup', stopResize);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.query-console-wrapper{
|
||||
width: 100%;
|
||||
z-index: 9;
|
||||
margin-top: auto;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
|
||||
.query-console-resizer{
|
||||
height: 4px;
|
||||
top: -1px;
|
||||
width: 100%;
|
||||
cursor: ns-resize;
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
transition: background 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: rgba($primary-color, 50%);
|
||||
}
|
||||
}
|
||||
|
||||
.query-console {
|
||||
padding: 0;
|
||||
padding-bottom: $footer-height;
|
||||
.query-console-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 4px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.query-console-body {
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 100%;
|
||||
padding: 0 6px;
|
||||
|
||||
.query-console-log {
|
||||
padding: 1px 3px;
|
||||
user-select: text;
|
||||
border-radius: $border-radius;
|
||||
&:hover {
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
@ -372,6 +372,8 @@ const resize = (e: MouseEvent) => {
|
||||
editorHeight.value = localEditorHeight;
|
||||
};
|
||||
|
||||
const resizeResults = () => queryTable.value.resizeResults();
|
||||
|
||||
const onWindowResize = (e: MouseEvent) => {
|
||||
const el = queryEditor.value.$el;
|
||||
const queryFooterHeight = queryAreaFooter.value.clientHeight;
|
||||
@ -386,7 +388,7 @@ const onWindowResize = (e: MouseEvent) => {
|
||||
const stopResize = () => {
|
||||
window.removeEventListener('mousemove', resize);
|
||||
if (queryTable.value && results.value.length)
|
||||
queryTable.value.resizeResults();
|
||||
resizeResults();
|
||||
|
||||
if (queryEditor.value)
|
||||
queryEditor.value.editor.resize();
|
||||
@ -476,6 +478,8 @@ const rollbackTab = async () => {
|
||||
isQuering.value = false;
|
||||
};
|
||||
|
||||
defineExpose({ resizeResults });
|
||||
|
||||
query.value = props.tab.content as string;
|
||||
selectedSchema.value = props.tab.schema || breadcrumbsSchema.value;
|
||||
|
||||
|
@ -118,6 +118,7 @@ import { storeToRefs } from 'pinia';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { useConsoleStore } from '@/stores/console';
|
||||
import { arrayToFile } from '../libs/arrayToFile';
|
||||
import { TEXT, LONG_TEXT, BLOB } from 'common/fieldTypes';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
|
||||
@ -132,10 +133,13 @@ import { TableUpdateParams } from 'common/interfaces/tableApis';
|
||||
const { t } = useI18n();
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const consoleStore = useConsoleStore();
|
||||
const { getWorkspace } = useWorkspacesStore();
|
||||
|
||||
const { dataTabLimit: pageSize } = storeToRefs(settingsStore);
|
||||
|
||||
const { consoleHeight } = storeToRefs(consoleStore);
|
||||
|
||||
const props = defineProps({
|
||||
results: Array as Prop<QueryResult[]>,
|
||||
connUid: String,
|
||||
@ -298,8 +302,13 @@ const resizeResults = () => {
|
||||
const el = tableWrapper.value;
|
||||
|
||||
if (el) {
|
||||
let sizeToSubtract = 0;
|
||||
const footer = document.getElementById('footer');
|
||||
const size = window.innerHeight - el.getBoundingClientRect().top - footer.offsetHeight;
|
||||
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||
|
||||
sizeToSubtract += consoleHeight.value;
|
||||
|
||||
const size = window.innerHeight - el.getBoundingClientRect().top - sizeToSubtract;
|
||||
resultsSize.value = size;
|
||||
}
|
||||
resultTable.value.updateWindow();
|
||||
@ -664,6 +673,10 @@ watch(() => props.isSelected, async (val) => {
|
||||
}
|
||||
});
|
||||
|
||||
watch(consoleHeight, () => {
|
||||
resizeResults();
|
||||
});
|
||||
|
||||
onUpdated(() => {
|
||||
if (table.value)
|
||||
refreshScroller();
|
||||
|
Reference in New Issue
Block a user