Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move tags to details panel #9905

Merged
merged 15 commits into from
Nov 9, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,17 @@
:slot-props="{ space, resource }"
:multiple="true"
/>
<tr v-if="showTags" data-testid="tags">
<th scope="col" class="oc-pr-s oc-font-semibold" v-text="$gettext('Tags')" />
<tr data-testid="tags">
<th scope="col" class="oc-pr-s oc-font-semibold">
{{ $gettext('Tags') }}
<oc-contextual-helper
v-if="contextualHelper?.isEnabled"
v-bind="contextualHelper?.data"
class="oc-pl-xs"
></oc-contextual-helper>
</th>
<td>
<span v-for="(tag, index) in resource.tags" :key="tag">
<component
:is="!isPublicLinkContext ? 'router-link' : 'span'"
v-bind="getTagComponentAttrs(tag)"
>
<span v-if="index + 1 < resource.tags.length">{{ tag }}</span>
<span v-else v-text="tag" /></component
><span v-if="index + 1 < resource.tags.length" class="oc-mr-xs">,</span>
</span>
<tags-select :resource="resource"></tags-select>
</td>
</tr>
</table>
Expand All @@ -120,9 +119,8 @@
<script lang="ts">
import { computed, defineComponent, inject, Ref, ref, unref, watch } from 'vue'
import { mapGetters } from 'vuex'
import { ImageDimension } from '@ownclouders/web-pkg'
import { ImageDimension, useConfigurationManager } from '@ownclouders/web-pkg'
import upperFirst from 'lodash-es/upperFirst'
import { createLocationCommon } from '@ownclouders/web-pkg'
import { ShareTypes } from '@ownclouders/web-client/src/helpers/share'
import {
useCapabilityFilesTags,
Expand All @@ -145,18 +143,23 @@ import { useTask } from 'vue-concurrency'
import { useGettext } from 'vue3-gettext'
import { getSharedAncestorRoute } from '@ownclouders/web-pkg'
import { AncestorMetaData } from '@ownclouders/web-pkg'
import { tagsHelper } from '../../../helpers/contextualHelpers'
import { ContextualHelper } from '@ownclouders/design-system/src/helpers'
import TagsSelect from './TagsSelect.vue'

export default defineComponent({
name: 'FileDetails',
components: { TagsSelect },
setup() {
const configurationManager = useConfigurationManager()
const store = useStore()
const clientService = useClientService()
const { getMatchingSpace } = useGetMatchingSpace()
const language = useGettext()

const resource = inject<Resource>('resource')
const space = inject<Ref<SpaceResource>>('space')
const isPublicLinkContext = usePublicLinkContext({ store })
const clientService = useClientService()
const previewService = usePreviewService()
const preview = ref(undefined)

Expand Down Expand Up @@ -223,6 +226,11 @@ export default defineComponent({
{ immediate: true }
)

const contextualHelper = {
isEnabled: configurationManager.options.contextHelpers,
data: tagsHelper({ configurationManager: configurationManager })
} as ContextualHelper

return {
preview,
isPublicLinkContext,
Expand All @@ -233,7 +241,8 @@ export default defineComponent({
ancestorMetaData,
sharedAncestor,
formatDateRelative,
matchingSpace
matchingSpace,
AlexAndBear marked this conversation as resolved.
Show resolved Hide resolved
contextualHelper
}
},
computed: {
Expand Down Expand Up @@ -312,9 +321,6 @@ export default defineComponent({
const displayDate = formatDateFromHTTP(this.resource.mdate, this.$language.current)
return upperFirst(displayDate)
},
showTags() {
return this.hasTags && this.resource.tags?.length
},
hasAnyShares() {
return (
this.resource.shareTypes?.length > 0 ||
Expand All @@ -339,21 +345,6 @@ export default defineComponent({
methods: {
expandVersionsPanel() {
eventBus.publish(SideBarEventTopics.setActivePanel, 'versions')
},
getTagLink(tag) {
const currentTerm = unref(this.$router.currentRoute).query?.term
return createLocationCommon('files-common-search', {
query: { provider: 'files.sdk', q_tags: tag, ...(currentTerm && { term: currentTerm }) }
})
},
getTagComponentAttrs(tag) {
if (this.isPublicLinkContext) {
return {}
}

return {
to: this.getTagLink(tag)
}
}
}
})
Expand Down Expand Up @@ -398,4 +389,8 @@ export default defineComponent({
max-width: 192px !important;
width: 192px !important;
}

.oc-tag:hover {
cursor: pointer;
}
</style>
Original file line number Diff line number Diff line change
@@ -1,92 +1,115 @@
<template>
<div id="tags-panel">
<div id="tags-form" class="oc-background-highlight oc-p-m">
<oc-loader v-if="loadAvailableTagsTask.isRunning" />
<oc-select
v-else
ref="tagSelect"
v-model="selectedTags"
class="oc-mb-s"
:multiple="true"
:disabled="readonly"
:options="availableTags"
:contextual-helper="contextualHelper"
taggable
:select-on-key-codes="[keycode('enter'), keycode(',')]"
:label="$gettext('Add or edit tags')"
:create-option="createOption"
:selectable="isOptionSelectable"
:fix-message-line="true"
:map-keydown="keydownMethods"
@update:model-value="save"
>
<template #selected-option-container="{ option, deselect }">
<oc-select
ref="tagSelect"
v-model="selectedTags"
:multiple="true"
:disabled="readonly"
:options="availableTags"
taggable
:select-on-key-codes="[keycode('enter'), keycode(',')]"
:create-option="createOption"
:selectable="isOptionSelectable"
:map-keydown="keydownMethods"
data-test-id="tags-select"
@update:model-value="save"
>
<template #selected-option-container="{ option, deselect }">
<oc-tag class="tags-control-tag oc-ml-xs" :rounded="true" size="small">
<router-link class="oc-flex oc-flex-middle" :to="generateTagLink(option.label)">
<oc-icon name="price-tag-3" class="oc-mr-xs" size="small" />
<span class="oc-text-truncate">{{ option.label }}</span>
</router-link>

<span class="oc-flex oc-flex-middle oc-mr-xs">
<oc-icon v-if="option.readonly" class="vs__deselect-lock" name="lock" size="small" />
<oc-button
v-else
appearance="raw"
:title="$gettext('Deselect %{label}', { label: option.label })"
:aria-label="$gettext('Deselect %{label}', { label: option.label })"
class="vs__deselect oc-mx-rm"
@mousedown.stop.prevent
@click="deselect(option)"
>
<oc-icon name="close" size="small" />
</oc-button>
</span>
</oc-tag>
</template>
<template #option="{ label, error }">
<div class="oc-flex">
<span class="oc-flex oc-flex-center">
<oc-tag class="tags-control-tag oc-ml-xs" :rounded="true" size="small">
<oc-icon name="price-tag-3" size="small" />
<span class="oc-text-truncate">{{ option.label }}</span>
<span class="oc-flex oc-flex-middle oc-ml-s oc-mr-xs">
<oc-icon v-if="option.readonly" class="vs__deselect-lock" name="lock" size="small" />
<oc-button
v-else
appearance="raw"
:title="$gettext('Deselect %{label}', { label: option.label })"
:aria-label="$gettext('Deselect %{label}', { label: option.label })"
class="vs__deselect oc-mx-rm"
@mousedown.stop.prevent
@click="deselect(option)"
>
<oc-icon name="close" size="small" />
</oc-button>
</span>
<span class="oc-text-truncate">{{ label }}</span>
</oc-tag>
</template>
<template #option="{ label, error }">
<div class="oc-flex">
<span class="oc-flex oc-flex-center">
<oc-tag class="tags-control-tag oc-ml-xs" :rounded="true" size="small">
<oc-icon name="price-tag-3" size="small" />
<span class="oc-text-truncate">{{ label }}</span>
</oc-tag>
</span>
</div>
<div v-if="error" class="oc-text-input-danger">{{ error }}</div>
</template>
</oc-select>
</div>
</div>
</span>
</div>
<div v-if="error" class="oc-text-input-danger">{{ error }}</div>
</template>
</oc-select>
</template>

<script lang="ts">
import { computed, defineComponent, inject, onMounted, ref, unref, VNodeRef, watch } from 'vue'
import { eventBus } from '@ownclouders/web-pkg'
import {
computed,
defineComponent,
onMounted,
PropType,
ref,
toRef,
unref,
VNodeRef,
watch
} from 'vue'
import {
createLocationCommon,
eventBus,
useClientService,
useGetMatchingSpace,
useRouter,
useStore
} from '@ownclouders/web-pkg/src'
import { useGettext } from 'vue3-gettext'
import { useTask } from 'vue-concurrency'
import { useClientService, useConfigurationManager, useStore } from '@ownclouders/web-pkg'
import { Resource } from '@ownclouders/web-client'
import diff from 'lodash-es/difference'
import { useGettext } from 'vue3-gettext'
import keycode from 'keycode'
import { tagsHelper } from 'web-app-files/src/helpers/contextualHelpers'
import { ContextualHelper } from 'design-system/src/helpers'

const tagsMaxCount = 100
import { Resource } from '@ownclouders/web-client'

type TagOption = {
label: string
error?: string
selectable?: boolean
}

const tagsMaxCount = 100

export default defineComponent({
name: 'TagsPanel',
setup() {
name: 'TagsSelect',
props: {
/**
* The resource
*/
resource: {
type: Object as PropType<Resource>,
required: true
}
},
setup(props) {
const store = useStore()
const clientService = useClientService()
const { $gettext } = useGettext()
const configurationManager = useConfigurationManager()
const { getMatchingSpace } = useGetMatchingSpace()
const language = useGettext()
const $router = useRouter()

const injectedResource = inject<Resource>('resource')
const resource = computed<Resource>(() => unref(injectedResource))
const readonly = computed(() => unref(resource).locked === true)
const resource = toRef(props, 'resource')
const { $gettext } = useGettext()
const readonly = computed(
() =>
unref(resource).locked === true ||
(typeof unref(resource).canEditTags === 'function' &&
unref(resource).canEditTags() === false) // where is canEditTags implemented? it's not present here...
AlexAndBear marked this conversation as resolved.
Show resolved Hide resolved
)
const selectedTags = ref<TagOption[]>([])
const availableTags = ref<TagOption[]>([])
let allTags: string[] = []
Expand Down Expand Up @@ -212,17 +235,18 @@ export default defineComponent({
return objectMapping
}

const contextualHelper = {
isEnabled: configurationManager.options.contextHelpers,
data: tagsHelper({ configurationManager: configurationManager })
} as ContextualHelper
const generateTagLink = (tag: string) => {
const currentTerm = unref($router.currentRoute).query?.term
return createLocationCommon('files-common-search', {
query: { provider: 'files.sdk', q_tags: tag, ...(currentTerm && { term: currentTerm }) }
})
}

return {
loadAvailableTagsTask,
availableTags,
tagsMaxCount,
selectedTags,
resource,
tagSelect,
currentTags,
revertChanges,
Expand All @@ -232,21 +256,15 @@ export default defineComponent({
save,
keycode,
keydownMethods,
contextualHelper,
readonly
readonly,
generateTagLink
}
}
})
</script>

<style lang="scss">
#tags-panel {
#tags-form {
border-radius: 5px;
}
}
.tags-control-tag {
max-width: 12rem;
height: var(--oc-space-large);
<style scoped lang="scss">
.oc-tag {
height: 1.5rem;
}
</style>
Loading