Merge remote-tracking branch 'origin/infinite_scroll' into api

# Conflicts:
#	config/vuefilemanager.php
#	package-lock.json
#	package.json
#	public/mix-manifest.json
#	resources/js/store/modules/fileBrowser.js
#	resources/js/store/modules/sharing.js
#	resources/js/store/modules/teams.js
#	resources/js/store/modules/userAuth.js
#	src/App/Socialite/Controllers/SocialiteCallbackController.php
#	src/Domain/Browsing/Controllers/BrowseTrashContentController.php
#	src/Domain/Browsing/Controllers/VisitorBrowseFolderController.php
#	src/Domain/Files/Controllers/UploadFileController.php
#	src/Domain/Items/Controllers/RenameFileOrFolderController.php
#	src/Support/helpers.php
This commit is contained in:
Čarodej
2022-05-24 10:22:21 +02:00
26 changed files with 356 additions and 104 deletions
+4
View File
@@ -61,6 +61,10 @@ return [
], ],
], ],
'paginate' => [
'perPage' => 8,
],
// The update versions which need to run upgrade process // The update versions which need to run upgrade process
'updates' => [ 'updates' => [
'2_0_10', '2_0_10',
+4 -4
View File
@@ -23,26 +23,26 @@
"resolve-url-loader": "^2.3.1", "resolve-url-loader": "^2.3.1",
"sass": "^1.49.11", "sass": "^1.49.11",
"sass-loader": "^8.0.2", "sass-loader": "^8.0.2",
"tailwindcss": "^3.0.23", "tailwindcss": "^3.0.24",
"tailwindcss-debug-screens": "^2.2.1", "tailwindcss-debug-screens": "^2.2.1",
"vue-loader": "^15.9.8", "vue-loader": "^15.9.8",
"vue-template-compiler": "^2.6.14" "vue-template-compiler": "^2.6.14"
}, },
"dependencies": { "dependencies": {
"@paypal/paypal-js": "^4.2.2", "@paypal/paypal-js": "^4.2.2",
"@stripe/stripe-js": "^1.26.0", "@stripe/stripe-js": "^1.29.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"node-sass": "^4.14.1", "node-sass": "^4.14.1",
"pdfvuer": "^1.9.2", "pdfvuer": "^1.9.2",
"tailwind-scrollbar-hide": "^1.1.7", "tailwind-scrollbar-hide": "^1.1.7",
"twemoji": "^13.1.1", "twemoji": "^13.1.1",
"v-click-outside": "^3.1.2", "v-click-outside": "^3.2.0",
"vee-validate": "^3.4.14", "vee-validate": "^3.4.14",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-feather-icons": "^5.1.0", "vue-feather-icons": "^5.1.0",
"vue-i18n": "^8.27.1", "vue-i18n": "^8.27.1",
"vue-recaptcha-v3": "^1.9.0", "vue-recaptcha-v3": "^1.9.0",
"vue-router": "^3.5.3", "vue-router": "^3.5.4",
"vuex": "^3.6.2" "vuex": "^3.6.2"
} }
} }
@@ -11,6 +11,7 @@
@dragover="dragEnter" @dragover="dragEnter"
@dragleave="dragLeave" @dragleave="dragLeave"
@dragover.prevent @dragover.prevent
@scroll="infiniteScroll"
tabindex="-1" tabindex="-1"
@click.self="deselect" @click.self="deselect"
> >
@@ -24,6 +25,15 @@
:key="item.data.id" :key="item.data.id"
:item="item" :item="item"
/> />
<!-- Infinite Loader Element -->
<div
v-show="showInfiniteLoadSpinner"
class="relative h-16 md:my-0 my-4"
ref="infinityLoader"
>
<Spinner />
</div>
</div> </div>
</template> </template>
@@ -31,14 +41,17 @@
import ItemHandler from './ItemHandler' import ItemHandler from './ItemHandler'
import { events } from '../../bus' import { events } from '../../bus'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import Spinner from './Spinner'
import { debounce } from 'lodash'
export default { export default {
name: 'FileBrowser', name: 'FileBrowser',
components: { components: {
ItemHandler, ItemHandler,
Spinner
}, },
computed: { computed: {
...mapGetters(['isVisibleSidebar', 'currentFolder', 'itemViewType', 'clipboard', 'entries', 'config']), ...mapGetters(['isVisibleSidebar', 'currentFolder', 'itemViewType', 'clipboard', 'entries', 'config', 'paginate']),
draggedItems() { draggedItems() {
// Set opacity for dragged items // Set opacity for dragged items
if (!this.clipboard.includes(this.draggingId)) { if (!this.clipboard.includes(this.draggingId)) {
@@ -49,14 +62,39 @@ export default {
return this.clipboard return this.clipboard
} }
}, },
canLoadMoreEntries() {
return this.paginate?.currentPage !== this.paginate?.lastPage
},
showInfiniteLoadSpinner() {
return this.canLoadMoreEntries && this.entries.length !== 0 && this.paginate.perPage <= this.entries.length
},
}, },
data() { data() {
return { return {
draggingId: undefined, draggingId: undefined,
isDragging: false, isDragging: false,
isLoadingNewEntries: false,
} }
}, },
methods: { methods: {
infiniteScroll: debounce(function () {
if (this.isInfinityLoaderAtBottomPage() && this.canLoadMoreEntries && !this.isLoadingNewEntries) {
this.isLoadingNewEntries = true
this.$getDataByLocation(this.paginate.currentPage + 1)
.then(() => this.isLoadingNewEntries = false)
}
}, 150),
isInfinityLoaderAtBottomPage() {
let rect = this.$refs.infinityLoader.getBoundingClientRect()
return (
rect.bottom > 0 &&
rect.right > 0 &&
rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
rect.top < (window.innerHeight || document.documentElement.clientHeight)
);
},
deleteItems() { deleteItems() {
if ((this.clipboard.length > 0 && this.$checkPermission('master')) || this.$checkPermission('editor')) { if ((this.clipboard.length > 0 && this.$checkPermission('master')) || this.$checkPermission('editor')) {
this.$store.dispatch('deleteItem') this.$store.dispatch('deleteItem')
@@ -81,7 +119,7 @@ export default {
// Store dragged folder // Store dragged folder
this.draggingId = data this.draggingId = data
// TODO: founded issue on firefox // TODO: found issue on firefox
}, },
dragFinish(data, event) { dragFinish(data, event) {
if (event.dataTransfer.items.length === 0) { if (event.dataTransfer.items.length === 0) {
@@ -131,6 +169,11 @@ export default {
}, },
}, },
created() { created() {
// Track document scrolling to load new entries if needed
if (window.innerWidth <= 1024) {
document.addEventListener('scroll', this.infiniteScroll)
}
events.$on('drop', () => { events.$on('drop', () => {
this.isDragging = false this.isDragging = false
@@ -115,7 +115,7 @@ export default {
'isDarkMode', 'isDarkMode',
]), ]),
favourites() { favourites() {
return this.user.data.relationships.favourites.data.attributes.folders return this.user.data.relationships.favourites.attributes.folders
}, },
storage() { storage() {
return this.$store.getters.user.data.attributes.storage return this.$store.getters.user.data.attributes.storage
@@ -132,7 +132,7 @@ export default {
computed: { computed: {
...mapGetters(['isVisibleNavigationBars', 'navigation', 'clipboard', 'config', 'user']), ...mapGetters(['isVisibleNavigationBars', 'navigation', 'clipboard', 'config', 'user']),
favourites() { favourites() {
return this.user.data.relationships.favourites.data return this.user.data.relationships.favourites
}, },
storage() { storage() {
return this.$store.getters.user.data.attributes.storage return this.$store.getters.user.data.attributes.storage
@@ -900,13 +900,13 @@ export default {
.then((response) => { .then((response) => {
// Show user result // Show user result
if (this.activeFilter === 'users') { if (this.activeFilter === 'users') {
this.results = response.data.data this.results = response.data
} }
// Show file result // Show file result
if (!this.activeFilter) { if (!this.activeFilter) {
let files = response.data.files.data let files = response.data.files
let folders = response.data.folders.data let folders = response.data.folders
this.results = folders.concat(files) this.results = folders.concat(files)
} }
+10 -10
View File
@@ -350,19 +350,19 @@ const FunctionHelpers = {
}[this.$router.currentRoute.name] }[this.$router.currentRoute.name]
} }
Vue.prototype.$getDataByLocation = function () { Vue.prototype.$getDataByLocation = async function (page) {
let routes = { let routes = {
RequestUpload: ['getUploadRequestFolder', router.currentRoute.params.id || undefined ], RequestUpload: ['getUploadRequestFolder', {page:page, id:router.currentRoute.params.id || undefined} ],
Public: ['getSharedFolder', router.currentRoute.params.id || undefined], Public: ['getSharedFolder', {page:page, id:router.currentRoute.params.id || undefined}],
Files: ['getFolder', router.currentRoute.params.id || undefined], Files: ['getFolder', {page:page, id:router.currentRoute.params.id || undefined}],
RecentUploads: ['getRecentUploads'], RecentUploads: ['getRecentUploads', page],
MySharedItems: ['getMySharedItems'], MySharedItems: ['getMySharedItems', page],
Trash: ['getTrash', router.currentRoute.params.id || undefined], Trash: ['getTrash', {page:page , id:router.currentRoute.params.id || undefined}],
TeamFolders: ['getTeamFolder', router.currentRoute.params.id || undefined], TeamFolders: ['getTeamFolder',{page:page, id:router.currentRoute.params.id || undefined}],
SharedWithMe: ['getSharedWithMeFolder', router.currentRoute.params.id || undefined], SharedWithMe: ['getSharedWithMeFolder',{page:page, id:router.currentRoute.params.id || undefined}],
} }
store.dispatch(...routes[router.currentRoute.name]) await store.dispatch(...routes[router.currentRoute.name])
} }
Vue.prototype.$getPaymentLogo = function (driver) { Vue.prototype.$getPaymentLogo = function (driver) {
+1 -1
View File
@@ -17,7 +17,7 @@ const itemHelpers = {
} }
Vue.prototype.$toggleFavourites = function (entry) { Vue.prototype.$toggleFavourites = function (entry) {
let favourites = store.getters.user.data.relationships.favourites.data let favourites = store.getters.user.data.relationships.favourites
// Check if folder is in favourites and then add/remove from favourites // Check if folder is in favourites and then add/remove from favourites
if (favourites && !favourites.find((el) => el.data.id === entry.data.id)) { if (favourites && !favourites.find((el) => el.data.id === entry.data.id)) {
+42 -29
View File
@@ -6,45 +6,50 @@ import i18n from '../../i18n'
const defaultState = { const defaultState = {
currentFolder: undefined, currentFolder: undefined,
isMultiSelectMode: false,
fastPreview: undefined, fastPreview: undefined,
navigation: undefined, navigation: undefined,
isMultiSelectMode: false, paginate: undefined,
isLoading: true, isLoading: true,
clipboard: [], clipboard: [],
entries: [], entries: [],
} }
const actions = { const actions = {
getFolder: ({ commit, getters }, id) => { getFolder: ({ commit, getters },{page, id}) => {
commit('LOADING_STATE', { loading: true, data: [] }) return new Promise ((resolve, reject) => {
if(! page)
commit('LOADING_STATE', { loading: true, data: [] })
axios axios
.get(`${getters.api}/browse/folders/${id || 'all'}${getters.sorting.URI}`) .get(`${getters.api}/browse/folders/${id || 'all'}${getters.sorting.URI}&page=${currentPage}`)
.then((response) => { .then((response) => {
let folders = response.data.folders.data commit('SET_PAGINATE', response.data.meta.paginate)
let files = response.data.files.data
commit('LOADING_STATE', { commit('LOADING_STATE', {
loading: false, loading: false,
data: folders.concat(files), data: response.data.data,
})
commit('SET_CURRENT_FOLDER', response.data.root)
events.$emit('scrollTop')
})
.catch((error) => {
// Redirect if unauthenticated
if ([401, 403].includes(error.response.status)) {
commit('SET_AUTHORIZED', false)
router.push({ name: 'SignIn' })
} else {
// Show error message
events.$emit('alert:open', {
title: i18n.t('popup_error.title'),
message: i18n.t('popup_error.message'),
}) })
} commit('SET_CURRENT_FOLDER', response.data.meta.root)
})
events.$emit('scrollTop')
resolve(response);
})
.catch((error) => {
// Redirect if unauthenticated
if ([401, 403].includes(error.response.status)) {
commit('SET_AUTHORIZED', false)
router.push({ name: 'SignIn' })
} else {
// Show error message
events.$emit('alert:open', {
title: i18n.t('popup_error.title'),
message: i18n.t('popup_error.message'),
})
}
})
})
}, },
getRecentUploads: ({ commit, getters }) => { getRecentUploads: ({ commit, getters }) => {
commit('LOADING_STATE', { loading: true, data: [] }) commit('LOADING_STATE', { loading: true, data: [] })
@@ -125,8 +130,15 @@ const actions = {
} }
const mutations = { const mutations = {
SET_PAGINATE(state, payload) {
state.paginate = payload
},
LOADING_STATE(state, payload) { LOADING_STATE(state, payload) {
state.entries = payload.data if(payload.data.length === 0) {
state.entries = []
} else {
state.entries.push(...payload.data)
}
state.isLoading = payload.loading state.isLoading = payload.loading
}, },
SET_CURRENT_FOLDER(state, folder) { SET_CURRENT_FOLDER(state, folder) {
@@ -220,6 +232,7 @@ const getters = {
navigation: (state) => state.navigation, navigation: (state) => state.navigation,
clipboard: (state) => state.clipboard, clipboard: (state) => state.clipboard,
isLoading: (state) => state.isLoading, isLoading: (state) => state.isLoading,
paginate: (state) => state.paginate,
entries: (state) => state.entries, entries: (state) => state.entries,
} }
+7 -2
View File
@@ -15,8 +15,8 @@ const actions = {
axios axios
.get(`/api/file-request/${router.currentRoute.params.token}/browse/${id || 'all'}${getters.sorting.URI}`) .get(`/api/file-request/${router.currentRoute.params.token}/browse/${id || 'all'}${getters.sorting.URI}`)
.then((response) => { .then((response) => {
let folders = response.data.folders.data let folders = response.data.folders
let files = response.data.files.data let files = response.data.files
commit('LOADING_STATE', { commit('LOADING_STATE', {
loading: false, loading: false,
@@ -52,6 +52,11 @@ const actions = {
commit('SET_CURRENT_FOLDER', response.data.data.relationships.folder) commit('SET_CURRENT_FOLDER', response.data.data.relationships.folder)
} }
}) })
.catch((error) => {
Vue.prototype.$isSomethingWrong()
reject(error)
})
}) })
}, },
closeUploadRequest: ({ commit }) => { closeUploadRequest: ({ commit }) => {
+2 -2
View File
@@ -254,7 +254,7 @@ export default {
return this.item && this.item.data.type === 'folder' return this.item && this.item.data.type === 'folder'
}, },
isInFavourites() { isInFavourites() {
return this.user.data.relationships.favourites.data.find((el) => el.data.id === this.item.data.id) return this.user.data.relationships.favourites.find((el) => el.data.id === this.item.data.id)
}, },
hasFile() { hasFile() {
return this.clipboard.find((item) => item.data.type !== 'folder') return this.clipboard.find((item) => item.data.type !== 'folder')
@@ -266,7 +266,7 @@ export default {
} }
}, },
created() { created() {
this.$store.dispatch('getFolder', this.$route.params.id) this.$store.dispatch('getFolder', {page:null, id:this.$route.params.id})
events.$on('context-menu:show', (event, item) => (this.item = item)) events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('context-menu:current-folder', (folder) => (this.item = folder)) events.$on('context-menu:current-folder', (folder) => (this.item = folder))
@@ -157,7 +157,7 @@ export default {
return this.item && this.item.type === 'folder' return this.item && this.item.type === 'folder'
}, },
isInFavourites() { isInFavourites() {
return this.user.data.relationships.favourites.data.find((el) => el.id === this.item.id) return this.user.data.relationships.favourites.find((el) => el.id === this.item.id)
}, },
hasFile() { hasFile() {
return this.clipboard.find((item) => item.type !== 'folder') return this.clipboard.find((item) => item.type !== 'folder')
+1 -1
View File
@@ -234,7 +234,7 @@ export default {
}, },
}, },
created() { created() {
this.$store.dispatch('getSharedFolder', this.$route.params.id) this.$store.dispatch('getSharedFolder', {page:null, id:this.$route.params.id})
events.$on('context-menu:show', (event, item) => (this.item = item)) events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('mobile-context-menu:show', (item) => (this.item = item)) events.$on('mobile-context-menu:show', (item) => (this.item = item))
+2 -2
View File
@@ -242,7 +242,7 @@ export default {
}, },
}, },
mounted() { mounted() {
this.$store.dispatch('getSharedWithMeFolder', this.$route.params.id) this.$store.dispatch('getSharedWithMeFolder',{page:null, id:this.$route.params.id})
events.$on('context-menu:show', (event, item) => (this.item = item)) events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('mobile-context-menu:show', (item) => (this.item = item)) events.$on('mobile-context-menu:show', (item) => (this.item = item))
@@ -257,7 +257,7 @@ export default {
if (this.$route.params.id) { if (this.$route.params.id) {
this.$router.push({ name: 'SharedWithMe' }) this.$router.push({ name: 'SharedWithMe' })
} else { } else {
this.$store.dispatch('getSharedWithMeFolder', undefined) this.$store.dispatch('getSharedWithMeFolder',{page:null, id:undefined})
} }
events.$emit('toaster', { events.$emit('toaster', {
+2 -2
View File
@@ -281,7 +281,7 @@ export default {
return this.item && this.item.data.type === 'folder' return this.item && this.item.data.type === 'folder'
}, },
isInFavourites() { isInFavourites() {
return this.user.data.relationships.favourites.data.find((el) => el.id === this.item.id) return this.user.data.relationships.favourites.find((el) => el.id === this.item.id)
}, },
hasFile() { hasFile() {
return this.clipboard.find((item) => item.type !== 'folder') return this.clipboard.find((item) => item.type !== 'folder')
@@ -293,7 +293,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.$store.dispatch('getTeamFolder', this.$route.params.id) this.$store.dispatch('getTeamFolder', {page:null, id:this.$route.params.id})
events.$on('context-menu:show', (event, item) => (this.item = item)) events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('mobile-context-menu:show', (item) => (this.item = item)) events.$on('mobile-context-menu:show', (item) => (this.item = item))
+1 -1
View File
@@ -149,7 +149,7 @@ export default {
} }
}, },
created() { created() {
this.$store.dispatch('getTrash', this.$route.params.id) this.$store.dispatch('getTrash', {page:null, id:this.$route.params.id})
events.$on('context-menu:show', (event, item) => (this.item = item)) events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('mobile-context-menu:show', (item) => (this.item = item)) events.$on('mobile-context-menu:show', (item) => (this.item = item))
+1 -2
View File
@@ -160,8 +160,7 @@ class User extends Authenticatable implements MustVerifyEmail
->with([ ->with([
'parent:id,name', 'parent:id,name',
'shared:token,id,item_id,permission,is_protected,expire_in', 'shared:token,id,item_id,permission,is_protected,expire_in',
]) ]);
->take(40);
} }
/** /**
@@ -16,24 +16,49 @@ class BrowseFolderController
): array { ): array {
$root_id = Str::isUuid($id) ? $id : null; $root_id = Str::isUuid($id) ? $id : null;
$folderQuery = [
'parent_id' => $root_id,
'team_folder' => false,
'user_id' => Auth::id(),
'deleted_at' => null,
];
$fileQuery = [
'parent_id' => $root_id,
'user_id' => Auth::id(),
'deleted_at' => null,
];
list($foldersTake, $foldersSkip, $filesTake, $filesSkip, $totalItemsCount) = getRecordsCount($folderQuery, $fileQuery, request()->input('page'));
$folders = Folder::with(['parent:id,name', 'shared:token,id,item_id,permission,is_protected,expire_in']) $folders = Folder::with(['parent:id,name', 'shared:token,id,item_id,permission,is_protected,expire_in'])
->where('parent_id', $root_id) ->where($folderQuery)
->where('team_folder', false)
->where('user_id', Auth::id())
->sortable() ->sortable()
->skip($foldersSkip)
->take($foldersTake)
->get(); ->get();
$files = File::with(['parent:id,name', 'shared:token,id,item_id,permission,is_protected,expire_in']) $files = File::with(['parent:id,name', 'shared:token,id,item_id,permission,is_protected,expire_in'])
->where('parent_id', $root_id) ->where($fileQuery)
->where('user_id', Auth::id())
->sortable() ->sortable()
->skip($filesSkip)
->take($filesTake)
->get(); ->get();
$entries = collect([
$folders ? json_decode((new FolderCollection($folders))->toJson(), true) : null,
$files ? json_decode((new FilesCollection($files))->toJson(), true) : null,
])->collapse();
list($paginate, $links) = generatePaginationCounts($totalItemsCount);
// Collect folders and files to single array
return [ return [
'folders' => new FolderCollection($folders), 'data' => $entries,
'files' => new FilesCollection($files), 'links' => $links,
'root' => $root_id ? new FolderResource(Folder::findOrFail($root_id)) : null, 'meta' => [
'paginate' => $paginate,
'root' => $root_id ? new FolderResource(Folder::findOrFail($root_id)) : null,
],
]; ];
} }
} }
@@ -2,12 +2,12 @@
namespace Domain\Browsing\Controllers; namespace Domain\Browsing\Controllers;
use App\Users\Models\User; use App\Users\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Domain\Files\Resources\FilesCollection;
class BrowseLatestFilesController class BrowseLatestFilesController
{ {
public function __invoke(): array public function __invoke(Request $request): array
{ {
$user = User::with([ $user = User::with([
'latestUploads' => fn ($query) => $query->sortable(['created_at' => 'desc']), 'latestUploads' => fn ($query) => $query->sortable(['created_at' => 'desc']),
@@ -15,9 +15,15 @@ class BrowseLatestFilesController
->where('id', Auth::id()) ->where('id', Auth::id())
->first(); ->first();
list($data, $paginate, $links) = groupPaginate($request, null, $user->latestUploads);
return [ return [
'files' => new FilesCollection($user->latestUploads), 'data' => $data,
'root' => null, 'links' => $links,
'meta' => [
'paginate' => $paginate,
'root' => null,
],
]; ];
} }
} }
@@ -1,16 +1,15 @@
<?php <?php
namespace Domain\Browsing\Controllers; namespace Domain\Browsing\Controllers;
use Illuminate\Http\Request;
use Domain\Files\Models\File; use Domain\Files\Models\File;
use Domain\Sharing\Models\Share; use Domain\Sharing\Models\Share;
use Domain\Folders\Models\Folder; use Domain\Folders\Models\Folder;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Domain\Files\Resources\FilesCollection;
use Domain\Folders\Resources\FolderCollection;
class BrowseSharedItemsController class BrowseSharedItemsController
{ {
public function __invoke(): array public function __invoke(Request $request): array
{ {
$user_id = Auth::id(); $user_id = Auth::id();
@@ -36,11 +35,16 @@ class BrowseSharedItemsController
->sortable() ->sortable()
->get(); ->get();
list($data, $paginate, $links) = groupPaginate($request, $folders, $files);
// Collect folders and files to single array // Collect folders and files to single array
return [ return [
'folders' => new FolderCollection($folders), 'data' => $data,
'files' => new FilesCollection($files), 'links' => $links,
'root' => null, 'meta' => [
'paginate' => $paginate,
'root' => null,
],
]; ];
} }
} }
@@ -1,16 +1,15 @@
<?php <?php
namespace Domain\Files\Resources; namespace Domain\Files\Resources;
use Illuminate\Support\Collection;
use Illuminate\Http\Resources\Json\ResourceCollection; use Illuminate\Http\Resources\Json\ResourceCollection;
class FilesCollection extends ResourceCollection class FilesCollection extends ResourceCollection
{ {
public $collects = FileResource::class; public $collects = FileResource::class;
public function toArray($request): array public function toArray($request): Collection
{ {
return [ return $this->collection;
'data' => $this->collection,
];
} }
} }
@@ -1,16 +1,15 @@
<?php <?php
namespace Domain\Folders\Resources; namespace Domain\Folders\Resources;
use Illuminate\Support\Collection;
use Illuminate\Http\Resources\Json\ResourceCollection; use Illuminate\Http\Resources\Json\ResourceCollection;
class FolderCollection extends ResourceCollection class FolderCollection extends ResourceCollection
{ {
public $collects = FolderResource::class; public $collects = FolderResource::class;
public function toArray($request): array public function toArray($request): Collection
{ {
return [ return $this->collection;
'data' => $this->collection,
];
} }
} }
@@ -3,17 +3,16 @@ namespace Domain\Teams\Controllers;
use Str; use Str;
use Gate; use Gate;
use Illuminate\Http\Request;
use Domain\Files\Models\File; use Domain\Files\Models\File;
use Domain\Folders\Models\Folder; use Domain\Folders\Models\Folder;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Domain\Files\Resources\FilesCollection;
use Domain\Folders\Resources\FolderResource; use Domain\Folders\Resources\FolderResource;
use Domain\Folders\Resources\FolderCollection;
class BrowseSharedWithMeController class BrowseSharedWithMeController
{ {
public function __invoke($id): array public function __invoke(Request $request, $id): array
{ {
$id = Str::isUuid($id) ? $id : null; $id = Str::isUuid($id) ? $id : null;
@@ -46,11 +45,16 @@ class BrowseSharedWithMeController
->get(); ->get();
} }
list($data, $paginate, $links) = groupPaginate($request, $folders, $files ?? null);
return [ return [
'root' => $id ? new FolderResource(Folder::findOrFail($id)) : null, 'data' => $data,
'folders' => new FolderCollection($folders),
'files' => isset($files) ? new FilesCollection($files) : new FilesCollection([]),
'teamFolder' => $id ? new FolderResource($teamFolder) : null, 'teamFolder' => $id ? new FolderResource($teamFolder) : null,
'links' => $links,
'meta' => [
'paginate' => $paginate,
'root' => $id ? new FolderResource(Folder::findOrFail($id)) : null,
],
]; ];
} }
} }
@@ -2,6 +2,7 @@
namespace Domain\Teams\Controllers; namespace Domain\Teams\Controllers;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Domain\Files\Models\File; use Domain\Files\Models\File;
use Domain\Folders\Models\Folder; use Domain\Folders\Models\Folder;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@@ -10,10 +11,8 @@ use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Domain\Teams\Models\TeamFolderMember; use Domain\Teams\Models\TeamFolderMember;
use Domain\Teams\DTO\CreateTeamFolderData; use Domain\Teams\DTO\CreateTeamFolderData;
use Domain\Files\Resources\FilesCollection;
use Domain\Folders\Resources\FolderResource; use Domain\Folders\Resources\FolderResource;
use Domain\Teams\Actions\UpdateMembersAction; use Domain\Teams\Actions\UpdateMembersAction;
use Domain\Folders\Resources\FolderCollection;
use Domain\Teams\Actions\UpdateInvitationsAction; use Domain\Teams\Actions\UpdateInvitationsAction;
use Domain\Teams\Requests\CreateTeamFolderRequest; use Domain\Teams\Requests\CreateTeamFolderRequest;
use Domain\Teams\Requests\UpdateTeamFolderMembersRequest; use Domain\Teams\Requests\UpdateTeamFolderMembersRequest;
@@ -28,7 +27,7 @@ class TeamFoldersController extends Controller
) { ) {
} }
public function show($id): array public function show(Request $request, $id): array
{ {
$id = Str::isUuid($id) ? $id : null; $id = Str::isUuid($id) ? $id : null;
@@ -51,12 +50,17 @@ class TeamFoldersController extends Controller
->get(); ->get();
} }
list($data, $paginate, $links) = groupPaginate($request, $folders, $files ?? null);
// Collect folders and files to single array // Collect folders and files to single array
return [ return [
'folders' => new FolderCollection($folders), 'data' => $data,
'files' => isset($files) ? new FilesCollection($files) : new FilesCollection([]),
'root' => $id ? new FolderResource(Folder::findOrFail($id)) : null,
'teamFolder' => $id ? new FolderResource(Folder::findOrFail($id)->getLatestParent()) : null, 'teamFolder' => $id ? new FolderResource(Folder::findOrFail($id)->getLatestParent()) : null,
'links' => $links,
'meta' => [
'paginate' => $paginate,
'root' => $id ? new FolderResource(Folder::findOrFail($id)) : null,
],
]; ];
} }
+90
View File
@@ -9,6 +9,7 @@ use Domain\Files\Models\File;
use Domain\Sharing\Models\Share; use Domain\Sharing\Models\Share;
use Domain\Folders\Models\Folder; use Domain\Folders\Models\Folder;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Domain\Settings\Models\Setting; use Domain\Settings\Models\Setting;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@@ -1208,4 +1209,93 @@ if (! function_exists('extractItemsFromGetAttribute')) {
]; ];
}); });
} }
if (! function_exists('generatePaginationCounts')) {
/**
* Group paginate of Foldes and Files
*/
function generatePaginationCounts(
int $totalItemsCount
) : array {
$perPage = config('vuefilemanager.paginate.perPage');
$currentPage = request()->input('page') === 'all' ? 1 : (int) request()->input('page');
$uri = request()->fullUrl();
$lastPage = ceil($totalItemsCount / $perPage);
return [
[
'currentPage' => $currentPage,
'from' => 1,
'lastPage' => $lastPage,
'path' => $uri,
'perPage' => $perPage,
'to' => $perPage,
'total' => $totalItemsCount,
],
[
'first' => $uri . '&page=1',
'last' => $uri . '&page=' . $lastPage,
'next' => $currentPage == $lastPage ? null : $uri . '&page=' . $currentPage + 1,
'prev' => $currentPage == 1 ? null : $uri . '&page=' . $currentPage - 1,
],
];
}
}
if (! function_exists('getRecordsCount')) {
/**
* Get count of items from the Database
*/
function getRecordsCount(
array $folderQuery,
array $fileQuery,
string $page
) : array {
$perPage = config('vuefilemanager.paginate.perPage');
$currentPage = $page === 'all' ? 1 : (int) $page;
$foldersSkip = 0;
$foldersTake = 0;
$filesSkip = 0;
$filesTake = 0;
$foldersCount = DB::table('folders')
->where($folderQuery)
->count();
$filesCount = DB::table('files')
->where($fileQuery)
->count();
$totalItemsCount = $foldersCount + $filesCount;
if ($page !== 'all') {
// Folders pages
if ($foldersCount >= $currentPage * $perPage) {
$foldersTake = $perPage;
$foldersSkip = ($currentPage - 1) * $perPage;
}
// Mixed page
if ($foldersCount < $currentPage * $perPage && ceil($currentPage) === ceil($foldersCount / $perPage)) {
$foldersSkip = ($currentPage - 1) * $perPage;
$foldersTake = $foldersCount - $foldersSkip;
$filesTake = ($currentPage * $perPage) - $foldersCount;
$filesSkip = 0;
}
// Files pages
if ($currentPage > ceil($foldersCount / $perPage)) {
$filesTake = $perPage;
$filesSkip = ((ceil($foldersCount / $perPage) * $perPage) - $foldersCount) + ($currentPage - (ceil($foldersCount / $perPage)) - 1) * $perPage;
}
} else {
$foldersTake = $foldersCount;
$filesTake = $filesCount;
}
return [$foldersTake, $foldersSkip, $filesTake, $filesSkip, $totalItemsCount];
}
}
} }
+57
View File
@@ -2,6 +2,10 @@
namespace Tests\Support\Helpers; namespace Tests\Support\Helpers;
use Tests\TestCase; use Tests\TestCase;
use App\Users\Models\User;
use Domain\Files\Models\File;
use Domain\Folders\Models\Folder;
use Illuminate\Support\Facades\Config;
class HelperTest extends TestCase class HelperTest extends TestCase
{ {
@@ -25,4 +29,57 @@ class HelperTest extends TestCase
$this->assertEquals('Jane', $thirdTest['first_name']); $this->assertEquals('Jane', $thirdTest['first_name']);
$this->assertEquals('', $thirdTest['last_name']); $this->assertEquals('', $thirdTest['last_name']);
} }
/**
* @test
*/
public function it_test_get_records_count()
{
$user = User::factory()
->hasSettings()
->create();
Folder::factory()
->count(12)
->create([
'user_id' => $user->id,
'parent_id' => null,
]);
File::factory()
->count(13)
->create([
'user_id' => $user->id,
'parent_id' => null,
]);
$folderQuery = [
'parent_id' => null,
'team_folder' => false,
'user_id' => $user->id,
'deleted_at' => null,
];
$fileQuery = [
'parent_id' => null,
'user_id' => $user->id,
'deleted_at' => null,
];
Config::set('vuefilemanager.paginate.perPage', 5);
// getRecordsCunt returned array [foldersTake, foldersSkip, filesTake, filesSkip, totalItemsCount]
// Get folders page
$this->assertEquals([5, 0, 0, 0, 25], getRecordsCount($folderQuery, $fileQuery, '1'));
// Get mixed page
$this->assertEquals([2, 10, 3, 0, 25], getRecordsCount($folderQuery, $fileQuery, '3'));
// Get files page
$this->assertEquals([0, 0, 5, 8, 25], getRecordsCount($folderQuery, $fileQuery, '5'));
// Get all pages
$this->assertEquals([12, 0, 13, 0, 25], getRecordsCount($folderQuery, $fileQuery, 'all'));
}
} }