feat: ability to edit notes

This commit is contained in:
Fabio Di Stasio 2023-12-21 18:10:51 +01:00
parent eaaf1b756a
commit 08e5a13f72
6 changed files with 167 additions and 12 deletions

View File

@ -0,0 +1,116 @@
<template>
<ConfirmModal
size="medium"
:disable-autofocus="true"
:close-on-confirm="!!localNote.note.length"
:confirm-text="t('general.save')"
@confirm="updateNote"
@hide="$emit('hide')"
>
<template #header>
<div class="d-flex">
<BaseIcon
icon-name="mdiNoteEditOutline"
class="mr-1"
:size="24"
/> {{ t('application.editNote') }}
</div>
</template>
<template #body>
<form class="form">
<div class="form-group columns">
<div class="column col-8">
<label class="form-label">{{ t('connection.connection') }}</label>
<BaseSelect
v-model="localNote.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="localNote.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
v-model="localNote.note"
:mode="editorMode"
:show-line-numbers="false"
/>
</div>
</form>
</template>
</ConfirmModal>
</template>
<script lang="ts" setup>
import { inject, onBeforeMount, PropType, 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, useScratchpadStore } from '@/stores/scratchpad';
const { t } = useI18n();
const { editNote } = useScratchpadStore();
const emit = defineEmits(['hide']);
const props = defineProps({
note: {
type: Object as PropType<ConnectionNote>,
required: true
}
});
const noteTags = inject<{code: TagCode; name: string}[]>('noteTags');
const connectionOptions = inject<{code: string; name: string}[]>('connectionOptions');
const editorMode = ref('markdown');
const localNote: Ref<ConnectionNote> = ref({
uid: 'dummy',
cUid: null,
title: undefined,
note: '',
date: new Date(),
type: 'note',
isArchived: false
});
const updateNote = () => {
if (localNote.value.note) {
if (!localNote.value.title)// Set a default title
localNote.value.title = `${localNote.value.type.toLocaleUpperCase()}: ${localNote.value.uid}`;
localNote.value.date = new Date();
editNote(localNote.value);
emit('hide');
}
};
watch(() => localNote.value.type, () => {
if (localNote.value.type === 'query')
editorMode.value = 'sql';
else
editorMode.value = 'markdown';
});
onBeforeMount(() => {
localNote.value = props.note;
});
</script>

View File

@ -3,6 +3,7 @@
size="medium"
:disable-autofocus="true"
:close-on-confirm="!!newNote.note.length"
:confirm-text="t('general.save')"
@confirm="createNote"
@hide="$emit('hide')"
>

View File

@ -30,7 +30,8 @@
<div class="tile-content-message" :class="[{'opened': isSelected}]">
<code
v-if="note.type === 'query'"
class="cut-text"
ref="noteParagraph"
class="tile-paragraph"
v-html="highlightWord(note.note)"
/>
<div
@ -47,7 +48,7 @@
<button
v-if="note.type === 'todo' && !note.isArchived"
class="btn btn-link pl-1"
@click="$emit('archive-note', note.uid)"
@click.stop="$emit('archive-note', note.uid)"
>
<BaseIcon
icon-name="mdiCheck"
@ -58,7 +59,7 @@
<button
v-if="note.type === 'todo' && note.isArchived"
class="btn btn-link pl-1"
@click="$emit('restore-note', note.uid)"
@click.stop="$emit('restore-note', note.uid)"
>
<BaseIcon
icon-name="mdiRestore"
@ -69,7 +70,7 @@
<button
v-if="note.type === 'query'"
class="btn btn-link pl-1"
@click="copyText(note.note)"
@click.stop="copyText(note.note)"
>
<BaseIcon
icon-name="mdiContentCopy"
@ -80,7 +81,7 @@
<button
v-if=" !note.isArchived"
class="btn btn-link pl-1"
@click="null"
@click.stop="$emit('edit-note')"
>
<BaseIcon
icon-name="mdiPencil"
@ -88,7 +89,7 @@
:size="22"
/> {{ t('general.edit') }}
</button>
<button class="btn btn-link pl-1" @click="$emit('delete-note', note.uid)">
<button class="btn btn-link pl-1" @click.stop="$emit('delete-note', note.uid)">
<BaseIcon
icon-name="mdiDeleteForever"
class="pr-1"
@ -131,7 +132,14 @@ const { t } = useI18n();
const { formatDate } = useFilters();
const { getConnectionName } = useConnectionsStore();
defineEmits(['delete-note', 'select-note', 'toggle-note', 'archive-note', 'restore-note']);
defineEmits([
'edit-note',
'delete-note',
'select-note',
'toggle-note',
'archive-note',
'restore-note'
]);
const noteParagraph: Ref<HTMLDivElement> = ref(null);
const noteHeight = ref(useElementBounding(noteParagraph)?.height);
@ -188,7 +196,7 @@ const highlightWord = (string: string) => {
right: 2px;
top: 0px;
opacity: .7;
z-index: 9;
z-index: 2;
}
.tile-icon {
@ -233,13 +241,14 @@ const highlightWord = (string: string) => {
}
}
code {
code, pre {
max-width: 100%;
display: inline-block;
font-size: 100%;
// color: $primary-color;
opacity: 0.8;
font-weight: 600;
white-space: break-spaces;
}
.tile-subtitle {

View File

@ -109,6 +109,7 @@
:selected-note="selectedNote"
@select-note="selectedNote = note.uid"
@toggle-note="toggleNote"
@edit-note="startEditNote(note)"
@delete-note="deleteNote"
@archive-note="archiveNote"
@restore-note="restoreNote"
@ -139,7 +140,12 @@
</div>
</div>
</Teleport>
<ModalNewNote v-if="isAddModal" @hide="isAddModal = false" />
<ModalNoteNew v-if="isAddModal" @hide="isAddModal = false" />
<ModalNoteEdit
v-if="isEditModal"
:note="noteToEdit"
@hide="closeEditModal"
/>
</template>
<script setup lang="ts">
@ -161,11 +167,12 @@ import { useI18n } from 'vue-i18n';
import BaseIcon from '@/components/BaseIcon.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
import ModalNewNote from '@/components/ModalNewNote.vue';
import ModalNoteEdit from '@/components/ModalNoteEdit.vue';
import ModalNoteNew from '@/components/ModalNoteNew.vue';
import ScratchpadNote from '@/components/ScratchpadNote.vue';
import { useApplicationStore } from '@/stores/application';
import { useConnectionsStore } from '@/stores/connections';
import { TagCode, useScratchpadStore } from '@/stores/scratchpad';
import { ConnectionNote, TagCode, useScratchpadStore } from '@/stores/scratchpad';
import { useWorkspacesStore } from '@/stores/workspaces';
const { t } = useI18n();
@ -194,6 +201,7 @@ const localSearchTerm = ref('');
const showArchived = ref(false);
const isAddModal = ref(false);
const isEditModal = ref(false);
const noteToEdit: Ref<ConnectionNote> = ref(null);
const selectedTag = ref('all');
const selectedNote = ref(null);
@ -241,6 +249,11 @@ const toggleNote = (uid: string) => {
selectedNote.value = selectedNote.value !== uid ? uid : null;
};
const startEditNote = (note: ConnectionNote) => {
isEditModal.value = true;
noteToEdit.value = note;
};
const archiveNote = (uid: string) => {
const remappedNotes = connectionNotes.value.map(n => {
if (n.uid === uid)
@ -264,6 +277,11 @@ const deleteNote = (uid: string) => {
changeNotes(otherNotes);
};
const closeEditModal = () => {
isEditModal.value = false;
noteToEdit.value = null;
};
watch(searchTerm, () => {
clearTimeout(searchTermInterval.value);
@ -310,6 +328,7 @@ onBeforeUnmount(() => {
position: fixed;
margin-top: -40px;
margin-left: 580px;
z-index: 9;
}
.archived-button {
border-radius: 50%;

View File

@ -391,6 +391,7 @@ export const enUS = {
note: 'Note | Notes',
thereAreNoNotesYet: 'There are no notes yet',
addNote: 'Add note',
editNote: 'Edit note',
showArchivedNotes: 'Show archived notes',
hideArchivedNotes: 'Hide archived notes',
tag: 'Tag' // Note tag

View File

@ -32,6 +32,15 @@ export const useScratchpadStore = defineStore('scratchpad', {
...this.connectionNotes
];
persistentStore.set('connectionNotes', this.connectionNotes);
},
editNote (note: ConnectionNote) {
this.connectionNotes = (this.connectionNotes as ConnectionNote[]).map(n => {
if (n.uid === note.uid)
n = note;
return n;
});
persistentStore.set('connectionNotes', this.connectionNotes);
}
}
});