Skip to content

Commit

Permalink
Add batch actions to spaces (#9627)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan authored Aug 30, 2023
1 parent d4d3a5a commit 2ed4c09
Show file tree
Hide file tree
Showing 24 changed files with 141 additions and 193 deletions.
6 changes: 6 additions & 0 deletions changelog/unreleased/enhancement-add-batch-actions-to-spaces
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Add batch actions to spaces

We've added batch actions to spaces view

https://github.com/owncloud/web/pull/9627
https://github.com/owncloud/web/issues/9626
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@
<oc-img
v-if="hasThumbnail"
:key="thumbnail"
v-oc-tooltip="tooltipLabelIcon"
:src="thumbnail"
class="oc-resource-thumbnail"
width="40"
height="40"
v-oc-tooltip="tooltipLabelIcon"
:aria-label="tooltipLabelIcon"
/>
<oc-resource-icon
v-else
v-oc-tooltip="tooltipLabelIcon"
:aria-label="tooltipLabelIcon"
v-else
:resource="resource"
>
<template v-if="showStatusIcon" #status>
Expand Down
2 changes: 1 addition & 1 deletion packages/design-system/src/components/OcTile/OcTile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
<span v-text="$gettext('Disabled')" />
</oc-tag>
<div
class="oc-tile-card-preview oc-flex oc-flex-middle oc-flex-center"
v-oc-tooltip="tooltipLabelIcon"
class="oc-tile-card-preview oc-flex oc-flex-middle oc-flex-center"
:aria-label="tooltipLabelIcon"
>
<div class="oc-tile-card-hover"></div>
Expand Down
61 changes: 55 additions & 6 deletions packages/web-app-files/src/components/AppBar/AppBar.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
<template>
<div id="files-app-bar" ref="filesAppBar" :class="{ 'files-app-bar-squashed': sideBarOpen }">
<quota-modal
v-if="quotaModalIsOpen"
:cancel="closeQuotaModal"
:spaces="selectedFiles"
:max-quota="maxQuota"
/>
<oc-hidden-announcer :announcement="selectedResourcesAnnouncement" level="polite" />

<div class="files-topbar oc-py-s">
<h1 class="oc-invisible-sr" v-text="pageTitle" />
<div
Expand Down Expand Up @@ -75,7 +82,7 @@ import {
SpaceResource
} from 'web-client/src/helpers'
import BatchActions from 'web-pkg/src/components/BatchActions.vue'
import { isLocationTrashActive } from '../../router'
import { isLocationCommonActive, isLocationTrashActive } from '../../router'
import ContextActions from '../FilesList/ContextActions.vue'
import SharesNavigation from './SharesNavigation.vue'
import SidebarToggle from './SidebarToggle.vue'
Expand All @@ -91,20 +98,34 @@ import {
useFileActionsMove,
useFileActionsRestore
} from 'web-app-files/src/composables/actions'
import { useRouteMeta, useStore, ViewModeConstants } from 'web-pkg/src/composables'
import {
useCapabilitySpacesMaxQuota,
useRouteMeta,
useStore,
ViewModeConstants
} from 'web-pkg/src/composables'
import { BreadcrumbItem } from 'design-system/src/components/OcBreadcrumb/types'
import { useActiveLocation } from 'web-app-files/src/composables'
import { EVENT_ITEM_DROPPED } from 'design-system/src/helpers'
import ViewOptions from 'web-pkg/src/components/ViewOptions.vue'
import { useGettext } from 'vue3-gettext'
import {
FileAction,
useSpaceActionsDelete,
useSpaceActionsDisable,
useSpaceActionsEditQuota,
useSpaceActionsRestore
} from 'web-pkg/src/composables/actions'
import { QuotaModal } from 'web-pkg'
export default defineComponent({
components: {
BatchActions,
ContextActions,
SharesNavigation,
SidebarToggle,
ViewOptions
ViewOptions,
QuotaModal
},
props: {
viewModeDefault: {
Expand Down Expand Up @@ -152,11 +173,20 @@ export default defineComponent({
const { actions: emptyTrashBinActions } = useFileActionsEmptyTrashBin({ store })
const { actions: moveActions } = useFileActionsMove({ store })
const { actions: restoreActions } = useFileActionsRestore({ store })
const { actions: deleteSpaceActions } = useSpaceActionsDelete({ store })
const { actions: disableSpaceActions } = useSpaceActionsDisable({ store })
const {
actions: editSpaceQuotaActions,
modalOpen: quotaModalIsOpen,
closeModal: closeQuotaModal
} = useSpaceActionsEditQuota({ store })
const { actions: restoreSpaceActions } = useSpaceActionsRestore({ store })
const breadcrumbMaxWidth = ref<number>(0)
const isSearchLocation = useActiveLocation(isLocationCommonActive, 'files-common-search')
const batchActions = computed(() => {
return [
let actions = [
...unref(acceptShareActions),
...unref(declineShareActions),
...unref(downloadArchiveActions),
Expand All @@ -166,7 +196,23 @@ export default defineComponent({
...unref(emptyTrashBinActions),
...unref(deleteActions),
...unref(restoreActions)
].filter((item) =>
]
/**
* We show mixed results in search result page, including resources like files and folders but also spaces.
* Space actions shouldn't be possible in that context.
**/
if (!isSearchLocation.value) {
actions = [
...actions,
...unref(editSpaceQuotaActions),
...unref(restoreSpaceActions),
...unref(deleteSpaceActions),
...unref(disableSpaceActions)
] as FileAction[]
}
return actions.filter((item) =>
item.isEnabled({ space: props.space, resources: store.getters['Files/selectedFiles'] })
)
})
Expand Down Expand Up @@ -222,7 +268,10 @@ export default defineComponent({
breadcrumbMaxWidth,
breadcrumbTruncationOffset,
fileDroppedBreadcrumb,
pageTitle
pageTitle,
quotaModalIsOpen,
closeQuotaModal,
maxQuota: useCapabilitySpacesMaxQuota()
}
},
data: function () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
<span class="oc-invisible-sr" v-text="screenreaderShareExpiration" />
</div>
<oc-button
class="oc-mx-s"
id="show-more-share-options-btn"
class="oc-mx-s"
:aria-label="$gettext('Show more actions')"
appearance="raw"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,8 @@ export const useFileActionsCopy = ({ store }: { store?: Store<any> } = {}) => {
icon: 'file-copy-2',
handler,
shortcut: unref(copyShortcutString),
label: ({ resources }) => {
const copyLabel = $pgettext(
'Action in the files list row to initiate copying resources',
'Copy'
)

if (isLocationCommonActive(router, 'files-common-search') && resources.length > 1) {
const copyableResourcesCount = resources.filter(
(r) => !isProjectSpaceResource(r)
).length
return `${copyLabel} (${copyableResourcesCount.toString()})`
}

return copyLabel
},
label: () =>
$pgettext('Action in the files list row to initiate copying resources', 'Copy'),
isEnabled: ({ resources }) => {
if (
!isLocationSpacesActive(router, 'files-spaces-generic') &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,7 @@ export const useFileActionsDelete = ({ store }: { store?: Store<any> } = {}) =>
{
name: 'delete',
icon: 'delete-bin-5',
label: ({ resources }) => {
const deleteLabel = $gettext('Delete')

if (isLocationCommonActive(router, 'files-common-search') && resources.length > 1) {
const deletableResourcesCount = resources.filter(
(r) =>
r.canBeDeleted() &&
(!unref(hasSpaces) || !r.isShareRoot()) &&
!isProjectSpaceResource(r)
).length
return `${deleteLabel} (${deletableResourcesCount.toString()})`
}

return deleteLabel
},
label: () => $gettext('Delete'),
handler: ({ space, resources }) => handler({ space, resources, deletePermanent: false }),
isEnabled: ({ space, resources }) => {
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,7 @@ export const useFileActionsDownloadArchive = ({ store }: { store?: Store<any> }
handler: async (args) => {
await loadingService.addTask(() => handler(args))
},
label: ({ resources }) => {
const downloadLabel = $gettext('Download')

if (isLocationCommonActive(router, 'files-common-search') && resources.length > 1) {
const downloadableResourcesCount = resources.filter(
(r) => r.canDownload() && !isProjectSpaceResource(r)
).length
return `${downloadLabel} (${downloadableResourcesCount.toString()})`
}

return downloadLabel
},
label: () => $gettext('Download'),
disabledTooltip: ({ resources }) => {
return areArchiverLimitsExceeded(resources)
? $gettext('The selection exceeds the allowed archive size (max. %{maxSize})', {
Expand Down
2 changes: 1 addition & 1 deletion packages/web-app-files/src/views/spaces/Projects.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
:breadcrumbs="breadcrumbs"
:has-sidebar-toggle="true"
:show-actions-on-selection="true"
:has-bulk-actions="false"
:has-bulk-actions="true"
:has-hidden-files="false"
:has-file-extensions="false"
:has-pagination="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`AppBar component renders by default no breadcrumbs, no bulkactions, no sharesnavigation but viewoptions and sidebartoggle 1`] = `
<div class="" displayviewmodeswitch="false" id="files-app-bar">
<!--v-if-->
<oc-hidden-announcer-stub announcement="No items selected." level="polite"></oc-hidden-announcer-stub>
<div class="files-topbar oc-py-s">
<h1 class="oc-invisible-sr">ExampleTitle</h1>
Expand All @@ -25,6 +26,7 @@ exports[`AppBar component renders by default no breadcrumbs, no bulkactions, no

exports[`AppBar component renders if given, with content in the actions slot 1`] = `
<div class="" displayviewmodeswitch="false" id="files-app-bar">
<!--v-if-->
<oc-hidden-announcer-stub announcement="No items selected." level="polite"></oc-hidden-announcer-stub>
<div class="files-topbar oc-py-s">
<h1 class="oc-invisible-sr">ExampleTitle</h1>
Expand All @@ -49,6 +51,7 @@ exports[`AppBar component renders if given, with content in the actions slot 1`]

exports[`AppBar component renders if given, with content in the content slot 1`] = `
<div class="" displayviewmodeswitch="false" id="files-app-bar">
<!--v-if-->
<oc-hidden-announcer-stub announcement="No items selected." level="polite"></oc-hidden-announcer-stub>
<div class="files-topbar oc-py-s">
<h1 class="oc-invisible-sr">ExampleTitle</h1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { mock } from 'jest-mock-extended'

const spaceMock = {
id: '1',
root: { permissions: [{ roles: ['manager'], grantedToIdentities: [{ user: { id: 1 } }] }] }
root: { permissions: [{ roles: ['manager'], grantedToIdentities: [{ user: { id: 1 } }] }] },
driveType: 'project'
}

describe('SpaceContextActions', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,6 @@ import { useFileActionsCopy } from 'web-app-files/src/composables'
describe('copy', () => {
describe('search context', () => {
describe('computed property "actions"', () => {
describe('label', () => {
it.each([
{
resources: [{ id: '1' }, { id: '2' }] as Resource[],
copyAbleCount: 2
},
{
resources: [
{ id: '1' },
{ id: '2' },
{ id: '3' },
{ id: '5', driveType: 'project' }
] as Resource[],
copyAbleCount: 3
}
])('should be set correctly', ({ resources, copyAbleCount }) => {
const { wrapper } = getWrapper({
searchLocation: true,
setup: ({ actions }) => {
expect(unref(actions)[0].label({ space: null, resources })).toContain(
`(${copyAbleCount.toString()})`
)
}
})
})
})
describe('handler', () => {
it.each([
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,40 +93,6 @@ describe('delete', () => {
})
describe('search context', () => {
describe('computed property "actions"', () => {
describe('label', () => {
it.each([
{
resources: [
{ canBeDeleted: () => true, isShareRoot: () => false },
{ canBeDeleted: () => true, isShareRoot: () => false }
] as Resource[],
deletableCount: 2
},
{
resources: [
{ canBeDeleted: () => true, isShareRoot: () => false },
{ canBeDeleted: () => true, isShareRoot: () => false },
{ canBeDeleted: () => true, isShareRoot: () => false },
{ canBeDeleted: () => false, isShareRoot: () => false },
{ canBeDeleted: () => true, isShareRoot: () => true },
{ canBeDeleted: () => true, isShareRoot: () => false, driveType: 'project' }
] as Resource[],
deletableCount: 3
}
])('should be set correctly', ({ resources, deletableCount }) => {
const { wrapper } = getWrapper({
searchLocation: true,
setup: () => {
const store = useStore()
const { actions } = useFileActionsDelete({ store })

expect(unref(actions)[0].label({ space: null, resources })).toContain(
`(${deletableCount.toString()})`
)
}
})
})
})
describe('handler', () => {
it.each([
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,6 @@ jest.mock('web-pkg/src/composables/archiverService/useArchiverService')
describe('downloadArchive', () => {
describe('search context', () => {
describe('computed property "actions"', () => {
describe('label', () => {
it.each([
{
resources: [
{ id: '1', canDownload: () => true },
{ id: '2', canDownload: () => true }
] as Resource[],
downloadableCount: 2
},
{
resources: [
{ id: '1', canDownload: () => true },
{ id: '2', canDownload: () => true },
{ id: '3', canDownload: () => true },
{ id: '4', canDownload: () => false },
{ id: '5', canDownload: () => true, driveType: 'project' }
] as Resource[],
downloadableCount: 3
}
])('should be set correctly', ({ resources, downloadableCount }) => {
const { wrapper } = getWrapper({
searchLocation: true,
setup: () => {
const store = useStore()
const { actions } = useFileActionsDownloadArchive({ store })

expect(unref(actions)[0].label({ space: null, resources })).toContain(
`(${downloadableCount.toString()})`
)
}
})
})
})
describe('handler', () => {
it.each([
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exports[`Projects view different files view states lists all available project s
<div class="oc-flex oc-width-1-1">
<div class="files-view-wrapper oc-width-expand">
<div id="files-view">
<app-bar-stub breadcrumbs="[object Object]" breadcrumbscontextactionsitems="" hasbulkactions="false" hasfileextensions="false" hashiddenfiles="false" haspagination="false" hassharesnavigation="false" hassidebartoggle="true" hasviewoptions="true" showactionsonselection="true" sidebaropen="false" viewmodedefault="resource-tiles" viewmodes="[object Object],[object Object]"></app-bar-stub>
<app-bar-stub breadcrumbs="[object Object]" breadcrumbscontextactionsitems="" hasbulkactions="true" hasfileextensions="false" hashiddenfiles="false" haspagination="false" hassharesnavigation="false" hassidebartoggle="true" hasviewoptions="true" showactionsonselection="true" sidebaropen="false" viewmodedefault="resource-tiles" viewmodes="[object Object],[object Object]"></app-bar-stub>
<div class="spaces-list oc-mt-l">
<resource-table-stub arepathsdisplayed="false" areresourcesclickable="true" arethumbnailsdisplayed="true" class="spaces-table" dragdrop="false" fieldsdisplayed="image,name,manager,members,totalQuota,usedQuota,remainingQuota,status,mdate" hasactions="true" headerposition="0" hover="true" isselectable="true" paddingx="small" resourcedomselector="[Function]" resources="[object Object],[object Object]" selectedids="" sort-fields="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" sortby="[Function]" sortdir="desc" sticky="false" viewmode="resource-table"></resource-table-stub>
</div>
Expand Down
Loading

0 comments on commit 2ed4c09

Please sign in to comment.