Role Creation and Tree Vue Component Comnpleted

This commit is contained in:
jitendra 2018-07-05 13:28:26 +05:30
parent 79d303f54d
commit 97b1cf0d0e
71 changed files with 3514 additions and 2904 deletions

8
Laracel Command Normal file
View File

@ -0,0 +1,8 @@
php artisan make:controller UserController && mv app/Http/Controllers/UserController.php packages/Webkul/User/src/Ht
tp/Controllers
php artisan make:migration foo --path=packages/Webkul/User/src/Database/migrations
php artisan db:seed --class=Webkul\\User\\Database\\Seeders\\DatabaseSeeder
php artisan route:cache

View File

@ -13,7 +13,7 @@ return [
|
*/
'name' => env('APP_NAME', 'Laravel'),
'name' => env('APP_NAME', 'Bagisto'),
/*
|--------------------------------------------------------------------------

View File

@ -18,6 +18,6 @@
"vue": "^2.1.10"
},
"dependencies": {
"vee-validate": "^2.1.0-beta.3"
"vee-validate": "2.0.0-rc.26"
}
}

View File

@ -33,5 +33,13 @@ return [
'driver' => 'eloquent',
'model' => Webkul\User\Models\Admin::class,
]
]
],
'passwords' => [
'admins' => [
'provider' => 'admins',
'table' => 'admin_password_resets',
'expire' => 60,
],
],
];

View File

@ -3,28 +3,49 @@
Route::group(['middleware' => ['web']], function () {
Route::prefix('admin')->group(function () {
Route::get('/login', 'Webkul\User\Http\Controllers\SeesionController@create')->defaults('_config', [
'view' => 'admin::sessions.create'
// Login Routes
Route::get('/login', 'Webkul\User\Http\Controllers\SessionController@create')->defaults('_config', [
'view' => 'admin::users.sessions.create'
])->name('admin.session.create');
Route::post('/login', 'Webkul\User\Http\Controllers\SeesionController@store')->defaults('_config', [
'redirect' => 'admin/dashboard'
])->name('admin.session.store');
Route::post('/login', 'Webkul\User\Http\Controllers\SessionController@store')->defaults('_config', [
'redirect' => 'admin.dashboard.index'
])->name('admin.forget-password.store');
// Forget Password Routes
Route::get('/forget-password', 'Webkul\User\Http\Controllers\ForgetPasswordController@create')->defaults('_config', [
'view' => 'admin::users.forget-password.create'
])->name('admin.forget-password.create');
Route::post('/forget-password', 'Webkul\User\Http\Controllers\ForgetPasswordController@store')->name('admin.forget-password.store');
// Reset Password Routes
Route::get('/reset-password/{token}', 'Webkul\User\Http\Controllers\ResetPasswordController@create')->defaults('_config', [
'view' => 'admin::users.reset-password.create'
])->name('admin.reset-password.create');
Route::post('/reset-password', 'Webkul\User\Http\Controllers\ResetPasswordController@store')->defaults('_config', [
'redirect' => 'admin.dashboard.index'
])->name('admin.reset-password.store');
// Admin Routes
Route::group(['middleware' => ['admin']], function () {
Route::get('/logout', 'Webkul\User\Http\Controllers\SeesionController@destroy')->defaults('_config', [
'redirect' => 'admin/login'
Route::get('/logout', 'Webkul\User\Http\Controllers\SessionController@destroy')->defaults('_config', [
'redirect' => 'admin.session.create'
])->name('admin.session.destroy');
Route::get('/dashboard', 'Webkul\Admin\Http\Controllers\DashboardController@index')->name('admin.dashboard.index');
// User Routes
Route::get('/users', 'Webkul\User\Http\Controllers\UserController@index')->defaults('_config', [
'view' => 'admin::users.index'
'view' => 'admin::users.users.index'
])->name('admin.users.index');
Route::get('/users/create', 'Webkul\User\Http\Controllers\UserController@create')->defaults('_config', [
'view' => 'admin::users.create'
'view' => 'admin::users.users.create'
])->name('admin.users.create');
Route::post('/users/create', 'Webkul\User\Http\Controllers\UserController@store')->defaults('_config', [
@ -32,7 +53,7 @@ Route::group(['middleware' => ['web']], function () {
])->name('admin.users.store');
Route::get('/users/edit/{id}', 'Webkul\User\Http\Controllers\UserController@edit')->defaults('_config', [
'view' => 'admin::users.edit'
'view' => 'admin::users.users.edit'
])->name('admin.users.edit');
Route::put('/users/edit/{id}', 'Webkul\User\Http\Controllers\UserController@update')->defaults('_config', [
@ -41,11 +62,11 @@ Route::group(['middleware' => ['web']], function () {
// User Role Routes
Route::get('/roles', 'Webkul\User\Http\Controllers\RoleController@index')->defaults('_config', [
'view' => 'admin::roles.index'
'view' => 'admin::users.roles.index'
])->name('admin.roles.index');
Route::get('/roles/create', 'Webkul\User\Http\Controllers\RoleController@create')->defaults('_config', [
'view' => 'admin::roles.create'
'view' => 'admin::users.roles.create'
])->name('admin.roles.create');
Route::post('/roles/create', 'Webkul\User\Http\Controllers\RoleController@store')->defaults('_config', [
@ -53,7 +74,7 @@ Route::group(['middleware' => ['web']], function () {
])->name('admin.roles.store');
Route::get('/roles/edit/{id}', 'Webkul\User\Http\Controllers\RoleController@edit')->defaults('_config', [
'view' => 'admin::roles.edit'
'view' => 'admin::users.roles.edit'
])->name('admin.roles.edit');
Route::put('/roles/edit/{id}', 'Webkul\User\Http\Controllers\RoleController@update')->defaults('_config', [

View File

@ -5,7 +5,7 @@ namespace Webkul\Admin\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Blade;
use Webkul\Ui\Menu;
use Webkul\Admin\Providers\EventServiceProvider;
class AdminServiceProvider extends ServiceProvider
{
@ -26,42 +26,11 @@ class AdminServiceProvider extends ServiceProvider
$this->loadViewsFrom(__DIR__ . '/../Resources/views', 'admin');
$this->createAdminMenu();
$this->composeView();
Blade::directive('continue', function() { return "<?php continue; ?>"; });
}
/**
* This method fires an event for menu creation, any package can add their menu item by listening to the admin.menu.build event
*
* @return void
*/
public function createAdminMenu()
{
Event::listen('admin.menu.create', function() {
return Menu::create(function($menu) {
Event::fire('admin.menu.build', $menu);
});
});
Event::listen('admin.menu.build', function($menu) {
$menu->add('dashboard', 'Dashboard', route('admin.dashboard.index'), 1, 'icon-dashboard');
$menu->add('configuration', 'Configure', route('admin.account.edit'), 6, 'icon-configuration');
$menu->add('configuration.account', 'My Account', route('admin.account.edit'), 1, '');
$menu->add('settings', 'Settings', route('admin.users.index'), 6, 'icon-settings');
$menu->add('settings.users', 'Users', route('admin.users.index'), 1, '');
$menu->add('settings.users.users', 'Users', route('admin.users.index'), 1, '');
$menu->add('settings.users.roles', 'Roles', route('admin.roles.index'), 1, '');
});
$this->app->register(EventServiceProvider::class);
}
/**

View File

@ -0,0 +1,93 @@
<?php
namespace Webkul\Admin\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\View;
use Webkul\Ui\Menu;
class EventServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->createAdminMenu();
$this->buildACL();
$this->registerACL();
}
/**
* This method fires an event for menu creation, any package can add their menu item by listening to the admin.menu.build event
*
* @return void
*/
public function createAdminMenu()
{
Event::listen('admin.menu.create', function() {
return Menu::create(function($menu) {
Event::fire('admin.menu.build', $menu);
});
});
Event::listen('admin.menu.build', function($menu) {
$menu->add('dashboard', 'Dashboard', 'admin.dashboard.index', 1, 'dashboard-icon');
$menu->add('configuration', 'Configure', 'admin.account.edit', 6, 'configuration-icon');
$menu->add('configuration.account', 'My Account', 'admin.account.edit', 1);
$menu->add('settings', 'Settings', 'admin.users.index', 6, 'settings-icon');
$menu->add('settings.users', 'Users', 'admin.users.index', 1, '');
$menu->add('settings.users.users', 'Users', 'admin.users.index', 1, '');
$menu->add('settings.users.roles', 'Roles', 'admin.roles.index', 2, '');
});
}
/**
* Build route based ACL
*
* @return voidbuildACL
*/
public function buildACL()
{
Event::listen('admin.acl.build', function($acl) {
$acl->add('dashboard', 'Dashboard', 'admin.dashboard.index', 1);
$acl->add('configuration', 'Configure', 'admin.account.edit', 5);
$acl->add('settings', 'Settings', 'admin.users.index', 6);
$acl->add('settings.users', 'Users', 'admin.users.index');
$acl->add('settings.users.users', 'Users', 'admin.users.index');
$acl->add('settings.users.roles', 'Roles', 'admin.roles.index');
$acl->add('settings.users.roles1', 'Roles 1', 'admin.roles.index');
});
}
/**
* Registers acl to entire application
*
* @return void
*/
public function registerACL()
{
$this->app->singleton('acl', function() {
return current(Event::fire('admin.acl.create'));
});
View::share('acl', app('acl'));
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -28,7 +28,7 @@
<div class="accordian-content">
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name">{{ __('Name') }}</label>
<input type="text" v-validate="'required'" class="control" id="email" name="name" value="{{ $user->name }}"/>
<input type="text" v-validate="'required'" class="control" id="name" name="name" value="{{ $user->name }}"/>
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
</div>
@ -44,13 +44,13 @@
<div class="accordian-content">
<div class="control-group" :class="[errors.has('password') ? 'has-error' : '']">
<label for="password">{{ __('Password') }}</label>
<input type="password" v-validate="'min:6|max:18'" class="control" id="password" name="password"/>
<input type="password" v-validate="'min:6'" class="control" id="password" name="password"/>
<span class="control-error" v-if="errors.has('password')">@{{ errors.first('password') }}</span>
</div>
<div class="control-group" :class="[errors.has('password_confirmation') ? 'has-error' : '']">
<label for="password_confirmation">{{ __('Confirm Password') }}</label>
<input type="password" v-validate="'min:6|max:18|confirmed:password'" class="control" id="password_confirmation" name="password_confirmation"/>
<input type="password" v-validate="'min:6|confirmed:password'" class="control" id="password_confirmation" name="password_confirmation"/>
<span class="control-error" v-if="errors.has('password_confirmation')">@{{ errors.first('password_confirmation') }}</span>
</div>
</div>

View File

@ -0,0 +1,115 @@
<!DOCTYPE html>
<html lang="{{ config('app.locale') }}">
<head>
<title>@yield('page_title')</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="{{ asset('vendor/webkul/admin/assets/css/admin.css') }}">
<link rel="stylesheet" href="{{ asset('vendor/webkul/ui/assets/css/ui.css') }}">
<style>
.container {
text-align: center;
position: absolute;
width: 100%;
height: 100%;
display: table;
z-index: 1;
background: #F8F9FA;
}
.center-box {
display: table-cell;
vertical-align: middle;
}
.adjacent-center {
width: 365px;
display: inline-block;
text-align: left;
}
.form-container .control-group .control {
width: 100%;
}
h1 {
font-size: 24px;
font-weight: 600;
margin-bottom: 30px;
}
.brand-logo {
margin-bottom: 30px;
text-align: center;
}
.footer {
margin-top: 40px;
padding: 0 20px;
}
.footer p {
font-size: 14px;
color: #8E8E8E;
text-align: center;
}
.btn.btn-primary {
width: 100%;
}
</style>
@yield('css')
</head>
<body>
<div id="app" class="container">
<flash-wrapper ref='flashes'></flash-wrapper>
<div class="center-box">
<div class="adjacent-center">
<div class="brand-logo">
<img src="{{ asset('vendor/webkul/admin/assets/images/logo.png') }}" alt="Bagisto"/>
</div>
@yield('content')
<div class="footer">
<p>
© Copyright 2018 Webkul Software, All rights reserved.
</p>
</div>
</div>
</div>
</div>
<script type="text/javascript">
window.flashMessages = [];
@if($success = session('success'))
window.flashMessages = [{'type': 'alert-success', 'message': "{{ $success }}" }];
@elseif($warning = session('warning'))
window.flashMessages = [{'type': 'alert-warning', 'message': "{{ $warning }}" }];
@elseif($error = session('error'))
window.flashMessages = [{'type': 'alert-error', 'message': "{{ $error }}" }];
@endif
window.serverErrors = [];
@if (count($errors))
window.serverErrors = @json($errors->getMessages());
@endif
</script>
<script type="text/javascript" src="{{ asset('vendor/webkul/admin/assets/js/admin.js') }}"></script>
<script type="text/javascript" src="{{ asset('vendor/webkul/ui/assets/js/ui.js') }}"></script>
@yield('javascript')
</body>
</html>

View File

@ -1,47 +0,0 @@
<!DOCTYPE html>
<html lang="{{ config('app.locale') }}">
<head>
<title>@yield('page_title')</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="{{ asset('vendor/webkul/admin/assets/css/admin.css') }}">
</head>
<body>
<div class="container">
<form method="POST" action="login">
@csrf
<div class="element-block">
<label for="email" class="field-label"></label>
<div class="field-block">
<input type="text" class="field" id="email" name="email"/>
</div>
</div>
<div class="element-block">
<label for="password" class="field-label"></label>
<div class="field-block">
<input type="password" class="field" id="password" name="password"/>
</div>
</div>
@if (count($errors))
@foreach ($errors->all() as $error)
{{ $error }}
@endforeach
@endif
<div class="button-block">
<button type="submit" class="button">Login</button>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,55 @@
@extends('admin::layouts.anonymous-master')
@section('page_title')
{{ __('Forget Password') }}
@stop
@section('css')
<style>
.button-group {
margin-bottom: 25px;
}
.primary-back-icon {
vertical-align: middle;
}
</style>
@stop
@section('content')
<div class="panel">
<div class="panel-content">
<div class="form-container" style="text-align: left">
<h1>{{ __('Recover Password') }}</h1>
<form method="POST" action="{{ route('admin.forget-password.store') }}" @submit.prevent="onSubmit">
@csrf
<div class="control-group" :class="[errors.has('email') ? 'has-error' : '']">
<label for="email">{{ __('Registered Email') }}</label>
<input type="text" v-validate="'required'" class="control" id="email" name="email" value="{{ old('email') }}"/>
<span class="control-error" v-if="errors.has('email')">@{{ errors.first('email') }}</span>
</div>
<div class="button-group">
<button class="btn btn-xl btn-primary">{{ __('Email Password Reset Link') }}</button>
</div>
<div class="control-group" style="margin-bottom: 0">
<a href="{{ route('admin.session.create') }}">
<i class="icon primary-back-icon"></i>
{{ __('Back to Sign In') }}
</a>
</div>
</form>
</div>
</div>
</div>
@stop

View File

@ -0,0 +1,69 @@
@extends('admin::layouts.anonymous-master')
@section('page_title')
{{ __('Reset Password') }}
@stop
@section('css')
<style>
.button-group {
margin-bottom: 25px;
}
.primary-back-icon {
vertical-align: middle;
}
</style>
@stop
@section('content')
<div class="panel">
<div class="panel-content">
<div class="form-container" style="text-align: left">
<h1>{{ __('Reset Password') }}</h1>
<form method="POST" action="{{ route('admin.reset-password.store') }}" @submit.prevent="onSubmit">
@csrf
<input type="hidden" name="token" value="{{ $token }}">
<div class="control-group" :class="[errors.has('email') ? 'has-error' : '']">
<label for="email">{{ __('Email') }}</label>
<input type="text" v-validate="'required|email'" class="control" id="email" name="email" value="{{ old('email') }}"/>
<span class="control-error" v-if="errors.has('email')">@{{ errors.first('email') }}</span>
</div>
<div class="control-group" :class="[errors.has('password') ? 'has-error' : '']">
<label for="password">{{ __('Password') }}</label>
<input type="password" v-validate="'required|min:6'" class="control" id="password" name="password"/>
<span class="control-error" v-if="errors.has('password')">@{{ errors.first('password') }}</span>
</div>
<div class="control-group" :class="[errors.has('password_confirmation') ? 'has-error' : '']">
<label for="password_confirmation">{{ __('Confirm Password') }}</label>
<input type="password" v-validate="'required|min:6|confirmed:password'" class="control" id="password_confirmation" name="password_confirmation" data-vv-as="password"/>
<span class="control-error" v-if="errors.has('password_confirmation')">@{{ errors.first('password_confirmation') }}</span>
</div>
<div class="button-group">
<button type="submit" class="btn btn-xl btn-primary">{{ __('Reset Password') }}</button>
</div>
<div class="control-group" style="margin-bottom: 0">
<a href="{{ route('admin.session.create') }}">
<i class="icon primary-back-icon"></i>
{{ __('Back to Sign In') }}
</a>
</div>
</form>
</div>
</div>
</div>
@stop

View File

@ -2,6 +2,7 @@
@section('content')
<div class="content">
<form method="POST" action="{{ route('admin.roles.store') }}" @submit.prevent="onSubmit">
<div class="page-header">
<div class="page-title">
@ -45,12 +46,27 @@
</div>
<div class="control-group">
<tree-view/>
</div>
<tree-view value-field="route" id-field="key" value-field="route" items='@json($acl->items)'></tree-view>
</div>
</div>
</accordian>
</div>
</div>
</form>
</div>
@stop
@section('javascript')
<script>
$(document).ready(function () {
$('#permission_type').on('change', function(e) {
if($(e.target).val() == 'custom') {
$('.tree-container').removeClass('hide')
} else {
$('.tree-container').addClass('hide')
}
})
});
</script>
@stop

View File

@ -0,0 +1,55 @@
@extends('admin::layouts.anonymous-master')
@section('page_title')
{{ __('Sign In') }}
@stop
@section('content')
<div class="panel">
<div class="panel-content">
<div class="form-container" style="text-align: left">
<h1>{{ __('Sign In') }}</h1>
<form method="POST" action="login" @submit.prevent="onSubmit">
@csrf
<div class="control-group" :class="[errors.has('email') ? 'has-error' : '']">
<label for="email">{{ __('Email') }}</label>
<input type="text" v-validate="'required'" class="control" id="email" name="email"/>
<span class="control-error" v-if="errors.has('email')">@{{ errors.first('email') }}</span>
</div>
<div class="control-group" :class="[errors.has('password') ? 'has-error' : '']">
<label for="password">{{ __('Password') }}</label>
<input type="password" v-validate="'required|min:6'" class="control" id="password" name="password"/>
<span class="control-error" v-if="errors.has('password')">@{{ errors.first('password') }}</span>
</div>
<div class="control-group">
<a href="{{ route('admin.forget-password.create') }}">{{ __('Forget Password ?') }}</a>
</div>
<div class="control-group">
<span class="checkbox">
<input type="checkbox" id="remember" name="remember" value="1">
<label class="checkbox-view" for="remember"></label>
{{ __('Remember me') }}
</span>
</div>
<div class="button-group">
<button class="btn btn-xl btn-primary">{{ __('Sign In') }}</button>
</div>
</form>
</div>
</div>
</div>
@stop

View File

@ -5,6 +5,7 @@ require('laravel-mix-merge-manifest');
var publicPath = '../../../public/vendor/webkul/admin/assets';
mix.setPublicPath(publicPath).mergeManifest();
mix.disableNotifications();
mix.js(__dirname + '/src/Resources/assets/js/app.js', 'js/admin.js')
.copyDirectory( __dirname + '/src/Resources/assets/images', publicPath + '/images')

View File

@ -36,16 +36,18 @@ class Menu {
*
* @param string $key Dot seperated heirarchy
* @param string $name Text for the anchor
* @param string $url URL for the anchor
* @param string $route Route for the menu
* @param integer $sort Sorting index for the items
* @param string $iconClass Icon Class name
*/
public function add($key, $name, $url, $sort = 0, $iconClass = null)
public function add($key, $name, $route, $sort = 0, $iconClass = null)
{
$url = route($route);
$item = [
'key' => $key,
'name' => $name,
'url' => $url,
'route' => $route,
'sort' => $sort,
'icon-class' => $iconClass,
'children' => []

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Expand-Light-On</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Expand-Light-On" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(2.000000, 6.000000)" fill="#8E8E8E" id="Path-2">
<polygon points="0 0 13.3424655 0 6.67123275 7.3125"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Angle-Right</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Angle-Right" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<polyline id="Path-3" stroke="#A2A2A2" stroke-width="3" points="7 3 14 10.058476 7.11598308 17"></polyline>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Expand-Light</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Expand-Light" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(9.000000, 9.000000) rotate(-90.000000) translate(-9.000000, -9.000000) translate(2.000000, 5.000000)" fill="#3A3A3A" id="Path-2">
<polygon points="0 0 13.3424655 0 6.67123275 7.3125"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 710 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Checkbox-Checked</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Checkbox-Checked" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Base" stroke="#0041FF" stroke-width="2" fill="#0041FF" x="1" y="1" width="22" height="22" rx="2"></rect>
<g id="Check-Accent" transform="translate(6.000000, 7.000000)" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="3">
<polyline id="Path-2" points="0 5 4 9 13 0"></polyline>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 824 B

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Checkbox</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Checkbox" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Base" stroke="#C7C7C7" stroke-width="2" fill="#FFFFFF" x="1" y="1" width="22" height="22" rx="2"></rect>
</g>
</svg>

After

Width:  |  Height:  |  Size: 574 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Expand-Light-On</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Expand-Light-On" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(2.000000, 6.000000)" fill="#8E8E8E" id="Path-2">
<polygon points="0 0 13.3424655 0 6.67123275 7.3125"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Expand-Light</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Expand-Light" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(9.000000, 9.000000) rotate(-90.000000) translate(-9.000000, -9.000000) translate(2.000000, 5.000000)" fill="#3A3A3A" id="Path-2">
<polygon points="0 0 13.3424655 0 6.67123275 7.3125"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 710 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Icon-Back-Primary</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Icon-Back-Primary" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g id="Icon-Sort-Down" transform="translate(12.000000, 12.000000) scale(-1, 1) translate(-12.000000, -12.000000) translate(3.000000, 6.000000)" stroke="#0041FF" stroke-width="2">
<path d="M1,6 L16.068125,6" id="Path-3"></path>
<polyline id="Path-4" points="12 0 18 6.08548298 12 12"></polyline>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 856 B

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="41px" height="41px" viewBox="0 0 41 41" style="enable-background:new 0 0 41 41;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:#333333;}
.st2{fill:#B1B1AE;}
</style>
<path class="st0" d="M31,21.5L31,21.5c5.2,0,9.5,4.3,9.5,9.5l0,0c0,5.2-4.3,9.5-9.5,9.5l0,0c-5.2,0-9.5-4.3-9.5-9.5l0,0
C21.5,25.8,25.8,21.5,31,21.5z"/>
<circle class="st1" cx="31" cy="31" r="5"/>
<g id="checkbox">
<path class="st0" d="M3.5,0.5h13c1.7,0,3,1.3,3,3v13c0,1.7-1.3,3-3,3h-13c-1.7,0-3-1.3-3-3v-13C0.5,1.8,1.8,0.5,3.5,0.5z"/>
<path class="st2" d="M16.5,20h-13C1.6,20,0,18.4,0,16.5v-13C0,1.6,1.6,0,3.5,0h13C18.4,0,20,1.6,20,3.5v13C20,18.4,18.4,20,16.5,20
z M3.5,1C2.1,1,1,2.1,1,3.5v13C1,17.9,2.1,19,3.5,19h13c1.4,0,2.5-1.1,2.5-2.5v-13C19,2.1,17.9,1,16.5,1H3.5z"/>
</g>
<path id="checkbox-checked" class="st1" d="M17,41H3c-1.7,0-3-1.3-3-3V24c0-1.7,1.3-3,3-3h14c1.7,0,3,1.3,3,3v14
C20,39.7,18.7,41,17,41z M13.3,26l-5.9,5.7l-1.7-1.6L4,31.7L7.4,35l7.6-7.4L13.3,26z"/>
<g id="checkbox_1_">
<path class="st0" d="M31,0.5L31,0.5c5.2,0,9.5,4.3,9.5,9.5l0,0c0,5.2-4.3,9.5-9.5,9.5l0,0c-5.2,0-9.5-4.3-9.5-9.5l0,0
C21.5,4.8,25.8,0.5,31,0.5z"/>
<path class="st2" d="M31,20c-5.5,0-10-4.5-10-10c0-5.5,4.5-10,10-10c5.5,0,10,4.5,10,10C41,15.5,36.5,20,31,20z M31,1c-5,0-9,4-9,9
c0,5,4,9,9,9c5,0,9-4,9-9C40,5,36,1,31,1z"/>
</g>
<path id="radio-checked" class="st1" d="M31,41c-5.5,0-10-4.5-10-10s4.5-10,10-10s10,4.5,10,10S36.5,41,31,41z M31,22c-5,0-9,4-9,9
s4,9,9,9s9-4,9-9S36,22,31,22z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -2,4 +2,5 @@ Vue.component('flash-wrapper', require('./components/flash-wrapper'))
Vue.component('flash', require('./components/flash'))
Vue.component('accordian', require('./components/accordian'))
Vue.component('tree-view', require('./components/tree-view/tree-view'))
Vue.component('tree-item', require('./components/tree-view/tree-item'))
Vue.component('tree-checkbox', require('./components/tree-view/tree-checkbox'))

View File

@ -13,7 +13,7 @@
var this_this = this;
setTimeout(function() {
this_this.$emit('onRemoveFlash', this_this.flash)
}, 1000)
}, 5000)
},
methods: {

View File

@ -1 +0,0 @@
export { default as Treeview } from './tree-view';

View File

@ -1,21 +0,0 @@
<template>
<span class="checkbox">
<input type="checkbox" name="permissions[]" :id="inputValue" v-model="inputValue" @change="inputChanged($event)" :checked="isChecked">
<label class="checkbox-view" :for="inputValue"></label>
{{ label }}
</span>
</template>
<script>
export default {
name: 'tree-checkbox',
props: ['label', 'inputValue', 'isChecked'],
methods: {
inputChanged (e) {
this.$emit('change', this.inputValue)
}
}
}
</script>

View File

@ -1,147 +0,0 @@
<script>
export default {
name: 'tree-view',
inheritAttrs: false,
props: {
items: {
type: Object,
required: false,
default: () => ({
"name": "Root",
"value": "1",
"children": [{
"name": "First Child",
"value": "2",
}, {
"name": "Second Child",
"value": "3",
"children": [{
"name": "GrandChild 1",
"value": "4",
}, {
"name": "GrandChild 2",
"value": "5",
}, {
"name":"GrandChild 3",
"value": "6",
}]
}]
})
},
value: {
type: Array,
required: false,
default: () => ([])
}
},
computed: {
allChildren () {
let leafs = [];
let searchTree = items => {
if(!! items['children'] && items['children'].length > 0) {
items['children'].forEach(child => searchTree(child))
} else {
leafs.push(items)
}
}
searchTree(this.items)
return leafs;
},
hasChildren () {
return !! this.items['children'] && this.items['children'].length > 0;
},
hasSelection () {
return !! this.value && this.value.length > 0;
},
isAllChildrenSelected () {
return this.hasChildren && this.hasSelection && this.allChildren.every(leaf => this.value.some(sel => sel === leaf.value))
},
isSomeChildrenSelected () {
return this.hasSelection && this.allChildren.some(leaf => this.value.some(sel => sel === leaf.value))
},
isChecked () {
return this.hasChildren ? this.isSomeChildrenSelected : (this.value.indexOf(this.items['value']) === -1 ? false : true);
}
},
methods: {
generateRoot () {
return this.$createElement('tree-checkbox', {
props: {
label: this.items['name'],
inputValue: this.items['value'],
isChecked: this.isChecked
},
on: {
change: selection => {
if(this.hasChildren) {
if(this.isAllChildrenSelected) {
this.allChildren.forEach(leaf => {
let index = this.value.indexOf(leaf.value)
this.value.splice(index, 1)
})
} else {
this.allChildren.forEach(leaf => {
let index = this.value.indexOf(leaf.value)
if(index === -1) {
this.value.push(leaf.value);
}
})
}
this.$emit('input', this.value)
} else {
this.$emit('input', selection);
}
}
}
})
},
generateChildren () {
let childElements = [];
if(this.items['children']) {
this.items['children'].forEach(child => {
childElements.push(this.generateChild(child));
})
}
return childElements;
},
generateChild (child) {
return this.$createElement('tree-view', {
class: 'tree-item',
on: {
input: selection => {
// Main Turning Point
console.log(this.items)
this.$emit('input', selection)
}
},
props: {
items: child,
value: this.value
}
})
}
},
render (createElement) {
return createElement('div', {}, [this.generateRoot(), ... this.generateChildren()])
}
}
</script>

View File

@ -1,8 +1,8 @@
<template>
<span class="checkbox">
<input type="checkbox" name="permissions[]" :id="inputValue" :value="inputValue.value" @change="inputChanged($event)" :checked="isActive">
<label class="checkbox-view" :for="inputValue"></label>
{{ inputValue }} ======== {{ value }}
<input type="checkbox" :id="id" name="permissions[]" :value="modelValue" @change="inputChanged()" :checked="isActive">
<label class="checkbox-view" :for="id"></label>
<span class="" :for="id">{{ label }}</span>
</span>
</template>
@ -10,11 +10,63 @@
export default {
name: 'tree-checkbox',
props: ['label', 'inputValue', 'value'],
props: ['id', 'label', 'modelValue', 'inputValue', 'value'],
computed: {
isMultiple () {
return Array.isArray(this.internalValue)
},
isActive () {
const value = this.value
const input = this.internalValue
if (this.isMultiple) {
return input.some(item => this.valueComparator(item, value))
}
return value ? this.valueComparator(value, input) : Boolean(input)
},
internalValue: {
get () {
return this.lazyValue
},
set (val) {
this.lazyValue = val
this.$emit('input', val)
}
}
},
data: vm => ({
lazyValue: vm.inputValue
}),
watch: {
inputValue (val) {
this.internalValue = val
}
},
methods: {
inputChanged (e) {
this.$emit('change', this.inputValue)
inputChanged () {
const value = this.value
let input = this.internalValue
if (this.isMultiple) {
const length = input.length
input = input.filter(item => !this.valueComparator(item, value))
if (input.length === length) {
input.push(value)
}
} else {
input = !input
}
this.$emit('change', input)
},
valueComparator (a, b) {
@ -33,28 +85,6 @@
return props.every(p => this.valueComparator(a[p], b[p]))
}
},
computed: {
isMultiple () {
return Array.isArray(this.inputValue)
},
isActive () {
const value = this.value
const input = this.inputValue
if (this.isMultiple) {
if (!Array.isArray(input))
return false
return input.some(item => this.valueComparator(item, value))
}
var isChecked = value ? this.valueComparator(value, input) : Boolean(input)
return isChecked;
},
}
}
</script>

View File

@ -0,0 +1,189 @@
<script>
export default {
name: 'tree-view',
inheritAttrs: false,
props: {
idField: String,
captionField: String,
childrenField: String,
valueField: String,
items: {
type: [Array, String, Object],
required: false,
default: null
},
value: {
type: Array,
required: false,
default: null
}
},
computed: {
caption () {
return this.items[this.captionField]
},
allChildren () {
let leafs = [];
let searchTree = items => {
if(!! items[this.childrenField] && this.getLength(items[this.childrenField]) > 0) {
if(typeof items[this.childrenField] == 'object') {
for(let key in items[this.childrenField]) {
searchTree(items[this.childrenField][key])
}
} else {
items[this.childrenField].forEach(child => searchTree(child))
}
} else {
leafs.push(items)
}
}
searchTree(this.items)
return leafs;
},
hasChildren () {
return !! this.items[this.childrenField] && this.getLength(this.items[this.childrenField]) > 0;
},
hasSelection () {
return !! this.value && this.value.length > 0;
},
isAllChildrenSelected () {
return this.hasChildren && this.hasSelection && this.allChildren.every(leaf => this.value.some(sel => sel[this.idField] === leaf[this.idField]))
},
isSomeChildrenSelected () {
return this.hasChildren && this.hasSelection && this.allChildren.some(leaf => this.value.some(sel => sel[this.idField] === leaf[this.idField]))
}
},
methods: {
getLength (items) {
if(typeof items == 'object') {
let length = 0;
for(let item in items) {
length++;
}
return length;
}
return items.length;
},
generateRoot () {
return this.$createElement('tree-checkbox', {
props: {
id: this.items[this.idField],
label: this.caption,
modelValue: this.items[this.valueField],
inputValue: this.hasChildren ? this.isSomeChildrenSelected : this.value,
value: this.hasChildren ? this.isAllChildrenSelected : this.items
},
on: {
change: selection => {
if(this.hasChildren) {
if(this.isAllChildrenSelected) {
this.allChildren.forEach(leaf => {
let index = this.value.indexOf(leaf)
this.value.splice(index, 1)
})
} else {
this.allChildren.forEach(leaf => {
let exists = false;
this.value.forEach(item => {
if(item['key'] == leaf['key']) {
exists = true;
}
})
if(!exists) {
this.value.push(leaf);
}
})
}
this.$emit('input', this.value)
} else {
this.$emit('input', selection);
}
}
}
})
},
generateChild (child) {
return this.$createElement('tree-item', {
on: {
input: selection => {
this.$emit('input', selection)
}
},
props: {
items: child,
value: this.value,
captionField: this.captionField,
childrenField: this.childrenField,
valueField: this.valueField,
idField: this.idField,
}
})
},
generateChildren () {
let childElements = [];
if(this.items[this.childrenField]) {
if(typeof this.items[this.childrenField] == 'object') {
for(let key in this.items[this.childrenField]) {
childElements.push(this.generateChild(this.items[this.childrenField][key]));
}
} else {
this.items[this.childrenField].forEach(child => {
childElements.push(this.generateChild(child));
})
}
}
return childElements;
},
generateIcon () {
return this.$createElement('i', {
class: ['expand-icon'],
on: {
click: selection => {
this.$el.classList.toggle("active")
}
}
})
}
},
render (createElement) {
return createElement('div', {
class: [
'tree-item',
'active',
this.hasChildren ? 'has-children' : ''
]
}, [
this.generateIcon(), this.generateRoot(), ... this.generateChildren()
]
)
}
}
</script>

View File

@ -6,30 +6,57 @@
inheritAttrs: false,
props: {
items: {
type: Object,
idField: {
type: String,
required: false,
default: () => ({
"name": "Root",
"value": "1",
"children": [{
"name": "First Child",
"value": "2",
default: 'id'
},
captionField: {
type: String,
required: false,
default: 'name'
},
childrenField: {
type: String,
required: false,
default: 'children'
},
valueField: {
type: String,
required: false,
default: 'value'
},
items: {
type: [Array, String, Object],
required: false,
default: () => ([{
"name": "Dashboard",
"value": "1",
}, {
"name": "Second Child",
"value": "3",
"name": "Root",
"value": "2",
"children": [{
"name": "GrandChild 1",
"value": "4",
}, {
"name": "GrandChild 2",
"value": "5",
}, {
"name":"GrandChild 3",
"value": "6",
}]
}]
})
"name": "First Child",
"value": "3",
}, {
"name": "Second Child",
"value": "4",
"children": [{
"name": "GrandChild 1",
"value": "5",
}, {
"name": "GrandChild 2",
"value": "6",
}, {
"name":"GrandChild 3",
"value": "7",
}]
}]
}])
},
value: {
@ -39,102 +66,54 @@
}
},
computed: {
allChildren () {
let leafs = [];
let searchTree = items => {
if(!! items['children'] && items['children'].length > 0) {
items['children'].forEach(child => searchTree(child))
} else {
leafs.push(items)
}
}
searchTree(this.items)
return leafs;
},
hasChildren () {
return !! this.items['children'] && this.items['children'].length > 0;
},
hasSelection () {
return !! this.value && this.value.length > 0;
},
isAllChildrenSelected () {
return this.hasChildren && this.hasSelection && this.allChildren.every(leaf => this.value.some(sel => sel === leaf))
},
isSomeChildrenSelected () {
return this.hasSelection && this.allChildren.some(leaf => this.value.some(sel => sel === leaf))
}
created() {
this.finalValues = this.value;
},
data: () => ({
finalValues: []
}),
methods: {
generateRoot () {
return this.$createElement('tree-checkbox', {
props: {
label: this.items['name'],
inputValue: this.hasChildren ? this.isAllChildrenSelected : this.value,
value: this.hasChildren ? this.isAllChildrenSelected : this.items
},
on: {
change: selection => {
if(this.hasChildren) {
if(this.isAllChildrenSelected) {
this.allChildren.forEach(leaf => {
let index = this.value.indexOf(leaf)
this.value.splice(index, 1)
})
} else {
this.allChildren.forEach(leaf => {
let index = this.value.indexOf(leaf)
if(index === -1) {
this.value.push(leaf);
}
})
}
this.$emit('input', this.value)
} else {
this.$emit('input', selection);
}
}
}
})
},
generateChild (child) {
return this.$createElement('tree-view', {
class: 'tree-item',
on: {
input: selection => {
this.$emit('input', selection)
}
},
props: {
items: child,
value: this.value
}
})
},
generateChildren () {
let childElements = [];
if(this.items['children']) {
this.items['children'].forEach(child => {
childElements.push(this.generateChild(child));
})
let items = (typeof this.items == 'string') ? JSON.parse(this.items) : this.items;
for(let key in items) {
childElements.push(this.generateTreeItem(items[key]));
}
return childElements;
},
generateTreeItem(item) {
return this.$createElement('tree-item', {
props: {
items: item,
value: this.finalValues,
captionField: this.captionField,
childrenField: this.childrenField,
valueField: this.valueField,
idField: this.idField
},
on: {
input: selection => {
this.finalValues = selection;
}
},
})
}
},
render (createElement) {
return createElement('div', {}, [this.generateRoot(), ... this.generateChildren()])
return createElement('div', {
class: [
'tree-container',
]
}, [this.generateChildren()]
)
}
}
</script>

View File

@ -21,6 +21,7 @@ a:visited,
a:focus,
a:active {
text-decoration: none;
color: $brand-color;
}
ul {
@ -40,6 +41,10 @@ h2 {
color: #3A3A3A;
}
.hide {
display: none !important;
}
.btn {
@include box-shadow(0 1px 4px 0 rgba(0, 0, 0, 0.20), 0 0 8px 0 rgba(0, 0, 0, 0.10));
border-radius: 3px;
@ -65,10 +70,12 @@ h2 {
}
&.btn-xl {
padding: 12px 24px;
font-size: 16px;
}
&.btn-primary {
background: $brand-color;
color: #ffffff;
}
&[disabled="disabled"],
@ -244,10 +251,9 @@ h2 {
}
.checkbox-view {
background-image: url('../images/controls.svg');
background-position: 0px 0px;
height: 20px;
width: 20px;
background-image: url('../images/Checkbox.svg');
height: 24px;
width: 24px;
margin: 0;
display: inline-block !important;
vertical-align: middle;
@ -255,7 +261,7 @@ h2 {
}
input:checked + .checkbox-view {
background-position: 0px -21px;
background-image: url('../images/Checkbox-Checked.svg');
}
input:disabled + .checkbox-view {
@ -298,68 +304,66 @@ h2 {
}
}
.form-container {
.control-group {
.control-group {
display: block;
margin-bottom: 25px;
font-size: 15px;
color: #333333;
width: 750px;
max-width: 100%;
label {
display: block;
margin-bottom: 25px;
color: #3A3A3A;
}
textarea.control {
height: 100px;
}
.control {
background: #fff;
border: 2px solid $control-border-color;
border-radius: 3px;
width: 70%;
height: 36px;
display: inline-block;
vertical-align: middle;
transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
padding: 0px 10px;
font-size: 15px;
color: #333333;
width: 750px;
max-width: 100%;
margin-top: 10px;
margin-bottom: 5px;
label {
display: block;
color: #3A3A3A;
&:focus {
border-color: $brand-color;
}
textarea.control {
height: 100px;
&[disabled="disabled"] {
border-color: #D3D3D3;
background-color: #D3D3D3;
cursor: not-allowed;
}
}
.control {
background: #fff;
border: 2px solid $control-border-color;
border-radius: 3px;
width: 70%;
height: 36px;
display: inline-block;
vertical-align: middle;
transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
padding: 0px 10px;
font-size: 15px;
margin-top: 10px;
margin-bottom: 5px;
.control-info {
display: block;
font-style: italic;
color: #6F6F6F;
}
&:focus {
border-color: $brand-color;
}
.control-error {
display: none;
color: #FF5656;
margin-top: 5px;
}
&[disabled="disabled"] {
border-color: #D3D3D3;
background-color: #D3D3D3;
cursor: not-allowed;
}
}
&.has-error .control {
border-color: $danger-color;
}
.control-info {
display: block;
font-style: italic;
color: #6F6F6F;
}
.control-error {
display: none;
color: #FF5656;
margin-top: 5px;
}
&.has-error .control {
border-color: $danger-color;
}
&.has-error .control-error {
display: block;
}
&.has-error .control-error {
display: block;
}
}
@ -369,6 +373,7 @@ h2 {
right: 10px;
position: fixed;
z-index: 6;
text-align: left;
.alert {
width: 300px;
@ -458,13 +463,55 @@ h2 {
}
}
.tree-item {
padding-left: 30px;
display: inline-block;
width: 100%;
.tree-container {
.tree-item {
padding-left: 30px;
display: inline-block;
margin-top: 10px;
width: 100%;
.checkbox {
margin: 0;
margin-bottom: 5px;
> .tree-item {
display: none;
}
&.active > .tree-item {
display: inline-block;
}
.checkbox {
margin: 0;
display: inline-block;
}
.expand-icon {
display: inline-block;
margin-right: 10px;
cursor: pointer;
background-image: url('../images/Expand-Light.svg');
width: 18px;
height: 18px;
vertical-align: middle;
}
&.active {
> .expand-icon {
background-image: url('../images/Expand-Light-On.svg');
}
}
}
> .tree-item {
padding-left: 0;
}
}
.panel {
box-shadow: 0 2px 25px 0 rgba(0,0,0,0.15);
border-radius: 5px;
background: #fff;
.panel-content {
padding: 20px;
}
}

View File

@ -10,15 +10,15 @@
display: inline-block;
background-size: cover;
}
.icon-dashboard {
.dashboard-icon {
@extend %menu-properties;
background-image: url('../images/Icon-Dashboard.svg');
}
.icon-configuration {
.configuration-icon {
@extend %menu-properties;
background-image: url('../images/Icon-Configure.svg');
}
.icon-settings {
.settings-icon {
@extend %menu-properties;
background-image: url('../images/Icon-Settings.svg');
}
@ -41,6 +41,12 @@
height: 8px;
}
.arrow-right-icon {
background-image: url('../images/Arrow-Right.svg');
width: 18px;
height: 18px;
}
.white-cross-sm-icon {
background-image: url('../images/Icon-Sm-Cross-White.svg');
width: 18px;
@ -94,6 +100,12 @@
height: 18px;
}
.primary-back-icon {
background-image: url('../images/Icon-Back-Primary.svg');
width: 24px;
height: 24px;
}
.active {
.icon-dashboard {
background-image: url('../images/Icon-Dashboard-Active.svg');
@ -114,15 +126,15 @@
height: 8px;
}
&.icon-dashboard {
&.dashboard-icon {
background-image: url('../images/Icon-Dashboard-Active.svg');
}
&.icon-settings {
&.settings-icon {
background-image: url('../images/Icon-Settings-Active.svg');
}
&.icon-configuration {
&.configuration-icon {
@extend %menu-properties;
background-image: url('../images/Icon-Configure-Active.svg');
}

View File

@ -343,6 +343,10 @@
<i class="icon arrow-down-icon active"></i>
</span>
<span class="icon-wrapper">
<i class="icon arrow-right-icon"></i>
</span>
<span class="icon-wrapper">
<i class="icon white-cross-sm-icon"></i>
</span>

View File

@ -1,10 +1,12 @@
const { mix } = require('laravel-mix');
require('laravel-mix-merge-manifest');
// var publicPath = 'publishable/assets';
var publicPath = '../../../public/vendor/webkul/ui/assets';
mix.setPublicPath(publicPath).mergeManifest();
mix.disableNotifications();
mix.js([
__dirname + '/src/Resources/assets/js/app.js',

View File

@ -0,0 +1,62 @@
<?php
namespace Webkul\User;
class ACLCreator {
public $items = [];
/**
* Shortcut method for create a acl with a callback.
* This will allow you to do things like fire an event on creation.
*
* @param callable $callback Callback to use after the acl creation
* @return object
*/
public static function create($callback) {
$acl = new ACLCreator();
$callback($acl);
$acl->sortItems($acl->items);
return $acl;
}
/**
* Add a acl item to the item stack
*
* @param string $key Dot seperated heirarchy
* @param string $name Text for the anchor
* @param string $route Route for the acl
* @param integer $sort Sorting index for the items
*/
public function add($key, $name, $route, $sort = 0)
{
$item = [
'key' => $key,
'name' => $name,
'route' => $route,
'sort' => $sort,
'children' => []
];
$children = str_replace('.', '.children.', $key);
array_set($this->items, $children, $item);
}
/**
* Method to sort through the acl items and put them in order
*
* @return void
*/
public function sortItems($items) {
usort($items, function($a, $b) {
if ($a['sort'] == $b['sort']) {
return 0;
}
return ($a['sort'] < $b['sort']) ? -1 : 1;
});
return $items;
}
}

View File

@ -12,7 +12,7 @@ class RolesTableSeeder extends Seeder
$Role = new Role();
$Role->name = 'Administrator';
$Role->description = 'Administrator role';
$Role->status = true;
$Role->permission_type = 'all';
$Role->permissions = [];
$Role->save();
}

View File

@ -4,7 +4,7 @@ use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class Foo extends Migration
class CreateAdminPasswordResetsTable extends Migration
{
/**
* Run the migrations.
@ -13,7 +13,11 @@ class Foo extends Migration
*/
public function up()
{
//
Schema::create('admin_password_resets', function (Blueprint $table) {
$table->string('email')->index();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
}
/**
@ -23,6 +27,6 @@ class Foo extends Migration
*/
public function down()
{
//
Schema::dropIfExists('admin_password_resets');
}
}

View File

@ -16,7 +16,8 @@ class CreateRolesTable extends Migration
Schema::create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('description');
$table->string('description')->nullable();
$table->string('permission_type');
$table->json('permissions')->nullable();
$table->timestamps();
});

View File

@ -10,8 +10,18 @@ namespace Webkul\User\Http\Controllers;
*/
class AccountController extends Controller
{
/**
* Contains route related configuration
*
* @var array
*/
protected $_config;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->_config = request('_config');

View File

@ -0,0 +1,85 @@
<?php
namespace Webkul\User\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Support\Facades\Password;
/**
* Admin forget password controller
*
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class ForgetPasswordController extends Controller
{
use SendsPasswordResetEmails;
/**
* Contains route related configuration
*
* @var array
*/
protected $_config;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->_config = request('_config');
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view($this->_config['view']);
}
/**
* Store a newly created resource in storage.
*
* @return \Illuminate\Http\Response
*/
public function store()
{
$this->validate(request(), [
'email' => 'required|email'
]);
$response = $this->broker()->sendResetLink(
request(['email'])
);
if($response == Password::RESET_LINK_SENT) {
session()->flash('success', trans($response));
return back();
}
return back()
->withInput(request(['email']))
->withErrors(
['email' => trans($response)]
);
}
/**
* Get the broker to be used during password reset.
*
* @return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker()
{
return Password::broker('admins');
}
}

View File

@ -0,0 +1,117 @@
<?php
namespace Webkul\User\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\Hash;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Support\Str;
/**
* Admin reset password controller
*
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class ResetPasswordController extends Controller
{
use ResetsPasswords;
/**
* Contains route related configuration
*
* @var array
*/
protected $_config;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->_config = request('_config');
}
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* @param \Illuminate\Http\Request $request
* @param string|null $token
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function create(Request $request, $token = null)
{
return view($this->_config['view'])->with(
['token' => $token, 'email' => $request->email]
);
}
/**
* Store a newly created resource in storage.
*
* @return \Illuminate\Http\Response
*/
public function store()
{
$this->validate(request(), [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed|min:6',
]);
$response = $this->broker()->reset(
request(['email', 'password', 'password_confirmation', 'token']), function ($admin, $password) {
$this->resetPassword($admin, $password);
}
);
if($response == Password::PASSWORD_RESET) {
return redirect()->route($this->_config['redirect']);
}
return back()
->withInput(request(['email']))
->withErrors([
'email' => trans($response)
]);
}
/**
* Reset the given admin's password.
*
* @param \Illuminate\Contracts\Auth\CanResetPassword $admin
* @param string $password
* @return void
*/
protected function resetPassword($admin, $password)
{
$admin->password = Hash::make($password);
$admin->setRememberToken(Str::random(60));
$admin->save();
event(new PasswordReset($admin));
auth()->guard('admin')->login($admin);
}
/**
* Get the broker to be used during password reset.
*
* @return \Illuminate\Contracts\Auth\PasswordBroker
*/
public function broker()
{
return Password::broker('admins');
}
}

View File

@ -4,7 +4,6 @@ namespace Webkul\User\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Webkul\User\Models\Role;
/**
@ -15,8 +14,18 @@ use Webkul\User\Models\Role;
*/
class RoleController extends Controller
{
/**
* Contains route related configuration
*
* @var array
*/
protected $_config;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->_config = request('_config');
@ -50,6 +59,12 @@ class RoleController extends Controller
*/
public function store(Request $request)
{
$this->validate(request(), [
'name' => 'required',
'permission_type' => 'required',
]);
Role::create(request()->all());
session()->flash('success', 'Role created successfully.');

View File

@ -4,7 +4,6 @@ namespace Webkul\User\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
/**
* Admin user session controller
@ -12,10 +11,20 @@ use Illuminate\Routing\Controller;
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class SeesionController extends Controller
class SessionController extends Controller
{
/**
* Contains route related configuration
*
* @var array
*/
protected $_config;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->_config = request('_config');
@ -40,13 +49,19 @@ class SeesionController extends Controller
*/
public function store()
{
if(! auth()->guard('admin')->attempt(request(['email', 'password']))) {
return back()->withErrors([
'message' => 'Please check your credentials and try again.'
]);
$this->validate(request(), [
'email' => 'required|email',
'password' => 'required'
]);
$remember = request('remember');
if(! auth()->guard('admin')->attempt(request(['email', 'password']), $remember)) {
session()->flash('error', 'Please check your credentials and try again.');
return back();
}
return redirect($this->_config['redirect']);
return redirect()->route($this->_config['redirect']);
}
/**
@ -59,6 +74,6 @@ class SeesionController extends Controller
{
auth()->guard('admin')->logout();
return redirect($this->_config['redirect']);
return redirect()->route($this->_config['redirect']);
}
}

View File

@ -4,7 +4,6 @@ namespace Webkul\User\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Webkul\User\Models\Admin;
use Webkul\User\Models\Role;
use Webkul\User\Http\Requests\UserForm;
@ -17,8 +16,18 @@ use Webkul\User\Http\Requests\UserForm;
*/
class UserController extends Controller
{
/**
* Contains route related configuration
*
* @var array
*/
protected $_config;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->_config = request('_config');

View File

@ -5,6 +5,8 @@ namespace Webkul\User\Models;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Webkul\User\Models\Role;
use Webkul\User\Notifications\AdminResetPassword;
class Admin extends Authenticatable
{
@ -36,6 +38,17 @@ class Admin extends Authenticatable
return $this->belongsTo(Role::class);
}
/**
* Send the password reset notification.
*
* @param string $token
* @return void
*/
public function sendPasswordResetNotification($token)
{
$this->notify(new AdminResetPassword($token));
}
/**
* Checks if admin has permission to perform certain action.
*

View File

@ -7,6 +7,16 @@ use Webkul\User\Models\Admin;
class Role extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'description', 'permission_type', 'permissions',
];
protected $casts = [
'permissions' => 'array'
];

View File

@ -0,0 +1,28 @@
<?php
namespace Webkul\User\Notifications;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Auth\Notifications\ResetPassword;
class AdminResetPassword extends ResetPassword
{
/**
* Build the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable, $this->token);
}
return (new MailMessage)
->line('You are receiving this email because we received a password reset request for your account.')
->action('Reset Password', route('admin.reset-password.create', $this->token))
->line('If you did not request a password reset, no further action is required.');
}
}

View File

@ -5,9 +5,11 @@ namespace Webkul\User\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Event;
use Webkul\User\Bouncer;
use Webkul\User\Facades\Bouncer as BouncerFacade;
use Webkul\User\Http\Middleware\RedirectIfNotAdmin;
use Webkul\User\ACLCreator;
class UserServiceProvider extends ServiceProvider
{
@ -21,6 +23,22 @@ class UserServiceProvider extends ServiceProvider
$router->aliasMiddleware('admin', RedirectIfNotAdmin::class);
$this->loadMigrationsFrom(__DIR__ . '/../Database/migrations');
$this->createACL();
}
/**
* This method fires an event for acl creation, any package can add their acl item by listening to the admin.acl.build event
*
* @return void
*/
public function createACL()
{
Event::listen('admin.acl.create', function() {
return ACLCreator::create(function($acl) {
Event::fire('admin.acl.build', $acl);
});
});
}
/**

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="147px" height="60px" viewBox="0 0 147 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Logo+Text</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Sign-In" transform="translate(-726.000000, -100.000000)">
<g id="Paper" transform="translate(618.000000, 100.000000)">
<g id="Logo+Text-LG" transform="translate(108.000000, 0.000000)">
<g id="Logo+Text">
<g id="Logo">
<rect id="Rectangle" fill="#0041FF" x="0" y="16" width="44" height="44"></rect>
<rect id="Rectangle" fill="#000311" x="0" y="54" width="44" height="6"></rect>
<path d="M36,15.2214765 L36,25.557047 C36,26.9062527 34.9580948,28 33.6728395,28 C32.3875843,28 31.345679,26.9062527 31.345679,25.557047 L31.345679,15.2214765 C31.345679,9.51329856 26.9376184,4.88590604 21.5,4.88590604 C16.0623816,4.88590604 11.654321,9.51329856 11.654321,15.2214765 L11.654321,25.557047 C11.654321,26.9062527 10.6124157,28 9.32716049,28 C8.04190524,28 7,26.9062527 7,25.557047 L7,15.2214765 C7,6.81488716 13.4918711,0 21.5,0 C29.5081289,0 36,6.81488716 36,15.2214765 Z" id="Combined-Shape" fill="#000311"></path>
</g>
<text id="bagisto" font-family="Montserrat-SemiBold, Montserrat" font-size="24" font-weight="500" letter-spacing="-0.3839998" fill="#0041FF">
<tspan x="59" y="45">bagisto</tspan>
</text>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="147px" height="60px" viewBox="0 0 147 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Logo+Text</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Sign-In" transform="translate(-726.000000, -100.000000)">
<g id="Paper" transform="translate(618.000000, 100.000000)">
<g id="Logo+Text-LG" transform="translate(108.000000, 0.000000)">
<g id="Logo+Text">
<g id="Logo">
<rect id="Rectangle" fill="#0041FF" x="0" y="16" width="44" height="44"></rect>
<rect id="Rectangle" fill="#000311" x="0" y="54" width="44" height="6"></rect>
<path d="M36,15.2214765 L36,25.557047 C36,26.9062527 34.9580948,28 33.6728395,28 C32.3875843,28 31.345679,26.9062527 31.345679,25.557047 L31.345679,15.2214765 C31.345679,9.51329856 26.9376184,4.88590604 21.5,4.88590604 C16.0623816,4.88590604 11.654321,9.51329856 11.654321,15.2214765 L11.654321,25.557047 C11.654321,26.9062527 10.6124157,28 9.32716049,28 C8.04190524,28 7,26.9062527 7,25.557047 L7,15.2214765 C7,6.81488716 13.4918711,0 21.5,0 C29.5081289,0 36,6.81488716 36,15.2214765 Z" id="Combined-Shape" fill="#000311"></path>
</g>
<text id="bagisto" font-family="Montserrat-SemiBold, Montserrat" font-size="24" font-weight="500" letter-spacing="-0.3839998" fill="#0041FF">
<tspan x="59" y="45">bagisto</tspan>
</text>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
.icon-dashboard, .icon-configuration, .icon-settings, .active .icon-configuration, .active.icon-configuration {
.dashboard-icon, .configuration-icon, .settings-icon, .active .icon-configuration, .active.configuration-icon {
width: 48px;
height: 48px;
margin-bottom: 10px;
@ -11,15 +11,15 @@
background-size: cover;
}
.icon-dashboard {
.dashboard-icon {
background-image: url("../images/Icon-Dashboard.svg");
}
.icon-configuration {
.configuration-icon {
background-image: url("../images/Icon-Configure.svg");
}
.icon-settings {
.settings-icon {
background-image: url("../images/Icon-Settings.svg");
}
@ -41,6 +41,12 @@
height: 8px;
}
.arrow-right-icon {
background-image: url("../images/Arrow-Right.svg");
width: 18px;
height: 18px;
}
.white-cross-sm-icon {
background-image: url("../images/Icon-Sm-Cross-White.svg");
width: 18px;
@ -95,6 +101,12 @@
height: 18px;
}
.primary-back-icon {
background-image: url("../images/Icon-Back-Primary.svg");
width: 24px;
height: 24px;
}
.active .icon-dashboard {
background-image: url("../images/Icon-Dashboard-Active.svg");
}
@ -113,15 +125,15 @@
height: 8px;
}
.active.icon-dashboard {
.active.dashboard-icon {
background-image: url("../images/Icon-Dashboard-Active.svg");
}
.active.icon-settings {
.active.settings-icon {
background-image: url("../images/Icon-Settings-Active.svg");
}
.active.icon-configuration {
.active.configuration-icon {
background-image: url("../images/Icon-Configure-Active.svg");
}
@ -221,6 +233,7 @@ a:visited,
a:focus,
a:active {
text-decoration: none;
color: #0041FF;
}
ul {
@ -240,6 +253,10 @@ h2 {
color: #3A3A3A;
}
.hide {
display: none !important;
}
.btn {
-webkit-box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.2), 0 0 8px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.2), 0 0 8px 0 rgba(0, 0, 0, 0.1);
@ -271,10 +288,12 @@ h2 {
.btn.btn-xl {
padding: 12px 24px;
font-size: 16px;
}
.btn.btn-primary {
background: #0041FF;
color: #ffffff;
}
.btn[disabled="disabled"], .btn[disabled="disabled"]:hover, .btn[disabled="disabled"]:active {
@ -453,10 +472,9 @@ h2 {
}
.checkbox .checkbox-view {
background-image: url("../images/controls.svg");
background-position: 0px 0px;
height: 20px;
width: 20px;
background-image: url("../images/Checkbox.svg");
height: 24px;
width: 24px;
margin: 0;
display: inline-block !important;
vertical-align: middle;
@ -464,7 +482,7 @@ h2 {
}
.checkbox input:checked + .checkbox-view {
background-position: 0px -21px;
background-image: url("../images/Checkbox-Checked.svg");
}
.checkbox input:disabled + .checkbox-view {
@ -506,7 +524,7 @@ h2 {
cursor: not-allowed;
}
.form-container .control-group {
.control-group {
display: block;
margin-bottom: 25px;
font-size: 15px;
@ -515,16 +533,16 @@ h2 {
max-width: 100%;
}
.form-container .control-group label {
.control-group label {
display: block;
color: #3A3A3A;
}
.form-container .control-group textarea.control {
.control-group textarea.control {
height: 100px;
}
.form-container .control-group .control {
.control-group .control {
background: #fff;
border: 2px solid #C7C7C7;
border-radius: 3px;
@ -540,33 +558,33 @@ h2 {
margin-bottom: 5px;
}
.form-container .control-group .control:focus {
.control-group .control:focus {
border-color: #0041FF;
}
.form-container .control-group .control[disabled="disabled"] {
.control-group .control[disabled="disabled"] {
border-color: #D3D3D3;
background-color: #D3D3D3;
cursor: not-allowed;
}
.form-container .control-group .control-info {
.control-group .control-info {
display: block;
font-style: italic;
color: #6F6F6F;
}
.form-container .control-group .control-error {
.control-group .control-error {
display: none;
color: #FF5656;
margin-top: 5px;
}
.form-container .control-group.has-error .control {
.control-group.has-error .control {
border-color: #FC6868;
}
.form-container .control-group.has-error .control-error {
.control-group.has-error .control-error {
display: block;
}
@ -576,6 +594,7 @@ h2 {
right: 10px;
position: fixed;
z-index: 6;
text-align: left;
}
.alert-wrapper .alert {
@ -664,13 +683,51 @@ h2 {
display: inline-block;
}
.tree-item {
.tree-container .tree-item {
padding-left: 30px;
display: inline-block;
margin-top: 10px;
width: 100%;
}
.tree-item .checkbox {
margin: 0;
margin-bottom: 5px;
.tree-container .tree-item > .tree-item {
display: none;
}
.tree-container .tree-item.active > .tree-item {
display: inline-block;
}
.tree-container .tree-item .checkbox {
margin: 0;
display: inline-block;
}
.tree-container .tree-item .expand-icon {
display: inline-block;
margin-right: 10px;
cursor: pointer;
background-image: url("../images/Expand-Light.svg");
width: 18px;
height: 18px;
vertical-align: middle;
}
.tree-container .tree-item.active > .expand-icon {
background-image: url("../images/Expand-Light-On.svg");
}
.tree-container > .tree-item {
padding-left: 0;
}
.panel {
-webkit-box-shadow: 0 2px 25px 0 rgba(0, 0, 0, 0.15);
box-shadow: 0 2px 25px 0 rgba(0, 0, 0, 0.15);
border-radius: 5px;
background: #fff;
}
.panel .panel-content {
padding: 20px;
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Expand-Light-On</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Expand-Light-On" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(2.000000, 6.000000)" fill="#8E8E8E" id="Path-2">
<polygon points="0 0 13.3424655 0 6.67123275 7.3125"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Expand-Light-On</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Expand-Light-On" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(2.000000, 6.000000)" fill="#8E8E8E" id="Path-2">
<polygon points="0 0 13.3424655 0 6.67123275 7.3125"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Expand-Light</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Expand-Light" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(9.000000, 9.000000) rotate(-90.000000) translate(-9.000000, -9.000000) translate(2.000000, 5.000000)" fill="#3A3A3A" id="Path-2">
<polygon points="0 0 13.3424655 0 6.67123275 7.3125"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 710 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Checkbox-Checked</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Checkbox-Checked" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Base" stroke="#0041FF" stroke-width="2" fill="#0041FF" x="1" y="1" width="22" height="22" rx="2"></rect>
<g id="Check-Accent" transform="translate(6.000000, 7.000000)" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="3">
<polyline id="Path-2" points="0 5 4 9 13 0"></polyline>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 824 B

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Checkbox</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Checkbox" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Base" stroke="#C7C7C7" stroke-width="2" fill="#FFFFFF" x="1" y="1" width="22" height="22" rx="2"></rect>
</g>
</svg>

After

Width:  |  Height:  |  Size: 574 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Expand-Light-On</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Expand-Light-On" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(2.000000, 6.000000)" fill="#8E8E8E" id="Path-2">
<polygon points="0 0 13.3424655 0 6.67123275 7.3125"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Expand-Light</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Expand-Light" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(9.000000, 9.000000) rotate(-90.000000) translate(-9.000000, -9.000000) translate(2.000000, 5.000000)" fill="#3A3A3A" id="Path-2">
<polygon points="0 0 13.3424655 0 6.67123275 7.3125"></polygon>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 710 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
<title>Icon-Back-Primary</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Icon-Back-Primary" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g id="Icon-Sort-Down" transform="translate(12.000000, 12.000000) scale(-1, 1) translate(-12.000000, -12.000000) translate(3.000000, 6.000000)" stroke="#0041FF" stroke-width="2">
<path d="M1,6 L16.068125,6" id="Path-3"></path>
<polyline id="Path-4" points="12 0 18 6.08548298 12 12"></polyline>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 856 B

View File

@ -177,8 +177,8 @@ module.exports = function normalizeComponent (
/***/ (function(module, exports, __webpack_require__) {
__webpack_require__(2);
__webpack_require__(17);
module.exports = __webpack_require__(19);
__webpack_require__(19);
module.exports = __webpack_require__(21);
/***/ }),
@ -189,7 +189,8 @@ Vue.component('flash-wrapper', __webpack_require__(3));
Vue.component('flash', __webpack_require__(6));
Vue.component('accordian', __webpack_require__(9));
Vue.component('tree-view', __webpack_require__(12));
Vue.component('tree-checkbox', __webpack_require__(14));
Vue.component('tree-item', __webpack_require__(14));
Vue.component('tree-checkbox', __webpack_require__(16));
/***/ }),
/* 3 */
@ -388,7 +389,7 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
var this_this = this;
setTimeout(function () {
this_this.$emit('onRemoveFlash', this_this.flash);
}, 1000);
}, 5000);
},
methods: {
@ -616,7 +617,7 @@ module.exports = Component.exports
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
/* harmony default export */ __webpack_exports__["default"] = ({
name: 'tree-view',
@ -624,31 +625,58 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
inheritAttrs: false,
props: {
idField: {
type: String,
required: false,
default: 'id'
},
captionField: {
type: String,
required: false,
default: 'name'
},
childrenField: {
type: String,
required: false,
default: 'children'
},
valueField: {
type: String,
required: false,
default: 'value'
},
items: {
type: Object,
type: [Array, String, Object],
required: false,
default: function _default() {
return {
return [{
"name": "Dashboard",
"value": "1"
}, {
"name": "Root",
"value": "1",
"value": "2",
"children": [{
"name": "First Child",
"value": "2"
"value": "3"
}, {
"name": "Second Child",
"value": "3",
"value": "4",
"children": [{
"name": "GrandChild 1",
"value": "4"
}, {
"name": "GrandChild 2",
"value": "5"
}, {
"name": "GrandChild 3",
"name": "GrandChild 2",
"value": "6"
}, {
"name": "GrandChild 3",
"value": "7"
}]
}]
};
}];
}
},
@ -661,116 +689,54 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
}
},
computed: {
allChildren: function allChildren() {
var leafs = [];
var searchTree = function searchTree(items) {
if (!!items['children'] && items['children'].length > 0) {
items['children'].forEach(function (child) {
return searchTree(child);
});
} else {
leafs.push(items);
}
};
created: function created() {
this.finalValues = this.value;
},
searchTree(this.items);
return leafs;
},
hasChildren: function hasChildren() {
return !!this.items['children'] && this.items['children'].length > 0;
},
hasSelection: function hasSelection() {
return !!this.value && this.value.length > 0;
},
isAllChildrenSelected: function isAllChildrenSelected() {
var _this = this;
return this.hasChildren && this.hasSelection && this.allChildren.every(function (leaf) {
return _this.value.some(function (sel) {
return sel === leaf;
});
});
},
isSomeChildrenSelected: function isSomeChildrenSelected() {
var _this2 = this;
return this.hasSelection && this.allChildren.some(function (leaf) {
return _this2.value.some(function (sel) {
return sel === leaf;
});
});
}
data: function data() {
return {
finalValues: []
};
},
methods: {
generateRoot: function generateRoot() {
var _this3 = this;
return this.$createElement('tree-checkbox', {
props: {
label: this.items['name'],
inputValue: this.hasChildren ? this.isAllChildrenSelected : this.value,
value: this.hasChildren ? this.isAllChildrenSelected : this.items
},
on: {
change: function change(selection) {
if (_this3.hasChildren) {
if (_this3.isAllChildrenSelected) {
_this3.allChildren.forEach(function (leaf) {
var index = _this3.value.indexOf(leaf);
_this3.value.splice(index, 1);
});
} else {
_this3.allChildren.forEach(function (leaf) {
var index = _this3.value.indexOf(leaf);
if (index === -1) {
_this3.value.push(leaf);
}
});
}
_this3.$emit('input', _this3.value);
} else {
_this3.$emit('input', selection);
}
}
}
});
},
generateChild: function generateChild(child) {
var _this4 = this;
return this.$createElement('tree-view', {
class: 'tree-item',
on: {
input: function input(selection) {
_this4.$emit('input', selection);
}
},
props: {
items: child,
value: this.value
}
});
},
generateChildren: function generateChildren() {
var _this5 = this;
var childElements = [];
if (this.items['children']) {
this.items['children'].forEach(function (child) {
childElements.push(_this5.generateChild(child));
});
var items = typeof this.items == 'string' ? JSON.parse(this.items) : this.items;
for (var key in items) {
childElements.push(this.generateTreeItem(items[key]));
}
return childElements;
},
generateTreeItem: function generateTreeItem(item) {
var _this = this;
return this.$createElement('tree-item', {
props: {
items: item,
value: this.finalValues,
captionField: this.captionField,
childrenField: this.childrenField,
valueField: this.valueField,
idField: this.idField
},
on: {
input: function input(selection) {
_this.finalValues = selection;
}
}
});
}
},
render: function render(createElement) {
return createElement('div', {}, [this.generateRoot()].concat(_toConsumableArray(this.generateChildren())));
return createElement('div', {
class: ['tree-container']
}, [this.generateChildren()]);
}
});
@ -783,7 +749,259 @@ var normalizeComponent = __webpack_require__(0)
/* script */
var __vue_script__ = __webpack_require__(15)
/* template */
var __vue_template__ = __webpack_require__(16)
var __vue_template__ = null
/* template functional */
var __vue_template_functional__ = false
/* styles */
var __vue_styles__ = null
/* scopeId */
var __vue_scopeId__ = null
/* moduleIdentifier (server only) */
var __vue_module_identifier__ = null
var Component = normalizeComponent(
__vue_script__,
__vue_template__,
__vue_template_functional__,
__vue_styles__,
__vue_scopeId__,
__vue_module_identifier__
)
Component.options.__file = "src/Resources/assets/js/components/tree-view/tree-item.vue"
/* hot reload */
if (false) {(function () {
var hotAPI = require("vue-hot-reload-api")
hotAPI.install(require("vue"), false)
if (!hotAPI.compatible) return
module.hot.accept()
if (!module.hot.data) {
hotAPI.createRecord("data-v-2af003eb", Component.options)
} else {
hotAPI.reload("data-v-2af003eb", Component.options)
}
module.hot.dispose(function (data) {
disposed = true
})
})()}
module.exports = Component.exports
/***/ }),
/* 15 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
/* harmony default export */ __webpack_exports__["default"] = ({
name: 'tree-view',
inheritAttrs: false,
props: {
idField: String,
captionField: String,
childrenField: String,
valueField: String,
items: {
type: [Array, String, Object],
required: false,
default: null
},
value: {
type: Array,
required: false,
default: null
}
},
computed: {
caption: function caption() {
return this.items[this.captionField];
},
allChildren: function allChildren() {
var _this = this;
var leafs = [];
var searchTree = function searchTree(items) {
if (!!items[_this.childrenField] && _this.getLength(items[_this.childrenField]) > 0) {
if (_typeof(items[_this.childrenField]) == 'object') {
for (var key in items[_this.childrenField]) {
searchTree(items[_this.childrenField][key]);
}
} else {
items[_this.childrenField].forEach(function (child) {
return searchTree(child);
});
}
} else {
leafs.push(items);
}
};
searchTree(this.items);
return leafs;
},
hasChildren: function hasChildren() {
return !!this.items[this.childrenField] && this.getLength(this.items[this.childrenField]) > 0;
},
hasSelection: function hasSelection() {
return !!this.value && this.value.length > 0;
},
isAllChildrenSelected: function isAllChildrenSelected() {
var _this2 = this;
return this.hasChildren && this.hasSelection && this.allChildren.every(function (leaf) {
return _this2.value.some(function (sel) {
return sel[_this2.idField] === leaf[_this2.idField];
});
});
},
isSomeChildrenSelected: function isSomeChildrenSelected() {
var _this3 = this;
return this.hasChildren && this.hasSelection && this.allChildren.some(function (leaf) {
return _this3.value.some(function (sel) {
return sel[_this3.idField] === leaf[_this3.idField];
});
});
}
},
methods: {
getLength: function getLength(items) {
if ((typeof items === 'undefined' ? 'undefined' : _typeof(items)) == 'object') {
var length = 0;
for (var item in items) {
length++;
}
return length;
}
return items.length;
},
generateRoot: function generateRoot() {
var _this4 = this;
return this.$createElement('tree-checkbox', {
props: {
id: this.items[this.idField],
label: this.caption,
modelValue: this.items[this.valueField],
inputValue: this.hasChildren ? this.isSomeChildrenSelected : this.value,
value: this.hasChildren ? this.isAllChildrenSelected : this.items
},
on: {
change: function change(selection) {
if (_this4.hasChildren) {
if (_this4.isAllChildrenSelected) {
_this4.allChildren.forEach(function (leaf) {
var index = _this4.value.indexOf(leaf);
_this4.value.splice(index, 1);
});
} else {
_this4.allChildren.forEach(function (leaf) {
var exists = false;
_this4.value.forEach(function (item) {
if (item['key'] == leaf['key']) {
exists = true;
}
});
if (!exists) {
_this4.value.push(leaf);
}
});
}
_this4.$emit('input', _this4.value);
} else {
_this4.$emit('input', selection);
}
}
}
});
},
generateChild: function generateChild(child) {
var _this5 = this;
return this.$createElement('tree-item', {
on: {
input: function input(selection) {
_this5.$emit('input', selection);
}
},
props: {
items: child,
value: this.value,
captionField: this.captionField,
childrenField: this.childrenField,
valueField: this.valueField,
idField: this.idField
}
});
},
generateChildren: function generateChildren() {
var _this6 = this;
var childElements = [];
if (this.items[this.childrenField]) {
if (_typeof(this.items[this.childrenField]) == 'object') {
for (var key in this.items[this.childrenField]) {
childElements.push(this.generateChild(this.items[this.childrenField][key]));
}
} else {
this.items[this.childrenField].forEach(function (child) {
childElements.push(_this6.generateChild(child));
});
}
}
return childElements;
},
generateIcon: function generateIcon() {
var _this7 = this;
return this.$createElement('i', {
class: ['expand-icon'],
on: {
click: function click(selection) {
_this7.$el.classList.toggle("active");
}
}
});
}
},
render: function render(createElement) {
return createElement('div', {
class: ['tree-item', 'active', this.hasChildren ? 'has-children' : '']
}, [this.generateIcon(), this.generateRoot()].concat(_toConsumableArray(this.generateChildren())));
}
});
/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {
var disposed = false
var normalizeComponent = __webpack_require__(0)
/* script */
var __vue_script__ = __webpack_require__(17)
/* template */
var __vue_template__ = __webpack_require__(18)
/* template functional */
var __vue_template_functional__ = false
/* styles */
@ -822,7 +1040,7 @@ module.exports = Component.exports
/***/ }),
/* 15 */
/* 17 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -839,14 +1057,76 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony default export */ __webpack_exports__["default"] = ({
name: 'tree-checkbox',
props: ['label', 'inputValue', 'value'],
props: ['id', 'label', 'modelValue', 'inputValue', 'value'],
computed: {
isMultiple: function isMultiple() {
return Array.isArray(this.internalValue);
},
isActive: function isActive() {
var _this = this;
var value = this.value;
var input = this.internalValue;
if (this.isMultiple) {
return input.some(function (item) {
return _this.valueComparator(item, value);
});
}
return value ? this.valueComparator(value, input) : Boolean(input);
},
internalValue: {
get: function get() {
return this.lazyValue;
},
set: function set(val) {
this.lazyValue = val;
this.$emit('input', val);
}
}
},
data: function data(vm) {
return {
lazyValue: vm.inputValue
};
},
watch: {
inputValue: function inputValue(val) {
this.internalValue = val;
}
},
methods: {
inputChanged: function inputChanged(e) {
this.$emit('change', this.inputValue);
inputChanged: function inputChanged() {
var _this2 = this;
var value = this.value;
var input = this.internalValue;
if (this.isMultiple) {
var length = input.length;
input = input.filter(function (item) {
return !_this2.valueComparator(item, value);
});
if (input.length === length) {
input.push(value);
}
} else {
input = !input;
}
this.$emit('change', input);
},
valueComparator: function valueComparator(a, b) {
var _this = this;
var _this3 = this;
if (a === b) return true;
@ -861,38 +1141,14 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
}
return props.every(function (p) {
return _this.valueComparator(a[p], b[p]);
return _this3.valueComparator(a[p], b[p]);
});
}
},
computed: {
isMultiple: function isMultiple() {
return Array.isArray(this.inputValue);
},
isActive: function isActive() {
var _this2 = this;
var value = this.value;
var input = this.inputValue;
if (this.isMultiple) {
if (!Array.isArray(input)) return false;
return input.some(function (item) {
return _this2.valueComparator(item, value);
});
}
var isChecked = value ? this.valueComparator(value, input) : Boolean(input);
return isChecked;
}
}
});
/***/ }),
/* 16 */
/* 18 */
/***/ (function(module, exports, __webpack_require__) {
var render = function() {
@ -901,26 +1157,18 @@ var render = function() {
var _c = _vm._self._c || _h
return _c("span", { staticClass: "checkbox" }, [
_c("input", {
attrs: { type: "checkbox", name: "permissions[]", id: _vm.inputValue },
domProps: { value: _vm.inputValue.value, checked: _vm.isActive },
attrs: { type: "checkbox", id: _vm.id, name: "permissions[]" },
domProps: { value: _vm.modelValue, checked: _vm.isActive },
on: {
change: function($event) {
_vm.inputChanged($event)
_vm.inputChanged()
}
}
}),
_vm._v(" "),
_c("label", {
staticClass: "checkbox-view",
attrs: { for: _vm.inputValue }
}),
_vm._v(
"\n " +
_vm._s(_vm.inputValue) +
" ======== " +
_vm._s(_vm.value) +
"\n"
)
_c("label", { staticClass: "checkbox-view", attrs: { for: _vm.id } }),
_vm._v(" "),
_c("span", { attrs: { for: _vm.id } }, [_vm._v(_vm._s(_vm.label))])
])
}
var staticRenderFns = []
@ -934,10 +1182,10 @@ if (false) {
}
/***/ }),
/* 17 */
/* 19 */
/***/ (function(module, exports, __webpack_require__) {
window.jQuery = window.$ = $ = __webpack_require__(18);
window.jQuery = window.$ = $ = __webpack_require__(20);
$(function () {
$(document).click(function (e) {
@ -1002,7 +1250,7 @@ $(function () {
});
/***/ }),
/* 18 */
/* 20 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
@ -11373,7 +11621,7 @@ return jQuery;
/***/ }),
/* 19 */
/* 21 */
/***/ (function(module, exports) {
// removed by extract-text-webpack-plugin