bookmarks/src/components/SidebarFolder.vue

264 lines
7.8 KiB
Vue
Raw Normal View History

<template>
<AppSidebar
2020-03-30 15:20:01 +00:00
v-if="isActive"
class="sidebar"
:title="folder.title"
@close="onClose">
2020-04-02 15:25:14 +00:00
<AppSidebarTab id="folder-details" :name="t('bookmarks', 'Details')" icon="icon-info">
2020-03-30 15:20:01 +00:00
<h3>{{ t('bookmarks', 'Owner') }}</h3>
<UserBubble :user="folder.userId" :display-name="folder.userId" />
</AppSidebarTab>
2020-04-02 15:25:14 +00:00
<AppSidebarTab v-if="isSharable"
id="folder-sharing"
:name="t('bookmarks', 'Sharing')"
icon="icon-shared">
2020-03-30 15:20:01 +00:00
<div class="participant-select">
2020-06-01 08:48:05 +00:00
<figure :class="{'icon-user': true, 'share__avatar': true }" />
2020-03-30 15:20:01 +00:00
<Multiselect v-model="participant"
label="displayName"
track-by="user"
class="participant-select__selection"
:user-select="true"
:options="participantSearchResults"
:loading="isSearching"
:placeholder="t('bookmarks', 'Select a user or group')"
@select="onAddShare"
@search-change="onParticipantSearch" />
</div>
<div class="share">
<figure :class="{'icon-public': true, 'share__avatar': true, active: publicLink }" />
2020-03-30 15:20:01 +00:00
<h3 class="share__title">
{{ t('bookmarks', 'Share link') }}
</h3>
<Actions class="share__actions">
<template v-if="publicLink">
<ActionButton icon="icon-clippy" @click="onCopyPublicLink">
{{ t('bookmarks', 'Copy link') }}
</ActionButton>
<ActionButton icon="icon-clippy" @click="onCopyRssLink">
{{ t('bookmarks', 'Copy RSS feed') }}
</ActionButton>
<ActionSeparator />
2020-03-30 15:20:01 +00:00
<ActionButton icon="icon-delete" @click="onDeletePublicLink">
{{ t('bookmarks', 'Delete link') }}
</ActionButton>
</template>
<ActionButton v-else icon="icon-add" @click="onAddPublicLink">
{{ t('bookmarks', 'Create public link') }}
</ActionButton>
</Actions>
</div>
2020-03-30 15:20:01 +00:00
<div v-for="share of shares" :key="share.id">
<div class="share">
<Avatar :user="share.participant" class="share__avatar" :size="44" />
<h3 class="share__title">
{{ share.participant }}
</h3>
<Actions class="share__actions">
<ActionCheckbox :checked="share.canWrite" @update:checked="onEditShare(share.id, {canWrite: $event, canShare: share.canShare})">
{{ t('bookmarks', 'Allow editing') }}
</ActionCheckbox>
<ActionCheckbox :checked="share.canShare" @update:checked="onEditShare(share.id, {canWrite: share.canWrite, canShare: $event})">
{{ t('bookmarks', 'Allow sharing') }}
</ActionCheckbox>
<ActionButton icon="icon-delete" @click="onDeleteShare(share.id)">
{{ t('bookmarks', 'Remove share') }}
</ActionButton>
</Actions>
</div>
</div>
</AppSidebarTab>
</AppSidebar>
</template>
<script>
2020-03-31 16:47:50 +00:00
import AppSidebar from '@nextcloud/vue/dist/Components/AppSidebar'
import AppSidebarTab from '@nextcloud/vue/dist/Components/AppSidebarTab'
import Avatar from '@nextcloud/vue/dist/Components/Avatar'
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
import Actions from '@nextcloud/vue/dist/Components/Actions'
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
import ActionCheckbox from '@nextcloud/vue/dist/Components/ActionCheckbox'
2020-06-01 08:48:05 +00:00
import ActionSeparator from '@nextcloud/vue/dist/Components/ActionSeparator'
2020-03-31 16:47:50 +00:00
import UserBubble from '@nextcloud/vue/dist/Components/UserBubble'
import { getCurrentUser } from '@nextcloud/auth'
2020-04-30 19:24:21 +00:00
import { generateUrl, generateOcsUrl } from '@nextcloud/router'
2020-03-31 16:47:50 +00:00
import axios from '@nextcloud/axios'
import copy from 'copy-text-to-clipboard'
import { actions, mutations } from '../store/'
2020-03-31 16:47:50 +00:00
export default {
2020-03-30 15:20:01 +00:00
name: 'SidebarFolder',
2020-06-01 08:48:05 +00:00
components: { AppSidebar, AppSidebarTab, Avatar, Multiselect, ActionButton, ActionCheckbox, Actions, UserBubble, ActionSeparator },
2020-03-30 15:20:01 +00:00
data() {
return {
participantSearchResults: [],
participant: null,
isSearching: false,
}
},
computed: {
isActive() {
if (!this.$store.state.sidebar) return false
return this.$store.state.sidebar.type === 'folder'
2020-03-30 12:31:54 +00:00
},
2020-03-30 15:20:01 +00:00
folder() {
if (!this.isActive) return
const folders = this.$store.getters.getFolder(this.$store.state.sidebar.id)
const folder = folders[0]
if (folder.userId === getCurrentUser()) {
2020-03-30 15:20:01 +00:00
this.$store.dispatch(actions.LOAD_SHARES_OF_FOLDER, folder.id)
this.$store.dispatch(actions.LOAD_PUBLIC_LINK, folder.id)
2020-03-30 12:31:54 +00:00
}
2020-03-30 15:20:01 +00:00
return folder
},
isOwner() {
2020-03-30 15:20:01 +00:00
if (!this.folder) return
const currentUser = getCurrentUser()
return currentUser && this.folder.userId === currentUser.uid
},
permissions() {
return this.$store.getters.getPermissionsForFolder(this.folder.id)
},
isSharable() {
if (!this.folder) return
return this.isOwner || (!this.isOwner && this.permissions.canShare)
},
isEditable() {
if (!this.folder) return
return this.isOwner || (!this.isOwner && this.permissions.canWrite)
2020-03-30 15:20:01 +00:00
},
shares() {
if (!this.folder) return
return this.$store.getters.getSharesOfFolder(this.folder.id)
},
token() {
if (!this.folder) return
return this.$store.getters.getTokenOfFolder(this.folder.id)
},
2020-03-30 15:20:01 +00:00
publicLink() {
if (!this.token) return
return window.location.origin + generateUrl('/apps/bookmarks/public/' + this.token)
},
rssLink() {
return (
window.location.origin
+ generateUrl(
'/apps/bookmarks/public/rest/v2/bookmark?'
+ new URLSearchParams(
Object.assign({}, this.$store.state.fetchState.query, {
format: 'rss',
page: -1,
token: this.token,
})
).toString()
)
)
},
2020-03-30 15:20:01 +00:00
},
2020-03-30 15:20:01 +00:00
watch: {
},
2020-03-30 12:31:54 +00:00
2020-03-30 15:20:01 +00:00
methods: {
onClose() {
this.$store.commit(mutations.SET_SIDEBAR, null)
},
2020-03-30 15:20:01 +00:00
async onAddPublicLink() {
await this.$store.dispatch(actions.CREATE_PUBLIC_LINK, this.folder.id)
this.onCopyPublicLink()
},
onCopyPublicLink() {
copy(this.publicLink)
this.$store.commit(mutations.SET_NOTIFICATION, t('bookmarks', 'Link copied'))
},
onCopyRssLink() {
copy(this.rssLink)
this.$store.commit(mutations.SET_NOTIFICATION, t('bookmarks', 'RSS feed copied'))
},
2020-03-30 15:20:01 +00:00
async onDeletePublicLink() {
await this.$store.dispatch(actions.DELETE_PUBLIC_LINK, this.folder.id)
},
async onParticipantSearch(searchTerm) {
2020-04-30 19:11:34 +00:00
if (!searchTerm) {
return
}
2020-03-30 15:20:01 +00:00
this.isSearching = true
2020-04-30 19:24:21 +00:00
const { data: { ocs: { data, meta } } } = await axios.get(generateOcsUrl('apps/files_sharing/api/v1', 1) + `sharees?format=json&itemType=folder&search=${searchTerm}&lookup=false&perPage=200&shareType[]=0&shareType[]=1`)
2020-03-30 15:20:01 +00:00
if (meta.status !== 'ok') {
this.participantSearchResults = []
return
}
const users = data.exact.users.concat(data.users)
const groups = data.exact.groups.concat(data.groups)
this.participantSearchResults = users.map(result => ({
2020-03-30 15:20:01 +00:00
user: result.value.shareWith,
displayName: result.label,
icon: 'icon-user',
isNoUser: false,
})).concat(groups.map(result => ({
2020-03-30 15:20:01 +00:00
user: result.value.shareWith,
displayName: result.label,
icon: 'icon-group',
isNoUser: true,
})))
this.isSearching = false
},
async onAddShare(user) {
await this.$store.dispatch(actions.CREATE_SHARE, { folderId: this.folder.id, participant: user.user, type: user.isNoUser ? 1 : 0 })
},
async onEditShare(shareId, { canWrite, canShare }) {
await this.$store.dispatch(actions.EDIT_SHARE, { shareId, canWrite, canShare })
},
async onDeleteShare(shareId) {
await this.$store.dispatch(actions.DELETE_SHARE, shareId)
},
},
}
</script>
<style>
2020-03-30 15:20:01 +00:00
.sidebar span[class^='icon-'] {
display: inline-block;
position: relative;
top: 3px;
opacity: 0.5;
}
2020-03-30 15:20:01 +00:00
.participant-select {
display: flex;
}
2020-03-30 15:20:01 +00:00
.participant-select__selection {
flex: 1;
margin-top: 5px !important;
}
2020-03-30 15:20:01 +00:00
.participant-select__actions {
flex-grow: 0;
}
2020-03-30 15:20:01 +00:00
.share {
display: flex;
margin-top: 10px;
}
2020-03-30 15:20:01 +00:00
.share__avatar {
flex-grow: 0;
height: 44px;
width: 44px;
}
2020-03-30 12:31:54 +00:00
.share__avatar.active {
background-color: var(--color-primary-light);
border-radius: 44px;
}
2020-03-30 15:20:01 +00:00
.share__title {
flex: 1;
padding-left: 10px;
}
2020-03-30 12:31:54 +00:00
2020-03-30 15:20:01 +00:00
.share__actions {
flex-grow: 0;
}
</style>