v1.5-alpha.10

This commit is contained in:
carodej
2020-05-18 12:37:33 +02:00
parent dfe4991177
commit 633bef7660
13 changed files with 475 additions and 26 deletions

View File

@@ -2,7 +2,9 @@
namespace App\Http\Controllers\User;
use App\FileManagerFile;
use App\FileManagerFolder;
use App\Http\Resources\StorageDetailResource;
use App\Http\Tools\Demo;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Support\Facades\Validator;
@@ -34,10 +36,10 @@ class AccountController extends Controller
->get();
return [
'user' => $user->only(['name', 'email', 'avatar']),
'favourites' => $user->favourites->makeHidden(['pivot']),
'tree' => $tree,
'storage' => [
'user' => $user->only(['name', 'email', 'avatar']),
'favourites' => $user->favourites->makeHidden(['pivot']),
'tree' => $tree,
'storage' => [
'used' => Metric::bytes($user->used_capacity)->format(),
'capacity' => format_gigabytes(config('vuefilemanager.user_storage_capacity')),
'percentage' => get_storage_fill_percentage($user->used_capacity, config('vuefilemanager.user_storage_capacity')),
@@ -45,6 +47,89 @@ class AccountController extends Controller
];
}
/**
* Get storage details
*
* @return array
*/
public function storage()
{
$document_mimetypes = [
'pdf', 'numbers', 'xlsx', 'xls', 'txt', 'md', 'rtf', 'pptx', 'ppt', 'odt', 'ods', 'odp', 'epub', 'docx', 'doc', 'csv', 'pages'
];
$user = Auth::user();
$storage_capacity = config('vuefilemanager.user_storage_capacity');
$images = FileManagerFile::where('user_id', $user->id)
->where('type', 'image')->get()->map(function ($item) {
return (int)$item->getOriginal('filesize');
})->sum();
$audios = FileManagerFile::where('user_id', $user->id)
->where('type', 'audio')->get()->map(function ($item) {
return (int)$item->getOriginal('filesize');
})->sum();
$videos = FileManagerFile::where('user_id', $user->id)
->where('type', 'video')->get()->map(function ($item) {
return (int)$item->getOriginal('filesize');
})->sum();
$documents = FileManagerFile::where('user_id', $user->id)
->whereIn('mimetype', $document_mimetypes)->get()->map(function ($item) {
return (int)$item->getOriginal('filesize');
})->sum();
$others = FileManagerFile::where('user_id', $user->id)
->whereNotIn('mimetype', $document_mimetypes)
->whereNotIn('type', ['audio', 'video', 'image'])
->get()->map(function ($item) {
return (int)$item->getOriginal('filesize');
})->sum();
$usage = collect([
'images' => [
'used' => $images,
'percentage' => get_storage_fill_percentage($images, $storage_capacity),
],
'audios' => [
'used' => $audios,
'percentage' => get_storage_fill_percentage($audios, $storage_capacity),
],
'videos' => [
'used' => $videos,
'percentage' => get_storage_fill_percentage($videos, $storage_capacity),
],
'documents' => [
'used' => $documents,
'percentage' => get_storage_fill_percentage($documents, $storage_capacity),
],
'others' => [
'used' => $others,
'percentage' => get_storage_fill_percentage($others, $storage_capacity),
],
]);
return [
'data' => [
'id' => '1',
'type' => 'disk',
'attributes' => [
'used' => Metric::bytes($user->used_capacity)->format(),
'capacity' => format_gigabytes($storage_capacity),
'percentage' => get_storage_fill_percentage($user->used_capacity, $storage_capacity),
],
'relationships' => $usage->map(function ($item) {
return [
'used' => Metric::bytes($item['used'])->format(),
'percentage' => $item['percentage']
];
})
]
];
}
/**
* Update user profile
*

View File

@@ -230,7 +230,7 @@ class Editor
$image = Image::make($file->getRealPath())->orientate();
// Resize image
$image->resize(256, null, function ($constraint) {
$image->resize(564, null, function ($constraint) {
$constraint->aspectRatio();
})->stream();

View File

@@ -1,19 +1,50 @@
{
"/js/main.js": "/js/main.js",
"/css/app.css": "/css/app.css",
"/js/main.e46fa96cd6ffd39a4562.hot-update.js": "/js/main.e46fa96cd6ffd39a4562.hot-update.js",
"/js/main.f2d49bc1541da0f12970.hot-update.js": "/js/main.f2d49bc1541da0f12970.hot-update.js",
"/js/main.1eef99df4b0f12424803.hot-update.js": "/js/main.1eef99df4b0f12424803.hot-update.js",
"/js/main.5ddffc9a7b267188676c.hot-update.js": "/js/main.5ddffc9a7b267188676c.hot-update.js",
"/js/main.390ae60e2291b0dbccc3.hot-update.js": "/js/main.390ae60e2291b0dbccc3.hot-update.js",
"/js/main.6f2959aac5b1dece64a9.hot-update.js": "/js/main.6f2959aac5b1dece64a9.hot-update.js",
"/js/main.46741bd43cbaa6ee89b1.hot-update.js": "/js/main.46741bd43cbaa6ee89b1.hot-update.js",
"/js/main.273e3c85d127556c963f.hot-update.js": "/js/main.273e3c85d127556c963f.hot-update.js",
"/js/main.262acc9e6f3602846eb5.hot-update.js": "/js/main.262acc9e6f3602846eb5.hot-update.js",
"/js/main.340ad852bdc54fb22ddd.hot-update.js": "/js/main.340ad852bdc54fb22ddd.hot-update.js",
"/js/main.0f01b236243cc4d2ab64.hot-update.js": "/js/main.0f01b236243cc4d2ab64.hot-update.js",
"/js/main.bc5704d8e53dc4abc11a.hot-update.js": "/js/main.bc5704d8e53dc4abc11a.hot-update.js",
"/js/main.d639deb26abe56ea8a48.hot-update.js": "/js/main.d639deb26abe56ea8a48.hot-update.js",
"/js/main.4a2927afd0488259ade3.hot-update.js": "/js/main.4a2927afd0488259ade3.hot-update.js",
"/js/main.11e163fdc882ac0dd7c2.hot-update.js": "/js/main.11e163fdc882ac0dd7c2.hot-update.js"
"/js/main.817eec0cf589070e068c.hot-update.js": "/js/main.817eec0cf589070e068c.hot-update.js",
"/js/main.febf57d8b972d78cd0b1.hot-update.js": "/js/main.febf57d8b972d78cd0b1.hot-update.js",
"/js/main.aacc9173e79145d56d68.hot-update.js": "/js/main.aacc9173e79145d56d68.hot-update.js",
"/js/main.ca3534dd246f7214e1ca.hot-update.js": "/js/main.ca3534dd246f7214e1ca.hot-update.js",
"/js/main.e92c163dbc9d8e0461fe.hot-update.js": "/js/main.e92c163dbc9d8e0461fe.hot-update.js",
"/js/main.977d0f1ba01a7ecdc83f.hot-update.js": "/js/main.977d0f1ba01a7ecdc83f.hot-update.js",
"/js/main.d20455489c82352218e1.hot-update.js": "/js/main.d20455489c82352218e1.hot-update.js",
"/js/main.c41fdf00e1caa293dcd4.hot-update.js": "/js/main.c41fdf00e1caa293dcd4.hot-update.js",
"/js/main.9f85a9b69995df3358b1.hot-update.js": "/js/main.9f85a9b69995df3358b1.hot-update.js",
"/js/main.d8ebb130e1de006f1b7d.hot-update.js": "/js/main.d8ebb130e1de006f1b7d.hot-update.js",
"/js/main.7ca180c1b27f6f443c15.hot-update.js": "/js/main.7ca180c1b27f6f443c15.hot-update.js",
"/js/main.3a13a704160c56773b6c.hot-update.js": "/js/main.3a13a704160c56773b6c.hot-update.js",
"/js/main.dd2255fe79ad7e9bd1cb.hot-update.js": "/js/main.dd2255fe79ad7e9bd1cb.hot-update.js",
"/js/main.ed6abb6ca89a967371e6.hot-update.js": "/js/main.ed6abb6ca89a967371e6.hot-update.js",
"/js/main.cb6413fa3b436014f6c0.hot-update.js": "/js/main.cb6413fa3b436014f6c0.hot-update.js",
"/js/main.1c62802df52b712688b8.hot-update.js": "/js/main.1c62802df52b712688b8.hot-update.js",
"/js/main.807705eac82af8c701fa.hot-update.js": "/js/main.807705eac82af8c701fa.hot-update.js",
"/js/main.afd9626567ad2df2ac9c.hot-update.js": "/js/main.afd9626567ad2df2ac9c.hot-update.js",
"/js/main.cf2327d8b73200ab16d4.hot-update.js": "/js/main.cf2327d8b73200ab16d4.hot-update.js",
"/js/main.1c91e2f63c823bd221e7.hot-update.js": "/js/main.1c91e2f63c823bd221e7.hot-update.js",
"/js/main.b2972d6f67a9ccedaef7.hot-update.js": "/js/main.b2972d6f67a9ccedaef7.hot-update.js",
"/js/main.0d8a9dd4bd71257d9296.hot-update.js": "/js/main.0d8a9dd4bd71257d9296.hot-update.js",
"/js/main.2b287dbf8bd092e3d350.hot-update.js": "/js/main.2b287dbf8bd092e3d350.hot-update.js",
"/js/main.9b2de5e892f0ae4a1e84.hot-update.js": "/js/main.9b2de5e892f0ae4a1e84.hot-update.js",
"/js/main.cf9b7d50041d873f8a81.hot-update.js": "/js/main.cf9b7d50041d873f8a81.hot-update.js",
"/js/main.8bacb170e9bc97bfcfd8.hot-update.js": "/js/main.8bacb170e9bc97bfcfd8.hot-update.js",
"/js/main.3a8f3274463b0c3957d7.hot-update.js": "/js/main.3a8f3274463b0c3957d7.hot-update.js",
"/js/main.12cfdab35701103a62d9.hot-update.js": "/js/main.12cfdab35701103a62d9.hot-update.js",
"/js/main.25b363299b1ff981c99a.hot-update.js": "/js/main.25b363299b1ff981c99a.hot-update.js",
"/js/main.ac60fa6550e88275018b.hot-update.js": "/js/main.ac60fa6550e88275018b.hot-update.js",
"/js/main.11cceb6b79b7bc522fd2.hot-update.js": "/js/main.11cceb6b79b7bc522fd2.hot-update.js",
"/js/main.7e5540a975e19e4a02eb.hot-update.js": "/js/main.7e5540a975e19e4a02eb.hot-update.js",
"/js/main.27f8370c72233614bc39.hot-update.js": "/js/main.27f8370c72233614bc39.hot-update.js",
"/js/main.2c2a0d75a6d3a7c4565e.hot-update.js": "/js/main.2c2a0d75a6d3a7c4565e.hot-update.js",
"/js/main.f334180312804bae36e9.hot-update.js": "/js/main.f334180312804bae36e9.hot-update.js",
"/js/main.0d0aaa4c32c5b8d3bb8f.hot-update.js": "/js/main.0d0aaa4c32c5b8d3bb8f.hot-update.js",
"/js/main.9eb0004310ed2536b0c4.hot-update.js": "/js/main.9eb0004310ed2536b0c4.hot-update.js",
"/js/main.875b00580be4eff0d64b.hot-update.js": "/js/main.875b00580be4eff0d64b.hot-update.js",
"/js/main.65819ac7c832f34c71bd.hot-update.js": "/js/main.65819ac7c832f34c71bd.hot-update.js",
"/js/main.5db94bea7020fc6c29ba.hot-update.js": "/js/main.5db94bea7020fc6c29ba.hot-update.js",
"/js/main.22b4060751a2d9bcca48.hot-update.js": "/js/main.22b4060751a2d9bcca48.hot-update.js",
"/js/main.bb942b8829b5fb097736.hot-update.js": "/js/main.bb942b8829b5fb097736.hot-update.js",
"/js/main.6babdb7ce1c9178fe8f7.hot-update.js": "/js/main.6babdb7ce1c9178fe8f7.hot-update.js",
"/js/main.fb55dc009cd6252dff65.hot-update.js": "/js/main.fb55dc009cd6252dff65.hot-update.js",
"/js/main.0a8179cde3b86b4f0623.hot-update.js": "/js/main.0a8179cde3b86b4f0623.hot-update.js",
"/js/main.84773de15d7781e4d40d.hot-update.js": "/js/main.84773de15d7781e4d40d.hot-update.js"
}

View File

@@ -164,7 +164,7 @@
color: $dark_mode_text_primary;
img {
opacity: .8;
opacity: .95;
}
}
}

View File

@@ -8,6 +8,8 @@
<power-icon v-if="link.icon === 'power'" size="17"></power-icon>
<settings-icon v-if="link.icon === 'settings'" size="17"></settings-icon>
<upload-cloud-icon v-if="link.icon === 'latest'" size="17"></upload-cloud-icon>
<user-icon v-if="link.icon === 'user'" size="17"></user-icon>
<lock-icon v-if="link.icon === 'lock'" size="17"></lock-icon>
</div>
<b class="menu-link">
<span>{{ link.title }}</span>
@@ -26,6 +28,8 @@
Trash2Icon,
PowerIcon,
ShareIcon,
UserIcon,
LockIcon,
} from 'vue-feather-icons'
export default {
@@ -38,6 +42,8 @@
Trash2Icon,
PowerIcon,
ShareIcon,
LockIcon,
UserIcon,
},
props: [
'navigation'

View File

@@ -0,0 +1,34 @@
<template>
<b class="text-label">
<slot></slot>
</b>
</template>
<script>
export default {
name: 'SectionTitle',
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.text-label {
@include font-size(12);
color: #AFAFAF;
font-weight: 700;
display: block;
margin-bottom: 20px;
}
@media only screen and (max-width: 1024px) {
}
@media (prefers-color-scheme: dark) {
.text-label {
color: $theme;
}
}
</style>

View File

@@ -0,0 +1,184 @@
<template>
<article class="detail-storage-item" :class="type">
<div class="header-storage-item">
<div class="icon">
<image-icon v-if="type == 'images'" size="23"></image-icon>
<video-icon v-if="type == 'videos'" size="23"></video-icon>
<file-text-icon v-if="type == 'documents'" size="23"></file-text-icon>
<file-icon v-if="type == 'others'" size="23"></file-icon>
<hard-drive-icon v-if="type == 'disk'" size="23"></hard-drive-icon>
</div>
<div class="title">
<b class="type">{{ title }}</b>
<span class="total-size">{{ used }}</span>
</div>
</div>
<ProgressBar class="storage-progress" :progress="percentage" />
</article>
</template>
<script>
import ProgressBar from '@/components/FilesView/ProgressBar'
import { ImageIcon, VideoIcon, FileTextIcon, FileIcon, HardDriveIcon } from 'vue-feather-icons'
export default {
name: 'StorageItemDetail',
props: ['percentage', 'title', 'type', 'used'],
components: {
HardDriveIcon,
FileTextIcon,
ProgressBar,
VideoIcon,
ImageIcon,
FileIcon,
},
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.detail-storage-item {
margin-bottom: 35px;
&.disk {
.icon {
path, line, polyline, rect, circle, polygon {
stroke: $theme;
}
}
.storage-progress {
/deep/ span {
background: $theme;
}
}
}
&.images {
.icon {
path, line, polyline, rect, circle, polygon {
stroke: $purple;
}
}
.storage-progress {
/deep/ span {
background: $purple;
}
}
}
&.videos {
.icon {
path, line, polyline, rect, circle, polygon {
stroke: $yellow;
}
}
.storage-progress {
/deep/ span {
background: $yellow;
}
}
}
&.documents {
.icon {
path, line, polyline, rect, circle, polygon {
stroke: $red;
}
}
.storage-progress {
/deep/ span {
background: $red;
}
}
}
&.others {
.icon {
path, line, polyline, rect, circle, polygon {
stroke: $text;
}
}
.storage-progress {
/deep/ span {
background: $text;
}
}
}
}
.header-storage-item {
display: flex;
align-items: flex-start;
margin-bottom: 10px;
.icon {
width: 35px;
}
.type {
@include font-size(15);
color: $text;
}
.total-size {
@include font-size(10);
display: block;
color: $text-muted;
}
}
@media (prefers-color-scheme: dark) {
.header-storage-item {
.type {
color: $dark_mode_text_primary;
}
.total-size {
color: $dark_mode_text_secondary;
}
}
.detail-storage-item {
&.others {
.icon {
path, line, polyline, rect, circle, polygon {
stroke: lighten($dark_mode_foreground, 15%);
}
}
.storage-progress {
/deep/ span {
background: lighten($dark_mode_foreground, 15%);
}
}
}
}
}
</style>

View File

@@ -26,7 +26,7 @@
</div>
</router-link>
<router-link :to="{name: 'Profile'}" :class="{'is-active': $isThisRoute($route, ['Password'])}" class="icon-navigation-item settings">
<router-link :to="{name: 'Profile'}" :class="{'is-active': $isThisRoute($route, ['Password', 'Profile', 'Storage'])}" class="icon-navigation-item settings">
<div class="button-icon">
<settings-icon size="19"></settings-icon>
</div>

View File

@@ -10,6 +10,7 @@ import CreateNewPassword from './views/Auth/CreateNewPassword'
import Settings from './views/Settings'
import Profile from './views/User/Profile'
import Storage from './views/User/Storage'
import Trash from './views/FilePages/Trash'
import Files from './views/FilePages/Files'
import Password from './views/User/Password'
@@ -120,6 +121,15 @@ const router = new Router({
title: 'Change Password'
},
},
{
name: 'Storage',
path: '/settings/storage',
component: Storage,
meta: {
requiresAuth: true,
title: 'Storage'
},
},
]
},
{

View File

@@ -25,15 +25,20 @@
return {
navigation: [
{
icon: 'hard-drive',
icon: 'user',
title: 'Profile Settings',
routeName: 'Profile',
},
{
icon: 'latest',
icon: 'lock',
title: 'Password',
routeName: 'Password',
},
{
icon: 'hard-drive',
title: 'Storage',
routeName: 'Storage',
},
]
}
},

View File

@@ -25,14 +25,14 @@
Password
</div>
</router-link>
<!--<router-link :to="{name: 'Profile'}" class="menu-list-item link">
<router-link :to="{name: 'Storage'}" class="menu-list-item link">
<div class="icon">
<hard-drive-icon size="17"></hard-drive-icon>
</div>
<div class="label">
Storage
</div>
</router-link>-->
</router-link>
</div>
</ContentGroup>
</ContentSidebar>
@@ -46,6 +46,7 @@
import ContentGroup from '@/components/Sidebar/ContentGroup'
import UserHeadline from '@/components/Sidebar/UserHeadline'
import {
HardDriveIcon,
UserIcon,
LockIcon,
} from 'vue-feather-icons'
@@ -54,6 +55,7 @@
name: 'Settings',
components: {
ContentSidebar,
HardDriveIcon,
UserHeadline,
ContentGroup,
UserIcon,

View File

@@ -0,0 +1,91 @@
<template>
<div id="user-settings" v-if="app">
<MobileHeader/>
<PageHeader :title="$router.currentRoute.meta.title"/>
<div class="content-page">
<SectionTitle>Storage Capacity</SectionTitle>
<StorageItemDetail type="disk" :title="'Total used ' + storage.used" :percentage="storage.percentage" :used="storage.capacity"/>
<SectionTitle>Capacity Used Details</SectionTitle>
<StorageItemDetail type="images" title="Images" :percentage="storageDetails.images.percentage" :used="storageDetails.images.used" />
<StorageItemDetail type="videos" title="Videos" :percentage="storageDetails.videos.percentage" :used="storageDetails.videos.used" />
<StorageItemDetail type="documents" title="Documents" :percentage="storageDetails.documents.percentage" :used="storageDetails.documents.used" />
<StorageItemDetail type="others" title="Others" :percentage="storageDetails.others.percentage" :used="storageDetails.others.used" />
</div>
</div>
</template>
<script>
import StorageItemDetail from '@/components/Others/StorageItemDetail'
import MobileHeader from '@/components/Mobile/MobileHeader'
import SectionTitle from '@/components/Others/SectionTitle'
import PageHeader from '@/components/Others/PageHeader'
import {mapGetters} from 'vuex'
import axios from 'axios'
export default {
name: 'Profile',
components: {
StorageItemDetail,
SectionTitle,
MobileHeader,
PageHeader,
},
computed: {
...mapGetters(['app']),
},
data() {
return {
storage: undefined,
storageDetails: undefined
}
},
created() {
axios.get('/api/user/storage')
.then(response => {
this.storage = response.data.data.attributes
this.storageDetails = response.data.data.relationships
})
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
#user-settings {
overflow: hidden;
width: 100%;
height: 100%;
position: relative;
.content-page {
overflow-y: auto;
height: 100%;
padding-bottom: 100px;
max-width: 700px;
width: 100%;
margin: 0 auto;
}
}
@media only screen and (max-width: 960px) {
#user-settings {
.content-page {
padding-left: 15px;
padding-right: 15px;
}
}
}
@media (prefers-color-scheme: dark) {
}
</style>

View File

@@ -50,6 +50,7 @@ Route::group(['middleware' => ['auth:api', 'auth.master', 'scope:master']], func
// User
Route::post('/user/password', 'User\AccountController@change_password');
Route::patch('/user/profile', 'User\AccountController@update_profile');
Route::get('/user/storage', 'User\AccountController@storage');
Route::get('/user', 'User\AccountController@user');
// Browse