diff options
author | Devlin Junker <devlin.junker@gmail.com> | 2023-09-26 14:39:38 -0700 |
---|---|---|
committer | Devlin Junker <devlin.junker@gmail.com> | 2023-09-26 14:42:50 -0700 |
commit | b7179b5858c2f3393407777e5ba0d9c6b0e9720b (patch) | |
tree | ebc8bee1a6635250653db33c40f251c65d584b9f /src | |
parent | 2ebd898a1b049e6f4dbd3f8a2ca5ff2d04814bb1 (diff) |
working share component
Signed-off-by: Devlin Junker <devlin.junker@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/components/ShareItem.vue | 138 | ||||
-rw-r--r-- | src/components/Sidebar.vue | 2 | ||||
-rw-r--r-- | src/components/feed-display/FeedItemRow.vue | 20 | ||||
-rw-r--r-- | src/dataservices/share.service.ts | 28 |
4 files changed, 179 insertions, 9 deletions
diff --git a/src/components/ShareItem.vue b/src/components/ShareItem.vue new file mode 100644 index 000000000..c7898330c --- /dev/null +++ b/src/components/ShareItem.vue @@ -0,0 +1,138 @@ +<template> + <NcModal @close="$emit('close')"> + <div id="share-item"> + <form name="feedform"> + <fieldset> + <input v-model="userName" + type="text" + :placeholder="t('news', 'User Name')" + name="user" + pattern="[^\s]+" + required + autofocus + @keyup="debounceSearchUsers()"> + + <div class="user-bubble-container"> + <NcLoadingIcon v-if="searching" /> + <NcUserBubble v-for="user in users" + v-else-if="!searching" + :key="user.shareName" + :size="30" + :display-name="user.displayName" + :primary="selected.map((val) => { return val.shareName }).includes(user.shareName)" + :user="user.shareName" + @click="clickUser(user)" /> + </div> + + <NcButton :wide="true" + type="primary" + :disabled="selected.length === 0" + @click="share()"> + <template v-if="selected.length === 0"> + {{ t("news", "Share") }} + </template> + <template v-else-if="selected.length === 1"> + {{ t("news", "Share with") + ' ' + selected[0].displayName }} + </template> + <template v-else-if="selected.length > 1"> + {{ t("news", "Share with {num} users", { num: selected.length }) }} + </template> + </NcButton> + </fieldset> + </form> + </div> + </NcModal> +</template> + +<script lang="ts"> + +import Vue from 'vue' +import _ from 'lodash' + +import NcModal from '@nextcloud/vue/dist/Components/NcModal.js' +import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' +import NcUserBubble from '@nextcloud/vue/dist/Components/NcUserBubble.js' +import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js' + +import { ShareService } from '../dataservices/share.service' + +export default Vue.extend({ + components: { + NcModal, + NcButton, + NcUserBubble, + NcLoadingIcon, + }, + props: { + itemId: { + type: Number, + required: true, + }, + }, + data: () => { + return { + userName: '', + users: [], + selected: [], + searching: false, + } as any + }, + created() { + this.debounceSearchUsers = _.debounce(this.searchUsers, 800) + }, + methods: { + clickUser(user: any) { + const selectedUsers = this.selected.map((val: any) => { return val.shareName }) + if (selectedUsers.includes(user.shareName)) { + this.selected.splice(selectedUsers.indexOf(user.shareName), 1) + } else { + this.selected.push(user) + } + }, + + async searchUsers() { + this.users = [] + this.searching = true + const response = await ShareService.fetchUsers(this.userName) + this.searching = false + + for (const user of response.data.ocs.data.users) { + this.users.push({ displayName: user.label, shareName: user.value.shareWith }) + } + }, + + /** + * Shares an item with another use in the same nextcloud instance + */ + async share() { + await ShareService.share(this.itemId, this.selected.map((val: any) => { return val.shareName })) + + this.$emit('close') + }, + }, +}) + +</script> + +<style> +#share-item .user-bubble__content * { + cursor: pointer; +} + +#share-item fieldset { + padding: 16px; +} + +#share-item input { + width: 90%; +} + +#share-item .user-bubble-container { + margin: 10px; +} + +#share-item .user-bubble__wrapper { + margin: 5px 10px; +} + +</style> diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 392c0ccfb..f29e6503e 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -84,7 +84,7 @@ </NcCounterBubble> </template> <template #actions> - <SidebarFeedLinkActions v-if="topLevelItem.name === undefined" :feed-id="topLevelItem.id" /> + <SidebarFeedLinkActions v-if="topLevelItem.name === undefined && !topLevelItem.url.includes('news/sharedwithme')" :feed-id="topLevelItem.id" /> <NcActionButton v-if="topLevelItem.name !== undefined" icon="icon-checkmark" @click="markFolderRead(topLevelItem)"> {{ t("news", "Mark read") }} diff --git a/src/components/feed-display/FeedItemRow.vue b/src/components/feed-display/FeedItemRow.vue index 03670295a..854f83633 100644 --- a/src/components/feed-display/FeedItemRow.vue +++ b/src/components/feed-display/FeedItemRow.vue @@ -1,5 +1,6 @@ <template> <div class="feed-item-row" @click="select()"> + <ShareItem v-if="showShareMenu" :item-id="shareItem" @close="closeShareMenu()" /> <div class="link-container"> <a class="external" target="_blank" @@ -28,14 +29,9 @@ <EyeIcon v-if="item.unread && !keepUnread" @click="toggleKeepUnread(item)" /> <EyeCheckIcon v-if="!item.unread && !keepUnread" @click="toggleKeepUnread(item)" /> <EyeLockIcon v-if="keepUnread" class="keep-unread" @click="toggleKeepUnread(item)" /> - <NcActions :force-menu="true"> - <template #icon> - <ShareVariant /> - </template> - <NcActionButton> - <template #default> - <!-- TODO: Share Menu --> TODO - </template> + <NcActions> + <NcActionButton :title="t('news', 'Share within Instance')" @click="shareItem = item.id; showShareMenu = true"> + {{ t('news', 'Share') }} <template #icon> <ShareVariant /> </template> @@ -60,6 +56,8 @@ import ShareVariant from 'vue-material-design-icons/ShareVariant.vue' import NcActions from '@nextcloud/vue/dist/Components/NcActions.js' import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' +import ShareItem from '../ShareItem.vue' + import { Feed } from '../../types/Feed' import { FeedItem } from '../../types/FeedItem' import { ACTIONS, MUTATIONS } from '../../store' @@ -76,6 +74,7 @@ export default Vue.extend({ RssIcon, NcActions, NcActionButton, + ShareItem, }, props: { item: { @@ -86,6 +85,8 @@ export default Vue.extend({ data: () => { return { keepUnread: false, + showShareMenu: false, + shareItem: undefined, } }, computed: { @@ -142,6 +143,9 @@ export default Vue.extend({ toggleStarred(item: FeedItem): void { this.$store.dispatch(item.starred ? ACTIONS.UNSTAR_ITEM : ACTIONS.STAR_ITEM, { item }) }, + closeShareMenu() { + this.showShareMenu = false + }, }, }) diff --git a/src/dataservices/share.service.ts b/src/dataservices/share.service.ts new file mode 100644 index 000000000..c060bc3f0 --- /dev/null +++ b/src/dataservices/share.service.ts @@ -0,0 +1,28 @@ +import { AxiosResponse } from 'axios' +import axios from '@nextcloud/axios' +import { generateOcsUrl } from '@nextcloud/router' + +export class ShareService { + + /** + * Retrieves all of users matching the search term + * + * @param query {String} search string + * @return {AxiosResponse} Folders contained in data.folders property + */ + static fetchUsers(query: string): Promise<AxiosResponse> { + return axios.get(generateOcsUrl(`apps/files_sharing/api/v1/sharees?search=${query}&itemType=news_item&perPage=5/`)) + } + + static async share(id: number, users: string[]): Promise<boolean> { + const promises = [] + for (const shareName of users) { + promises.push(axios.post(`items/${id}/share/${shareName}`)) + } + + await Promise.all(promises) + + return true + } + +} |