1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-04-26 15:58:42 +02:00

chore: utility commit

This commit is contained in:
Fabio Di Stasio 2023-12-13 18:29:45 +01:00
parent dbd533b229
commit 84d221aaa7
6 changed files with 288 additions and 142 deletions

View File

@ -280,7 +280,6 @@ export default defineComponent({
if (props.searchable)
searchInput.value.focus();
else
el.value.focus();

View File

@ -0,0 +1,91 @@
<template>
<ConfirmModal size="400">
<template #header>
<div class="d-flex">
<BaseIcon
icon-name="mdiNotePlusOutline"
class="mr-1"
:size="24"
/> {{ t('application.addNote') }}
</div>
</template>
<template #body>
<form class="form">
<div class="form-group columns">
<div class="column col-12">
<label class="form-label">{{ t('general.title') }}</label>
<input
ref="firstInput"
v-model="newNote.title"
class="form-input"
type="text"
>
</div>
</div>
<div class="form-group columns">
<div class="column col-8">
<label class="form-label">{{ t('connection.connection') }}</label>
<BaseSelect
v-model="newNote.cUid"
class="form-select"
:options="connectionOptions"
option-track-by="code"
option-label="name"
@change="null"
/>
</div>
<div class="column col-4">
<label class="form-label">{{ t('application.tag') }}</label>
<BaseSelect
v-model="newNote.type"
class="form-select"
:options="noteTags"
option-track-by="code"
option-label="name"
@change="null"
/>
</div>
</div>
<div class="form-group">
<label class="form-label">{{ t('general.content') }}</label>
<BaseTextEditor :mode="editorMode" :show-line-numbers="false" />
</div>
</form>
</template>
</ConfirmModal>
</template>
<script lang="ts" setup>
import { uidGen } from 'common/libs/uidGen';
import { inject, Ref, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import BaseIcon from '@/components/BaseIcon.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import BaseTextEditor from '@/components/BaseTextEditor.vue';
import { ConnectionNote, TagCode } from '@/stores/scratchpad';
const { t } = useI18n();
const noteTags = inject<{code: TagCode; name: string}[]>('noteTags');
const connectionOptions = inject<{code: string; name: string}[]>('connectionOptions');
const editorMode = ref('markdown');
const newNote: Ref<ConnectionNote> = ref({
uid: uidGen('N'),
cUid: null,
title: undefined,
note: '',
date: new Date(),
type: 'note'
});
watch(() => newNote.value.type, () => {
if (newNote.value.type === 'query')
editorMode.value = 'sql';
else
editorMode.value = 'markdown';
});
</script>

View File

@ -4,6 +4,7 @@
:cancel-text="t('general.close')"
size="medium"
:hide-footer="true"
:disable-autofocus="true"
@hide="hideScratchpad"
>
<template #header>
@ -16,157 +17,173 @@
</div>
</template>
<template #body>
<div class="d-flex p-vcentered" style="gap: 0 10px">
<div style="flex: 1;">
<BaseSelect
v-model="localConnection"
class="form-select"
:options="connectionOptions"
option-track-by="code"
option-label="name"
@change="null"
/>
</div>
<div class="btn-group btn-group-block text-uppercase">
<div class="btn btn-primary">
{{ t('general.all') }}
</div>
<div class="btn btn-dark">
{{ t('application.note', 1) }}
</div>
<div class="btn btn-dark">
TODO
</div>
<div class="btn btn-dark">
Query
</div>
</div>
<div class="">
<button class="btn btn-link px-1 tooltip tooltip-left" :data-tooltip="'Show archived notes'">
<BaseIcon
icon-name="mdiArchiveEyeOutline"
class=""
:size="24"
<div class="p-relative">
<div class="d-flex p-vcentered" style="gap: 0 10px">
<div style="flex: 1;">
<BaseSelect
v-model="localConnection"
class="form-select"
:options="connectionOptions"
option-track-by="code"
option-label="name"
@change="null"
/>
</button>
</div>
<div class="btn-group btn-group-block text-uppercase">
<div
v-for="tag in [{ code: 'all', name: t('general.all') }, ...noteTags]"
:key="tag.code"
class="btn"
:class="[selectedTab === tag.code ? 'btn-primary': 'btn-dark']"
@click="selectedTab = tag.code"
>
{{ tag.name }}
</div>
</div>
<div class="">
<div
class="btn px-1 tooltip tooltip-left s-rounded archived-button"
:class="[showArchived ? 'btn-primary' : 'btn-link']"
:data-tooltip="showArchived ? t('application.hideArchivedNotes') : t('application.showArchivedNotes')"
@click="showArchived = !showArchived"
>
<BaseIcon
:icon-name="!showArchived ? 'mdiArchiveEyeOutline' : 'mdiArchiveCancelOutline'"
class=""
:size="24"
/>
</div>
</div>
</div>
<div>
<div
v-if="filteredNotes.length"
ref="searchForm"
class="form-group has-icon-right m-0"
>
<input
v-model="searchTerm"
class="form-input"
type="text"
:placeholder="t('general.search')"
>
<BaseIcon
v-if="!searchTerm"
icon-name="mdiMagnify"
class="form-icon pr-2"
:size="18"
/>
<BaseIcon
v-else
icon-name="mdiBackspace"
class="form-icon c-hand pr-2"
:size="18"
@click="searchTerm = ''"
/>
</div>
</div>
</div>
<div>
<div
v-if="filteredNotes.length"
ref="searchForm"
class="form-group has-icon-right m-0"
v-if="connectionNotes.length"
ref="tableWrapper"
class="vscroll px-1"
:style="{'height': resultsSize+'px'}"
>
<input
v-model="searchTerm"
class="form-input"
type="text"
:placeholder="t('general.search')"
>
<BaseIcon
v-if="!searchTerm"
icon-name="mdiMagnify"
class="form-icon pr-2"
:size="18"
/>
<BaseIcon
v-else
icon-name="mdiBackspace"
class="form-icon c-hand pr-2"
:size="18"
@click="searchTerm = ''"
/>
</div>
</div>
<div
v-if="connectionNotes.length"
ref="tableWrapper"
class="vscroll px-1"
:style="{'height': resultsSize+'px'}"
>
<div ref="table">
<BaseVirtualScroll
ref="resultTable"
:items="filteredNotes"
:item-height="66"
:visible-height="resultsSize"
:scroll-element="scrollElement"
>
<template #default="{ items }">
<div
v-for="note in items"
:key="note.uid"
class="tile my-2"
tabindex="0"
>
<div class="tile-icon">
<BaseIcon
icon-name="mdiCodeTags"
class="pr-1"
:size="24"
/>
</div>
<div class="tile-content">
<div class="tile-title">
<code
class="cut-text"
:title="note.note"
v-html="highlightWord(note.note)"
<div ref="table">
<BaseVirtualScroll
ref="resultTable"
:items="filteredNotes"
:item-height="66"
:visible-height="resultsSize"
:scroll-element="scrollElement"
>
<template #default="{ items }">
<div
v-for="note in items"
:key="note.uid"
class="tile my-2"
tabindex="0"
>
<div class="tile-icon">
<BaseIcon
icon-name="mdiCodeTags"
class="pr-1"
:size="24"
/>
</div>
<div class="tile-bottom-content">
<!-- <small class="tile-subtitle">{{ query.schema }} · {{ formatDate(query.date) }}</small>
<div class="tile-history-buttons">
<button class="btn btn-link pl-1" @click.stop="$emit('select-query', query.sql)">
<BaseIcon
icon-name="mdiOpenInApp"
class="pr-1"
:size="22"
/> {{ t('general.select') }}
</button>
<button class="btn btn-link pl-1" @click="copyQuery(query.sql)">
<BaseIcon
icon-name="mdiContentCopy"
class="pr-1"
:size="22"
/> {{ t('general.copy') }}
</button>
<button class="btn btn-link pl-1" @click="deleteQuery(query)">
<BaseIcon
icon-name="mdiDeleteForever"
class="pr-1"
:size="22"
/> {{ t('general.delete') }}
</button>
</div> -->
<div class="tile-content">
<div class="tile-title">
<code
class="cut-text"
:title="note.note"
v-html="highlightWord(note.note)"
/>
</div>
<div class="tile-bottom-content">
<!-- <small class="tile-subtitle">{{ query.schema }} · {{ formatDate(query.date) }}</small>
<div class="tile-history-buttons">
<button class="btn btn-link pl-1" @click.stop="$emit('select-query', query.sql)">
<BaseIcon
icon-name="mdiOpenInApp"
class="pr-1"
:size="22"
/> {{ t('general.select') }}
</button>
<button class="btn btn-link pl-1" @click="copyQuery(query.sql)">
<BaseIcon
icon-name="mdiContentCopy"
class="pr-1"
:size="22"
/> {{ t('general.copy') }}
</button>
<button class="btn btn-link pl-1" @click="deleteQuery(query)">
<BaseIcon
icon-name="mdiDeleteForever"
class="pr-1"
:size="22"
/> {{ t('general.delete') }}
</button>
</div> -->
</div>
</div>
</div>
</div>
</template>
</BaseVirtualScroll>
</template>
</BaseVirtualScroll>
</div>
</div>
</div>
<div v-else class="empty">
<div class="empty-icon">
<BaseIcon icon-name="mdiNoteSearch" :size="48" />
<div v-else class="empty">
<div class="empty-icon">
<BaseIcon icon-name="mdiNoteSearch" :size="48" />
</div>
<p class="empty-title h5">
{{ t('application.thereAreNoNotesYet') }}
</p>
</div>
<div
class="btn btn-primary p-0 add-button p-absolute tooltip tooltip-left"
:data-tooltip="t('application.addNote')"
@click="isAddModal = true"
>
<BaseIcon
icon-name="mdiPlus"
:size="48"
/>
</div>
<p class="empty-title h5">
{{ t('application.thereIsNoNotesYet') }}
</p>
</div>
</template>
</ConfirmModal>
<ModalNewNote v-if="isAddModal" @hide="isAddModal = false" />
</template>
<script setup lang="ts">
import { ConnectionParams } from 'common/interfaces/antares';
import { storeToRefs } from 'pinia';
import {
Component,
computed,
ComputedRef,
onBeforeUnmount,
onMounted,
onUpdated,
provide,
Ref,
ref
} from 'vue';
@ -176,10 +193,10 @@ import ConfirmModal from '@/components/BaseConfirmModal.vue';
import BaseIcon from '@/components/BaseIcon.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
import { unproxify } from '@/libs/unproxify';
import ModalNewNote from '@/components/ModalNewNote.vue';
import { useApplicationStore } from '@/stores/application';
import { SidebarElement, useConnectionsStore } from '@/stores/connections';
import { useScratchpadStore } from '@/stores/scratchpad';
import { useConnectionsStore } from '@/stores/connections';
import { TagCode, useScratchpadStore } from '@/stores/scratchpad';
const { t } = useI18n();
@ -191,7 +208,6 @@ const { changeNotes } = scratchpadStore;
const { hideScratchpad } = applicationStore;
const { getConnectionName } = useConnectionsStore();
const { connections } = storeToRefs(useConnectionsStore());
const localConnections = unproxify<ConnectionParams[]>(connections.value);
const localConnection = ref(null);
const table: Ref<HTMLDivElement> = ref(null);
@ -204,7 +220,16 @@ const searchTermInterval: Ref<NodeJS.Timeout> = ref(null);
const scrollElement: Ref<HTMLDivElement> = ref(null);
const searchTerm = ref('');
const localSearchTerm = ref('');
const showArchived = ref(false);
const isAddModal = ref(false);
const isEditModal = ref(false);
const selectedTab = ref('all');
const noteTags: ComputedRef<{code: TagCode; name: string}[]> = computed(() => [
{ code: 'note', name: t('application.note') },
{ code: 'todo', name: 'TODO' },
{ code: 'query', name: 'Query' }
]);
const filteredNotes = computed(() => localNotes.value);
const connectionOptions = computed(() => {
return [
@ -213,6 +238,9 @@ const connectionOptions = computed(() => {
];
});
provide('noteTags', noteTags);
provide('connectionOptions', connectionOptions);
const resizeResults = () => {
if (resultTable.value) {
const el = tableWrapper.value.parentElement;
@ -256,3 +284,19 @@ onBeforeUnmount(() => {
});
</script>
<style lang="scss" scoped>
.add-button{
bottom: 15px;
right: 0;
border: none;
height: 48px;
width: 48px;
border-radius: 50%;
}
.archived-button {
border-radius: 50%;
width: 36px;
height: 36px;
}
</style>

View File

@ -83,12 +83,15 @@
@click="showSettingModal('general')"
>
<div class="settingbar-element-icon-wrapper">
<BaseIcon
icon-name="mdiCog"
<div
class="settingbar-element-icon text-light"
:class="{ 'badge badge-update': hasUpdates }"
:size="24"
/>
>
<BaseIcon
icon-name="mdiCog"
:size="24"
/>
</div>
</div>
</li>
</ul>
@ -262,7 +265,7 @@ if (!connectionsArr.value.length)
.settingbar-element-icon {
&.badge::after {
top: 10px;
right: -6px;
right: -3px;
position: absolute;
}

View File

@ -76,9 +76,11 @@ export const enUS = {
singleFile: 'Single {ext} file',
zipCompressedFile: 'ZIP compressed {ext} file',
copyName: 'Copy name',
search: 'Search'
search: 'Search',
title: 'Title'
},
connection: { // Database connection
connection: 'Connection',
connectionName: 'Connection name',
hostName: 'Host name',
client: 'Client',
@ -385,7 +387,11 @@ export const enUS = {
wrongFileFormat: 'Wrong file format',
dataImportSuccess: 'Data successfully imported',
note: 'Note | Notes',
thereIsNoNotesYet: 'There is no notes yet'
thereAreNoNotesYet: 'There are no notes yet',
addNote: 'Add note',
showArchivedNotes: 'Show archived notes',
hideArchivedNotes: 'Hide archived notes',
tag: 'Tag' // Note tag
},
faker: { // Faker.js methods, used in random generated content
address: 'Address',

View File

@ -2,10 +2,13 @@ import * as Store from 'electron-store';
import { defineStore } from 'pinia';
const persistentStore = new Store({ name: 'notes' });
export type TagCode = 'all' | 'note' | 'todo' | 'query'
export interface ConnectionNote {
uid: string;
cUid: string;
cUid: string | null;
title?: string;
type: TagCode;
note: string;
date: Date;
}
@ -15,7 +18,7 @@ export const useScratchpadStore = defineStore('scratchpad', {
/** Global notes */
notes: persistentStore.get('notes', '# HOW TO SUPPORT ANTARES\n\n- [ ] Leave a star to Antares [GitHub repo](https://github.com/antares-sql/antares)\n- [ ] Send feedbacks and advices\n- [ ] Report for bugs\n- [ ] If you enjoy, share Antares with friends\n\n# ABOUT SCRATCHPAD\n\nThis is a scratchpad where you can save your **personal notes**. It supports `markdown` format, but you are free to use plain text.\nThis content is just a placeholder, feel free to clear it to make space for your notes.\n') as string,
/** Connection specific notes */
connectionNotes: persistentStore.get('connectionNotes', {}) as ConnectionNote[]
connectionNotes: persistentStore.get('connectionNotes', []) as ConnectionNote[]
}),
actions: {
changeNotes (notes: ConnectionNote[]) {