Merge remote-tracking branch 'origin/master' into ads

# Conflicts:
#	package.json
#	public/9346.js
#	public/chunks/admin.js
#	public/chunks/app-environment.js
#	public/chunks/app-server.js
#	public/chunks/billing.js
#	public/chunks/forgotten-password.js
#	public/chunks/homepage.js
#	public/chunks/plan-create/metered.js
#	public/chunks/plan-settings.js
#	public/chunks/platform.js
#	public/chunks/profile.js
#	public/chunks/recent-uploads.js
#	public/chunks/request.js
#	public/chunks/settings.js
#	public/chunks/shared.js
#	public/chunks/shared/authenticate.js
#	public/chunks/shared/single-file.js
#	public/chunks/sign-in.js
#	public/css/tailwind.css
#	public/js/main.js
#	public/js/main.js.LICENSE.txt
#	public/mix-manifest.json
This commit is contained in:
Čarodej
2022-08-08 08:50:24 +02:00
244 changed files with 6918 additions and 23202 deletions

View File

@@ -35,7 +35,7 @@
{{ data.app.license }}
</ColorLabel>
</a>
<b v-if="data.app.license === 'extended'" class="mr-4 inline-block">
<b class="mr-4 inline-block">
<span class="text-sm font-bold"> {{ $t('subscription') }}: </span>
<ColorLabel color="purple">
{{ config.subscriptionType }}

View File

@@ -114,7 +114,7 @@
{{ $t(row.data.attributes.role) }}
</ColorLabel>
</td>
<td class="px-3 md:px-1" v-if="config.isSaaS">
<td class="px-3 md:px-1" v-if="config.subscriptionType === 'fixed'">
<span class="text-sm font-bold">
{{ row.data.relationships.subscription ? $t('premium') : $t('free') }}
</span>

View File

@@ -11,6 +11,7 @@
@dragover="dragEnter"
@dragleave="dragLeave"
@dragover.prevent
@scroll="infiniteScroll"
tabindex="-1"
@click.self="deselect"
>
@@ -24,21 +25,34 @@
:key="item.data.id"
:item="item"
/>
<!-- Infinite Loader Element -->
<div
v-show="showInfiniteLoadSpinner"
class="relative h-8 md:mt-0 md:mb-4 my-4 col-span-full scale-50"
ref="infinityLoader"
>
<Spinner />
</div>
</div>
</template>
<script>
import { getFilesFromDataTransferItems } from 'datatransfer-files-promise'
import Spinner from '../UI/Others/Spinner'
import ItemHandler from './ItemHandler'
import { events } from '../../bus'
import { mapGetters } from 'vuex'
import { debounce } from 'lodash'
export default {
name: 'FileBrowser',
components: {
ItemHandler,
Spinner
},
computed: {
...mapGetters(['isVisibleSidebar', 'currentFolder', 'itemViewType', 'clipboard', 'entries', 'config']),
...mapGetters(['isVisibleSidebar', 'currentFolder', 'itemViewType', 'clipboard', 'entries', 'config', 'paginate']),
draggedItems() {
// Set opacity for dragged items
if (!this.clipboard.includes(this.draggingId)) {
@@ -49,14 +63,39 @@ export default {
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() {
return {
draggingId: undefined,
isDragging: false,
isLoadingNewEntries: false,
}
},
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() {
if ((this.clipboard.length > 0 && this.$checkPermission('master')) || this.$checkPermission('editor')) {
this.$store.dispatch('deleteItem')
@@ -81,10 +120,21 @@ export default {
// Store dragged folder
this.draggingId = data
// TODO: founded issue on firefox
// TODO: found issue on firefox
},
dragFinish(data, event) {
if (event.dataTransfer.items.length === 0) {
async dragFinish(data, event) {
if (event.dataTransfer.files.length) {
// Check if user dropped folder with files
let files = await getFilesFromDataTransferItems(event.dataTransfer.items)
if (files.length !== 0 && event.dataTransfer.items.length === 0) {
const id = data.data.type !== 'folder' ? this.currentFolder?.data.id : data.data.id
// Upload folder with files
this.$uploadDraggedFolderOrFile(files, id)
}
} else {
// Prevent to drop on file or image
if (data.data.type !== 'folder' || this.draggingId === data) return
@@ -106,13 +156,7 @@ export default {
item: null,
})
}
} else {
// Get id from current folder
const id = data.data.type !== 'folder' ? this.currentFolder?.data.id : data.data.id
// Upload external file
this.$uploadDraggedFiles(event, id)
}
}
this.isDragging = false
},
@@ -131,6 +175,11 @@ export default {
},
},
created() {
// Track document scrolling to load new entries if needed
if (window.innerWidth <= 1024) {
document.addEventListener('scroll', this.infiniteScroll)
}
events.$on('drop', () => {
this.isDragging = false

View File

@@ -115,7 +115,7 @@ export default {
'isDarkMode',
]),
favourites() {
return this.user.data.relationships.favourites.data.attributes.folders
return this.user.data.relationships.favourites.attributes.folders
},
storage() {
return this.$store.getters.user.data.attributes.storage

View File

@@ -132,7 +132,7 @@ export default {
computed: {
...mapGetters(['isVisibleNavigationBars', 'navigation', 'clipboard', 'config', 'user']),
favourites() {
return this.user.data.relationships.favourites.data
return this.user.data.relationships.favourites
},
storage() {
return this.$store.getters.user.data.attributes.storage

View File

@@ -3,6 +3,12 @@
class="absolute bottom-0 top-0 left-0 right-0 z-10 mx-auto overflow-y-auto rounded-xl md:p-5"
:style="{ width: documentSize + '%' }"
>
<div
v-if="isLoading"
class="mx-auto fixed left-0 right-0 top-1/2 translate-y-5 w-full z-10"
>
<Spinner />
</div>
<pdf
:src="pdfData"
v-for="i in numPages"
@@ -12,39 +18,43 @@
scale="page-width"
id="printable-file"
class="mx-auto mb-6 w-full overflow-hidden md:rounded-xl md:shadow-lg"
>
<template slot="loading">
<b>
{{ $t('loading_content') }}
</b>
</template>
</pdf>
@loading="documentLoaded"
/>
</div>
</template>
<script>
import Spinner from "../../UI/Others/Spinner"
import { events } from '../../../bus'
import pdf from 'pdfvuer'
export default {
name: 'PdfFile',
components: {
Spinner,
pdf,
},
props: ['file'],
props: [
'file'
],
watch: {
file() {
this.getPdf()
this.isLoading = true
},
},
data() {
return {
pdfData: undefined,
documentSize: 50,
isLoading: true,
numPages: 0,
}
},
methods: {
documentLoaded() {
this.isLoading = false
},
getPdf() {
this.pdfData = undefined
this.numPages = 0

View File

@@ -11,7 +11,7 @@
<span v-if="description" class="block text-xs leading-4 dark:text-gray-500 text-gray-500" v-html="description"></span>
<!--Input Description-->
<span v-if="error" class="error-message">
<span v-if="error" class="text-left text-xs text-red-600">
{{ error }}
</span>
</div>

View File

@@ -1,5 +1,5 @@
<template>
<div v-if="isVisible" class="w-full max-w-xl text-center">
<div v-if="isVisible" class="w-full max-w-xl text-center m-auto py-6">
<slot />
</div>
</template>

View File

@@ -1,5 +1,5 @@
<template>
<div class="flex items-center justify-center px-2.5 md:px-6">
<div class="flex px-2.5 md:px-6">
<slot />
</div>
</template>

View File

@@ -1,5 +1,5 @@
<template>
<div @click="goBack" class="relative flex select-none items-center text-left">
<div @click="goBack" class="relative flex select-none items-center text-left min-w-0 lg:pr-6 pr-12">
<!--Menu icon-->
<div
v-if="!isVisibleNavigationBars"
@@ -15,13 +15,13 @@
'-translate-x-3 opacity-0': !isLoadedFolder || !isNotHomepage,
'translate-x-0 opacity-100': isLoadedFolder && isNotHomepage,
}"
class="mr-2 -ml-1 cursor-pointer align-middle transition-all duration-200 lg:-mt-0.5"
class="mr-2 -ml-1 cursor-pointer align-middle transition-all duration-200 lg:-mt-0.5 shrink-0"
/>
<!--Folder Title-->
<b
:class="{ '-translate-x-4': !isLoadedFolder || !isNotHomepage }"
class="inline-block lg:max-w-[210px] max-w-[190px] transform overflow-hidden text-ellipsis whitespace-nowrap align-middle text-sm font-bold transition-all duration-200 dark:text-gray-100"
class="inline-block min-w-0 transform overflow-hidden text-ellipsis whitespace-nowrap align-middle text-sm font-bold transition-all duration-200 dark:text-gray-100"
>
{{ $getCurrentLocationName() }}
</b>

View File

@@ -88,6 +88,8 @@ export default {
})
)
this.$store.commit('START_LOADING_VIEW')
// Update sorting state in vuex
this.$store.commit('UPDATE_SORTING')
@@ -97,7 +99,7 @@ export default {
// Get data of Navigator tree
this.$store.dispatch('getFolderTree')
this.$getDataByLocation()
this.$getDataByLocation(1)
},
changePreview(previewType) {
this.$store.dispatch('togglePreviewType', previewType)

View File

@@ -204,7 +204,7 @@ export default {
goToFiles() {
if (this.$route.name !== 'Files') this.$router.push({ name: 'Files' })
this.$store.dispatch('getFolder')
this.$store.dispatch('getFolder', {page: 1})
},
logOut() {
this.$store.dispatch('logOut')

View File

@@ -19,7 +19,7 @@
class="vue-feather text-theme shrink-0"
/>
<alert-triangle-icon
v-if="['billing-alert', 'insufficient-balance'].includes(notification.data.attributes.category)"
v-if="['billing-alert', 'insufficient-balance', 'payment-alert'].includes(notification.data.attributes.category)"
size="22"
class="vue-feather text-theme shrink-0"
/>

View File

@@ -8,7 +8,8 @@
<div class="fixed top-0 bottom-0 left-0 right-0 z-10 m-auto w-full bg-white shadow-xl dark:bg-dark-foreground md:relative md:w-[490px] md:rounded-xl">
<div class="flex h-full -translate-y-7 transform items-center justify-center px-8 text-center md:translate-y-0">
<div>
<img src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f627.svg" alt="" class="mx-auto mb-4 w-20 md:mt-6 min-h-[80px]" />
<img v-if="isSuccess" src="https://twemoji.maxcdn.com/v/13.1.1/svg/1f609.svg" alt="" class="mx-auto mb-4 w-20 md:mt-6 min-h-[80px]" />
<img v-if="isAlert" src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f627.svg" alt="" class="mx-auto mb-4 w-20 md:mt-6 min-h-[80px]" />
<h1 v-if="title" class="mb-2 text-2xl font-bold">
{{ title }}
@@ -46,7 +47,8 @@ export default {
message: undefined,
title: undefined,
button: undefined,
emoji: undefined,
isSuccess: undefined,
isAlert: undefined,
}
},
methods: {
@@ -58,18 +60,14 @@ export default {
// Show alert
events.$on('alert:open', (args) => {
this.isVisibleWrapper = true
this.isAlert = true
this.title = args.title || undefined
this.message = args.message || undefined
this.button = this.$te('alerts.error_confirm') ? this.$t('alerts.error_confirm') : 'Thats horrible!'
this.emoji = '😢😢😢'
this.buttonStyle = 'danger'
if (args.emoji) {
this.emoji = args.emoji
}
if (args.buttonStyle) {
this.buttonStyle = args.buttonStyle
}
@@ -82,22 +80,20 @@ export default {
// Show alert
events.$on('success:open', (args) => {
this.isVisibleWrapper = true
this.isSuccess = true
this.title = args.title
this.message = args.message
this.button = this.$t('alerts.success_confirm')
this.emoji = '🥳🥳🥳'
this.buttonStyle = 'theme'
if (args.emoji) {
this.emoji = args.emoji
}
})
// Close popup
events.$on('popup:close', () => {
this.isVisibleWrapper = false
this.isSuccess = undefined
this.isAlert = undefined
})
},
}

View File

@@ -213,6 +213,7 @@ export default {
isExpiration: false,
isEmailSharing: false,
shareOptions: {
id: undefined,
isPassword: undefined,
expiration: undefined,
password: undefined,
@@ -244,7 +245,7 @@ export default {
// Send request to get share link
axios
.post(`/api/share/${this.id}`, this.shareOptions)
.post('/api/share', this.shareOptions)
.then((response) => {
// End loading
this.isGeneratedShared = true
@@ -278,18 +279,18 @@ export default {
this.pickedItem = args.item
this.shareOptions.type = args.item.data.type
this.id = args.item.data.id
this.shareOptions.id = args.item.data.id
})
// Close popup
events.$on('popup:close', () => {
// Restore data
setTimeout(() => {
this.id = undefined
this.isGeneratedShared = false
this.isExpiration = false
this.isEmailSharing = false
this.shareOptions = {
id: undefined,
isPassword: false,
expiration: undefined,
password: undefined,

View File

@@ -121,8 +121,10 @@ export default {
.then(() => {
// If broadcasting is not set
if (!this.$store.getters.isBroadcasting) {
this.$store.commit('START_LOADING_VIEW')
// Reload data
this.$getDataByLocation()
this.$getDataByLocation(1)
events.$emit('toaster', {
type: 'success',

View File

@@ -1,5 +1,6 @@
<template>
<div
id="spotlight"
v-if="isVisible"
@keyup.esc="exitSpotlight"
@click.exact.self="exitSpotlight"
@@ -898,18 +899,7 @@ export default {
params: { query: value },
})
.then((response) => {
// Show user result
if (this.activeFilter === 'users') {
this.results = response.data.data
}
// Show file result
if (!this.activeFilter) {
let files = response.data.files.data
let folders = response.data.folders.data
this.results = folders.concat(files)
}
this.results = response.data.data
})
.catch(() => this.$isSomethingWrong())
.finally(() => (this.isLoading = false))
@@ -970,3 +960,9 @@ export default {
},
}
</script>
<style lang="scss">
#spotlight .item-name {
padding-right: 35px;
}
</style>

View File

@@ -139,17 +139,13 @@ export default {
planCode: this.selectedPlan.data.meta.driver_plan_id.stripe,
})
.then((response) => {
window.location = response.data.data.url
window.location = response.data.url
})
.catch((error) => {
if (error.response.status === 500 && error.response.data.type) {
events.$emit('alert:open', {
title: error.response.data.title,
message: error.response.data.message,
})
} else {
this.$isSomethingWrong()
}
events.$emit('alert:open', {
title: error.response.data.title || this.$t('popup_error.title'),
message: error.response.data.message || this.$t('popup_error.message'),
})
})
}

View File

@@ -15,7 +15,7 @@
}"
>
<PaymentMethod
@click.native="payByPayPal"
@click.native.once="payByPayPal"
driver="paypal"
:description="config.paypal_payment_description"
>

View File

@@ -31,7 +31,7 @@
}"
>
<PaymentMethod
@click.native="payByPayPal"
@click.native.once="payByPayPal"
driver="paypal"
:description="$t(config.paypal_payment_description)"
>
@@ -256,23 +256,16 @@ export default {
planCode: this.selectedPlan.data.meta.driver_plan_id.stripe,
})
.then((response) => {
window.location = response.data.data.url
window.location = response.data.url
})
.catch((error) => {
this.$closePopup()
setTimeout(() => {
if (error.response.status === 500 && error.response.data.type) {
events.$emit('alert:open', {
title: error.response.data.title,
message: error.response.data.message,
})
} else {
events.$emit('alert:open', {
title: this.$t('popup_error.title'),
message: this.$t('popup_error.message'),
})
}
events.$emit('alert:open', {
title: error.response.data.title || this.$t('popup_error.title'),
message: error.response.data.message || this.$t('popup_error.message'),
})
}, 100)
})
.finally(() => {

View File

@@ -1,7 +1,7 @@
<template>
<div v-if="$store.getters.isLimitedUser" class="bg-red-500 py-1 text-center">
<div v-if="$store.getters.userLimitationReason" class="bg-gradient-to-r from-red-600 to-red-500 py-2.5 px-1 text-center leading-none">
<router-link :to="{ name: 'Billing' }" class="text-xs font-bold text-white">
{{ $t('restricted_account_warning') }}
{{ $t('restricted_account_warning') + ' ' + $store.getters.userLimitationReason }}
</router-link>
</div>
</template>

View File

@@ -58,7 +58,7 @@
<!--Member list-->
<ValidationProvider tag="div" mode="passive" name="Members" rules="required" v-slot="{ errors }">
<AppInputText :title="$t('your_members')" :error="errors[0]" :is-last="true">
<span v-if="errors[0]" class="error-message" style="margin-top: -5px">
<span v-if="errors[0]" class="text-left text-xs text-red-600" style="margin-top: -5px">
{{ $t('add_at_least_one_member') }}
</span>
@@ -179,7 +179,7 @@ export default {
// Add created team folder into Team Folder homepage view
} else if (isTeamFoldersLocation && !this.$route.params.id) {
this.$store.commit('ADD_NEW_FOLDER', response.data)
this.$store.commit('ADD_NEW_ITEM', response.data)
// Redirect to Team Folders after converting simple folder
} else if (!isTeamFoldersLocation) {

View File

@@ -39,7 +39,7 @@
<!--Member list-->
<ValidationProvider tag="div" mode="passive" name="Members" v-slot="{ errors }">
<label class="input-label">{{ $t('your_members') }}:</label>
<span v-if="errors[0]" class="error-message" style="margin-top: -5px">{{
<span v-if="errors[0]" class="text-left text-xs text-red-600" style="margin-top: -5px">{{
$t('add_at_least_one_member')
}}</span>
<TeamList v-model="members" />

View File

@@ -179,13 +179,13 @@ export default {
isFolder() {
return this.entry.data.type === 'folder'
},
timeStamp() {
return this.entry.data.attributes.deleted_at
? this.$t('entry_thumbnail.deleted_at', {
time: this.entry.data.attributes.deleted_at,
})
: this.entry.data.attributes.created_at
},
timeStamp() {
return this.entry.data.attributes.deleted_at
? this.$t('item_thumbnail.deleted_at', {
time: this.entry.data.attributes.deleted_at,
})
: this.entry.data.attributes.created_at
},
canEditName() {
return (
!this.$isMobile() &&

View File

@@ -51,12 +51,14 @@
</div>
<!--Item Info-->
<div class="pl-2">
<div class="pl-2 min-w-0">
<!--Item Title-->
<span
class="mb-0.5 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold"
:class="{ 'hover:underline cursor-text': canEditName }"
style="max-width: 240px"
class="item-name mb-0.5 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold lg:pr-0 pr-4"
:class="{
'hover:underline cursor-text': canEditName,
'lg:!pr-16': mobileHandler && $isMobile(),
}"
ref="name"
@input="renameItem"
@keydown.delete.stop
@@ -125,7 +127,11 @@ export default {
EyeIcon,
Emoji,
},
props: ['mobileHandler', 'highlight', 'entry'],
props: [
'mobileHandler',
'highlight',
'entry',
],
watch: {
isChecked: function (val) {
if (val) {

View File

@@ -1,7 +1,7 @@
<template>
<div class="flex select-none items-center rounded-xl" spellcheck="false">
<!--Item thumbnail-->
<div class="relative w-16">
<div class="relative w-16 shrink-0">
<!--Member thumbnail for team folders-->
<MemberAvatar
v-if="user && canShowAuthor"
@@ -39,12 +39,9 @@
</div>
<!--Item Info-->
<div class="pl-2">
<div class="pl-2 min-w-0">
<!--Item Title-->
<b
class="mb-0.5 block overflow-hidden text-ellipsis whitespace-nowrap text-sm hover:underline"
style="max-width: 240px"
>
<b class="mb-0.5 block overflow-hidden text-ellipsis whitespace-nowrap text-sm hover:underline">
{{ item.data.attributes.name }}
</b>

View File

@@ -8,7 +8,7 @@
<file-icon v-if="icon === 'file'" class="text-theme vue-feather" size="19" />
</div>
<div>
<b class="block w-52 overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold 2xl:w-72">
<b class="block overflow-hidden text-ellipsis text-sm font-bold">
{{ title }}
</b>
<small class="block text-xs font-bold text-gray-400">

View File

@@ -1,6 +1,6 @@
<template>
<div
class="mb-6 flex cursor-pointer items-center rounded-xl p-5 shadow-card"
class="mb-6 flex items-center rounded-xl p-5 shadow-card"
:class="{
'dark:bg-green-700/30 bg-green-200': color === 'green',
'dark:bg-rose-700/30 bg-rose-200': color === 'rose',
@@ -25,7 +25,7 @@
}"
/>
<p
class="text-sm text-green-700 dark:text-green-500"
class="text-sm"
:class="{
'text-green-700 dark:text-green-500': color === 'green',
'text-rose-700 dark:text-rose-500': color === 'rose',

View File

@@ -28,7 +28,9 @@
background: member.data.attributes.color ? member.data.attributes.color : '',
}"
>
<span :class="fontSize" class="font-extrabold uppercase text-white">
<span class="font-extrabold uppercase text-white dark:text-gray-900"
:class="[fontSize, {'!text-gray-900': !member.data.attributes.color}]"
>
{{ letter }}
</span>
</div>

View File

@@ -10,7 +10,7 @@
<!--Form to set upload request-->
<ValidationObserver
v-if="!generatedUploadRequest"
v-if="!uploadRequest"
@submit.prevent="createUploadRequest"
ref="createForm"
v-slot="{ invalid }"
@@ -82,13 +82,13 @@
</ValidationObserver>
<!--Copy generated link-->
<AppInputText v-if="generatedUploadRequest" :title="$t('copy_upload_request_link')" :is-last="true">
<CopyInput :str="generatedUploadRequest.data.attributes.url" />
<AppInputText v-if="uploadRequest" :title="$t('copy_upload_request_link')" :is-last="true">
<CopyInput :str="uploadRequestURL" />
</AppInputText>
</PopupContent>
<!--Actions-->
<PopupActions v-if="!generatedUploadRequest">
<PopupActions v-if="!uploadRequest">
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="secondary"
>{{ $t('cancel') }}
</ButtonBase>
@@ -98,7 +98,7 @@
</PopupActions>
<!--Actions-->
<PopupActions v-if="generatedUploadRequest">
<PopupActions v-if="uploadRequest">
<ButtonBase class="w-full" @click.native="$closePopup()" button-style="theme"
>{{ $t('awesome_iam_done') }}
</ButtonBase>
@@ -147,7 +147,8 @@ export default {
folder_id: undefined,
name: undefined,
},
generatedUploadRequest: undefined,
uploadRequest: undefined,
uploadRequestURL: undefined,
shareViaEmail: false,
pickedItem: undefined,
isLoading: false,
@@ -166,7 +167,10 @@ export default {
axios
.post(`/api/file-request`, this.form)
.then((response) => {
this.generatedUploadRequest = response.data
this.uploadRequest = response.data
// Format upload request url
this.uploadRequestURL = `${this.$store.getters.config.host}/request/${response.data.data.id}/upload`
})
.catch(() => {
events.$emit('alert:open', {
@@ -192,7 +196,7 @@ export default {
// Restore data
setTimeout(() => {
this.generatedUploadRequest = undefined
this.uploadRequest = undefined
this.pickedItem = undefined
this.shareViaEmail = false

View File

@@ -178,46 +178,41 @@ const FunctionHelpers = {
return
}
if (files.length === 0) return
if (files.length === 0) {
return
}
if (!this.$checkFileMimetype(files) || !this.$checkUploadLimit(files)) return // Push items to file queue
;[...files].map((item) => {
store.commit('ADD_FILES_TO_QUEUE', {
if (!this.$checkFileMimetype(files) || !this.$checkUploadLimit(files)) {
return
}
// Push items to file queue
[...files].map((item) => {
store.dispatch('pushFileToTheUploadQueue', {
parent_id: store.getters.currentFolder ? store.getters.currentFolder.data.id : '',
file: item,
path: '/' + item.webkitRelativePath,
})
})
// Start uploading if uploading process isn't running
if (store.getters.filesInQueueTotal === 0) this.$handleUploading(store.getters.fileQueue[0])
// Increase total files in upload bar
store.commit('INCREASE_FILES_IN_QUEUES_TOTAL', files.length)
}
Vue.prototype.$uploadDraggedFiles = async function (event, parent_id) {
// Show alert message when upload is disabled
if (store.getters.user && !store.getters.user.data.meta.restrictions.canUpload) {
Vue.prototype.$temporarilyDisabledUpload()
Vue.prototype.$uploadDraggedFolderOrFile = async function (files, parent_id) {
files.map((file) => {
// Get file path
let filePath = file.filepath ? '/' + file.filepath : undefined
return
}
// Determine if we are uploading folder or file
if (filePath.split('/').length > 2) {
store.commit('UPDATE_UPLOADING_FOLDER_STATE', true)
}
// Prevent submit empty files
if (event.dataTransfer.items.length === 0) return // Push items to file queue
;[...event.dataTransfer.items].map((item) => {
store.commit('ADD_FILES_TO_QUEUE', {
parent_id: parent_id ? parent_id : '',
file: item.getAsFile(),
// Push file to the upload queue
store.dispatch('pushFileToTheUploadQueue', {
parent_id: parent_id || '',
path: filePath,
file: file,
})
})
// Start uploading if uploading process isn't running
if (store.getters.filesInQueueTotal == 0) this.$handleUploading(store.getters.fileQueue[0])
// Increase total files in upload bar
store.commit('INCREASE_FILES_IN_QUEUES_TOTAL', [...event.dataTransfer.items].length)
}
Vue.prototype.$handleUploading = async function (item) {
@@ -350,19 +345,19 @@ const FunctionHelpers = {
}[this.$router.currentRoute.name]
}
Vue.prototype.$getDataByLocation = function () {
Vue.prototype.$getDataByLocation = async function (page) {
let routes = {
RequestUpload: ['getUploadRequestFolder', router.currentRoute.params.id || undefined ],
Public: ['getSharedFolder', router.currentRoute.params.id || undefined],
Files: ['getFolder', router.currentRoute.params.id || undefined],
RecentUploads: ['getRecentUploads'],
MySharedItems: ['getMySharedItems'],
Trash: ['getTrash', router.currentRoute.params.id || undefined],
TeamFolders: ['getTeamFolder', router.currentRoute.params.id || undefined],
SharedWithMe: ['getSharedWithMeFolder', router.currentRoute.params.id || undefined],
RequestUpload: ['getUploadRequestFolder', {page: page, id: router.currentRoute.params.id || undefined}],
Public: ['getSharedFolder', {page: page, id: router.currentRoute.params.id || undefined}],
Files: ['getFolder', {page: page, id: router.currentRoute.params.id || undefined}],
RecentUploads: ['getRecentUploads', page],
MySharedItems: ['getMySharedItems', page],
Trash: ['getTrash', {page: page, id: router.currentRoute.params.id || undefined}],
TeamFolders: ['getTeamFolder', {page: page, id: router.currentRoute.params.id || undefined}],
SharedWithMe: ['getSharedWithMeFolder', {page: page, id: router.currentRoute.params.id || undefined}],
}
store.dispatch(...routes[router.currentRoute.name])
return await store.dispatch(...routes[router.currentRoute.name])
}
Vue.prototype.$getPaymentLogo = function (driver) {

View File

@@ -17,7 +17,7 @@ const itemHelpers = {
}
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
if (favourites && !favourites.find((el) => el.data.id === entry.data.id)) {

View File

@@ -6,99 +6,113 @@ import i18n from '../../i18n'
const defaultState = {
currentFolder: undefined,
isMultiSelectMode: false,
fastPreview: undefined,
navigation: undefined,
isMultiSelectMode: false,
paginate: undefined,
isLoading: true,
clipboard: [],
entries: [],
}
const actions = {
getFolder: ({ commit, getters }, id) => {
commit('LOADING_STATE', { loading: true, data: [] })
getFolder: ({ commit, getters },{page, id}) => {
return new Promise ((resolve, reject) => {
if(page === 1)
commit('START_LOADING_VIEW')
axios
.get(`${getters.api}/browse/folders/${id || 'all'}${getters.sorting.URI}`)
.then((response) => {
let folders = response.data.folders.data
let files = response.data.files.data
axios
.get(`${getters.api}/browse/folders/${id || 'all'}${getters.sorting.URI}&page=${page}`)
.then((response) => {
commit('SET_CURRENT_FOLDER', response.data.meta.root)
commit('SET_PAGINATOR', response.data.meta.paginate)
commit('STOP_LOADING_VIEW')
commit('ADD_NEW_ITEMS', response.data.data)
commit('LOADING_STATE', {
loading: false,
data: folders.concat(files),
events.$emit('scrollTop')
resolve(response);
})
commit('SET_CURRENT_FOLDER', response.data.root)
.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'),
})
}
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'),
})
}
})
reject(error);
})
})
},
getRecentUploads: ({ commit, getters }) => {
commit('LOADING_STATE', { loading: true, data: [] })
getRecentUploads: ({commit, getters}, page) => {
return new Promise((resolve, reject) => {
if (page === 1)
commit('START_LOADING_VIEW')
axios
.get(getters.api + '/browse/latest')
.then((response) => {
commit('LOADING_STATE', {
loading: false,
data: response.data.files.data,
axios
.get(`${getters.api}/browse/latest?page=${page}`)
.then((response) => {
commit('SET_PAGINATOR', response.data.meta.paginate)
commit('SET_CURRENT_FOLDER', undefined)
commit('STOP_LOADING_VIEW')
commit('ADD_NEW_ITEMS', response.data.data)
events.$emit('scrollTop')
resolve(response)
})
commit('SET_CURRENT_FOLDER', undefined)
events.$emit('scrollTop')
})
.catch(() => Vue.prototype.$isSomethingWrong())
.catch(() => Vue.prototype.$isSomethingWrong())
})
},
getMySharedItems: ({ commit, getters }) => {
commit('LOADING_STATE', { loading: true, data: [] })
getMySharedItems: ({ commit, getters }, page) => {
return new Promise((resolve, reject) => {
if (page === 1)
commit('START_LOADING_VIEW')
axios
.get(getters.api + '/browse/share' + getters.sorting.URI)
.then((response) => {
let folders = response.data.folders.data
let files = response.data.files.data
axios
.get(`${getters.api}/browse/share${getters.sorting.URI}&page=${page}`)
.then((response) => {
commit('SET_PAGINATOR', response.data.meta.paginate)
commit('SET_CURRENT_FOLDER', undefined)
commit('STOP_LOADING_VIEW')
commit('ADD_NEW_ITEMS', response.data.data)
commit('LOADING_STATE', {
loading: false,
data: folders.concat(files),
events.$emit('scrollTop')
resolve(response)
})
commit('SET_CURRENT_FOLDER', undefined)
events.$emit('scrollTop')
})
.catch(() => Vue.prototype.$isSomethingWrong())
.catch(() => Vue.prototype.$isSomethingWrong())
})
},
getTrash: ({ commit, getters }, id) => {
commit('LOADING_STATE', { loading: true, data: [] })
getTrash: ({ commit, getters }, {page, id}) => {
return new Promise((resolve, reject) => {
if (page === 1)
commit('START_LOADING_VIEW')
axios
.get(`${getters.api}/browse/trash/${id || 'all'}${getters.sorting.URI}`)
.then((response) => {
let folders = response.data.folders.data
let files = response.data.files.data
axios
.get(`${getters.api}/browse/trash/${id || 'all'}${getters.sorting.URI}&page=${page}`)
.then((response) => {
commit('SET_PAGINATOR', response.data.meta.paginate)
commit('SET_CURRENT_FOLDER', response.data.meta.root)
commit('STOP_LOADING_VIEW')
commit('ADD_NEW_ITEMS', response.data.data)
commit('LOADING_STATE', {
loading: false,
data: folders.concat(files),
events.$emit('scrollTop')
resolve(response)
})
commit('SET_CURRENT_FOLDER', response.data.root)
.catch((error) => {
Vue.prototype.$isSomethingWrong()
events.$emit('scrollTop')
})
.catch(() => Vue.prototype.$isSomethingWrong())
reject(error);
})
})
},
getFolderTree: ({ commit, getters }) => {
return new Promise((resolve, reject) => {
@@ -125,9 +139,15 @@ const actions = {
}
const mutations = {
LOADING_STATE(state, payload) {
state.entries = payload.data
state.isLoading = payload.loading
SET_PAGINATOR(state, payload) {
state.paginate = payload
},
START_LOADING_VIEW(state) {
state.entries = []
state.isLoading = true
},
STOP_LOADING_VIEW(state) {
state.isLoading = false
},
SET_CURRENT_FOLDER(state, folder) {
state.currentFolder = folder
@@ -164,7 +184,7 @@ const mutations = {
if (item.data.id === data.data.id) item.data = data.data
})
},
ADD_NEW_FOLDER(state, folder) {
ADD_NEW_ITEM(state, folder) {
state.entries.unshift(folder)
},
ADD_NEW_ITEMS(state, items) {
@@ -220,6 +240,7 @@ const getters = {
navigation: (state) => state.navigation,
clipboard: (state) => state.clipboard,
isLoading: (state) => state.isLoading,
paginate: (state) => state.paginate,
entries: (state) => state.entries,
}

View File

@@ -98,7 +98,7 @@ const actions = {
parent_id: getters.currentFolder?.data.id,
})
.then((response) => {
commit('ADD_NEW_FOLDER', response.data)
commit('ADD_NEW_ITEM', response.data)
events.$emit('scrollTop')
@@ -196,7 +196,7 @@ const actions = {
response.data.data.attributes.parent_id === getters.currentFolder.data.id)
) {
// Add uploaded item into view
commit('ADD_NEW_ITEMS', response.data)
commit('ADD_NEW_ITEM', response.data)
}
// Reset file progress
@@ -216,8 +216,10 @@ const actions = {
// Reload File data after folder uploading is finished
if (getters.isUploadingFolder) {
// Reload files after upload is done
Vue.prototype.$getDataByLocation()
commit('START_LOADING_VIEW')
// Reload files after folder upload is done
Vue.prototype.$getDataByLocation(1)
// Reload folder tree
dispatch('getFolderTree')
@@ -342,14 +344,14 @@ const actions = {
},
emptyTrash: ({ commit, getters }) => {
// Clear file browser
commit('LOADING_STATE', { loading: true, data: [] })
commit('START_LOADING_VIEW')
axios
.post(getters.api + '/trash/dump', {
_method: 'delete',
})
.then(() => {
commit('LOADING_STATE', { loading: false, data: [] })
commit('STOP_LOADING_VIEW')
events.$emit('scrollTop')
commit('CLIPBOARD_CLEAR')
@@ -363,7 +365,7 @@ const actions = {
})
.then(() => {
if (router.currentRoute.name === 'Trash') {
commit('LOADING_STATE', { loading: false, data: [] })
commit('STOP_LOADING_VIEW')
}
events.$emit('toaster', {
@@ -373,6 +375,28 @@ const actions = {
})
.catch(() => Vue.prototype.$isSomethingWrong())
},
pushFileToTheUploadQueue: ({commit, getters}, item) => {
// Prevent to upload file with 0kb file size
if (item.file.size === 0) {
events.$emit('toaster', {
type: 'danger',
message: `The file ${item.file.name} can't be uploaded`,
})
}
if (item.file.size !== 0 && item.file.name !== '.DS_Store') {
// commit file to the upload queue
commit('ADD_FILES_TO_QUEUE', item)
// Start uploading if uploading process isn't running
if (getters.filesInQueueTotal === 0) {
Vue.prototype.$handleUploading(getters.fileQueue[0])
}
// Increase total files in upload bar
commit('INCREASE_FILES_IN_QUEUES_TOTAL')
}
}
}
const mutations = {
@@ -394,8 +418,8 @@ const mutations = {
UPLOADING_FILE_PROGRESS(state, percentage) {
state.uploadingProgress = percentage
},
INCREASE_FILES_IN_QUEUES_TOTAL(state, count) {
state.filesInQueueTotal += count
INCREASE_FILES_IN_QUEUES_TOTAL(state) {
state.filesInQueueTotal += 1
},
INCREASE_FILES_IN_QUEUE_UPLOADED(state) {
state.filesInQueueUploaded++

View File

@@ -20,21 +20,19 @@ const defaultState = {
sharedFile: undefined,
}
const actions = {
getSharedFolder: ({ commit, getters }, id) => {
commit('LOADING_STATE', { loading: true, data: [] })
getSharedFolder: ({ commit, getters }, {page, id}) => {
return new Promise((resolve, reject) => {
axios
.get(`/api/sharing/folders/${id}/${router.currentRoute.params.token}${getters.sorting.URI}`)
.then((response) => {
let folders = response.data.folders.data
let files = response.data.files.data
commit('LOADING_STATE', {
loading: false,
data: folders.concat(files),
})
commit('SET_CURRENT_FOLDER', response.data.root)
if(page === 1)
commit('START_LOADING_VIEW')
axios
.get(`/api/sharing/folders/${id}/${router.currentRoute.params.token}${getters.sorting.URI}&page=${page}`)
.then((response) => {
commit('SET_CURRENT_FOLDER', response.data.meta.root)
commit('SET_PAGINATOR', response.data.meta.paginate)
commit('STOP_LOADING_VIEW')
commit('ADD_NEW_ITEMS', response.data.data)
events.$emit('scrollTop')

View File

@@ -1,129 +1,134 @@
import router from '../../router'
import { events } from '../../bus'
import {events} from '../../bus'
import i18n from '../../i18n'
import axios from 'axios'
import Vue from 'vue'
const defaultState = {
currentTeamFolder: undefined,
currentTeamFolder: undefined,
}
const actions = {
getTeamFolder: ({ commit, getters }, id) => {
commit('LOADING_STATE', { loading: true, data: [] })
getTeamFolder: ({commit, getters}, {page, id}) => {
return new Promise((resolve, reject) => {
if (page === 1)
commit('START_LOADING_VIEW')
if (typeof id === 'undefined') {
commit('SET_CURRENT_TEAM_FOLDER', null)
}
if (typeof id === 'undefined')
commit('SET_CURRENT_TEAM_FOLDER', null)
axios
.get(`${getters.api}/teams/folders/${id || 'all'}${getters.sorting.URI}`)
.then((response) => {
let folders = response.data.folders.data
let files = response.data.files.data
axios
.get(`${getters.api}/teams/folders/${id || 'all'}${getters.sorting.URI}&page=${page}`)
.then((response) => {
commit('SET_CURRENT_FOLDER', response.data.meta.root)
commit('SET_PAGINATOR', response.data.meta.paginate)
commit('STOP_LOADING_VIEW')
commit('ADD_NEW_ITEMS', response.data.data)
commit('LOADING_STATE', {
loading: false,
data: folders.concat(files),
})
commit('SET_CURRENT_FOLDER', response.data.root)
if (
!getters.currentTeamFolder ||
getters.currentTeamFolder.data.id !== response.data.meta.teamFolder.data.id
) {
commit('SET_CURRENT_TEAM_FOLDER', response.data.meta.teamFolder)
}
if (
!getters.currentTeamFolder ||
getters.currentTeamFolder.data.id !== response.data.teamFolder.data.id
) {
commit('SET_CURRENT_TEAM_FOLDER', response.data.teamFolder)
}
events.$emit('scrollTop')
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'),
})
}
})
},
getSharedWithMeFolder: ({ commit, getters }, id) => {
commit('LOADING_STATE', { loading: true, data: [] })
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'),
})
}
if (typeof id === 'undefined') {
commit('SET_CURRENT_TEAM_FOLDER', null)
}
reject(error)
})
})
},
getSharedWithMeFolder: ({commit, getters}, {page, id}) => {
return new Promise((resolve, reject) => {
if (page === 1)
commit('START_LOADING_VIEW')
axios
.get(`${getters.api}/teams/shared-with-me/${id || 'all'}${getters.sorting.URI}`)
.then((response) => {
let folders = response.data.folders.data
let files = response.data.files.data
if (typeof id === 'undefined') {
commit('SET_CURRENT_TEAM_FOLDER', null)
}
commit('LOADING_STATE', {
loading: false,
data: folders.concat(files),
})
commit('SET_CURRENT_FOLDER', response.data.root)
axios
.get(`${getters.api}/teams/shared-with-me/${id || 'all'}${getters.sorting.URI}&page=${page}`)
.then((response) => {
commit('SET_CURRENT_FOLDER', response.data.meta.root)
commit('SET_PAGINATOR', response.data.meta.paginate)
commit('STOP_LOADING_VIEW')
commit('ADD_NEW_ITEMS', response.data.data)
if (
!getters.currentTeamFolder ||
getters.currentTeamFolder.data.id !== response.data.teamFolder.data.id
) {
commit('SET_CURRENT_TEAM_FOLDER', response.data.teamFolder)
}
if (
!getters.currentTeamFolder ||
getters.currentTeamFolder.data.id !== response.data.meta.teamFolder.data.id
) {
commit('SET_CURRENT_TEAM_FOLDER', response.data.meta.teamFolder)
}
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'),
})
}
})
},
getTeamFolderTree: ({ commit, getters }) => {
return new Promise((resolve, reject) => {
axios
.get(`/api/teams/folders/${getters.currentTeamFolder.data.id}/tree${getters.sorting.URI}`)
.then((response) => {
resolve(response)
events.$emit('scrollTop')
commit('UPDATE_FOLDER_TREE', response.data)
})
.catch((error) => {
reject(error)
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'),
})
}
Vue.prototype.$isSomethingWrong()
})
})
},
reject(error)
})
})
},
getTeamFolderTree: ({commit, getters}) => {
return new Promise((resolve, reject) => {
axios
.get(`/api/teams/folders/${getters.currentTeamFolder.data.id}/tree${getters.sorting.URI}`)
.then((response) => {
resolve(response)
commit('UPDATE_FOLDER_TREE', response.data)
})
.catch((error) => {
reject(error)
Vue.prototype.$isSomethingWrong()
})
})
},
}
const mutations = {
SET_CURRENT_TEAM_FOLDER(state, payload) {
state.currentTeamFolder = payload
},
SET_CURRENT_TEAM_FOLDER(state, payload) {
state.currentTeamFolder = payload
},
}
const getters = {
currentTeamFolder: (state) => state.currentTeamFolder,
currentTeamFolder: (state) => state.currentTeamFolder,
}
export default {
state: defaultState,
getters,
actions,
mutations,
state: defaultState,
getters,
actions,
mutations,
}

View File

@@ -9,20 +9,16 @@ const defaultState = {
const actions = {
getUploadRequestFolder: ({ commit, getters }, id) => {
commit('LOADING_STATE', { loading: true, data: [] })
commit('START_LOADING_VIEW')
return new Promise((resolve, reject) => {
axios
.get(`/api/file-request/${router.currentRoute.params.token}/browse/${id || 'all'}${getters.sorting.URI}`)
.then((response) => {
let folders = response.data.folders.data
let files = response.data.files.data
commit('LOADING_STATE', {
loading: false,
data: folders.concat(files),
})
commit('SET_CURRENT_FOLDER', response.data.root)
commit('SET_CURRENT_FOLDER', response.data.meta.root)
commit('SET_PAGINATOR', response.data.meta.paginate)
commit('STOP_LOADING_VIEW')
commit('ADD_NEW_ITEMS', response.data.data)
events.$emit('scrollTop')
@@ -43,7 +39,7 @@ const actions = {
// Stop loading spinner
if (['active', 'filled', 'expired'].includes(response.data.data.attributes.status) )
commit('LOADING_STATE', { loading: false, data: [] })
commit('STOP_LOADING_VIEW')
commit('SET_UPLOAD_REQUEST', response.data)
@@ -52,13 +48,19 @@ const actions = {
commit('SET_CURRENT_FOLDER', response.data.data.relationships.folder)
}
})
.catch((error) => {
Vue.prototype.$isSomethingWrong()
reject(error)
})
})
},
closeUploadRequest: ({ commit }) => {
axios
.delete(`/api/file-request/${router.currentRoute.params.token}`)
.then((response) => {
commit('LOADING_STATE', { loading: false, data: [] })
commit('START_LOADING_VIEW')
commit('STOP_LOADING_VIEW')
commit('SET_UPLOAD_REQUEST_AS_FILLED')
})
.catch(() => this.$isSomethingWrong())

View File

@@ -80,7 +80,7 @@ const actions = {
let itemsToFavourites = items.map((item) => {
if (item.data.type === 'folder') {
if (context.getters.user.data.relationships.favourites.data.find((folder) => folder.id === item.data.id))
if (context.getters.user.data.relationships.favourites.find((folder) => folder.id === item.data.id))
return
return item.data.id;
@@ -89,7 +89,7 @@ const actions = {
// Check is favorites already don't include some of pushed folders
let favouritesWidget = items.map((item) => {
if (!context.getters.user.data.relationships.favourites.data.find((folder) => folder.data.id === item.id)) {
if (!context.getters.user.data.relationships.favourites.find((folder) => folder.data.id === item.id)) {
return item
}
})
@@ -149,7 +149,7 @@ const mutations = {
},
ADD_TO_FAVOURITES(state, folder) {
folder.forEach((item) => {
state.user.data.relationships.favourites.data.push(item)
state.user.data.relationships.favourites.push(item)
})
},
UPDATE_FIRST_NAME(state, name) {
@@ -166,12 +166,12 @@ const mutations = {
}
},
REMOVE_ITEM_FROM_FAVOURITES(state, item) {
state.user.data.relationships.favourites.data = state.user.data.relationships.favourites.data.filter(
state.user.data.relationships.favourites.data = state.user.data.relationships.favourites.filter(
(folder) => folder.data.id !== item.data.id
)
},
UPDATE_NAME_IN_FAVOURITES(state, data) {
state.user.data.relationships.favourites.data.find((folder) => {
state.user.data.relationships.favourites.find((folder) => {
if (folder.id === data.id) {
folder.name = data.name
}
@@ -201,10 +201,7 @@ const mutations = {
}
const getters = {
isLimitedUser: (state) =>
state.user &&
state.user.data.relationships.failedPayments &&
state.user.data.relationships.failedPayments.data.length === 3,
userLimitationReason: (state) => state.user && state.user.data.meta.restrictions.reason,
permission: (state) => state.permission,
user: (state) => state.user,
}

View File

@@ -12,8 +12,10 @@
</AlertBox>
<!--Cron Alert-->
<AlertBox v-if="!data.app.isRunningCron && !config.isDev" color="rose">
We detect your cron jobs probably doesn't work correctly, please check it, you need it for running app correctly. If you set your cron job, please get back one minute later.
<AlertBox v-if="!data.app.cron.isRunning && !config.isDev" color="rose">
<p class="text-sm text-rose-700 dark:text-rose-500">We detect your cron jobs probably doesn't work correctly, please check it, you need it for running app correctly. If you set your cron job, please get back one minute later.</p>
<p class="text-sm text-rose-700 dark:text-rose-500 mt-4 font-bold">Command for Shared Web Hosting (Cpanel, Plesk, etc...): <br/> {{ data.app.cron.command.shared }}</p>
<p class="text-sm text-rose-700 dark:text-rose-500 mt-4 font-bold">Command for crontab: <br/> {{ data.app.cron.command.vps }}</p>
</AlertBox>
<!--Metric widgets-->

View File

@@ -18,14 +18,11 @@
@click="getLanguage(language)"
v-for="language in languages"
:key="language.data.id"
class="border-bottom-theme inline-block border-b-2 border-transparent px-4 py-5 text-sm font-bold"
class="border-bottom-theme inline-block border-b-2 border-transparent px-4 py-5 text-sm font-bold text-gray-600"
:class="{
'text-theme router-link-active':
selectedLanguage &&
selectedLanguage.data.attributes.locale === language.data.attributes.locale,
'text-gray-600':
!selectedLanguage &&
selectedLanguage.data.attributes.locale !== language.data.attributes.locale,
}"
>
{{ language.data.attributes.name }}
@@ -55,7 +52,7 @@
class="group flex cursor-pointer items-center justify-between py-2 pr-4"
>
<label
class="text-base font-bold"
class="text-base font-bold cursor-pointer"
:class="{
'text-theme':
selectedLanguage &&

View File

@@ -75,6 +75,49 @@
</AppInputButton>
</div>
<!--Fraud Prevention Mechanism Rules-->
<div v-if="config.subscriptionType === 'metered' && allowedPayments" class="card shadow-card">
<FormLabel icon="shield">
{{ $t('Usage Restriction Rules for User Accounts') }}
</FormLabel>
<AppInputSwitch
:title="$t('allow_limit_usage_in_new_accounts')"
:description="$t('limit_usage_description_for_restrictions')"
>
<SwitchInput
@input="$updateText('/admin/settings', 'limit_usage_in_new_accounts', settings.limitUsageInNewAccounts)"
v-model="settings.limitUsageInNewAccounts"
:state="settings.limitUsageInNewAccounts"
/>
</AppInputSwitch>
<AppInputText
v-if="settings.limitUsageInNewAccounts"
class="-mt-3"
>
<input
@input="$updateText('/admin/settings', 'limit_usage_in_new_accounts_amount', settings.limitUsageInNewAccountsAmount)"
v-model="settings.limitUsageInNewAccountsAmount"
:placeholder="$t('Max Usage Amount...')"
type="number"
class="focus-border-theme input-dark"
/>
</AppInputText>
<AppInputSwitch
:title="$t('allow_limit_usage_bigger_than_balance')"
:description="$t('limit_usage_description_for_restrictions')"
:is-last="true"
>
<SwitchInput
@input="$updateText('/admin/settings', 'usage_bigger_than_balance', settings.usageBiggerThanBalance)"
v-model="settings.usageBiggerThanBalance"
:state="settings.usageBiggerThanBalance"
/>
</AppInputSwitch>
</div>
<!--Stripe method configuration-->
<div v-if="allowedPayments" class="card shadow-card">
<img :src="$getPaymentLogo('stripe')" alt="Stripe" class="mb-8 h-8" />
@@ -348,7 +391,7 @@
</AppInputText>
<div v-if="paypal.isConfigured">
<AppInputSwitch :title="$t('Live Mode')" :description="$t('Toggle between live and sandbox mode')">
<AppInputSwitch :title="$t('Live Mode')" :description="$t('Toggle between sandbox and live mode')">
<SwitchInput
@input="$updateText('/admin/settings', 'paypal_live', config.isPayPalLive)"
v-model="config.isPayPalLive"
@@ -404,7 +447,7 @@
</FormLabel>
<ValidationProvider>
<AppInputSwitch v-if="! paypal.isConfigured" :title="$t('Live Mode')" :description="$t('Toggle between live and sandbox mode')">
<AppInputSwitch :title="$t('Live Mode')" :description="$t('Toggle between sandbox and live mode')">
<SwitchInput v-model="paypal.credentials.live" :state="paypal.credentials.live" />
</AppInputSwitch>
</ValidationProvider>
@@ -507,11 +550,24 @@ export default {
PageTab,
InfoBox,
},
watch: {
'paypal.credentials.live': function (val) {
this.$updateText('/admin/settings', 'paypal_live', val)
this.$store.commit('REPLACE_CONFIG_VALUE', {
key: 'isPayPalLive',
value: val,
})
}
},
computed: {
...mapGetters(['config']),
...mapGetters([
'config'
]),
},
data() {
return {
settings: undefined,
allowedRegistrationBonus: true,
registrationBonusAmount: undefined,
@@ -550,7 +606,7 @@ export default {
key: undefined,
secret: undefined,
webhook: undefined,
live: undefined,
live: false,
},
},
columns: [
@@ -651,6 +707,23 @@ export default {
})
}
},
mounted() {
axios
.get('/api/admin/settings', {
params: {
column: 'limit_usage_in_new_accounts|limit_usage_in_new_accounts_amount|usage_bigger_than_balance',
},
})
.then((response) => {
this.isLoading = false
this.settings = {
limitUsageInNewAccounts: parseInt(response.data.limit_usage_in_new_accounts),
limitUsageInNewAccountsAmount: parseInt(response.data.limit_usage_in_new_accounts_amount),
usageBiggerThanBalance: parseInt(response.data.usage_bigger_than_balance),
}
})
},
created() {
// Set payment description
this.stripe.paymentDescription = this.config.stripe_payment_description

View File

@@ -45,7 +45,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -65,7 +65,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
@@ -111,7 +111,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -133,7 +133,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
@@ -185,7 +185,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
@@ -210,7 +210,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
@@ -229,7 +229,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
@@ -254,7 +254,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
@@ -273,7 +273,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
@@ -298,14 +298,14 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
</div>
<!--Pricing Content-->
<div v-if="config.isSaaS" class="card shadow-card">
<div v-if="config.subscriptionType === 'fixed'" class="card shadow-card">
<FormLabel>Pricing Content</FormLabel>
<div class="block-wrapper">
@@ -354,7 +354,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -376,7 +376,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
@@ -428,7 +428,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -454,7 +454,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
@@ -480,7 +480,7 @@
:class="{ '!border-rose-600': errors[0] }"
class="focus-border-theme input-dark"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
@@ -540,7 +540,7 @@ export default {
})
.then((response) => {
this.app = {
allow_homepage: parseInt(response.data.allow_homepage),
allow_homepage: parseInt(response.data.allow_homepage || 1),
section_features: parseInt(response.data.section_features),
section_feature_boxes: parseInt(response.data.section_feature_boxes),
section_pricing_content: parseInt(response.data.section_pricing_content),

View File

@@ -1,6 +1,22 @@
<template>
<PageTab :is-loading="isLoading">
<!-- Subscription -->
<div v-if="app" class="card shadow-card">
<FormLabel icon="credit-card">
{{ $t('subscription') }}
</FormLabel>
<AppInputText :description="$t('subscription_type_note')" :is-last="true" :title="$t('subscription_type')">
<SelectInput
:default="app.subscriptionType"
:options="subscriptionTypes"
:placeholder="$t('select_subscription_type')"
@change="subscriptionTypeChange"
/>
</AppInputText>
</div>
<div v-if="app" class="card shadow-card">
<FormLabel>
{{ $t('upload_settings') }}
@@ -216,63 +232,6 @@
@input="$updateText('/admin/settings', 'google_analytics', app.googleAnalytics, true)"
/>
</AppInputText>
</div>
<!--Upgrade License-->
<div v-if="app && !config.isSaaS" class="card shadow-card">
<FormLabel icon="trending-up">
{{ $t('Upgrade your License') }}
</FormLabel>
<ValidationObserver
ref="upgradeLicense"
v-slot="{ invalid }"
class="mt-6"
tag="form"
@submit.prevent="upgradeLicense"
>
<ValidationProvider
v-slot="{ errors }"
mode="passive"
name="Purchase Code"
rules="required"
tag="div"
>
<AppInputText
:error="errors[0]"
:is-last="true"
>
<div class="space-y-4 sm:flex sm:space-x-4 sm:space-y-0">
<input
v-model="purchaseCode"
:class="{ '!border-rose-600': errors[0] }"
:placeholder="$t('Paste your Purchase code here...')"
class="focus-border-theme input-dark"
type="text"
/>
<ButtonBase :loading="isLoadingUpgradingButton" button-style="theme" class="w-full sm:w-auto" type="submit">
{{ $t('Upgrade') }}
</ButtonBase>
</div>
</AppInputText>
</ValidationProvider>
</ValidationObserver>
</div>
<!-- Subscription -->
<div v-if="app && config.isSaaS" class="card shadow-card">
<FormLabel icon="credit-card">
{{ $t('subscription') }}
</FormLabel>
<AppInputText :description="$t('subscription_type_note')" :is-last="true" :title="$t('subscription_type')">
<SelectInput
:default="app.subscriptionType"
:options="subscriptionTypes"
:placeholder="$t('select_subscription_type')"
@change="subscriptionTypeChange"
/>
</AppInputText>
</div>
</PageTab>
</template>
@@ -330,45 +289,6 @@ export default {
}
},
methods: {
async upgradeLicense() {
this.isLoadingUpgradingButton = true
// Validate fields
const isValid = await this.$refs.upgradeLicense.validate()
if (!isValid) return
axios.post('/api/admin/upgrade-license', {
purchaseCode: this.purchaseCode
})
.then((response) => {
this.$store.dispatch('getLanguageTranslations', this.config.locale)
this.$store.commit('REPLACE_CONFIG_VALUE', {
key: 'isSaaS',
value: true,
})
events.$emit('toaster', {
type: 'success',
message: this.$t('Your license was successfully upgraded'),
})
})
.catch((error) => {
if (error.response.status === 400) {
events.$emit('alert:open', {
title: this.$t('Purchase code is invalid or is not Extended License'),
})
} else {
events.$emit('alert:open', {
title: this.$t('popup_error.title'),
message: this.$t('popup_error.message'),
})
}
})
.finally(() => {
this.isLoadingUpgradingButton = false
})
},
subscriptionTypeChange(type) {
events.$emit('confirm:open', {
title: this.$t('subscription_type_change_warn'),

View File

@@ -29,7 +29,7 @@
</div>
<!--Broadcasting-->
<div class="card shadow-card">
<div v-if="config.broadcasting" class="card shadow-card">
<FormLabel icon="info">Broadcasting</FormLabel>
<div class="lg:flex lg:space-y-0 space-y-3 items-center justify-between">

View File

@@ -14,6 +14,7 @@
<tr class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
<td class="py-5 pr-3 md:pr-1">
<router-link
v-if="row.data.relationships.user"
class="flex items-center"
:to="{
name: 'UserDetail',
@@ -35,6 +36,9 @@
</span>
</div>
</router-link>
<span v-else class="text-sm font-bold">
-
</span>
</td>
<td class="px-3 md:px-1">
<ColorLabel :color="$getSubscriptionStatusColor(row.data.attributes.status)">
@@ -53,12 +57,7 @@
</td>
<td class="px-3 md:px-1">
<span class="text-sm font-bold">
<!--todo: update renew attribute-->
{{
row.data.attributes.renews_at
? row.data.attributes.renews_at
: row.data.attributes.created_at
}}
{{ row.data.attributes.renews_at }}
</span>
</td>
<td class="px-3 md:px-1">

View File

@@ -91,7 +91,7 @@ export default {
this.isSendingRequest = true
axios
.post(this.$store.getters.api + '/admin/users/' + this.$route.params.id + '/delete', {
.post(this.$store.getters.api + '/admin/users/' + this.$route.params.id, {
name: this.userName,
_method: 'delete',
})
@@ -104,7 +104,7 @@ export default {
})
}
if (response.status === 204) {
if (response.status === 200) {
events.$emit('success:open', {
emoji: '👍',
title: this.$t('popup_deleted_user.title'),

View File

@@ -73,7 +73,7 @@ export default {
this.limitations.push({
message: payload.message[key],
isVisibleBar: item.total === -1,
isVisibleBar: item.total !== -1 && item.total !== 0,
distribution: [
{
progress: item.percentage,

View File

@@ -1,5 +1,5 @@
<template>
<AuthContentWrapper ref="auth">
<AuthContentWrapper ref="auth" class="h-screen">
<!--Create new password-->
<AuthContent name="create-new-password" :visible="true">
<Headline :title="$t('page_create_password.title')" :description="$t('page_create_password.subtitle')" />
@@ -30,7 +30,7 @@
class="dark:placeholder:text-gray-600 focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
:class="{ '!border-rose-600': errors[0] }"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -53,7 +53,7 @@
class="dark:placeholder:text-gray-600 focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
:class="{ '!border-rose-600': errors[0] }"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -76,7 +76,7 @@
class="dark:placeholder:text-gray-600 focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
:class="{ '!border-rose-600': errors[0] }"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>

View File

@@ -459,7 +459,7 @@ export default {
this.$scrollTop()
this.$store.commit('PROCESSING_POPUP', undefined)
if (this.config.isDemo || this.config.isDev) {
if (this.config.isPrefilledUsers) {
this.loginEmail = 'howdy@hi5ve.digital'
this.loginPassword = 'vuefilemanager'
}

View File

@@ -1,7 +1,7 @@
<template>
<AuthContentWrapper ref="auth">
<AuthContentWrapper ref="auth" class="h-screen">
<!--Registration-->
<AuthContent name="sign-up" :visible="true" class="mt-4 mb-12">
<AuthContent name="sign-up" :visible="true">
<Headline :title="$t('page_registration.title')" :description="$t('page_registration.subtitle')" />
<ValidationObserver
@@ -208,11 +208,10 @@ export default {
this.isLoading = true
// Get ReCaptcha token
if (config.allowedRecaptcha) {
this.register.reCaptcha = await this.$reCaptchaToken('register').then((response) => {
return response
})
}
if (this.config.allowedRecaptcha) {
this.register.reCaptcha = await this.$reCaptchaToken('register')
.then((response) => response)
}
// Send request to get user token
axios
@@ -278,7 +277,7 @@ export default {
this.$router.push({name: 'Files'})
}
if (this.config.isDemo || this.config.isDev) {
if (this.config.isPrefilledUsers) {
this.register = {
name: 'John Doe',
email: 'demo-' + Math.floor(Math.random() * 100000) + '@doe.com',

View File

@@ -254,7 +254,7 @@ export default {
return this.item && this.item.data.type === 'folder'
},
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() {
return this.clipboard.find((item) => item.data.type !== 'folder')
@@ -266,7 +266,7 @@ export default {
}
},
created() {
this.$store.dispatch('getFolder', this.$route.params.id)
this.$store.dispatch('getFolder', {page: 1, id:this.$route.params.id})
events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('context-menu:current-folder', (folder) => (this.item = folder))

View File

@@ -157,7 +157,7 @@ export default {
return this.item && this.item.type === 'folder'
},
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() {
return this.clipboard.find((item) => item.type !== 'folder')
@@ -169,7 +169,7 @@ export default {
}
},
created() {
this.$store.dispatch('getMySharedItems')
this.$store.dispatch('getMySharedItems', 1)
events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('mobile-context-menu:show', (item) => (this.item = item))

View File

@@ -234,7 +234,7 @@ export default {
},
},
created() {
this.$store.dispatch('getSharedFolder', this.$route.params.id)
this.$store.dispatch('getSharedFolder', {page: 1, id: this.$route.params.id})
events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('mobile-context-menu:show', (item) => (this.item = item))

View File

@@ -151,7 +151,7 @@ export default {
}
},
created() {
this.$store.dispatch('getRecentUploads')
this.$store.dispatch('getRecentUploads', 1)
events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('mobile-context-menu:show', (item) => (this.item = item))

View File

@@ -242,7 +242,7 @@ export default {
},
},
mounted() {
this.$store.dispatch('getSharedWithMeFolder', this.$route.params.id)
this.$store.dispatch('getSharedWithMeFolder',{page: 1, id:this.$route.params.id})
events.$on('context-menu:show', (event, 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) {
this.$router.push({ name: 'SharedWithMe' })
} else {
this.$store.dispatch('getSharedWithMeFolder', undefined)
this.$store.dispatch('getSharedWithMeFolder',{page: 1, id:undefined})
}
events.$emit('toaster', {

View File

@@ -281,7 +281,7 @@ export default {
return this.item && this.item.data.type === 'folder'
},
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() {
return this.clipboard.find((item) => item.type !== 'folder')
@@ -293,7 +293,7 @@ export default {
}
},
mounted() {
this.$store.dispatch('getTeamFolder', this.$route.params.id)
this.$store.dispatch('getTeamFolder', {page: 1, id:this.$route.params.id})
events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('mobile-context-menu:show', (item) => (this.item = item))

View File

@@ -149,7 +149,7 @@ export default {
}
},
created() {
this.$store.dispatch('getTrash', this.$route.params.id)
this.$store.dispatch('getTrash', {page: 1, id: this.$route.params.id})
events.$on('context-menu:show', (event, item) => (this.item = item))
events.$on('mobile-context-menu:show', (item) => (this.item = item))

View File

@@ -30,7 +30,7 @@
class="focus-border-theme input-dark"
:class="{ '!border-rose-600': errors[0] }"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -44,7 +44,7 @@
class="focus-border-theme input-dark"
:class="{ '!border-rose-600': errors[0] }"
></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -121,11 +121,10 @@ export default {
this.isLoading = true
// Get ReCaptcha token
if (config.allowedRecaptcha) {
this.register.reCaptcha = await this.$reCaptchaToken('register').then((response) => {
return response
})
}
if (this.config.allowedRecaptcha) {
this.contact.reCaptcha = await this.$reCaptchaToken('register')
.then((response) => response)
}
// Send request to get user token
axios

View File

@@ -24,7 +24,7 @@
<MainFeatures />
<!--Pricing Tables-->
<PricingTables v-if="config.isSaaS && config.subscriptionType === 'fixed'" />
<PricingTables v-if="config.subscriptionType === 'fixed'" />
<!--Get Started Call To Action-->
<GetStarted />

View File

@@ -36,7 +36,7 @@
<div
@contextmenu.prevent.capture="contextMenu($event, undefined)"
class="lg:flex lg:flex-col lg:w-full lg:px-3.5"
class="lg:flex lg:flex-col lg:w-full lg:px-3.5 min-w-0"
>
<DesktopToolbar />
@@ -53,7 +53,7 @@
<!--File list & info sidebar-->
<div class="flex space-x-3 lg:overflow-hidden grow" @drop.stop.prevent="uploadDroppedItems($event)" @dragenter.prevent @dragover.prevent>
<router-view id="file-view" class="relative w-full" :key="$route.fullPath" />
<router-view id="file-view" class="relative w-full min-w-0" :key="$route.fullPath" />
<InfoSidebar v-if="isVisibleSidebar" />
</div>
@@ -62,6 +62,7 @@
</template>
<script>
import { getFilesFromDataTransferItems } from 'datatransfer-files-promise'
import FileSortingMobile from '../components/Menus/FileSortingMobile'
import SidebarNavigation from '../components/Sidebar/SidebarNavigation'
import FileFilterMobile from '../components/Menus/FileFilterMobile'
@@ -116,7 +117,7 @@ export default {
DragUI,
},
computed: {
...mapGetters(['isVisibleSidebar', 'isLimitedUser', 'config', 'currentFolder']),
...mapGetters(['isVisibleSidebar', 'config', 'currentFolder']),
},
data() {
return {
@@ -124,8 +125,14 @@ export default {
}
},
methods: {
uploadDroppedItems(event) {
this.$uploadDraggedFiles(event, this.currentFolder?.data.id)
async uploadDroppedItems(event) {
// Check if user dropped folder with files
let files = await getFilesFromDataTransferItems(event.dataTransfer.items)
if (files.length !== 0) {
// Upload folder with files
this.$uploadDraggedFolderOrFile(files, this.currentFolder?.data.id)
}
},
contextMenu(event, item) {
events.$emit('context-menu:show', event, item)

View File

@@ -194,7 +194,7 @@
</ValidationProvider>
</div>
<div v-if="isExtended" class="card text-left shadow-card">
<div class="card text-left shadow-card">
<FormLabel>Subscription</FormLabel>
<ValidationProvider
@@ -275,7 +275,6 @@ export default {
data() {
return {
isLoading: false,
isExtended: undefined,
app: {
color: '#00BC7E',
subscriptionType: undefined,
@@ -357,8 +356,6 @@ export default {
created() {
this.$scrollTop()
this.isExtended = localStorage.getItem('license') === 'Extended'
if (this.$root.$data.config.isSetupWizardDebug) {
this.app.subscriptionType = 'metered'
this.app.title = 'VueFileManager'

View File

@@ -256,7 +256,7 @@ export default {
axios
.get('/api/ping')
.then((response) => {
this.apiRunning = response.data === 'pong'
this.apiRunning = response.data.message === 'pong'
})
.catch(() => {
this.apiRunning = false

View File

@@ -25,7 +25,7 @@
<div
@contextmenu.prevent.capture="contextMenu($event, undefined)"
class="lg:flex lg:flex-col lg:w-full lg:px-3.5"
class="lg:flex lg:flex-col lg:w-full lg:px-3.5 min-w-0"
>
<DesktopSharepageToolbar />
@@ -36,7 +36,7 @@
<!--File list & info sidebar-->
<div class="flex space-x-3 lg:overflow-hidden grow" @drop.stop.prevent="uploadDroppedItems($event)" @dragenter.prevent @dragover.prevent>
<router-view id="file-view" class="relative w-full" :key="$route.fullPath" />
<router-view id="file-view" class="relative w-full min-w-0" :key="$route.fullPath" />
<InfoSidebar v-if="isVisibleSidebar" />
</div>
@@ -64,6 +64,7 @@ import { mapGetters } from 'vuex'
import { events } from '../bus'
import DesktopSharepageToolbar from '../components/Layout/Toolbars/DesktopSharepageToolbar'
import RemoteUploadPopup from "../components/RemoteUpload/RemoteUploadPopup";
import {getFilesFromDataTransferItems} from "datatransfer-files-promise";
export default {
name: 'Shared',
@@ -95,8 +96,14 @@ export default {
}
},
methods: {
uploadDroppedItems(event) {
this.$uploadDraggedFiles(event, this.currentFolder?.data.id)
async uploadDroppedItems(event) {
// Check if user dropped folder with files
let files = await getFilesFromDataTransferItems(event.dataTransfer.items)
if (files.length !== 0) {
// Upload folder with files
this.$uploadDraggedFolderOrFile(files, this.currentFolder?.data.id)
}
},
contextMenu(event, item) {
events.$emit('context-menu:show', event, item)

View File

@@ -21,7 +21,7 @@
<div
@contextmenu.prevent.capture="contextMenu($event, undefined)"
class="lg:flex lg:flex-col lg:w-full lg:px-3.5"
class="lg:flex lg:flex-col lg:w-full lg:px-3.5 min-w-0"
>
<DesktopUploadRequestToolbar v-if="canShowUI" />
<MobileUploadRequestToolBar v-if="canShowUI" />
@@ -31,7 +31,7 @@
<!--File list & info sidebar-->
<div class="flex space-x-3 lg:overflow-hidden grow" @drop.stop.prevent="uploadDroppedItems($event)" @dragenter.prevent @dragover.prevent>
<router-view id="file-view" class="relative w-full" :key="$route.fullPath" />
<router-view id="file-view" class="relative w-full min-w-0" :key="$route.fullPath" />
<InfoSidebarUploadRequest v-if="canShowUI && isVisibleSidebar" />
</div>
@@ -56,6 +56,7 @@ import DragUI from '../components/UI/Others/DragUI'
import { mapGetters } from 'vuex'
import { events } from '../bus'
import RemoteUploadPopup from "../components/RemoteUpload/RemoteUploadPopup";
import {getFilesFromDataTransferItems} from "datatransfer-files-promise";
export default {
name: 'UploadRequest',
@@ -87,8 +88,14 @@ export default {
}
},
methods: {
uploadDroppedItems(event) {
this.$uploadDraggedFiles(event, this.currentFolder?.data.id)
async uploadDroppedItems(event) {
// Check if user dropped folder with files
let files = await getFilesFromDataTransferItems(event.dataTransfer.items)
if (files.length !== 0) {
// Upload folder with files
this.$uploadDraggedFolderOrFile(files, this.currentFolder?.data.id)
}
},
contextMenu(event, item) {
events.$emit('context-menu:show', event, item)

View File

@@ -1,15 +1,15 @@
<!DOCTYPE html>
<html class="{{ $config->installation === 'installation-needed' ? 'dark:bg-dark-background bg-light-background' : '' }}" style="min-height: 100%" lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<html class="{{ $config->app->installation === 'installation-needed' ? 'dark:bg-dark-background bg-light-background' : '' }}" style="min-height: 100%" lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta name="theme-color" content="{{ $config->app_color ?? '#00BC7E' }}">
<meta name="theme-color" content="{{ $config->theme->color ?? '#00BC7E' }}">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui">
<meta name="description" content="{{ $config->app_description ?? __t('app_description') }}">
<meta name="description" content="{{ $config->app->description ?? __t('app_description') }}">
<title>
{{ $config->app_title ?? 'VueFileManager' }} | {{ $config->app_description ?? __t('app_description') }}
{{ $config->app->name ?? 'VueFileManager' }} | {{ $config->app->description ?? __t('app_description') }}
</title>
{{--StyleSheet--}}
@@ -18,18 +18,18 @@
{{--OG items--}}
<meta property="og:url" content="{{ url('/') }}">
<meta property="og:title" content="{{ $config->app_title ?? 'VueFileManager' }} | {{ $config->app_description ?? __t('app_description') }}">
<meta property="og:description" content="{{ $config->app_description ?? __t('app_description') }}">
<meta property="og:image" content="{{ isset($config->app_og_image) ? url($config->app_og_image) : '' }}">
<meta property="og:title" content="{{ $config->app->name ?? 'VueFileManager' }} | {{ $config->app->description ?? __t('app_description') }}">
<meta property="og:description" content="{{ $config->app->description ?? __t('app_description') }}">
<meta property="og:image" content="{{ isset($config->logos->og_image) ? url($config->logos->og_image) : '' }}">
{{-- Apple Mobile Web App--}}
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="white">
<meta name="apple-mobile-web-app-title" content="{{ $config->app_title ?? 'VueFileManager' }}">
<meta name="apple-mobile-web-app-title" content="{{ $config->app->name ?? 'VueFileManager' }}">
{{--Icons--}}
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="{{ isset($config->app_touch_icon) ? url($config->app_touch_icon) : '' }}">
<link rel="icon" href="{{ isset($config->app_favicon) ? url($config->app_favicon) : asset('favicon.png') }}?v={{ get_version() }}">
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="{{ isset($config->logos->touch_icon) ? url($config->logos->touch_icon) : '' }}">
<link rel="icon" href="{{ isset($config->logos->favicon) ? url($config->logos->favicon) : asset('favicon.png') }}?v={{ get_version() }}">
{{--Format Detection--}}
<meta name="format-detection" content="telephone=no">
@@ -43,112 +43,112 @@
<script>
let config = {
host: '{{ $config->host }}',
api: '{{ $config->api }}',
locale: '{{ $config->locale }}',
host: '{{ $config->app->host }}',
api: '{{ $config->app->api }}',
locale: '{{ $config->app->locale }}',
broadcasting: '{{ $config->broadcasting }}',
broadcastingKey: '{{ $config->broadcastingKey }}',
broadcastingHost: '{{ $config->broadcastingHost }}',
broadcastingPort: '{{ $config->broadcastingPort }}',
broadcastingCluster: '{{ $config->broadcastingCluster }}',
broadcasting: '{{ $config->broadcasting->driver }}',
broadcastingKey: '{{ $config->broadcasting->key }}',
broadcastingHost: '{{ $config->broadcasting->host }}',
broadcastingPort: '{{ $config->broadcasting->port }}',
broadcastingCluster: '{{ $config->broadcasting->cluster }}',
app_logo: '{{ $config->app_logo }}',
app_logo_dark: '{{ $config->app_logo_dark }}',
app_logo_horizontal: '{{ $config->app_logo_horizontal }}',
app_logo_horizontal_dark: '{{ $config->app_logo_horizontal_dark }}',
app_logo: '{{ $config->logos->main }}',
app_logo_dark: '{{ $config->logos->main_dark }}',
app_logo_horizontal: '{{ $config->logos->horizontal }}',
app_logo_horizontal_dark: '{{ $config->logos->horizontal_dark }}',
app_color: '{{ $config->app_color }}',
app_footer: '{!! $config->app_footer !!}',
app_name: '{{ $config->app_name }}',
app_description: '{{ $config->app_description }}',
app_color: '{{ $config->theme->color }}',
app_footer: '{!! $config->app->footer !!}',
app_name: '{{ $config->app->name }}',
app_description: '{{ $config->app->description }}',
allowHomepage: {{ $config->allowHomepage }},
storageLimit: {{ $config->storageLimit }},
storageLimit: {{ $config->storage->limit }},
teamsDefaultMembers: {{ $config->teamsDefaultMembers }},
storageDefaultSpace: {{ $config->storageDefaultSpace }},
storageDefaultSpaceFormatted: '{{ $config->storageDefaultSpaceFormatted }}',
mimetypesBlacklist: '{{ $config->mimetypesBlacklist }}',
uploadLimit: {{ $config->uploadLimit }},
uploadLimitFormatted: '{{ $config->uploadLimitFormatted }}',
chunkSize: {{ $config->chunkSize }},
storageDefaultSpace: {{ $config->storage->defaultSpace }},
storageDefaultSpaceFormatted: '{{ $config->storage->defaultSpaceFormatted }}',
mimetypesBlacklist: '{{ $config->upload->disabledMimetypes }}',
uploadLimit: {{ $config->upload->limit }},
uploadLimitFormatted: '{{ $config->upload->limitFormatted }}',
chunkSize: {{ $config->upload->chunkSize }},
isAuthenticated: {{ $config->isAuthenticated }},
isSaaS: {{ $config->isSaaS }},
isAuthenticated: {{ $config->app->isAuthenticated }},
isDev: {{ $config->isDev }},
isDemo: {{ $config->isDemo }},
isDev: {{ $config->app->isDev }},
isDemo: {{ $config->app->isDemo }},
legal: {!! $config->legal !!},
installation: '{{ $config->installation }}',
statusCheck: {!! $config->statusCheck !!},
isSetupWizardDemo: {{ $config->isSetupWizardDemo }},
isSetupWizardDebug: {{ $config->isSetupWizardDebug }},
installation: '{{ $config->app->installation }}',
statusCheck: {!! $config->debug->statusCheck !!},
isSetupWizardDemo: {{ $config->debug->isSetupWizardDemo }},
isSetupWizardDebug: {{ $config->debug->isSetupWizardDebug }},
isPrefilledUsers: {{ $config->debug->isPrefilledUsers }},
// States
isEmptyPlans: {{ $config->isEmptyPlans }},
isEmptyTransactions: {{ $config->isEmptyTransactions }},
isEmptySubscriptions: {{ $config->isEmptySubscriptions }},
isEmptyPlans: {{ $config->payments->isEmptyPlans }},
isEmptyTransactions: {{ $config->payments->isEmptyTransactions }},
isEmptySubscriptions: {{ $config->payments->isEmptySubscriptions }},
// Hidden set ups
isAdminVueFileManagerBar: {{ $config->isAdminVueFileManagerBar }},
isAdminVueFileManagerBar: {{ $config->debug->isAdminVueFileManagerBar }},
// Metered
allowed_registration_bonus: {{ $config->allowed_registration_bonus }},
registration_bonus_amount: {{ $config->registration_bonus_amount }},
isCreatedMeteredPlan: {{ $config->isCreatedMeteredPlan }},
meteredPlanId: '{{ $config->meteredPlanId }}',
allowed_registration_bonus: {{ $config->billing_metered->allowed_registration_bonus }},
registration_bonus_amount: {{ $config->billing_metered->registration_bonus_amount }},
isCreatedMeteredPlan: {{ $config->billing_metered->isCreatedMeteredPlan }},
meteredPlanId: '{{ $config->billing_metered->meteredPlanId }}',
// Payments
allowed_payments: {{ $config->allowed_payments }},
subscriptionType: '{{ $config->subscriptionType }}',
allowed_payments: {{ $config->payments->allowed }},
subscriptionType: '{{ $config->payments->type }}',
// PayPal
isPayPal: {{ $config->isPayPal }},
isPayPalLive: {{ $config->isPayPalLive }},
paypal_client_id: '{{ $config->paypal_client_id }}',
paypal_payment_description: '{{ $config->paypal_payment_description }}',
isPayPal: {{ $config->gateways->paypal->allowed }},
isPayPalLive: {{ $config->gateways->paypal->live }},
paypal_client_id: '{{ $config->gateways->paypal->client_id }}',
paypal_payment_description: '{{ $config->gateways->paypal->payment_description }}',
// Paystack
isPaystack: {{ $config->isPaystack }},
paystack_public_key: '{{ $config->paystack_public_key }}',
paystack_payment_description: '{{ $config->paystack_payment_description }}',
isPaystack: {{ $config->gateways->paystack->allowed }},
paystack_public_key: '{{ $config->gateways->paystack->public_key }}',
paystack_payment_description: '{{ $config->gateways->paystack->payment_description }}',
// Stripe
isStripe: {{ $config->isStripe }},
stripe_public_key: '{{ $config->stripe_public_key }}',
stripe_payment_description: '{{ $config->stripe_payment_description }}',
isStripe: {{ $config->gateways->stripe->allowed }},
stripe_public_key: '{{ $config->gateways->stripe->public_key }}',
stripe_payment_description: '{{ $config->gateways->stripe->payment_description }}',
// ReCaptcha
recaptcha_client_id: '{{ $config->recaptcha_client_id }}',
allowedRecaptcha: {{ $config->allowedRecaptcha }},
isRecaptchaConfigured: {{ $config->isRecaptchaConfigured }},
recaptcha_client_id: '{{ $config->recaptcha->client_id }}',
allowedRecaptcha: {{ $config->recaptcha->allowed }},
isRecaptchaConfigured: {{ $config->recaptcha->is_configured }},
// Social logins
allowedFacebookLogin: {{ $config->allowedFacebookLogin }},
isFacebookLoginConfigured: {{ $config->isFacebookLoginConfigured }},
allowedFacebookLogin: {{ $config->social_logins->is_facebook_allowed }},
isFacebookLoginConfigured: {{ $config->social_logins->is_facebook_configured }},
allowedGoogleLogin: {{ $config->allowedGoogleLogin }},
isGoogleLoginConfigured: {{ $config->isGoogleLoginConfigured }},
allowedGoogleLogin: {{ $config->social_logins->is_google_allowed }},
isGoogleLoginConfigured: {{ $config->social_logins->is_google_configured }},
allowedGithubLogin: {{ $config->allowedGithubLogin }},
isGithubLoginConfigured: {{ $config->isGithubLoginConfigured }},
allowedGithubLogin: {{ $config->social_logins->is_github_allowed }},
isGithubLoginConfigured: {{ $config->social_logins->is_github_configured }},
// Adsense
allowedAdsense: {{ $config->allowedAdsense }},
adsenseClientId: '{{ $config->adsenseClientId }}',
adsenseBanner01: `{!! $config->adsenseBanner01 !!}`,
adsenseBanner02: `{!! $config->adsenseBanner02 !!}`,
adsenseBanner03: `{!! $config->adsenseBanner03 !!}`,
allowedAdsense: {{ $config->adsense->allowed }},
adsenseClientId: '{{ $config->adsense->clientId }}',
adsenseBanner01: `{!! $config->adsense->banner01 !!}`,
adsenseBanner02: `{!! $config->adsense->banner02 !!}`,
adsenseBanner03: `{!! $config->adsense->banner03 !!}`,
// User settings
defaultEmoji: '{{ $config->defaultEmoji }}',
defaultThemeMode: '{{ $config->defaultThemeMode }}',
defaultEmoji: '{{ $config->theme->emoji }}',
defaultThemeMode: '{{ $config->theme->mode }}',
// App settings
userRegistration: {{ $config->userRegistration }},
userVerification: {{ $config->userVerification }},
userRegistration: {{ $config->registration->allowed }},
userVerification: {{ $config->registration->verification }},
}
</script>
@@ -158,7 +158,7 @@
<script src="{{ asset('js/main.js') }}?v={{ get_version() }}"></script>
{{--Global site tag (gtag.js) - Google Analytics--}}
@if(isset($config->google_analytics) && $config->google_analytics)
@if($config->google_analytics)
<script async src="https://www.googletagmanager.com/gtag/js?id={{ $config->google_analytics }}"></script>
<script>
window.dataLayer = window.dataLayer || [];

View File

@@ -1,7 +1,7 @@
<style>
@php
$color = $settings->app_color ?? '#00BC7E';
$color = $config->theme->color ?? '#00BC7E';
@endphp
{{-- Tailwind Helpers --}}