Datagrid fallback to new URL format
This commit is contained in:
parent
6b54f4d526
commit
7ddcba62f9
|
|
@ -27,6 +27,7 @@ class DataGridController extends Controller
|
|||
'table' => 'admins as u',
|
||||
'select' => 'u.id',
|
||||
'aliased' => true , //boolean to validate aliasing on the basis of this.
|
||||
'perpage' => 2,
|
||||
'filterable' => [
|
||||
[
|
||||
'column' => 'u.id',
|
||||
|
|
|
|||
|
|
@ -27,148 +27,28 @@ class UserComposer
|
|||
public function compose(View $view)
|
||||
{
|
||||
|
||||
$datagrid = DataGrid::make([
|
||||
'name' => 'Admins',
|
||||
'table' => 'admins',
|
||||
'select' => 'id',
|
||||
'aliased' => false, //use this with false as default and true in case of joins
|
||||
'perpage' => 2,
|
||||
//don't use aliasing in case of filters
|
||||
'filterable' => [
|
||||
[
|
||||
'column' => 'name',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin Name'
|
||||
]
|
||||
],
|
||||
//don't use aliasing in case of searchables
|
||||
'searchable' => [
|
||||
[
|
||||
'column' => 'email',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin E-Mail'
|
||||
], [
|
||||
'column' => 'name',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin Name'
|
||||
]
|
||||
],
|
||||
'massoperations' =>[
|
||||
[
|
||||
'route' => route('admin.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'label' => 'Delete',
|
||||
'type' => 'button',
|
||||
],
|
||||
// [
|
||||
// 'route' => route('admin.datagrid.index'),
|
||||
// 'method' => 'POST',
|
||||
// 'label' => 'View Grid',
|
||||
// 'type' => 'select',
|
||||
// 'options' =>[
|
||||
// 1 => 'Edit',
|
||||
// 2 => 'Set',
|
||||
// 3 => 'Change Status'
|
||||
// ]
|
||||
// ],
|
||||
],
|
||||
'join' => [
|
||||
// [
|
||||
// 'join' => 'leftjoin',
|
||||
// 'table' => 'roles as r',
|
||||
// 'primaryKey' => 'u.role_id',
|
||||
// 'condition' => '=',
|
||||
// 'secondaryKey' => 'r.id',
|
||||
// ]
|
||||
],
|
||||
|
||||
//use aliasing on secodary columns if join is performed
|
||||
'columns' => [
|
||||
[
|
||||
'name' => 'id',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin ID',
|
||||
'sortable' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'name',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin Name',
|
||||
'sortable' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'email',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin E-Mail',
|
||||
'sortable' => true,
|
||||
],
|
||||
// [
|
||||
// 'name' => 'a.first_name',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Admin Name',
|
||||
// 'sortable' => true,
|
||||
// 'filterable' => true,
|
||||
// // will create on run time query
|
||||
// // 'filter' => [
|
||||
// // 'function' => 'where', // orwhere
|
||||
// // 'condition' => ['name', '=', 'Admin'] // multiarray
|
||||
// // ],
|
||||
// 'attributes' => [
|
||||
// 'class' => 'class-a class-b',
|
||||
// 'data-attr' => 'whatever you want',
|
||||
// 'onclick' => "window.alert('alert from datagrid column')"
|
||||
// ],
|
||||
// 'wrapper' => function ($value, $object) {
|
||||
// return '<a href="'.$value.'">' . $object->first_name . '</a>';
|
||||
// },
|
||||
// ],
|
||||
|
||||
],
|
||||
'operators' => [
|
||||
'eq' => "=",
|
||||
'lt' => "<",
|
||||
'gt' => ">",
|
||||
'lte' => "<=",
|
||||
'gte' => ">=",
|
||||
'neqs' => "<>",
|
||||
'neqn' => "!=",
|
||||
'like' => "like",
|
||||
'nlike' => "not like",
|
||||
],
|
||||
// 'css' => []
|
||||
|
||||
]);
|
||||
// $datagrid = DataGrid::make([
|
||||
// 'name' => 'Admins',
|
||||
// 'table' => 'admins as u',
|
||||
// 'select' => 'u.id',
|
||||
// 'aliased' => true, //use this with false as default and true in case of joins
|
||||
|
||||
// 'table' => 'admins',
|
||||
// 'select' => 'id',
|
||||
// 'aliased' => false, //use this with false as default and true in case of joins
|
||||
// 'perpage' => 2,
|
||||
// //don't use aliasing in case of filters
|
||||
// 'filterable' => [
|
||||
// [
|
||||
// 'column' => 'u.name',
|
||||
// 'column' => 'name',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Admin Name'
|
||||
// ], [
|
||||
// 'column' => 'u.id',
|
||||
// 'type' => 'number',
|
||||
// 'label' => 'Admin ID'
|
||||
// ],
|
||||
// [
|
||||
// 'column' => 'r.id',
|
||||
// 'type' => 'number',
|
||||
// 'label' => 'Role ID'
|
||||
// ]
|
||||
// ],
|
||||
// //don't use aliasing in case of searchables
|
||||
// 'searchable' => [
|
||||
// [
|
||||
// 'column' => 'u.email',
|
||||
// 'column' => 'email',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Admin E-Mail'
|
||||
// ], [
|
||||
// 'column' => 'u.name',
|
||||
// 'column' => 'name',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Admin Name'
|
||||
// ]
|
||||
|
|
@ -193,47 +73,35 @@ class UserComposer
|
|||
// // ],
|
||||
// ],
|
||||
// 'join' => [
|
||||
// [
|
||||
// 'join' => 'leftjoin',
|
||||
// 'table' => 'roles as r',
|
||||
// 'primaryKey' => 'u.role_id',
|
||||
// 'condition' => '=',
|
||||
// 'secondaryKey' => 'r.id',
|
||||
// ]
|
||||
// // [
|
||||
// // 'join' => 'leftjoin',
|
||||
// // 'table' => 'roles as r',
|
||||
// // 'primaryKey' => 'u.role_id',
|
||||
// // 'condition' => '=',
|
||||
// // 'secondaryKey' => 'r.id',
|
||||
// // ]
|
||||
// ],
|
||||
|
||||
// //use aliasing on secodary columns if join is performed
|
||||
// 'columns' => [
|
||||
// [
|
||||
// 'name' => 'u.id',
|
||||
// 'name' => 'id',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Admin ID',
|
||||
// 'sortable' => true,
|
||||
// ],
|
||||
// [
|
||||
// 'name' => 'u.name',
|
||||
// 'name' => 'name',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Admin Name',
|
||||
// 'sortable' => true,
|
||||
// ],
|
||||
// [
|
||||
// 'name' => 'u.email',
|
||||
// 'name' => 'email',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Admin E-Mail',
|
||||
// 'sortable' => true,
|
||||
// ],
|
||||
// [
|
||||
// 'name' => 'r.name as Role Name',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Role Name',
|
||||
// 'sortable' => true,
|
||||
// ],
|
||||
// [
|
||||
// 'name' => 'r.id as Role ID',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Role ID',
|
||||
// 'sortable' => true,
|
||||
// ],
|
||||
// // [
|
||||
// // 'name' => 'a.first_name',
|
||||
// // 'type' => 'string',
|
||||
|
|
@ -270,6 +138,160 @@ class UserComposer
|
|||
// // 'css' => []
|
||||
|
||||
// ]);
|
||||
$datagrid = DataGrid::make([
|
||||
'name' => 'Admins',
|
||||
'table' => 'admins as u',
|
||||
'select' => 'u.id',
|
||||
'perpage' => 2,
|
||||
'aliased' => true, //use this with false as default and true in case of joins
|
||||
|
||||
'massoperations' =>[
|
||||
[
|
||||
'route' => route('admin.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'label' => 'Delete',
|
||||
'type' => 'button',
|
||||
],
|
||||
// [
|
||||
// 'route' => route('admin.datagrid.index'),
|
||||
// 'method' => 'POST',
|
||||
// 'label' => 'View Grid',
|
||||
// 'type' => 'select',
|
||||
// 'options' =>[
|
||||
// 1 => 'Edit',
|
||||
// 2 => 'Set',
|
||||
// 3 => 'Change Status'
|
||||
// ]
|
||||
// ],
|
||||
],
|
||||
'actions' => [
|
||||
[
|
||||
'type' => 'Delete',
|
||||
'route' => route('admin.datagrid.delete'),
|
||||
'icon' => 'icon trash-icon',
|
||||
], [
|
||||
'type' => 'Edit',
|
||||
'route' => route('admin.datagrid.delete'),
|
||||
'icon' => 'icon pencil-lg-icon',
|
||||
],
|
||||
],
|
||||
'join' => [
|
||||
[
|
||||
'join' => 'leftjoin',
|
||||
'table' => 'roles as r',
|
||||
'primaryKey' => 'u.role_id',
|
||||
'condition' => '=',
|
||||
'secondaryKey' => 'r.id',
|
||||
]
|
||||
],
|
||||
|
||||
//use aliasing on secodary columns if join is performed
|
||||
'columns' => [
|
||||
[
|
||||
'name' => 'u.id',
|
||||
'alias' => 'ID',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin ID',
|
||||
'sortable' => true,
|
||||
'wrapper' => function ($value, $object) {
|
||||
return '<a class="color-red">' . $object->ID . '</a>';
|
||||
},
|
||||
],
|
||||
[
|
||||
'name' => 'u.name',
|
||||
'alias' => 'Name',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin Name',
|
||||
'sortable' => true,
|
||||
'wrapper' => function ($value, $object) {
|
||||
return '<a class="color-red">' . $object->Name . '</a>';
|
||||
},
|
||||
],
|
||||
[
|
||||
'name' => 'u.email',
|
||||
'alias' => 'Email',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin E-Mail',
|
||||
'sortable' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'r.name',
|
||||
'alias' => 'xa',
|
||||
'type' => 'string',
|
||||
'label' => 'Role Name',
|
||||
'sortable' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'r.id',
|
||||
'alias' => 'xc',
|
||||
'type' => 'string',
|
||||
'label' => 'Role ID',
|
||||
'sortable' => true,
|
||||
],
|
||||
// [
|
||||
// 'name' => 'a.first_name',
|
||||
// 'type' => 'string',
|
||||
// 'label' => 'Admin Name',
|
||||
// 'sortable' => true,
|
||||
// 'filterable' => true,
|
||||
// // will create on run time query
|
||||
// // 'filter' => [
|
||||
// // 'function' => 'where', // orwhere
|
||||
// // 'condition' => ['name', '=', 'Admin'] // multiarray
|
||||
// // ],
|
||||
// 'attributes' => [
|
||||
// 'class' => 'class-a class-b',
|
||||
// 'data-attr' => 'whatever you want',
|
||||
// 'onclick' => "window.alert('alert from datagrid column')"
|
||||
// ],
|
||||
// 'wrapper' => function ($value, $object) {
|
||||
// return '<a href="'.$value.'">' . $object->first_name . '</a>';
|
||||
// },
|
||||
// ],
|
||||
|
||||
],
|
||||
//don't use aliasing in case of filters
|
||||
'filterable' => [
|
||||
[
|
||||
'column' => 'u.name',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin Name'
|
||||
], [
|
||||
'column' => 'u.id',
|
||||
'type' => 'number',
|
||||
'label' => 'Admin ID'
|
||||
], [
|
||||
'column' => 'r.id',
|
||||
'type' => 'number',
|
||||
'label' => 'Role ID'
|
||||
]
|
||||
],
|
||||
//don't use aliasing in case of searchables
|
||||
'searchable' => [
|
||||
[
|
||||
'column' => 'u.email',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin E-Mail'
|
||||
], [
|
||||
'column' => 'u.name',
|
||||
'type' => 'string',
|
||||
'label' => 'Admin Name'
|
||||
]
|
||||
],
|
||||
'operators' => [
|
||||
'eq' => "=",
|
||||
'lt' => "<",
|
||||
'gt' => ">",
|
||||
'lte' => "<=",
|
||||
'gte' => ">=",
|
||||
'neqs' => "<>",
|
||||
'neqn' => "!=",
|
||||
'like' => "like",
|
||||
'nlike' => "not like",
|
||||
],
|
||||
// 'css' => []
|
||||
|
||||
]);
|
||||
|
||||
$view->with('datagrid', $datagrid);
|
||||
// $view->with('count', $this->users->count());
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use Illuminate\Support\Facades\DB;
|
|||
use Webkul\Ui\DataGrid\Helpers\Column;
|
||||
use Webkul\Ui\DataGrid\Helpers\Pagination;
|
||||
use Webkul\Ui\DataGrid\Helpers\Css;
|
||||
use Webkul\Ui\DataGrid\Helpers\MassAction;
|
||||
use URL;
|
||||
|
||||
class DataGrid
|
||||
|
|
@ -104,6 +103,13 @@ class DataGrid
|
|||
*/
|
||||
protected $css;
|
||||
|
||||
/**
|
||||
* Actions $action
|
||||
* @var action
|
||||
*/
|
||||
|
||||
protected $actions;
|
||||
|
||||
/**
|
||||
* URL parse $parsed
|
||||
* @var parse
|
||||
|
|
@ -135,9 +141,9 @@ class DataGrid
|
|||
// list($name, $select, $table, $join, $columns) = array_values($args);
|
||||
$name = $select = $aliased = $table = false;
|
||||
$join = $columns = $filterable = $searchable =
|
||||
$massoperations = $css = $operators = [];
|
||||
$massoperations = $css = $operators = $actions = [];
|
||||
extract($args);
|
||||
return $this->build($name, $select, $filterable, $searchable, $massoperations, $aliased, $perpage, $table, $join, $columns, $css, $operators);
|
||||
return $this->build($name, $select, $filterable, $searchable, $massoperations, $aliased, $perpage, $table, $join, $columns, $css, $operators,$actions);
|
||||
}
|
||||
|
||||
//starts buikding the queries on the basis of selects, joins and filter with
|
||||
|
|
@ -156,6 +162,7 @@ class DataGrid
|
|||
array $columns = null,
|
||||
array $css = [],
|
||||
array $operators = [],
|
||||
array $actions = [],
|
||||
Pagination $pagination = null
|
||||
) {
|
||||
$this->request = Request::capture();
|
||||
|
|
@ -171,6 +178,7 @@ class DataGrid
|
|||
$this->addColumns($columns, true);
|
||||
$this->setCss($css);
|
||||
$this->setOperators($operators);
|
||||
$this->setActions($actions);
|
||||
// $this->addPagination($pagination);
|
||||
return $this;
|
||||
}
|
||||
|
|
@ -308,6 +316,17 @@ class DataGrid
|
|||
// return $this;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Section actions bag
|
||||
* here.
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setActions($actions = []) {
|
||||
$this->actions = $actions ?: [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Columns.
|
||||
*
|
||||
|
|
@ -421,12 +440,16 @@ class DataGrid
|
|||
{
|
||||
$select = [];
|
||||
foreach ($this->columns as $column) {
|
||||
$select[] = $column->name;
|
||||
$select[] = $column->name.' as '.$column->alias;
|
||||
}
|
||||
|
||||
$this->query->select(...$select);
|
||||
|
||||
if ($this->select) {
|
||||
$this->query->addselect($this->select);
|
||||
}
|
||||
|
||||
// dd($this->query);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -687,7 +710,10 @@ class DataGrid
|
|||
if (!empty($parsed)) {
|
||||
$this->getQueryWithFilters();
|
||||
}
|
||||
// $this->results = $this->query->get();
|
||||
// return $this->results;
|
||||
$this->results = $this->query->get();
|
||||
$this->results = $this->query->paginate($this->perpage)->appends(request()->except('page'));
|
||||
return $this->results;
|
||||
|
||||
} else {
|
||||
|
|
@ -719,6 +745,7 @@ class DataGrid
|
|||
'filterable' =>$this->filterable,
|
||||
'operators' => $this->operators,
|
||||
'massoperations' => $this->massoperations,
|
||||
'actions' => $this->actions,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,727 @@
|
|||
<?php
|
||||
namespace Webkul\Ui\DataGrid;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Validate;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Ui\DataGrid\Helpers\Column;
|
||||
use Webkul\Ui\DataGrid\Helpers\Pagination;
|
||||
use Webkul\Ui\DataGrid\Helpers\Css;
|
||||
use Webkul\Ui\DataGrid\Helpers\MassAction;
|
||||
use URL;
|
||||
|
||||
class DataGridX
|
||||
{
|
||||
/**
|
||||
* Name of DataGrid
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
/**
|
||||
* select from table(s)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $select;
|
||||
|
||||
/**
|
||||
* Table
|
||||
* @var Boolean for aliasing
|
||||
*/
|
||||
protected $aliased;
|
||||
|
||||
/**
|
||||
* Pagination variable
|
||||
* @var String
|
||||
*/
|
||||
|
||||
protected $perpage;
|
||||
|
||||
/**
|
||||
* Table
|
||||
*
|
||||
* @var String Classs name $table
|
||||
*/
|
||||
|
||||
protected $table;
|
||||
/**
|
||||
* Join
|
||||
*
|
||||
* @var Array name $join
|
||||
*
|
||||
* [
|
||||
* 'join' => 'left',
|
||||
* 'table' => 'posts',
|
||||
* 'primaryKey' => 'user.id',
|
||||
* 'condition' => '=',
|
||||
* 'secondryKey' => 'posts.user_id',
|
||||
* 'callback' => 'not supported yet'
|
||||
* ]
|
||||
*/
|
||||
protected $join;
|
||||
/**
|
||||
* Collection Object of Column $columns
|
||||
*
|
||||
* @var Collection
|
||||
*/
|
||||
protected $columns;
|
||||
|
||||
/**
|
||||
* array of columns
|
||||
* to be filtered
|
||||
* @var Array
|
||||
*/
|
||||
protected $filterable;
|
||||
|
||||
/**
|
||||
* array of columns
|
||||
* to be searched
|
||||
*
|
||||
* @var Array
|
||||
*/
|
||||
protected $searchable;
|
||||
|
||||
/**
|
||||
* mass operations
|
||||
*
|
||||
* @var Array
|
||||
*/
|
||||
protected $massoperations;
|
||||
|
||||
/**
|
||||
* Pagination $pagination
|
||||
*
|
||||
* @var Pagination
|
||||
*/
|
||||
protected $pagination;
|
||||
/**
|
||||
* Css $css
|
||||
*
|
||||
* @var Css
|
||||
*/
|
||||
protected $css;
|
||||
|
||||
/**
|
||||
* URL parse $parsed
|
||||
* @var parse
|
||||
*/
|
||||
protected $parsed;
|
||||
/*
|
||||
public function __construct(
|
||||
$name = null ,
|
||||
$table = null ,
|
||||
array $join = [],
|
||||
Collection $columns = null,
|
||||
Pagination $pagination = null
|
||||
){
|
||||
$this->make(
|
||||
$name,
|
||||
$table,
|
||||
$join,
|
||||
$columns,
|
||||
$pagination
|
||||
);
|
||||
return $this;
|
||||
|
||||
Separates the bags in the array of make attributes
|
||||
}
|
||||
*/
|
||||
|
||||
public function make($args)
|
||||
{
|
||||
// list($name, $select, $table, $join, $columns) = array_values($args);
|
||||
$name = $select = $aliased = $table = false;
|
||||
$join = $columns = $filterable = $searchable =
|
||||
$massoperations = $css = $operators = [];
|
||||
extract($args);
|
||||
return $this->build($name, $select, $filterable, $searchable, $massoperations, $aliased, $perpage, $table, $join, $columns, $css, $operators);
|
||||
}
|
||||
|
||||
//starts buikding the queries on the basis of selects, joins and filter with
|
||||
//attributes for class names and styles.
|
||||
|
||||
public function build(
|
||||
$name = null,
|
||||
$select = false,
|
||||
array $filterable = [],
|
||||
array $searchable = [],
|
||||
array $massoperations = [],
|
||||
bool $aliased = false,
|
||||
$perpage = 0,
|
||||
$table = null,
|
||||
array $join = [],
|
||||
array $columns = null,
|
||||
array $css = [],
|
||||
array $operators = [],
|
||||
Pagination $pagination = null
|
||||
) {
|
||||
$this->request = Request::capture();
|
||||
$this->setName($name);
|
||||
$this->setSelect($select);
|
||||
$this->setFilterable($filterable);
|
||||
$this->setSearchable($filterable);
|
||||
$this->setMassOperations($massoperations);
|
||||
$this->setAlias($aliased);
|
||||
$this->setPerPage($perpage);
|
||||
$this->setTable($table);
|
||||
$this->setJoin($join);
|
||||
$this->addColumns($columns, true);
|
||||
$this->setCss($css);
|
||||
$this->setOperators($operators);
|
||||
// $this->addPagination($pagination);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Name.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setName(string $name)
|
||||
{
|
||||
$this->name = $name ?: 'Default' . time();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Select.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setSelect($select)
|
||||
{
|
||||
$this->select = $select ? : false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Filterable
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setFilterable(array $filterable)
|
||||
{
|
||||
$this->filterable = $filterable ? : [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Searchable columns
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setSearchable($searchable)
|
||||
{
|
||||
$this->searchable = $searchable ? : [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mass operations
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setMassOperations($massops)
|
||||
{
|
||||
$this->massoperations = $massops ? : [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set alias parameter
|
||||
* to know whether
|
||||
* aliasing is true or not.
|
||||
*
|
||||
* @return $this.
|
||||
*/
|
||||
|
||||
public function setAlias(bool $aliased)
|
||||
{
|
||||
$this->aliased = $aliased ? : false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default
|
||||
* pagination for
|
||||
* data grid.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setPerPage($perpage)
|
||||
{
|
||||
$this->perpage = $perpage ? : 5;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set table name in front
|
||||
* of query scope.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setTable(string $table)
|
||||
{
|
||||
$this->table = $table ?: false;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set join bag if
|
||||
* present.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setJoin(array $join)
|
||||
{
|
||||
$this->join = $join ?: [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the custom css rules
|
||||
* @retun $this
|
||||
*/
|
||||
|
||||
private function setCss($css = [])
|
||||
{
|
||||
$this->css = new Css($css);
|
||||
return $this->css;
|
||||
}
|
||||
|
||||
/**
|
||||
* setFilterableColumns
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
// public function setFilterableColumns($filterable_columns = [])
|
||||
// {
|
||||
// $this->join = $filterable_columns ?: [];
|
||||
// return $this;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Add Columns.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function addColumns($columns = [], $reCreate = false)
|
||||
{
|
||||
if ($reCreate) {
|
||||
$this->columns = new Collection();
|
||||
}
|
||||
if ($columns) {
|
||||
foreach ($columns as $column) {
|
||||
$this->addColumn($column);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Column.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function addColumn($column = [])
|
||||
{
|
||||
if ($column instanceof Column) {
|
||||
$this->columns->push($column);
|
||||
} elseif (gettype($column) == 'array' && $column) {
|
||||
$this->columns->push(new Column($column, $this->request));
|
||||
} else {
|
||||
throw new \Exception("DataGrid: Add Column argument is not valid!");
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ColumnMultiple.
|
||||
* Currently is not
|
||||
* of any use.
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
private function addColumnMultiple($column = [], $multiple = false)
|
||||
{
|
||||
if ($column instanceof Column) {
|
||||
if ($multiple) {
|
||||
if ($this->columns->offsetExists($column->getName())) {
|
||||
$this->columns->offsetSet($column->getName(). time(), $column);
|
||||
} else {
|
||||
$this->columns->offsetSet($column->getName(), $column);
|
||||
}
|
||||
} else {
|
||||
$this->columns->offsetSet($column->getName(), $column);
|
||||
}
|
||||
} elseif (gettype($column) == 'array' && $column) {
|
||||
$columnObj = new Column($column);
|
||||
if ($multiple) {
|
||||
if ($this->columns->offsetExists($columnObj->getName())) {
|
||||
$this->columns->offsetSet($columnObj->getName(). time(), $columnObj);
|
||||
} else {
|
||||
$this->columns->offsetSet($columnObj->getName(), $columnObj);
|
||||
}
|
||||
} else {
|
||||
$this->columns->offsetSet($columnObj->getName(), $columnObj);
|
||||
}
|
||||
} else {
|
||||
throw new \Exception("DataGrid: Add Column argument is not valid!");
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds expressional verbs to be used
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function setOperators(array $operators)
|
||||
{
|
||||
$this->operators = $operators ?: [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Pagination.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
public function addPagination($pagination = [])
|
||||
{
|
||||
if ($pagination instanceof Pagination) {
|
||||
$this->pagination = $pagination;
|
||||
} elseif (gettype($pagination) == 'array' && $pagination) {
|
||||
$this->pagination = new Pagination($pagination);
|
||||
} else {
|
||||
throw new \Exception("DataGrid: Pagination argument is not valid!");
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for selecting
|
||||
* the columns got in
|
||||
* make from controller.
|
||||
* @return $this
|
||||
*/
|
||||
|
||||
private function getSelect()
|
||||
{
|
||||
$select = [];
|
||||
foreach ($this->columns as $column) {
|
||||
$select[] = $column->name;
|
||||
}
|
||||
$this->query->select(...$select);
|
||||
if ($this->select) {
|
||||
$this->query->addselect($this->select);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the URL
|
||||
* and get it ready
|
||||
* to be used.
|
||||
*/
|
||||
|
||||
private function parse()
|
||||
{
|
||||
$parsed = [];
|
||||
$unparsed = url()->full();
|
||||
if (count(explode('?', $unparsed))>1) {
|
||||
$to_be_parsed = explode('?', $unparsed)[1];
|
||||
parse_str($to_be_parsed, $parsed);
|
||||
unset($parsed['page']);
|
||||
return $parsed;
|
||||
} else {
|
||||
return $parsed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ->join('contacts', 'users.id', '=', 'contacts.user_id')
|
||||
* @return $this->query
|
||||
*/
|
||||
|
||||
private function getQueryWithJoin()
|
||||
{
|
||||
foreach ($this->join as $join) {
|
||||
$this->query->{$join['join']}($join['table'], $join['primaryKey'], $join['condition'], $join['secondaryKey']);
|
||||
}
|
||||
}
|
||||
|
||||
private function getQueryWithColumnFilters()
|
||||
{
|
||||
foreach ($this->columns as $column) {
|
||||
if ($column->filter) { // if the filter bag in array exists then these will be applied.
|
||||
dd($column);
|
||||
if (count($column->filter['condition']) == count($column->filter['condition'], COUNT_RECURSIVE)) {
|
||||
$this->query->{$column->filter['function']}(...$column->filter['condition']);
|
||||
} else {
|
||||
if (count($column->filter['condition']) == 3) {
|
||||
$this->query->{$column->filter['function']}(
|
||||
extract(
|
||||
array_combine(
|
||||
// ['key', 'condition', 'value'],
|
||||
array_fill( //will work with all kind of where conditions
|
||||
0,
|
||||
(count($column->filter['condition']) - 1),
|
||||
'array_fill_nikhil'.time()
|
||||
),
|
||||
$column->filter['condition']
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function runs when
|
||||
* filters, sort, search
|
||||
* any of it is applied
|
||||
* @return $this->query
|
||||
*/
|
||||
|
||||
private function getQueryWithFilters()
|
||||
{
|
||||
$parsed = $this->parse();
|
||||
|
||||
if ($this->aliased) { //aliasing is expected in this case or it will be changed to presence of join bag
|
||||
foreach ($parsed as $key=>$value) {
|
||||
if ($key=="sort") {
|
||||
//resolve the case with the column helper class
|
||||
if(substr_count($key,'_') >= 1)
|
||||
$column_name = str_replace_first('_', '.', $key);
|
||||
|
||||
//case that don't need any resolving
|
||||
$count_keys = count(array_keys($value));
|
||||
if ($count_keys==1) {
|
||||
$this->query->orderBy(
|
||||
str_replace('_', '.', array_keys($value)[0]),
|
||||
array_values($value)[0]
|
||||
);
|
||||
} else {
|
||||
throw new \Exception('Multiple Sort keys Found, Please Resolve the URL Manually.');
|
||||
}
|
||||
} elseif ($key=="search") {
|
||||
|
||||
$count_keys = count(array_keys($value));
|
||||
if($count_keys==1)
|
||||
$this->query->where(function ($query) use ($parsed) {
|
||||
foreach ($this->searchable as $search) {
|
||||
$query->orWhere($search['column'], 'like', '%'.$parsed['search']['all'].'%');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$column_name = str_replace_first('_', '.', $key);
|
||||
|
||||
if (array_keys($value)[0]=="like" || array_keys($value)[0]=="nlike") {
|
||||
foreach ($value as $condition => $filter_value) {
|
||||
$this->query->where(
|
||||
$column_name,
|
||||
$this->operators[$condition],
|
||||
'%'.$filter_value.'%'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
foreach ($value as $condition => $filter_value) {
|
||||
$this->query->where(
|
||||
$column_name,
|
||||
$this->operators[$condition],
|
||||
$filter_value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//this is the case for the non aliasing.
|
||||
foreach ($parsed as $key=>$value) {
|
||||
|
||||
if ($key=="sort") {
|
||||
|
||||
//case that don't need any resolving
|
||||
$count_keys = count(array_keys($value));
|
||||
if ($count_keys==1) {
|
||||
|
||||
$this->query->orderBy(
|
||||
array_keys($value)[0],
|
||||
array_values($value)[0]
|
||||
);
|
||||
|
||||
} else {
|
||||
throw new \Exception('Multiple Sort keys Found, Please Resolve the URL Manually.');
|
||||
}
|
||||
} elseif ($key=="search") {
|
||||
|
||||
$count_keys = count(array_keys($value));
|
||||
if($count_keys==1)
|
||||
$this->query->where(function ($query) use ($parsed) {
|
||||
foreach ($this->searchable as $search) {
|
||||
$query->orWhere($search['column'], 'like', '%'.$parsed['search']['all'].'%');
|
||||
}
|
||||
});
|
||||
else
|
||||
throw new \Exception('Multiple Search keys Found, Please Resolve the URL Manually.');
|
||||
|
||||
} else {
|
||||
|
||||
$column_name = $key;
|
||||
|
||||
if (array_keys($value)[0]=="like" || array_keys($value)[0]=="nlike") {
|
||||
foreach ($value as $condition => $filter_value) {
|
||||
$this->query->where(
|
||||
$column_name,
|
||||
$this->operators[$condition],
|
||||
'%'.$filter_value.'%'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
foreach ($value as $condition => $filter_value) {
|
||||
$this->query->where(
|
||||
$column_name,
|
||||
$this->operators[$condition],
|
||||
$filter_value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private function getDbQueryResults()
|
||||
{
|
||||
$parsed = $this->parse();
|
||||
|
||||
if ($this->aliased==true) {
|
||||
//flags
|
||||
$table_alias = false;
|
||||
$join_table_alias = false;
|
||||
$allowed_joins = false;
|
||||
$other_joins = false;
|
||||
$join_good = false;
|
||||
|
||||
//prepare query object
|
||||
$this->query = DB::table($this->table);
|
||||
|
||||
//explode if alias is available
|
||||
if (strpos('.', $this->table)) {
|
||||
throw new \Exception("dot/s cannot be used in table names in mysql");
|
||||
} else {
|
||||
$exploded = explode('as', $this->table);
|
||||
}
|
||||
|
||||
//check whether exploded string still has same table name
|
||||
if ($exploded[0]==$this->table) {
|
||||
$table_alias = false;
|
||||
} else { // (isset($exploded))
|
||||
$table_alias = true;
|
||||
$table_name = trim($exploded[0]);
|
||||
$table_alias = trim($exploded[1]);
|
||||
}
|
||||
//Run this if there are any selects priorly.
|
||||
if (!empty($this->select)) {
|
||||
$this->getSelect();
|
||||
}
|
||||
|
||||
//Run this if there are joins
|
||||
if (!empty($this->join)) {
|
||||
foreach ($this->join as $join) {
|
||||
$name = strtolower($join['join']);
|
||||
//Allow joins i.e left or right
|
||||
if ($name=='leftjoin' || $name=='rightjoin') {
|
||||
|
||||
//check if the aliasing on the primary table and primaryKey in join is also the same
|
||||
$primary_key_alias = trim(explode('.', $join['primaryKey'])[0]);
|
||||
|
||||
if ($primary_key_alias == $table_alias) {
|
||||
$join_table_alias = explode('as', $join['table']);
|
||||
if (isset($join_table_alias)) {
|
||||
$alias1 = trim($join_table_alias[1]); //important!!!!!
|
||||
|
||||
//check if the secondary table match column is not having '.' and has proper alias
|
||||
$secondary_join_column = $join['secondaryKey'];
|
||||
if (isset($secondary_join_column)) {
|
||||
$exploded_secondary = explode('.', $secondary_join_column);
|
||||
$alias2 = trim($exploded_secondary[0]);
|
||||
if ($alias1 == $alias2) {
|
||||
$this->getQueryWithJoin();
|
||||
$alias_proper_secondary = true;
|
||||
} else {
|
||||
throw new \Exception('Aliases of Join table and the secondary key columns do not match');
|
||||
}
|
||||
} else {
|
||||
throw new \Exception('Improper aliasing on secondary/join column for join');
|
||||
}
|
||||
} else {
|
||||
throw new \Exception('Join/Secondary table alias is not found for join');
|
||||
}
|
||||
} else {
|
||||
throw new \Exception('Primary key and primary table aliases do not match for join');
|
||||
}
|
||||
} else {
|
||||
$other_joins = true;
|
||||
throw new \Exception('Please check if there is some fault in your aliasing and do not use as in column names or you might have been using a join that is not allowed i.e cross, inner, etc use left and right join only');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Check for column filter bags and resolve aliasing
|
||||
$this->getQueryWithColumnFilters();
|
||||
if (!empty($parsed)) {
|
||||
$this->getQueryWithFilters();
|
||||
}
|
||||
// $this->results = $this->query->get();
|
||||
// return $this->results;
|
||||
$this->results = $this->query->get();
|
||||
$this->results = $this->query->paginate($this->perpage)->appends(request()->except('page'));
|
||||
return $this->results;
|
||||
|
||||
} else {
|
||||
|
||||
$this->query = DB::table($this->table);
|
||||
|
||||
$this->getSelect();
|
||||
$this->getQueryWithColumnFilters();
|
||||
if (!empty($parsed)) {
|
||||
$this->getQueryWithFilters();
|
||||
}
|
||||
$this->results = $this->query->get();
|
||||
$this->results = $this->query->paginate($this->perpage)->appends(request()->except('page'));
|
||||
return $this->results;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return view
|
||||
*/
|
||||
|
||||
public function render()
|
||||
{
|
||||
$this->getDbQueryResults();
|
||||
return view('ui::datagrid.index', [
|
||||
'css' => $this->css,
|
||||
'results' => $this->results,
|
||||
'columns' => $this->columns,
|
||||
'filterable' =>$this->filterable,
|
||||
'operators' => $this->operators,
|
||||
'massoperations' => $this->massoperations,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ class Column extends AbstractFillable
|
|||
|
||||
private $request = null;
|
||||
private $readableName = false;
|
||||
private $aliasing = false;
|
||||
private $value = false;
|
||||
private $sortHtml = '<a href="%s">%s</a>';
|
||||
|
||||
|
|
@ -44,6 +45,12 @@ class Column extends AbstractFillable
|
|||
'sortable',
|
||||
'searchable',
|
||||
'filterable',
|
||||
'massoperations' => [
|
||||
'allowed' => 'array'
|
||||
],
|
||||
'actions' => [
|
||||
'allowed' => 'array'
|
||||
],
|
||||
'filter' => [
|
||||
'allowed' => 'array',
|
||||
],
|
||||
|
|
@ -110,7 +117,6 @@ class Column extends AbstractFillable
|
|||
$this->value = call_user_func($this->wrapper, $this->value, $obj);
|
||||
}
|
||||
}
|
||||
|
||||
private function sortingUrl()
|
||||
{
|
||||
$query = ['sort' => $this->correct(false)];
|
||||
|
|
@ -143,10 +149,18 @@ class Column extends AbstractFillable
|
|||
|
||||
public function render($obj)
|
||||
{
|
||||
if (property_exists($obj, ($this->readableName = $this->correct()))) {
|
||||
$this->value = $obj->{$this->readableName};
|
||||
|
||||
// if (property_exists($obj, ($this->readableName = $this->correct()))) {
|
||||
// $this->value = $obj->{$this->readableName};
|
||||
// dump($this->value);
|
||||
// $this->wrap($obj);
|
||||
// }
|
||||
// return $obj->{$this->alias};
|
||||
if (property_exists($obj, ($this->aliasing = $this->alias))) {
|
||||
$this->value = $obj->{$this->aliasing};
|
||||
$this->wrap($obj);
|
||||
}
|
||||
return $this->value;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -855,6 +855,7 @@ h2 {
|
|||
th.sort-head {
|
||||
.sort-down-icon {
|
||||
margin-left: 8px;
|
||||
margin-top: -5px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@
|
|||
@foreach($columns as $column)
|
||||
<li data-name="{{ $column->name }}">
|
||||
{{ $column->label }}
|
||||
<span class="checkbox">
|
||||
<input type="checkbox" id="{{ $column->id }}" name="checkbox1[]">
|
||||
<label for="checkbox1" class="checkbox-view"></label>
|
||||
</span>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
{{-- Section for datagrid javascript --}}
|
||||
@section('javascript')
|
||||
<script type="text/javascript">
|
||||
var columns = @json($columns); //referential
|
||||
var allFilters1 = [];
|
||||
var search_value;
|
||||
var filter_column;
|
||||
|
|
@ -243,6 +244,7 @@
|
|||
moreSplitted = [];
|
||||
splitted = t.split('&');
|
||||
for(i=0;i<splitted.length;i++) {
|
||||
|
||||
moreSplitted.push(splitted[i].split('='));
|
||||
}
|
||||
for(i=0;i<moreSplitted.length;i++) {
|
||||
|
|
@ -252,16 +254,16 @@
|
|||
obj.column = col;
|
||||
obj.cond = cond;
|
||||
obj.val = val;
|
||||
allFilters1.push(obj);
|
||||
if(col!=undefined && cond!=undefined && val!=undefined)
|
||||
allFilters1.push(obj);
|
||||
obj = {};
|
||||
}
|
||||
makeTagsTestPrior();
|
||||
makeTags();
|
||||
}
|
||||
|
||||
//use the label to prevent the display of column name on the body
|
||||
function makeTagsTestPrior() {
|
||||
function makeTags() {
|
||||
var filterRepeat = 0;
|
||||
console.log(allFilters1);
|
||||
if(allFilters1.length!=0)
|
||||
for(var i = 0;i<allFilters1.length;i++) {
|
||||
if(allFilters1[i].column == "sort") {
|
||||
|
|
@ -277,8 +279,7 @@
|
|||
$('.filter-row-two').append(filter_card);
|
||||
|
||||
} else {
|
||||
|
||||
col_label_tag = $('li[data-name="'+allFilters1[i].column+'"]').text();
|
||||
col_label_tag = $('li[data-name="'+allFilters1[i].column+'"]').text().trim();
|
||||
var filter_card = '<span class="filter-one" id="'+ i +'"><span class="filter-name">'+ col_label_tag +'</span><span class="filter-value"><span class="f-value">'+ allFilters1[i].val +'</span><span class="icon cross-icon remove-filter"></span></span></span>';
|
||||
$('.filter-row-two').append(filter_card);
|
||||
|
||||
|
|
@ -287,7 +288,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
//obselete or can be used for mediation control if necessary
|
||||
//This is being used for validation of url params and making array of filters
|
||||
function formURL(column, condition, response, urlparams,clabel) {
|
||||
/*validate the conditions here and do the replacements and
|
||||
push here in the all filters array*/
|
||||
|
|
|
|||
|
|
@ -104,6 +104,11 @@
|
|||
@else
|
||||
<th class="labelled-col grid_head" data-column-name="{{ $column->name }}" data-column-label="{{ $column->label }}">{!! $column->sorting() !!}</th>
|
||||
@endif @endforeach
|
||||
@foreach($actions as $action)
|
||||
<th>
|
||||
{{ $action['type'] }}
|
||||
</th>
|
||||
@endforeach
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="{{ $css->tbody }}">
|
||||
|
|
@ -118,13 +123,18 @@
|
|||
@foreach ($columns as $column)
|
||||
<td class="">{!! $column->render($result) !!}</td>
|
||||
@endforeach
|
||||
@foreach($actions as $action)
|
||||
<td class="action">
|
||||
<span class="action-{{ $action['type'] }}" id="{{ $result->id }}">
|
||||
<i class="{{ $action['icon'] }}"></i>
|
||||
</span>
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="pagination">
|
||||
{{-- <a class="page-item previous"><i class="icon angle-left-icon"></i></a>
|
||||
<a href="#status/6/page/2" class="page-item next"><i class="icon angle-right-icon"></i></a> --}}
|
||||
{{ $results->links() }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<i class="icon angle-left-icon"></i>
|
||||
</a>
|
||||
@else
|
||||
<a data-page="{{ $paginator->previousPageUrl() }}" href="{{ urldecode($paginator->nextPageUrl()) }}" id="previous" class="page-item previous">
|
||||
<a data-page="{{ urldecode($paginator->previousPageUrl()) }}" href="{{ urldecode($paginator->previousPageUrl()) }}" id="previous" class="page-item previous">
|
||||
<i class="icon angle-left-icon"></i>
|
||||
</a>
|
||||
@endif
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
{{ $page }}
|
||||
</a>
|
||||
@else
|
||||
<a class="page-item" href="{{ $url }}">
|
||||
<a class="page-item as" href="{{ urldecode($url) }}">
|
||||
{{ $page }}
|
||||
</a>
|
||||
@endif
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
{{-- Next Page Link --}}
|
||||
@if ($paginator->hasMorePages())
|
||||
<a href="{{ urldecode($paginator->nextPageUrl()) }}" data-page="{{ $paginator->nextPageUrl() }}" id="next" class="page-item next">
|
||||
<a href="{{ urldecode($paginator->nextPageUrl()) }}" data-page="{{ urldecode($paginator->nextPageUrl()) }}" id="next" class="page-item next">
|
||||
<i class="icon angle-right-icon"></i>
|
||||
</a>
|
||||
@else
|
||||
|
|
|
|||
Loading…
Reference in New Issue