Skip to content

Commit

Permalink
[full-ci] Merge master into experimental (#7460)
Browse files Browse the repository at this point in the history
* change ocis to experimental
change sdk to experimental

* bump ocis commit id

* Add tags to ResourceTable (#7388)

* Add tags to resourcetable

* Use file tags instead of tags

* Add changelog, remove border for + item

* Replace OcFileTag

* Dump ODS

* [full-ci] Tags (#7385)

Tags init

* Truncate tags (#7442)

Truncate tags

Co-authored-by: Paul Neubauer <paulneubauer@live.de>
Co-authored-by: Jan <jackermann@owncloud.com>
  • Loading branch information
3 people committed Aug 16, 2022
1 parent 6db777d commit 83bc21c
Show file tree
Hide file tree
Showing 19 changed files with 397 additions and 35 deletions.
4 changes: 2 additions & 2 deletions .drone.env
@@ -1,3 +1,3 @@
# The version of OCIS to use in pipelines that test against OCIS
OCIS_COMMITID=8bb2ebcf4bcecd0ddfb3ce8f2cb4ba3d51be19b5
OCIS_BRANCH=master
OCIS_COMMITID=f99a2072d33debc7fda43f9b27ba48c01014a83b
OCIS_BRANCH=experimental
10 changes: 10 additions & 0 deletions changelog/unreleased/enhancement-tags-support
@@ -0,0 +1,10 @@
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
https://github.com/owncloud/web/pull/7442
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 @@ -50,6 +51,7 @@ export default {
Restore,
ShowActions,
ShowDetails,
ShowEditTags,
ShowShares,
SetSpaceImage,
SetSpaceReadme,
Expand Down Expand Up @@ -152,6 +154,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
45 changes: 43 additions & 2 deletions packages/web-app-files/src/components/FilesList/ResourceTable.vue
Expand Up @@ -81,6 +81,22 @@
<template #size="{ item }">
<oc-resource-size :size="item.size || Number.NaN" />
</template>
<template #tags="{ item }">
<router-link v-for="tag in item.tags.slice(0, 2)" :key="tag" :to="getTagLink(tag)">
<oc-tag class="resource-table-tag oc-ml-xs" :rounded="true" size="small">
<oc-icon name="price-tag-3" size="small" />
<span class="oc-text-truncate">{{ tag }}</span>
</oc-tag>
</router-link>
<oc-tag
v-if="item.tags.length > 2"
size="small"
class="resource-table-tag-more"
@click="openTagsSidebar"
>
+ {{ item.tags.length - 2 }}
</oc-tag>
</template>
<template #mdate="{ item }">
<span
v-oc-tooltip="formatDate(item.mdate)"
Expand Down Expand Up @@ -188,7 +204,7 @@ import { extractDomSelector } from 'web-client/src/helpers/resource'
import { Resource } from 'web-client'
import { ClipboardActions } from '../../helpers/clipboardActions'
import { ShareTypes } from 'web-client/src/helpers/share'
import { createLocationSpaces } from '../../router'
import { createLocationSpaces, createLocationCommon } from '../../router'
import { formatDateFromJSDate, formatRelativeDateFromJSDate } from 'web-pkg/src/helpers'
const mapResourceFields = (resource: Resource, mapping = {}) => {
Expand Down Expand Up @@ -401,7 +417,7 @@ export default defineComponent({
}
},
computed: {
...mapGetters(['configuration']),
...mapGetters(['configuration', 'capabilities']),
...mapState('Files', [
'areFileExtensionsShown',
'latestSelectedId',
Expand Down Expand Up @@ -473,6 +489,15 @@ export default defineComponent({
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 @@ -564,9 +589,15 @@ export default defineComponent({
},
methods: {
...mapActions('Files/sidebar', ['openWithPanel']),
...mapActions('Files/sidebar', { openSidebar: 'open' }),
isResourceSelected(item) {
return this.selectedIds.includes(item.id)
},
getTagLink(tag) {
return createLocationCommon('files-common-search', {
query: { term: `Tags:${tag}`, provider: 'files.sdk' }
})
},
isResourceCut(resource) {
if (this.clipboardAction !== ClipboardActions.Cut) return false
return this.clipboardResources.some((r) => r.id === resource.id)
Expand All @@ -581,6 +612,9 @@ export default defineComponent({
openRenameDialog(item) {
this.$_rename_trigger({ resources: [item] })
},
openTagsSidebar() {
this.openSidebar()
},
openSharingSidebar(file) {
if (file.share?.shareType === ShareTypes.link.value) {
this.openWithPanel('sharing-item#linkShares')
Expand Down Expand Up @@ -821,6 +855,13 @@ export default defineComponent({
}
}
}
&-tag {
max-width: 80px;
}
&-tag-more {
cursor: pointer;
border: 0 !important;
}
&-edit-name {
display: inline-flex;
vertical-align: super;
Expand Down
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,8 +163,9 @@ import { ImageDimension } from '../../../constants'
import { loadPreview } from 'web-pkg/src/helpers/preview'
import upperFirst from 'lodash-es/upperFirst'
import path from 'path'
import { createLocationSpaces, isLocationSpacesActive } from '../../../router'
import { createLocationSpaces, isLocationSpacesActive, createLocationCommon } from '../../../router'
import { ShareTypes } from 'web-client/src/helpers/share'
import {
useAccessToken,
usePublicLinkContext,
Expand Down Expand Up @@ -209,7 +221,7 @@ export default defineComponent({
}),
computed: {
...mapGetters('Files', ['versions', 'sharesTree', 'sharesTreeLoading']),
...mapGetters(['user', 'configuration']),
...mapGetters(['user', 'configuration', 'capabilities']),
file() {
return this.displayedItem.value
Expand Down Expand Up @@ -334,6 +346,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 @@ -462,6 +480,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 @@ -476,6 +499,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
@@ -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
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 @@ -140,6 +141,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')
)
}
}),
({ highlightedFile, capabilities }) => ({
app: 'space-share-item',
icon: 'group',
Expand Down
2 changes: 1 addition & 1 deletion packages/web-app-files/src/helpers/resource/filter.ts
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

0 comments on commit 83bc21c

Please sign in to comment.