mirror of
https://github.com/nextcloud/server.git
synced 2026-02-20 00:12:30 -05:00
fix(files_sharing): show note, label and list of uploaded files on file drop
This was missing from the Vue migration of the public share view: - Show the note as the description of the file drop - Show the label as the heading of the file drop if available - Show list of uploaded files for verification Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
27149b7f24
commit
60ccc85e76
5 changed files with 99 additions and 19 deletions
|
|
@ -91,6 +91,9 @@ class DefaultPublicShareTemplateProvider implements IPublicShareTemplateProvider
|
|||
'disclaimer',
|
||||
$this->appConfig->getValueString('core', 'shareapi_public_link_disclaimertext'),
|
||||
);
|
||||
// file drops do not request the root folder so we need to provide label and note if available
|
||||
$this->initialState->provideInitialState('label', $share->getLabel());
|
||||
$this->initialState->provideInitialState('note', $share->getNote());
|
||||
}
|
||||
// Set up initial state
|
||||
$this->initialState->provideInitialState('isPublic', true);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
*/
|
||||
import type { VueConstructor } from 'vue'
|
||||
|
||||
import { Folder, Permission, View, davRemoteURL, davRootPath, getNavigation } from '@nextcloud/files'
|
||||
import { Folder, Permission, View, getNavigation } from '@nextcloud/files'
|
||||
import { defaultRemoteURL, defaultRootPath } from '@nextcloud/files/dav'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import svgCloudUpload from '@mdi/svg/svg/cloud-upload.svg?raw'
|
||||
|
|
@ -45,8 +46,8 @@ export default () => {
|
|||
// Fake a writeonly folder as root
|
||||
folder: new Folder({
|
||||
id: 0,
|
||||
source: `${davRemoteURL}${davRootPath}`,
|
||||
root: davRootPath,
|
||||
source: `${defaultRemoteURL}${defaultRootPath}`,
|
||||
root: defaultRootPath,
|
||||
owner: null,
|
||||
permissions: Permission.CREATE,
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -5,13 +5,29 @@
|
|||
<template>
|
||||
<NcEmptyContent class="file-drop-empty-content"
|
||||
data-cy-files-sharing-file-drop
|
||||
:name="t('files_sharing', 'File drop')">
|
||||
:name="name">
|
||||
<template #icon>
|
||||
<NcIconSvgWrapper :svg="svgCloudUpload" />
|
||||
</template>
|
||||
<template #description>
|
||||
{{ t('files_sharing', 'Upload files to {foldername}.', { foldername }) }}
|
||||
{{ disclaimer === '' ? '' : t('files_sharing', 'By uploading files, you agree to the terms of service.') }}
|
||||
<p>
|
||||
{{ shareNote || t('files_sharing', 'Upload files to {foldername}.', { foldername }) }}
|
||||
</p>
|
||||
<p v-if="disclaimer">
|
||||
{{ t('files_sharing', 'By uploading files, you agree to the terms of service.') }}
|
||||
</p>
|
||||
<NcNoteCard v-if="getSortedUploads().length"
|
||||
class="file-drop-empty-content__note-card"
|
||||
type="success">
|
||||
<h2 id="file-drop-empty-content__heading">
|
||||
{{ t('files_sharing', 'Successfully uploaded files') }}
|
||||
</h2>
|
||||
<ul aria-labelledby="file-drop-empty-content__heading" class="file-drop-empty-content__list">
|
||||
<li v-for="file in getSortedUploads()" :key="file">
|
||||
{{ file }}
|
||||
</li>
|
||||
</ul>
|
||||
</NcNoteCard>
|
||||
</template>
|
||||
<template #action>
|
||||
<template v-if="disclaimer">
|
||||
|
|
@ -34,16 +50,24 @@
|
|||
</NcEmptyContent>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
/* eslint-disable import/first */
|
||||
|
||||
// We need this on module level rather than on the instance as view will be refreshed by the files app after uploading
|
||||
const uploads = new Set<string>()
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { translate as t } from '@nextcloud/l10n'
|
||||
import { getUploader, UploadPicker } from '@nextcloud/upload'
|
||||
import { getUploader, UploadPicker, UploadStatus } from '@nextcloud/upload'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
import NcDialog from '@nextcloud/vue/components/NcDialog'
|
||||
import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
|
||||
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
|
||||
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
|
||||
import svgCloudUpload from '@mdi/svg/svg/cloud-upload.svg?raw'
|
||||
|
||||
defineProps<{
|
||||
|
|
@ -51,17 +75,62 @@ defineProps<{
|
|||
}>()
|
||||
|
||||
const disclaimer = loadState<string>('files_sharing', 'disclaimer', '')
|
||||
const shareLabel = loadState<string>('files_sharing', 'label', '')
|
||||
const shareNote = loadState<string>('files_sharing', 'note', '')
|
||||
|
||||
const name = shareLabel || t('files_sharing', 'File drop')
|
||||
|
||||
const showDialog = ref(false)
|
||||
const uploadDestination = getUploader().destination
|
||||
|
||||
getUploader()
|
||||
.addNotifier((upload) => {
|
||||
if (upload.status === UploadStatus.FINISHED && upload.file.name) {
|
||||
// if a upload is finished and is not a meta upload (name is set)
|
||||
// then we add the upload to the list of finished uploads to be shown to the user
|
||||
uploads.add(upload.file.name)
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Get the previous uploads as sorted list
|
||||
*/
|
||||
function getSortedUploads() {
|
||||
return [...uploads].sort((a, b) => a.localeCompare(b))
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.terms-of-service-dialog) {
|
||||
min-height: min(100px, 20vh);
|
||||
}
|
||||
/* TODO fix in library */
|
||||
.file-drop-empty-content :deep(.empty-content__action) {
|
||||
display: flex;
|
||||
gap: var(--default-grid-baseline);
|
||||
<style scoped lang="scss">
|
||||
.file-drop-empty-content {
|
||||
margin: auto;
|
||||
max-width: max(50vw, 300px);
|
||||
|
||||
.file-drop-empty-content__note-card {
|
||||
width: fit-content;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
#file-drop-empty-content__heading {
|
||||
margin-block: 0 10px;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.file-drop-empty-content__list {
|
||||
list-style: inside;
|
||||
max-height: min(350px, 33vh);
|
||||
overflow-y: scroll;
|
||||
padding-inline-end: calc(2 * var(--default-grid-baseline));
|
||||
}
|
||||
|
||||
:deep(.terms-of-service-dialog) {
|
||||
min-height: min(100px, 20vh);
|
||||
}
|
||||
|
||||
/* TODO fix in library */
|
||||
:deep(.empty-content__action) {
|
||||
display: flex;
|
||||
gap: var(--default-grid-baseline);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -399,6 +399,8 @@ class ShareControllerTest extends \Test\TestCase {
|
|||
->setPassword('password')
|
||||
->setShareOwner('ownerUID')
|
||||
->setSharedBy('initiatorUID')
|
||||
->setNote('The note')
|
||||
->setLabel('A label')
|
||||
->setNode($file)
|
||||
->setTarget("/$filename")
|
||||
->setToken('token');
|
||||
|
|
@ -478,6 +480,8 @@ class ShareControllerTest extends \Test\TestCase {
|
|||
'disclaimer' => 'My disclaimer text',
|
||||
'owner' => 'ownerUID',
|
||||
'ownerDisplayName' => 'ownerDisplay',
|
||||
'note' => 'The note',
|
||||
'label' => 'A label',
|
||||
];
|
||||
|
||||
$response = $this->shareController->showShare();
|
||||
|
|
@ -487,9 +491,9 @@ class ShareControllerTest extends \Test\TestCase {
|
|||
$csp = new ContentSecurityPolicy();
|
||||
$csp->addAllowedFrameDomain('\'self\'');
|
||||
$expectedResponse = new PublicTemplateResponse('files', 'index');
|
||||
$expectedResponse->setParams(['pageTitle' => $filename]);
|
||||
$expectedResponse->setParams(['pageTitle' => 'A label']);
|
||||
$expectedResponse->setContentSecurityPolicy($csp);
|
||||
$expectedResponse->setHeaderTitle($filename);
|
||||
$expectedResponse->setHeaderTitle('A label');
|
||||
$expectedResponse->setHeaderDetails('shared by ownerDisplay');
|
||||
$expectedResponse->setHeaderActions([
|
||||
new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', 'shareUrl'),
|
||||
|
|
|
|||
|
|
@ -149,9 +149,12 @@ describe('files_sharing: Public share - File drop', { testIsolation: true }, ()
|
|||
after(() => cy.runOccCommand('config:app:delete core shareapi_public_link_disclaimertext'))
|
||||
|
||||
it('shows ToS on file-drop view', () => {
|
||||
cy.contains(`Upload files to ${shareName}`)
|
||||
cy.get('[data-cy-files-sharing-file-drop]')
|
||||
.contains(`Upload files to ${shareName}`)
|
||||
.should('be.visible')
|
||||
cy.get('[data-cy-files-sharing-file-drop]')
|
||||
.contains('agree to the terms of service')
|
||||
.should('be.visible')
|
||||
.should('contain.text', 'agree to the terms of service')
|
||||
cy.findByRole('button', { name: /Terms of service/i })
|
||||
.should('be.visible')
|
||||
.click()
|
||||
|
|
|
|||
Loading…
Reference in a new issue