Skip to content

Commit

Permalink
[full-ci] Tags (#7385)
Browse files Browse the repository at this point in the history
Tags init
  • Loading branch information
Jan authored and JammingBen committed Dec 8, 2022
1 parent 7c2e24e commit 83bde1b
Show file tree
Hide file tree
Showing 16 changed files with 335 additions and 22 deletions.
5 changes: 0 additions & 5 deletions changelog/unreleased/enhancement-add-tags-to-resource-table

This file was deleted.

9 changes: 9 additions & 0 deletions changelog/unreleased/enhancement-tags-support
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Enhancement: Add Tag support

Managing files via tags is now possible in web, the feature is experimental and will be only available through a dedicated experimental web build.
Beside that the web version is experimental, it also needs a special experimental ocis version.

Creating Tags, tagging resources and search for tags now is possible and can be used as an alternative way of working and organizing resources.

https://github.com/owncloud/web/pull/7388
https://github.com/owncloud/web/pull/7385
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Rename from '../../mixins/actions/rename'
import Restore from '../../mixins/actions/restore'
import ShowActions from '../../mixins/actions/showActions'
import ShowDetails from '../../mixins/actions/showDetails'
import ShowEditTags from '../../mixins/actions/showEditTags'
import ShowShares from '../../mixins/actions/showShares'
import SetSpaceImage from '../../mixins/spaces/actions/setImage'
import SetSpaceReadme from '../../mixins/spaces/actions/setReadme'
Expand Down Expand Up @@ -51,6 +52,7 @@ export default {
Restore,
ShowActions,
ShowDetails,
ShowEditTags,
ShowShares,
SetSpaceImage,
SetSpaceReadme,
Expand Down Expand Up @@ -158,6 +160,7 @@ export default {
...this.$_copy_items,
...this.$_paste_items,
...this.$_rename_items,
...this.$_showEditTags_items,
...this.$_restore_items,
...this.$_acceptShare_items,
...this.$_declineShare_items,
Expand Down
24 changes: 14 additions & 10 deletions packages/web-app-files/src/components/FilesList/ResourceTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ export default defineComponent({
}
},
computed: {
...mapGetters(['configuration']),
...mapGetters(['configuration', 'capabilities']),
...mapState('Files', [
'areFileExtensionsShown',
'latestSelectedId',
Expand Down Expand Up @@ -466,13 +466,15 @@ export default defineComponent({
alignH: 'right',
wrap: 'nowrap'
},
{
name: 'tags',
title: this.$gettext('Tags'),
type: 'slot',
alignH: 'right',
wrap: 'nowrap'
},
this.capabilities?.files?.tags
? {
name: 'tags',
title: this.$gettext('Tags'),
type: 'slot',
alignH: 'right',
wrap: 'nowrap'
}
: {},
{
name: 'owner',
title: this.$gettext('Shared by'),
Expand Down Expand Up @@ -566,6 +568,8 @@ export default defineComponent({
},
methods: {
...mapActions('Files', ['toggleFileSelection']),
...mapActions('Files/sidebar', ['openWithPanel']),
...mapActions('Files/sidebar', { openSidebar: 'open' }),
isResourceSelected(item) {
return this.selectedIds.includes(item.id)
},
Expand All @@ -577,7 +581,7 @@ export default defineComponent({
},
getTagLink(tag) {
return createLocationCommon('files-common-search', {
query: { term: `tag:${tag}`, provider: 'files.sdk' }
query: { term: `Tags:${tag}`, provider: 'files.sdk' }
})
},
isLatestSelectedItem(item) {
Expand All @@ -591,7 +595,7 @@ export default defineComponent({
this.$_rename_trigger({ resources: [item] }, this.getMatchingSpace(item))
},
openTagsSidebar() {
this.openWithPanel('tags-item')
this.openSidebar()
},
openSharingSidebar(file) {
let panelToOpen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@
</div>
</td>
</tr>
<tr v-if="showTags" data-testid="tags">
<th scope="col" class="oc-pr-s" v-text="tagsLabel" />
<td>
<router-link v-for="(tag, index) in file.tags" :key="tag" :to="getTagLink(tag)">
<span>
<span v-if="index + 1 < file.tags.length" class="oc-mr-xs">{{ tag }},</span>
<span v-else v-text="tag" />
</span>
</router-link>
</td>
</tr>
</table>
</div>
<p v-else data-testid="noContentText" v-text="noContentText" />
Expand All @@ -152,7 +163,7 @@ import { ImageDimension } from '../../../constants'
import { loadPreview } from 'web-pkg/src/helpers/preview'
import upperFirst from 'lodash-es/upperFirst'
import { basename, dirname } from 'path'
import { createLocationSpaces } from '../../../router'
import { createLocationSpaces, createLocationCommon } from '../../../router'
import { ShareTypes } from 'web-client/src/helpers/share'
import { useAccessToken, usePublicLinkContext, useStore } from 'web-pkg/src/composables'
import { getIndicators } from '../../../helpers/statusIndicators'
Expand Down Expand Up @@ -188,7 +199,7 @@ export default defineComponent({
computed: {
...mapGetters('runtime/spaces', ['spaces']),
...mapGetters('Files', ['versions', 'sharesTree', 'sharesTreeLoading', 'highlightedFile']),
...mapGetters(['user', 'configuration']),
...mapGetters(['user', 'configuration', 'capabilities']),
matchingSpace() {
return this.space || this.spaces.find((space) => space.id === this.file.storageId)
Expand Down Expand Up @@ -338,6 +349,12 @@ export default defineComponent({
const displayDate = formatDateFromHTTP(this.file.mdate, this.$language.current)
return upperFirst(displayDate)
},
showTags() {
return this.capabilities?.files.tags && this.file.tags?.length
},
tagsLabel() {
return this.$gettext('Tags')
},
hasAnyShares() {
return (
this.file.shareTypes?.length > 0 ||
Expand Down Expand Up @@ -464,6 +481,11 @@ export default defineComponent({
this.copiedDirect = false
this.copiedEos = false
}, 550)
},
getTagLink(tag) {
return createLocationCommon('files-common-search', {
query: { term: `Tags:${tag}`, provider: 'files.sdk' }
})
}
}
})
Expand All @@ -478,6 +500,7 @@ export default defineComponent({
td {
max-width: 0;
width: 100%;
overflow-wrap: break-word;
div {
min-width: 0;
Expand Down
146 changes: 146 additions & 0 deletions packages/web-app-files/src/components/SideBar/TagsPanel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<template>
<div>
<div class="oc-background-highlight oc-p-m">
<oc-loader v-if="loadAllTagsTask.isRunning" />
<oc-select
v-else
ref="tagSelect"
v-model="editAssignedTags"
multiple
:options="allTags"
taggable
push-tags
:label="$gettext('Add or edit tags')"
:create-option="createOption"
:selectable="() => editAssignedTags.length <= tagsMaxCount"
:fix-message-line="true"
>
<template #selected-option="{ label }">
<span class="oc-flex oc-flex-center">
<avatar-image
class="oc-flex oc-align-self-center oc-mr-s"
:width="16.8"
:userid="label"
:user-name="label"
/>
<span>{{ label }}</span>
</span>
</template>
<template #option="{ label }">
<div class="oc-flex">
<span v-if="showSelectNewLabel(label)" v-translate class="oc-mr-s">New</span>
<span class="oc-flex oc-flex-center">
<avatar-image
class="oc-flex oc-align-self-center oc-mr-s"
:width="16.8"
:userid="label"
:user-name="label"
/>
<span>{{ label }}</span>
</span>
</div>
</template>
</oc-select>
</div>
<compare-save-dialog
class="edit-compare-save-dialog"
:original-object="{ tags: resource.tags }"
:compare-object="{ tags: editAssignedTags }"
@revert="revertChanges"
@confirm="save"
></compare-save-dialog>
</div>
</template>

<script lang="ts">
import { mapActions, mapMutations } from 'vuex'
import { defineComponent, ref } from '@vue/composition-api'
import CompareSaveDialog from 'web-pkg/src/components/sidebar/CompareSaveDialog.vue'
import { bus } from 'web-pkg/src/instance'
import { useTask } from 'vue-concurrency'
import { useRequest, useStore } from 'web-pkg/src/composables'
const tagsMaxCount = 100
export default defineComponent({
name: 'Tags',
components: {
CompareSaveDialog
},
inject: ['displayedItem'],
setup() {
const store = useStore()
const allTags = ref([])
const { makeRequest } = useRequest()
const loadAllTagsTask = useTask(function* (signal, ref) {
const {
data: { tags = [] }
} = yield makeRequest('GET', `${store.getters.configuration.server}experimental/tags`, {})
allTags.value = tags
})
return {
loadAllTagsTask,
allTags,
tagsMaxCount
}
},
data: function () {
return {
editAssignedTags: []
}
},
computed: {
resource() {
return this.displayedItem.value
}
},
mounted() {
this.editAssignedTags = [...this.resource.tags]
this.loadAllTagsTask.perform(this)
},
methods: {
...mapActions(['showMessage']),
...mapMutations('Files', ['UPDATE_RESOURCE_FIELD']),
revertChanges() {
this.editAssignedTags = [...this.resource.tags]
},
async save() {
try {
const tagsToAdd = this.editAssignedTags.filter((tag) => !this.resource.tags.includes(tag))
const tagsToRemove = this.resource.tags.filter(
(tag) => !this.editAssignedTags.includes(tag)
)
if (tagsToAdd.length) {
await this.$client.tags.addResourceTag(this.resource.fileId, tagsToAdd)
}
if (tagsToRemove.length) {
await this.$client.tags.removeResourceTag(this.resource.fileId, tagsToRemove)
}
this.UPDATE_RESOURCE_FIELD({
id: this.resource.id,
field: 'tags',
value: [...this.editAssignedTags]
})
this.displayedItem.value.tags = [...this.editAssignedTags]
bus.publish('sidebar.entity.saved')
} catch (e) {
console.error(e)
}
},
createOption(option) {
return option.toLowerCase()
},
showSelectNewLabel(option) {
return !this.$refs.tagSelect.$refs.select.optionExists(option)
}
}
})
</script>

<style lang="scss"></style>
19 changes: 19 additions & 0 deletions packages/web-app-files/src/fileSideBars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import FileDetailsMultiple from './components/SideBar/Details/FileDetailsMultipl
import FileActions from './components/SideBar/Actions/FileActions.vue'
import FileVersions from './components/SideBar/Versions/FileVersions.vue'
import SharesPanel from './components/SideBar/Shares/SharesPanel.vue'
import TagsPanel from './components/SideBar/TagsPanel.vue'
import NoSelection from './components/SideBar/NoSelection.vue'
import SpaceActions from './components/SideBar/Actions/SpaceActions.vue'
import SpaceDetails from './components/SideBar/Details/SpaceDetails.vue'
Expand Down Expand Up @@ -154,6 +155,24 @@ const panelGenerators: (({
return false
}
}),
({ capabilities, highlightedFile, router, multipleSelection, rootFolder }) => ({
app: 'tags-item',
icon: 'price-tag-3',
iconFillType: 'line',
title: $gettext('Tags'),
component: TagsPanel,
componentAttrs: {},
get enabled() {
if (!capabilities?.files?.tags || multipleSelection || rootFolder) return false
if (typeof highlightedFile.canEditTags !== 'function' || !highlightedFile.canEditTags())
return false
return !(
isLocationTrashActive(router, 'files-trash-personal') ||
isLocationTrashActive(router, 'files-trash-spaces-project') ||
isLocationPublicActive(router, 'files-public-files')
)
}
}),
({ multipleSelection, highlightedFile, capabilities }) => ({
app: 'space-share',
icon: 'group',
Expand Down
2 changes: 1 addition & 1 deletion packages/web-app-files/src/helpers/resource/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const filterResources = (resources: unknown[], term: string, limit?: numb
includeScore: true,
useExtendedSearch: true,
threshold: 0.3,
keys: ['name', 'type', 'icon', 'extension']
keys: ['name', 'type', 'icon', 'extension', 'tags']
})

return (engine.search(term, { limit }) as any[]).map((result: any) => result.item)
Expand Down
4 changes: 4 additions & 0 deletions packages/web-app-files/src/helpers/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ export function buildSharedResource(
resource.canShare = () => SharePermissions.share.enabled(share.permissions)
resource.canRename = () => parseInt(share.state) === ShareStatus.accepted
resource.canBeDeleted = () => SharePermissions.delete.enabled(share.permissions)
resource.canEditTags = () =>
parseInt(share.state) === ShareStatus.accepted &&
SharePermissions.update.enabled(share.permissions)
} else {
resource.sharedWith = share.sharedWith || []
resource.shareOwner = share.uid_owner
Expand All @@ -211,6 +214,7 @@ export function buildSharedResource(
resource.canShare = () => true
resource.canRename = () => true
resource.canBeDeleted = () => true
resource.canEditTags = () => true
}

resource.extension = extractExtensionFromFile(resource)
Expand Down
Loading

0 comments on commit 83bde1b

Please sign in to comment.