Savepoint

This commit is contained in:
Juan Ferrer 2020-03-07 13:52:02 +01:00
parent eb0a9ceed0
commit c6b2db9a79
7 changed files with 148 additions and 136 deletions

View File

@ -13,8 +13,11 @@ import './style.scss';
* *
* @property {Object} filter A key-value object with filter parameters * @property {Object} filter A key-value object with filter parameters
* @property {SearchPanel} panel The panel used for advanced searches * @property {SearchPanel} panel The panel used for advanced searches
* @property {CrudModel} model The model used for searching
* @property {Function} exprBuilder If defined, is used to build each non-null param expresion
* @property {Function} onSearch Function to call when search is submited
*/ */
export default class Controller extends Component { export default class Searchbar extends Component {
constructor($element, $) { constructor($element, $) {
super($element, $); super($element, $);
this.searchState = '.'; this.searchState = '.';
@ -26,6 +29,9 @@ export default class Controller extends Component {
$postLink() { $postLink() {
this.onStateChange(); this.onStateChange();
if (this.$state.is(this.searchState) && this.filter !== null)
this.doSearch();
} }
$onDestroy() { $onDestroy() {
@ -58,8 +64,9 @@ export default class Controller extends Component {
onStateChange() { onStateChange() {
let filter = null; let filter = null;
let isIndex = this.$state.is(this.searchState);
if (this.$state.is(this.searchState)) { if (isIndex) {
if (this.$params.q) { if (this.$params.q) {
try { try {
filter = JSON.parse(this.$params.q); filter = JSON.parse(this.$params.q);
@ -72,6 +79,11 @@ export default class Controller extends Component {
} }
this.filter = filter; this.filter = filter;
if (isIndex)
this.doSearch();
else if (this.model)
this.model.clear();
} }
openPanel(event) { openPanel(event) {
@ -100,25 +112,21 @@ export default class Controller extends Component {
this.$.popover.hide(); this.$.popover.hide();
filter = compact(filter); filter = compact(filter);
filter = filter != null ? filter : {}; filter = filter != null ? filter : {};
this.doSearch(filter); this.goSearch(filter);
} }
onSubmit() { onSubmit() {
this.doSearch(this.fromBar()); this.goSearch(this.fromBar());
} }
removeParam(index) { removeParam(index) {
this.params.splice(index, 1); this.params.splice(index, 1);
this.doSearch(this.fromBar()); this.goSearch(this.fromBar());
} }
doSearch(filter) { goSearch(filter) {
this.filter = filter; this.filter = filter;
this.doSearch();
let opts = this.$state.is(this.searchState)
? {location: 'replace'} : null;
this.$state.go(this.searchState,
{q: JSON.stringify(filter)}, opts);
} }
fromBar() { fromBar() {
@ -171,61 +179,6 @@ export default class Controller extends Component {
this.params.push({chip, key, value}); this.params.push({chip, key, value});
}); });
} }
}
ngModule.vnComponent('vnSearchbar', {
controller: Controller,
template: require('./searchbar.html'),
bindings: {
searchState: '@?',
filter: '<?',
suggestedFilter: '<?',
panel: '@',
info: '@?'
}
});
/**
* @property {CrudModel} model The model used for searching
* @property {Function} exprBuilder If defined, is used to build each non-null param expresion
* @property {Function} onSearch Function to call when search is submited
*/
class AutoSearch {
constructor($state, $transitions) {
this.$state = $state;
this.$transitions = $transitions;
let criteria = {to: this.$state.current.name};
this.deregisterCallback = this.$transitions.onSuccess(criteria,
() => this.onStateChange());
this.fetchFilter();
}
$postLink() {
if (this.filter !== null)
this.doSearch();
}
$onDestroy() {
this.deregisterCallback();
}
fetchFilter() {
if (this.$state.params.q) {
try {
this.filter = JSON.parse(this.$state.params.q);
} catch (e) {
console.error(e);
}
} else
this.filter = null;
}
onStateChange() {
this.fetchFilter();
this.doSearch();
}
doSearch() { doSearch() {
let filter = this.filter; let filter = this.filter;
@ -257,25 +210,81 @@ class AutoSearch {
this.model.applyFilter( this.model.applyFilter(
where ? {where} : null, where ? {where} : null,
hasParams ? userParams : null hasParams ? userParams : null
); ).then(() => this.onModelFilter());
} else } else
this.model.clear(); this.model.clear();
} }
} }
onModelFilter() {
let params;
let opts;
let data = this.model.data;
let currentState = this.$state.current.name;
let stateParts = currentState.split('.');
let baseState = stateParts[0];
let subState = stateParts[1];
if (this.goState && data && data.length == 1) {
switch (subState) {
case 'index':
subState = 'card.summary';
break;
case 'card':
subState += `.${stateParts[2]}`;
break;
}
if (this.goStateParams)
params = this.goStateParams({$row: data[0]});
} else {
if (subState == 'index')
opts = {location: 'replace'};
subState = `index`;
params = {q: JSON.stringify(this.filter)};
}
this.$state.go(`${baseState}.${subState}`, params, opts);
}
exprBuilder(param, value) { exprBuilder(param, value) {
return {[param]: value}; return {[param]: value};
} }
} }
AutoSearch.$inject = ['$state', '$transitions'];
ngModule.vnComponent('vnSearchbar', {
controller: Searchbar,
template: require('./searchbar.html'),
bindings: {
searchState: '@?',
filter: '<?',
suggestedFilter: '<?',
panel: '@',
info: '@?',
model: '<?',
onSearch: '&?',
exprBuilder: '&?',
paramBuilder: '&?',
goState: '@?',
goStateParams: '&?'
}
});
class AutoSearch {
constructor(vnSlotService) {
let searchbar = vnSlotService.getContent('topbar');
if (searchbar && searchbar.$ctrl instanceof Searchbar) {
this.model = searchbar.$ctrl.model;
console.log(this.model.data);
}
}
}
AutoSearch.$inject = ['vnSlotService'];
ngModule.vnComponent('vnAutoSearch', { ngModule.vnComponent('vnAutoSearch', {
controller: AutoSearch, controller: AutoSearch,
bindings: { bindings: {
model: '<?', model: '=?'
onSearch: '&?',
exprBuilder: '&?',
paramBuilder: '&?'
} }
}); });

View File

@ -67,6 +67,12 @@ export class SlotService {
$content.remove(); $content.remove();
} }
getContent(slot) {
if (this.slots[slot])
return this.slots[slot].$element[0].firstElementChild;
return null;
}
refreshContent(slot) { refreshContent(slot) {
if (!this.slots[slot]) return; if (!this.slots[slot]) return;
let $content = this.stacks[slot][0]; let $content = this.stacks[slot][0];

View File

@ -63,9 +63,12 @@ export function config($translatePartialLoaderProvider, $httpProvider, $compileP
$httpProvider.interceptors.push('vnInterceptor'); $httpProvider.interceptors.push('vnInterceptor');
$compileProvider $compileProvider
.debugInfoEnabled(false)
.commentDirectivesEnabled(false) .commentDirectivesEnabled(false)
.cssClassDirectivesEnabled(false); .cssClassDirectivesEnabled(false);
let env = process.env.NODE_ENV;
if (!env || env == 'development')
$compileProvider.debugInfoEnabled(false);
} }
ngModule.config(config); ngModule.config(config);

View File

@ -1,14 +1,5 @@
<vn-crud-model
vn-id="model"
url="Zones"
filter="::$ctrl.filter"
limit="20"
data="zones"
auto-load="false">
</vn-crud-model>
<vn-auto-search <vn-auto-search
model="model" model="model">
expr-builder="$ctrl.exprBuilder(param, value)">
</vn-auto-search> </vn-auto-search>
<vn-data-viewer <vn-data-viewer
model="model" model="model"
@ -27,7 +18,7 @@
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<vn-tr <vn-tr
ng-repeat="zone in zones" ng-repeat="zone in model.data"
ui-sref="zone.card.summary({id: zone.id})" ui-sref="zone.card.summary({id: zone.id})"
class="clickable search-result"> class="clickable search-result">
<vn-td number>{{::zone.id}}</vn-td> <vn-td number>{{::zone.id}}</vn-td>
@ -61,7 +52,7 @@
</vn-popup> </vn-popup>
<vn-confirm <vn-confirm
vn-id="clone" vn-id="clone"
on-response="$ctrl.onCloneAccept($response)" on-accept="$ctrl.onCloneAccept()"
question="Do you want to clone this zone?" question="Do you want to clone this zone?"
message="All it's properties will be copied"> message="All it's properties will be copied">
</vn-confirm> </vn-confirm>

View File

@ -1,55 +1,10 @@
import ngModule from '../module'; import ngModule from '../module';
export default class Controller { export default class Controller {
constructor($scope, $http, $state) { constructor($, $http, $state) {
this.$scope = $scope; this.$ = $;
this.$http = $http; this.$http = $http;
this.$state = $state; this.$state = $state;
this.filter = {
include: {
relation: 'agencyMode',
scope: {fields: ['name']}
}
};
}
exprBuilder(param, value) {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {id: value}
: {name: {like: `%${value}%`}};
case 'name':
return {[param]: {like: `%${value}%`}};
case 'agencyModeFk':
return {[param]: value};
}
}
/**
* Clones a zone and all its properties
* @param {Object} event - Event object
* @param {Object} zone - Selected item
*/
clone(event, zone) {
this.stopEvent(event);
this.selectedZone = zone;
this.$scope.clone.show();
}
/**
* Clone response callback
* @param {String} response - Response string (['accept', 'cancel'])
*/
onCloneAccept(response) {
if (!(response == 'accept' && this.selectedZone)) return;
const query = `Zones/${this.selectedZone.id}/clone`;
this.$http.post(query).then(res => {
if (res && res.data)
this.$state.go('zone.card.basicData', {id: res.data.id});
});
this.selectedZone = null;
} }
/** /**
@ -60,13 +15,28 @@ export default class Controller {
preview(event, zone) { preview(event, zone) {
this.stopEvent(event); this.stopEvent(event);
this.selectedZone = zone; this.selectedZone = zone;
this.$scope.summary.show(); this.$.summary.show();
} }
/** /**
* Prevents normal event propagation * Clones a zone and all its properties
* @param {Object} event - Event object * @param {Object} event - Event object
* @param {Object} zone - Selected item
*/ */
clone(event, zone) {
this.stopEvent(event);
this.selectedZone = zone;
this.$.clone.show();
}
onCloneAccept() {
return this.$http.post(`Zones/${this.selectedZone.id}/clone`)
.then(res => {
this.selectedZone = null;
this.$state.go('zone.card.basicData', {id: res.data.id});
});
}
stopEvent(event) { stopEvent(event) {
event.preventDefault(); event.preventDefault();
event.stopImmediatePropagation(); event.stopImmediatePropagation();

View File

@ -1,8 +1,18 @@
<vn-crud-model
vn-id="model"
url="Zones"
filter="::$ctrl.filter"
limit="20">
</vn-crud-model>
<vn-portal slot="topbar"> <vn-portal slot="topbar">
<vn-searchbar <vn-searchbar
search-state="zone.index" search-state="zone.index"
panel="vn-zone-search-panel" panel="vn-zone-search-panel"
info="Search zone by id or name"> info="Search zone by id or name"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)"
go-state="zone.card.summary"
go-state-params="{id: $row.id}">
</vn-searchbar> </vn-searchbar>
</vn-portal> </vn-portal>
<vn-portal slot="menu"> <vn-portal slot="menu">

View File

@ -1,7 +1,30 @@
import ngModule from '../module'; import ngModule from '../module';
import ModuleMain from 'salix/components/module-main'; import ModuleMain from 'salix/components/module-main';
export default class Zone extends ModuleMain {} export default class Zone extends ModuleMain {
constructor($element, $) {
super($element, $);
this.filter = {
include: {
relation: 'agencyMode',
scope: {fields: ['name']}
}
};
}
exprBuilder(param, value) {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {id: value}
: {name: {like: `%${value}%`}};
case 'name':
return {[param]: {like: `%${value}%`}};
case 'agencyModeFk':
return {[param]: value};
}
}
}
ngModule.vnComponent('vnZone', { ngModule.vnComponent('vnZone', {
controller: Zone, controller: Zone,