mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Vue Datatables (#2597)
* Adding Vue components for Charts and Multi Select * List Views * Improve UI of datatable * Refactor Vue Datatable for reusability
This commit is contained in:
parent
0faf91dd5d
commit
9204510193
@ -109,7 +109,7 @@ class ClientDatatable extends EntityDatatable
|
|||||||
* @param $data Std Class of client datatable rows
|
* @param $data Std Class of client datatable rows
|
||||||
* @return object Rendered action column items
|
* @return object Rendered action column items
|
||||||
*/
|
*/
|
||||||
private function buildActionColumn($data) : object
|
private function buildActionColumn($data)
|
||||||
{
|
{
|
||||||
|
|
||||||
//if(auth()->user()->is_admin())
|
//if(auth()->user()->is_admin())
|
||||||
@ -157,4 +157,70 @@ class ClientDatatable extends EntityDatatable
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function buildOptions()
|
||||||
|
{
|
||||||
|
return collect([
|
||||||
|
'per_page' => 20,
|
||||||
|
'sort_order' => [
|
||||||
|
[
|
||||||
|
'field' => 'name',
|
||||||
|
'sortField' => 'name',
|
||||||
|
'direction' => 'asc',
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'fields' => [
|
||||||
|
[
|
||||||
|
'name' => '__checkbox', // <----
|
||||||
|
'title' => '',
|
||||||
|
'titleClass' => 'center aligned',
|
||||||
|
'dataClass' => 'center aligned'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'name',
|
||||||
|
'title' => trans('texts.name'),
|
||||||
|
'sortField' => 'name',
|
||||||
|
'visible' => false,
|
||||||
|
'dataClass' => 'center aligned'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'contact',
|
||||||
|
'title' => trans('texts.contact'),
|
||||||
|
'sortField' => 'contact',
|
||||||
|
'visible' => false,
|
||||||
|
'dataClass' => 'center aligned'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'email',
|
||||||
|
'title' => trans('texts.email'),
|
||||||
|
'sortField' => 'email',
|
||||||
|
'dataClass' => 'center aligned'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'client_created_at',
|
||||||
|
'title' => trans('texts.date_created'),
|
||||||
|
'sortField' => 'client_created_at',
|
||||||
|
'dataClass' => 'center aligned'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'last_login',
|
||||||
|
'title' => trans('texts.last_login'),
|
||||||
|
'sortField' => 'last_login',
|
||||||
|
'dataClass' => 'center aligned'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'balance',
|
||||||
|
'title' => trans('texts.balance'),
|
||||||
|
'sortField' => 'balance',
|
||||||
|
'dataClass' => 'center aligned'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => '__component:client-actions',
|
||||||
|
'title' => '',
|
||||||
|
'titleClass' => 'center aligned',
|
||||||
|
'dataClass' => 'center aligned'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -20,6 +20,13 @@ class ClientFilters extends QueryFilters
|
|||||||
return $this->builder->where('balance', $parts->operator, $parts->value);
|
return $this->builder->where('balance', $parts->operator, $parts->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function between_balance($balance)
|
||||||
|
{
|
||||||
|
$parts = explode(":", $balance);
|
||||||
|
|
||||||
|
return $this->builder->whereBetween('balance', [$parts[0], $parts[1]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter by popularity.
|
* Filter by popularity.
|
||||||
|
@ -41,7 +41,11 @@ class ClientController extends Controller
|
|||||||
if(request('page'))
|
if(request('page'))
|
||||||
return $this->clientDatatable->query(request(), $this->getCurrentCompanyId());
|
return $this->clientDatatable->query(request(), $this->getCurrentCompanyId());
|
||||||
|
|
||||||
return view('client.vue_list');
|
$data = [
|
||||||
|
'datatable' => $this->clientDatatable->buildOptions()
|
||||||
|
];
|
||||||
|
|
||||||
|
return view('client.vue_list', $data);
|
||||||
/*
|
/*
|
||||||
if (request()->ajax()) {
|
if (request()->ajax()) {
|
||||||
|
|
||||||
@ -212,4 +216,9 @@ class ClientController extends Controller
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function builk()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,7 @@
|
|||||||
"predis/predis": "^1.1",
|
"predis/predis": "^1.1",
|
||||||
"spatie/laravel-html": "^2.19",
|
"spatie/laravel-html": "^2.19",
|
||||||
"webpatser/laravel-countries": "dev-master#75992ad",
|
"webpatser/laravel-countries": "dev-master#75992ad",
|
||||||
"wildbit/postmark-php": "^2.6",
|
"wildbit/postmark-php": "^2.6"
|
||||||
"yajra/laravel-datatables": "^1.0",
|
|
||||||
"yajra/laravel-datatables-html": "^3.0"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"beyondcode/laravel-dump-server": "^1.0",
|
"beyondcode/laravel-dump-server": "^1.0",
|
||||||
|
956
composer.lock
generated
956
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -159,8 +159,6 @@ return [
|
|||||||
Illuminate\Translation\TranslationServiceProvider::class,
|
Illuminate\Translation\TranslationServiceProvider::class,
|
||||||
Illuminate\Validation\ValidationServiceProvider::class,
|
Illuminate\Validation\ValidationServiceProvider::class,
|
||||||
Illuminate\View\ViewServiceProvider::class,
|
Illuminate\View\ViewServiceProvider::class,
|
||||||
Yajra\DataTables\DataTablesServiceProvider::class,
|
|
||||||
Yajra\DataTables\HtmlServiceProvider::class,
|
|
||||||
/*
|
/*
|
||||||
* Dependency Service Providers
|
* Dependency Service Providers
|
||||||
*/
|
*/
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
/*
|
|
||||||
* Namespaces used by the generator.
|
|
||||||
*/
|
|
||||||
'namespace' => [
|
|
||||||
/*
|
|
||||||
* Base namespace/directory to create the new file.
|
|
||||||
* This is appended on default Laravel namespace.
|
|
||||||
* Usage: php artisan datatables:make User
|
|
||||||
* Output: App\DataTables\UserDataTable
|
|
||||||
* With Model: App\User (default model)
|
|
||||||
* Export filename: users_timestamp
|
|
||||||
*/
|
|
||||||
'base' => 'DataTables',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Base namespace/directory where your model's are located.
|
|
||||||
* This is appended on default Laravel namespace.
|
|
||||||
* Usage: php artisan datatables:make Post --model
|
|
||||||
* Output: App\DataTables\PostDataTable
|
|
||||||
* With Model: App\Post
|
|
||||||
* Export filename: posts_timestamp
|
|
||||||
*/
|
|
||||||
'model' => '',
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set Custom stub folder
|
|
||||||
*/
|
|
||||||
//'stub' => '/resources/custom_stub',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PDF generator to be used when converting the table to pdf.
|
|
||||||
* Available generators: excel, snappy
|
|
||||||
* Snappy package: barryvdh/laravel-snappy
|
|
||||||
* Excel package: maatwebsite/excel
|
|
||||||
*/
|
|
||||||
'pdf_generator' => 'snappy',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Snappy PDF options.
|
|
||||||
*/
|
|
||||||
'snappy' => [
|
|
||||||
'options' => [
|
|
||||||
'no-outline' => true,
|
|
||||||
'margin-left' => '0',
|
|
||||||
'margin-right' => '0',
|
|
||||||
'margin-top' => '10mm',
|
|
||||||
'margin-bottom' => '10mm',
|
|
||||||
],
|
|
||||||
'orientation' => 'landscape',
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default html builder parameters.
|
|
||||||
*/
|
|
||||||
'parameters' => [
|
|
||||||
'dom' => 'Bfrtip',
|
|
||||||
'order' => [[0, 'desc']],
|
|
||||||
'buttons' => [
|
|
||||||
'create',
|
|
||||||
'export',
|
|
||||||
'print',
|
|
||||||
'reset',
|
|
||||||
'reload',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
/*
|
|
||||||
* Request key name to parse includes on fractal.
|
|
||||||
*/
|
|
||||||
'includes' => 'include',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default fractal serializer.
|
|
||||||
*/
|
|
||||||
'serializer' => League\Fractal\Serializer\DataArraySerializer::class,
|
|
||||||
];
|
|
@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
/*
|
|
||||||
* Default table attributes when generating the table.
|
|
||||||
*/
|
|
||||||
'table' => [
|
|
||||||
'class' => 'table table-hover',
|
|
||||||
'id' => 'ninja',
|
|
||||||
],
|
|
||||||
/*
|
|
||||||
* Default condition to determine if a parameter is a callback or not
|
|
||||||
* Callbacks needs to start by those terms or they will be casted to string
|
|
||||||
*/
|
|
||||||
'callback' => ['$', '$.', 'function'],
|
|
||||||
];
|
|
@ -1,116 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
/*
|
|
||||||
* DataTables search options.
|
|
||||||
*/
|
|
||||||
'search' => [
|
|
||||||
/*
|
|
||||||
* Smart search will enclose search keyword with wildcard string "%keyword%".
|
|
||||||
* SQL: column LIKE "%keyword%"
|
|
||||||
*/
|
|
||||||
'smart' => true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Multi-term search will explode search keyword using spaces resulting into multiple term search.
|
|
||||||
*/
|
|
||||||
'multi_term' => true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Case insensitive will search the keyword in lower case format.
|
|
||||||
* SQL: LOWER(column) LIKE LOWER(keyword)
|
|
||||||
*/
|
|
||||||
'case_insensitive' => true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wild card will add "%" in between every characters of the keyword.
|
|
||||||
* SQL: column LIKE "%k%e%y%w%o%r%d%"
|
|
||||||
*/
|
|
||||||
'use_wildcards' => false,
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DataTables internal index id response column name.
|
|
||||||
*/
|
|
||||||
'index_column' => 'DT_Row_Index',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List of available builders for DataTables.
|
|
||||||
* This is where you can register your custom dataTables builder.
|
|
||||||
*/
|
|
||||||
'engines' => [
|
|
||||||
'eloquent' => \Yajra\DataTables\EloquentDataTable::class,
|
|
||||||
'query' => \Yajra\DataTables\QueryDataTable::class,
|
|
||||||
'collection' => \Yajra\DataTables\CollectionDataTable::class,
|
|
||||||
'resource' => \Yajra\DataTables\ApiResourceDataTable::class,
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DataTables accepted builder to engine mapping.
|
|
||||||
* This is where you can override which engine a builder should use
|
|
||||||
* Note, only change this if you know what you are doing!
|
|
||||||
*/
|
|
||||||
'builders' => [
|
|
||||||
//Illuminate\Database\Eloquent\Relations\Relation::class => 'eloquent',
|
|
||||||
//Illuminate\Database\Eloquent\Builder::class => 'eloquent',
|
|
||||||
//Illuminate\Database\Query\Builder::class => 'query',
|
|
||||||
//Illuminate\Support\Collection::class => 'collection',
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Nulls last sql pattern for Posgresql & Oracle.
|
|
||||||
* For MySQL, use '-%s %s'
|
|
||||||
*/
|
|
||||||
'nulls_last_sql' => '%s %s NULLS LAST',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* User friendly message to be displayed on user if error occurs.
|
|
||||||
* Possible values:
|
|
||||||
* null - The exception message will be used on error response.
|
|
||||||
* 'throw' - Throws a \Yajra\DataTables\Exceptions\Exception. Use your custom error handler if needed.
|
|
||||||
* 'custom message' - Any friendly message to be displayed to the user. You can also use translation key.
|
|
||||||
*/
|
|
||||||
'error' => env('DATATABLES_ERROR', null),
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default columns definition of dataTable utility functions.
|
|
||||||
*/
|
|
||||||
'columns' => [
|
|
||||||
/*
|
|
||||||
* List of columns hidden/removed on json response.
|
|
||||||
*/
|
|
||||||
'excess' => ['rn', 'row_num'],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List of columns to be escaped. If set to *, all columns are escape.
|
|
||||||
* Note: You can set the value to empty array to disable XSS protection.
|
|
||||||
*/
|
|
||||||
'escape' => '*',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List of columns that are allowed to display html content.
|
|
||||||
* Note: Adding columns to list will make us available to XSS attacks.
|
|
||||||
*/
|
|
||||||
'raw' => ['action'],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List of columns are are forbidden from being searched/sorted.
|
|
||||||
*/
|
|
||||||
'blacklist' => ['password', 'remember_token'],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List of columns that are only allowed fo search/sort.
|
|
||||||
* If set to *, all columns are allowed.
|
|
||||||
*/
|
|
||||||
'whitelist' => '*',
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
* JsonResponse header and options config.
|
|
||||||
*/
|
|
||||||
'json' => [
|
|
||||||
'header' => [],
|
|
||||||
'options' => 0,
|
|
||||||
],
|
|
||||||
|
|
||||||
];
|
|
@ -20,7 +20,7 @@
|
|||||||
"axios": "^0.18",
|
"axios": "^0.18",
|
||||||
"babel-preset-stage-2": "^6.24.1",
|
"babel-preset-stage-2": "^6.24.1",
|
||||||
"bootstrap": "^4.0.0",
|
"bootstrap": "^4.0.0",
|
||||||
"chart.js": "^2.7.2",
|
"chart.js": "^2.7.3",
|
||||||
"cross-env": "^5.1",
|
"cross-env": "^5.1",
|
||||||
"flag-icon-css": "3.2.0",
|
"flag-icon-css": "3.2.0",
|
||||||
"font-awesome": "^4.7",
|
"font-awesome": "^4.7",
|
||||||
@ -45,8 +45,10 @@
|
|||||||
"socket.io-client": "^2.1.1",
|
"socket.io-client": "^2.1.1",
|
||||||
"ts-loader": "3.5.0",
|
"ts-loader": "3.5.0",
|
||||||
"typescript": "^3.1.6",
|
"typescript": "^3.1.6",
|
||||||
|
"vue-chartjs": "^3.4.0",
|
||||||
"vue-events": "^3.1.0",
|
"vue-events": "^3.1.0",
|
||||||
"vue-i18n": "^8.3.0",
|
"vue-i18n": "^8.3.0",
|
||||||
|
"vue-multiselect": "^2.1.3",
|
||||||
"vue-select": "^2.5.1",
|
"vue-select": "^2.5.1",
|
||||||
"vue-toastr": "^2.0.16"
|
"vue-toastr": "^2.0.16"
|
||||||
}
|
}
|
||||||
|
10
public/js/client_edit.js
vendored
10
public/js/client_edit.js
vendored
@ -34374,6 +34374,8 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
|
|||||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash__);
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash__);
|
||||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_vue_toastr__ = __webpack_require__("./node_modules/vue-toastr/dist/vue-toastr.js");
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_vue_toastr__ = __webpack_require__("./node_modules/vue-toastr/dist/vue-toastr.js");
|
||||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_vue_toastr___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_vue_toastr__);
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_vue_toastr___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_vue_toastr__);
|
||||||
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_vue__ = __webpack_require__("./node_modules/vue/dist/vue.common.js");
|
||||||
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_vue___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_vue__);
|
||||||
// lodash handles our translations
|
// lodash handles our translations
|
||||||
|
|
||||||
|
|
||||||
@ -34383,11 +34385,13 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
|
|||||||
// Import toastr scss file: need webpack sass-loader
|
// Import toastr scss file: need webpack sass-loader
|
||||||
__webpack_require__("./node_modules/vue-toastr/src/vue-toastr.scss");
|
__webpack_require__("./node_modules/vue-toastr/src/vue-toastr.scss");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Register vue component
|
// Register vue component
|
||||||
Vue.component('vue-toastr', __WEBPACK_IMPORTED_MODULE_1_vue_toastr___default.a);
|
__WEBPACK_IMPORTED_MODULE_2_vue___default.a.component('vue-toastr', __WEBPACK_IMPORTED_MODULE_1_vue_toastr___default.a);
|
||||||
|
|
||||||
// Global translation helper
|
// Global translation helper
|
||||||
Vue.prototype.trans = function (string) {
|
__WEBPACK_IMPORTED_MODULE_2_vue___default.a.prototype.trans = function (string) {
|
||||||
return __WEBPACK_IMPORTED_MODULE_0_lodash__["get"](i18n, string);
|
return __WEBPACK_IMPORTED_MODULE_0_lodash__["get"](i18n, string);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34397,7 +34401,7 @@ window.Vue = __webpack_require__("./node_modules/vue/dist/vue.common.js");
|
|||||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||||
|
|
||||||
/* Development only*/
|
/* Development only*/
|
||||||
Vue.config.devtools = true;
|
__WEBPACK_IMPORTED_MODULE_2_vue___default.a.config.devtools = true;
|
||||||
|
|
||||||
window.axios.defaults.headers.common = {
|
window.axios.defaults.headers.common = {
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
10
public/js/client_edit.min.js
vendored
10
public/js/client_edit.min.js
vendored
@ -34374,6 +34374,8 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
|
|||||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash__);
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_lodash___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_lodash__);
|
||||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_vue_toastr__ = __webpack_require__("./node_modules/vue-toastr/dist/vue-toastr.js");
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_vue_toastr__ = __webpack_require__("./node_modules/vue-toastr/dist/vue-toastr.js");
|
||||||
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_vue_toastr___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_vue_toastr__);
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_vue_toastr___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_vue_toastr__);
|
||||||
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_vue__ = __webpack_require__("./node_modules/vue/dist/vue.common.js");
|
||||||
|
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_vue___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2_vue__);
|
||||||
// lodash handles our translations
|
// lodash handles our translations
|
||||||
|
|
||||||
|
|
||||||
@ -34383,11 +34385,13 @@ Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
|
|||||||
// Import toastr scss file: need webpack sass-loader
|
// Import toastr scss file: need webpack sass-loader
|
||||||
__webpack_require__("./node_modules/vue-toastr/src/vue-toastr.scss");
|
__webpack_require__("./node_modules/vue-toastr/src/vue-toastr.scss");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Register vue component
|
// Register vue component
|
||||||
Vue.component('vue-toastr', __WEBPACK_IMPORTED_MODULE_1_vue_toastr___default.a);
|
__WEBPACK_IMPORTED_MODULE_2_vue___default.a.component('vue-toastr', __WEBPACK_IMPORTED_MODULE_1_vue_toastr___default.a);
|
||||||
|
|
||||||
// Global translation helper
|
// Global translation helper
|
||||||
Vue.prototype.trans = function (string) {
|
__WEBPACK_IMPORTED_MODULE_2_vue___default.a.prototype.trans = function (string) {
|
||||||
return __WEBPACK_IMPORTED_MODULE_0_lodash__["get"](i18n, string);
|
return __WEBPACK_IMPORTED_MODULE_0_lodash__["get"](i18n, string);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34397,7 +34401,7 @@ window.Vue = __webpack_require__("./node_modules/vue/dist/vue.common.js");
|
|||||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||||
|
|
||||||
/* Development only*/
|
/* Development only*/
|
||||||
Vue.config.devtools = true;
|
__WEBPACK_IMPORTED_MODULE_2_vue___default.a.config.devtools = true;
|
||||||
|
|
||||||
window.axios.defaults.headers.common = {
|
window.axios.defaults.headers.common = {
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
21198
public/js/client_list.js
vendored
21198
public/js/client_list.js
vendored
File diff suppressed because one or more lines are too long
21198
public/js/client_list.min.js
vendored
21198
public/js/client_list.min.js
vendored
File diff suppressed because one or more lines are too long
2
resources/js/src/bootstrap.js
vendored
2
resources/js/src/bootstrap.js
vendored
@ -7,6 +7,8 @@ import Toastr from 'vue-toastr';
|
|||||||
// Import toastr scss file: need webpack sass-loader
|
// Import toastr scss file: need webpack sass-loader
|
||||||
require('vue-toastr/src/vue-toastr.scss');
|
require('vue-toastr/src/vue-toastr.scss');
|
||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
// Register vue component
|
// Register vue component
|
||||||
Vue.component('vue-toastr',Toastr);
|
Vue.component('vue-toastr',Toastr);
|
||||||
|
|
||||||
|
@ -1,13 +1,22 @@
|
|||||||
//import * as Vue from 'vue';
|
require('../bootstrap');
|
||||||
|
|
||||||
|
/* Must be declare in every child view*/
|
||||||
|
declare var i18n;
|
||||||
|
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
|
|
||||||
Vue.component('client-list', require('../components/client/ClientList.vue'));
|
Vue.component('client-list', require('../components/client/ClientList.vue'));
|
||||||
Vue.component('client-actions', require('../components/client/ClientActions.vue'));
|
Vue.component('client-actions', require('../components/client/ClientActions.vue'));
|
||||||
Vue.component('vuetable', require('vuetable-2/src/components/Vuetable'));
|
Vue.component('vuetable', require('vuetable-2/src/components/Vuetable'));
|
||||||
Vue.component('vuetable-pagination', require('vuetable-2/src/components/VuetablePagination'));
|
Vue.component('vuetable-pagination', require('vuetable-2/src/components/VuetablePagination'));
|
||||||
Vue.component('vuetable-pagination-bootstrap', require('../components/util/VuetablePaginationBootstrap'));
|
Vue.component('vuetable-pagination-bootstrap', require('../components/util/VuetablePaginationBootstrap'));
|
||||||
Vue.component('vuetable-filter-bar', require('../components/util/VuetableFilterBar'));
|
Vue.component('vuetable-filter-bar', require('../components/util/VuetableFilterBar'));
|
||||||
|
Vue.component('vuetable-query-filter', require('../components/client/ClientFilters.vue'));
|
||||||
|
Vue.component('vuetable-multi-select', require('../components/util/VuetableMultiSelect.vue'));
|
||||||
|
Vue.component('list-actions', require('../components/util/VueListActions.vue'));
|
||||||
|
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
|
|
||||||
|
23
resources/js/src/components/client/ClientFilters.vue
Normal file
23
resources/js/src/components/client/ClientFilters.vue
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<vuetable-filter-bar></vuetable-filter-bar>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
console.dir('loaded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
</style>
|
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<vuetable-filter-bar></vuetable-filter-bar>
|
|
||||||
|
|
||||||
<vuetable ref="vuetable"
|
<vuetable ref="vuetable"
|
||||||
api-url="/clients"
|
api-url="/clients"
|
||||||
:fields="fields"
|
:fields="fields"
|
||||||
:per-page="20"
|
:per-page="perPage"
|
||||||
:sort-order="sortOrder"
|
:sort-order="sortOrder"
|
||||||
:append-params="moreParams"
|
:append-params="moreParams"
|
||||||
:css="css.table"
|
:css="css.table"
|
||||||
@ -39,76 +38,27 @@ import VuetableCss from '../util/VuetableCss'
|
|||||||
Vue.use(VueEvents)
|
Vue.use(VueEvents)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
Vuetable,
|
Vuetable,
|
||||||
VuetablePagination,
|
VuetablePagination,
|
||||||
VuetablePaginationInfo
|
VuetablePaginationInfo
|
||||||
},
|
},
|
||||||
data () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
css: VuetableCss,
|
css: VuetableCss,
|
||||||
sortOrder: [
|
perPage: this.datatable.per_page,
|
||||||
{
|
sortOrder: this.datatable.sort_order,
|
||||||
field: 'name',
|
|
||||||
sortField: 'name',
|
|
||||||
direction: 'asc'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
moreParams: {},
|
moreParams: {},
|
||||||
fields: [
|
fields: this.datatable.fields
|
||||||
{
|
|
||||||
name: '__checkbox', // <----
|
|
||||||
title: '',
|
|
||||||
titleClass: 'center aligned',
|
|
||||||
dataClass: 'center aligned'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'name',
|
|
||||||
sortField: 'name',
|
|
||||||
dataClass: 'center aligned'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'contact',
|
|
||||||
sortField: 'contact',
|
|
||||||
dataClass: 'center aligned'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'email',
|
|
||||||
sortField: 'email',
|
|
||||||
dataClass: 'center aligned'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'client_created_at',
|
|
||||||
title: 'Date created',
|
|
||||||
sortField: 'client_created_at',
|
|
||||||
dataClass: 'center aligned'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'last_login',
|
|
||||||
title: 'Last login',
|
|
||||||
sortField: 'last_login',
|
|
||||||
dataClass: 'center aligned'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'balance',
|
|
||||||
sortField: 'balance',
|
|
||||||
dataClass: 'center aligned'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '__component:client-actions', // <----
|
|
||||||
title: '',
|
|
||||||
titleClass: 'center aligned',
|
|
||||||
dataClass: 'center aligned'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
//props: ['list'],
|
props: ['datatable'],
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
||||||
this.$events.$on('filter-set', eventData => this.onFilterSet(eventData))
|
this.$events.$on('filter-set', eventData => this.onFilterSet(eventData))
|
||||||
this.$events.$on('filter-reset', e => this.onFilterReset())
|
this.$events.$on('filter-reset', e => this.onFilterReset())
|
||||||
|
console.dir(this.datatable)
|
||||||
},
|
},
|
||||||
beforeMount: function () {
|
beforeMount: function () {
|
||||||
|
|
||||||
@ -144,7 +94,8 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style type="text/css">
|
||||||
|
|
||||||
.pagination {
|
.pagination {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
float: right;
|
float: right;
|
||||||
@ -180,4 +131,12 @@ export default {
|
|||||||
.pagination-info {
|
.pagination-info {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
th {
|
||||||
|
background: #777777;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.sortable th i:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
42
resources/js/src/components/util/VueListActions.vue
Normal file
42
resources/js/src/components/util/VueListActions.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-start">
|
||||||
|
|
||||||
|
<div class="p-2">
|
||||||
|
|
||||||
|
<div class="btn-group">
|
||||||
|
<button type="button" class="btn btn-primary btn-lg">Archive</button>
|
||||||
|
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" x-placement="bottom-start" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(81px, 38px, 0px);">
|
||||||
|
<a class="dropdown-item" href="#">Archive</a>
|
||||||
|
<a class="dropdown-item" href="#">Delete</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mr-auto p-2">
|
||||||
|
<vuetable-multi-select></vuetable-multi-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ml-auto p-2">
|
||||||
|
<vuetable-query-filter></vuetable-query-filter>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-2">
|
||||||
|
<button class="btn btn-primary btn-lg ">{{ trans('texts.new_client') }}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
export default {
|
export default {
|
||||||
table: {
|
table: {
|
||||||
tableClass: 'table table-bordered table-hover',
|
tableClass: 'table table-striped table-hover',
|
||||||
loadingClass: 'loading',
|
loadingClass: 'loading',
|
||||||
ascendingIcon: 'fa fa-angle-double-up',
|
ascendingIcon: 'fa fa-angle-double-up',
|
||||||
descendingIcon: 'fa fa-angle-double-down',
|
descendingIcon: 'fa fa-angle-double-down',
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-9" style="padding:10px;">
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" v-model="filterText" class="form-control" @keyup.enter="doFilter" placeholder="search">
|
<input type="text" v-model="filterText" class="form-control" @keyup.enter="doFilter" placeholder="search">
|
||||||
<button class="btn btn-primary" @click="doFilter">Go</button>
|
<button class="btn btn-primary" @click="doFilter">Go</button>
|
||||||
<button class="btn btn-light" @click="resetFilter">Reset</button>
|
<button class="btn btn-light" @click="resetFilter">Reset</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -38,4 +34,7 @@
|
|||||||
.form-inline > * {
|
.form-inline > * {
|
||||||
margin:5px 10px;
|
margin:5px 10px;
|
||||||
}
|
}
|
||||||
|
.form-control {
|
||||||
|
min-height: 40px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
42
resources/js/src/components/util/VuetableMultiSelect.vue
Normal file
42
resources/js/src/components/util/VuetableMultiSelect.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!-- Vue component -->
|
||||||
|
<template>
|
||||||
|
<div style="width:300px;">
|
||||||
|
<multiselect v-model="value"
|
||||||
|
:options="options"
|
||||||
|
:multiple="true"
|
||||||
|
:placeholder="trans('texts.status')"
|
||||||
|
@input="onChange"
|
||||||
|
></multiselect>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
|
||||||
|
import Multiselect from 'vue-multiselect'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// OR register locally
|
||||||
|
components: { Multiselect },
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
value: 'active',
|
||||||
|
options: ['active', 'archived', 'deleted']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange (value) {
|
||||||
|
console.dir(this.value)
|
||||||
|
this.value = value
|
||||||
|
if (value.indexOf('Reset me!') !== -1) this.value = []
|
||||||
|
},
|
||||||
|
onSelect (option) {
|
||||||
|
if (option === 'Disable me!') this.isDisabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -1,4 +1,4 @@
|
|||||||
@extends('layouts.master', ['header' => $header])
|
@extends('layouts.master', ['header' => $header])
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
<main class="main" id="client_create">
|
<main class="main" id="client_create">
|
||||||
|
@ -10,23 +10,18 @@
|
|||||||
<!-- Breadcrumb-->
|
<!-- Breadcrumb-->
|
||||||
{{ Breadcrumbs::render('clients') }}
|
{{ Breadcrumbs::render('clients') }}
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid" id="client_list">
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<button class="btn btn-primary btn-lg pull-right">{{ trans('texts.new_client') }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="client_list" style="padding-top:20px;">
|
<list-actions></list-actions>
|
||||||
<div class="animated fadeIn">
|
|
||||||
<div class="col-md-12 card">
|
|
||||||
|
|
||||||
<client-list></client-list>
|
<div style="background: #fff;">
|
||||||
|
|
||||||
|
<client-list :datatable="{{ $datatable }}"></client-list>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script defer src=" {{ mix('/js/client_list.min.js') }}"></script>
|
<script defer src=" {{ mix('/js/client_list.min.js') }}"></script>
|
||||||
|
@ -42,11 +42,17 @@ Route::group(['middleware' => ['auth:user', 'db']], function () {
|
|||||||
Route::resource('dashboard', 'DashboardController'); // name = (dashboard. index / create / show / update / destroy / edit
|
Route::resource('dashboard', 'DashboardController'); // name = (dashboard. index / create / show / update / destroy / edit
|
||||||
Route::get('logout', 'Auth\LoginController@logout')->name('user.logout');
|
Route::get('logout', 'Auth\LoginController@logout')->name('user.logout');
|
||||||
Route::resource('invoices', 'InvoiceController'); // name = (invoices. index / create / show / update / destroy / edit
|
Route::resource('invoices', 'InvoiceController'); // name = (invoices. index / create / show / update / destroy / edit
|
||||||
|
Route::post('invoices/bulk', 'InvoiceController@bulk')->name('invoices.bulk');
|
||||||
Route::resource('clients', 'ClientController'); // name = (clients. index / create / show / update / destroy / edit
|
Route::resource('clients', 'ClientController'); // name = (clients. index / create / show / update / destroy / edit
|
||||||
|
Route::post('clients/bulk', 'ClientController@bulk')->name('clients.bulk');
|
||||||
Route::resource('tasks', 'TaskController'); // name = (tasks. index / create / show / update / destroy / edit
|
Route::resource('tasks', 'TaskController'); // name = (tasks. index / create / show / update / destroy / edit
|
||||||
|
Route::post('tasks/bulk', 'TaskController@bulk')->name('tasks.bulk');
|
||||||
Route::resource('payments', 'PaymentController'); // name = (payments. index / create / show / update / destroy / edit
|
Route::resource('payments', 'PaymentController'); // name = (payments. index / create / show / update / destroy / edit
|
||||||
|
Route::post('payments/bulk', 'PaymentController@bulk')->name('payments.bulk');
|
||||||
Route::resource('credits', 'CreditController'); // name = (credits. index / create / show / update / destroy / edit
|
Route::resource('credits', 'CreditController'); // name = (credits. index / create / show / update / destroy / edit
|
||||||
|
Route::post('credits/bulk', 'CreditController@bulk')->name('credits.bulk');
|
||||||
Route::resource('expenses', 'ExpenseController'); // name = (expenses. index / create / show / update / destroy / edit
|
Route::resource('expenses', 'ExpenseController'); // name = (expenses. index / create / show / update / destroy / edit
|
||||||
|
Route::post('expenses/bulk', 'ExpenseController@bulk')->name('expenses.bulk');
|
||||||
Route::resource('user', 'UserProfileController'); // name = (clients. index / create / show / update / destroy / edit
|
Route::resource('user', 'UserProfileController'); // name = (clients. index / create / show / update / destroy / edit
|
||||||
Route::get('settings', 'SettingsController@index')->name('user.settings');
|
Route::get('settings', 'SettingsController@index')->name('user.settings');
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user