Skip to content

Commit

Permalink
fix(files_sharing): Make account file filter consistent have design
Browse files Browse the repository at this point in the history
Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux authored and blizzz committed Jul 30, 2024
1 parent 8b4340a commit 77cffcb
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 19 deletions.
10 changes: 9 additions & 1 deletion apps/files/src/components/FileListFilters.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@
<NcChip :aria-label-close="t('files', 'Remove filter')"
:icon-svg="chip.icon"
:text="chip.text"
@close="chip.onclick" />
@close="chip.onclick">
<template v-if="chip.user" #icon>
<NcAvatar disable-menu
:show-user-status="false"
:size="24"
:user="chip.user" />
</template>
</NcChip>
</li>
</ul>
</div>
Expand All @@ -25,6 +32,7 @@ import { t } from '@nextcloud/l10n'
import { computed, ref, watchEffect } from 'vue'
import { useFiltersStore } from '../store/filters.ts'

import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js'
import NcChip from '@nextcloud/vue/dist/Components/NcChip.js'

const filterStore = useFiltersStore()
Expand Down
2 changes: 2 additions & 0 deletions apps/files/src/store/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const useFiltersStore = defineStore('keyboard', {
onFilterUpdateChips(event: FilterUpdateChipsEvent) {
const id = (event.target as IFileListFilter).id
this.chips = { ...this.chips, [id]: [...event.detail] }

logger.debug('File list filter chips updated', { filter: id, chips: event.detail })
},

init() {
Expand Down
101 changes: 86 additions & 15 deletions apps/files_sharing/src/components/FileListFilterAccount.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,53 @@
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<NcSelect v-model="selectedAccounts"
:aria-label-combobox="t('files_sharing', 'Accounts')"
class="file-list-filter-accounts"
multiple
no-wrap
:options="availableAccounts"
:placeholder="t('files_sharing', 'Accounts')"
user-select />
<FileListFilter class="file-list-filter-accounts"
:is-active="selectedAccounts.length > 0"
:filter-name="t('files', 'People')"
@reset-filter="resetFilter">
<template #icon>
<NcIconSvgWrapper :path="mdiAccountMultiple" />
</template>
<NcActionInput v-if="availableAccounts.length > 1"
:label="t('files_sharing', 'Filter accounts')"
:label-outside="false"
:show-trailing-button="false"
type="search"
:value.sync="accountFilter" />
<NcActionButton v-for="account of shownAccounts"
:key="account.id"
class="file-list-filter-accounts__item"
type="radio"
:model-value="selectedAccounts.includes(account)"
:value="account.id"
@click="toggleAccount(account.id)">
<template #icon>
<NcAvatar class="file-list-filter-accounts__avatar"
v-bind="account"
:size="24"
disable-menu
:show-user-status="false" />
</template>
{{ account.displayName }}
</NcActionButton>
</FileListFilter>
</template>

<script setup lang="ts">
import type { IAccountData } from '../filters/AccountFilter.ts'

import { translate as t } from '@nextcloud/l10n'
import { mdiAccountMultiple } from '@mdi/js'
import { useBrowserLocation } from '@vueuse/core'
import { ref, watch, watchEffect } from 'vue'
import { computed, ref, watch } from 'vue'
import { useNavigation } from '../../../files/src/composables/useNavigation.ts'

import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
import FileListFilter from '../../../files/src/components/FileListFilter/FileListFilter.vue'
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js'
import NcAvatar from '@nextcloud/vue/dist/Components/NcAvatar.js'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
import { ShareType } from '@nextcloud/sharing'

interface IUserSelectData {
id: string
Expand All @@ -35,9 +63,41 @@ const emit = defineEmits<{

const { currentView } = useNavigation()
const currentLocation = useBrowserLocation()
const accountFilter = ref('')
const availableAccounts = ref<IUserSelectData[]>([])
const selectedAccounts = ref<IUserSelectData[]>([])

/**
* Currently shown accounts (filtered)
*/
const shownAccounts = computed(() => {
if (!accountFilter.value) {
return availableAccounts.value
}
const queryParts = accountFilter.value.toLocaleLowerCase().trim().split(' ')
return availableAccounts.value.filter((account) =>
queryParts.every((part) =>
account.user.toLocaleLowerCase().includes(part)
|| account.displayName.toLocaleLowerCase().includes(part),
),
)
})

/**
* Toggle an account as selected
* @param accountId The account to toggle
*/
function toggleAccount(accountId: string) {
const account = availableAccounts.value.find(({ id }) => id === accountId)
if (account && selectedAccounts.value.includes(account)) {
selectedAccounts.value = selectedAccounts.value.filter(({ id }) => id !== accountId)
} else {
if (account) {
selectedAccounts.value = [...selectedAccounts.value, account]
}
}
}

// Watch selected account, on change we emit the new account data to the filter instance
watch(selectedAccounts, () => {
// Emit selected accounts as account data
Expand Down Expand Up @@ -75,6 +135,9 @@ async function updateAvailableAccounts(path: string = '/') {
if (sharee.id === '') {
continue
}
if (sharee.type !== ShareType.User && sharee.type !== ShareType.Remote) {
continue
}
// Add if not already added
if (!available.has(sharee.id)) {
available.set(sharee.id, {
Expand All @@ -94,23 +157,31 @@ async function updateAvailableAccounts(path: string = '/') {
*/
function resetFilter() {
selectedAccounts.value = []
accountFilter.value = ''
}
defineExpose({ resetFilter })
defineExpose({ resetFilter, toggleAccount })

// When the current view changes or the current directory,
// then we need to rebuild the available accounts
watchEffect(() => {
watch([currentView, currentLocation], () => {
if (currentView.value) {
// we have no access to the files router here...
const path = (currentLocation.value.search ?? '?dir=/').match(/(?<=&|\?)dir=([^&#]+)/)?.[1]
selectedAccounts.value = []
resetFilter()
updateAvailableAccounts(decodeURIComponent(path ?? '/'))
}
})
}, { immediate: true })
</script>

<style scoped lang="scss">
.file-list-filter-accounts {
max-width: 300px;
&__item {
min-width: 250px;
}

&__avatar {
// 24px is the avatar size
margin: calc((var(--default-clickable-area) - 24px) / 2)
}
}
</style>
18 changes: 15 additions & 3 deletions apps/files_sharing/src/filters/AccountFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { INode } from '@nextcloud/files'
import type { IFileListFilterChip, INode } from '@nextcloud/files'

import { FileListFilter, registerFileListFilter } from '@nextcloud/files'
import Vue from 'vue'
Expand All @@ -13,12 +13,14 @@ export interface IAccountData {
displayName: string
}

type CurrentInstance = Vue & { resetFilter: () => void, toggleAccount: (account: string) => void }

/**
* File list filter to filter by owner / sharee
*/
class AccountFilter extends FileListFilter {

private currentInstance?: Vue
private currentInstance?: CurrentInstance
private filterAccounts?: IAccountData[]

constructor() {
Expand All @@ -35,7 +37,7 @@ class AccountFilter extends FileListFilter {
el,
})
.$on('update:accounts', this.setAccounts.bind(this))
.$mount()
.$mount() as CurrentInstance
}

public filter(nodes: INode[]): INode[] {
Expand Down Expand Up @@ -66,6 +68,16 @@ class AccountFilter extends FileListFilter {

public setAccounts(accounts?: IAccountData[]) {
this.filterAccounts = accounts
let chips: IFileListFilterChip[] = []
if (this.filterAccounts && this.filterAccounts.length > 0) {
chips = this.filterAccounts.map(({ displayName, uid }) => ({
text: displayName,
user: uid,
onclick: () => this.currentInstance?.toggleAccount(uid),
}))
}

this.updateChips(chips)
this.filterUpdated()
}

Expand Down

0 comments on commit 77cffcb

Please sign in to comment.