shared dashboards

This commit is contained in:
denisdulici 2020-01-07 17:15:00 +03:00
parent dcab115207
commit 2436898f04
33 changed files with 806 additions and 457 deletions

View File

@ -58,7 +58,7 @@ abstract class Controller extends BaseController
$controller .= Str::kebab($arr[0]);
// Skip ACL
$skip = ['common-dashboard', 'portal-dashboard'];
$skip = ['portal-dashboard'];
if (in_array($controller, $skip)) {
return;
}

View File

@ -0,0 +1,70 @@
<?php
namespace App\BulkActions\Common;
use App\Abstracts\BulkAction;
use App\Jobs\Common\DeleteDashboard;
use App\Jobs\Common\UpdateDashboard;
use App\Models\Common\Dashboard;
class Dashboards extends BulkAction
{
public $model = Dashboard::class;
public $actions = [
'enable' => [
'name' => 'general.enable',
'message' => 'bulk_actions.message.enable',
'permission' => 'update-common-dashboards',
],
'disable' => [
'name' => 'general.disable',
'message' => 'bulk_actions.message.disable',
'permission' => 'update-common-dashboards',
],
'delete' => [
'name' => 'general.delete',
'message' => 'bulk_actions.message.delete',
'permission' => 'delete-common-dashboards',
],
];
public function enable($request)
{
$dashboards = $this->getSelectedRecords($request);
foreach ($dashboards as $dashboard) {
try {
$this->dispatch(new UpdateDashboard($dashboard, $request->merge(['enabled' => 1])));
} catch (\Exception $e) {
flash($e->getMessage())->error();
}
}
}
public function disable($request)
{
$dashboards = $this->getSelectedRecords($request);
foreach ($dashboards as $dashboard) {
try {
$this->dispatch(new UpdateDashboard($dashboard, $request->merge(['enabled' => 0])));
} catch (\Exception $e) {
flash($e->getMessage())->error();
}
}
}
public function destroy($request)
{
$dashboards = $this->getSelectedRecords($request);
foreach ($dashboards as $dashboard) {
try {
$this->dispatch(new DeleteDashboard($dashboard));
} catch (\Exception $e) {
flash($e->getMessage())->error();
}
}
}
}

View File

@ -1,117 +0,0 @@
<?php
namespace App\Http\Controllers\Common;
use App\Abstracts\Http\Controller;
use App\Http\Requests\Common\Dashboard as Request;
use App\Models\Common\Dashboard as Model;
use App\Models\Common\Widget;
use App\Traits\DateTime;
use App\Utilities\Widgets as WidgetUtility;
class Dashboard extends Controller
{
use DateTime;
/**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
$dashboard_id = session('dashboard_id', 0);
// Change Dashboard
if (request()->get('dashboard_id', 0)) {
$dashboard_id = request()->get('dashboard_id');
session(['dashboard_id' => $dashboard_id]);
}
$dashboards = Model::where('user_id', user()->id)->enabled()->get();
if (!$dashboard_id) {
$dashboard_id = $dashboards->pluck('id')->first();
}
// Dashboard
$dashboard = Model::find($dashboard_id);
// Widgets
$widgets = Widget::where('dashboard_id', $dashboard->id)->orderBy('sort', 'asc')->get()->filter(function ($widget) {
return WidgetUtility::canRead($widget->class);
});
$financial_start = $this->getFinancialStart()->format('Y-m-d');
return view('common.dashboard.index', compact('dashboards', 'dashboard', 'widgets', 'financial_start'));
}
/**
* Store a newly created resource in storage.
*
* @param $request
* @return Response
*/
public function store(Request $request)
{
$request['enabled'] = 1;
$request['user_id'] = user()->id;
$dashboard = Model::create($request->input());
$response['data'] = $dashboard;
$response['redirect'] = route('dashboard');
return response()->json($response);
}
/**
* Show the form for editing the specified resource.
*
* @param Model $dashboard
*
* @return Response
*/
public function edit(Model $dashboard)
{
return response()->json($dashboard);
}
/**
* Update the specified resource in storage.
*
* @param Model $dashboard
* @param $request
* @return Response
*/
public function update(Model $dashboard, Request $request)
{
$request['enabled'] = 1;
$dashboard->update($request->input());
$response['data'] = $dashboard;
$response['redirect'] = route('dashboard');
return response()->json($response);
}
/**
* Remove the specified resource from storage.
*
* @param Model $dashboard
*
* @return Response
*/
public function destroy(Model $dashboard)
{
$dashboard->delete();
session(['dashboard_id' => user()->dashboards()->pluck('id')->first()]);
$response['redirect'] = route('dashboard');
return response()->json($response);
}
}

View File

@ -0,0 +1,244 @@
<?php
namespace App\Http\Controllers\Common;
use App\Abstracts\Http\Controller;
use App\Http\Requests\Common\Dashboard as Request;
use App\Jobs\Common\CreateDashboard;
use App\Jobs\Common\DeleteDashboard;
use App\Jobs\Common\UpdateDashboard;
use App\Models\Common\Company;
use App\Models\Common\Dashboard;
use App\Models\Common\Widget;
use App\Traits\DateTime;
use App\Traits\Users;
use App\Utilities\Widgets;
class Dashboards extends Controller
{
use DateTime, Users;
/**
* Instantiate a new controller instance.
*/
public function __construct()
{
// Add CRUD permission check
$this->middleware('permission:create-common-dashboards')->only(['create', 'store', 'duplicate', 'import']);
$this->middleware('permission:read-common-dashboards')->only(['index', 'edit', 'export']);
$this->middleware('permission:update-common-dashboards')->only(['update', 'enable', 'disable', 'share']);
$this->middleware('permission:delete-common-dashboards')->only('destroy');
}
/**
* Display a listing of the resource.
*
* @return Response
*/
public function index()
{
$dashboards = user()->dashboards()->collect();
return view('common.dashboards.index', compact('dashboards'));
}
/**
* Show the form for viewing the specified resource.
*
* @return Response
*/
public function show()
{
$dashboard_id = session('dashboard_id', 0);
// Change Dashboard
if (request()->get('dashboard_id', 0)) {
$dashboard_id = request()->get('dashboard_id');
session(['dashboard_id' => $dashboard_id]);
}
$dashboards = user()->dashboards()->enabled()->get();
if (!$dashboard_id) {
$dashboard_id = $dashboards->pluck('id')->first();
}
// Dashboard
$dashboard = Dashboard::find($dashboard_id);
// Widgets
$widgets = Widget::where('dashboard_id', $dashboard->id)->orderBy('sort', 'asc')->get()->filter(function ($widget) {
return Widgets::canRead($widget->class);
});
$financial_start = $this->getFinancialStart()->format('Y-m-d');
return view('common.dashboards.show', compact('dashboards', 'dashboard', 'widgets', 'financial_start'));
}
/**
* Show the form for creating a new resource.
*
* @return Response
*/
public function create()
{
$users = Company::find(session('company_id'))->users()->get()->sortBy('name');
return view('common.dashboards.create', compact('users'));
}
/**
* Store a newly created resource in storage.
*
* @param $request
* @return Response
*/
public function store(Request $request)
{
$response = $this->ajaxDispatch(new CreateDashboard($request));
if ($response['success']) {
$response['redirect'] = route('dashboard');
$message = trans('messages.success.added', ['type' => trans_choice('general.dashboards', 1)]);
flash($message)->success();
} else {
$response['redirect'] = route('dashboard');
$message = $response['message'];
flash($message)->error();
}
return response()->json($response);
}
/**
* Show the form for editing the specified resource.
*
* @param Dashboard $dashboard
*
* @return Response
*/
public function edit(Dashboard $dashboard)
{
if (!$this->isUserDashboard($dashboard->id)) {
return redirect()->route('dashboards.index');
}
$users = Company::find(session('company_id'))->users()->get()->sortBy('name');
return view('common.dashboards.edit', compact('dashboard', 'users'));
}
/**
* Update the specified resource in storage.
*
* @param Dashboard $dashboard
* @param $request
* @return Response
*/
public function update(Dashboard $dashboard, Request $request)
{
$response = $this->ajaxDispatch(new UpdateDashboard($dashboard, $request));
if ($response['success']) {
$response['redirect'] = route('dashboards.index');
$message = trans('messages.success.updated', ['type' => trans_choice('general.dashboards', 1)]);
flash($message)->success();
} else {
$response['redirect'] = route('dashboards.edit', $dashboard->id);
$message = $response['message'];
flash($message)->error();
}
return response()->json($response);
}
/**
* Enable the specified resource.
*
* @param Dashboard $dashboard
*
* @return Response
*/
public function enable(Dashboard $dashboard)
{
$response = $this->ajaxDispatch(new UpdateDashboard($dashboard, request()->merge(['enabled' => 1])));
if ($response['success']) {
$response['message'] = trans('messages.success.enabled', ['type' => trans_choice('general.dashboards', 1)]);
}
return response()->json($response);
}
/**
* Disable the specified resource.
*
* @param Dashboard $dashboard
*
* @return Response
*/
public function disable(Dashboard $dashboard)
{
$response = $this->ajaxDispatch(new UpdateDashboard($dashboard, request()->merge(['enabled' => 0])));
if ($response['success']) {
$response['message'] = trans('messages.success.disabled', ['type' => trans_choice('general.dashboards', 1)]);
}
return response()->json($response);
}
/**
* Remove the specified resource from storage.
*
* @param Dashboard $dashboard
*
* @return Response
*/
public function destroy(Dashboard $dashboard)
{
$response = $this->ajaxDispatch(new DeleteDashboard($dashboard));
$response['redirect'] = route('dashboard');
if ($response['success']) {
$message = trans('messages.success.deleted', ['type' => $dashboard->name]);
flash($message)->success();
session(['dashboard_id' => user()->dashboards()->pluck('id')->first()]);
} else {
$message = $response['message'];
flash($message)->error();
}
return response()->json($response);
}
/**
* Change the active dashboard.
*
* @param Dashboard $dashboard
*
* @return Response
*/
public function switch(Dashboard $dashboard)
{
if ($this->isUserDashboard($dashboard->id)) {
session(['dashboard_id' => $dashboard->id]);
}
return redirect()->route('dashboard');
}
}

View File

@ -29,10 +29,6 @@ class CreateUser extends Job
{
$user = User::create($this->request->input());
if ($this->request->has('permissions')) {
$user->permissions()->attach($this->request->get('permissions'));
}
// Upload picture
if ($this->request->file('picture')) {
$media = $this->getMedia($this->request->file('picture'), 'users');
@ -40,10 +36,16 @@ class CreateUser extends Job
$user->attachMedia($media, 'picture');
}
// Attach roles
if ($this->request->has('dashboards')) {
$user->dashboards()->attach($this->request->get('dashboards'));
}
if ($this->request->has('permissions')) {
$user->permissions()->attach($this->request->get('permissions'));
}
$user->roles()->attach($this->request->get('roles'));
// Attach companies
$user->companies()->attach($this->request->get('companies'));
Artisan::call('cache:clear');

View File

@ -28,8 +28,6 @@ class DeleteUser extends Job
{
$this->authorize();
$this->deleteRelationships($this->user, ['widgets', 'dashboards']);
$this->user->delete();
Artisan::call('cache:clear');

View File

@ -0,0 +1,52 @@
<?php
namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Models\Common\Dashboard;
class CreateDashboard extends Job
{
protected $request;
/**
* Create a new job instance.
*
* @param $request
*/
public function __construct($request)
{
$this->request = $this->getRequestInstance($request);
}
/**
* Execute the job.
*
* @return Item
*/
public function handle()
{
$this->request['enabled'] = $this->request['enabled'] ?? 1;
$this->dashboard = Dashboard::create($this->request->all());
$this->attachToUser();
return $this->dashboard;
}
protected function attachToUser()
{
if ($this->request->has('users')) {
$user = $this->request->get('users');
} else {
$user = user();
}
if (empty($user)) {
return;
}
$this->dashboard->users()->attach($user);
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Traits\Users;
use Artisan;
class DeleteDashboard extends Job
{
use Users;
protected $dashboard;
/**
* Create a new job instance.
*
* @param $dashboard
*/
public function __construct($dashboard)
{
$this->dashboard = $dashboard;
}
/**
* Execute the job.
*
* @return boolean
*/
public function handle()
{
$this->authorize();
$this->deleteRelationships($this->dashboard, ['widgets']);
$this->dashboard->delete();
Artisan::call('cache:clear');
return true;
}
/**
* Determine if this action is applicable.
*
* @return void
*/
public function authorize()
{
// Can't delete your last dashboard
if (user()->dashboards()->enabled()->count() == 1) {
$message = trans('dashboards.error.delete_last');
throw new \Exception($message);
}
// Check if user can access dashboard
if (!$this->isUserDashboard($this->dashboard->id)) {
$message = trans('dashboards.error.not_user_dashboard');
throw new \Exception($message);
}
}
}

View File

@ -0,0 +1,70 @@
<?php
namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Models\Common\Dashboard;
use App\Traits\Users;
class UpdateDashboard extends Job
{
use Users;
protected $dashboard;
protected $request;
/**
* Create a new job instance.
*
* @param $dashboard
* @param $request
*/
public function __construct($dashboard, $request)
{
$this->dashboard = $dashboard;
$this->request = $this->getRequestInstance($request);
}
/**
* Execute the job.
*
* @return Dashboard
*/
public function handle()
{
$this->authorize();
$this->dashboard->update($this->request->all());
if ($this->request->has('users')) {
$this->dashboard->users()->sync($this->request->get('users'));
}
return $this->dashboard;
}
/**
* Determine if this action is applicable.
*
* @return void
*/
public function authorize()
{
$user = user();
// Can't delete your last dashboard
if ($this->request->has('users') && !in_array($user->id, (array) $this->request->get('users')) && ($user->dashboards()->enabled()->count() == 1)) {
$message = trans('dashboards.error.delete_last');
throw new \Exception($message);
}
// Check if user can access dashboard
if (!$this->isUserDashboard($this->dashboard->id)) {
$message = trans('dashboards.error.not_user_dashboard');
throw new \Exception($message);
}
}
}

View File

@ -3,7 +3,6 @@
namespace App\Listeners\Menu;
use App\Events\Menu\AdminCreated as Event;
use App\Models\Common\Dashboard;
class AddAdminItems
{
@ -21,7 +20,7 @@ class AddAdminItems
$attr = ['icon' => ''];
// Dashboard
$dashboards = Dashboard::ofUser($user->id)->get();
$dashboards = user()->dashboards()->enabled()->get();
if ($dashboards->count() > 1) {
$menu->dropdown(trim(trans_choice('general.dashboards', 2)), function ($sub) use ($user, $attr, $dashboards) {

View File

@ -695,6 +695,7 @@ class Version200 extends Listener
{
$this->attachPermissions([
'admin' => [
'common-dashboards' => 'c,r,u,d',
'common-reports' => 'c,r,u,d',
'common-search' => 'r',
'common-widgets' => 'c,r,u,d',
@ -720,9 +721,10 @@ class Version200 extends Listener
'widgets-total-profit' => 'r',
],
'manager' => [
'common-dashboards' => 'c,r,u,d',
'common-reports' => 'c,r,u,d',
'common-search' => 'r',
'common-widgets' => 'r',
'common-widgets' => 'c,r,u,d',
'offline-payments-settings' => 'r,u,d',
'paypal-standard-settings' => 'r,u',
'settings-company' => 'r',
@ -885,6 +887,7 @@ class Version200 extends Listener
'app/Http/Controllers/Api/Incomes/Revenues.php',
'app/Http/Controllers/ApiController.php',
'app/Http/Controllers/Controller.php',
'app/Http/Controllers/Common/Dashboard.php',
'app/Http/Controllers/Modals/BillPayments.php',
'app/Http/Controllers/Modals/InvoicePayments.php',
'app/Http/Controllers/modules/Token.php',
@ -1021,6 +1024,7 @@ class Version200 extends Listener
'public/js/highchart',
'public/js/lightbox',
'public/js/moment',
'resources/views/common/dashboard',
'resources/views/customers',
'resources/views/expenses',
'resources/views/incomes',

View File

@ -59,12 +59,7 @@ class User extends Authenticatable
public function dashboards()
{
return $this->hasMany('App\Models\Common\Dashboard');
}
public function widgets()
{
return $this->hasManyThrough('App\Models\Common\Widget', 'App\Models\Common\Dashboard');
return $this->morphToMany('App\Models\Common\Dashboard', 'user', 'user_dashboards', 'user_id', 'dashboard_id');
}
/**

View File

@ -16,7 +16,7 @@ class Dashboard extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'user_id', 'name', 'enabled'];
protected $fillable = ['company_id', 'name', 'enabled'];
/**
* Sortable columns.
@ -25,18 +25,13 @@ class Dashboard extends Model
*/
public $sortable = ['name', 'enabled'];
public function user()
public function users()
{
return $this->belongsTo('App\Models\Auth\User', 'user_id', 'id');
return $this->morphedByMany('App\Models\Auth\User', 'user', 'user_dashboards', 'dashboard_id', 'user_id');
}
public function widgets()
{
return $this->hasMany('App\Models\Common\Widget')->orderBy('sort', 'asc');
}
public function scopeOfUser($query, $user_id)
{
return $query->where('user_id', $user_id);
}
}

View File

@ -2,8 +2,6 @@
namespace App\Traits;
use App\Models\Auth\User;
trait Users
{
/**
@ -39,4 +37,28 @@ trait Users
return false;
}
/**
* Check user dashboard assignment
*
* @param $id
*
* @return boolean
*/
public function isUserDashboard($id)
{
$user = user();
if (empty($user)) {
return false;
}
$dashboards = $user->dashboards()->pluck('id')->toArray();
if (in_array($id, $dashboards)) {
return true;
}
return false;
}
}

View File

@ -108,6 +108,13 @@ return [
],
],
App\Models\Common\Dashboard::class => [
'columns' => [
'name' => ['searchable' => true],
'enabled' => ['boolean' => true],
],
],
App\Models\Common\Item::class => [
'columns' => [
'name' => ['searchable' => true],

View File

@ -16,7 +16,6 @@ class CreateDashboardsTable extends Migration
Schema::create('dashboards', function (Blueprint $table) {
$table->increments('id');
$table->integer('company_id');
$table->integer('user_id');
$table->string('name');
$table->boolean('enabled')->default(1);
$table->timestamps();
@ -25,6 +24,14 @@ class CreateDashboardsTable extends Migration
$table->index(['company_id']);
});
Schema::create('user_dashboards', function (Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->integer('dashboard_id')->unsigned();
$table->string('user_type', 20);
$table->primary(['user_id', 'dashboard_id', 'user_type']);
});
Schema::create('widgets', function (Blueprint $table) {
$table->increments('id');
$table->integer('company_id');
@ -36,7 +43,7 @@ class CreateDashboardsTable extends Migration
$table->timestamps();
$table->softDeletes();
$table->index(['company_id']);
$table->index(['company_id', 'dashboard_id']);
});
}
@ -48,6 +55,7 @@ class CreateDashboardsTable extends Migration
public function down()
{
Schema::drop('dashboards');
Schema::drop('user_dashboards');
Schema::drop('widgets');
}
}

View File

@ -3,9 +3,10 @@
namespace Database\Seeds;
use App\Abstracts\Model;
use App\Models\Auth\User;
use App\Models\Common\Widget;
use App\Models\Common\Dashboard;
use App\Utilities\Widgets as WidgetUtility;
use App\Utilities\Widgets;
use Illuminate\Database\Seeder;
class Dashboards extends Seeder
@ -31,12 +32,11 @@ class Dashboards extends Seeder
$dashboard = Dashboard::create([
'company_id' => $company_id,
'user_id' => $user_id,
'name' => trans('general.dashboard'),
'name' => trans_choice('general.dashboards', 1),
'enabled' => 1,
]);
$widgets = WidgetUtility::getClasses(false);
$widgets = Widgets::getClasses(false);
$sort = 1;
@ -52,5 +52,7 @@ class Dashboards extends Seeder
$sort++;
}
User::find($user_id)->dashboards()->attach($dashboard->id);
}
}

View File

@ -38,6 +38,7 @@ class Roles extends Seeder
'banking-transactions' => 'c,r,u,d',
'banking-transfers' => 'c,r,u,d',
'common-companies' => 'c,r,u,d',
'common-dashboards' => 'c,r,u,d',
'common-import' => 'c',
'common-items' => 'c,r,u,d',
'common-notifications' => 'c,r,u,d',
@ -98,13 +99,14 @@ class Roles extends Seeder
'banking-transactions' => 'c,r,u,d',
'banking-transfers' => 'c,r,u,d',
'common-companies' => 'c,r,u,d',
'common-dashboards' => 'c,r,u,d',
'common-import' => 'c',
'common-items' => 'c,r,u,d',
'common-notifications' => 'c,r,u,d',
'common-reports' => 'c,r,u,d',
'common-search' => 'r',
'common-uploads' => 'r',
'common-widgets' => 'r',
'common-widgets' => 'c,r,u,d',
'purchases-bills' => 'c,r,u,d',
'purchases-payments' => 'c,r,u,d',
'purchases-vendors' => 'c,r,u,d',

View File

@ -1,212 +0,0 @@
<template>
<akaunting-modal
:title="title"
:show="display"
@cancel="onCancel"
v-if="display">
<template #modal-body>
<div class="modal-body text-left">
<div class="row">
<div class="col-md-12">
<base-input
v-model="form.name"
:label="text.name"
prepend-icon="fas fa-tag"
:placeholder="text.name"
inputGroupClasses="input-group-merge"
></base-input>
</div>
<!--
<akaunting-radio-group
:name="'enabled'"
:text="text.enabled"
:value="form.enabled"
@change="onEnabled"
:enable="text.yes"
:disable="text.no"
:col="'col-md-12'"
></akaunting-radio-group>
-->
</div>
</div>
</template>
<template #card-footer>
<div class="row">
<div class="col-md-12">
<div class="float-right">
<button type="button" class="btn btn-icon btn-outline-secondary" @click="onCancel">
<span class="btn-inner--icon"><i class="fas fa-times"></i></span>
<span class="btn-inner--text">{{ text.cancel }}</span>
</button>
<button :disabled="form.loading" type="button" class="btn btn-icon btn-success button-submit" @click="onSave">
<div v-if="form.loading" class="aka-loader-frame"><div class="aka-loader"></div></div>
<span v-if="!form.loading" class="btn-inner--icon"><i class="fas fa-save"></i></span>
<span v-if="!form.loading" class="btn-inner--text">{{ text.save }}</span>
</button>
</div>
</div>
</div>
</template>
</akaunting-modal>
</template>
<script>
import AkauntingModal from "./AkauntingModal";
import AkauntingRadioGroup from './forms/AkauntingRadioGroup';
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import Form from './../plugins/form';
import BulkAction from './../plugins/bulk-action';
import NProgressAxios from './../plugins/nprogress-axios';
export default {
name: 'akaunting-dashobard',
components: {
AkauntingModal,
AkauntingRadioGroup
},
props: {
show: Boolean,
title: {
type: String,
default: '',
description: "Modal header title"
},
text: {},
name: {
type: String,
default: ''
},
enabled: Number,
type: {
type: String,
default: 'create',
description: "Modal header title"
},
dashboard_id: {
type: Number,
default: 0,
description: "Modal header title"
},
},
data() {
return {
form: {
loading: false,
name: this.name,
enabled: this.enabled
},
display: this.show
};
},
methods: {
closeModal() {
this.$emit("update:show", false);
this.$emit("close");
},
onSave() {
this.form.loading = true;
let data = Object.assign({}, this.form);
delete data.loading;
var self = this;
var path = url + '/common/dashboards';
if ((self.type != 'create')) {
path = url + '/common/dashboards/' + self.dashboard_id;
data['_method'] = 'PATCH';
}
axios.post(path, data)
.then(function (response) {
self.form.loading = false;
if (response.data.redirect) {
self.form.loading = true;
window.location.href = response.data.redirect;
}
self.form.response = response.data;
})
.catch(function (error) {
this.errors.record(error.response.data.errors);
self.form.loading = false;
});
},
onCancel() {
this.display = false;
this.form.name = '';
this.form.enabled = 1;
this.$emit("cancel");
},
onEnabled(value) {
this.form.enabled = value;
}
},
watch: {
show(val) {
let documentClasses = document.body.classList;
if (val) {
documentClasses.add("modal-open");
} else {
documentClasses.remove("modal-open");
}
}
}
}
</script>
<style>
.loader10 {
width: 28px;
height: 28px;
border-radius: 50%;
position: relative;
animation: loader10 0.9s ease alternate infinite;
animation-delay: 0.36s;
top: 50%;
margin: -42px auto 0;
}
.loader10::after, .loader10::before {
content: '';
position: absolute;
width: 28px;
height: 28px;
border-radius: 50%;
animation: loader10 0.9s ease alternate infinite;
}
.loader10::before {
left: -40px;
animation-delay: 0.18s;
}
.loader10::after {
right: -40px;
animation-delay: 0.54s;
}
@keyframes loader10 {
0% {
box-shadow: 0 28px 0 -28px #0052ec;
}
100% {
box-shadow: 0 28px 0 #0052ec;
}
}
</style>

View File

@ -11,9 +11,11 @@ import Vue from 'vue';
import DashboardPlugin from './../../plugins/dashboard-plugin';
import Global from './../../mixins/global';
import Form from './../../plugins/form';
import BulkAction from './../../plugins/bulk-action';
import {getQueryVariable} from './../../plugins/functions';
import AkauntingDashboard from './../../components/AkauntingDashboard';
import AkauntingWidget from './../../components/AkauntingWidget';
import {DatePicker, Tooltip} from 'element-ui';
@ -29,7 +31,6 @@ const dashboard = new Vue({
components: {
[DatePicker.name]: DatePicker,
[Tooltip.name]: Tooltip,
AkauntingDashboard,
AkauntingWidget
},
@ -39,13 +40,6 @@ const dashboard = new Vue({
data: function () {
return {
dashboard_modal: false,
dashboard: {
name: '',
enabled: 1,
type: 'create',
dashboard_id: 0
},
widget_modal: false,
widgets: {},
widget: {
@ -57,7 +51,8 @@ const dashboard = new Vue({
sort: 0,
},
filter_date: [],
form: new Form('dashboard'),
bulk_action: new BulkAction('dashboards')
};
},
@ -75,33 +70,6 @@ const dashboard = new Vue({
},
methods:{
// Create Dashboard form open
onCreateDashboard() {
this.dashboard_modal = true;
this.dashboard.name = '';
this.dashboard.enabled = 1;
this.dashboard.type = 'create';
this.dashboard.dashboard_id = 0;
},
// Edit Dashboard information
onEditDashboard(dashboard_id) {
var self = this;
axios.get(url + '/common/dashboards/' + dashboard_id + '/edit')
.then(function (response) {
self.dashboard.name = response.data.name;
self.dashboard.enabled = response.data.enabled;
self.dashboard.type = 'edit';
self.dashboard.dashboard_id = dashboard_id;
self.dashboard_modal = true;
})
.catch(function (error) {
self.dashboard_modal = false;
});
},
// Get All Widgets
getWidgets() {
var self = this;
@ -140,13 +108,6 @@ const dashboard = new Vue({
},
onCancel() {
this.dashboard_modal = false;
this.dashboard.name = '';
this.dashboard.enabled = 1;
this.dashboard.type = 'create';
this.dashboard.dashboard_id = 0;
this.widget_modal = false;
this.widget.id = 0;

View File

@ -4,12 +4,10 @@ return [
'domain' => 'Domain',
'logo' => 'Logo',
'manage' => 'Manage Companies',
'all' => 'All Companies',
'error' => [
'not_user_company' => 'Error: You are not allowed to change this company!',
'delete_active' => 'Error: Can not delete active company, please, change it first!',
'delete_active' => 'Error: Can not delete the active company. Please, switch to another first!',
],
];

View File

@ -0,0 +1,10 @@
<?php
return [
'error' => [
'not_user_dashboard' => 'Error: You are not allowed to change this dashboard!',
'delete_last' => 'Error: Can not delete the last dashboard. Please, create a new one first!',
],
];

View File

@ -52,7 +52,6 @@ return [
'sales' => 'Sale|Sales',
'purchases' => 'Purchases|Purchases',
'dashboard' => 'Dashboard',
'welcome' => 'Welcome',
'banking' => 'Banking',
'general' => 'General',
@ -142,6 +141,8 @@ return [
'cash' => 'Cash',
'group_by' => 'Group By',
'accounting' => 'Accounting',
'sort' => 'Sort',
'width' => 'Width',
'month' => 'Month',
'year' => 'Year',
@ -161,6 +162,7 @@ return [
'send' => 'Send :type',
'get' => 'Get :type',
'add' => 'Add :type',
'manage' => 'Manage :type',
],
'form' => [

View File

@ -0,0 +1,41 @@
@extends('layouts.admin')
@section('title', trans('general.title.new', ['type' => trans_choice('general.dashboards', 1)]))
@section('content')
<div class="card">
{!! Form::open([
'id' => 'dashboard',
'route' => 'dashboards.store',
'@submit.prevent' => 'onSubmit',
'@keydown' => 'form.errors.clear($event.target.name)',
'files' => true,
'role' => 'form',
'class' => 'form-loading-button',
'novalidate' => true,
]) !!}
<div class="card-body">
<div class="row">
{{ Form::textGroup('name', trans('general.name'), 'font') }}
@permission('read-auth-users')
{{ Form::checkboxGroup('users', trans_choice('general.users', 2), $users, 'name') }}
@endpermission
{{ Form::radioGroup('enabled', trans('general.enabled'), true) }}
</div>
</div>
<div class="card-footer">
<div class="row float-right">
{{ Form::saveButtons('common/dashboards') }}
</div>
</div>
{!! Form::close() !!}
</div>
@endsection
@push('scripts_start')
<script src="{{ asset('public/js/common/dashboards.js?v=' . version('short')) }}"></script>
@endpush

View File

@ -0,0 +1,44 @@
@extends('layouts.admin')
@section('title', trans('general.title.edit', ['type' => trans_choice('general.dashboards', 1)]))
@section('content')
<div class="card">
{!! Form::model($dashboard, [
'id' => 'dashboard',
'method' => 'PATCH',
'route' => ['dashboards.update', $dashboard->id],
'@submit.prevent' => 'onSubmit',
'@keydown' => 'form.errors.clear($event.target.name)',
'files' => true,
'role' => 'form',
'class' => 'form-loading-button',
'novalidate' => true,
]) !!}
<div class="card-body">
<div class="row">
{{ Form::textGroup('name', trans('general.name'), 'font') }}
@permission('read-auth-users')
{{ Form::checkboxGroup('users', trans_choice('general.users', 2), $users, 'name') }}
@endpermission
{{ Form::radioGroup('enabled', trans('general.enabled'), $dashboard->enabled) }}
</div>
</div>
@permission('update-common-dashboards')
<div class="card-footer">
<div class="row float-right">
{{ Form::saveButtons('common/dashboards') }}
</div>
</div>
@endpermission
{!! Form::close() !!}
</div>
@endsection
@push('scripts_start')
<script src="{{ asset('public/js/common/dashboards.js?v=' . version('short')) }}"></script>
@endpush

View File

@ -0,0 +1,92 @@
@extends('layouts.admin')
@section('title', trans_choice('general.dashboards', 2))
@permission('create-common-dashboards')
@section('new_button')
<span><a href="{{ route('dashboards.create') }}" class="btn btn-success btn-sm btn-alone"><span class="fa fa-plus"></span> &nbsp;{{ trans('general.add_new') }}</a></span>
@endsection
@endpermission
@section('content')
<div class="card">
<div class="card-header border-bottom-0" v-bind:class="[bulk_action.show ? 'bg-gradient-primary' : '']">
{!! Form::open([
'route' => 'dashboards.index',
'role' => 'form',
'method' => 'GET',
'class' => 'mb-0'
]) !!}
<div class="row" v-if="!bulk_action.show">
<div class="col-12 d-flex align-items-center">
<span class="font-weight-400 d-none d-lg-block mr-2">{{ trans('general.search') }}:</span>
<akaunting-search></akaunting-search>
</div>
</div>
{{ Form::bulkActionRowGroup('general.dashboards', $bulk_actions, 'common/dashboards') }}
{!! Form::close() !!}
</div>
<div class="table-responsive">
<table class="table table-flush table-hover">
<thead class="thead-light">
<tr class="row table-head-line">
<th class="col-sm-2 col-md-2 col-lg-1 col-xl-1 d-none d-sm-block">{{ Form::bulkActionAllGroup() }}</th>
<th class="col-xs-4 col-sm-3 col-md-6 col-lg-7 col-xl-7 long-texts">@sortablelink('name', trans('general.name'))</th>
<th class="col-xs-4 col-sm-3 col-md-2 col-lg-2 col-xl-2">@sortablelink('enabled', trans('general.enabled'))</th>
<th class="col-xs-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 text-center">{{ trans('general.actions') }}</th>
</tr>
</thead>
<tbody>
@foreach($dashboards as $item)
<tr class="row align-items-center border-top-1">
<td class="col-sm-2 col-md-2 col-lg-1 col-xl-1 d-none d-sm-block">{{ Form::bulkActionGroup($item->id, $item->name) }}</td>
<td class="col-xs-4 col-sm-3 col-md-6 col-lg-7 col-xl-7 long-texts"><a class="text-success" href="{{ route('dashboards.edit', $item->id) }}">{{ $item->name }}</a></td>
<td class="col-xs-4 col-sm-3 col-md-2 col-lg-2 col-xl-2">
@if (user()->can('update-common-dashboards'))
{{ Form::enabledGroup($item->id, $item->name, $item->enabled) }}
@else
@if ($item->enabled)
<badge rounded type="success">{{ trans('general.enabled') }}</badge>
@else
<badge rounded type="danger">{{ trans('general.disabled') }}</badge>
@endif
@endif
</td>
<td class="col-xs-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 text-center">
<div class="dropdown">
<a class="btn btn-neutral btn-sm text-light items-align-center py-2" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-ellipsis-h text-muted"></i>
</a>
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
@if ($item->enabled)
<a class="dropdown-item" href="{{ route('dashboards.switch', $item->id) }}">{{ trans('general.switch') }}</a>
<div class="dropdown-divider"></div>
@endif
<a class="dropdown-item" href="{{ route('dashboards.edit', $item->id) }}">{{ trans('general.edit') }}</a>
@permission('delete-common-dashboards')
<div class="dropdown-divider"></div>
{!! Form::deleteLink($item, 'common/dashboards') !!}
@endpermission
</div>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="card-footer table-action">
<div class="row">
@include('partials.admin.pagination', ['items' => $dashboards])
</div>
</div>
</div>
@endsection
@push('scripts_start')
<script src="{{ asset('public/js/common/dashboards.js?v=' . version('short')) }}"></script>
@endpush

View File

@ -3,6 +3,7 @@
@section('title', $dashboard->name)
@section('dashboard_action')
@permission(['create-common-widgets', 'read-common-dashboards'])
<span class="dashboard-action">
<div class="dropdown">
<a class="btn btn-sm items-align-center py-2 mt--1" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@ -10,41 +11,32 @@
</a>
<div class="dropdown-menu dropdown-menu-left dropdown-menu-arrow">
{!! Form::button(trans('general.title.add', ['type' => trans_choice('general.widgets', 1)]), array(
@permission('create-common-widgets')
{!! Form::button(trans('general.title.add', ['type' => trans_choice('general.widgets', 1)]), [
'type' => 'button',
'class' => 'dropdown-item',
'title' => trans('general.title.add', ['type' => trans_choice('general.widgets', 1)]),
'@click' => 'onCreateWidget()'
)) !!}
{!! Form::button(trans('general.title.edit', ['type' => trans_choice('general.dashboard', 1)]), array(
'type' => 'button',
'class' => 'dropdown-item',
'title' => trans('general.title.edit', ['type' => trans_choice('general.dashboard', 1)]),
'@click' => 'onEditDashboard(' . $dashboard->id . ')'
)) !!}
@if ($dashboards->count() > 1)
{!! Form::deleteLink($dashboard, 'common/dashboards') !!}
@endif
'@click' => 'onCreateWidget()',
]) !!}
@endpermission
@permission('read-common-dashboards')
<div class="dropdown-divider"></div>
{!! Form::button(trans('general.title.add', ['type' => trans_choice('general.dashboard', 1)]), array(
'type' => 'button',
'class' => 'dropdown-item',
'title' => trans('general.title.add', ['type' => trans_choice('general.dashboard', 1)]),
'@click' => 'onCreateDashboard()'
)) !!}
@permission('create-common-dashboards')
<a class="dropdown-item" href="{{ route('dashboards.create') }}">{{ trans('general.title.create', ['type' => trans_choice('general.dashboards', 1)]) }}</a>
@endpermission
<a class="dropdown-item" href="{{ route('dashboards.index') }}">{{ trans('general.title.manage', ['type' => trans_choice('general.dashboards', 2)]) }}</a>
@endpermission
</div>
</div>
</span>
@endpermission
@php
$text = json_encode([
'name' => trans('general.name'),
'type' => 'Type',
'width' => 'Width',
'sort' => 'Sort',
'type' => trans_choice('general.types', 1),
'width' => trans('general.width'),
'sort' => trans('general.sort'),
'enabled' => trans('general.enabled'),
'yes' => trans('general.yes'),
'no' => trans('general.no'),
@ -54,24 +46,12 @@
$placeholder = json_encode([
'name' => trans('general.form.enter', ['field' => trans('general.name')]),
'type' => trans('general.form.enter', ['field' => 'Type']),
'width' => trans('general.form.enter', ['field' => 'Width']),
'sort' => trans('general.form.enter', ['field' => 'Sort'])
'type' => trans('general.form.enter', ['field' => trans_choice('general.types', 1)]),
'width' => trans('general.form.enter', ['field' => trans('general.width')]),
'sort' => trans('general.form.enter', ['field' => trans('general.sprt')])
]);
@endphp
<akaunting-dashboard
v-if="dashboard_modal"
:title="'{{ trans('general.dashboard') }}'"
:show="dashboard_modal"
:name="dashboard.name"
:enabled="dashboard.enabled"
:type="dashboard.type"
:dashboard_id="dashboard.dashboard_id"
:text="{{ $text }}"
@cancel="onCancel">
</akaunting-dashboard>
<akaunting-widget
v-if="widget_modal"
:title="'{{ trans_choice('general.widgets', 1) }}'"
@ -181,5 +161,5 @@
@endsection
@push('scripts_start')
<script src="{{ asset('public/js/common/dashboard.js?v=' . version('short')) }}"></script>
<script src="{{ asset('public/js/common/dashboards.js?v=' . version('short')) }}"></script>
@endpush

View File

@ -23,7 +23,7 @@
<div class="dropdown-divider"></div>
<a href="{{ route('companies.index') }}" class="dropdown-item">
<i class="fas fa-cogs"></i>
<span>{{ trans('companies.manage') }}</span>
<span>{{ trans('general.title.manage', ['type' => trans_choice('general.companies', 2)]) }}</span>
</a>
@endpermission
</div>

View File

@ -1,3 +1,4 @@
@permission(['update-common-widgets', 'delete-common-widgets'])
<div class="card-header{{ !empty($header_class) ? ' ' . $header_class : '' }}">
<div class="row align-items-center">
@ -13,17 +14,22 @@
</a>
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
@permission('update-common-widgets')
{!! Form::button(trans('general.edit'), [
'type' => 'button',
'class' => 'dropdown-item',
'title' => trans('general.edit'),
'@click' => 'onEditWidget(' . $model->id . ')'
]) !!}
@endpermission
@permission('delete-common-widgets')
<div class="dropdown-divider"></div>
{!! Form::deleteLink($model, 'common/widgets') !!}
@endpermission
</div>
</div>
</span>
</div>
</div>
</div>
@endpermission

View File

@ -1,3 +1,4 @@
@permission(['update-common-widgets', 'delete-common-widgets'])
<span>
<div class="dropdown card-action-button">
<a class="btn btn-sm items-align-center py-2 mr-0 shadow-none--hover" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@ -5,14 +6,19 @@
</a>
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow">
@permission('update-common-widgets')
{!! Form::button(trans('general.edit'), [
'type' => 'button',
'class' => 'dropdown-item',
'title' => trans('general.edit'),
'@click' => 'onEditWidget(' . $model->id . ')'
]) !!}
@endpermission
@permission('delete-common-widgets')
<div class="dropdown-divider"></div>
{!! Form::deleteLink($model, 'common/widgets') !!}
@endpermission
</div>
</div>
</span>
</span>
@endpermission

View File

@ -10,7 +10,11 @@ Route::group(['prefix' => 'common'], function () {
Route::get('companies/{company}/disable', 'Common\Companies@disable')->name('companies.disable');
Route::resource('companies', 'Common\Companies');
Route::resource('dashboards', 'Common\Dashboard');
Route::get('dashboards/{dashboard}/switch', 'Common\Dashboards@switch')->name('dashboards.switch');
Route::get('dashboards/{dashboard}/enable', 'Common\Dashboards@enable')->name('dashboards.enable');
Route::get('dashboards/{dashboard}/disable', 'Common\Dashboards@disable')->name('dashboards.disable');
Route::resource('dashboards', 'Common\Dashboards');
Route::post('widgets/getData', 'Common\Widgets@getData')->name('widgets.getData');
Route::resource('widgets', 'Common\Widgets');

View File

@ -9,7 +9,7 @@ Route::group(['middleware' => 'auth'], function () {
Route::group(['middleware' => ['permission:read-admin-panel']], function () {
Route::group(['middleware' => ['menu.admin']], function () {
Route::get('/', 'Common\Dashboard@index')->name('dashboard');
Route::get('/', 'Common\Dashboards@show')->name('dashboard');
});
Route::get('wizard', 'Wizard\Companies@edit')->name('wizard.edit');

2
webpack.mix.js vendored
View File

@ -31,7 +31,7 @@ mix
// Common
.js('resources/assets/js/views/common/items.js', 'public/js/common')
.js('resources/assets/js/views/common/companies.js', 'public/js/common')
.js('resources/assets/js/views/common/dashboard.js', 'public/js/common')
.js('resources/assets/js/views/common/dashboards.js', 'public/js/common')
.js('resources/assets/js/views/common/reports.js', 'public/js/common')
.js('resources/assets/js/views/common/search.js', 'public/js/common')