Merge remote-tracking branch 'origin/version-v1.8.1'

# Conflicts:
#	config/vuefilemanager.php
#	public/chunks/admin-account.js
#	public/chunks/admin.js
#	public/chunks/app-appearance.js
#	public/chunks/app-billings.js
#	public/chunks/app-email.js
#	public/chunks/app-index.js
#	public/chunks/app-others.js
#	public/chunks/app-payments.js
#	public/chunks/app-settings.js
#	public/chunks/app-setup.js
#	public/chunks/billings-detail.js
#	public/chunks/contact-us.js
#	public/chunks/dashboard.js
#	public/chunks/database.js
#	public/chunks/environment-setup.js
#	public/chunks/files.js
#	public/chunks/files~chunks/shared-files~chunks/shared-page.js
#	public/chunks/installation-disclaimer.js
#	public/chunks/invoices.js
#	public/chunks/landing-page.js
#	public/chunks/pages.js
#	public/chunks/plan-create.js
#	public/chunks/plan-delete.js
#	public/chunks/plan-settings.js
#	public/chunks/plan-subscribers.js
#	public/chunks/plan.js
#	public/chunks/plans.js
#	public/chunks/profile.js
#	public/chunks/purchase-code.js
#	public/chunks/settings-create-payment-methods.js
#	public/chunks/settings-invoices.js
#	public/chunks/settings-payment-methods.js
#	public/chunks/settings-storage.js
#	public/chunks/settings-subscription.js
#	public/chunks/settings.js
#	public/chunks/shared-files.js
#	public/chunks/shared-page.js
#	public/chunks/sign-up.js
#	public/chunks/stripe-credentials.js
#	public/chunks/subscription-plans.js
#	public/chunks/subscription-service.js
#	public/chunks/upgrade-billing.js
#	public/chunks/upgrade.js
#	public/chunks/user-create.js
#	public/chunks/user-delete.js
#	public/chunks/user-detail.js
#	public/chunks/user-invoices.js
#	public/chunks/user-password.js
#	public/chunks/user-storage.js
#	public/chunks/user-subscription.js
#	public/chunks/user.js
#	public/chunks/users.js
#	public/js/main.js
#	public/mix-manifest.json
#	resources/js/views/FilePages/Files.vue
This commit is contained in:
Peter Papp
2021-02-07 18:05:56 +01:00
140 changed files with 17575 additions and 1524 deletions

View File

@@ -102,7 +102,7 @@ class FileManagerFile extends Model
*/
public function getCreatedAtAttribute()
{
return format_date($this->attributes['created_at'], __('vuefilemanager.time'));
return format_date(set_time_by_user_timezone($this->attributes['created_at']), __('vuefilemanager.time'));
}
/**
@@ -114,7 +114,7 @@ class FileManagerFile extends Model
{
if (!$this->attributes['deleted_at']) return null;
return format_date($this->attributes['deleted_at'], __('vuefilemanager.time'));
return format_date(set_time_by_user_timezone($this->attributes['deleted_at']), __('vuefilemanager.time'));
}
/**

View File

@@ -73,6 +73,10 @@ class FileManagerFolder extends Model
'items', 'trashed_items'
];
protected $casts = [
'icon_emoji' => 'object',
];
/**
* Sortable columns
*
@@ -133,7 +137,7 @@ class FileManagerFolder extends Model
*/
public function getCreatedAtAttribute()
{
return format_date($this->attributes['created_at'], __('vuefilemanager.time'));
return format_date(set_time_by_user_timezone($this->attributes['created_at']), __('vuefilemanager.time'));
}
/**
@@ -145,7 +149,7 @@ class FileManagerFolder extends Model
{
if (! $this->attributes['deleted_at']) return null;
return format_date($this->attributes['deleted_at'], __('vuefilemanager.time'));
return format_date(set_time_by_user_timezone($this->attributes['deleted_at']), __('vuefilemanager.time'));
}
/**

View File

@@ -26,6 +26,7 @@ class AppFunctionsController extends Controller
* @var array
*/
private $whitelist = [
'section_features',
'footer_content',
'get_started_description',
'get_started_title',
@@ -44,7 +45,7 @@ class AppFunctionsController extends Controller
'section_get_started',
'section_pricing_content',
'section_feature_boxes',
'section_features',
'allow_homepage',
];
/**

View File

@@ -96,7 +96,7 @@ class BrowseController extends Controller
// Get User
$user = User::with(['latest_uploads' => function($query) {
$query->sortable();
$query->sortable(['created_at' => 'desc']);
}])
->where('id', Auth::id())
->first();

View File

@@ -15,6 +15,7 @@ use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;
use App\Http\Tools\Guardian;
use App\Http\Tools\Editor;
use App\FileManagerFolder;
use App\FileManagerFile;
use Exception;
@@ -114,6 +115,12 @@ class EditItemsController extends Controller
}
}
// If request have a change folder icon values set the folder icon
if ($request->type === 'folder' && $request->filled('folder_icon')) {
Editor::set_folder_icon($request->folder_icon, $unique_id);
}
// Rename Item
return Editor::rename_item($request, $unique_id);
}
@@ -150,6 +157,12 @@ class EditItemsController extends Controller
Guardian::check_item_access($item->folder_id, $shared);
}
// If request have a change folder icon values set the folder icon
if ($request->type === 'folder' && $request->filled('folder_icon')) {
Editor::set_folder_icon($request->folder_icon, $unique_id, $shared);
}
// Rename item
$item = Editor::rename_item($request, $unique_id, $shared);
@@ -315,6 +328,85 @@ class EditItemsController extends Controller
return $new_file;
}
/**
* User download folder via zip
*
* @param $unique_id
* @return string
*/
public function user_zip_folder(Request $request,$unique_id)
{
// Get user id
$user_id = Auth::id();
// Check permission to download for authenticated editor
if ($request->user()->tokenCan('editor')) {
// check if shared_token cookie exist
if (!$request->hasCookie('shared_token')) abort('401');
// Get shared token
$shared = get_shared($request->cookie('shared_token'));
// Check access to requested directory
Guardian::check_item_access($unique_id, $shared);
}
// Get folder
$folder = FileManagerFolder::whereUserId($user_id)
->where('unique_id', $unique_id);
if (! $folder->exists()) {
abort(404, 'Requested folder doesn\'t exists.');
}
$zip = Editor::zip_folder($unique_id);
// Get file
return response([
'url' => route('zip', $zip->id),
'name' => $zip->basename,
], 200);
}
/**
* Guest download folder via zip
*
* @param Request $request
* @param $unique_id
* @param $token
* @return string
*/
public function guest_zip_folder($unique_id, $token)
{
// Get shared record
$shared = get_shared($token);
// Check access to requested folder
Guardian::check_item_access($unique_id, $shared);
// Get folder
$folder = FileManagerFolder::whereUserId($shared->user_id)
->where('unique_id', $unique_id);
if (! $folder->exists()) {
abort(404, 'Requested folder doesn\'t exists.');
}
$zip = Editor::zip_folder($unique_id, $shared);
// Get file
return response([
'url' => route('zip_public', [
'id' => $zip->id,
'token' => $shared->token,
]),
'name' => $zip->basename,
], 200);
}
/**
* User download multiple files via zip
*

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\FileFunctions;
use App\Http\Requests\Share\CreateShareRequest;
use App\Http\Requests\Share\UpdateShareRequest;
use App\Http\Resources\ShareResource;
use App\Notifications\SharedSendViaEmail;
use App\Zip;
use Illuminate\Contracts\Routing\ResponseFactory;
use App\Http\Controllers\Controller;
@@ -12,8 +13,10 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Str;
use App\Share;
use Validator;
class ShareController extends Controller
{
@@ -58,7 +61,17 @@ class ShareController extends Controller
];
// Return created shared record
return new ShareResource(Share::create($options));
$share = new ShareResource(Share::create($options));
// Send shared link via email
if ($request->has('emails')) {
foreach ($request->emails as $email) {
Notification::route('mail', $email)->notify(new SharedSendViaEmail($token));
}
}
return $share;
}
/**
@@ -96,7 +109,7 @@ class ShareController extends Controller
*/
public function destroy(Request $request)
{
foreach($request->input('tokens') as $token) {
foreach ($request->input('tokens') as $token) {
// Get sharing record
Share::where('token', $token)
@@ -117,4 +130,40 @@ class ShareController extends Controller
// Done
return response('Done!', 204);
}
/**
* Send shared link via email to recipients
*
* @param $token
* @param $request
*/
public function shared_send_via_email(Request $request, $token)
{
// Make validation of array of emails
$validator = Validator::make($request->all(), [
'emails.*' => 'required|email',
]);
// Return error
if ($validator->fails()) abort(400, 'Bad emails input');
// Get shared by token
$share = Share::where('token', $token)
->where('user_id', Auth::id())
->first();
// Demo preview
if (env('APP_DEMO')) {
return response('Done!', 204);
}
// Send shared link via email
if($request->has('emails')) {
foreach ($request->emails as $email) {
Notification::route('mail', $email)->notify(new SharedSendViaEmail($token));
}
}
return response('Done!', 204);
}
}

View File

@@ -59,12 +59,12 @@ class TrashController extends Controller
* @param $unique_id
* @return ResponseFactory|\Illuminate\Http\Response
*/
public function restore(Request $request, $unique_id)
public function restore(Request $request)
{
// Validate request
$validator = Validator::make($request->all(), [
'type' => 'required|string',
'to_home' => 'boolean',
$validator = Validator::make($request->input('data'), [
'*.type' => 'required|string',
'*.unique_id' => 'integer',
]);
// Return error
@@ -77,38 +77,41 @@ class TrashController extends Controller
return Demo::response_204();
}
// Get folder
if ($request->type === 'folder') {
foreach($request->input('data') as $restore_item) {
// Get folder
$item = FileManagerFolder::onlyTrashed()
->where('user_id', $user_id)
->where('unique_id', $unique_id)
->first();
if ($restore_item['type'] === 'folder') {
// Restore item to home directory
if ($request->has('to_home') && $request->to_home) {
$item->parent_id = 0;
$item->save();
// Get folder
$item = FileManagerFolder::onlyTrashed()
->where('user_id', $user_id)
->where('unique_id', $restore_item['unique_id'])
->first();
// Restore item to home directory
if ($request->has('to_home') && $request->to_home) {
$item->parent_id = 0;
$item->save();
}
} else {
// Get item
$item = FileManagerFile::onlyTrashed()
->where('user_id', $user_id)
->where('unique_id', $restore_item['unique_id'])
->first();
// Restore item to home directory
if ($request->has('to_home') && $request->to_home) {
$item->folder_id = 0;
$item->save();
}
}
} else {
// Get item
$item = FileManagerFile::onlyTrashed()
->where('user_id', $user_id)
->where('unique_id', $unique_id)
->first();
// Restore item to home directory
if ($request->has('to_home') && $request->to_home) {
$item->folder_id = 0;
$item->save();
}
// Restore Item
$item->restore();
}
// Restore Item
$item->restore();
// Return response
return response('Done!', 204);
}

View File

@@ -466,19 +466,16 @@ class SetupWizardController extends Controller
]);
// Create legal pages and index content
if ($request->license === 'Extended') {
$pages = collect(config('content.pages'));
$content = $request->license === 'Extended' ? collect(config('content.content_extended')) : collect(config('content.content_regular'));
$pages = collect(config('content.pages'));
$content = collect(config('content.content'));
$content->each(function ($content) {
Setting::updateOrCreate($content);
});
$content->each(function ($content) {
Setting::updateOrCreate($content);
});
$pages->each(function ($page) {
Page::updateOrCreate($page);
});
}
$pages->each(function ($page) {
Page::updateOrCreate($page);
});
// Retrieve access token
$response = Route::dispatch(self::make_login_request($request));

View File

@@ -11,119 +11,6 @@ use Schema;
class UpgradeAppController extends Controller
{
/**
* Upgrade account from 1.6 to 1.7
*
* @param Request $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function upgrade(Request $request)
{
$upgraded = Setting::where('name', 'latest_upgrade')->first();
if ($upgraded && $upgraded->value === '1.7') abort(401);
// Create legal pages and index content
if ($request->license === 'Extended') {
$pages = collect(config('content.pages'));
$content = collect(config('content.content'));
$content->each(function ($content) {
Setting::updateOrCreate($content);
});
$pages->each(function ($page) {
Page::updateOrCreate($page);
});
}
// Store Logo
if ($request->hasFile('logo')) {
$logo = store_system_image($request->file('logo'), 'system');
}
// Store Logo horizontal
if ($request->hasFile('logo_horizontal')) {
$logo_horizontal = store_system_image($request->file('logo_horizontal'), 'system');
}
// Store favicon
if ($request->hasFile('favicon')) {
$favicon = store_system_image($request->file('favicon'), 'system');
}
// Get options
$settings = collect([
[
'name' => 'setup_wizard_database',
'value' => 1,
],
[
'name' => 'setup_wizard_success',
'value' => 1,
],
[
'name' => 'license',
'value' => $request->license,
],
[
'name' => 'purchase_code',
'value' => $request->purchase_code,
],
[
'name' => 'app_title',
'value' => $request->title,
],
[
'name' => 'app_description',
'value' => $request->description,
],
[
'name' => 'app_logo',
'value' => $request->hasFile('logo') ? $logo : null,
],
[
'name' => 'app_logo_horizontal',
'value' => $request->hasFile('logo_horizontal') ? $logo_horizontal : null,
],
[
'name' => 'app_favicon',
'value' => $request->hasFile('favicon') ? $favicon : null,
],
[
'name' => 'google_analytics',
'value' => $request->googleAnalytics,
],
[
'name' => 'contact_email',
'value' => $request->contactMail,
],
[
'name' => 'registration',
'value' => $request->userRegistration,
],
[
'name' => 'storage_limitation',
'value' => $request->storageLimitation,
],
[
'name' => 'storage_default',
'value' => $request->defaultStorage ? $request->defaultStorage : 5,
],
[
'name' => 'latest_upgrade',
'value' => '1.7',
],
]);
// Store options
$settings->each(function ($col) {
Setting::updateOrCreate(['name' => $col['name']], $col);
});
return response('Done', 200);
}
/**
* Start maintenance mode
@@ -150,8 +37,33 @@ class UpgradeAppController extends Controller
/**
* Upgrade database
*/
public function upgrade_database()
public function upgrade()
{
/*
* Upgrade user_settings & file_manager_folders table
*
* @since v1.8.1
*/
if (! Schema::hasColumn('user_settings', 'timezone') && ! Schema::hasColumn('file_manager_folders', 'icon_color')) {
$this->upgrade_database();
// Create legal pages and index content for regular license
if (get_setting('license') === 'Regular') {
$pages = collect(config('content.pages'));
$content = collect(config('content.content_regular'));
$content->each(function ($content) {
Setting::updateOrCreate($content);
});
$pages->each(function ($page) {
Page::updateOrCreate($page);
});
}
}
/*
* Upgrade expire_in in shares table
*
@@ -159,17 +71,16 @@ class UpgradeAppController extends Controller
*/
if (! Schema::hasTable('traffic') && ! Schema::hasTable('zips') && ! Schema::hasTable('jobs')) {
$command = Artisan::call('migrate', [
'--force' => true
]);
$this->upgrade_database();
}
/*
* Upgrade expire_in in shares table
*
* @since v1.8
*/
if (! Schema::hasTable('traffic') && ! Schema::hasTable('zips') && ! Schema::hasTable('jobs')) {
if ($command === 0) {
echo 'Operation was successful.';
}
if ($command === 1) {
echo 'Operation failed.';
}
$this->upgrade_database();
}
/*
@@ -179,17 +90,7 @@ class UpgradeAppController extends Controller
*/
if (! Schema::hasColumn('shares', 'expire_in')) {
$command = Artisan::call('migrate', [
'--force' => true
]);
if ($command === 0) {
echo 'Operation was successful.';
}
if ($command === 1) {
echo 'Operation failed.';
}
$this->upgrade_database();
}
/*
@@ -199,17 +100,26 @@ class UpgradeAppController extends Controller
*/
if (! Schema::hasColumn('file_manager_files', 'metadata')) {
$command = Artisan::call('migrate', [
'--force' => true
]);
if ($command === 0) {
echo 'Operation was successful.';
}
if ($command === 1) {
echo 'Operation failed.';
}
$this->upgrade_database();
}
}
/**
* @return int|mixed
*/
private function upgrade_database()
{
$command = Artisan::call('migrate', [
'--force' => true
]);
if ($command === 0) {
echo 'Operation was successful.';
}
if ($command === 1) {
echo 'Operation failed.';
}
return $command;
}
}

View File

@@ -2,6 +2,7 @@
use App\FileManagerFile;
use App\FileManagerFolder;
use App\User;
use App\Setting;
use App\Share;
use ByteUnits\Metric;
@@ -558,7 +559,17 @@ function get_pretty_name($basename, $name, $mimetype)
function get_image_meta_data($file)
{
if (get_file_type_from_mimetype($file->getMimeType()) === 'jpeg') {
return exif_read_data($file);
try {
// Try to get the exif data
return mb_convert_encoding(Image::make($file->getRealPath())->exif(),'UTF8', 'UTF8');
} catch ( \Exception $e) {
return null;
}
}
}
@@ -733,3 +744,61 @@ function remove_accents($string) {
return $string;
}
/**
* Get all files from folder and get their folder location in VueFileManager directories
*
* @param $folders
* @param null $files
* @param array $path
* @return array
*/
function get_files_for_zip($folders, $files, $path = [])
{
// Return file list
if (!isset($folders->folders)) {
return $files->unique()->values()->all();
}
// Push file path
array_push($path, $folders->name);
// Push file to collection
$folders->files->each(function ($file) use ($files, $path) {
$files->push([
'name' => $file->name,
'basename' => $file->basename,
'folder_path' => implode('/', $path),
]);
});
// Get all children folders and folders within
if ($folders->folders->isNotEmpty()) {
$folders->folders->map(function ($folder) use ($files, $path) {
return get_files_for_zip($folder, $files, $path);
});
}
return get_files_for_zip($folders->folders->first(), $files, $path);
}
/**
* Set time by user timezone GMT
*
* @param $time
* @return int
*/
function set_time_by_user_timezone($time)
{
$user = Auth::user();
if($user) {
// Get the value of timezone if user have some
$time_zone = intval($user->settings->timezone * 60 ?? null);
return Carbon::parse($time)->addMinutes($time_zone ?? null);
}
return Carbon::parse($time);
}

View File

@@ -31,6 +31,7 @@ class CreateShareRequest extends FormRequest
'expiration' => 'integer|nullable',
'permission' => 'string',
'password' => 'string',
'emails.*' => 'email'
];
}
}

View File

@@ -76,7 +76,16 @@ class UserResource extends JsonResource
'folders' => $this->folder_tree
],
],
]
],
'timezone' => [
'data' => [
'id' => '1',
'type' => 'timezone',
'attributes' => [
'timezone' =>$this->settings->timezone
],
]
],
]
];
}

View File

@@ -26,6 +26,116 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
class Editor
{
/**
* Store folder icon
*
* @param $folder_icon
* @param $unique_id
* @param $shared
*/
public static function set_folder_icon ($folder_icon, $unique_id, $shared = null)
{
$user_id = is_null($shared) ? Auth::id() : $shared->user_id;
// Get folder
$folder = FileManagerFolder::where('user_id', $user_id)
->where('unique_id', $unique_id)
->first();
// If request have emoji set folder icon emoji
if(isset($folder_icon['emoji'])) {
$folder->icon_emoji = $folder_icon['emoji'];
$folder->icon_color = null;
}
// If request have color set folder icon color
if(isset($folder_icon['color'])) {
$folder->icon_emoji = null;
$folder->icon_color = $folder_icon['color'];
}
// Save changes
$folder->save();
}
/**
* Zip requested folder
*
* @param $unique_id
* @param $shared
* @return mixed
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public static function zip_folder($unique_id, $shared = null)
{
// Get folder
$requested_folder = FileManagerFolder::with(['folders.files', 'files'])
->where('unique_id', $unique_id)
->where('user_id', Auth::id() ?? $shared->user_id)
->with('folders')
->first();
$files = get_files_for_zip($requested_folder, collect([]));
// Local storage instance
$disk_local = Storage::disk('local');
// Create zip directory
if (!$disk_local->exists('zip')) {
$disk_local->makeDirectory('zip');
}
// Move file to local storage
if (!is_storage_driver('local')) {
// Create temp directory
if (!$disk_local->exists('temp')) {
$disk_local->makeDirectory('temp');
}
foreach ($files as $file) {
try {
$disk_local->put('temp/' . $file['basename'], Storage::get('file-manager/' . $file['basename']));
} catch (FileNotFoundException $e) {
throw new HttpException(404, 'File not found');
}
}
}
// Get zip path
$zip_name = Str::random(16) . '-' . Str::slug($requested_folder->name) . '.zip';
$zip_path = 'zip/' . $zip_name;
// Create zip
$zip = Madzipper::make(storage_path() . '/app/' . $zip_path);
// Get files folder on local storage drive
$files_folder = is_storage_driver('local') ? 'file-manager' : 'temp';
// Add files to zip
foreach ($files as $file) {
$zip->folder($file['folder_path'])->addString($file['name'], File::get(storage_path() . '/app/' . $files_folder . '/' . $file['basename']));
}
// Close zip
$zip->close();
// Delete temporary files
if (!is_storage_driver('local')) {
foreach ($files as $file) {
$disk_local->delete('temp/' . $file['basename']);
}
}
// Store zip record
return Zip::create([
'user_id' => $shared->user_id ?? Auth::id(),
'shared_token' => $shared->token ?? null,
'basename' => $zip_name,
]);
}
/**
* Zip selected files, store it in /zip folder and retrieve zip record
@@ -329,7 +439,7 @@ class Editor
$temp_filename = $file->getClientOriginalName();
// File Path
$file_path = config('filesystems.disks.local.root') . '/chunks/' . $temp_filename;\
$file_path = config('filesystems.disks.local.root') . '/chunks/' . $temp_filename;
// Generate file
File::append($file_path, $file->get());

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Auth;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class SharedSendViaEmail extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*
* @param $token
*/
public function __construct($token)
{
$this->token = $token;
$this->user = Auth::user();
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject(__('vuefilemanager.shared_link_email_subject' , ['user' => $this->user->name]))
->greeting(__('vuefilemanager.shared_link_email_greeting'))
->line(__('vuefilemanager.shared_link_email_user', ['user' => $this->user->name, 'email' => $this->user->email]))
->action(__('vuefilemanager.shared_link_email_link'), url('/shared', ['token' => $this->token]));
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}

View File

@@ -3,6 +3,8 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Notifications\SharedSendViaEmail;
use Illuminate\Notifications\Notifiable;
/**
* App\Share
@@ -37,6 +39,8 @@ use Illuminate\Database\Eloquent\Model;
*/
class Share extends Model
{
use Notifiable;
protected $guarded = ['id'];
protected $appends = ['link'];
@@ -46,8 +50,8 @@ class Share extends Model
*
* @return string
*/
public function getLinkAttribute() {
public function getLinkAttribute()
{
return url('/shared', ['token' => $this->attributes['token']]);
}
}

View File

@@ -1,27 +1,97 @@
<?php
return [
'pages' => [
'pages' => [
[
'visibility' => 1,
'visibility' => 0,
'title' => 'Terms of Service',
'slug' => 'terms-of-service',
'content' => 'Laoreet cum hendrerit iaculis arcu phasellus congue et elementum, pharetra risus imperdiet aptent posuere rutrum parturient blandit, dapibus tellus ridiculus potenti aliquam sociis turpis. Nullam commodo eget laoreet risus cursus vel placerat, in dapibus sociis gravida faucibus sodales, fringilla potenti elit semper iaculis ullamcorper. Dignissim vulputate pretium montes pellentesque mollis, consectetur adipiscing curabitur semper sem rhoncus, litora viverra curae proin.',
],
[
'visibility' => 1,
'visibility' => 0,
'title' => 'Privacy Policy',
'slug' => 'privacy-policy',
'content' => 'Sit orci justo augue maecenas laoreet consectetur natoque magnis in viverra sagittis, himenaeos urna facilisis mus proin primis diam accumsan tristique inceptos. Primis quisque posuere sit praesent lobortis feugiat semper convallis facilisis, vivamus gravida ligula nostra curae eu donec duis parturient senectus, arcu dolor viverra penatibus natoque cum nisi commodo. Litora sociis mauris justo nullam suspendisse mattis maecenas nascetur congue phasellus cras ultricies posuere donec, dapibus egestas diam lacus ornare montes senectus tincidunt eu taciti sed consequat.',
],
[
'visibility' => 1,
'visibility' => 0,
'title' => 'Cookie Policy',
'slug' => 'cookie-policy',
'content' => 'Metus penatibus ligula dolor natoque non habitasse laoreet facilisis, libero vivamus eget semper vulputate interdum integer, phasellus lorem enim blandit consectetur nullam sollicitudin. Hendrerit interdum luctus ut in molestie himenaeos eros cum laoreet parturient est, eu lectus hac et netus viverra dictumst congue elit sem senectus litora, fames scelerisque adipiscing inceptos fringilla montes sociosqu suscipit auctor potenti. Elementum lacus vulputate viverra ac morbi ligula ipsum facilisi, sit eu imperdiet lacinia congue dis vitae.',
],
],
'content' => [
'content_regular' => [
[
'name' => 'section_features',
'value' => 0,
],
[
'name' => 'section_feature_boxes',
'value' => 0,
],
[
'name' => 'section_get_started',
'value' => 0,
],
[
'name' => 'header_title',
'value' => 'Simple <span style="color: #41B883">&</span> Powerful Personal Cloud Storage',
],
[
'name' => 'header_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
],
[
'name' => 'features_title',
'value' => 'The Fastest Growing <span style="color: #41B883">File Manager</span> on the CodeCanyon Market',
],
[
'name' => 'features_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
],
[
'name' => 'feature_title_1',
'value' => 'Truly Freedom',
],
[
'name' => 'feature_description_1',
'value' => 'You have full control over VueFileManager, no third authorities will control your service or usage, only you.',
],
[
'name' => 'feature_title_2',
'value' => 'The Sky is the Limit',
],
[
'name' => 'feature_description_2',
'value' => 'VueFileManager is cloud storage software. You have to install and running application on your own server hosting.',
],
[
'name' => 'feature_title_3',
'value' => 'No Monthly Fees',
],
[
'name' => 'feature_description_3',
'value' => 'When you running VueFileManager on your own server hosting, anybody can\'t control your content or resell your user data. Your data is safe.',
],
[
'name' => 'get_started_title',
'value' => 'Ready to Get <span style="color: #41B883">Started</span><br> With Us?',
],
[
'name' => 'get_started_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
],
[
'name' => 'footer_content',
'value' => '© 2021 Simple & Powerful Personal Cloud Storage. Developed by <a href="https://hi5ve.digital" target="_blank">Hi5Ve.Digital</a>',
],
[
'name' => 'allow_homepage',
'value' => 0,
],
],
'content_extended' => [
[
'name' => 'section_features',
'value' => '1',
@@ -96,7 +166,7 @@ return [
],
[
'name' => 'footer_content',
'value' => '© 2020 Simple & Powerful Personal Cloud Storage. Developed by <a href="https://hi5ve.digital" target="_blank">Hi5Ve.Digital</a>',
'value' => '© 2021 Simple & Powerful Personal Cloud Storage. Developed by <a href="https://hi5ve.digital" target="_blank">Hi5Ve.Digital</a>',
],
],
];

View File

@@ -2,7 +2,7 @@
return [
'version' => '1.8.0.2',
'version' => '1.8.1',
// Define size of chunk uploaded by MB. E.g. integer 128 means chunk size will be 128MB.
'chunk_size' => env('CHUNK_SIZE', '128'),

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddTimezoneToUserSettingsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('user_settings', function (Blueprint $table) {
$table->decimal('timezone', 10, 1)->after('billing_phone_number')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('user_settings', function (Blueprint $table) {
//
});
}
}

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddFolderIconOptionsToFileManagerFoldersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('file_manager_folders', function (Blueprint $table) {
$table->string('icon_color')->after('user_scope')->nullable();
$table->string('icon_emoji')->after('icon_color')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('file_manager_folders', function (Blueprint $table) {
//
});
}
}

50
package-lock.json generated
View File

@@ -10003,6 +10003,53 @@
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
"twemoji": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/twemoji/-/twemoji-13.0.1.tgz",
"integrity": "sha512-mrTBq+XpCLM4zm76NJOjLHoQNV9mHdBt3Cba/T5lS1rxn8ArwpqE47mqTocupNlkvcLxoeZJjYSUW0DU5ZwqZg==",
"requires": {
"fs-extra": "^8.0.1",
"jsonfile": "^5.0.0",
"twemoji-parser": "13.0.0",
"universalify": "^0.1.2"
},
"dependencies": {
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
},
"dependencies": {
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"requires": {
"graceful-fs": "^4.1.6"
}
}
}
},
"jsonfile": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-5.0.0.tgz",
"integrity": "sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w==",
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^0.1.2"
}
}
}
},
"twemoji-parser": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/twemoji-parser/-/twemoji-parser-13.0.0.tgz",
"integrity": "sha512-zMaGdskpH8yKjT2RSE/HwE340R4Fm+fbie4AaqjDa4H/l07YUmAvxkSfNl6awVWNRRQ0zdzLQ8SAJZuY5MgstQ=="
},
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
@@ -10124,8 +10171,7 @@
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"unpipe": {
"version": "1.0.0",

View File

@@ -23,6 +23,7 @@
"@fortawesome/vue-fontawesome": "^0.1.10",
"lodash": "^4.17.20",
"node-sass": "^4.14.1",
"twemoji": "^13.0.1",
"vee-validate": "^3.3.9",
"vue": "^2.6.11",
"vue-feather-icons": "^5.1.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 KiB

After

Width:  |  Height:  |  Size: 649 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 KiB

After

Width:  |  Height:  |  Size: 636 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{"2wZp":function(t,e,n){"use strict";var i=n("Mlra");n.n(i).a},"6Rdq":function(t,e,n){"use strict";var i=n("9Q3x"),r=n("yMep"),o=n("c4kp"),s=n("2QtR"),a=n("L2JU"),c=n("xCqy");function l(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,i)}return n}function p(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var u={name:"FilesView",components:{DesktopSortingAndPreview:i.a,DesktopToolbar:r.a,FileBrowser:o.a,ContextMenu:s.a},computed:function(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?l(Object(n),!0).forEach((function(e){p(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}({},Object(a.b)(["config"])),methods:{contextMenu:function(t,e){c.a.$emit("contextMenu:show",t,e)}}},d=(n("2wZp"),n("KHd+")),f=Object(d.a)(u,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{attrs:{id:"files-view"},on:{"!contextmenu":function(e){return e.preventDefault(),t.contextMenu(e,void 0)}}},[n("ContextMenu"),t._v(" "),n("DesktopSortingAndPreview"),t._v(" "),n("DesktopToolbar"),t._v(" "),n("FileBrowser")],1)}),[],!1,null,null,null);e.a=f.exports},CoTS:function(t,e,n){"use strict";n.r(e);var i=n("6Rdq"),r=n("LtV2"),o=n("hXay"),s=n("CjXH"),a={name:"FilesView",components:{ContentFileView:i.a,ContentSidebar:r.a,ContentGroup:o.a,LinkIcon:s.E,UsersIcon:s.bb},methods:{getShared:function(){this.$store.dispatch("getShared",[{back:!1,init:!1}])},getParticipantUploads:function(){this.$store.dispatch("getParticipantUploads")}},mounted:function(){this.getShared()}},c=n("KHd+"),l=Object(c.a)(a,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("section",{attrs:{id:"viewport"}},[n("ContentSidebar",[n("ContentGroup",{attrs:{title:t.$t("sidebar.locations_title")}},[n("div",{staticClass:"menu-list-wrapper vertical"},[n("li",{staticClass:"menu-list-item link",class:{"is-active":t.$isThisLocation(["shared"])},on:{click:function(e){return t.getShared()}}},[n("div",{staticClass:"icon"},[n("link-icon",{attrs:{size:"17"}})],1),t._v(" "),n("div",{staticClass:"label"},[t._v("\n "+t._s(t.$t("sidebar.my_shared"))+"\n ")])]),t._v(" "),n("li",{staticClass:"menu-list-item link",class:{"is-active":t.$isThisLocation(["participant_uploads"])},on:{click:function(e){return t.getParticipantUploads()}}},[n("div",{staticClass:"icon"},[n("users-icon",{attrs:{size:"17"}})],1),t._v(" "),n("div",{staticClass:"label"},[t._v("\n "+t._s(t.$t("sidebar.participant_uploads"))+"\n ")])])])])],1),t._v(" "),n("ContentFileView")],1)}),[],!1,null,"fd8b19c0",null);e.default=l.exports},Mlra:function(t,e,n){var i=n("Q8SN");"string"==typeof i&&(i=[[t.i,i,""]]);var r={hmr:!0,transform:void 0,insertInto:void 0};n("aET+")(i,r);i.locals&&(t.exports=i.locals)},Q8SN:function(t,e,n){(t.exports=n("I1BE")(!1)).push([t.i,"#files-view {\n font-family: 'Nunito', sans-serif;\n font-size: 16px;\n width: 100%;\n height: 100%;\n position: relative;\n min-width: 320px;\n overflow-x: hidden;\n padding-left: 15px;\n padding-right: 15px;\n overflow-y: hidden;\n}\n@media only screen and (max-width: 690px) {\n#files-view {\n padding-left: 0;\n padding-right: 0;\n}\n}\n",""])}}]);
(window.webpackJsonp=window.webpackJsonp||[]).push([[43],{"2wZp":function(t,e,n){"use strict";var i=n("Mlra");n.n(i).a},"6Rdq":function(t,e,n){"use strict";var i=n("9Q3x"),r=n("yMep"),o=n("c4kp"),s=n("2QtR"),a=n("L2JU"),c=n("xCqy");function l(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,i)}return n}function p(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var d={name:"FilesView",components:{DesktopSortingAndPreview:i.a,DesktopToolbar:r.a,FileBrowser:o.a,ContextMenu:s.a},computed:function(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{};e%2?l(Object(n),!0).forEach((function(e){p(t,e,n[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):l(Object(n)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))}))}return t}({},Object(a.b)(["config"])),methods:{contextMenu:function(t,e){c.a.$emit("contextMenu:show",t,e)}}},u=(n("2wZp"),n("KHd+")),f=Object(u.a)(d,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{attrs:{id:"files-view"},on:{"!contextmenu":function(e){return e.preventDefault(),t.contextMenu(e,void 0)}}},[n("ContextMenu"),t._v(" "),n("DesktopSortingAndPreview"),t._v(" "),n("DesktopToolbar"),t._v(" "),n("FileBrowser")],1)}),[],!1,null,null,null);e.a=f.exports},CoTS:function(t,e,n){"use strict";n.r(e);var i=n("6Rdq"),r=n("LtV2"),o=n("hXay"),s=n("CjXH"),a={name:"FilesView",components:{ContentFileView:i.a,ContentSidebar:r.a,ContentGroup:o.a,LinkIcon:s.E,UsersIcon:s.db},methods:{getShared:function(){this.$store.dispatch("getShared",[{back:!1,init:!1}])},getParticipantUploads:function(){this.$store.dispatch("getParticipantUploads")}},mounted:function(){this.getShared()}},c=n("KHd+"),l=Object(c.a)(a,(function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("section",{attrs:{id:"viewport"}},[n("ContentSidebar",[n("ContentGroup",{attrs:{title:t.$t("sidebar.locations_title")}},[n("div",{staticClass:"menu-list-wrapper vertical"},[n("li",{staticClass:"menu-list-item link",class:{"is-active":t.$isThisLocation(["shared"])},on:{click:function(e){return t.getShared()}}},[n("div",{staticClass:"icon"},[n("link-icon",{attrs:{size:"17"}})],1),t._v(" "),n("div",{staticClass:"label"},[t._v("\n "+t._s(t.$t("sidebar.my_shared"))+"\n ")])]),t._v(" "),n("li",{staticClass:"menu-list-item link",class:{"is-active":t.$isThisLocation(["participant_uploads"])},on:{click:function(e){return t.getParticipantUploads()}}},[n("div",{staticClass:"icon"},[n("users-icon",{attrs:{size:"17"}})],1),t._v(" "),n("div",{staticClass:"label"},[t._v("\n "+t._s(t.$t("sidebar.participant_uploads"))+"\n ")])])])])],1),t._v(" "),n("ContentFileView")],1)}),[],!1,null,"fd8b19c0",null);e.default=l.exports},Mlra:function(t,e,n){var i=n("Q8SN");"string"==typeof i&&(i=[[t.i,i,""]]);var r={hmr:!0,transform:void 0,insertInto:void 0};n("aET+")(i,r);i.locals&&(t.exports=i.locals)},Q8SN:function(t,e,n){(t.exports=n("I1BE")(!1)).push([t.i,"#files-view {\n font-family: 'Nunito', sans-serif;\n font-size: 16px;\n width: 100%;\n height: 100%;\n position: relative;\n min-width: 320px;\n overflow-x: hidden;\n padding-left: 15px;\n padding-right: 15px;\n overflow-y: hidden;\n}\n@media only screen and (max-width: 690px) {\n#files-view {\n padding-left: 0;\n padding-right: 0;\n}\n}\n",""])}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
public/css/app.css vendored

File diff suppressed because one or more lines are too long

2
public/js/main.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,65 +1,65 @@
{
"/chunks/files~chunks/shared-files~chunks/shared-page.js": "/chunks/files~chunks/shared-files~chunks/shared-page.js?id=6f92f91cd55e4196332e",
"/js/main.js": "/js/main.js?id=e8894d3950c9beed4fac",
"/css/app.css": "/css/app.css?id=8f6d5dcb7110a726e142",
"/chunks/admin.js": "/chunks/admin.js?id=e79f03760dd792065e39",
"/chunks/admin-account.js": "/chunks/admin-account.js?id=ee790061a19bc95065e7",
"/chunks/app-appearance.js": "/chunks/app-appearance.js?id=9b4372004796098c4342",
"/chunks/app-billings.js": "/chunks/app-billings.js?id=afd381a2e9c5a197c903",
"/chunks/app-email.js": "/chunks/app-email.js?id=6c69211c91b0807383db",
"/chunks/app-index.js": "/chunks/app-index.js?id=032068b59885a15384da",
"/chunks/app-others.js": "/chunks/app-others.js?id=2d12f866294128405962",
"/chunks/app-payments.js": "/chunks/app-payments.js?id=8ee9629110f5a125d981",
"/chunks/app-settings.js": "/chunks/app-settings.js?id=8cd72a89e9315a693bac",
"/chunks/app-setup.js": "/chunks/app-setup.js?id=f75223c444a94ead6fa1",
"/chunks/billings-detail.js": "/chunks/billings-detail.js?id=38e051f88505b88a42bf",
"/chunks/contact-us.js": "/chunks/contact-us.js?id=27312366ac591bd2a6f4",
"/chunks/files~chunks/shared-files~chunks/shared-page.js": "/chunks/files~chunks/shared-files~chunks/shared-page.js?id=42d1881aa3cd2b5a0e21",
"/js/main.js": "/js/main.js?id=86eb60282c3151df7fa7",
"/css/app.css": "/css/app.css?id=dfd52fc997b919cd3686",
"/chunks/admin.js": "/chunks/admin.js?id=7672646537b5813becf0",
"/chunks/admin-account.js": "/chunks/admin-account.js?id=3f5a34aa8341af8d2b4c",
"/chunks/app-appearance.js": "/chunks/app-appearance.js?id=9ec9a42482cb302a05f6",
"/chunks/app-billings.js": "/chunks/app-billings.js?id=92903bd1d316b3db1dfa",
"/chunks/app-email.js": "/chunks/app-email.js?id=9d646578982ba61813b6",
"/chunks/app-index.js": "/chunks/app-index.js?id=4623bd961647897a5b81",
"/chunks/app-others.js": "/chunks/app-others.js?id=b19a701cdfa06e4817ff",
"/chunks/app-payments.js": "/chunks/app-payments.js?id=11c86d822269f1a1577e",
"/chunks/app-settings.js": "/chunks/app-settings.js?id=6784314933372fb1adf0",
"/chunks/app-setup.js": "/chunks/app-setup.js?id=d304bcf7d4157e81f3e2",
"/chunks/billings-detail.js": "/chunks/billings-detail.js?id=b73a5b6f7d2a448cc5ab",
"/chunks/contact-us.js": "/chunks/contact-us.js?id=81906d205ba0107c5105",
"/chunks/create-new-password.js": "/chunks/create-new-password.js?id=004908727045abd0852e",
"/chunks/dashboard.js": "/chunks/dashboard.js?id=b37c48e90323f1276385",
"/chunks/database.js": "/chunks/database.js?id=8d25d86c109fe2e20cc9",
"/chunks/dashboard.js": "/chunks/dashboard.js?id=08e4f7d923ce9e49dcc3",
"/chunks/database.js": "/chunks/database.js?id=b8d8269f77c52f78c784",
"/chunks/dynamic-page.js": "/chunks/dynamic-page.js?id=2e3af103d13536c50757",
"/chunks/environment-setup.js": "/chunks/environment-setup.js?id=95a76efcbd60ade7ae8d",
"/chunks/files.js": "/chunks/files.js?id=9f7d14e864ad595c75b8",
"/chunks/environment-setup.js": "/chunks/environment-setup.js?id=106f81cefe76c62d476e",
"/chunks/files.js": "/chunks/files.js?id=b213d4fe15c2a9933f32",
"/chunks/forgotten-password.js": "/chunks/forgotten-password.js?id=95ce5e5685dc9315f515",
"/chunks/installation-disclaimer.js": "/chunks/installation-disclaimer.js?id=3ad1fe9e22348bac9add",
"/chunks/invoices.js": "/chunks/invoices.js?id=0a6586dd3169a1a24cc7",
"/chunks/landing-page.js": "/chunks/landing-page.js?id=8028fa31b01b287be989",
"/chunks/installation-disclaimer.js": "/chunks/installation-disclaimer.js?id=6db12008aa646ad5fb6f",
"/chunks/invoices.js": "/chunks/invoices.js?id=83389adf0760820af6f5",
"/chunks/landing-page.js": "/chunks/landing-page.js?id=546ed735edf0d80c8a7e",
"/chunks/not-found-shared.js": "/chunks/not-found-shared.js?id=848666d6c49c613f7f99",
"/chunks/page-edit.js": "/chunks/page-edit.js?id=bd41ae13951c2a5025c3",
"/chunks/pages.js": "/chunks/pages.js?id=8af814ea8d2b799cafbc",
"/chunks/plan.js": "/chunks/plan.js?id=c7734358550edf510972",
"/chunks/plan-create.js": "/chunks/plan-create.js?id=02557829a165a4244037",
"/chunks/plan-delete.js": "/chunks/plan-delete.js?id=5dce9b126b1bfdfb15f8",
"/chunks/plan-settings.js": "/chunks/plan-settings.js?id=9d71d419c6513f37cc31",
"/chunks/plan-subscribers.js": "/chunks/plan-subscribers.js?id=932a409548a43699a335",
"/chunks/plans.js": "/chunks/plans.js?id=e131a500fb080d44c5b1",
"/chunks/profile.js": "/chunks/profile.js?id=6864af1dd72ba9f5d701",
"/chunks/purchase-code.js": "/chunks/purchase-code.js?id=96913b57f214cf91e9ff",
"/chunks/settings.js": "/chunks/settings.js?id=98e238110e8c4a3fadc0",
"/chunks/settings-create-payment-methods.js": "/chunks/settings-create-payment-methods.js?id=3261532853614f8e83c7",
"/chunks/settings-invoices.js": "/chunks/settings-invoices.js?id=cd6984f9d5f4a295fc77",
"/chunks/pages.js": "/chunks/pages.js?id=df7245abef9e3b77a218",
"/chunks/plan.js": "/chunks/plan.js?id=cfd7b4ee7e21639a837d",
"/chunks/plan-create.js": "/chunks/plan-create.js?id=9bb62af36193ee9648d3",
"/chunks/plan-delete.js": "/chunks/plan-delete.js?id=7b7601f044e0ef47720b",
"/chunks/plan-settings.js": "/chunks/plan-settings.js?id=8d3e75ff9adb22a25d57",
"/chunks/plan-subscribers.js": "/chunks/plan-subscribers.js?id=3b4a29497fc878f503db",
"/chunks/plans.js": "/chunks/plans.js?id=feb924949bffcdf3d9fb",
"/chunks/profile.js": "/chunks/profile.js?id=f990697f8d4ff45df434",
"/chunks/purchase-code.js": "/chunks/purchase-code.js?id=5d7406ecd84c676db8fb",
"/chunks/settings.js": "/chunks/settings.js?id=d16d9e2cda6aa3a3f6dc",
"/chunks/settings-create-payment-methods.js": "/chunks/settings-create-payment-methods.js?id=b05e24dd8be60f62ee27",
"/chunks/settings-invoices.js": "/chunks/settings-invoices.js?id=72d317b39264987e6ed0",
"/chunks/settings-password.js": "/chunks/settings-password.js?id=014597c63c94d3ac9f60",
"/chunks/settings-payment-methods.js": "/chunks/settings-payment-methods.js?id=de5336048bc08c15d898",
"/chunks/settings-storage.js": "/chunks/settings-storage.js?id=711b33d8a692cdb4803f",
"/chunks/settings-subscription.js": "/chunks/settings-subscription.js?id=fedeba9f333b20bd4e7f",
"/chunks/settings-payment-methods.js": "/chunks/settings-payment-methods.js?id=2a0ea9cf661deba6fc13",
"/chunks/settings-storage.js": "/chunks/settings-storage.js?id=b3f25de02dd4ef072df0",
"/chunks/settings-subscription.js": "/chunks/settings-subscription.js?id=aa3d963f578d7bc5ff88",
"/chunks/setup-wizard.js": "/chunks/setup-wizard.js?id=47090233afc7b0cdf855",
"/chunks/shared-files.js": "/chunks/shared-files.js?id=4999dc298d5b5f112199",
"/chunks/shared-page.js": "/chunks/shared-page.js?id=c947a35f01f93ab6633d",
"/chunks/sign-in.js": "/chunks/sign-in.js?id=a0478dcfe7a0fac4cec3",
"/chunks/sign-up.js": "/chunks/sign-up.js?id=7fe81882ef9104c1077f",
"/chunks/stripe-credentials.js": "/chunks/stripe-credentials.js?id=867925c1349f73b17007",
"/chunks/subscription-plans.js": "/chunks/subscription-plans.js?id=d96da77e778c983afe61",
"/chunks/subscription-service.js": "/chunks/subscription-service.js?id=a6f6db1c5149dcbdffb2",
"/chunks/upgrade.js": "/chunks/upgrade.js?id=153edcbb43f83e02a608",
"/chunks/upgrade-billing.js": "/chunks/upgrade-billing.js?id=ae093d8358a732ea0739",
"/chunks/shared-files.js": "/chunks/shared-files.js?id=ba10fd3f52a7b62d3092",
"/chunks/shared-page.js": "/chunks/shared-page.js?id=4489cb4cfa33fb249bea",
"/chunks/sign-in.js": "/chunks/sign-in.js?id=c52ce81c3dad56d7a7d8",
"/chunks/sign-up.js": "/chunks/sign-up.js?id=2f12850d320b2413cf54",
"/chunks/stripe-credentials.js": "/chunks/stripe-credentials.js?id=6622381f1d96e8319999",
"/chunks/subscription-plans.js": "/chunks/subscription-plans.js?id=f1b093a3bcfebd5bc8a5",
"/chunks/subscription-service.js": "/chunks/subscription-service.js?id=e0e2f821aac16b32da34",
"/chunks/upgrade.js": "/chunks/upgrade.js?id=0c8d40bed72e86359529",
"/chunks/upgrade-billing.js": "/chunks/upgrade-billing.js?id=a8db2246f9326e5c5957",
"/chunks/upgrade-plan.js": "/chunks/upgrade-plan.js?id=f050f10627424b730dc2",
"/chunks/user.js": "/chunks/user.js?id=c623fa2a9df7e87f5e47",
"/chunks/user-create.js": "/chunks/user-create.js?id=9a366b08828fbf9d1576",
"/chunks/user-delete.js": "/chunks/user-delete.js?id=3d19351cacce370511f5",
"/chunks/user-detail.js": "/chunks/user-detail.js?id=fd98258fb7f4f80a3768",
"/chunks/user-invoices.js": "/chunks/user-invoices.js?id=87f509205536493604f4",
"/chunks/user-password.js": "/chunks/user-password.js?id=8b59c799e132b6b10e18",
"/chunks/user-storage.js": "/chunks/user-storage.js?id=fe93fb8fbc7d1f1080bc",
"/chunks/user-subscription.js": "/chunks/user-subscription.js?id=b1e8f6ca454e5586a4f5",
"/chunks/users.js": "/chunks/users.js?id=22c7c7a9073162f6a328"
"/chunks/user.js": "/chunks/user.js?id=6f2ab796211a3ac8670f",
"/chunks/user-create.js": "/chunks/user-create.js?id=0d630acda4552c315417",
"/chunks/user-delete.js": "/chunks/user-delete.js?id=db041eae3aef3e45197a",
"/chunks/user-detail.js": "/chunks/user-detail.js?id=8cf2fe554e8d67ac8677",
"/chunks/user-invoices.js": "/chunks/user-invoices.js?id=a0613909cb0c21817804",
"/chunks/user-password.js": "/chunks/user-password.js?id=653bba3eb8d117c3a043",
"/chunks/user-storage.js": "/chunks/user-storage.js?id=630b0ff649e16d3627af",
"/chunks/user-subscription.js": "/chunks/user-subscription.js?id=0b4226ba77f10b83de4a",
"/chunks/users.js": "/chunks/users.js?id=04ca09662595fae56488"
}

View File

@@ -12,6 +12,7 @@
<!--Mobile Navigation-->
<MobileNavigation/>
<!-- Processing popup for zip -->
<ProcessingPopup/>
<!--Confirm Popup-->
@@ -58,7 +59,6 @@
<CookieDisclaimer/>
<!--Background vignette-->
<Vignette/>
</div>
</template>

View File

@@ -23,7 +23,7 @@
<!-- Single options -->
<OptionGroup v-if="multiSelectContextMenu">
<Option @click.native="restoreItem" v-if="item" :title="$t('context_menu.restore')" icon="restore"/>
<Option @click.native="deleteItem" :title="$t('context_menu.delete')" icon="trash"/>
<Option @click.native="deleteItem" v-if="item" :title="$t('context_menu.delete')" icon="trash"/>
<Option @click.native="emptyTrash" :title="$t('context_menu.empty_trash')" icon="empty-trash"/>
</OptionGroup>
@@ -34,6 +34,7 @@
<!-- Multi options -->
<OptionGroup v-if="!multiSelectContextMenu">
<Option @click.native="restoreItem" v-if="item" :title="$t('context_menu.restore')" icon="restore"/>
<Option @click.native="deleteItem" :title="$t('context_menu.delete')" icon="trash"/>
<Option @click.native="emptyTrash" :title="$t('context_menu.empty_trash')" icon="empty-trash"/>
</OptionGroup>
@@ -62,6 +63,7 @@
<OptionGroup v-if="item && multiSelectContextMenu">
<Option @click.native="ItemDetail" :title="$t('context_menu.detail')" icon="detail"/>
<Option @click.native="downloadItem" v-if="!isFolder" :title="$t('context_menu.download')" icon="download"/>
<Option @click.native="downloadFolder" v-if="isFolder" :title="$t('context_menu.zip_folder')" icon="zip-folder"/>
</OptionGroup>
<!-- Multi options -->
@@ -83,13 +85,15 @@
<!-- Base location with MASTER permission-->
<div v-if="$isThisLocation(['base', 'participant_uploads', 'latest']) && $checkPermission('master') && !showFromPreview" id="menu-list" class="menu-options">
<!-- No Files options -->
<OptionGroup v-if="!$isThisLocation(['participant_uploads', 'latest']) && multiSelectContextMenu && !item">
<Option @click.native="createFolder" :title="$t('context_menu.create_folder')" icon="create-folder"/>
</OptionGroup>
<!-- Single options -->
<OptionGroup v-if="!$isThisLocation(['participant_uploads', 'latest']) && multiSelectContextMenu">
<Option @click.native="addToFavourites" v-if="item && isFolder " :title="isInFavourites
? $t('context_menu.remove_from_favourites')
: $t('context_menu.add_to_favourites')" icon="favourites"/>
<Option @click.native="createFolder" :title="$t('context_menu.create_folder')" icon="create-folder"/>
<OptionGroup v-if="!$isThisLocation(['participant_uploads', 'latest']) && item && multiSelectContextMenu && isFolder">
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites"/>
</OptionGroup>
@@ -106,6 +110,7 @@
<OptionGroup v-if="item && multiSelectContextMenu ">
<Option @click.native="ItemDetail" :title="$t('context_menu.detail')" icon="detail"/>
<Option @click.native="downloadItem" v-if="!isFolder" :title="$t('context_menu.download')" icon="download"/>
<Option @click.native="downloadFolder" v-if="isFolder" :title="$t('context_menu.zip_folder')" icon="zip-folder"/>
</OptionGroup>
<!-- Multi options -->
@@ -113,7 +118,6 @@
<Option @click.native="addToFavourites" v-if="item && !hasFile" :title=" isInFavourites
? $t('context_menu.remove_from_favourites')
: $t('context_menu.add_to_favourites')" icon="favourites"/>
<Option @click.native="createFolder" :title="$t('context_menu.create_folder')" icon="create-folder"/>
</OptionGroup>
<OptionGroup v-if="item && !multiSelectContextMenu">
@@ -129,11 +133,13 @@
<!-- Base & Public location with EDITOR permission-->
<div v-if="$isThisLocation(['base', 'public']) && $checkPermission('editor') && !showFromPreview " id="menu-list" class="menu-options">
<!-- Single options -->
<OptionGroup v-if="multiSelectContextMenu">
<!-- No Files options -->
<OptionGroup v-if="multiSelectContextMenu && !item">
<Option @click.native="createFolder" :title="$t('context_menu.create_folder')" icon="create-folder"/>
</OptionGroup>
<!-- Single options -->
<OptionGroup v-if="item && multiSelectContextMenu">
<Option @click.native="renameItem" :title=" $t('context_menu.rename')" icon="rename"/>
<Option @click.native="moveItem" :title="$t('context_menu.move')" icon="move-item"/>
@@ -143,12 +149,10 @@
<OptionGroup v-if="item && multiSelectContextMenu">
<Option @click.native="ItemDetail" :title="$t('context_menu.detail')" icon="detail"/>
<Option @click.native="downloadItem" v-if="!isFolder" :title="$t('context_menu.download')" icon="download"/>
<Option @click.native="downloadFolder" v-if="isFolder" :title="$t('context_menu.zip_folder')" icon="zip-folder"/>
</OptionGroup>
<!-- Multi options -->
<OptionGroup v-if="!multiSelectContextMenu">
<Option @click.native="createFolder" :title="$t('context_menu.create_folder')" icon="create-folder"/>
</OptionGroup>
<OptionGroup v-if="item && !multiSelectContextMenu">
<Option @click.native="moveItem" :title="$t('context_menu.move')" icon="move-item"/>
@@ -167,6 +171,7 @@
<OptionGroup v-if="item && multiSelectContextMenu">
<Option @click.native="ItemDetail" :title="$t('context_menu.detail')" icon="detail"/>
<Option @click.native="downloadItem" v-if="!isFolder" :title="$t('context_menu.download')" icon="download"/>
<Option @click.native="downloadFolder" v-if="isFolder" :title="$t('context_menu.zip_folder')" icon="zip-folder"/>
</OptionGroup>
<!-- Multi options -->
@@ -250,11 +255,21 @@ export default {
},
methods: {
downloadFolder(){
this.$store.dispatch('downloadFolder' , this.item)
},
emptyTrash() {
this.$store.dispatch('emptyTrash')
},
restoreItem() {
this.$store.dispatch('restoreItem', this.item)
// If is item not in selected items restore just this single item
if(!this.fileInfoDetail.includes(this.item))
this.$store.dispatch('restoreItem', this.item)
// If is item in selected items restore all items from fileInfoDetail
if(this.fileInfoDetail.includes(this.item))
this.$store.dispatch('restoreItem', null)
},
shareCancel() {
this.$store.dispatch('shareCancel')

View File

@@ -25,22 +25,22 @@
<SearchBar/>
</div>
<!--Files controlls-->
<!--Creating controls-->
<div class="toolbar-button-wrapper" v-if="$checkPermission(['master', 'editor'])">
<ToolbarButtonUpload :class="{ 'is-inactive': canUploadInView || !hasCapacity }" :action="$t('actions.upload')"/>
<ToolbarButton :class="{ 'is-inactive': canCreateFolderInView }" @click.native="createFolder" source="folder-plus" :action="$t('actions.create_folder')"/>
</div>
<div class="toolbar-button-wrapper" v-if="$checkPermission(['master', 'editor'])">
<!--File Controls-->
<div class="toolbar-button-wrapper" v-if="$checkPermission(['master', 'editor']) && ! $isMobile()">
<ToolbarButton source="move" :class="{ 'is-inactive': canMoveInView }" :action="$t('actions.move')" @click.native="moveItem"/>
<ToolbarButton v-if="!$isThisLocation(['public'])" source="share" :class="{ 'is-inactive': canShareInView }" :action="$t('actions.share')" @click.native="shareItem"/>
<ToolbarButton source="trash" :class="{ 'is-inactive': canDeleteInView }" :action="$t('actions.delete')" @click.native="deleteItem"/>
</div>
<!--View options-->
<!--View Controls-->
<div class="toolbar-button-wrapper">
<ToolbarButton source="preview-sorting" class="preview-sorting" :action="$t('actions.sorting_view')" :class="{ active: sortingAndPreview }" @click.stop.native="sortingAndPreview = !sortingAndPreview"/>
<ToolbarButton :action="$t('actions.info_panel')" :class="{ active: fileInfoVisible }" @click.native="$store.dispatch('fileInfoToggle')" source="info"/>
</div>
</div>
@@ -103,7 +103,7 @@ export default {
return !this.$isThisLocation(['base', 'public'])
},
canDeleteInView() {
return !this.$isThisLocation([
let locations = [
'trash',
'trash-root',
'base',
@@ -111,19 +111,22 @@ export default {
'latest',
'shared',
'public'
])
]
return !this.$isThisLocation(locations) || this.fileInfoDetail.length === 0
},
canUploadInView() {
return !this.$isThisLocation(['base', 'public'])
},
canMoveInView() {
return !this.$isThisLocation([
let locations = [
'base',
'participant_uploads',
'latest',
'shared',
'public'
])
]
return !this.$isThisLocation(locations) || this.fileInfoDetail.length === 0
},
canShareInView() {
let locations = [
@@ -134,7 +137,7 @@ export default {
'public'
]
return !this.$isThisLocation(locations) || this.fileInfoDetail.length > 1
return !this.$isThisLocation(locations) || this.fileInfoDetail.length > 1 || this.fileInfoDetail.length === 0
}
},
data() {

View File

@@ -1,72 +1,77 @@
<template>
<MultiSelected :title="title" :subtitle="subtitle" id="multi-select-ui" v-show="dragged" />
<MultiSelected :title="title" :subtitle="subtitle" id="multi-select-ui" v-show="isVisible"/>
</template>
<script>
import MultiSelected from '@/components/FilesView/MultiSelected'
import {mapGetters} from 'vuex'
import {events} from '@/bus'
import { mapGetters } from 'vuex'
import { events } from '@/bus'
export default {
name:"DragUI",
components: {MultiSelected},
computed: {
...mapGetters(['fileInfoDetail']),
title(){
export default {
name: 'DragUI',
components: { MultiSelected },
computed: {
...mapGetters(['fileInfoDetail']),
title() {
let filesLength = this.fileInfoDetail.length,
hasDraggedItem = this.fileInfoDetail.includes(this.draggedItem)
// Title for multiple selected items
if(this.fileInfoDetail.length > 1 && this.fileInfoDetail.includes(this.draggedItem)) {
return this.$t('file_detail.selected_multiple')
}
// Title for multiple selected items
if (filesLength > 1 && hasDraggedItem) {
return this.$t('file_detail.selected_multiple')
}
// Title for single item
if((this.fileInfoDetail.length < 2 || !this.fileInfoDetail.includes(this.draggedItem)) && this.draggedItem ) {
return this.draggedItem.name
}
},
subtitle(){
// Subtitle for multiple selected items
if(this.fileInfoDetail.length > 1 && this.fileInfoDetail.includes(this.draggedItem) ) {
return this.fileInfoDetail.length + ' ' + this.$tc('file_detail.items', this.fileInfoDetail.length)
}
if((this.fileInfoDetail.length < 2 || !this.fileInfoDetail.includes(this.draggedItem)) && this.draggedItem) {
// Subtitle for single folder
if(this.draggedItem.type === 'folder') {
return this.draggedItem.items == 0 ? this.$t('folder.empty') : this.$tc('folder.item_counts', this.draggedItem.items)
}
// Subtitle for single file
if(this.draggedItem !== 'folder' && this.draggedItem.mimetype){
return '.'+this.draggedItem.mimetype
}
}
},
},
data () {
return {
dragged: false,
draggedItem: undefined
// Title for single item
if ((filesLength < 2 || !hasDraggedItem) && this.draggedItem) {
return this.draggedItem.name
}
},
mounted () {
subtitle() {
let filesLength = this.fileInfoDetail.length,
hasDraggedItem = this.fileInfoDetail.includes(this.draggedItem)
// Hnadle Drag & Drop Ghost show
events.$on('dragstart', (data) => {
setTimeout(() => {
this.dragged = true
}, 50);
this.draggedItem = data
})
events.$on('drop', () => {
this.dragged = false
})
// Subtitle for multiple selected items
if (filesLength > 1 && hasDraggedItem) {
return filesLength + ' ' + this.$tc('file_detail.items', filesLength)
}
if ((filesLength < 2 || !hasDraggedItem) && this.draggedItem) {
// Subtitle for single folder
if (this.draggedItem.type === 'folder') {
return this.draggedItem.items == 0 ? this.$t('folder.empty') : this.$tc('folder.item_counts', this.draggedItem.items)
}
// Subtitle for single file
if (this.draggedItem !== 'folder' && this.draggedItem.mimetype) {
return '.' + this.draggedItem.mimetype
}
}
}
},
data() {
return {
isVisible: false,
draggedItem: undefined
}
},
created() {
// Handle Drag & Drop Ghost show
events.$on('dragstart', data => {
this.draggedItem = data
setTimeout(() => {
this.isVisible = true
}, 100)
})
events.$on('drop', () => {
this.isVisible = false
})
}
}
</script>
<style lang="scss" scoped>
@@ -82,38 +87,44 @@ import {events} from '@/bus'
padding: 10px;
border-radius: 8px;
box-shadow: 0 7px 25px 1px rgba(0, 0, 0, 0.12);
background:white;
/deep/.text{
.title {
color: $text;
}
.count {
color: $text-muted;
}
background: white;
/deep/ .text {
.title {
color: $text;
}
/deep/.icon-wrapper {
.icon {
stroke: $theme;
}
.count {
color: $text-muted;
}
}
/deep/ .icon-wrapper {
.icon {
stroke: $theme;
}
}
}
@media (prefers-color-scheme: dark) {
#multi-select-ui {
background: $dark_mode_foreground;
/deep/.text {
/deep/ .text {
.title {
color: $dark_mode_text_primary;
}
.count {
color: $dark_mode_text_secondary;
}
}
/deep/.icon-wrapper {
.icon {
}
/deep/ .icon-wrapper {
.icon {
stroke: $theme;
}
}
}
}
}
}

View File

@@ -53,7 +53,7 @@
<div class="sharelink">
<lock-icon v-if="isLocked" @click="shareItemOptions" class="lock-icon" size="17"></lock-icon>
<unlock-icon v-if="! isLocked" @click="shareItemOptions" class="lock-icon" size="17"></unlock-icon>
<CopyInput class="copy-sharelink" size="small" :value="fileInfoDetail[0].shared.link"/>
<CopyInput class="copy-sharelink" size="small" :item="fileInfoDetail[0]"/>
</div>
</ListInfoItem>

View File

@@ -25,14 +25,18 @@
<!--Image thumbnail-->
<img loading="lazy" v-if="isImage && data.thumbnail" class="image" :src="data.thumbnail" :alt="data.name"/>
<!-- If folder have set emoji -->
<Emoji class="emoji" v-if="isFolder && folderIconHandle" :emoji="folderIconHandle" size="80" />
<!--Else show only folder icon-->
<FontAwesomeIcon v-if="isFolder" :class="{'is-deleted': isDeleted}" class="folder-icon" icon="folder"/>
<FontAwesomeIcon v-if="isFolder && !folderIconHandle" :ref="`folder${this.data.unique_id}`" :class="{'is-deleted': isDeleted}" class="folder-icon" icon="folder"/>
</div>
<!--Name-->
<div class="item-name">
<!--Name-->
<b ref="name" @input="renameItem" @keydown.delete.stop :contenteditable="canEditName" class="name">
<b :ref="this.data.unique_id" @input="renameItem" @keydown.delete.stop @click.stop :contenteditable="canEditName" class="name">
{{ itemName }}
</b>
@@ -67,6 +71,7 @@
<script>
import { LinkIcon, UserPlusIcon, CheckIcon } from 'vue-feather-icons'
import Emoji from '@/components/Others/Emoji'
import { debounce } from 'lodash'
import { mapGetters } from 'vuex'
import { events } from '@/bus'
@@ -77,12 +82,28 @@ export default {
components: {
UserPlusIcon,
CheckIcon,
LinkIcon
LinkIcon,
Emoji
},
computed: {
...mapGetters([
'FilePreviewType', 'sharedDetail', 'fileInfoDetail'
]),
folderIconHandle(){
// If folder have set some color
if(this.data.icon_color) {
this.$nextTick(() => {
this.$refs[`folder${this.data.unique_id}`].firstElementChild.style.fill = `${this.data.icon_color}`
})
return false
}
// If folder have set some emoji
if(this.data.icon_emoji)
return this.data.icon_emoji
},
...mapGetters({ allData: 'data' }),
isClicked() {
return this.fileInfoDetail.some(element => element.unique_id == this.data.unique_id)
@@ -158,6 +179,10 @@ export default {
events.$emit('unClick')
if (!this.$isMobile()) {
// After click deselect new folder rename input
document.getSelection().removeAllRanges();
if (e.ctrlKey || e.metaKey && !e.shiftKey) {
// Click + Ctrl
if (this.fileInfoDetail.some(item => item.unique_id === this.data.unique_id)) {
@@ -267,6 +292,14 @@ export default {
created() {
this.itemName = this.data.name
events.$on('newFolder:focus', (unique_id) => {
if(this.data.unique_id == unique_id) {
this.$refs[unique_id].focus()
document.execCommand('selectAll')
}
})
events.$on('mobileSelecting:start', () => {
this.multiSelectMode = true
this.$store.commit('CLEAR_FILEINFO_DETAIL')
@@ -318,7 +351,7 @@ export default {
}
.select-box-active {
background-color: $text;
background-color: $theme;
.icon {
stroke: white;
@@ -452,6 +485,10 @@ export default {
display: flex;
align-items: center;
.emoji {
margin: 0 auto;
}
.file-link {
display: block;
}
@@ -568,10 +605,10 @@ export default {
}
.select-box-active {
background-color: #f4f5f6;
background-color: lighten($theme, 5%);
.icon {
stroke: $text;
stroke: white;
}
}

View File

@@ -1,9 +1,14 @@
<template>
<div class="file-wrapper" @click.stop="clickedItem" @dblclick="goToItem" spellcheck="false">
<!--List preview-->
<div :draggable="canDrag" @dragstart="$emit('dragstart')" @drop="
drop()
area = false" @dragleave="dragLeave" @dragover.prevent="dragEnter" class="file-item" :class="{'is-clicked' : isClicked , 'no-clicked' : !isClicked && this.$isMobile(), 'is-dragenter': area }">
<div
:draggable="canDrag"
@dragstart="$emit('dragstart')"
@drop="drop()"
@dragleave="dragLeave"
@dragover.prevent="dragEnter"
class="file-item" :class="{'is-clicked' : isClicked , 'no-clicked' : !isClicked && this.$isMobile(), 'is-dragenter': area }"
>
<!-- MultiSelecting for the mobile version -->
<transition name="slide-from-left">
<div class="check-select" v-if="mobileMultiSelect">
@@ -26,13 +31,17 @@
<!--Image thumbnail-->
<img loading="lazy" v-if="isImage && data.thumbnail" class="image" :src="data.thumbnail" :alt="data.name"/>
<!-- If folder have set emoji -->
<Emoji v-if="isFolder && folderIconHandle" :emoji="folderIconHandle" size="52" />
<!--Else show only folder icon-->
<FontAwesomeIcon v-if="isFolder" :class="{ 'is-deleted': isDeleted }" class="folder-icon" icon="folder"/>
<FontAwesomeIcon v-if="isFolder && !folderIconHandle" :ref="`folder${this.data.unique_id}`" :class="{ 'is-deleted': isDeleted }" class="folder-icon" icon="folder"/>
</div>
<!--Name-->
<div class="item-name">
<b ref="name" @input="renameItem" @keydown.delete.stop :contenteditable="canEditName" class="name">
<b :ref="this.data.unique_id" @input="renameItem" @keydown.delete.stop @click.stop :contenteditable="canEditName" class="name">
{{ itemName }}
</b>
@@ -69,6 +78,7 @@
<script>
import { LinkIcon, UserPlusIcon, CheckIcon } from 'vue-feather-icons'
import Emoji from '@/components/Others/Emoji'
import { debounce } from 'lodash'
import { mapGetters } from 'vuex'
import { events } from '@/bus'
@@ -79,11 +89,27 @@ export default {
components: {
UserPlusIcon,
LinkIcon,
CheckIcon
CheckIcon,
Emoji
},
computed: {
...mapGetters(['FilePreviewType', 'fileInfoDetail']),
...mapGetters({ allData: 'data' }),
folderIconHandle(){
// If folder have set some icon color
if(this.data.icon_color) {
this.$nextTick(() => {
this.$refs[`folder${this.data.unique_id}`].firstElementChild.style.fill = `${this.data.icon_color}`
})
return false
}
// If folder have set some emoji
if(this.data.icon_emoji)
return this.data.icon_emoji
},
isClicked() {
return this.fileInfoDetail.some(element => element.unique_id == this.data.unique_id)
},
@@ -140,6 +166,7 @@ export default {
},
methods: {
drop() {
this.area = false
events.$emit('drop')
},
showItemActions() {
@@ -162,6 +189,9 @@ export default {
if (!this.$isMobile()) {
// After click deselect new folder rename input
document.getSelection().removeAllRanges();
if ((e.ctrlKey || e.metaKey) && !e.shiftKey) {
// Click + Ctrl
@@ -265,8 +295,17 @@ export default {
}, 300)
},
created() {
this.itemName = this.data.name
events.$on('newFolder:focus', (unique_id) => {
if(this.data.unique_id == unique_id) {
this.$refs[unique_id].focus()
document.execCommand('selectAll')
}
})
events.$on('mobileSelecting:start', () => {
this.mobileMultiSelect = true
this.$store.commit('CLEAR_FILEINFO_DETAIL')
@@ -289,6 +328,7 @@ export default {
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.slide-from-left-move {
transition: transform 300s ease;
}
@@ -328,10 +368,10 @@ export default {
}
.select-box-active {
background-color: #f4f5f6;
background-color: $theme;
.icon {
stroke: $text;
stroke: white;
}
}
}
@@ -533,10 +573,10 @@ export default {
}
.select-box-active {
background-color: lighten($dark_mode_foreground, 10%);
background-color: $theme;
.icon {
stroke: $theme;
stroke: white;
}
}
}

View File

@@ -6,7 +6,7 @@
<p class="title">{{ fileInfoDetail[0].name }}</p>
<span class="file-count"> ({{ showingImageIndex + ' ' + $t('pronouns.of') + ' ' + filteredFiles.length }}) </span>
</div>
<span id="fast-preview-menu" class="fast-menu-icon" @click.stop="menuOpen" v-if="$checkPermission(['master', 'editor'])">
<span id="fast-preview-menu" class="fast-menu-icon" @click.stop="menuOpen" v-if="$checkPermission(['master', 'editor', 'visitor'])">
<more-horizontal-icon class="more-icon" size="14"> </more-horizontal-icon>
</span>
</div>

View File

@@ -5,7 +5,7 @@
<audio class="file audio" :class="{ 'file-shadow': !isMobileDevice }" v-if="fileInfoDetail[0].type == 'audio'" :src="currentFile.file_url" controlsList="nodownload" controls></audio>
<img v-if="fileInfoDetail[0].type === 'image' && currentFile.thumbnail" class="file" :class="{ 'file-shadow': !isMobileDevice }" id="image" :src="currentFile.file_url" />
<div class="video-wrapper" v-if="fileInfoDetail[0].type === 'video' && currentFile.file_url">
<video :src="currentFile.file_url" class="video" :class="{ 'file-shadow': !isMobileDevice }" controlsList="nodownload" disablePictureInPicture playsinline controls />
<video :src="currentFile.file_url" class="video" :class="{ 'file-shadow': !isMobileDevice }" controlsList="nodownload" disablePictureInPicture playsinline controls autoplay />
</div>
</div>
</div>

File diff suppressed because it is too large Load Diff

View File

@@ -42,7 +42,7 @@ import { events } from '@/bus'
@media (prefers-color-scheme: dark) {
.options {
background: $dark_mode_background;
background: $dark_mode_foreground;
}
}

View File

@@ -1,5 +1,5 @@
<template>
<li class="menu-option">
<li class="menu-option" :class="[icon === 'trash' ? 'danger' : '']">
<div class="icon">
<trash-2-icon v-if="icon === 'trash'" size="17"></trash-2-icon>
<life-buoy-icon v-if="icon === 'restore'" size="17"></life-buoy-icon>
@@ -12,6 +12,7 @@
<star-icon v-if="icon === 'favourites'" size="17"></star-icon>
<folder-plus-icon v-if="icon === 'create-folder'" size="17"></folder-plus-icon>
<smile-icon v-if="icon === 'no-options'" size="17"></smile-icon>
<paperclip-icon v-if="icon === 'zip-folder'" size="17"></paperclip-icon>
</div>
<div class="text-label">
{{ title }}
@@ -24,6 +25,7 @@ import {
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
PaperclipIcon,
LifeBuoyIcon,
Trash2Icon,
Edit2Icon,
@@ -41,6 +43,7 @@ import {
CornerDownRightIcon,
DownloadCloudIcon,
FolderPlusIcon,
PaperclipIcon,
LifeBuoyIcon,
Trash2Icon,
SmileIcon,
@@ -57,6 +60,22 @@ import {
@import "@assets/vue-file-manager/_variables";
@import "@assets/vue-file-manager/_mixins";
.danger {
.text-label {
color: $danger !important;
}
.icon {
path,
line,
polyline,
rect,
circle,
polygon {
stroke: $danger !important;
}
}
}
.menu-option {
white-space: nowrap;
font-weight: 700;
@@ -95,6 +114,11 @@ import {
}
}
@media (prefers-color-scheme: dark) {
.danger {
&:hover {
background: rgba($danger, 0.1) !important;
}
}
.menu-option {
color: $dark_mode_text_primary;

View File

@@ -1,13 +1,13 @@
<template>
<transition name="popup">
<div class="popup" v-if="isZippingFiles">
<div class="popup" v-if="processingPopup">
<div class="popup-wrapper">
<div class="popup-content">
<div class="spinner-wrapper">
<Spinner/>
</div>
<h1 class="title">{{ $t('popup_zipping.title') }}</h1>
<p class="message">{{ $t('popup_zipping.message') }}</p>
<h1 class="title">{{ processingPopup.title }}</h1>
<p class="message">{{ processingPopup.message }}</p>
</div>
</div>
</div>
@@ -25,7 +25,7 @@ export default {
},
computed: {
...mapGetters([
'isZippingFiles'
'processingPopup'
])
}
}

View File

@@ -84,8 +84,6 @@ export default {
this.filter.field = field
console.log(this.filter);
// Set sorting direction
if (this.filter.sort === 'DESC')
this.filter.sort = 'ASC'

View File

@@ -5,11 +5,17 @@
:description="index.header_description"
></PageTitle>
<router-link class="sign-up-button" :to="{name: 'SignUp'}">
<!--User registration button-->
<router-link v-if="config.userRegistration" class="sign-up-button" :to="{name: 'SignUp'}">
<AuthButton class="button" icon="chevron-right" :text="$t('page_index.sign_up_button')" />
</router-link>
<div class="features">
<!--User login button-->
<router-link v-if="! config.userRegistration" class="sign-up-button" :to="{name: 'SignIn'}">
<AuthButton class="button" icon="chevron-right" :text="$t('page_index.menu.log_in')" />
</router-link>
<div class="features" v-if="config.isSaaS">
<div class="feature">
<credit-card-icon size="19" class="feature-icon"></credit-card-icon>
<b class="feature-title">{{ $t('page_index.sign_feature_1') }}</b>

View File

@@ -1,7 +1,7 @@
<template>
<div class="cookie-wrapper" v-if="isVisibleDisclaimer && config.isSaaS">
<span class="close-icon">
<x-icon @click="closeDisclaimer" size="12"></x-icon>
<span @click="closeDisclaimer" class="close-icon">
<x-icon size="12"></x-icon>
</span>
<i18n path="cookie_disclaimer.description" tag="p">
<router-link :to="{name: 'DynamicPage', params: {slug: 'cookie-policy'}}">{{ $t('cookie_disclaimer.button') }}</router-link>

View File

@@ -13,7 +13,7 @@
<!--Set password-->
<ValidationProvider tag="div" mode="passive" class="input-wrapper password" name="Title" rules="required" v-slot="{ errors }">
<label class="input-label">{{ $t('popup_create_folder.label') }}:</label>
<input v-model="name" :class="{'is-error': errors[0]}" type="text" :placeholder="$t('popup_create_folder.placeholder')">
<input v-model="name" :class="{'is-error': errors[0]}" type="text" ref="input" :placeholder="$t('popup_create_folder.placeholder')">
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</ValidationObserver>
@@ -82,6 +82,15 @@
}
},
},
mounted() {
events.$on('popup:open', ({name}) => {
if (name === 'create-folder')
this.$nextTick(() => {
this.$refs.input.focus()
})
})
}
}
</script>

View File

@@ -0,0 +1,25 @@
<template>
<div v-show="transferEmoji" :style="{width: `${size}px`, height: `${size}px`}" v-html="transferEmoji"/>
</template>
<script>
import twemoji from 'twemoji'
export default {
name: 'Emoji',
props: ['emoji', 'size'],
computed: {
transferEmoji () {
// Transfer single emoji to twemoji
return twemoji.parse(this.emoji.char, {
folder: 'svg',
ext: '.svg',
attributes: () => ({
loading: 'lazy',
})
})
}
},
}
</script>

View File

@@ -1,95 +1,190 @@
<template>
<div class="inline-wrapper icon-append copy-input" :class="size" @click="copyUrl">
<input ref="sel" :value="value" id="link-input" type="text" class="input-text" readonly>
<div class="icon">
<link-icon v-if="! isCopiedLink" size="14"></link-icon>
<check-icon v-if="isCopiedLink" size="14"></check-icon>
<input ref="sel" :value="item.shared.link" id="link-input" type="text" class="input-text" readonly>
<div class="multi-icon">
<div class="icon-item">
<link-icon v-if="! isCopiedLink" size="14"></link-icon>
<check-icon v-if="isCopiedLink" size="14"></check-icon>
</div>
<div class="icon-item" @click.stop.prevent="menuForEmail">
<send-icon size="14"></send-icon>
</div>
</div>
</div>
</template>
<script>
import { LinkIcon, CheckIcon } from 'vue-feather-icons'
import { LinkIcon, CheckIcon, SendIcon } from 'vue-feather-icons'
import { events } from '@/bus'
export default {
name: 'CopyInput',
props: ['size', 'value'],
components: {
CheckIcon,
LinkIcon,
export default {
name: 'CopyInput',
props: ['size', 'item'],
components: {
CheckIcon,
LinkIcon,
SendIcon
},
data() {
return {
isCopiedLink: false
}
},
methods: {
menuForEmail() {
events.$emit('popup:open', {
name: 'share-edit',
item: this.item,
sentToEmail: true,
})
},
data() {
return {
isCopiedLink: false,
}
},
methods: {
copyUrl() {
copyUrl() {
// Get input value
var copyText = document.getElementById("link-input");
// Get input value
var copyText = document.getElementById('link-input')
// select link
copyText.select();
copyText.setSelectionRange(0, 99999);
// select link
copyText.select()
copyText.setSelectionRange(0, 99999)
// Copy
document.execCommand("copy");
// Copy
document.execCommand('copy')
// Mark button as copied
this.isCopiedLink = true
// Mark button as copied
this.isCopiedLink = true
// Reset copy button
setTimeout(() => {this.isCopiedLink = false}, 1000)
},
// Reset copy button
setTimeout(() => {
this.isCopiedLink = false
}, 1000)
}
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
@import "@assets/vue-file-manager/_inapp-forms.scss";
@import "@assets/vue-file-manager/_forms.scss";
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
@import "@assets/vue-file-manager/_inapp-forms.scss";
@import "@assets/vue-file-manager/_forms.scss";
// Single page
.copy-input {
.multi-icon {
display: flex;
align-items: center;
background: $light_background;
border-bottom-right-radius: 8px;
border-top-right-radius: 8px;
&.small {
line,
path,
polygon {
stroke: $text !important;
}
&.icon-append {
.icon-item {
padding: 9px 10px;
display: flex;
align-items: center;
border-left: 1px solid $light_mode_border_darken;
cursor: pointer;
.icon {
padding: 10px;
}
}
&:hover {
background: $text;
input {
padding: 6px 10px;
@include font-size(13);
line,
polyline,
path,
polygon {
stroke: white !important;
}
}
.icon {
cursor: pointer;
&:first-child {
border-left: none;
}
&:last-child {
border-bottom-right-radius: 8px;
border-top-right-radius: 8px;
}
}
}
// Single page
.copy-input {
border: 1px solid $light_mode_border_darken;
border-radius: 8px;
&.small {
&.icon-append {
.icon {
padding: 10px;
}
}
input {
text-overflow: ellipsis;
&:disabled {
color: $text;
cursor: pointer;
}
padding: 6px 10px;
@include font-size(13);
}
}
@media (prefers-color-scheme: dark) {
.icon {
cursor: pointer;
}
.copy-input {
input {
color: $dark_mode_text_primary;
}
input {
text-overflow: ellipsis;
box-shadow: none;
&:disabled {
color: $text;
cursor: pointer;
}
}
}
@media (prefers-color-scheme: dark) {
.copy-input {
border-color: #333333;
}
.multi-icon {
background: $dark_mode_foreground;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12);
line,
path,
polygon {
stroke: $dark_mode_text_primary !important;
}
.icon-item {
border-color: #333333;
&:hover {
background: rgba($theme, 0.1);
line,
polyline,
path,
polygon {
stroke: $theme !important;
}
}
}
}
.copy-input {
input {
color: $dark_mode_text_primary;
}
}
}
</style>

View File

@@ -35,12 +35,19 @@
}
p {
@include font-size(15);
font-size: 15px;
line-height: 1.6;
word-break: break-word;
font-weight: 600;
/deep/ a {
font-size: 15px;
color: $theme;
}
/deep/ b {
font-size: 15px;
font-weight: 700;
color: $theme;
}
}
@@ -71,10 +78,6 @@
}
}
@media only screen and (max-width: 960px) {
}
@media only screen and (max-width: 690px) {
.info-box {

View File

@@ -0,0 +1,197 @@
<template>
<div class="wrapper">
<label class="input-label">{{ label }}:</label>
<div class="input-wrapper" :class="{'is-error' : isError}" @click="$refs.input.focus()">
<div class="email-list">
<div class="email-tag" :class="{'mb-offset': getCharactersLength > 45}" v-for="(email, i) in emails" :key="i">
<span>{{ email }}</span>
<x-icon @click="removeEmail(email)" class="icon" size="14"/>
</div>
<input @keydown.delete=removeLastEmail($event) @keyup="handleEmail()" v-model="email" :size="inputSize" class="email-input" :placeholder="placeHolder" autocomplete="new-password" ref="input"/>
</div>
</div>
<span class="error-message" v-if="isError">{{ isError }}</span>
</div>
</template>
<script>
import { XIcon } from 'vue-feather-icons'
import { events } from '@/bus'
export default {
name: 'MultiEmailInput',
components: { XIcon },
props: ['isError', 'label'],
computed: {
getCharactersLength() {
return this.emails.join( '' ).length
},
placeHolder() {
return !this.emails.length ? this.$t( 'shared_form.email_placeholder' ) : ''
},
inputSize() {
return this.email && this.email.length > 14 ? this.email.length : 14
}
},
data() {
return {
emails: [],
email: undefined
}
},
methods: {
removeEmail( email ) {
this.emails = this.emails.filter( item => item !== email )
// After romove email send new emails list to parent
events.$emit( 'emailsInputValues', this.emails )
},
removeLastEmail( event ) {
// If is input empty and presse backspace remove last email from array
if ( event.code === 'Backspace' && this.email === '' )
this.emails.pop()
},
handleEmail() {
if ( this.email.length > 0 ) {
// Get index of @ and last dot
let lastDot = this.email.lastIndexOf( '.' )
let at = this.email.indexOf( '@' )
// Check if is after @ some dot, if email have @ anf if dont have more like one
if ( lastDot < at || at === -1 || this.email.match(/@/g).length > 1 ) return
// First email dont need to be separated by comma or space to be sended
if( this.emails.length === 0 )
events.$emit('emailsInputValues', [this.email])
// After come or backspace push the single email to array or emails
if ( this.email.includes(',') || this.email.includes(' ') ) {
let email = this.email.replace( /[","," "]/, '' )
this.email = ''
// Push single email to aray of emails
this.emails.push( email )
events.$emit( 'emailsInputValues', this.emails )
}
}
}
},
created() {
this.$nextTick(() => {
this.$refs.input.focus()
})
}
}
</script>
<style scoped lang="scss">
@import "@assets/vue-file-manager/_inapp-forms.scss";
@import '@assets/vue-file-manager/_forms';
.wrapper {
margin-bottom: 20px;
}
.input-label {
@include font-size(14);
font-weight: 700;
margin-bottom: 8px;
}
.input-wrapper {
margin-bottom: 0;
background: white;
max-width: 100%;
display: flex;
min-height: 50px;
border-radius: 8px;
padding: 6px 10px;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12);
cursor: text;
border: 1px solid transparent;
@include transition(150ms);
&.is-error {
border: 1px solid $danger;
box-shadow: 0 0 7px rgba($danger, 0.3);
}
&:focus-within {
border: 1px solid $theme;
box-shadow: 0 1px 5px rgba($theme, 0.3);
}
.email-list {
display: flex;
flex-wrap: wrap;
.email-input {
font-size: 14px;
}
}
.email-tag {
white-space: nowrap;
display: flex;
padding: 5px 10px;
background: rgba($theme, .1);
border-radius: 8px;
margin-right: 5px;
align-items: center;
&.mb-offset {
margin-top: 3px;
margin-bottom: 3px;
}
span {
color: $theme;
font-weight: 700;
@include font-size(14);
}
.icon {
cursor: pointer;
margin-left: 4px;
}
}
.email-input {
width: auto;
border: none ;
font-weight: 700;
@include font-size(16);
padding-left: 11px;
&::placeholder {
color: rgba($text-muted, .5)
}
}
}
@media (prefers-color-scheme: dark) {
.input-wrapper {
background: $dark_mode_foreground;
.email-list {
.email-input {
background: $dark_mode_foreground;
color: $dark_mode_text_primary;
&::placeholder {
color: $dark_mode_text_secondary;
}
}
}
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More