Skip to content

Commit 1ec0f5a

Browse files
committed
Category: Add new category button to create new folders in current
notes path for categories. Signed-off-by: Jonathan Pagel <jonny_tischbein@systemli.org>
1 parent 1736b4e commit 1ec0f5a

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"stylelint:fix": "stylelint 'src/**/*.vue' 'css/**/*.css' --fix"
1414
},
1515
"dependencies": {
16+
"@nextcloud/auth": "^2.0.0",
1617
"@nextcloud/axios": "^2.3.0",
1718
"@nextcloud/dialogs": "^4.0.1",
1819
"@nextcloud/event-bus": "^3.0.2",

src/NotesService.js

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import axios from '@nextcloud/axios'
2-
import { generateUrl } from '@nextcloud/router'
2+
import { getCurrentUser } from '@nextcloud/auth'
3+
import { generateUrl, generateRemoteUrl } from '@nextcloud/router'
34
import { showError } from '@nextcloud/dialogs'
45

56
import store from './store.js'
@@ -338,6 +339,40 @@ export const setFavorite = (noteId, favorite) => {
338339
})
339340
}
340341

342+
export const findCategory = (categoryName) => {
343+
return axios
344+
.get(generateRemoteUrl(`dav/files/${getCurrentUser().uid}/${store.state.app.settings.notesPath}${categoryName}`))
345+
.then(response => {
346+
return categoryName
347+
})
348+
.catch(err => {
349+
if (err?.response?.status === 404) {
350+
return false
351+
} else {
352+
console.error(err)
353+
handleSyncError(t('notes', 'Fetching category {name} has failed.', { name: categoryName }), err)
354+
throw err
355+
}
356+
})
357+
}
358+
359+
export const createCategory = (categoryName) => {
360+
// Axios MKCOL workaround: https://github.com/axios/axios/issues/2220
361+
return axios
362+
.request({
363+
url: generateRemoteUrl(`dav/files/${getCurrentUser().uid}/${store.state.app.settings.notesPath}${categoryName}`),
364+
method: 'MKCOL',
365+
})
366+
.then(response => {
367+
return categoryName
368+
})
369+
.catch(err => {
370+
console.error(err)
371+
handleSyncError(t('notes', 'Creating new category {name} has failed.', { name: categoryName }), err)
372+
throw err
373+
})
374+
}
375+
341376
export const setCategory = (noteId, category) => {
342377
return axios
343378
.put(url('/notes/' + noteId + '/category'), { category })

src/components/NavigationCategoriesItem.vue

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,32 @@
44
class="app-navigation-noclose separator-below"
55
:class="{ 'category-header': selectedCategory !== null }"
66
:open.sync="open"
7+
:menu-open.sync="menuOpen"
78
:allow-collapse="true"
89
@click.prevent.stop="onToggleCategories"
910
>
11+
<template #menu-icon>
12+
<AddIcon :size="20" @click="onToggleNewCategory" />
13+
</template>
14+
<template #actions>
15+
<NcActionText>
16+
<template #icon>
17+
<ErrorIcon v-if="createCategoryError" :size="20" />
18+
<AddIcon v-else-if="!createCategoryError" :size="20" />
19+
</template>
20+
{{ createCategoryError ? createCategoryError : t('notes', 'Create a new category') }}
21+
</NcActionText>
22+
<NcActionInput
23+
icon=""
24+
:value="t('notes', 'Category name')"
25+
@submit.prevent.stop="createNewCategory"
26+
>
27+
<template #icon>
28+
<FolderIcon :size="20" />
29+
</template>
30+
</NcActionInput>
31+
</template>
32+
1033
<FolderIcon slot="icon" :size="20" />
1134
<NcAppNavigationItem
1235
:title="t('notes', 'All notes')"
@@ -34,15 +57,19 @@
3457

3558
<script>
3659
import {
60+
NcActionInput,
61+
NcActionText,
3762
NcAppNavigationItem,
3863
NcAppNavigationCounter,
3964
} from '@nextcloud/vue'
4065
4166
import FolderIcon from 'vue-material-design-icons/Folder.vue'
4267
import FolderOutlineIcon from 'vue-material-design-icons/FolderOutline.vue'
4368
import HistoryIcon from 'vue-material-design-icons/History.vue'
69+
import AddIcon from 'vue-material-design-icons/Plus.vue'
70+
import ErrorIcon from 'vue-material-design-icons/AlertCircle.vue'
4471
45-
import { getCategories } from '../NotesService.js'
72+
import { createCategory, findCategory, getCategories } from '../NotesService.js'
4673
import { categoryLabel } from '../Util.js'
4774
import store from '../store.js'
4875
@@ -53,6 +80,10 @@ export default {
5380
FolderIcon,
5481
FolderOutlineIcon,
5582
HistoryIcon,
83+
AddIcon,
84+
ErrorIcon,
85+
NcActionInput,
86+
NcActionText,
5687
NcAppNavigationItem,
5788
NcAppNavigationCounter,
5889
},
@@ -67,6 +98,8 @@ export default {
6798
data() {
6899
return {
69100
open: false,
101+
menuOpen: false,
102+
createCategoryError: null,
70103
}
71104
},
72105
@@ -93,10 +126,34 @@ export default {
93126
this.open = !this.open
94127
},
95128
129+
onToggleNewCategory() {
130+
this.menuOpen = !this.menuOpen
131+
},
132+
96133
onSelectCategory(category) {
97134
this.open = false
98135
this.$emit('category-selected', category)
99136
},
137+
138+
createNewCategory(event) {
139+
const input = event.target.querySelector('input[type=text]')
140+
const categoryName = input.value.trim()
141+
142+
// Check if already exists
143+
findCategory(categoryName).then(data => {
144+
if (data !== false) {
145+
this.createCategoryError = t('notes', 'This category already exists')
146+
return
147+
}
148+
149+
// Create new directory for category in current notes path defined in settings
150+
createCategory(categoryName)
151+
this.createCategoryError = null
152+
this.onToggleNewCategory()
153+
this.onSelectCategory(categoryName)
154+
})
155+
156+
},
100157
},
101158
}
102159
</script>

0 commit comments

Comments
 (0)