mirror of https://github.com/nextcloud/photos
enh: Migrate photos picker to use NcDialog
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
8f699e99c4
commit
5f03c45728
|
@ -44,30 +44,21 @@ Cypress.on('uncaught:exception', (err) => {
|
|||
}
|
||||
})
|
||||
|
||||
describe('Manage albums', () => {
|
||||
describe('Manage albums', { testIsolation: true }, () => {
|
||||
let user = null
|
||||
|
||||
before(function() {
|
||||
beforeEach(function() {
|
||||
cy.createRandomUser()
|
||||
.then(_user => {
|
||||
user = _user
|
||||
uploadTestMedia(user)
|
||||
cy.login(user)
|
||||
cy.visit('/apps/photos')
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit(`${Cypress.env('baseUrl')}/index.php/apps/photos/albums`)
|
||||
createAnAlbumFromAlbums('albums_test')
|
||||
addFilesToAlbumFromAlbum('albums_test', [0, 1, 2])
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
deleteAnAlbumFromAlbumContent()
|
||||
cy.contains('There is no album yet!').click()
|
||||
})
|
||||
|
||||
it('Create an album, populate it and delete it', () => {
|
||||
cy.get('[data-test="media"]').should('have.length', 3)
|
||||
})
|
||||
|
@ -156,7 +147,7 @@ describe('Manage albums', () => {
|
|||
})
|
||||
|
||||
it('Delete a file that was added to an album', () => {
|
||||
addFilesToAlbumFromAlbumFromHeader('albums_test', [0])
|
||||
addFilesToAlbumFromAlbumFromHeader('albums_test', [3])
|
||||
cy.get('[data-test="media"]').should('have.length', 4)
|
||||
cy.visit('/apps/photos')
|
||||
selectMedia([3])
|
||||
|
|
|
@ -69,12 +69,11 @@ export function addFilesToAlbumFromAlbum(albumName: string, itemsIndex: number[]
|
|||
|
||||
export function addFilesToAlbumFromAlbumFromHeader(albumName: string, itemsIndex: number[]) {
|
||||
cy.contains('New').click()
|
||||
cy.intercept({ times: 1, method: 'SEARCH', url: '**/dav/' }).as('search')
|
||||
cy.contains('Add photos to this album').click()
|
||||
cy.wait('@search')
|
||||
cy.get('.photos-picker__file-list').within(() => {
|
||||
selectMedia(itemsIndex)
|
||||
})
|
||||
|
||||
cy.intercept({ times: 1, method: 'PROPFIND', url: `**/dav/photos/**/albums/${albumName}` }).as('propFind')
|
||||
cy.contains(`Add to ${albumName}`).click()
|
||||
cy.wait('@propFind')
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/sharing": "^0.1.0",
|
||||
"@nextcloud/upload": "^1.0.4",
|
||||
"@nextcloud/vue": "^8.5.0",
|
||||
"@nextcloud/vue": "^8.6.1",
|
||||
"camelcase": "^8.0.0",
|
||||
"debounce": "^1.2.1",
|
||||
"he": "^1.2.0",
|
||||
|
@ -3808,9 +3808,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue": {
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-8.5.0.tgz",
|
||||
"integrity": "sha512-PitpFCtBRWy3p7MEbjHzVwDf3Cx2+IfxDjj5gi8u1M+LKt2chSXidUOURKGsXhnttlqh1aC+sQWjHM2s3zRuEQ==",
|
||||
"version": "8.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue/-/vue-8.6.1.tgz",
|
||||
"integrity": "sha512-CPPo3A1Az0DDRNI0pn7w6Yn8pJtEDktTXnrfym2Pd+lTzqTj4P2ywf+spArXMHu0BPIB95Eero7XlCiRpmhg/g==",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.1.0",
|
||||
"@linusborg/vue-simple-portal": "^0.1.5",
|
||||
|
@ -3830,7 +3830,7 @@
|
|||
"clone": "^2.1.2",
|
||||
"debounce": "2.0.0",
|
||||
"dompurify": "^3.0.5",
|
||||
"emoji-mart-vue-fast": "^15.0.0",
|
||||
"emoji-mart-vue-fast": "^15.0.1",
|
||||
"escape-html": "^1.0.3",
|
||||
"floating-vue": "^1.0.0-beta.19",
|
||||
"focus-trap": "^7.4.3",
|
||||
|
@ -3947,18 +3947,6 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue/node_modules/emoji-mart-vue-fast": {
|
||||
"version": "15.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-mart-vue-fast/-/emoji-mart-vue-fast-15.0.0.tgz",
|
||||
"integrity": "sha512-3BzkDrs60JyT00dLHMAxWKbpFhbyaW9C+q1AjtqGovSxTu8TC2mYAGsvTmXNYKm39IRRAS56v92TihOcB98IsQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.6",
|
||||
"core-js": "^3.23.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": ">2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nextcloud/vue/node_modules/is-plain-obj": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
|
||||
|
@ -9499,6 +9487,18 @@
|
|||
"url": "https://github.com/sindresorhus/emittery?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-mart-vue-fast": {
|
||||
"version": "15.0.1",
|
||||
"resolved": "https://registry.npmjs.org/emoji-mart-vue-fast/-/emoji-mart-vue-fast-15.0.1.tgz",
|
||||
"integrity": "sha512-FcBio4MZsad+IwbaD2+1/obaK7W0F8EXlVXOXKgNCICaxkJD5WnA5bAtSXR0+FSBrMWz7DCAOqOojm7EapZ1eg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.6",
|
||||
"core-js": "^3.23.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": ">2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/emojis-list": {
|
||||
"version": "3.0.0",
|
||||
"dev": true,
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
"@nextcloud/router": "^2.0.0",
|
||||
"@nextcloud/sharing": "^0.1.0",
|
||||
"@nextcloud/upload": "^1.0.4",
|
||||
"@nextcloud/vue": "^8.5.0",
|
||||
"@nextcloud/vue": "^8.6.1",
|
||||
"camelcase": "^8.0.0",
|
||||
"debounce": "^1.2.1",
|
||||
"he": "^1.2.0",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
- @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>
|
||||
-
|
||||
- @author Louis Chemineau <louis@chmn.me>
|
||||
- @author Ferdinand Thiessen <opensource@fthiessen.de>
|
||||
-
|
||||
- @license AGPL-3.0-or-later
|
||||
-
|
||||
|
@ -20,51 +21,45 @@
|
|||
-
|
||||
-->
|
||||
<template>
|
||||
<div class="photos-picker">
|
||||
<div class="photos-picker__content">
|
||||
<nav class="photos-picker__navigation" :class="{'photos-picker__navigation--placeholder': monthsList.length === 0}">
|
||||
<ul>
|
||||
<li v-for="month in monthsList"
|
||||
:key="month"
|
||||
class="photos-picker__navigation__month"
|
||||
:class="{selected: targetMonth === month}">
|
||||
<NcButton type="tertiary" :aria-label="t('photos', 'Jump to {date}', {date: dateMonthAndYear(month)})" @click="targetMonth = month">
|
||||
{{ month | dateMonthAndYear }}
|
||||
</NcButton>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<FilesListViewer class="photos-picker__file-list"
|
||||
:class="{'photos-picker__file-list--placeholder': monthsList.length === 0}"
|
||||
:file-ids-by-section="fileIdsByMonth"
|
||||
:empty-message="t('photos', 'There are no photos or videos yet!')"
|
||||
:sections="monthsList"
|
||||
:loading="loadingFiles"
|
||||
:base-height="100"
|
||||
:section-header-height="50"
|
||||
:scroll-to-section="targetMonth"
|
||||
@need-content="getFiles"
|
||||
@focusout.native="onFocusOut">
|
||||
<template slot-scope="{file, height, isHeader, distance}">
|
||||
<h3 v-if="isHeader"
|
||||
:id="`photos-picker-section-header-${file.id}`"
|
||||
:style="{ height: `${height}px`}"
|
||||
class="section-header">
|
||||
{{ file.id | dateMonthAndYear }}
|
||||
</h3>
|
||||
|
||||
<File v-else
|
||||
:file="files[file.id]"
|
||||
:allow-selection="true"
|
||||
:selected="selection[file.id] === true"
|
||||
:distance="distance"
|
||||
@select-toggled="onFileSelectToggle" />
|
||||
<NcDialog content-classes="photos-picker"
|
||||
:name="name"
|
||||
:open="open"
|
||||
out-transition
|
||||
size="large"
|
||||
@update:open="(open) => $emit('update:open', open)">
|
||||
<!-- Navigation containing the months available -->
|
||||
<template #navigation="{ isCollapsed }">
|
||||
<!-- Mobile view -->
|
||||
<NcSelect v-if="isCollapsed"
|
||||
v-model="targetMonth"
|
||||
:aria-label-combobox="t('photos', 'Jump to specific date in list')"
|
||||
class="photos-picker__navigation__month-select"
|
||||
:clearable="false"
|
||||
:options="monthsList">
|
||||
<template #selected-option="{ label }">
|
||||
{{ dateMonthAndYear(label) }}
|
||||
</template>
|
||||
</FilesListViewer>
|
||||
</div>
|
||||
<template #option="{ label }">
|
||||
{{ dateMonthAndYear(label) }}
|
||||
</template>
|
||||
</NcSelect>
|
||||
|
||||
<div class="photos-picker__actions">
|
||||
<!-- Default view -->
|
||||
<ul v-else>
|
||||
<li v-for="month in monthsList"
|
||||
:key="month"
|
||||
class="photos-picker__navigation__month">
|
||||
<NcButton :type="targetMonth === month ? 'secondary' : 'tertiary'"
|
||||
:aria-label="t('photos', 'Jump to {date}', { date: dateMonthAndYear(month) })"
|
||||
@click="targetMonth = month">
|
||||
{{ dateMonthAndYear(month) }}
|
||||
</NcButton>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<!-- The actions on the bottom -->
|
||||
<template #actions>
|
||||
<UploadPicker :accept="allowedMimes"
|
||||
:context="uploadContext"
|
||||
:destination="photosLocationFolder"
|
||||
|
@ -77,14 +72,44 @@
|
|||
</template>
|
||||
{{ t('photos', 'Add to {destination}', { destination }) }}
|
||||
</NcButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<FilesListViewer class="photos-picker__file-list"
|
||||
:class="{'photos-picker__file-list--placeholder': monthsList.length === 0}"
|
||||
:file-ids-by-section="fileIdsByMonth"
|
||||
:empty-message="t('photos', 'There are no photos or videos yet!')"
|
||||
:sections="monthsList"
|
||||
:loading="loadingFiles"
|
||||
:base-height="100"
|
||||
:section-header-height="50"
|
||||
:scroll-to-section="targetMonth"
|
||||
@need-content="getFiles"
|
||||
@focusout.native="onFocusOut">
|
||||
<template slot-scope="{file, height, isHeader, distance}">
|
||||
<h3 v-if="isHeader"
|
||||
:id="`photos-picker-section-header-${file.id}`"
|
||||
:style="{ height: `${height}px`}"
|
||||
class="section-header">
|
||||
{{ dateMonthAndYear(file.id) }}
|
||||
</h3>
|
||||
|
||||
<File v-else
|
||||
:file="files[file.id]"
|
||||
:allow-selection="true"
|
||||
:selected="selection[file.id] === true"
|
||||
:distance="distance"
|
||||
@select-toggled="onFileSelectToggle" />
|
||||
</template>
|
||||
</FilesListViewer>
|
||||
</NcDialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { NcButton, NcLoadingIcon, useIsMobile } from '@nextcloud/vue'
|
||||
import { UploadPicker } from '@nextcloud/upload'
|
||||
import { NcButton, NcDialog, NcLoadingIcon, NcSelect, useIsMobile } from '@nextcloud/vue'
|
||||
import { defineComponent } from 'vue'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
import moment from '@nextcloud/moment'
|
||||
|
||||
import ImagePlus from 'vue-material-design-icons/ImagePlus.vue'
|
||||
|
@ -98,40 +123,20 @@ import FilesByMonthMixin from '../mixins/FilesByMonthMixin.js'
|
|||
import UserConfig from '../mixins/UserConfig.js'
|
||||
import allowedMimes from '../services/AllowedMimes.js'
|
||||
|
||||
const isMobile = useIsMobile()
|
||||
|
||||
/**
|
||||
* @param {string} date - In the following format: YYYYMM
|
||||
*/
|
||||
function dateMonthAndYear(date) {
|
||||
if (isMobile.value) {
|
||||
return moment(date, 'YYYYMM').format('MMM YYYY')
|
||||
} else {
|
||||
return moment(date, 'YYYYMM').format('MMMM YYYY')
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'FilesPicker',
|
||||
export default defineComponent({
|
||||
name: 'PhotosPicker',
|
||||
|
||||
components: {
|
||||
File,
|
||||
FilesListViewer,
|
||||
ImagePlus,
|
||||
NcButton,
|
||||
NcDialog,
|
||||
NcLoadingIcon,
|
||||
NcSelect,
|
||||
UploadPicker,
|
||||
},
|
||||
|
||||
filters: {
|
||||
/**
|
||||
* @param {string} date - In the following format: YYYYMM
|
||||
*/
|
||||
dateMonthAndYear(date) {
|
||||
|
||||
return dateMonthAndYear(date)
|
||||
},
|
||||
},
|
||||
mixins: [
|
||||
FetchFilesMixin,
|
||||
FilesByMonthMixin,
|
||||
|
@ -140,6 +145,22 @@ export default {
|
|||
],
|
||||
|
||||
props: {
|
||||
/**
|
||||
* If the photos picker should be opened
|
||||
*/
|
||||
open: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
/**
|
||||
* Name to be used as heading
|
||||
*/
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
|
||||
// Label to show in the submit button.
|
||||
destination: {
|
||||
type: String,
|
||||
|
@ -159,6 +180,14 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
emits: ['files-picked', 'update:open'],
|
||||
|
||||
setup() {
|
||||
return {
|
||||
isMobile: useIsMobile(),
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
allowedMimes,
|
||||
|
@ -208,43 +237,34 @@ export default {
|
|||
* @param {string} date - In the following format: YYYYMM
|
||||
*/
|
||||
dateMonthAndYear(date) {
|
||||
return dateMonthAndYear(date)
|
||||
if (this.isMobile) {
|
||||
return moment(date, 'YYYYMM').format('MMM YYYY')
|
||||
}
|
||||
return moment(date, 'YYYYMM').format('MMMM YYYY')
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.photos-picker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 12px;
|
||||
:deep(.photos-picker) {
|
||||
// remove padding to move scrollbar to the very end
|
||||
padding-inline-end: 0 !important;
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-grow: 1;
|
||||
height: 500px;
|
||||
padding: 0 2px;
|
||||
}
|
||||
.photos-picker {
|
||||
|
||||
&__navigation {
|
||||
flex-basis: 200px;
|
||||
overflow: scroll;
|
||||
height: 100%;
|
||||
padding: 0 2px;
|
||||
|
||||
@media only screen and (max-width: 1200px) {
|
||||
flex-basis: 100px;
|
||||
}
|
||||
|
||||
&--placeholder {
|
||||
background: var(--color-primary-element-light);
|
||||
border-radius: var(--border-radius-large);
|
||||
}
|
||||
|
||||
&__month {
|
||||
margin: 4px 0;
|
||||
// For focus-visible outline
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
&__month-select {
|
||||
flex: 1;
|
||||
// align with other content
|
||||
padding-inline-end: 12px;
|
||||
padding-block-end: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,12 +295,5 @@ export default {
|
|||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
&__actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-items: center;
|
||||
padding-top: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -127,15 +127,11 @@
|
|||
</NcEmptyContent>
|
||||
</CollectionContent>
|
||||
|
||||
<NcModal v-if="showAddPhotosModal"
|
||||
size="large"
|
||||
<PhotosPicker :open.sync="showAddPhotosModal"
|
||||
:blacklist-ids="albumFileIds"
|
||||
:destination="album.basename"
|
||||
:name="t('photos', 'Add photos to {albumName}', {albumName: albumName})"
|
||||
@close="showAddPhotosModal = false">
|
||||
<FilesPicker v-if="album !== undefined"
|
||||
:destination="album.basename"
|
||||
:blacklist-ids="albumFileIds"
|
||||
@files-picked="handleFilesPicked" />
|
||||
</NcModal>
|
||||
@files-picked="handleFilesPicked" />
|
||||
|
||||
<NcModal v-if="showManageCollaboratorView && album !== undefined"
|
||||
:name="t('photos', 'Manage collaborators')"
|
||||
|
@ -196,7 +192,7 @@ import ActionFavorite from '../components/Actions/ActionFavorite.vue'
|
|||
import AlbumForm from '../components/Albums/AlbumForm.vue'
|
||||
import CollaboratorsSelectionForm from '../components/Albums/CollaboratorsSelectionForm.vue'
|
||||
import CollectionContent from '../components/Collection/CollectionContent.vue'
|
||||
import FilesPicker from '../components/FilesPicker.vue'
|
||||
import PhotosPicker from '../components/PhotosPicker.vue'
|
||||
import HeaderNavigation from '../components/HeaderNavigation.vue'
|
||||
|
||||
import allowedMimes from '../services/AllowedMimes.js'
|
||||
|
@ -214,7 +210,7 @@ export default {
|
|||
Delete,
|
||||
// Download,
|
||||
// DownloadMultiple,
|
||||
FilesPicker,
|
||||
PhotosPicker,
|
||||
HeaderNavigation,
|
||||
ImagePlus,
|
||||
MapMarker,
|
||||
|
|
|
@ -111,23 +111,19 @@
|
|||
</NcEmptyContent>
|
||||
</CollectionContent>
|
||||
|
||||
<NcModal v-if="showAddPhotosModal"
|
||||
size="large"
|
||||
<PhotosPicker :open.sync="showAddPhotosModal"
|
||||
:name="t('photos', 'Add photos to {albumName}', {albumName: albumOriginalName})"
|
||||
@close="showAddPhotosModal = false">
|
||||
<FilesPicker v-if="album !== undefined"
|
||||
:destination="album.basename"
|
||||
:blacklist-ids="albumFileIds"
|
||||
:loading="loadingAddFilesToAlbum"
|
||||
@files-picked="handleFilesPicked" />
|
||||
</NcModal>
|
||||
:destination="album.basename"
|
||||
:blacklist-ids="albumFileIds"
|
||||
:loading="loadingAddFilesToAlbum"
|
||||
@files-picked="handleFilesPicked" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex'
|
||||
|
||||
import { NcActions, NcActionButton, NcButton, NcModal, NcEmptyContent, NcActionSeparator, NcUserBubble, isMobile } from '@nextcloud/vue'
|
||||
import { NcActions, NcActionButton, NcButton, NcEmptyContent, NcActionSeparator, NcUserBubble, isMobile } from '@nextcloud/vue'
|
||||
import { Type } from '@nextcloud/sharing'
|
||||
import { translate } from '@nextcloud/l10n'
|
||||
|
||||
|
@ -145,7 +141,7 @@ import FetchCollectionContentMixin from '../mixins/FetchCollectionContentMixin.j
|
|||
import CollectionContent from '../components/Collection/CollectionContent.vue'
|
||||
import HeaderNavigation from '../components/HeaderNavigation.vue'
|
||||
// import ActionDownload from '../components/Actions/ActionDownload.vue'
|
||||
import FilesPicker from '../components/FilesPicker.vue'
|
||||
import PhotosPicker from '../components/PhotosPicker.vue'
|
||||
|
||||
export default {
|
||||
name: 'SharedAlbumContent',
|
||||
|
@ -162,11 +158,10 @@ export default {
|
|||
NcActionButton,
|
||||
NcActionSeparator,
|
||||
NcButton,
|
||||
NcModal,
|
||||
NcUserBubble,
|
||||
CollectionContent,
|
||||
// ActionDownload,
|
||||
FilesPicker,
|
||||
PhotosPicker,
|
||||
HeaderNavigation,
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in New Issue