This is an automated email from the git hooks/post-receive script. New commit to branch bow-v2-go in repository bow. See https://gitlab.nuiton.org/chorem/bow.git commit 24cee2c478783491c6cdb2c176649b04c8615e27 Author: Benjamin <poussin@codelutin.com> Date: Mon May 18 02:13:29 2020 +0200 ajout de l'edition des tags --- pkg/http/router.go | 1 + pkg/repository/bookmarkRepository.go | 18 +++- web/package.json | 1 + web/src/components/preferences/TagsEditor.vue | 146 ++++++++++++++++++++++++++ web/src/views/Preferences.vue | 4 +- web/yarn.lock | 9 +- 6 files changed, 175 insertions(+), 4 deletions(-) diff --git a/pkg/http/router.go b/pkg/http/router.go index 33d0fea..a97d2e1 100644 --- a/pkg/http/router.go +++ b/pkg/http/router.go @@ -64,6 +64,7 @@ func Start(bowPublicURL string, addr string) { s.HandleFunc("/bookmarks", addBookmark).Methods(http.MethodPost, http.MethodOptions) s.HandleFunc("/bookmarks/tags", getTags).Methods(http.MethodGet, http.MethodOptions) s.HandleFunc("/bookmarks/tags/{oldName}/{newName}", renameTag).Methods(http.MethodPut, http.MethodOptions) + s.HandleFunc("/bookmarks/tags/{oldName}", renameTag).Methods(http.MethodDelete, http.MethodOptions) s.HandleFunc("/bookmarks/{id}", getBookmark).Methods(http.MethodGet, http.MethodOptions) s.HandleFunc("/bookmarks/{id}", deleteBookmark).Methods(http.MethodDelete, http.MethodOptions) s.HandleFunc("/bookmarks/{id}", updateBookmark).Methods(http.MethodPut, http.MethodOptions) diff --git a/pkg/repository/bookmarkRepository.go b/pkg/repository/bookmarkRepository.go index 750a741..64eac14 100644 --- a/pkg/repository/bookmarkRepository.go +++ b/pkg/repository/bookmarkRepository.go @@ -58,10 +58,22 @@ func BookmarkJSON(currentUser model.BowUser, id string, uri string, tags string, return result, nil } +/* +RenameTag renomme ou supprime un tag si newName est vide +*/ func RenameTag(currentUser model.BowUser, oldName string, newName string) (int64, error) { tagArray := "{" + oldName + "}" - q := &query{sql: `UPDATE bookmark SET tags=array_replace(tags, '$2, $3) where tags @> $1::text[]`} - count, err := q.execOnNRow(currentUser, tagArray, oldName, newName) + + var q *query + var count int64 + var err error + if newName == "" { + q = &query{sql: `UPDATE bookmark SET tags=array_remove(tags, $2) where tags @> $1::text[]`} + count, err = q.execOnNRow(currentUser, tagArray, oldName) + } else { + q = &query{sql: `UPDATE bookmark SET tags=array_replace(tags, $2, $3) where tags @> $1::text[]`} + count, err = q.execOnNRow(currentUser, tagArray, oldName, newName) + } if err != nil { return 0, utils.NewHTTPError500(err, currentUser) } @@ -72,6 +84,8 @@ func RenameTag(currentUser model.BowUser, oldName string, newName string) (int64 /* TagsJSON retourne la liste des tags qui match le filtre le format de retour est celui d'opensearch +si on demande avec le count, on a un tableau de tag, suivi du tableau du nombre d'occurence de ce tag: +[["tag1", "tag2", ...], [12, 34, ...]] */ func TagsJSON(currentUser model.BowUser, filter string, withCount bool) (string, error) { var q *query diff --git a/web/package.json b/web/package.json index e265de3..2bb54f5 100644 --- a/web/package.json +++ b/web/package.json @@ -8,6 +8,7 @@ "lint": "vue-cli-service lint" }, "dependencies": { + "@johmun/vue-tags-input": "^2.1.0", "core-js": "^3.6.4", "vue": "^2.6.11", "vue-property-decorator": "^8.4.1", diff --git a/web/src/components/preferences/TagsEditor.vue b/web/src/components/preferences/TagsEditor.vue new file mode 100644 index 0000000..3199a4f --- /dev/null +++ b/web/src/components/preferences/TagsEditor.vue @@ -0,0 +1,146 @@ +<template> + <div class="tags-editor"> + <label for="oldTags">Replace</label + ><vue-tags-input + id="oldTags" + v-model="oldName" + :tags="oldTags" + @tags-changed="(t) => (oldTags = t)" + :add-only-from-autocomplete="true" + :max-tags="1" + :autocomplete-items="filteredOldTags" + :add-on-key="key" + :save-on-key="key" + > + <template #tag-right="{ tag }"> + ({{ tag.count }}) + </template> + </vue-tags-input> + <label for="newTags">with</label + ><vue-tags-input + id="newTags" + v-model="newName" + :tags="newTags" + @tags-changed="(t) => (newTags = t)" + :max-tags="1" + :autocomplete-items="filteredNewTags" + :add-on-key="key" + :save-on-key="key" + /> + <button class="replace" @click.prevent="doAction">replace</button> + <span class="errorMsg">{{ errorMsg }}</span> + </div> +</template> + +<script> +import { Component, Vue } from 'vue-property-decorator' +import VueTagsInput from '@johmun/vue-tags-input' + +@Component({ + name: 'TagsEditor', + components: { VueTagsInput } +}) +class TagsEditor extends Vue { + errorMsg = '' + + key = [13, ',', ';', ' ', '\t'] + + tags = [] + + oldName = '' + oldTags = [] + newName = '' + newTags = [] + + get filteredOldTags() { + return this.filteredTags(this.oldName) + } + + get filteredNewTags() { + return this.filteredTags(this.newName) + } + + filteredTags(tag) { + let lowerCased = tag.toLowerCase() + console.log('XXXXX', tag, lowerCased) + return this.tags.filter((a) => { + return a.text.toLowerCase().indexOf(lowerCased) !== -1 + }) + } + + doAction() { + if (this.newTags[0]) { + this.doReplace() + } else { + this.doDelete() + } + } + + doReplace() { + let oldName = this.oldTags[0].text + let newName = this.newTags[0].text + this.$fetch.put(`/bookmarks/tags/${oldName}/${newName}`).then( + (data) => { + this.errorMsg = `renamed ${oldName}(${data.count}) -> ${newName}` + this.oldName = '' + this.newName = '' + this.oldTags = [] + this.newTags = [] + // on recharge pour avoir le nouveau tag et le bon count + this.load() + }, + (err) => { + console.log('ko', err) + this.errorMsg = err.cause + } + ) + } + + doDelete() { + let oldName = this.oldTags[0].text + this.$fetch.delete(`/bookmarks/tags/${oldName}`).then( + (data) => { + this.errorMsg = `deleted ${oldName}(${data.count})` + this.oldName = '' + this.newName = '' + this.oldTags = [] + this.newTags = [] + // on recharge pour avoir le bon count + this.load() + }, + (err) => { + console.log('ko', err) + this.errorMsg = err.cause + } + ) + } + + load() { + this.$fetch.get('/bookmarks/tags?with-count=true').then( + (tags) => { + console.log('ok', tags) + this.tags = tags[0].map((text, i) => { + return {text, count: tags[1][i]} + }) + }, + (err) => { + console.log('ko', err) + this.errorMsg = err.cause + } + ) + } + + beforeMount() { + this.load() + } +} + +export default TagsEditor +</script> + +<style scoped lang="less"> +.tags-editor { + display: flex; + flex-direction: row; +} +</style> diff --git a/web/src/views/Preferences.vue b/web/src/views/Preferences.vue index 249c824..b957322 100644 --- a/web/src/views/Preferences.vue +++ b/web/src/views/Preferences.vue @@ -4,6 +4,7 @@ <a :href="bookmarkletAdd">bookmarklet add</a> <MaxResultEditor :user="user"></MaxResultEditor> <Actions :actions="user.actions"></Actions> + <TagsEditor></TagsEditor> </div> </template> @@ -12,10 +13,11 @@ import { Component, Vue } from 'vue-property-decorator' import MaxResultEditor from '@/components/preferences/MaxResultEditor' import Actions from '@/components/preferences/Actions' +import TagsEditor from '@/components/preferences/TagsEditor' @Component({ name: 'Preferences', - components: {MaxResultEditor, Actions} + components: {MaxResultEditor, Actions, TagsEditor} }) class Preferences extends Vue { errorMsg = '' diff --git a/web/yarn.lock b/web/yarn.lock index eff5d5d..f9561a4 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -837,6 +837,13 @@ cssnano-preset-default "^4.0.0" postcss "^7.0.0" +"@johmun/vue-tags-input@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@johmun/vue-tags-input/-/vue-tags-input-2.1.0.t..." + integrity sha512-Fdwfss/TqCqMJbGAkmlzKbcG/ia1MstYjhqPBj+zG7h/166tIcE1TIftUxhT9LZ+RWjRSG0EFA1UyaHQSr3k3Q== + dependencies: + vue "^2.6.10" + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2..." @@ -8017,7 +8024,7 @@ vue-template-es2015-compiler@^1.9.0: resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2..." integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw== -vue@^2.6.11: +vue@^2.6.10, vue@^2.6.11: version "2.6.11" resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35..." integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ== -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.