Merge remote-tracking branch 'origin/bulk-operations'

# Conflicts:
#	app/Http/Helpers/helpers.php
#	config/vuefilemanager.php
#	public/chunks/app-others.js
#	public/chunks/files~chunks/shared-files~chunks/shared-page~chunks/trash.js
#	public/js/main.js
#	public/mix-manifest.json
#	resources/js/components/FilesView/FileItemList.vue
#	resources/js/components/FilesView/FilePreview.vue
#	resources/js/helpers.js
#	resources/js/store/modules/fileFunctions.js
This commit is contained in:
Peter Papp
2020-12-21 17:02:49 +01:00
167 changed files with 6839 additions and 3151 deletions
+1 -1
View File
@@ -160,7 +160,7 @@
}
&.widgets-coll-3 {
grid-template-columns: repeat(auto-fill, 33%);
grid-template-columns: repeat(auto-fill, 33.3%);
}
.widget {
+170 -129
View File
@@ -3,8 +3,9 @@
<ContentSidebar>
<!--Empty storage warning-->
<ContentGroup v-if="config.storageLimit && storage.used > 95">
<UpgradeSidebarBanner />
<UpgradeSidebarBanner/>
</ContentGroup>
<!--Locations-->
@@ -18,8 +19,7 @@
{{ $t('sidebar.home') }}
</div>
</a>
<a class="menu-list-item link" :class="{'is-active': $isThisLocation(['latest'])}"
@click="getLatest">
<a class="menu-list-item link" :class="{'is-active': $isThisLocation(['latest'])}" @click="getLatest">
<div class="icon">
<upload-cloud-icon size="17"></upload-cloud-icon>
</div>
@@ -27,37 +27,35 @@
{{ $t('sidebar.latest') }}
</div>
</a>
<a class="menu-list-item link trash" :class="{'is-active-trash': $isThisLocation(['trash', 'trash-root'])}" @click="getTrash">
<div class="icon">
<trash2-icon size="17"></trash2-icon>
</div>
<div class="label">
{{ $t('locations.trash') }}
</div>
</a>
</div>
</ContentGroup>
<!--Navigator-->
<ContentGroup :title="$t('sidebar.navigator_title')" class="navigator">
<ContentGroup :title="$t('sidebar.navigator_title')" slug="navigator" :can-collapse="true" class="navigator">
<span class="empty-note navigator" v-if="tree.length == 0">
{{ $t('sidebar.folders_empty') }}
</span>
<TreeMenuNavigator class="folder-tree" :depth="0" :nodes="items" v-for="items in tree"
:key="items.unique_id"/>
<TreeMenuNavigator class="folder-tree" :depth="0" :nodes="items" v-for="items in tree" :key="items.unique_id"/>
</ContentGroup>
<!--Favourites-->
<ContentGroup :title="$t('sidebar.favourites')">
<ContentGroup :title="$t('sidebar.favourites')" slug="favourites" :can-collapse="true">
<div class="menu-list-wrapper vertical favourites"
:class="{ 'is-dragenter': area }"
@dragover.prevent="dragEnter"
@dragleave="dragLeave"
@drop="dragFinish($event)"
>
<div class="menu-list-wrapper vertical favourites" :class="{ 'is-dragenter': area }" @dragover.prevent="dragEnter" @dragleave="dragLeave" @drop="dragFinish($event)">
<transition-group tag="div" class="menu-list" name="folder-item">
<span class="empty-note favourites" v-if="favourites.length == 0" :key="0">
{{ $t('sidebar.favourites_empty') }}
</span>
<a @click.stop="openFolder(folder)"
class="menu-list-item"
:class="{'is-current': (folder && currentFolder) && (currentFolder.unique_id === folder.unique_id)}"
v-for="folder in favourites"
:key="folder.unique_id">
<a @click.stop="openFolder(folder)" class="menu-list-item" :class="{'is-current': (folder && currentFolder) && (currentFolder.unique_id === folder.unique_id)}" v-for="(folder, i) in favourites" :key="i">
<div>
<folder-icon size="17" class="folder-icon"></folder-icon>
<span class="label">{{ folder.name }}</span>
@@ -69,153 +67,196 @@
</ContentGroup>
</ContentSidebar>
<ContentFileView/>
</section>
</template>
<script>
import UpgradeSidebarBanner from '@/components/Others/UpgradeSidebarBanner'
import TreeMenuNavigator from '@/components/Others/TreeMenuNavigator'
import ContentFileView from '@/components/Others/ContentFileView'
import ContentSidebar from '@/components/Sidebar/ContentSidebar'
import ContentGroup from '@/components/Sidebar/ContentGroup'
import {mapGetters} from 'vuex'
import {events} from '@/bus'
import {
import UpgradeSidebarBanner from '@/components/Others/UpgradeSidebarBanner'
import TreeMenuNavigator from '@/components/Others/TreeMenuNavigator'
import MultiSelected from '@/components/FilesView/MultiSelected'
import ContentFileView from '@/components/Others/ContentFileView'
import ContentSidebar from '@/components/Sidebar/ContentSidebar'
import ContentGroup from '@/components/Sidebar/ContentGroup'
import { mapGetters } from 'vuex'
import { events } from '@/bus'
import {
UploadCloudIcon,
FolderIcon,
Trash2Icon,
HomeIcon,
XIcon
} from 'vue-feather-icons'
export default {
name: 'FilesView',
components: {
UpgradeSidebarBanner,
TreeMenuNavigator,
ContentFileView,
MultiSelected,
ContentSidebar,
UploadCloudIcon,
ContentGroup,
FolderIcon,
Trash2Icon,
HomeIcon,
XIcon,
} from 'vue-feather-icons'
export default {
name: 'FilesView',
components: {
UpgradeSidebarBanner,
TreeMenuNavigator,
ContentFileView,
ContentSidebar,
UploadCloudIcon,
ContentGroup,
FolderIcon,
HomeIcon,
XIcon,
XIcon
},
computed: {
...mapGetters(['user', 'homeDirectory', 'currentFolder', 'config', 'fileInfoDetail']),
favourites() {
return this.user.relationships.favourites.data.attributes.folders
},
computed: {
...mapGetters(['user', 'homeDirectory', 'currentFolder', 'config']),
favourites() {
return this.user.relationships.favourites.data.attributes.folders
},
tree() {
return this.user.relationships.tree.data.attributes.folders
},
storage() {
return this.$store.getters.user.relationships.storage.data.attributes
}
tree() {
return this.user.relationships.tree.data.attributes.folders
},
data() {
return {
area: false,
draggedItem: undefined,
}
storage() {
return this.$store.getters.user.relationships.storage.data.attributes
}
},
data() {
return {
area: false,
draggedItem: undefined
}
},
methods: {
getTrash() {
this.$store.dispatch('getTrash')
},
methods: {
getLatest() {
this.$store.dispatch('getLatest')
},
goHome() {
this.$store.dispatch('getFolder', [{folder: this.homeDirectory, back: false, init: true}])
},
openFolder(folder) {
this.$store.dispatch('getFolder', [{folder: folder, back: false, init: false}])
},
dragEnter() {
if (this.draggedItem && this.draggedItem.type !== 'folder') return
getLatest() {
this.$store.dispatch('getLatest')
},
goHome() {
this.$store.dispatch('getFolder', [{ folder: this.homeDirectory, back: false, init: true }])
},
openFolder(folder) {
this.$store.dispatch('getFolder', [{ folder: folder, back: false, init: false }])
},
dragEnter() {
if (this.draggedItem && this.draggedItem.type !== 'folder') return
this.area = true
},
dragLeave() {
this.area = false
},
dragFinish() {
this.area = false
if (this.fileInfoDetail.length > 0 && this.fileInfoDetail.find(item => item.type !== 'folder')) return
// Check if draged item is folder
if (this.draggedItem && this.draggedItem.type !== 'folder') return
this.area = true
},
dragLeave() {
this.area = false
},
dragFinish() {
this.area = false
// Check if folder exist in favourites
if (this.favourites.find(folder => folder.unique_id == this.draggedItem.unique_id)) return
events.$emit('drop')
// Store favourites folder
// Check if dragged item is folder
if (this.draggedItem && this.draggedItem.type !== 'folder') return
// Check if folder exist in favourites
if (this.favourites.find(folder => folder.unique_id == this.draggedItem.unique_id)) return
// Prevent to move folders to self
if (this.fileInfoDetail.length > 0 && this.fileInfoDetail.find(item => item.type !== 'folder')) return
// Store favourites folder
//Add to favourites non selected folder
if (!this.fileInfoDetail.includes(this.draggedItem)) {
this.$store.dispatch('addToFavourites', this.draggedItem)
},
removeFavourite(folder) {
this.$store.dispatch('removeFromFavourites', folder)
}
},
created() {
this.goHome()
// Listen for dragstart folder items
events.$on('dragstart', (item) => this.draggedItem = item)
//Add to favourites selected folders
if (this.fileInfoDetail.includes(this.draggedItem)) {
this.$store.dispatch('addToFavourites', null)
}
},
removeFavourite(folder) {
this.$store.dispatch('removeFromFavourites', folder)
}
},
created() {
this.goHome()
// Listen for dragstart folder items
events.$on('dragstart', (item) => {
this.draggedItem = item , this.dragInProgress = true
})
events.$on('drop', () => {
this.dragInProgress = false
})
},
beforeRouteLeave(to, from, next) {
// Inquire user about his willing to step back to sign in page
if (to.name === 'SignIn') {
if (window.confirm(this.$t('alerts.leave_to_sign_in'))) {
next()
} else {
next(false)
}
} else {
next()
}
}
}
</script>
<style lang="scss" scoped>
.empty-note {
&.navigator {
padding: 5px 25px 10px;
}
&.favourites {
padding: 5px 23px 10px;
}
}
.navigator {
width: 100%;
overflow-x: auto;
}
@media only screen and (max-width: 1024px) {
.empty-note {
&.navigator {
padding: 5px 25px 10px;
padding: 5px 20px 10px;
}
&.favourites {
padding: 5px 23px 10px;
padding: 5px 18px 10px;
}
}
}
.navigator {
width: 100%;
overflow-x: auto;
}
// Transition
.folder-item-move {
transition: transform 300s ease;
}
@media only screen and (max-width: 1024px) {
.folder-item-enter-active {
transition: all 300ms ease;
}
.empty-note {
.folder-item-leave-active {
transition: all 300ms;
}
&.navigator {
padding: 5px 20px 10px;
}
.folder-item-enter, .folder-item-leave-to /* .list-leave-active below version 2.1.8 */
{
opacity: 0;
transform: translateX(30px);
}
&.favourites {
padding: 5px 18px 10px;
}
}
}
// Transition
.folder-item-move {
transition: transform 300s ease;
}
.folder-item-enter-active {
transition: all 300ms ease;
}
.folder-item-leave-active {
transition: all 300ms;
}
.folder-item-enter, .folder-item-leave-to /* .list-leave-active below version 2.1.8 */
{
opacity: 0;
transform: translateX(30px);
}
.folder-item-leave-active {
position: absolute;
}
.folder-item-leave-active {
position: absolute;
}
</style>
-51
View File
@@ -1,51 +0,0 @@
<template>
<section id="viewport">
<ContentSidebar>
<!--Tools-->
<ContentGroup :title="$t('sidebar.tools_title')" class="navigator">
<div class="menu-list-wrapper vertical">
<div class="menu-list-item link" @click="emptyTrash()">
<div class="icon">
<trash-icon size="17"></trash-icon>
</div>
<div class="label">
{{ $t('context_menu.empty_trash') }}
</div>
</div>
</div>
</ContentGroup>
</ContentSidebar>
<ContentFileView/>
</section>
</template>
<script>
import ContentFileView from '@/components/Others/ContentFileView'
import ContentSidebar from '@/components/Sidebar/ContentSidebar'
import ContentGroup from '@/components/Sidebar/ContentGroup'
import {
TrashIcon,
} from 'vue-feather-icons'
export default {
name: 'FilesView',
components: {
ContentFileView,
ContentSidebar,
ContentGroup,
TrashIcon,
},
methods: {
emptyTrash() {
this.$store.dispatch('emptyTrash')
},
},
created() {
this.$store.dispatch('getTrash')
}
}
</script>
<style lang="scss" scoped>
</style>
+118 -29
View File
@@ -9,9 +9,21 @@
<!--Move item setup-->
<MoveItem />
<!-- Mobile Menu for Multi selected items -->
<MobileMultiSelectMenu/>
<!--Rename folder or file item-->
<RenameItem/>
<!-- Drag & Drop UI -->
<DragUI/>
<!--Mobile Menu-->
<MobileMenu/>
<!-- Mobile menu for selecting view and sorting -->
<MobileSortingAndPreview/>
<!--System alerts-->
<Alert />
@@ -19,7 +31,7 @@
<Vignette/>
<!--Password verification-->
<div v-if="currentPage === 'page-password'" id="password-view">
<div v-if="isPagePasswordVerification" id="password-view">
<!--Verify share link by password-->
<AuthContent class="center" name="password" :visible="true">
@@ -41,42 +53,82 @@
</AuthContent>
</div>
<!--File browser-->
<div v-if="currentPage === 'page-files'" id="files-view">
<div id="single-file" v-if="sharedDetail.type === 'file'">
<div class="single-file-wrapper">
<FileItemGrid v-if="sharedFile" :data="sharedFile" :context-menu="false"/>
<!--Single file page-->
<div v-if="sharedDetail.type === 'file' && isPageFiles" id="single-file">
<div class="single-file-wrapper">
<FileItemGrid v-if="sharedFile" :data="sharedFile" :context-menu="false"/>
<ButtonBase @click.native="download" class="download-button" button-style="theme">
{{ $t('page_shared.download_file') }}
</ButtonBase>
</div>
</div>
<div v-if="sharedDetail.type === 'folder'" @contextmenu.prevent.capture="contextMenu($event, undefined)" @click="fileViewClick">
<!--Context menu-->
<ContextMenu/>
<!--Desktop Toolbar-->
<DesktopToolbar/>
<!--File browser-->
<FileBrowser/>
<ButtonBase @click.native="download" class="download-button" button-style="theme">
{{ $t('page_shared.download_file') }}
</ButtonBase>
</div>
</div>
<!--Multiple items view page-->
<div v-if="sharedDetail.type === 'folder' && isPageFiles"
@contextmenu.prevent.capture="contextMenu($event, undefined)"
id="viewport">
<ContentSidebar v-if="navigationTree">
<!--Locations-->
<ContentGroup :title="$t('sidebar.locations_title')">
<div class="menu-list-wrapper vertical">
<a class="menu-list-item link" @click="goHome">
<div class="icon">
<home-icon size="17"></home-icon>
</div>
<div class="label">
{{ $t('sidebar.home') }}
</div>
</a>
</div>
</ContentGroup>
<!--Navigator-->
<ContentGroup :title="$t('sidebar.navigator_title')" class="navigator">
<span class="empty-note navigator" v-if="navigationTree.length == 0">
{{ $t('sidebar.folders_empty') }}
</span>
<TreeMenuNavigator class="folder-tree" :depth="0" :nodes="items" v-for="items in navigationTree" :key="items.unique_id"/>
</ContentGroup>
</ContentSidebar>
<div id="files-view">
<!--Context menu-->
<ContextMenu/>
<!--Desktop Toolbar-->
<DesktopToolbar/>
<!--File browser-->
<FileBrowser/>
<!-- Selecting preview list and sorting -->
<DesktopSortingAndPreview/>
</div>
</div>
</div>
</template>
<script>
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
import MobileSortingAndPreview from '@/components/FilesView/MobileSortingAndPreview'
import MobileMultiSelectMenu from '@/components/FilesView/MobileMultiSelectMenu'
import DesktopSortingAndPreview from '@/components/FilesView/DesktopSortingAndPreview'
import TreeMenuNavigator from '@/components/Others/TreeMenuNavigator'
import FileFullPreview from '@/components/FilesView/FileFullPreview'
import DesktopToolbar from '@/components/FilesView/DesktopToolbar'
import FileFullPreview from "@/components/FilesView/FileFullPreview";
import ContentSidebar from '@/components/Sidebar/ContentSidebar'
import DragUI from '@/components/FilesView/DragUI'
import FileItemGrid from '@/components/FilesView/FileItemGrid'
import ContentGroup from '@/components/Sidebar/ContentGroup'
import FileBrowser from '@/components/FilesView/FileBrowser'
import ContextMenu from '@/components/FilesView/ContextMenu'
import ButtonBase from '@/components/FilesView/ButtonBase'
import MobileMenu from '@/components/FilesView/MobileMenu'
import AuthContent from '@/components/Auth/AuthContent'
import RenameItem from '@/components/Others/RenameItem'
import AuthButton from '@/components/Auth/AuthButton'
import Spinner from '@/components/FilesView/Spinner'
import MoveItem from '@/components/Others/MoveItem'
@@ -86,21 +138,33 @@
import {mapGetters} from 'vuex'
import {events} from '@/bus'
import axios from 'axios'
import {
HomeIcon,
} from 'vue-feather-icons'
export default {
name: 'SharedPage',
components: {
MobileSortingAndPreview,
MobileMultiSelectMenu,
ValidationProvider,
DesktopSortingAndPreview,
ValidationObserver,
TreeMenuNavigator,
FileFullPreview,
DesktopToolbar,
ContentSidebar,
DragUI,
FileItemGrid,
ContentGroup,
AuthContent,
FileBrowser,
ContextMenu,
AuthButton,
MobileMenu,
ButtonBase,
RenameItem,
HomeIcon,
MoveItem,
required,
Vignette,
@@ -108,7 +172,21 @@
Alert,
},
computed: {
...mapGetters(['config', 'sharedDetail', 'sharedFile']),
...mapGetters([
'config',
'sharedDetail',
'sharedFile',
'navigation'
]),
navigationTree() {
return this.navigation ? this.navigation[0].folders : undefined
},
isPageFiles() {
return this.currentPage === 'page-files'
},
isPagePasswordVerification() {
return this.currentPage === 'page-password'
}
},
data() {
return {
@@ -116,10 +194,14 @@
password: '',
isLoading: false,
isPageLoading: true,
currentPage: undefined
currentPage: undefined,
homeDirectory: undefined,
}
},
methods: {
goHome() {
this.$store.dispatch('browseShared', [{folder: this.homeDirectory, back: false, init: true}])
},
async authenticateProtected() {
// Validate fields
@@ -163,14 +245,17 @@
// Show folder
if (this.sharedDetail.type === 'folder') {
let homeDirectory = {
this.homeDirectory = {
unique_id: this.sharedDetail.item_id,
name: this.$t('locations.home'),
location: 'public',
}
// Get folder tree
this.$store.dispatch('getFolderTree')
// Load folder
this.$store.dispatch('browseShared', [{folder: homeDirectory, back: false, init: true}])
this.goHome()
}
// Get file
@@ -181,9 +266,6 @@
download() {
this.$downloadFile(this.sharedFile.file_url, this.sharedFile.name + '.' + this.sharedFile.mimetype)
},
fileViewClick() {
events.$emit('contextMenu:hide')
},
contextMenu(event, item) {
events.$emit('contextMenu:show', event, item)
},
@@ -288,4 +370,11 @@
}
}
.empty-note {
&.navigator {
padding: 5px 25px 10px;
}
}
</style>