feat: add bookmark

This commit is contained in:
mildred 2019-05-21 11:46:05 +01:00 committed by Henrique Dias
parent 2bf0926824
commit a548aa7e75
11 changed files with 112 additions and 9 deletions

View File

@ -0,0 +1,5 @@
import { fetchJSON } from './utils'
export async function get () {
return await fetchJSON(`/api/context`, {})
}

View File

@ -116,6 +116,18 @@ export async function post (url, content = '', overwrite = false, onupload) {
}).finally(() => { window.onbeforeunload = null }) }).finally(() => { window.onbeforeunload = null })
} }
export function bookmark (items) {
let promises = []
for (let item of items) {
const path = removePrefix(item.path)
const url = `${path}?action=${item.bookmarked ? 'bookmark' : 'remove-bookmark'}`
promises.push(resourceAction(url, 'PATCH'))
}
return Promise.all(promises)
}
function moveCopy (items, copy = false) { function moveCopy (items, copy = false) {
let promises = [] let promises = []

View File

@ -2,6 +2,7 @@ import * as files from './files'
import * as share from './share' import * as share from './share'
import * as users from './users' import * as users from './users'
import * as settings from './settings' import * as settings from './settings'
import * as context from './context'
import search from './search' import search from './search'
import commands from './commands' import commands from './commands'
@ -11,5 +12,6 @@ export {
users, users,
settings, settings,
commands, commands,
search search,
context
} }

View File

@ -45,6 +45,7 @@
<switch-button v-show="isListing"></switch-button> <switch-button v-show="isListing"></switch-button>
<download-button v-show="showDownloadButton"></download-button> <download-button v-show="showDownloadButton"></download-button>
<upload-button v-show="showUpload"></upload-button> <upload-button v-show="showUpload"></upload-button>
<bookmark-button v-show="showBookmarkButton"></bookmark-button>
<info-button v-show="isFiles"></info-button> <info-button v-show="isFiles"></info-button>
<button v-show="isListing" @click="openSelect" :aria-label="$t('buttons.selectMultiple')" :title="$t('buttons.selectMultiple')" class="action"> <button v-show="isListing" @click="openSelect" :aria-label="$t('buttons.selectMultiple')" :title="$t('buttons.selectMultiple')" class="action">
@ -71,6 +72,7 @@ import MoveButton from './buttons/Move'
import CopyButton from './buttons/Copy' import CopyButton from './buttons/Copy'
import ShareButton from './buttons/Share' import ShareButton from './buttons/Share'
import ShellButton from './buttons/Shell' import ShellButton from './buttons/Shell'
import BookmarkButton from './buttons/Bookmark'
import {mapGetters, mapState} from 'vuex' import {mapGetters, mapState} from 'vuex'
import { logoURL } from '@/utils/constants' import { logoURL } from '@/utils/constants'
import * as api from '@/api' import * as api from '@/api'
@ -89,7 +91,8 @@ export default {
UploadButton, UploadButton,
SwitchButton, SwitchButton,
MoveButton, MoveButton,
ShellButton ShellButton,
BookmarkButton
}, },
data: function () { data: function () {
return { return {
@ -145,6 +148,9 @@ export default {
? (this.selectedCount === 1 && this.user.perm.rename) ? (this.selectedCount === 1 && this.user.perm.rename)
: this.user.perm.rename) : this.user.perm.rename)
}, },
showBookmarkButton () {
return this.isFiles && this.isListing
},
showShareButton () { showShareButton () {
return this.isFiles && (this.isListing return this.isFiles && (this.isListing
? (this.selectedCount === 1 && this.user.perm.share) ? (this.selectedCount === 1 && this.user.perm.share)

View File

@ -6,7 +6,14 @@
<span>{{ $t('sidebar.myFiles') }}</span> <span>{{ $t('sidebar.myFiles') }}</span>
</router-link> </router-link>
<div v-if="user.perm.create"> <div>
<router-link v-for="(bookmark) in bookmarks" :to="'/files'+bookmark.path" class="action" :aria-label="bookmark.name" :title="bookmark.name">
<i class="material-icons">folder</i>
<span>{{ bookmark.name }}</span>
</router-link>
</div>
<div v-if="user.perm.create" v-show="showNew">
<button @click="$store.commit('showHover', 'newDir')" class="action" :aria-label="$t('sidebar.newFolder')" :title="$t('sidebar.newFolder')"> <button @click="$store.commit('showHover', 'newDir')" class="action" :aria-label="$t('sidebar.newFolder')" :title="$t('sidebar.newFolder')">
<i class="material-icons">create_new_folder</i> <i class="material-icons">create_new_folder</i>
<span>{{ $t('sidebar.newFolder') }}</span> <span>{{ $t('sidebar.newFolder') }}</span>
@ -46,7 +53,7 @@
<span> <span>
<span v-if="disableExternal">File Browser</span> <span v-if="disableExternal">File Browser</span>
<a v-else rel="noopener noreferrer" target="_blank" href="https://github.com/filebrowser/filebrowser">File Browser</a> <a v-else rel="noopener noreferrer" target="_blank" href="https://github.com/filebrowser/filebrowser">File Browser</a>
<span> {{ version }}</span> <span> v{{ version }}</span>
</span> </span>
<span><a @click="help">{{ $t('sidebar.help') }}</a></span> <span><a @click="help">{{ $t('sidebar.help') }}</a></span>
</p> </p>
@ -62,10 +69,18 @@ export default {
name: 'sidebar', name: 'sidebar',
computed: { computed: {
...mapState([ 'user' ]), ...mapState([ 'user' ]),
...mapGetters([ 'isLogged' ]), ...mapGetters([
'isLogged',
'bookmarks',
'isFiles',
'isListing'
]),
active () { active () {
return this.$store.state.show === 'sidebar' return this.$store.state.show === 'sidebar'
}, },
showNew() {
return this.isFiles && this.isListing
},
signup: () => signup, signup: () => signup,
version: () => version, version: () => version,
disableExternal: () => disableExternal, disableExternal: () => disableExternal,

View File

@ -0,0 +1,43 @@
<template>
<button @click="toggle" :aria-label="$t('buttons.bookmark')" :title="$t('buttons.bookmark')" class="action" id="bookmark-button">
<i class="material-icons">{{ icon }}</i>
<span>{{ $t('buttons.bookmark') }}</span>
</button>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
import { files as filesApi, context as contextApi } from '@/api'
export default {
name: 'bookmark-button',
computed: {
...mapState(['req']),
icon: function () {
if (this.req.bookmarked) return 'bookmark'
return 'bookmark_border'
}
},
methods: {
...mapMutations([ 'updateBookmark', 'closeHovers' ]),
toggle: async function () {
this.closeHovers()
const data = {
path: this.req.path,
bookmarked: (this.icon === 'bookmark_border')
}
try {
await filesApi.bookmark([data])
this.updateBookmark(data)
const ctx = await contextApi.get()
this.$store.commit('updateContext', ctx)
} catch (e) {
this.$showError(e)
}
}
}
}
</script>

View File

@ -32,7 +32,8 @@
"toggleSidebar": "Toggle sidebar", "toggleSidebar": "Toggle sidebar",
"update": "Update", "update": "Update",
"upload": "Upload", "upload": "Upload",
"permalink": "Get Permanent Link" "permalink": "Get Permanent Link",
"bookmark": "Bookmark"
}, },
"success": { "success": {
"linkCopied": "Link copied!" "linkCopied": "Link copied!"

View File

@ -3,7 +3,8 @@ const getters = {
isFiles: state => !state.loading && state.route.name === 'Files', isFiles: state => !state.loading && state.route.name === 'Files',
isListing: (state, getters) => getters.isFiles && state.req.isDir, isListing: (state, getters) => getters.isFiles && state.req.isDir,
isEditor: (state, getters) => getters.isFiles && (state.req.type === 'text' || state.req.type === 'textImmutable'), isEditor: (state, getters) => getters.isFiles && (state.req.type === 'text' || state.req.type === 'textImmutable'),
selectedCount: state => state.selected.length selectedCount: state => state.selected.length,
bookmarks: state => state.context.bookmarks
} }
export default getters export default getters

View File

@ -8,6 +8,7 @@ Vue.use(Vuex)
const state = { const state = {
user: null, user: null,
req: {}, req: {},
context: {},
oldReq: {}, oldReq: {},
clipboard: { clipboard: {
key: '', key: '',

View File

@ -71,10 +71,18 @@ const mutations = {
state.user[field] = value[field] state.user[field] = value[field]
} }
}, },
updateBookmark: (state, value) => {
if (value.path === state.req.path) {
state.req.bookmarked = value.bookmarked
}
},
updateRequest: (state, value) => { updateRequest: (state, value) => {
state.oldReq = state.req state.oldReq = state.req
state.req = value state.req = value
}, },
updateContext: (state, value) => {
state.context = value
},
updateClipboard: (state, value) => { updateClipboard: (state, value) => {
state.clipboard.key = value.key state.clipboard.key = value.key
state.clipboard.items = value.items state.clipboard.items = value.items

View File

@ -19,6 +19,7 @@ import Sidebar from '@/components/Sidebar'
import Prompts from '@/components/prompts/Prompts' import Prompts from '@/components/prompts/Prompts'
import SiteHeader from '@/components/Header' import SiteHeader from '@/components/Header'
import Shell from '@/components/Shell' import Shell from '@/components/Shell'
import { context as api } from '@/api'
export default { export default {
name: 'layout', name: 'layout',
@ -38,6 +39,14 @@ export default {
this.$store.commit('multiple', false) this.$store.commit('multiple', false)
if (this.$store.state.show !== 'success') this.$store.commit('closeHovers') if (this.$store.state.show !== 'success') this.$store.commit('closeHovers')
} }
},
async created() {
try {
const res = await api.get()
this.$store.commit('updateContext', res)
} catch (e) {
this.$showError(e)
}
} }
} }
</script> </script>