Skip to content
Prev Previous commit
Next Next commit
feat: add tags, api methods & actions
  • Loading branch information
antonreshetov committed Apr 7, 2022
commit 79362891edabd9d7874b1ed294bba4df6a9cf8ad
28 changes: 24 additions & 4 deletions src/main/services/api/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { store } from '../../store'
import { nanoid } from 'nanoid'
import { API_PORT } from '../../config'
import path from 'path'
import type { DB, Snippet } from '@shared/types/main/db'
import type { DB, Snippet, Tag } from '@shared/types/main/db'
import { remove } from 'lodash'

export const createApiServer = () => {
const db = path.resolve(store.preferences.get('storagePath') + '/db.json')
Expand Down Expand Up @@ -35,12 +36,31 @@ export const createApiServer = () => {
}
})

app.delete('/tags/:id', (req, res) => {
const id = req.params.id
const tags = router.db.get<Tag[]>('tags').value()
const snippets = router.db
.get<Snippet[]>('snippets')
.filter(i => i.tagsIds.includes(id))
.value()
const index = tags.findIndex(i => i.id === id)

snippets.forEach(i => {
remove(i.tagsIds, item => item === id)
})

tags.splice(index, 1)
router.db.write()

res.sendStatus(200)
})

app.get('/tags/:id/snippets', (req, res) => {
const id = req.params.id
const snippets = router.db.get<Snippet[]>('snippets').value()
const founded = snippets.filter(i => i.tagsIds.includes(id))
const _snippets = router.db.get<Snippet[]>('snippets').value()
const snippets = _snippets.filter(i => i.tagsIds.includes(id))

res.status(200).send(founded)
res.status(200).send(snippets)
})

app.use((req, res, next) => {
Expand Down
50 changes: 47 additions & 3 deletions src/main/services/ipc/context-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,13 @@ export const subscribeToContextMenu = () => {
)

ipcMain.handle<ContextMenuPayload, ContextMenuResponse>(
'context-menu:folder',
'context-menu:library',
async (event, payload) => {
const { name, type, data } = payload

return new Promise(resolve => {
const menu = createPopupMenu([])

const createLanguageMenu = () => {
return languages.map(i => {
return {
Expand All @@ -198,7 +200,7 @@ export const subscribeToContextMenu = () => {
}) as MenuItemConstructorOptions[]
}

const menu = createPopupMenu([
const folderMenu: MenuItemConstructorOptions[] = [
{
label: 'New folder',
click: () => {
Expand Down Expand Up @@ -241,7 +243,49 @@ export const subscribeToContextMenu = () => {
label: 'Default Language',
submenu: createLanguageMenu()
}
])
]

const tagMenu: MenuItemConstructorOptions[] = [
{
label: 'Delete',
click: () => {
const buttonId = dialog.showMessageBoxSync({
message: `Are you sure you want to delete "${name}"?`,
detail:
'This will also cause all snippets to have that tag removed.',
buttons: ['Delete', 'Cancel'],
defaultId: 0,
cancelId: 1
})

if (buttonId === 0) {
resolve({
action: 'delete',
type,
data: undefined
})
} else {
resolve({
action: 'none',
type,
data: undefined
})
}
}
}
]

if (type === 'folder') {
folderMenu.forEach(i => {
menu.append(new MenuItem(i))
})
}

if (type === 'tag') {
tagMenu.forEach(i => {
menu.append(new MenuItem(i))
})
}

menu.on('menu-will-close', () => {
BrowserWindow.getFocusedWindow()?.webContents.send(
Expand Down
49 changes: 42 additions & 7 deletions src/renderer/components/sidebar/SidebarListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
:class="{
'is-selected': isSelected,
'is-focused': isFocused,
'is-system': system,
'is-system': isSystem,
'is-tag': isTag
}"
@click="isFocused = true"
Expand Down Expand Up @@ -33,39 +33,46 @@ import { onClickOutside } from '@vueuse/core'
import { ipc } from '@/electron'
import type {
ContextMenuPayload,
ContextMenuResponse
ContextMenuResponse,
ContextMenuType
} from '@shared/types/main'
import { useFolderStore } from '@/store/folders'
import { useTagStore } from '@/store/tags'
import type { FolderTree } from '@shared/types/main/db'
import { useSnippetStore } from '@/store/snippets'

interface Props {
id?: string
icon?: FunctionalComponent
system?: boolean
isSystem?: boolean
nested?: boolean
open?: boolean
isSelected?: boolean
isTag?: boolean
isFolder?: boolean
model?: FolderTree
alias?: ContextMenuType
name?: string
}

const props = withDefaults(defineProps<Props>(), {
system: false,
nested: false,
open: false
})

const folderStore = useFolderStore()
const snippetStore = useSnippetStore()
const tagStore = useTagStore()

const isFocused = ref(false)
const itemRef = ref()

const onClickContextMenu = async () => {
if (props.id) {
if (props.isFolder) {
const { action, type, data } = await ipc.invoke<
ContextMenuResponse,
ContextMenuPayload
>('context-menu:folder', {
>('context-menu:library', {
name: props.model?.name,
type: 'folder',
data: JSON.parse(JSON.stringify(props.model))
Expand All @@ -82,7 +89,35 @@ const onClickContextMenu = async () => {

if (action === 'update:language') {
console.log(data)
await folderStore.patchFoldersById(props.id, { defaultLanguage: data })
await folderStore.patchFoldersById(props.id!, { defaultLanguage: data })
}
}

if (props.isTag) {
const { action, type, data } = await ipc.invoke<
ContextMenuResponse,
ContextMenuPayload
>('context-menu:library', {
name: props.name,
type: 'tag',
data: {}
})

if (action === 'delete') {
await tagStore.deleteTagById(props.id!)

if (props.id === tagStore.selectedId) {
tagStore.selectedId = undefined
}

if (tagStore.tags.length) {
const firstTagId = tagStore.tags[0].id
tagStore.selectedId = firstTagId
snippetStore.setSnippetsByTagId(firstTagId)
} else {
snippetStore.selected = undefined
snippetStore.snippets = []
}
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion src/renderer/components/sidebar/TheSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
v-for="i in systemFolders"
:key="i.name"
:icon="i.icon"
:system="true"
:is-system="true"
:alias="i.alias"
:is-selected="i.alias === folderStore.selectedAlias"
@click="onClickSystemFolder(i.alias)"
>
Expand All @@ -20,7 +21,9 @@
<template v-if="activeTab === 'tags'">
<SidebarListItem
v-for="i in tagStore.tags"
:id="i.id"
:key="i.id"
:name="i.name"
:icon="LabelAlt"
:is-tag="true"
:is-selected="i.id === tagStore.selectedId"
Expand Down Expand Up @@ -48,6 +51,7 @@
<template #default="{ node }">
<SidebarListItem
:id="node.id"
:is-folder="true"
:model="node"
@drop="onDrop($event, node.id)"
@dragover.prevent
Expand Down Expand Up @@ -184,11 +188,15 @@ watch(
snippetStore.setSnippetsByAlias(folderStore.selectedAlias)
} else {
await snippetStore.setSnippetsByFolderIds(true)
return
}
}

if (v === 'tags' && tagStore.selectedId) {
snippetStore.setSnippetsByTagId(tagStore.selectedId)
} else {
snippetStore.snippets = []
snippetStore.selected = undefined
}
}
)
Expand Down
1 change: 1 addition & 0 deletions src/renderer/components/snippets/SnippetHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
</div>
<div class="bottom">
<SnippetFragments v-if="snippetStore.isFragmentsShow" />
<SnippetsTags v-if="snippetStore.isTagsShow" />
</div>
</div>
</template>
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/components/snippets/SnippetListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import type {
import { onClickOutside } from '@vueuse/core'
import { computed, ref } from 'vue'
import type { SystemFolderAlias } from '@shared/types/renderer/sidebar'
import { useTagStore } from '@/store/tags'

interface Props {
id: string
Expand All @@ -55,6 +56,7 @@ const props = defineProps<Props>()

const snippetStore = useSnippetStore()
const folderStore = useFolderStore()
const tagStore = useTagStore()

const itemRef = ref()
const isFocused = ref(false)
Expand Down Expand Up @@ -100,6 +102,7 @@ const onClickSnippet = (e: MouseEvent) => {
snippetStore.fragment = 0
snippetStore.selectedMultiple = []
snippetStore.getSnippetsById(props.id)
tagStore.getTags()
}
}

Expand Down
61 changes: 61 additions & 0 deletions src/renderer/components/snippets/SnippetsTags.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<template>
<div class="tags">
<AppInputTags v-model="tags" />
</div>
</template>

<script setup lang="ts">
import { useAppStore } from '@/store/app'
import { useSnippetStore } from '@/store/snippets'
import { useTagStore } from '@/store/tags'
import { computed } from 'vue'

const tagStore = useTagStore()
const snippetStore = useSnippetStore()
const appStore = useAppStore()

const tags = computed({
get: () => snippetStore.currentTags.map(i => i.name),
set: async (v: any) => {
const tagsIds: string[] = []

for (const i of v) {
const tag = tagStore.tags.find(t => t.name === i.text)

if (tag) {
tagsIds.push(tag.id)
} else {
if (!i.text) return

const newTag = await tagStore.postTags(i.text)
await tagStore.getTags()

tagsIds.push(newTag.id)

if (snippetStore.selected?.tags) {
snippetStore.selected.tags.push(newTag)
} else {
snippetStore.selected!.tags = [newTag]
}
}
}

snippetStore.selected!.tagsIds = tagsIds

await snippetStore.patchSnippetsById(snippetStore.selectedId!, {
tagsIds
})
}
})

const tagsHeight = appStore.sizes.editor.tagsHeight + 'px'
</script>

<style lang="scss" scoped>
.tags {
height: v-bind(tagsHeight);
padding: 0 var(--spacing-xs);
display: flex;
align-items: center;
}
</style>
Loading