refactor: ts and composition api for modals

This commit is contained in:
Fabio Di Stasio 2022-05-24 23:02:14 +02:00
parent 84826ff4c0
commit cdca6eaa35
9 changed files with 31368 additions and 440 deletions

1
.gitignore vendored
View File

@ -7,5 +7,4 @@ node_modules
thumbs.db thumbs.db
NOTES.md NOTES.md
*.txt *.txt
package-lock.json
*.heapsnapshot *.heapsnapshot

30996
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -145,6 +145,7 @@
"@playwright/test": "~1.21.1", "@playwright/test": "~1.21.1",
"@types/better-sqlite3": "~7.5.0", "@types/better-sqlite3": "~7.5.0",
"@types/leaflet": "~1.7.9", "@types/leaflet": "~1.7.9",
"@types/marked": "~4.0.3",
"@types/node": "~17.0.23", "@types/node": "~17.0.23",
"@types/pg": "~8.6.5", "@types/pg": "~8.6.5",
"@typescript-eslint/eslint-plugin": "~5.18.0", "@typescript-eslint/eslint-plugin": "~5.18.0",

View File

@ -294,13 +294,13 @@ const closeContext = () => {
}; };
const copyCell = () => { const copyCell = () => {
const row = results.value.find(row => row.id === selectedRow.value); const row = results.value.find(row => Number(row.id) === selectedRow.value);
const valueToCopy = row[selectedCell.value.field]; const valueToCopy = row[selectedCell.value.field];
navigator.clipboard.writeText(valueToCopy); navigator.clipboard.writeText(valueToCopy);
}; };
const copyRow = () => { const copyRow = () => {
const row = results.value.find(row => row.id === selectedRow.value); const row = results.value.find(row => Number(row.id) === selectedRow.value);
const rowToCopy = JSON.parse(JSON.stringify(row)); const rowToCopy = JSON.parse(JSON.stringify(row));
navigator.clipboard.writeText(JSON.stringify(rowToCopy)); navigator.clipboard.writeText(JSON.stringify(rowToCopy));
}; };

View File

@ -1,14 +1,14 @@
<template> <template>
<BaseContextMenu <BaseContextMenu
:context-event="contextEvent" :context-event="props.contextEvent"
@close-context="closeContext" @close-context="closeContext"
> >
<div v-if="selectedRow" class="context-element"> <div v-if="props.selectedRow" class="context-element">
<span class="d-flex"><i class="mdi mdi-18px mdi-content-copy text-light pr-1" /> {{ $t('word.copy') }}</span> <span class="d-flex"><i class="mdi mdi-18px mdi-content-copy text-light pr-1" /> {{ $t('word.copy') }}</span>
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" /> <i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
<div class="context-submenu"> <div class="context-submenu">
<div <div
v-if="selectedRow" v-if="props.selectedRow"
class="context-element" class="context-element"
@click="copyCell" @click="copyCell"
> >
@ -17,7 +17,7 @@
</span> </span>
</div> </div>
<div <div
v-if="selectedRow" v-if="props.selectedRow"
class="context-element" class="context-element"
@click="copyRow" @click="copyRow"
> >
@ -28,7 +28,7 @@
</div> </div>
</div> </div>
<div <div
v-if="selectedRow" v-if="props.selectedRow"
class="context-element" class="context-element"
@click="killProcess" @click="killProcess"
> >
@ -39,38 +39,33 @@
</BaseContextMenu> </BaseContextMenu>
</template> </template>
<script> <script setup lang="ts">
import BaseContextMenu from '@/components/BaseContextMenu'; import BaseContextMenu from '@/components/BaseContextMenu.vue';
export default { const props = defineProps({
name: 'ModalProcessesListContext', contextEvent: MouseEvent,
components: { selectedRow: Number,
BaseContextMenu selectedCell: Object
}, });
props: {
contextEvent: MouseEvent, const emit = defineEmits(['close-context', 'copy-cell', 'copy-row', 'kill-process']);
selectedRow: Number,
selectedCell: Object const closeContext = () => {
}, emit('close-context');
emits: ['close-context', 'copy-cell', 'copy-row', 'kill-process'], };
computed: {
}, const copyCell = () => {
methods: { emit('copy-cell');
closeContext () { closeContext();
this.$emit('close-context'); };
},
copyCell () { const copyRow = () => {
this.$emit('copy-cell'); emit('copy-row');
this.closeContext(); closeContext();
}, };
copyRow () {
this.$emit('copy-row'); const killProcess = () => {
this.closeContext(); emit('kill-process');
}, closeContext();
killProcess () {
this.$emit('kill-process');
this.closeContext();
}
}
}; };
</script> </script>

View File

@ -31,11 +31,12 @@
<div> <div>
<div> <div>
<TextEditor <TextEditor
:value="row.info || ''" :model-value="props.row.info || ''"
editor-class="textarea-editor" editor-class="textarea-editor"
:mode="editorMode" :mode="editorMode"
:read-only="true" :read-only="true"
/> />
<div class="mb-4" />
</div> </div>
</div> </div>
</template> </template>
@ -43,60 +44,46 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import ConfirmModal from '@/components/BaseConfirmModal'; import { Ref, ref } from 'vue';
import TextEditor from '@/components/BaseTextEditor'; import ConfirmModal from '@/components/BaseConfirmModal.vue';
import TextEditor from '@/components/BaseTextEditor.vue';
export default { const props = defineProps({
name: 'ModalProcessesListRow', row: Object
components: { });
ConfirmModal,
TextEditor const emit = defineEmits(['select-row', 'contextmenu', 'stop-refresh']);
},
props: { const isInlineEditor: Ref<{[key: string]: boolean}> = ref({});
row: Object const isInfoModal = ref(false);
}, const editorMode = ref('sql');
emits: ['select-row', 'contextmenu', 'stop-refresh'],
data () { const isNull = (value: string | number) => value === null ? ' is-null' : '';
return {
isInlineEditor: {}, const selectRow = () => {
isInfoModal: false, emit('select-row');
editorMode: 'sql'
};
},
computed: {},
methods: {
isNull (value) {
return value === null ? ' is-null' : '';
},
selectRow () {
this.$emit('select-row');
},
openContext (event, payload) {
this.$emit('contextmenu', event, payload);
},
hideInfoModal () {
this.isInfoModal = false;
},
dblClick (col) {
if (col !== 'info') return;
this.$emit('stop-refresh');
this.isInfoModal = true;
},
onKey (e) {
e.stopPropagation();
if (e.key === 'Escape') {
this.isInlineEditor[this.editingField] = false;
this.editingField = null;
window.removeEventListener('keydown', this.onKey);
}
},
cutText (val) {
if (typeof val !== 'string') return val;
return val.length > 250 ? `${val.substring(0, 250)}[...]` : val;
}
}
}; };
const openContext = (event: MouseEvent, payload: { id: number; field: string }) => {
emit('contextmenu', event, payload);
};
const hideInfoModal = () => {
isInfoModal.value = false;
};
const dblClick = (col: string) => {
if (col !== 'info') return;
emit('stop-refresh');
isInfoModal.value = true;
};
const cutText = (val: string | number) => {
if (typeof val !== 'string') return val;
return val.length > 250 ? `${val.substring(0, 250)}[...]` : val;
};
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -7,7 +7,7 @@
<div class="modal-title h6"> <div class="modal-title h6">
<div class="d-flex"> <div class="d-flex">
<i class="mdi mdi-24px mdi-cog mr-1" /> <i class="mdi mdi-24px mdi-cog mr-1" />
<span class="cut-text">{{ $t('word.settings') }}</span> <span class="cut-text">{{ t('word.settings') }}</span>
</div> </div>
</div> </div>
<a class="btn btn-clear c-hand" @click="closeModal" /> <a class="btn btn-clear c-hand" @click="closeModal" />
@ -21,14 +21,14 @@
:class="{'active': selectedTab === 'general'}" :class="{'active': selectedTab === 'general'}"
@click="selectTab('general')" @click="selectTab('general')"
> >
<a class="tab-link">{{ $t('word.general') }}</a> <a class="tab-link">{{ t('word.general') }}</a>
</li> </li>
<li <li
class="tab-item c-hand" class="tab-item c-hand"
:class="{'active': selectedTab === 'themes'}" :class="{'active': selectedTab === 'themes'}"
@click="selectTab('themes')" @click="selectTab('themes')"
> >
<a class="tab-link">{{ $t('word.themes') }}</a> <a class="tab-link">{{ t('word.themes') }}</a>
</li> </li>
<li <li
v-if="updateStatus !== 'disabled'" v-if="updateStatus !== 'disabled'"
@ -36,21 +36,21 @@
:class="{'active': selectedTab === 'update'}" :class="{'active': selectedTab === 'update'}"
@click="selectTab('update')" @click="selectTab('update')"
> >
<a class="tab-link" :class="{'badge badge-update': hasUpdates}">{{ $t('word.update') }}</a> <a class="tab-link" :class="{'badge badge-update': hasUpdates}">{{ t('word.update') }}</a>
</li> </li>
<li <li
class="tab-item c-hand" class="tab-item c-hand"
:class="{'active': selectedTab === 'changelog'}" :class="{'active': selectedTab === 'changelog'}"
@click="selectTab('changelog')" @click="selectTab('changelog')"
> >
<a class="tab-link">{{ $t('word.changelog') }}</a> <a class="tab-link">{{ t('word.changelog') }}</a>
</li> </li>
<li <li
class="tab-item c-hand" class="tab-item c-hand"
:class="{'active': selectedTab === 'about'}" :class="{'active': selectedTab === 'about'}"
@click="selectTab('about')" @click="selectTab('about')"
> >
<a class="tab-link">{{ $t('word.about') }}</a> <a class="tab-link">{{ t('word.about') }}</a>
</li> </li>
</ul> </ul>
</div> </div>
@ -58,14 +58,14 @@
<div class="container"> <div class="container">
<form class="form-horizontal columns"> <form class="form-horizontal columns">
<div class="column col-12 h6 text-uppercase mb-1"> <div class="column col-12 h6 text-uppercase mb-1">
{{ $t('word.application') }} {{ t('word.application') }}
</div> </div>
<div class="column col-12 col-sm-12 mb-2 columns"> <div class="column col-12 col-sm-12 mb-2 columns">
<div class="form-group column col-12"> <div class="form-group column col-12">
<div class="col-5 col-sm-12"> <div class="col-5 col-sm-12">
<label class="form-label"> <label class="form-label">
<i class="mdi mdi-18px mdi-translate mr-1" /> <i class="mdi mdi-18px mdi-translate mr-1" />
{{ $t('word.language') }} {{ t('word.language') }}
</label> </label>
</div> </div>
<div class="col-3 col-sm-12"> <div class="col-3 col-sm-12">
@ -85,15 +85,15 @@
</div> </div>
<div class="col-4 col-sm-12 px-2 p-vcentered"> <div class="col-4 col-sm-12 px-2 p-vcentered">
<small class="d-block" style="line-height:1.1; font-size:70%;"> <small class="d-block" style="line-height:1.1; font-size:70%;">
{{ $t('message.missingOrIncompleteTranslation') }}<br> {{ t('message.missingOrIncompleteTranslation') }}<br>
<a class="text-bold c-hand" @click="openOutside('https://github.com/antares-sql/antares/wiki/Translate-Antares')">{{ $t('message.findOutHowToContribute') }}</a> <a class="text-bold c-hand" @click="openOutside('https://github.com/antares-sql/antares/wiki/Translate-Antares')">{{ t('message.findOutHowToContribute') }}</a>
</small> </small>
</div> </div>
</div> </div>
<div class="form-group column col-12"> <div class="form-group column col-12">
<div class="col-5 col-sm-12"> <div class="col-5 col-sm-12">
<label class="form-label"> <label class="form-label">
{{ $t('message.dataTabPageSize') }} {{ t('message.dataTabPageSize') }}
</label> </label>
</div> </div>
<div class="col-3 col-sm-12"> <div class="col-3 col-sm-12">
@ -114,7 +114,7 @@
<div class="form-group column col-12 mb-0"> <div class="form-group column col-12 mb-0">
<div class="col-5 col-sm-12"> <div class="col-5 col-sm-12">
<label class="form-label"> <label class="form-label">
{{ $t('message.restorePreviourSession') }} {{ t('message.restorePreviourSession') }}
</label> </label>
</div> </div>
<div class="col-3 col-sm-12"> <div class="col-3 col-sm-12">
@ -127,7 +127,7 @@
<div class="form-group column col-12 mb-0"> <div class="form-group column col-12 mb-0">
<div class="col-5 col-sm-12"> <div class="col-5 col-sm-12">
<label class="form-label"> <label class="form-label">
{{ $t('message.disableBlur') }} {{ t('message.disableBlur') }}
</label> </label>
</div> </div>
<div class="col-3 col-sm-12"> <div class="col-3 col-sm-12">
@ -140,7 +140,7 @@
<div class="form-group column col-12"> <div class="form-group column col-12">
<div class="col-5 col-sm-12"> <div class="col-5 col-sm-12">
<label class="form-label"> <label class="form-label">
{{ $t('message.notificationsTimeout') }} {{ t('message.notificationsTimeout') }}
</label> </label>
</div> </div>
<div class="col-3 col-sm-12"> <div class="col-3 col-sm-12">
@ -152,19 +152,19 @@
min="1" min="1"
@focusout="checkNotificationsTimeout" @focusout="checkNotificationsTimeout"
> >
<span class="input-group-addon">{{ $t('word.seconds') }}</span> <span class="input-group-addon">{{ t('word.seconds') }}</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="column col-12 h6 mt-4 text-uppercase mb-1"> <div class="column col-12 h6 mt-4 text-uppercase mb-1">
{{ $t('word.editor') }} {{ t('word.editor') }}
</div> </div>
<div class="column col-12 col-sm-12 columns"> <div class="column col-12 col-sm-12 columns">
<div class="form-group column col-12 mb-0"> <div class="form-group column col-12 mb-0">
<div class="col-5 col-sm-12"> <div class="col-5 col-sm-12">
<label class="form-label"> <label class="form-label">
{{ $t('word.autoCompletion') }} {{ t('word.autoCompletion') }}
</label> </label>
</div> </div>
<div class="col-3 col-sm-12"> <div class="col-3 col-sm-12">
@ -177,7 +177,7 @@
<div class="form-group column col-12 mb-0"> <div class="form-group column col-12 mb-0">
<div class="col-5 col-sm-12"> <div class="col-5 col-sm-12">
<label class="form-label"> <label class="form-label">
{{ $t('message.wrapLongLines') }} {{ t('message.wrapLongLines') }}
</label> </label>
</div> </div>
<div class="col-3 col-sm-12"> <div class="col-3 col-sm-12">
@ -196,18 +196,18 @@
<div class="container"> <div class="container">
<div class="columns"> <div class="columns">
<div class="column col-12 h6 text-uppercase mb-2"> <div class="column col-12 h6 text-uppercase mb-2">
{{ $t('message.applicationTheme') }} {{ t('message.applicationTheme') }}
</div> </div>
<div <div
class="column col-6 c-hand theme-block" class="column col-6 c-hand theme-block"
:class="{'selected': applicationTheme === 'dark'}" :class="{'selected': applicationTheme === 'dark'}"
@click="changeApplicationTheme('dark')" @click="changeApplicationTheme('dark')"
> >
<img src="../images/dark.png" class="img-responsive img-fit-cover s-rounded"> <img :src="darkPreview" class="img-responsive img-fit-cover s-rounded">
<div class="theme-name text-light"> <div class="theme-name text-light">
<i class="mdi mdi-moon-waning-crescent mdi-48px" /> <i class="mdi mdi-moon-waning-crescent mdi-48px" />
<div class="h6 mt-4"> <div class="h6 mt-4">
{{ $t('word.dark') }} {{ t('word.dark') }}
</div> </div>
</div> </div>
</div> </div>
@ -216,11 +216,11 @@
:class="{'selected': applicationTheme === 'light'}" :class="{'selected': applicationTheme === 'light'}"
@click="changeApplicationTheme('light')" @click="changeApplicationTheme('light')"
> >
<img src="../images/light.png" class="img-responsive img-fit-cover s-rounded"> <img :src="lightPreview" class="img-responsive img-fit-cover s-rounded">
<div class="theme-name text-dark"> <div class="theme-name text-dark">
<i class="mdi mdi-white-balance-sunny mdi-48px" /> <i class="mdi mdi-white-balance-sunny mdi-48px" />
<div class="h6 mt-4"> <div class="h6 mt-4">
{{ $t('word.light') }} {{ t('word.light') }}
</div> </div>
</div> </div>
</div> </div>
@ -228,7 +228,7 @@
<div class="columns mt-4"> <div class="columns mt-4">
<div class="column col-12 h6 text-uppercase mb-2 mt-4"> <div class="column col-12 h6 text-uppercase mb-2 mt-4">
{{ $t('message.editorTheme') }} {{ t('message.editorTheme') }}
</div> </div>
<div class="column col-6 h5 mb-4"> <div class="column col-6 h5 mb-4">
<select <select
@ -259,21 +259,21 @@
:class="{'active': editorFontSize === 'small'}" :class="{'active': editorFontSize === 'small'}"
@click="changeEditorFontSize('small')" @click="changeEditorFontSize('small')"
> >
{{ $t('word.small') }} {{ t('word.small') }}
</button> </button>
<button <button
class="btn btn-dark cut-text" class="btn btn-dark cut-text"
:class="{'active': editorFontSize === 'medium'}" :class="{'active': editorFontSize === 'medium'}"
@click="changeEditorFontSize('medium')" @click="changeEditorFontSize('medium')"
> >
{{ $t('word.medium') }} {{ t('word.medium') }}
</button> </button>
<button <button
class="btn btn-dark cut-text" class="btn btn-dark cut-text"
:class="{'active': editorFontSize === 'large'}" :class="{'active': editorFontSize === 'large'}"
@click="changeEditorFontSize('large')" @click="changeEditorFontSize('large')"
> >
{{ $t('word.large') }} {{ t('word.large') }}
</button> </button>
</div> </div>
</div> </div>
@ -299,19 +299,19 @@
<div v-show="selectedTab === 'about'" class="panel-body py-4"> <div v-show="selectedTab === 'about'" class="panel-body py-4">
<div class="text-center"> <div class="text-center">
<img src="../images/logo.svg" width="128"> <img :src="appLogo" width="128">
<h4>{{ appName }}</h4> <h4>{{ appName }}</h4>
<p class="mb-2"> <p class="mb-2">
{{ $t('word.version') }} {{ appVersion }}<br> {{ t('word.version') }} {{ appVersion }}<br>
<a class="c-hand" @click="openOutside('https://github.com/antares-sql/antares')"><i class="mdi mdi-github d-inline" /> GitHub</a> <a class="c-hand" @click="openOutside('https://twitter.com/AntaresSQL')"><i class="mdi mdi-twitter d-inline" /> Twitter</a> <a class="c-hand" @click="openOutside('https://antares-sql.app/')"><i class="mdi mdi-web d-inline" /> Website</a><br> <a class="c-hand" @click="openOutside('https://github.com/antares-sql/antares')"><i class="mdi mdi-github d-inline" /> GitHub</a> <a class="c-hand" @click="openOutside('https://twitter.com/AntaresSQL')"><i class="mdi mdi-twitter d-inline" /> Twitter</a> <a class="c-hand" @click="openOutside('https://antares-sql.app/')"><i class="mdi mdi-web d-inline" /> Website</a><br>
<small>{{ $t('word.author') }} <a class="c-hand" @click="openOutside('https://github.com/Fabio286')">{{ appAuthor }}</a></small><br> <small>{{ t('word.author') }} <a class="c-hand" @click="openOutside('https://github.com/Fabio286')">{{ appAuthor }}</a></small><br>
</p> </p>
<div class="mb-2"> <div class="mb-2">
<small class="d-block text-uppercase">{{ $t('word.contributors') }}:</small> <small class="d-block text-uppercase">{{ t('word.contributors') }}:</small>
<div class="d-block py-1"> <div class="d-block py-1">
<small v-for="(contributor, i) in otherContributors" :key="i">{{ i !== 0 ? ', ' : '' }}{{ contributor }}</small> <small v-for="(contributor, i) in otherContributors" :key="i">{{ i !== 0 ? ', ' : '' }}{{ contributor }}</small>
</div> </div>
<small>{{ $t('message.madeWithJS') }}</small> <small>{{ t('message.madeWithJS') }}</small>
</div> </div>
</div> </div>
</div> </div>
@ -322,174 +322,120 @@
</Teleport> </Teleport>
</template> </template>
<script> <script setup lang="ts">
import { onBeforeUnmount, Ref, ref } from 'vue';
import { shell } from 'electron'; import { shell } from 'electron';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { useApplicationStore } from '@/stores/application'; import { useApplicationStore } from '@/stores/application';
import { useSettingsStore } from '@/stores/settings'; import { useSettingsStore } from '@/stores/settings';
import { useWorkspacesStore } from '@/stores/workspaces'; import { useWorkspacesStore } from '@/stores/workspaces';
import { localesNames } from '@/i18n/supported-locales'; import { localesNames } from '@/i18n/supported-locales';
import ModalSettingsUpdate from '@/components/ModalSettingsUpdate'; import ModalSettingsUpdate from '@/components/ModalSettingsUpdate.vue';
import ModalSettingsChangelog from '@/components/ModalSettingsChangelog'; import ModalSettingsChangelog from '@/components/ModalSettingsChangelog.vue';
import BaseTextEditor from '@/components/BaseTextEditor'; import BaseTextEditor from '@/components/BaseTextEditor.vue';
import { computed } from '@vue/reactivity';
export default { const { t, availableLocales } = useI18n();
name: 'ModalSettings',
components: { const applicationStore = useApplicationStore();
ModalSettingsUpdate, const settingsStore = useSettingsStore();
ModalSettingsChangelog, const workspacesStore = useWorkspacesStore();
BaseTextEditor
const {
selectedSettingTab,
updateStatus
} = storeToRefs(applicationStore);
const {
locale: selectedLocale,
dataTabLimit: pageSize,
autoComplete: selectedAutoComplete,
lineWrap: selectedLineWrap,
notificationsTimeout,
restoreTabs,
disableBlur,
applicationTheme,
editorTheme,
editorFontSize
} = storeToRefs(settingsStore);
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const {
changeLocale,
changePageSize,
changeRestoreTabs,
changeDisableBlur,
changeAutoComplete,
changeLineWrap,
changeApplicationTheme,
changeEditorTheme,
changeEditorFontSize,
updateNotificationsTimeout
} = settingsStore;
const {
hideSettingModal: closeModal,
appName,
appVersion
} = applicationStore;
const { getWorkspace } = workspacesStore;
const appAuthor = 'Fabio Di Stasio';
const pageSizes = [30, 40, 100, 250, 500, 1000];
const contributors = process.env.APP_CONTRIBUTORS;
const appLogo = require('../images/logo.svg');
const darkPreview = require('../images/dark.png');
const lightPreview = require('../images/light.png');
const editorThemes= [
{
group: t('word.light'),
themes: [
{ code: 'chrome', name: 'Chrome' },
{ code: 'clouds', name: 'Clouds' },
{ code: 'crimson_editor', name: 'Crimson Editor' },
{ code: 'dawn', name: 'Dawn' },
{ code: 'dreamweaver', name: 'Dreamweaver' },
{ code: 'eclupse', name: 'Eclipse' },
{ code: 'github', name: 'GitHub' },
{ code: 'iplastic', name: 'IPlastic' },
{ code: 'solarized_light', name: 'Solarized Light' },
{ code: 'textmate', name: 'TextMate' },
{ code: 'tomorrow', name: 'Tomorrow' },
{ code: 'xcode', name: 'Xcode' },
{ code: 'kuroir', name: 'Kuroir' },
{ code: 'katzenmilch', name: 'KatzenMilch' },
{ code: 'sqlserver', name: 'SQL Server' }
]
}, },
setup () { {
const applicationStore = useApplicationStore(); group: t('word.dark'),
const settingsStore = useSettingsStore(); themes: [
const workspacesStore = useWorkspacesStore(); { code: 'ambiance', name: 'Ambiance' },
{ code: 'chaos', name: 'Chaos' },
const { { code: 'clouds_midnight', name: 'Clouds Midnight' },
selectedSettingTab, { code: 'dracula', name: 'Dracula' },
updateStatus { code: 'cobalt', name: 'Cobalt' },
} = storeToRefs(applicationStore); { code: 'gruvbox', name: 'Gruvbox' },
const { { code: 'gob', name: 'Green on Black' },
locale: selectedLocale, { code: 'idle_fingers', name: 'Idle Fingers' },
dataTabLimit: pageSize, { code: 'kr_theme', name: 'krTheme' },
autoComplete: selectedAutoComplete, { code: 'merbivore', name: 'Merbivore' },
lineWrap: selectedLineWrap, { code: 'mono_industrial', name: 'Mono Industrial' },
notificationsTimeout, { code: 'monokai', name: 'Monokai' },
restoreTabs, { code: 'nord_dark', name: 'Nord Dark' },
disableBlur, { code: 'pastel_on_dark', name: 'Pastel on Dark' },
applicationTheme, { code: 'solarized_dark', name: 'Solarized Dark' },
editorTheme, { code: 'terminal', name: 'Terminal' },
editorFontSize { code: 'tomorrow_night', name: 'Tomorrow Night' },
} = storeToRefs(settingsStore); { code: 'tomorrow_night_blue', name: 'Tomorrow Night Blue' },
{ code: 'tomorrow_night_bright', name: 'Tomorrow Night Bright' },
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore); { code: 'tomorrow_night_eighties', name: 'Tomorrow Night 80s' },
{ code: 'twilight', name: 'Twilight' },
const { { code: 'vibrant_ink', name: 'Vibrant Ink' }
changeLocale, ]
changePageSize, }
changeRestoreTabs, ];
changeDisableBlur, const exampleQuery = `-- This is an example
changeAutoComplete,
changeLineWrap,
changeApplicationTheme,
changeEditorTheme,
changeEditorFontSize,
updateNotificationsTimeout
} = settingsStore;
const {
hideSettingModal,
appName,
appVersion
} = applicationStore;
const { getWorkspace } = workspacesStore;
return {
appName,
appVersion,
selectedSettingTab,
updateStatus,
closeModal: hideSettingModal,
selectedLocale,
pageSize,
selectedAutoComplete,
selectedLineWrap,
notificationsTimeout,
restoreTabs,
disableBlur,
applicationTheme,
editorTheme,
editorFontSize,
changeLocale,
changePageSize,
changeRestoreTabs,
changeDisableBlur,
changeAutoComplete,
changeLineWrap,
changeApplicationTheme,
changeEditorTheme,
changeEditorFontSize,
updateNotificationsTimeout,
selectedWorkspace,
getWorkspace
};
},
data () {
return {
appAuthor: 'Fabio Di Stasio',
localLocale: null,
localPageSize: null,
localTimeout: null,
localEditorTheme: null,
selectedTab: 'general',
pageSizes: [30, 40, 100, 250, 500, 1000],
editorThemes: [
{
group: this.$t('word.light'),
themes: [
{ code: 'chrome', name: 'Chrome' },
{ code: 'clouds', name: 'Clouds' },
{ code: 'crimson_editor', name: 'Crimson Editor' },
{ code: 'dawn', name: 'Dawn' },
{ code: 'dreamweaver', name: 'Dreamweaver' },
{ code: 'eclupse', name: 'Eclipse' },
{ code: 'github', name: 'GitHub' },
{ code: 'iplastic', name: 'IPlastic' },
{ code: 'solarized_light', name: 'Solarized Light' },
{ code: 'textmate', name: 'TextMate' },
{ code: 'tomorrow', name: 'Tomorrow' },
{ code: 'xcode', name: 'Xcode' },
{ code: 'kuroir', name: 'Kuroir' },
{ code: 'katzenmilch', name: 'KatzenMilch' },
{ code: 'sqlserver', name: 'SQL Server' }
]
},
{
group: this.$t('word.dark'),
themes: [
{ code: 'ambiance', name: 'Ambiance' },
{ code: 'chaos', name: 'Chaos' },
{ code: 'clouds_midnight', name: 'Clouds Midnight' },
{ code: 'dracula', name: 'Dracula' },
{ code: 'cobalt', name: 'Cobalt' },
{ code: 'gruvbox', name: 'Gruvbox' },
{ code: 'gob', name: 'Green on Black' },
{ code: 'idle_fingers', name: 'Idle Fingers' },
{ code: 'kr_theme', name: 'krTheme' },
{ code: 'merbivore', name: 'Merbivore' },
{ code: 'mono_industrial', name: 'Mono Industrial' },
{ code: 'monokai', name: 'Monokai' },
{ code: 'nord_dark', name: 'Nord Dark' },
{ code: 'pastel_on_dark', name: 'Pastel on Dark' },
{ code: 'solarized_dark', name: 'Solarized Dark' },
{ code: 'terminal', name: 'Terminal' },
{ code: 'tomorrow_night', name: 'Tomorrow Night' },
{ code: 'tomorrow_night_blue', name: 'Tomorrow Night Blue' },
{ code: 'tomorrow_night_bright', name: 'Tomorrow Night Bright' },
{ code: 'tomorrow_night_eighties', name: 'Tomorrow Night 80s' },
{ code: 'twilight', name: 'Twilight' },
{ code: 'vibrant_ink', name: 'Vibrant Ink' }
]
}
],
contributors: process.env.APP_CONTRIBUTORS
};
},
computed: {
locales () {
const locales = [];
for (const locale of this.$i18n.availableLocales)
locales.push({ code: locale, name: localesNames[locale] });
return locales;
},
hasUpdates () {
return ['available', 'downloading', 'downloaded', 'link'].includes(this.updateStatus);
},
workspace () {
return this.getWorkspace(this.selectedWorkspace);
},
exampleQuery () {
return `-- This is an example
SELECT SELECT
employee.id, employee.id,
employee.first_name, employee.first_name,
@ -504,57 +450,81 @@ GROUP BY
ORDER BY ORDER BY
employee.id ASC; employee.id ASC;
`; `;
},
otherContributors () {
return this.contributors
.split(',')
.filter(c => !c.includes(this.appAuthor))
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
}
},
created () {
this.localLocale = this.selectedLocale;
this.localPageSize = this.pageSize;
this.localTimeout = this.notificationsTimeout;
this.localEditorTheme = this.editorTheme;
this.selectedTab = this.selectedSettingTab;
window.addEventListener('keydown', this.onKey);
},
beforeUnmount () {
window.removeEventListener('keydown', this.onKey);
},
methods: {
selectTab (tab) {
this.selectedTab = tab;
},
openOutside (link) {
shell.openExternal(link);
},
checkNotificationsTimeout () {
if (!this.localTimeout)
this.localTimeout = 10;
this.updateNotificationsTimeout(+this.localTimeout); const localLocale: Ref<string> = ref(null);
}, const localPageSize: Ref<number> = ref(null);
onKey (e) { const localTimeout: Ref<number> = ref(null);
e.stopPropagation(); const localEditorTheme: Ref<string> = ref(null);
if (e.key === 'Escape') const selectedTab: Ref<string> = ref('general');
this.closeModal();
}, const locales = computed(() => {
toggleRestoreSession () { const locales = [];
this.changeRestoreTabs(!this.restoreTabs); for (const locale of availableLocales)
}, locales.push({ code: locale, name: localesNames[locale] });
toggleDisableBlur () {
this.changeDisableBlur(!this.disableBlur); return locales;
}, });
toggleAutoComplete () {
this.changeAutoComplete(!this.selectedAutoComplete); const hasUpdates = computed(() => ['available', 'downloading', 'downloaded', 'link'].includes(updateStatus.value));
},
toggleLineWrap () { const workspace = computed(() => {
this.changeLineWrap(!this.selectedLineWrap); return getWorkspace(selectedWorkspace.value);
} });
}
const otherContributors = computed(() => {
return contributors
.split(',')
.filter(c => !c.includes(appAuthor))
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
});
const selectTab = (tab: string) => {
selectedTab.value = tab;
}; };
const openOutside = (link: string) => {
shell.openExternal(link);
};
const checkNotificationsTimeout = () => {
if (!localTimeout.value)
localTimeout.value = 10;
updateNotificationsTimeout(+localTimeout.value);
};
const onKey = (e: KeyboardEvent) => {
e.stopPropagation();
if (e.key === 'Escape')
closeModal();
};
const toggleRestoreSession = () => {
changeRestoreTabs(!restoreTabs.value);
};
const toggleDisableBlur = () => {
changeDisableBlur(!disableBlur.value);
};
const toggleAutoComplete = () => {
changeAutoComplete(!selectedAutoComplete.value);
};
const toggleLineWrap = () => {
changeLineWrap(!selectedLineWrap.value);
};
localLocale.value = selectedLocale.value as string;
localPageSize.value = pageSize.value as number;
localTimeout.value = notificationsTimeout.value as number;
localEditorTheme.value = editorTheme.value as string;
selectedTab.value = selectedSettingTab.value;
window.addEventListener('keydown', onKey);
onBeforeUnmount(() => {
window.removeEventListener('keydown', onKey);
});
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -13,66 +13,53 @@
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts">
<script>
import { marked } from 'marked'; import { marked } from 'marked';
import BaseLoader from '@/components/BaseLoader'; import BaseLoader from '@/components/BaseLoader.vue';
import { useApplicationStore } from '@/stores/application'; import { useApplicationStore } from '@/stores/application';
import { ref } from 'vue';
export default { const { appVersion } = useApplicationStore();
name: 'ModalSettingsChangelog',
components: { const changelog = ref('');
BaseLoader const isLoading = ref(true);
}, const error = ref('');
setup () { const isError = ref(false);
const { appVersion } = useApplicationStore();
return { appVersion }; const getChangelog = async () => {
}, try {
data () { const apiRes = await fetch(`https://api.github.com/repos/antares-sql/antares/releases/tags/v${appVersion}`, {
return { method: 'GET'
changelog: '', });
isLoading: true,
error: '', const { body } = await apiRes.json();
isError: false const cutOffset = body.indexOf('### Download');
const markdown = cutOffset >= 0
? body.substr(0, cutOffset)
: body;
const renderer = {
link (href: string, title: string, text: string) {
return text;
},
listitem (text: string) {
return `<li>${text.replace(/ *\([^)]*\) */g, '')}</li>`;
}
}; };
},
created () {
this.getChangelog();
},
methods: {
async getChangelog () {
try {
const apiRes = await fetch(`https://api.github.com/repos/antares-sql/antares/releases/tags/v${this.appVersion}`, {
method: 'GET'
});
const { body } = await apiRes.json(); marked.use({ renderer });
const cutOffset = body.indexOf('### Download');
const markdown = cutOffset >= 0
? body.substr(0, cutOffset)
: body;
const renderer = { changelog.value = marked(markdown);
link (href, title, text) {
return text;
},
listitem (text) {
return `<li>${text.replace(/ *\([^)]*\) */g, '')}</li>`;
}
};
marked.use({ renderer });
this.changelog = marked(markdown);
}
catch (err) {
this.error = err.message;
this.isError = true;
}
this.isLoading = false;
}
} }
catch (err) {
error.value = err.message;
isError.value = true;
}
isLoading.value = false;
}; };
getChangelog();
</script> </script>
<style lang="scss"> <style lang="scss">
#changelog { #changelog {

View File

@ -52,68 +52,61 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { ipcRenderer, shell } from 'electron'; import { ipcRenderer, shell } from 'electron';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useApplicationStore } from '@/stores/application'; import { useApplicationStore } from '@/stores/application';
import { useSettingsStore } from '@/stores/settings'; import { useSettingsStore } from '@/stores/settings';
export default { const { t } = useI18n();
name: 'ModalSettingsUpdate',
setup () {
const applicationStore = useApplicationStore();
const settingsStore = useSettingsStore();
const { const applicationStore = useApplicationStore();
updateStatus, const settingsStore = useSettingsStore();
getDownloadProgress
} = storeToRefs(applicationStore);
const { allowPrerelease } = storeToRefs(settingsStore);
const { changeAllowPrerelease } = settingsStore; const {
updateStatus,
getDownloadProgress: downloadPercentage
} = storeToRefs(applicationStore);
const { allowPrerelease } = storeToRefs(settingsStore);
return { const { changeAllowPrerelease } = settingsStore;
updateStatus,
downloadPercentage: getDownloadProgress, const updateMessage = computed(() => {
allowPrerelease, switch (updateStatus.value) {
changeAllowPrerelease case 'noupdate':
}; return t('message.noUpdatesAvailable');
}, case 'checking':
computed: { return t('message.checkingForUpdate');
updateMessage () { case 'nocheck':
switch (this.updateStatus) { return t('message.checkFailure');
case 'noupdate': case 'available':
return this.$t('message.noUpdatesAvailable'); return t('message.updateAvailable');
case 'checking': case 'downloading':
return this.$t('message.checkingForUpdate'); return t('message.downloadingUpdate');
case 'nocheck': case 'downloaded':
return this.$t('message.checkFailure'); return t('message.updateDownloaded');
case 'available': case 'link':
return this.$t('message.updateAvailable'); return t('message.updateAvailable');
case 'downloading': default:
return this.$t('message.downloadingUpdate'); return updateStatus.value;
case 'downloaded':
return this.$t('message.updateDownloaded');
case 'link':
return this.$t('message.updateAvailable');
default:
return this.updateStatus;
}
}
},
methods: {
openOutside (link) {
shell.openExternal(link);
},
checkForUpdates () {
ipcRenderer.send('check-for-updates');
},
restartToUpdate () {
ipcRenderer.send('restart-to-update');
},
toggleAllowPrerelease () {
this.changeAllowPrerelease(!this.allowPrerelease);
}
} }
});
const openOutside = (link: string) => {
shell.openExternal(link);
};
const checkForUpdates = () => {
ipcRenderer.send('check-for-updates');
};
const restartToUpdate = () => {
ipcRenderer.send('restart-to-update');
};
const toggleAllowPrerelease = () => {
changeAllowPrerelease(!allowPrerelease.value);
}; };
</script> </script>