Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/design-system/src/components/OcTable/OcTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ const handleSort = (field: FieldType) => {
.oc-table-hover tr {
@apply transition-colors duration-200 ease-in-out;
}
.oc-table-accentuated,
.item-accentuated,
.oc-table-highlighted,
.oc-table .highlightedDropTarget {
@apply bg-role-secondary-container;
Expand Down
5 changes: 0 additions & 5 deletions packages/web-app-files/src/HandleUpload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,11 +363,6 @@ export class HandleUpload extends BasePlugin<PluginOpts, OcUppyMeta, OcUppyBody>
...uppyFile,
meta: { ...uppyFile.meta, fileId: folder?.fileId }
})

if (isRoot && this.resourcesStore.currentFolder?.id === uploadFolder.id) {
// update file list for top level folders when the current folder is the upload target folder
this.resourcesStore.upsertResource(folder)
}
} catch (error) {
if (error.statusCode !== 405) {
console.error(error)
Expand Down
73 changes: 30 additions & 43 deletions packages/web-app-files/src/components/AppBar/CreateAndUpload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,7 @@ import {
import ResourceUpload from './Upload/ResourceUpload.vue'

import { computed, onMounted, onBeforeUnmount, unref, watch, ref } from 'vue'
import { eventBus } from '@opencloud-eu/web-pkg'
import {
Resource,
SpaceResource,
isPublicSpaceResource,
isShareSpaceResource
} from '@opencloud-eu/web-client'
import { Resource, SpaceResource, isPublicSpaceResource } from '@opencloud-eu/web-client'
import { useService, useUpload, UppyService, UploadResult } from '@opencloud-eu/web-pkg'
import { HandleUpload } from '../../HandleUpload'
import { useGettext } from 'vue3-gettext'
Expand All @@ -216,15 +210,10 @@ import { v4 as uuidV4 } from 'uuid'
import { storeToRefs } from 'pinia'
import { uploadMenuExtensionPoint } from '../../extensionPoints'

const {
space,
item,
itemId,
limitedScreenSpace = false
} = defineProps<{
const { space, limitedScreenSpace = false } = defineProps<{
space: SpaceResource
item?: string
itemId?: string | number
itemId?: string
limitedScreenSpace?: boolean
}>()

Expand Down Expand Up @@ -334,39 +323,37 @@ useEventListener(document, 'paste', (event: ClipboardEvent) => {
})

const onUploadComplete = async (result: UploadResult) => {
if (result.successful) {
const file = result.successful[0]

if (!file) {
return
}
const file = result.successful?.[0]
if (!file) {
return
}

const { spaceId, currentFolder, currentFolderId, driveType } = file.meta
if (!isPublicSpaceResource(unref(computedSpace))) {
const isOwnSpace = spacesStore.spaces
.find(({ id }) => id === spaceId)
?.isOwner(userStore.user)

if (driveType === 'project' || isOwnSpace) {
const client = clientService.graphAuthenticated
const updatedSpace = await client.drives.getDrive(spaceId)
spacesStore.updateSpaceField({
id: updatedSpace.id,
field: 'spaceQuota',
value: updatedSpace.spaceQuota
})
}
const { spaceId, driveType } = file.meta
if (!isPublicSpaceResource(unref(computedSpace))) {
const isOwnSpace = spacesStore.spaces.find(({ id }) => id === spaceId)?.isOwner(userStore.user)

if (driveType === 'project' || isOwnSpace) {
const client = clientService.graphAuthenticated
const updatedSpace = await client.drives.getDrive(spaceId)
spacesStore.updateSpaceField({
id: updatedSpace.id,
field: 'spaceQuota',
value: updatedSpace.spaceQuota
})
}
}

const sameFolder =
itemId && !isShareSpaceResource(unref(computedSpace))
? itemId.toString().startsWith(currentFolderId.toString())
: currentFolder === item
const fileIsInCurrentPath = spaceId === unref(computedSpace).id && sameFolder
if (fileIsInCurrentPath) {
eventBus.publish('app.files.list.load')
}
if (!unref(currentFolder) || spaceId !== unref(computedSpace).id) {
return
}

const { children } = await clientService.webdav.listFiles(unref(computedSpace), {
path: unref(currentFolder).path
})

const existingIds = new Set(resourcesStore.resources.map((r) => r.id))
const newResources = children.filter((child) => !existingIds.has(child.id))
resourcesStore.upsertResources(newResources)
}

const isMovingIntoSameFolder = computed(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,21 @@ export const useResourcesViewDefaults = <T extends Resource, TT, TU extends any[
page: paginationPage
} = usePagination<T>({ items, perPageStoragePrefix: 'files' })

const accentuateItem = async (id: string) => {
await nextTick()
fileList.accentuateItem(id)
}
resourcesStore.$onAction((action) => {
if (action.name === 'upsertResource') {
accentuateItem(action.args[0].id)
}
action.after(async () => {
switch (action.name) {
case 'upsertResource':
await nextTick()
fileList.accentuateItem(action.args[0].id)
break
case 'upsertResources':
await nextTick()
for (const resource of action.args[0]) {
fileList.accentuateItem(resource.id)
}
break
}
})
})

return {
Expand Down
4 changes: 2 additions & 2 deletions packages/web-app-files/src/helpers/ui/filesList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export const accentuateItem = (id: string, clearTimeout = 3500): void => {
return
}

item.classList.add('oc-table-accentuated')
item.classList.add('item-accentuated')
setTimeout(() => {
item.classList.remove('oc-table-accentuated')
item.classList.remove('item-accentuated')
}, clearTimeout)
}
2 changes: 1 addition & 1 deletion packages/web-app-files/src/views/spaces/GenericSpace.vue
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ export default defineComponent({
default: null
},
itemId: {
type: [String, Number],
type: String,
required: false,
default: null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import {
useFileActionsPaste,
useExtensionRegistry,
OcUppyFile,
ClipboardActions
ClipboardActions,
useResourcesStore
} from '@opencloud-eu/web-pkg'
import { eventBus } from '@opencloud-eu/web-pkg'
import { defaultPlugins, shallowMount, defaultComponentMocks } from '@opencloud-eu/web-test-helpers'
import { RouteLocation } from 'vue-router'
import { computed, ref, unref } from 'vue'
import { OcButton } from '@opencloud-eu/design-system/components'
import { ListFilesResult } from '@opencloud-eu/web-client/webdav'

vi.mock('@opencloud-eu/web-pkg', async (importOriginal) => ({
...(await importOriginal<any>()),
Expand Down Expand Up @@ -156,7 +157,9 @@ describe('CreateAndUpload component', () => {
{ driveType: 'share', updated: 0 },
{ driveType: 'public', updated: 0 }
])('updates the space quota for supported drive types: %s', async ({ driveType, updated }) => {
const file = mock<OcUppyFile>({ meta: { driveType, spaceId: '1' } })
const file = mock<OcUppyFile>({
meta: { driveType, spaceId: '1', relativeFolder: undefined }
})
const spaces = [
mock<SpaceResource>({ id: file.meta.spaceId, isOwner: () => driveType === 'personal' })
]
Expand All @@ -167,18 +170,48 @@ describe('CreateAndUpload component', () => {
const spacesStore = useSpacesStore()
expect(spacesStore.updateSpaceField).toHaveBeenCalledTimes(updated)
})
it('reloads the file list if files were uploaded to the current path', async () => {
const eventSpy = vi.spyOn(eventBus, 'publish')
const itemId = 'itemId'
const space = mock<SpaceResource>({ id: '1' })
const { mocks } = getWrapper({ itemId, space })
const file = mock<OcUppyFile>({
meta: { driveType: 'project', spaceId: space.id, currentFolderId: itemId }
})

const itemId = 'itemId'
const space = mock<SpaceResource>({ id: '1' })
const file = mock<OcUppyFile>({
meta: {
driveType: 'project',
spaceId: space.id,
currentFolderId: itemId,
relativeFolder: undefined
}
})

it('updates the store with the new files', async () => {
const currentFolder = mock<Resource>({ id: itemId })
const uploadedFile = mock<Resource>({ id: '2' })
const { mocks } = getWrapper({ itemId, space, currentFolder, uploadedFiles: [uploadedFile] })
const graphMock = mocks.$clientService.graphAuthenticated
graphMock.drives.getDrive.mockResolvedValue(mock<SpaceResource>())
await unref(mocks.onUploadCompleteCallback)({ successful: [file], failed: [] })
expect(eventSpy).toHaveBeenCalled()
await unref(mocks.onUploadCompleteCallback)({ successful: [file] })
const resourcesStore = useResourcesStore()
expect(resourcesStore.upsertResources).toHaveBeenCalledWith([uploadedFile])
})
it('does not update the store if no current folder given', async () => {
const currentFolder = mock<Resource>({ id: '2' })
const { mocks } = getWrapper({ itemId, space, currentFolder })
const graphMock = mocks.$clientService.graphAuthenticated
graphMock.drives.getDrive.mockResolvedValue(mock<SpaceResource>())
const resourcesStore = useResourcesStore()
resourcesStore.currentFolder = null
await unref(mocks.onUploadCompleteCallback)({ successful: [file] })
expect(resourcesStore.upsertResources).not.toHaveBeenCalled()
})
it('does not update the store if user navigated into another space after the upload', async () => {
const currentFolder = mock<Resource>({ id: '2' })
const { mocks } = getWrapper({ itemId, space, currentFolder })
const graphMock = mocks.$clientService.graphAuthenticated
graphMock.drives.getDrive.mockResolvedValue(mock<SpaceResource>())
const uploadedFile = { ...file }
uploadedFile.meta.spaceId = 'another-space'
await unref(mocks.onUploadCompleteCallback)({ successful: [uploadedFile] })
const resourcesStore = useResourcesStore()
expect(resourcesStore.upsertResources).not.toHaveBeenCalled()
})
})
describe('drop target', () => {
Expand Down Expand Up @@ -208,7 +241,8 @@ function getWrapper({
mock<FileAction>({ label: () => 'Mark-down file', ext: 'md' }),
mock<FileAction>({ label: () => 'Draw.io document', ext: 'drawio' })
],
clipboardAction = ClipboardActions.Cut
clipboardAction = ClipboardActions.Cut,
uploadedFiles = []
}: {
clipboardResources?: Resource[]
files?: Resource[]
Expand All @@ -220,6 +254,7 @@ function getWrapper({
areFileExtensionsShown?: boolean
createActions?: FileAction[]
clipboardAction?: ClipboardActions
uploadedFiles?: Resource[]
} = {}) {
const capabilities = {
spaces: { enabled: true },
Expand Down Expand Up @@ -261,6 +296,9 @@ function getWrapper({
onUploadCompleteCallback.value = callback
return null
})
defaultMocks.$clientService.webdav.listFiles.mockResolvedValue(
mock<ListFilesResult>({ children: uploadedFiles })
)

const mocks = {
...defaultMocks,
Expand Down
12 changes: 6 additions & 6 deletions packages/web-app-files/tests/unit/helpers/ui/filesList.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ describe('accentuateItem', () => {
const trs = document.getElementsByTagName('tr')

accentuateItem('1', 50)
expect(trs[0].classList.contains('oc-table-accentuated')).toBe(true)
expect(trs[1].classList.contains('oc-table-accentuated')).toBe(false)
expect(trs[0].classList.contains('item-accentuated')).toBe(true)
expect(trs[1].classList.contains('item-accentuated')).toBe(false)

vi.advanceTimersByTime(100)
expect(trs[0].classList.contains('oc-table-accentuated')).toBe(false)
expect(trs[1].classList.contains('oc-table-accentuated')).toBe(false)
expect(trs[0].classList.contains('item-accentuated')).toBe(false)
expect(trs[1].classList.contains('item-accentuated')).toBe(false)

accentuateItem('2', 50)
expect(trs[0].classList.contains('oc-table-accentuated')).toBe(false)
expect(trs[1].classList.contains('oc-table-accentuated')).toBe(true)
expect(trs[0].classList.contains('item-accentuated')).toBe(false)
expect(trs[1].classList.contains('item-accentuated')).toBe(true)

// do not fail in setTimeout if element went away
trs[1].remove()
Expand Down
2 changes: 1 addition & 1 deletion packages/web-pkg/src/components/FilesList/ResourceTile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<oc-card
ref="observerTarget"
body-class="p-0"
class="oc-tile-card flex flex-col h-full shadow-none"
class="oc-tile-card flex flex-col h-full shadow-none [&.item-accentuated]:bg-role-secondary-container"
:data-item-id="resource.id"
:class="{
'oc-tile-card-selected bg-role-secondary-container outline-2 outline-role-outline':
Expand Down
6 changes: 3 additions & 3 deletions packages/web-pkg/src/services/uppy/uppyService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,9 @@ export class UppyService {
return
}
this.publish('uploadCompleted', result)
result.successful.forEach((file) => {
this.uppy.removeFile(file.id)
})
for (let i = 0; i < result.successful.length; i++) {
this.uppy.removeFile(result.successful[i].id)
}
Comment on lines +266 to +268
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For performance reasons, there may be several thousand files.

this.clearInputs()
})
this.uppy.on('upload-success', (file) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`OcTile component > renders default space correctly 1`] = `
"<oc-card-stub tag="div" titletag="h2" logourl="" headerclass="" bodyclass="p-0" footerclass="" class="oc-tile-card flex flex-col h-full shadow-none bg-role-surface-container hover:bg-role-surface-container-highest outline outline-role-surface-container-highest" data-item-id="1">
"<oc-card-stub tag="div" titletag="h2" logourl="" headerclass="" bodyclass="p-0" footerclass="" class="oc-tile-card flex flex-col h-full shadow-none [&amp;.item-accentuated]:bg-role-secondary-container bg-role-surface-container hover:bg-role-surface-container-highest outline outline-role-surface-container-highest" data-item-id="1">
<resource-link-stub resource="[object Object]" isresourceclickable="true" class="oc-card-media-top flex justify-center items-center m-0 w-full relative aspect-[16/9]" tabindex="-1">
<div class="z-10 absolute top-0 left-0 [&amp;_input]:not-[.oc-checkbox-checked]:bg-role-surface-container"></div>
<!--v-if-->
Expand All @@ -26,7 +26,7 @@ exports[`OcTile component > renders default space correctly 1`] = `
`;

exports[`OcTile component > renders disabled space correctly 1`] = `
"<oc-card-stub tag="div" titletag="h2" logourl="" headerclass="" bodyclass="p-0" footerclass="" class="oc-tile-card flex flex-col h-full shadow-none bg-role-surface-container hover:bg-role-surface-container-highest outline outline-role-surface-container-highest oc-tile-card-disabled opacity-70 grayscale-60 pointer-events-none" data-item-id="1">
"<oc-card-stub tag="div" titletag="h2" logourl="" headerclass="" bodyclass="p-0" footerclass="" class="oc-tile-card flex flex-col h-full shadow-none [&amp;.item-accentuated]:bg-role-secondary-container bg-role-surface-container hover:bg-role-surface-container-highest outline outline-role-surface-container-highest oc-tile-card-disabled opacity-70 grayscale-60 pointer-events-none" data-item-id="1">
<resource-link-stub resource="[object Object]" isresourceclickable="true" class="oc-card-media-top flex justify-center items-center m-0 w-full relative aspect-[16/9]" tabindex="-1">
<div class="z-10 absolute top-0 left-0 [&amp;_input]:not-[.oc-checkbox-checked]:bg-role-surface-container"></div>
<!--v-if-->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ exports[`ResourceTiles component > renders an array of spaces correctly 1`] = `
</div>
<ul data-v-67d39700="" class="oc-list oc-tiles grid justify-start gap-3">
<li data-v-67d39700="" class="oc-tiles-item has-item-context-menu">
<div data-v-67d39700="" class="oc-card oc-tile-card flex flex-col h-full shadow-none bg-role-surface-container hover:bg-role-surface-container-highest outline outline-role-surface-container-highest" data-item-id="1" draggable="false">
<div data-v-67d39700="" class="oc-card oc-tile-card flex flex-col h-full shadow-none [&amp;.item-accentuated]:bg-role-secondary-container bg-role-surface-container hover:bg-role-surface-container-highest outline outline-role-surface-container-highest" data-item-id="1" draggable="false">
<!--v-if-->
<div class="oc-card-body p-0"><a data-v-88f32d7c="" attrs="[object Object]" target="_self" draggable="false" class="oc-resource-link max-w-full oc-card-media-top flex justify-center items-center m-0 w-full relative aspect-[16/9]" tabindex="-1"></a>
<div class="p-2">
Expand Down Expand Up @@ -65,7 +65,7 @@ exports[`ResourceTiles component > renders an array of spaces correctly 1`] = `
</div>
</li>
<li data-v-67d39700="" class="oc-tiles-item has-item-context-menu">
<div data-v-67d39700="" class="oc-card oc-tile-card flex flex-col h-full shadow-none bg-role-surface-container hover:bg-role-surface-container-highest outline outline-role-surface-container-highest" data-item-id="2" draggable="false">
<div data-v-67d39700="" class="oc-card oc-tile-card flex flex-col h-full shadow-none [&amp;.item-accentuated]:bg-role-secondary-container bg-role-surface-container hover:bg-role-surface-container-highest outline outline-role-surface-container-highest" data-item-id="2" draggable="false">
<!--v-if-->
<div class="oc-card-body p-0"><a data-v-88f32d7c="" attrs="[object Object]" target="_self" draggable="false" class="oc-resource-link max-w-full oc-card-media-top flex justify-center items-center m-0 w-full relative aspect-[16/9]" tabindex="-1"></a>
<div class="p-2">
Expand Down