Skip to content

Commit

Permalink
Merge pull request #10033 from owncloud/shares-search-filter
Browse files Browse the repository at this point in the history
Shares search filter
  • Loading branch information
JammingBen authored Nov 23, 2023
2 parents f1f799b + 847a581 commit cd16c43
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 103 deletions.
6 changes: 6 additions & 0 deletions changelog/unreleased/enhancement-share-search-filter
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Share search filter

The received shares on the "Shared with me"-page can now be filtered by their names via a text input field.

https://github.com/owncloud/web/issues/10014
https://github.com/owncloud/web/pull/10033
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<template>
<div id="group-list">
<oc-text-input
id="groups-filter"
v-model="filterTerm"
class="oc-ml-m oc-my-s"
:label="$gettext('Search')"
autocomplete="off"
/>
<div class="group-filters oc-flex oc-flex-right oc-flex-wrap oc-flex-bottom oc-mx-m oc-mb-m">
<oc-text-input
id="groups-filter"
v-model="filterTerm"
:label="$gettext('Search')"
autocomplete="off"
/>
</div>
<oc-table
ref="tableRef"
:sort-by="sortBy"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<template>
<div id="space-list">
<oc-text-input
id="spaces-filter"
v-model="filterTerm"
class="oc-ml-m oc-my-s"
:label="$gettext('Search')"
autocomplete="off"
/>
<div class="space-filters oc-flex oc-flex-right oc-flex-wrap oc-flex-bottom oc-mx-m oc-mb-m">
<oc-text-input
id="spaces-filter"
v-model="filterTerm"
:label="$gettext('Search')"
autocomplete="off"
/>
</div>
<oc-table
ref="tableRef"
class="spaces-table"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<template>
<div id="user-list">
<oc-text-input
id="users-filter"
v-model="filterTerm"
class="oc-ml-m oc-my-s"
:label="$gettext('Search')"
autocomplete="off"
/>
<slot name="filter" />
<div class="user-filters oc-flex oc-flex-between oc-flex-wrap oc-flex-bottom oc-mx-m oc-mb-m">
<slot name="filter" />
<oc-text-input
id="users-filter"
v-model="filterTerm"
:label="$gettext('Search')"
autocomplete="off"
/>
</div>
<no-content-message v-if="!users.length" icon="user">
<template #message>
<span v-text="$gettext('No users in here')" />
Expand Down
2 changes: 1 addition & 1 deletion packages/web-app-admin-settings/src/views/Users.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<context-actions :items="selectedUsers" />
</template>
<template #filter>
<div class="oc-flex oc-flex-middle oc-ml-m oc-mb-m oc-mt-m">
<div class="oc-flex oc-flex-middle">
<div class="oc-mr-m oc-flex oc-flex-middle">
<oc-icon name="filter-2" class="oc-mr-xs" />
<span v-text="$gettext('Filter:')" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

exports[`SpacesList should render all spaces in a table 1`] = `
<div headerposition="0" id="space-list">
<div class="oc-ml-m oc-my-s">
<label class="oc-label" for="spaces-filter">Search</label>
<div class="oc-position-relative">
<div class="space-filters oc-flex oc-flex-right oc-flex-wrap oc-flex-bottom oc-mx-m oc-mb-m">
<div class="">
<label class="oc-label" for="spaces-filter">Search</label>
<div class="oc-position-relative">
<!--v-if-->
<input aria-invalid="false" autocomplete="off" class="oc-text-input oc-input oc-rounded" id="spaces-filter" type="text">
<!--v-if-->
</div>
<!--v-if-->
<input aria-invalid="false" autocomplete="off" class="oc-text-input oc-input oc-rounded" id="spaces-filter" type="text">
<!--v-if-->
</div>
<!--v-if-->
<!--v-if-->
</div>
<table class="oc-table oc-table-hover oc-table-sticky has-item-context-menu spaces-table">
<thead class="oc-thead">
Expand Down
139 changes: 91 additions & 48 deletions packages/web-app-files/src/views/shares/SharedWithMe.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,64 @@
</app-bar>
<app-loading-spinner v-if="areResourcesLoading" />
<template v-else>
<div class="oc-flex oc-m-m">
<div class="oc-mr-m oc-flex oc-flex-middle">
<oc-icon name="filter-2" class="oc-mr-xs" />
<span v-text="$gettext('Filter:')" />
<div
class="shared-with-me-filters oc-flex oc-flex-between oc-flex-wrap oc-flex-bottom oc-mx-m oc-mb-m"
>
<div class="oc-flex">
<div class="oc-mr-m oc-flex oc-flex-middle">
<oc-icon name="filter-2" class="oc-mr-xs" />
<span v-text="$gettext('Filter:')" />
</div>
<item-filter-inline
class="share-visibility-filter"
filter-name="share-visibility"
:filter-options="visibilityOptions"
@toggle-filter="setAreHiddenFilesShown"
/>
<item-filter
:allow-multiple="true"
:filter-label="$gettext('Share Type')"
:filterable-attributes="['label']"
:items="shareTypes"
:option-filter-label="$gettext('Filter share types')"
:show-option-filter="true"
id-attribute="key"
class="share-type-filter oc-ml-s"
display-name-attribute="label"
filter-name="shareType"
>
<template #item="{ item }">
<span class="oc-ml-s" v-text="item.label" />
</template>
</item-filter>
<item-filter
:allow-multiple="true"
:filter-label="$gettext('Shared By')"
:filterable-attributes="['displayName']"
:items="fileOwners"
:option-filter-label="$gettext('Filter shared by')"
:show-option-filter="true"
id-attribute="username"
class="shared-by-filter oc-ml-s"
display-name-attribute="displayName"
filter-name="sharedBy"
>
<template #image="{ item }">
<avatar-image :width="32" :userid="item.username" :user-name="item.displayName" />
</template>
<template #item="{ item }">
<span class="oc-ml-s" v-text="item.displayName" />
</template>
</item-filter>
</div>
<div>
<oc-text-input
v-model="filterTerm"
class="search-filter"
:label="$gettext('Search')"
autocomplete="off"
/>
</div>
<item-filter-inline
class="share-visibility-filter"
filter-name="share-visibility"
:filter-options="visibilityOptions"
@toggle-filter="setAreHiddenFilesShown"
/>
<item-filter
:allow-multiple="true"
:filter-label="$gettext('Share Type')"
:filterable-attributes="['label']"
:items="shareTypes"
:option-filter-label="$gettext('Filter share types')"
:show-option-filter="true"
id-attribute="key"
class="share-type-filter oc-ml-s"
display-name-attribute="label"
filter-name="shareType"
>
<template #item="{ item }">
<span class="oc-ml-s" v-text="item.label" />
</template>
</item-filter>
<item-filter
:allow-multiple="true"
:filter-label="$gettext('Shared By')"
:filterable-attributes="['displayName']"
:items="fileOwners"
:option-filter-label="$gettext('Filter shared by')"
:show-option-filter="true"
id-attribute="username"
class="shared-by-filter oc-ml-s"
display-name-attribute="displayName"
filter-name="sharedBy"
>
<template #image="{ item }">
<avatar-image :width="32" :userid="item.username" :user-name="item.displayName" />
</template>
<template #item="{ item }">
<span class="oc-ml-s" v-text="item.displayName" />
</template>
</item-filter>
</div>
<shared-with-me-section
id="files-shared-with-me-view"
Expand All @@ -77,21 +89,23 @@
</template>

<script lang="ts">
import Fuse from 'fuse.js'
import Mark from 'mark.js'
import { useResourcesViewDefaults } from '../../composables'
import { AppLoadingSpinner, InlineFilterOption, ItemFilter } from '@ownclouders/web-pkg'
import { AppBar, ItemFilterInline } from '@ownclouders/web-pkg'
import { queryItemAsString, useRouteQuery } from '@ownclouders/web-pkg'
import SharedWithMeSection from '../../components/Shares/SharedWithMeSection.vue'
import { computed, defineComponent, onMounted, ref, unref } from 'vue'
import { computed, defineComponent, onMounted, ref, unref, watch } from 'vue'
import { Resource } from '@ownclouders/web-client'
import SideBar from '../../components/SideBar/SideBar.vue'
import FilesViewWrapper from '../../components/FilesViewWrapper.vue'
import { useGetMatchingSpace, useSort } from '@ownclouders/web-pkg'
import { useGroupingSettings } from '@ownclouders/web-pkg'
import SharesNavigation from 'web-app-files/src/components/AppBar/SharesNavigation.vue'
import { useGettext } from 'vue3-gettext'
import { useStore, useOpenWithDefaultApp } from '@ownclouders/web-pkg'
import { useStore, useOpenWithDefaultApp, defaultFuseOptions } from '@ownclouders/web-pkg'
import { ShareTypes } from '@ownclouders/web-client/src/helpers'
import { uniq } from 'lodash-es'
Expand Down Expand Up @@ -126,9 +140,11 @@ export default defineComponent({
const { $gettext } = useGettext()
const areHiddenFilesShown = ref(false)
const filterTerm = ref('')
const markInstance = ref<Mark>()
const shareSectionTitle = computed(() => {
return areHiddenFilesShown.value ? $gettext('Hidden Shares') : $gettext('Shares')
return unref(areHiddenFilesShown) ? $gettext('Hidden Shares') : $gettext('Shares')
})
const visibilityOptions = computed(() => [
Expand Down Expand Up @@ -166,9 +182,29 @@ export default defineComponent({
)
}
if (unref(filterTerm).trim()) {
const usersSearchEngine = new Fuse(result, { ...defaultFuseOptions, keys: ['name'] })
const fuseResult = usersSearchEngine.search(unref(filterTerm)).map((r) => r.item)
result = fuseResult.filter((item) => result.includes(item))
}
return result
})
watch(filteredItems, () => {
if (!unref(areResourcesLoading)) {
if (!unref(markInstance)) {
markInstance.value = new Mark('.oc-resource-details')
}
unref(markInstance).unmark()
unref(markInstance).mark(unref(filterTerm), {
element: 'span',
className: 'highlight-mark'
})
}
})
const { sortBy, sortDir, items, handleSort } = useSort({
items: filteredItems,
fields: sortFields
Expand Down Expand Up @@ -234,6 +270,7 @@ export default defineComponent({
visibleShares,
shareTypes,
fileOwners,
filterTerm,
handleSort,
sortBy,
Expand All @@ -246,3 +283,9 @@ export default defineComponent({
}
})
</script>

<style lang="scss" scoped>
.search-filter {
width: 16rem;
}
</style>
15 changes: 8 additions & 7 deletions packages/web-app-files/src/views/spaces/Projects.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@
</template>
</no-content-message>
<div v-else class="spaces-list oc-mt-l">
<oc-text-input
id="spaces-filter"
v-model="filterTerm"
class="oc-ml-m oc-my-m"
:label="$gettext('Search')"
autocomplete="off"
/>
<div class="spaces-list-filters oc-flex oc-flex-right oc-px-m oc-mb-m">
<oc-text-input
id="spaces-filter"
v-model="filterTerm"
:label="$gettext('Search')"
autocomplete="off"
/>
</div>
<resource-tiles
v-if="viewMode === ViewModeConstants.tilesView.name"
v-model:selectedIds="selectedResourcesIds"
Expand Down
17 changes: 10 additions & 7 deletions packages/web-app-files/src/views/trash/Overview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
</template>
</no-content-message>
<template v-else>
<oc-text-input
id="spaces-filter"
v-model="filterTerm"
class="oc-ml-m oc-my-s"
:label="$gettext('Search')"
autocomplete="off"
/>
<div
class="trash-bin-filters oc-flex oc-flex-right oc-flex-wrap oc-flex-bottom oc-mx-m oc-mb-m"
>
<oc-text-input
id="spaces-filter"
v-model="filterTerm"
:label="$gettext('Search')"
autocomplete="off"
/>
</div>
<oc-table
ref="tableRef"
class="spaces-table"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,33 @@ describe('SharedWithMe view', () => {
expect(filterItems).toEqual([collaborator1, collaborator2])
})
})
describe('search', () => {
it('shows filter', () => {
const { wrapper } = getMountedWrapper()
expect(wrapper.find('.search-filter').exists()).toBeTruthy()
})
it('filters shares accordingly by name', async () => {
const { wrapper } = getMountedWrapper({
files: [
mock<Resource>({
name: 'share1',
hidden: false,
share: { shareType: ShareTypes.user.value }
}),
mock<Resource>({
name: 'share2',
hidden: false,
share: { shareType: ShareTypes.user.value }
})
]
})

await wrapper.vm.$nextTick()
wrapper.vm.filterTerm = 'share1'
expect(wrapper.vm.items.find(({ name }) => name === 'share1')).toBeDefined()
expect(wrapper.vm.items.find(({ name }) => name === 'share2')).toBeUndefined()
})
})
})
})

Expand Down
Loading

0 comments on commit cd16c43

Please sign in to comment.