merge pull changes
gitea/salix/1625-worker_department_treeview This commit looks good Details

This commit is contained in:
Joan Sanchez 2019-10-08 09:23:29 +02:00
parent b32cf4a386
commit eb655215f4
121 changed files with 2282 additions and 1907 deletions

View File

@ -1,5 +1,6 @@
USE `vn`;
CREATE TABLE vn.`zoneWarehouse` (
CREATE TABLE `vn`.`zoneWarehouse` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`zoneFk` int(11) NOT NULL,
`warehouseFk` smallint(6) unsigned NOT NULL,
@ -10,7 +11,7 @@ CREATE TABLE vn.`zoneWarehouse` (
CONSTRAINT `zoneWarehouse_ibfk_2` FOREIGN KEY (`warehouseFk`) REFERENCES `vn2008`.`warehouse` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
CREATE TABLE vn.`zoneEvent` (
CREATE TABLE `vn`.`zoneEvent` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`zoneFk` int(11) NOT NULL,
`from` date DEFAULT NULL,
@ -25,7 +26,7 @@ CREATE TABLE vn.`zoneEvent` (
CONSTRAINT `zoneEvent_ibfk_1` FOREIGN KEY (`zoneFk`) REFERENCES `zone` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;
CREATE TABLE vn.`zoneExclusion` (
CREATE TABLE `vn`.`zoneExclusion` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`zoneFk` int(11) NOT NULL,
`day` date NOT NULL,

View File

@ -175,8 +175,8 @@ export default {
firstPaymentConfirmed: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon[icon="check"]'
},
dms: {
deleteFileButton: 'vn-client-dms-index vn-table vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
firstDocWorker: 'vn-client-dms-index vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(8) > span',
deleteFileButton: 'vn-client-dms-index vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
firstDocWorker: 'vn-client-dms-index vn-td:nth-child(8) > span',
firstDocWorkerDescriptor: '.vn-popover.shown vn-worker-descriptor',
acceptDeleteButton: 'vn-client-dms-index > vn-confirm button[response="ACCEPT"]'
},
@ -190,8 +190,8 @@ export default {
searchItemInput: 'vn-searchbar vn-textfield input',
searchButton: 'vn-searchbar vn-icon[icon="search"]',
closeItemSummaryPreview: 'vn-item-index [vn-id="preview"] button.close',
fieldsToShowButton: 'vn-item-index vn-table > div.ng-scope > div > vn-icon-button[icon="menu"]',
fieldsToShowForm: 'vn-item-index > div > vn-card > div > vn-table > div.ng-scope > div > vn-dialog > div > form',
fieldsToShowButton: 'vn-item-index vn-table > div > div > vn-icon-button[icon="menu"]',
fieldsToShowForm: 'vn-item-index vn-table > div > div > vn-dialog > div > form',
firstItemImage: 'vn-item-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1)',
firstItemId: 'vn-item-index vn-tbody > a:nth-child(1) > vn-td:nth-child(2)',
idCheckbox: 'vn-item-index vn-dialog form vn-horizontal:nth-child(2) > vn-check',
@ -494,9 +494,9 @@ export default {
},
ticketLog: {
logButton: 'vn-left-menu a[ui-sref="ticket.card.log"]',
changedBy: 'vn-ticket-log > vn-log > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2) > span',
actionTaken: 'vn-ticket-log > vn-log > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(1) > div > div:nth-child(3) > span.value.ng-scope.ng-binding',
id: 'vn-ticket-log > vn-log > vn-vertical > vn-card > div > vn-vertical > vn-table > div > vn-tbody > vn-tr > vn-td.before > vn-one:nth-child(1) > div > span.value.ng-scope.ng-binding'
changedBy: 'vn-ticket-log > vn-log vn-tr:nth-child(1) > vn-td:nth-child(2) > span',
actionTaken: 'vn-ticket-log > vn-log vn-td:nth-child(1) > div > div:nth-child(3) > span.value',
id: 'vn-ticket-log > vn-log vn-td.before > vn-one:nth-child(1) > div > span.value'
},
ticketService: {
addServiceButton: 'vn-ticket-service vn-icon-button[vn-tooltip="Add service"] > button',

View File

@ -65,6 +65,18 @@ describe('Client create path', () => {
expect(result).toEqual('Some fields are invalid');
});
it(`should attempt to create a new user with all it's data but wrong postal code`, async() => {
const result = await nightmare
.clearInput(selectors.createClientView.email)
.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es')
.clearInput(selectors.createClientView.postcode)
.write(selectors.createClientView.postcode, '479999')
.waitToClick(selectors.createClientView.createButton)
.waitForLastSnackbar();
expect(result).toEqual(`The postcode doesn't exists. Ensure you put the correct format`);
});
it(`should check for autocompleted city, province and country`, async() => {
const clientCity = await nightmare
.waitToGetProperty(`${selectors.createClientView.city}`, 'value');
@ -82,8 +94,8 @@ describe('Client create path', () => {
it(`should create a new user with all correct data`, async() => {
const result = await nightmare
.clearInput(selectors.createClientView.email)
.write(selectors.createClientView.email, 'caroldanvers@verdnatura.es')
.clearInput(selectors.createClientView.postcode)
.write(selectors.createClientView.postcode, '46000')
.waitToClick(selectors.createClientView.createButton)
.waitForLastSnackbar();

View File

@ -262,10 +262,12 @@ export default class Calendar extends Component {
*/
select(index) {
if (this.disabled) return;
let day = this.days[index];
day.index = index;
let day = this.days[index].dated;
this.emit('selection', {values: [day]});
this.emit('selection', {
$days: [day],
$type: 'day'
});
}
/**
@ -276,15 +278,17 @@ export default class Calendar extends Component {
selectAll(weekday) {
if (this.disabled) return;
let selected = [];
let days = [];
for (let i in this.days) {
const day = this.days[i];
const date = day.dated;
day.index = i;
if (date.getDay() === weekday && date.getMonth() == this.defaultDate.getMonth())
selected.push(day);
const day = this.days[i].dated;
if (day.getDay() === weekday && day.getMonth() == this.defaultDate.getMonth())
days.push(day);
}
this.emit('selection', {values: selected});
this.emit('selection', {
$days: days,
$type: 'weekday',
$weekday: weekday
});
}
renderStyle(style) {

View File

@ -60,12 +60,17 @@ describe('Component vnCalendar', () => {
describe('select()', () => {
it(`should return the selected element, then emit a 'selection' event`, () => {
spyOn(controller, 'emit');
const days = [{dated: new Date()}];
const dated = new Date();
const days = [{dated}];
controller.days = days;
controller.select(0);
expect(controller.emit).toHaveBeenCalledWith('selection', {values: days});
let res = {
$days: [dated],
$type: 'day'
};
expect(controller.emit).toHaveBeenCalledWith('selection', res);
});
});

View File

@ -1,4 +1,4 @@
<div class="check">
<div class="btn">
<div class="focus-mark"></div>
<div class="mark"></div>
</div>

View File

@ -1,29 +1,16 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import Toggle from '../toggle';
import './style.scss';
/**
* Basic element for user input. You can use this to supply a way for the user
* to toggle an option.
*
* @property {String} label Label to display along the component
* @property {any} field The value with which the element is linked
* @property {Boolean} checked Whether the checkbox is checked
* @property {Boolean} disabled Put component in disabled mode
* @property {Boolean} tripleState Switch between three states when clicked
* @property {Boolean} indeterminate Sets the element into indeterminate state
* @property {String} info Shows a text information tooltip to the user
*/
export default class Controller extends Component {
constructor($element, $, $attrs) {
super($element, $);
let element = this.element;
element.addEventListener('click', e => this.onClick(e));
element.addEventListener('keydown', e => this.onKeydown(e));
element.tabIndex = 0;
}
export default class Check extends Toggle {
set field(value) {
this._field = value;
this.element.classList.toggle('checked', Boolean(value));
@ -34,14 +21,12 @@ export default class Controller extends Component {
return this._field;
}
set disabled(value) {
this.element.tabIndex = !value ? 0 : -1;
this.element.classList.toggle('disabled', Boolean(value));
this._disabled = value;
set checked(value) {
this.field = Boolean(value);
}
get disabled() {
return this._disabled;
get checked() {
return Boolean(this.field);
}
set indeterminate(value) {
@ -63,9 +48,7 @@ export default class Controller extends Component {
}
onClick(event) {
event.preventDefault();
if (this.disabled) return;
if (super.onClick(event)) return;
if (this.tripleState) {
if (this.field == null)
@ -77,28 +60,18 @@ export default class Controller extends Component {
} else
this.field = !this.field;
this.$.$applyAsync();
this.element.dispatchEvent(new Event('change'));
this.emit('change', {value: this.field});
}
onKeydown(event) {
if (event.code == 'Space')
this.onClick(event);
this.changed();
}
}
Controller.$inject = ['$element', '$scope', '$attrs'];
ngModule.component('vnCheck', {
template: require('./index.html'),
controller: Controller,
controller: Check,
bindings: {
label: '@?',
field: '=?',
checked: '<?',
disabled: '<?',
checked: '<?',
tripleState: '<?',
indeterminate: '<?',
info: '@?'

View File

@ -1,26 +1,9 @@
@import "variables";
vn-check {
position: relative;
display: inline-block;
outline: none;
cursor: pointer;
&.disabled {
cursor: initial;
}
& > .check {
position: relative;
box-sizing: border-box;
display: inline-block;
vertical-align: middle;
& > .btn {
border-radius: 2px;
width: 20px;
height: 20px;
transition: background 250ms;
border: 2px solid #666;
margin: 6px 0;
margin-right: .4em;
& > .mark {
box-sizing: border-box;
@ -29,13 +12,10 @@ vn-check {
border-width: 0;
}
}
&.checked > .check {
background-color: $color-main;
&.checked > .btn {
border-color: $color-main;
background-color: $color-main;
& > .focus-mark {
background-color: rgba($color-main, .15);
}
& > .mark {
top: 0;
left: 4px;
@ -47,7 +27,7 @@ vn-check {
border-left: 0;
}
}
&.indeterminate > .check > .mark {
&.indeterminate > .btn > .mark {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
@ -55,23 +35,6 @@ vn-check {
height: 2px;
border-bottom: 2px solid #666;
}
& > .check > .focus-mark {
position: absolute;
top: 50%;
left: 50%;
height: 38px;
width: 38px;
margin-top: -19px;
margin-left: -19px;
border-radius: 50%;
transform: scale3d(0, 0, 0);
transition: background 250ms;
transition: transform 250ms;
background-color: rgba(0, 0, 0, .1);
}
&:focus:not(.disabled) > .check > .focus-mark {
transform: scale3d(1, 1, 1);
}
& > vn-icon {
margin-left: 5px;
color: $color-font-secondary;

View File

@ -207,8 +207,8 @@ export default class CrudModel extends ModelProxy {
sendRequest(filter, append) {
this.cancelRequest();
this.canceler = this.$q.defer();
this.isRefreshing = !append;
this.isPaging = append;
if (!append) this.status = 'loading';
let params = Object.assign(
{filter},
@ -221,9 +221,8 @@ export default class CrudModel extends ModelProxy {
return this.$http.get(this._url, options).then(
json => this.onRemoteDone(json, filter, append),
json => this.onRemoteError(json)
json => this.onRemoteError(json, append)
).finally(() => {
this.isRefreshing = false;
this.isPaging = false;
});
}
@ -243,7 +242,12 @@ export default class CrudModel extends ModelProxy {
this.onRequestEnd();
}
onRemoteError(err) {
onRemoteError(err, append) {
if (!append) {
this.clear();
this.status = 'error';
}
this.onRequestEnd();
throw err;
}

View File

@ -0,0 +1,31 @@
<div ng-if="$ctrl.isReady">
<div ng-transclude></div>
<vn-pagination
model="$ctrl.model"
pad-medium-top>
</vn-pagination>
</div>
<div
class="empty-rows"
ng-if="!$ctrl.isReady"
ng-switch="$ctrl.status">
<vn-spinner
ng-switch-when="loading"
enable="::true">
</vn-spinner>
<span
ng-switch-when="clear"
translate>
Enter a new search
</span>
<span
ng-switch-when="error"
translate>
Ups! It seems there was an error
</span>
<span
ng-switch-when="empty"
translate>
No results
</span>
</div>

View File

@ -0,0 +1,33 @@
import ngModule from '../../module';
import './style.scss';
export default class DataViewer {
get isReady() {
return this.status == 'ready';
}
get status() {
if (this.model)
return this.model.status;
if (this.isLoading)
return 'loading';
if (!this.data)
return 'clear';
if (this.data.length)
return 'ready';
else
return 'empty';
}
}
ngModule.component('vnDataViewer', {
template: require('./index.html'),
transclude: true,
controller: DataViewer,
bindings: {
model: '<?',
data: '<?',
isLoading: '<?'
}
});

View File

@ -0,0 +1,14 @@
@import "variables";
vn-data-viewer {
display: block;
& > .empty-rows {
display: block;
text-align: center;
padding: 1.5em;
box-sizing: border-box;
color: $color-font-secondary;
font-size: 1.4em;
}
}

View File

@ -0,0 +1,36 @@
<div class="container">
<div
ng-transclude="prepend"
class="prepend">
</div>
<div class="infix">
<div class="fix prefix"></div>
<div class="control">
<input type="text" ng-model="$ctrl.field"/>
</div>
<div class="fix suffix"></div>
<label>
<span translate>{{::$ctrl.label}}</span>
<span class="required">*</span>
</label>
</div>
<div class="icons">
<vn-icon
icon="clear"
translate-attr="{title: 'Clear'}"
ng-click="$ctrl.onClear()">
</vn-icon>
<vn-icon
ng-if="::$ctrl.info"
icon="info_outline"
vn-tooltip="{{::$ctrl.info}}">
</vn-icon>
</div>
<div
ng-transclude="append"
class="append">
</div>
<div class="underline blur"></div>
<div class="underline focus"></div>
</div>
<div class="hint"></div>

View File

@ -0,0 +1,178 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import './style.scss';
export default class Field extends Component {
constructor($element, $scope) {
super($element, $scope);
this._value = undefined;
this.prefix = null;
this.suffix = null;
this.input = this.element.querySelector('input');
this.classList = this.element.classList;
this.classList.add('vn-field');
this.element.addEventListener('focusin',
() => this.onFocus(true));
this.element.addEventListener('focusout',
() => this.onFocus(false));
this.element.addEventListener('click',
() => this.onClick());
}
$onInit() {
if (this.info) this.classList.add('has-icons');
}
set field(value) {
this._field = value;
this.classList.toggle('not-empty', value != null && value !== '');
}
get field() {
return this._field;
}
set type(value) {
this.input.type = value;
}
get type() {
return this.input.type;
}
set disabled(value) {
this._disabled = boolTag(value);
this.input.disabled = this._disabled;
this.classList.toggle('disabled', this._disabled);
}
get disabled() {
return this._disabled;
}
set readonly(value) {
this._readonly = boolTag(value);
this.input.readOnly = this._readonly;
this.classList.toggle('readonly', this._readonly);
}
get readonly() {
return this._readonly;
}
set required(value) {
this._required = boolTag(value);
let required = this.element.querySelector('.required');
display(required, this._required);
}
get required() {
return this._required;
}
set prefix(value) {
this._prefix = value;
this.refreshFix('.prefix', value);
}
get prefix() {
return this._prefix;
}
set suffix(value) {
this._suffix = value;
this.refreshFix('.suffix', value);
}
get suffix() {
return this._suffix;
}
set hint(value) {
this._hint = value;
this.refreshHint();
}
get hint() {
return this._hint;
}
set error(value) {
this._error = value;
this.refreshHint();
this.classList.toggle('invalid', Boolean(value));
}
get error() {
return this._error;
}
refreshHint() {
let hint = this.error || this.hint || '';
let hintEl = this.element.querySelector('.hint');
hintEl.innerText = hint;
hintEl.classList.toggle('filled', Boolean(hint));
}
refreshFix(selector, text) {
let fix = this.element.querySelector(selector);
display(fix, text);
fix.innerText = text || '';
}
onClick() {
if (this.input !== document.activeElement)
this.input.focus();
}
onFocus(hasFocus) {
this.classList.toggle('focused', hasFocus);
}
onClear() {
this.input.value = '';
this.input.dispatchEvent(new Event('change'));
}
focus() {
this.input.focus();
}
select() {
this.input.select();
}
}
Field.$inject = ['$element', '$scope'];
ngModule.component('vnField', {
template: require('./index.html'),
transclude: {
prepend: '?prepend',
append: '?append'
},
controller: Field,
bindings: {
field: '=?',
label: '@?',
name: '@?',
type: '@?',
info: '@?',
disabled: '@?',
readonly: '@?',
required: '@?',
prefix: '@?',
suffix: '@?',
hint: '@?',
error: '<?'
}
});
function boolTag(value) {
return Boolean(value || value === '');
}
function display(element, display) {
element.style.display = display ? 'initial' : 'none';
}

View File

@ -0,0 +1,227 @@
@import "variables";
.vn-field {
display: inline-block;
width: 100%;
& > .container {
display: flex;
align-items: stretch;
position: relative;
height: 56px;
& > .infix {
position: relative;
display: flex;
flex: auto;
width: 100%;
min-width: 0;
& > label {
position: absolute;
left: 0;
top: 18px;
line-height: 20px;
pointer-events: none;
color: $color-font-secondary;
transition-property: top, color, font-size;
transition-duration: 400ms;
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
& > .required {
display: none;
color: $color-alert
}
}
& > .fix {
padding-top: 24px;
line-height: 24px;
font-size: $input-font-size;
opacity: 0;
transition: opacity 200ms ease-in-out;
&.prefix {
padding-right: 5px;
}
&.suffix {
padding-left: 5px;
}
}
& > .control {
height: 100%;
flex: auto;
}
& > .control > input {
padding-top: 24px;
padding-bottom: 8px;
height: inherit;
outline: none;
border: none;
font-family: Arial, sans-serif;
display: block;
font-size: $input-font-size;
width: 100%;
background: 0;
color: inherit;
box-sizing: border-box;
&[type=time],
&[type=date] {
clip-path: inset(0 20px 0 0);
}
&[type=number] {
-moz-appearance: textfield;
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
&:invalid {
box-shadow: none;
}
}
}
& > .prepend,
& > .append,
& > .icons {
display: flex;
align-items: center;
color: $color-font-secondary;
}
& > .prepend > prepend,
& > .append > append,
& > .icons {
display: flex;
& > vn-icon {
font-size: 24px;
}
}
& > .prepend > prepend {
padding-right: 12px;
}
& > .append > append {
padding-left: 12px;
}
& > .icons > vn-icon[icon=clear] {
display: none;
cursor: pointer;
}
& > .underline {
position: absolute;
bottom: 0;
content: ' ';
pointer-events: none;
width: 100%;
&.blur {
border-bottom: 1px solid $color-input-underline;
transition: border-color 200ms ease-in-out;
}
&.focus {
height: 2px;
background-color: $color-main;
left: 50%;
width: 0;
transition-property: width, left, background-color;
transition-duration: 300ms;
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
}
}
}
&.not-empty > .container,
&.focused > .container {
& > .infix {
& > .fix {
opacity: 1;
}
& > label {
top: 5px;
color: $color-main;
padding: 0;
font-size: 12px;
}
}
}
&.has-icons,
&.not-empty:hover,
&.not-empty.focused {
& > .container > .append > append {
padding-left: 0;
}
& > .container > .icons {
padding-left: 12px;
}
}
&:not(.disabled):not(.readonly) {
&.focused > .container > .underline.focus {
left: 0;
width: 100%;
}
& > .container:hover > .underline.blur {
border-color: $color-input-underline-hover;
}
&.not-empty:hover,
&.not-empty.focused {
& > .container > .icons > vn-icon[icon=clear] {
display: initial;
}
}
}
&:not(.not-empty):not(.focused) > .container > .infix > .control > input {
&[type=time],
&[type=date] {
opacity: 0;
}
}
&.readonly > .container {
& > .infix > .control > input {
caret-color: transparent;
}
& > .underline.blur {
border-bottom-style: dashed;
}
}
& > .hint {
z-index: -1;
padding-top: 8px;
height: 20px;
color: rgba(0, 0, 0, .4);
font-size: 12px;
transform: translateY(-28px);
transition-property: opacity, transform, color;
transition-duration: 200ms;
transition-timing-function: ease-in-out;
opacity: 0;
&.filled {
z-index: 0;
opacity: 1;
transform: translateY(0);
}
}
&.invalid {
& > .container {
& > .infix > label {
color: $color-alert;
}
& > .underline.focus {
background-color: $color-alert;
}
& > .underline.blur {
border-bottom-color: $color-alert;
opacity: 1;
}
}
& > .hint {
color: $color-alert;
}
}
}
vn-table {
.vn-field {
margin: 0;
}
}

View File

@ -26,20 +26,21 @@ import './card/card';
import './float-button/float-button';
import './step-control/step-control';
import './label-value/label-value';
import './paging/paging';
import './pagination/pagination';
import './searchbar/searchbar';
import './scroll-up/scroll-up';
import './table';
import './td-editable';
import './input-range';
import './calendar';
import './check';
import './chip';
import './color-legend';
import './data-viewer';
import './field';
import './input-number';
import './input-time';
import './input-file';
import './radio';
import './table';
import './td-editable';
import './th';
import './treeview';

View File

@ -57,6 +57,7 @@ export default class ModelProxy extends DataModel {
constructor($element, $scope) {
super($element, $scope);
this.resetChanges();
this.status = 'clear';
}
get orgData() {
@ -90,6 +91,14 @@ export default class ModelProxy extends DataModel {
set data(value) {
this._data = value;
if (value == null)
this.status = 'clear';
else if (value.length)
this.status = 'ready';
else
this.status = 'empty';
this.emit('dataChange');
this.emit('dataUpdate');
}
@ -109,8 +118,12 @@ export default class ModelProxy extends DataModel {
this.removed.push(item);
this.isChanged = true;
if (!this.data.length)
this.status = 'empty';
this.emit('rowRemove', index);
this.emit('dataUpdate');
if (this.autoSave)
this.save();
}
@ -131,8 +144,11 @@ export default class ModelProxy extends DataModel {
this.data.push(newRow);
this.isChanged = true;
this.status = 'ready';
this.emit('rowInsert', index);
this.emit('dataUpdate');
return index;
}
@ -322,10 +338,10 @@ export class Paginable {
}
/**
* @type {Boolean} Whether the model is refreshing.
* @type {ready|loading|clear|empty|error} The current model status.
*/
get isRefreshing() {
return false;
get status() {
return null;
}
/**

View File

@ -1,13 +1,12 @@
<div
ng-if="$ctrl.model.moreRows">
<div ng-if="$ctrl.model.moreRows">
<vn-icon-button
ng-if="!$ctrl.model.isLoading"
ng-if="!$ctrl.model.isPaging"
icon="more_horiz"
vn-tooltip="Load more"
ng-click="$ctrl.onLoadClick()">
</vn-icon-button>
<vn-spinner
ng-if="$ctrl.model.isLoading"
enable="$ctrl.model.isLoading">
ng-if="$ctrl.model.isPaging"
enable="::true">
</vn-spinner>
</div>

View File

@ -3,7 +3,8 @@ vn-pagination {
display: block;
text-align: center;
& > div > vn-icon-button {
& > div > vn-icon-button {
font-size: 2em;
padding: 0;
}
}

View File

@ -1,11 +0,0 @@
<paging
page="$ctrl.currentPage"
page-size="$ctrl.numPerPage"
ng-if="$ctrl.numPages>1"
total="$ctrl.numItems"
show-prev-next="true"
show-first-last="false"
active-class="active"
ng-click="$ctrl.figureOutToDisplay()"
paging-action="$ctrl.onPageChange(page)">
</paging>

View File

@ -1,58 +0,0 @@
import ngModule from '../../module';
import './style.scss';
export default class Paging {
get numPages() {
return Math.ceil(this.numItems / this.numPerPage);
}
constructor($http, $scope) {
this.$http = $http;
this.$scope = $scope;
this.where = this.filter;
this.numPerPage = null;
this.numItems = 0;
$scope.$watch('$ctrl.index.model.length', () => this.onModelUpdated());
}
$onChanges(changes) {
if (!this.index) return;
this.numPerPage = this.index.filter.size;
this.currentPage = this.index.filter.page;
if (changes.total)
this.numItems = changes.total.currentValue;
}
onModelUpdated() {
let index = this.index;
let filter = index.filter;
if (filter.page >= this.numPages && index.model.length >= this.numPerPage)
this.numItems = filter.page * filter.size + 1;
}
onPageChange(page) {
this.index.filter.page = page;
if (typeof this.pageChange === 'undefined') {
this.index.accept();
} else {
this.pageChange();
}
}
$doCheck() {
if (this.index && this.index.filter && this.index.filter.page && this.index.filter.page != this.currentPage) {
this.currentPage = this.index.filter.page;
}
}
}
Paging.$inject = ['$http', '$scope'];
ngModule.component('vnPaging', {
template: require('./paging.html'),
bindings: {
index: '<',
pageChange: '&?',
total: '<'
},
controller: Paging
});

View File

@ -1,65 +0,0 @@
import './paging.js';
describe('Component vnPaging', () => {
let $scope;
let controller;
beforeEach(angular.mock.module('vnCore', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($componentController, $rootScope) => {
$scope = $rootScope.$new();
controller = $componentController('vnPaging', {$scope});
}));
describe('$onChanges()', () => {
it(`should define numberPage and currentPage based on index.filter properties`, () => {
controller.index = {filter: {size: 'something', page: 'something else'}};
controller.$onChanges({index: 'simpleChange', currentValue: 'current value', previousValue: 'previous value'});
expect(controller.numPerPage).toBe(controller.index.filter.size);
expect(controller.currentPage).toEqual(controller.index.filter.page);
});
it(`should define numItems based on changes.total.currentValue`, () => {
controller.index = {filter: {size: 'something', page: 'something else'}};
controller.$onChanges({total: {currentValue: 'current value'}});
expect(controller.numItems).toEqual('current value');
});
});
describe('onModelUpdated()', () => {
it(`should define controllers numItems as the result of page times size plus one`, () => {
controller.numPerPage = 2;
controller.index = {
filter: {size: 10, page: 10},
model: ['one mother..', 'another model..', 'last model..']
};
controller.onModelUpdated();
expect(controller.numItems).toBe(101);
});
});
describe('onPageChange()', () => {
it(`should call accept() since pageChange property is undefined`, () => {
controller.index = {accept: () => {}, filter: {page: 0}};
spyOn(controller.index, 'accept');
controller.onPageChange(100);
expect(controller.index.accept).toHaveBeenCalledWith();
});
it(`should call pageChange() since pageChange property isn't undefined`, () => {
controller.index = {accept: () => {}, filter: {page: 0}};
controller.pageChange = true;
spyOn(controller, 'pageChange');
controller.onPageChange(100);
expect(controller.pageChange).toHaveBeenCalledWith();
});
});
});

View File

@ -1,40 +0,0 @@
@import "variables";
vn-paging {
display: block;
text-align: center;
ul {
box-shadow: 0 0 .4em $color-shadow;
background-color: #fff;
display: inline-block;
margin: 20px 0;
border-radius: .1em;
padding: 0;
}
li {
display: inline;
&:first-child > a,
&:first-child > span {
margin-left: 0;
}
&.active > a {
background: $color-active;
color: #fff;
}
& > a,
& > span {
position: relative;
float: left;
padding: 6px 12px;
margin-left: -1px;
line-height: 1.42857143;
color: inherit;
text-decoration: none;
}
&:not(.active) > a:hover {
background-color: #ddd;
}
}
}

View File

@ -180,11 +180,8 @@ export default class Popover extends Component {
onDocKeyDown(event) {
if (event.defaultPrevented) return;
if (event.keyCode == 27) { // Esc
event.preventDefault();
if (event.code == 'Escape')
this.hide();
}
}
onMouseDown(event) {

View File

@ -1,29 +1,14 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import Toggle from '../toggle';
import './style.scss';
/**
* Basic element for user input. You can use this to supply a way for the user
* to pick an option from multiple choices.
*
* @property {String} label Label to display along the component
* @property {any} field The value with which the element is linked
* @property {Boolean} checked Whether the radio is checked
* @property {String} val The actual value of the option
* @property {Boolean} disabled Put component in disabled mode
*/
export default class Controller extends Component {
constructor($element, $, $attrs) {
super($element, $);
this.hasInfo = Boolean($attrs.info);
this.info = $attrs.info || null;
let element = this.element;
element.addEventListener('click', e => this.onClick(e));
element.addEventListener('keydown', e => this.onKeydown(e));
element.tabIndex = 0;
}
export default class Radio extends Toggle {
set field(value) {
this._field = value;
this.element.classList.toggle('checked',
@ -34,6 +19,14 @@ export default class Controller extends Component {
return this._field;
}
set checked(value) {
this.field = value ? this.val : null;
}
get checked() {
return this.field == this.val;
}
set val(value) {
this._val = value;
this.field = this.field;
@ -43,51 +36,21 @@ export default class Controller extends Component {
return this._val;
}
set checked(value) {
this.field = value ? this.val : null;
this.$.$applyAsync();
}
get checked() {
return this.field == this.val;
}
set disabled(value) {
this.element.tabIndex = !value ? 0 : -1;
this.element.classList.toggle('disabled', Boolean(value));
this._disabled = value;
}
get disabled() {
return this._disabled;
}
onClick(event) {
if (this.disabled) return;
event.preventDefault();
if (super.onClick(event)) return;
this.field = this.val;
this.$.$applyAsync();
this.element.dispatchEvent(new Event('change'));
}
onKeydown(event) {
if (event.code == 'Space')
this.onClick(event);
this.changed();
}
}
Controller.$inject = ['$element', '$scope', '$attrs'];
ngModule.component('vnRadio', {
template: require('./index.html'),
controller: Controller,
template: require('../toggle/index.html'),
controller: Radio,
bindings: {
label: '@?',
field: '=?',
disabled: '<?',
checked: '<?',
val: '@?',
disabled: '<?'
val: '@?'
}
});

View File

@ -1,4 +1,4 @@
describe('Component vnCheck', () => {
describe('Component vnRadio', () => {
let $element;
let $ctrl;
let element;
@ -8,8 +8,8 @@ describe('Component vnCheck', () => {
}));
beforeEach(inject(($compile, $rootScope) => {
$element = $compile(`<vn-check></vn-check`)($rootScope);
$ctrl = $element.controller('vnCheck');
$element = $compile(`<vn-radio val="myVal"></vn-radio`)($rootScope);
$ctrl = $element.controller('vnRadio');
element = $element[0];
}));
@ -18,47 +18,10 @@ describe('Component vnCheck', () => {
});
describe('field() setter', () => {
it(`should set model value`, () => {
$ctrl.field = true;
expect($ctrl.field).toEqual(true);
});
it(`should uncheck value and change to true when clicked`, () => {
$ctrl.field = false;
it(`should change field value when clicked`, () => {
element.click();
expect($ctrl.field).toEqual(true);
});
it(`should check value and change to false when clicked`, () => {
$ctrl.field = true;
element.click();
expect($ctrl.field).toEqual(false);
});
it(`should uncheck value and change to null when clicked`, () => {
$ctrl.field = false;
$ctrl.tripleState = true;
element.click();
expect($ctrl.field).toEqual(null);
});
it(`should set value to null and change to true when clicked`, () => {
$ctrl.field = null;
$ctrl.tripleState = true;
element.click();
expect($ctrl.field).toEqual(true);
});
it(`should cast value to boolean when clicked`, () => {
$ctrl.field = 0;
element.click();
expect($ctrl.field).toEqual(true);
expect($ctrl.field).toEqual('myVal');
});
});
});

View File

@ -1,31 +1,14 @@
@import "variables";
vn-radio {
position: relative;
cursor: pointer;
display: inline-block;
outline: none;
&.disabled {
cursor: initial;
}
& > .radio {
position: relative;
box-sizing: border-box;
display: inline-block;
vertical-align: middle;
& > .btn {
border-radius: 50%;
width: 20px;
height: 20px;
border: 2px solid #666;
margin: 6px 0;
margin-right: .4em;
& > .mark {
transition: background 250ms;
}
}
&.checked > .radio {
&.checked > .btn {
border-color: $color-main;
& > .mark {
@ -38,25 +21,5 @@ vn-radio {
height: 10px;
background-color: $color-main;
}
& > .focus-mark {
background-color: rgba($color-main, .15);
}
}
& > .radio > .focus-mark {
position: absolute;
top: 50%;
left: 50%;
height: 38px;
width: 38px;
margin-top: -19px;
margin-left: -19px;
border-radius: 50%;
transform: scale3d(0, 0, 0);
transition: background 250ms;
transition: transform 250ms;
background-color: rgba(0, 0, 0, .1);
}
&:focus:not(.disabled) > .radio > .focus-mark {
transform: scale3d(1, 1, 1);
}
}

View File

@ -1,11 +1,2 @@
<div class="table">
<vn-empty-rows ng-if="$ctrl.isRefreshing">
<vn-spinner enable="$ctrl.isRefreshing"></vn-spinner>
</vn-empty-rows>
<vn-empty-rows ng-if="$ctrl.model && !$ctrl.isRefreshing && !$ctrl.model.data">
<span translate>Enter a new search</span>
</vn-empty-rows>
<vn-empty-rows ng-if="$ctrl.model && !$ctrl.isRefreshing && $ctrl.model.data.length == 0">
<span translate>No results</span>
</vn-empty-rows>
<div class="table" ng-transclude>
</div>

View File

@ -8,18 +8,6 @@ export default class Table {
this.field = null;
this.order = null;
this.autoLoad = true;
$transclude($scope.$parent, clone => {
angular.element($element[0].querySelector('.table')).append(clone);
});
}
get isRefreshing() {
return (this.model && this.model.isRefreshing);
}
get isPaging() {
return (this.model && this.model.isPaging);
}
setOrder(field, order) {
@ -37,7 +25,9 @@ export default class Table {
}
$onChanges() {
if (this.model && this.autoLoad)
// FIXME: The autoload property should be removed from vnTable
// because it's already implemented at vnModel
if (this.autoLoad && this.model && !this.model.data)
this.applyOrder();
}

View File

@ -51,14 +51,15 @@ vn-table {
}
& > * > vn-tr,
& > * > a.vn-tr {
display: table-row
display: table-row;
height: 3em;
}
vn-thead, vn-tbody, vn-tfoot {
& > * {
display: table-row;
& > vn-th {
font-weight: bold;
color: $color-font-light;
padding-top: 1em;
padding-bottom: .8em;
}
@ -97,10 +98,10 @@ vn-table {
}
}
& > :last-child {
padding-right: 1em;
padding-right: 1.4em;
}
& > :first-child {
padding-left: 1em;
padding-left: 1.4em;
}
}
& > a.vn-tr {

View File

@ -1,4 +1,4 @@
<div class="radio">
<div class="btn">
<div class="focus-mark"></div>
<div class="mark"></div>
</div>

View File

@ -0,0 +1,62 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import './style.scss';
/**
* Base component with common logic and styles for checkbox and radio button.
*
* @property {String} label Label to display along the component
* @property {any} field The value with which the element is linked
* @property {Boolean} checked Whether the checkbox is checked
* @property {Boolean} disabled Put component in disabled mode
*/
export default class Toggle extends Component {
constructor($element, $) {
super($element, $);
let element = this.element;
element.tabIndex = 0;
element.addEventListener('click', e => this.onClick(e));
element.addEventListener('keydown', e => this.onKeydown(e));
element.classList.add('vn-toggle');
}
set disabled(value) {
this.element.tabIndex = !value ? 0 : -1;
this.element.classList.toggle('disabled', Boolean(value));
this._disabled = value;
}
get disabled() {
return this._disabled;
}
onKeydown(event) {
if (event.code == 'Space')
this.onClick(event);
}
onClick(event) {
if (this.disabled || event.defaultPrevented)
return true;
event.preventDefault();
}
changed() {
this.$.$applyAsync();
this.element.dispatchEvent(new Event('change'));
this.emit('change', {value: this.field});
}
}
Toggle.$inject = ['$element', '$scope'];
ngModule.component('vnToggle', {
controller: Toggle,
bindings: {
label: '@?',
field: '=?',
disabled: '<?',
checked: '<?'
}
});

View File

@ -0,0 +1,50 @@
@import "variables";
.vn-toggle {
position: relative;
cursor: pointer;
display: inline-block;
outline: none;
&.disabled {
cursor: inherit;
}
& > span {
font-size: $input-font-size;
}
& > .btn {
position: relative;
box-sizing: border-box;
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
margin: 6px 0;
margin-right: .4em;
border: 2px solid #666;
}
&.checked > .btn {
border-color: $color-main;
& > .focus-mark {
background-color: rgba($color-main, .15);
}
}
& > .btn > .focus-mark {
position: absolute;
top: 50%;
left: 50%;
height: 38px;
width: 38px;
margin-top: -19px;
margin-left: -19px;
border-radius: 50%;
transform: scale3d(0, 0, 0);
transition: background 250ms;
transition: transform 250ms;
background-color: rgba(0, 0, 0, .1);
}
&:focus:not(.disabled) > .btn > .focus-mark {
transform: scale3d(1, 1, 1);
}
}

View File

@ -1,11 +1,5 @@
@import "effects";
vn-treeview {
& > .add-item {
@extend %clickable;
}
}
vn-treeview-childs {
display: block;
@ -13,9 +7,26 @@ vn-treeview-childs {
padding: 0;
margin: 0;
& > li {
li {
list-style: none;
& > .node {
@extend %clickable;
display: flex;
padding: 5px;
align-items: center;
}
& > div > .arrow {
min-width: 24px;
margin-right: 10px;
transition: transform 200ms;
}
& > div.expanded > .arrow {
transform: rotate(180deg);
}
ul {
padding-left: 2.2em;
}
@ -35,33 +46,8 @@ vn-treeview-childs {
.node:hover > .buttons {
display: block
}
& > ul > li > .node {
@extend %clickable;
display: flex;
padding: 5px;
align-items: center;
& > .arrow {
min-width: 24px;
margin-right: 10px;
transition: transform 200ms;
}
&.expanded > .arrow {
transform: rotate(180deg);
}
& > vn-check:not(.indeterminate) {
color: $color-main;
& > .check {
border-color: $color-main;
}
}
& > vn-check.checked {
color: $color-main;
}
}
}
vn-treeview-content {
flex-grow: 1;
flex-grow: 1
}

View File

@ -2,7 +2,6 @@ import './module-loader';
import './crud';
import './acl-service';
import './template';
import './interpolate';
import './copy';
import './equals';
import './modified';

View File

@ -1,189 +0,0 @@
import ngModule from '../module';
import {ng} from '../vendor';
function stringify(value) {
if (value === null) { // null || undefined
return '';
}
switch (typeof value) {
case 'string':
break;
case 'number':
value = String(value);
break;
default:
value = angular.toJson(value);
}
return value;
}
var $interpolateMinErr = ng.$interpolateMinErr = ng.$$minErr('$interpolate');
$interpolateMinErr.throwNoconcat = function(text) {
throw $interpolateMinErr('noconcat',
'Error while interpolating: {0}\nStrict Contextual Escaping disallows ' +
'interpolations that concatenate multiple expressions when a trusted value is ' +
'required. See http://docs.angularjs.org/api/ng.$sce', text);
};
$interpolateMinErr.interr = function(text, err) {
return $interpolateMinErr('interr', 'Can\'t interpolate: {0}\n{1}', text, err.toString());
};
function $get($parse, $exceptionHandler, $sce) {
let startSymbolLength = this._startSymbol.length;
let endSymbolLength = this._endSymbol.length;
let escapedStartRegexp = new RegExp(this._startSymbol.replace(/./g, escape), 'g');
let escapedEndRegexp = new RegExp(this._endSymbol.replace(/./g, escape), 'g');
let self = this;
function escape(ch) {
return '\\\\\\' + ch;
}
function unescapeText(text) {
return text.replace(escapedStartRegexp, self._startSymbol)
.replace(escapedEndRegexp, self._endSymbol);
}
// TODO: this is the same as the constantWatchDelegate in parse.js
function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
var unwatch = scope.$watch(function constantInterpolateWatch(scope) {
unwatch();
return constantInterp(scope);
}, listener, objectEquality);
return unwatch;
}
function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
// Provide a quick exit and simplified result function for text with no interpolation
if (!text.length || text.indexOf(self._startSymbol) === -1) {
var constantInterp;
if (!mustHaveExpression) {
var unescapedText = unescapeText(text);
constantInterp = valueFn(unescapedText);
constantInterp.exp = text;
constantInterp.expressions = [];
constantInterp.$$watchDelegate = constantWatchDelegate;
}
return constantInterp;
}
allOrNothing = Boolean(allOrNothing);
let startIndex;
let endIndex;
let index = 0;
let expressions = [];
let parseFns = [];
let textLength = text.length;
let exp;
let concat = [];
let expressionPositions = [];
while (index < textLength) {
if (((startIndex = text.indexOf(self._startSymbol, index)) !== -1) &&
((endIndex = text.indexOf(self._endSymbol, startIndex + startSymbolLength)) !== -1)) {
if (index !== startIndex)
concat.push(unescapeText(text.substring(index, startIndex)));
exp = text.substring(startIndex + startSymbolLength, endIndex);
expressions.push(exp);
parseFns.push($parse(exp, parseStringifyInterceptor));
index = endIndex + endSymbolLength;
expressionPositions.push(concat.length);
concat.push('');
} else {
// we did not find an interpolation, so we have to add the remainder to the separators array
if (index !== textLength)
concat.push(unescapeText(text.substring(index)));
break;
}
}
if (trustedContext && concat.length > 1) {
$interpolateMinErr.throwNoconcat(text);
}
var getValue = function(value) {
return trustedContext ?
$sce.getTrusted(trustedContext, value) :
$sce.valueOf(value);
};
if (!mustHaveExpression || expressions.length) {
var compute = function(values) {
for (var i = 0, ii = expressions.length; i < ii; i++) {
if (allOrNothing && isUndefined(values[i])) return;
concat[expressionPositions[i]] = values[i];
}
return concat.join('');
};
return angular.extend(function interpolationFn(context) {
var i = 0;
var ii = expressions.length;
var values = new Array(ii);
try {
for (; i < ii; i++) {
values[i] = parseFns[i](context);
}
return compute(values);
} catch (err) {
$exceptionHandler($interpolateMinErr.interr(text, err));
}
}, {
// all of these properties are undocumented for now
exp: text, // just for compatibility with regular watchers created via $watch
expressions: expressions
});
}
function parseStringifyInterceptor(value) {
try {
value = getValue(value);
return allOrNothing && !isDefined(value) ? value : stringify(value);
} catch (err) {
$exceptionHandler($interpolateMinErr.interr(text, err));
}
}
}
$interpolate.startSymbol = function() {
return startSymbol;
};
$interpolate.endSymbol = function() {
return endSymbol;
};
return $interpolate;
}
$get.$inject = ['$parse', '$exceptionHandler', '$sce'];
export class Interpolate {
constructor() {
this._startSymbol = '*[';
this._endSymbol = ']*';
}
set startSymbol(value) {
if (value) {
this._startSymbol = value;
return this;
}
return this._startSymbol;
}
set endSymbol(value) {
if (value) {
this._endSymbol = value;
return this;
}
return this._endSymbol;
}
}
Interpolate.prototype.$get = $get;
var interpolate = new Interpolate();
ngModule.provider('vnInterpolate', () => interpolate);

34
front/core/lib/section.js Normal file
View File

@ -0,0 +1,34 @@
import Component from './component';
/**
* Class with commonly injected services assigned as properties. It also has
* abbreviations for commonly used methods like tranlation.
*
* @property {Object} $translate Angular tranlation service
* @property {Object} $http Angular HTTP service
* @property {Object} $state Router state service
* @property {Object} $stateParams Router state parameters
*/
export default class Section extends Component {
constructor($element, $scope, $translate, $http, $state) {
super($element, $scope);
Object.assign(this, {
$translate,
$http,
$state,
$stateParams: $state.params
});
}
/**
* Translates an string.
*
* @param {String} string String to translate
* @param {Array} params Translate parameters
* @return {String} The translated string
*/
_(string, params) {
return this.$translate.instant(string, params, );
}
}
Section.$inject = ['$element', '$scope', '$translate', '$http', '$state'];

View File

@ -1,13 +1,6 @@
import ngModule from '../module';
export default class Template {
constructor(vnInterpolate) {
this.vnInterpolate = vnInterpolate;
}
get(template, $attrs, defaults) {
let scope = Object.assign({}, defaults, $attrs);
return template && this.vnInterpolate(template)(scope);
}
getNormalized(template, $attrs, defaults) {
this.normalizeInputAttrs($attrs);
return this.get(template, $attrs, defaults);
@ -43,6 +36,5 @@ export default class Template {
$attrs.focus = 'vn-focus';
}
}
Template.$inject = ['vnInterpolate'];
ngModule.service('vnTemplate', Template);

View File

@ -24,6 +24,9 @@ Value should be %s characters long: El valor debe ser de %s carácteres de longi
Value should have a length between %s and %s: El valor debe tener una longitud de entre %s y %s
Value should have at least %s characters: El valor debe tener al menos %s carácteres
Value should have at most %s characters: El valor debe tener un máximo de %s carácteres
Enter a new search: Introduce una nueva búsqueda
No results: Sin resultados
Ups! It seems there was an error: ¡Vaya! Parece que ha habido un error
General search: Busqueda general
January: Enero
February: Febrero

View File

@ -1,4 +1,3 @@
import './md-override.scss';
import './mdl-override.scss';
import './mdi-override.css';
import './zoom-image.scss';

View File

@ -1,11 +0,0 @@
html {
background-color: initial;
}
// Disable ng-repeat effects
.ng-enter,
.ng-leave {
transition: none !important;
}

View File

@ -7,10 +7,6 @@ import 'angular-translate-loader-partial';
import '@uirouter/angularjs';
import 'mg-crud';
import 'oclazyload';
/*
import 'angular-material';
import 'angular-material/modules/scss/angular-material.scss';
*/
import 'angular-moment';
export const ngDeps = [
@ -18,7 +14,6 @@ export const ngDeps = [
'ui.router',
'mgCrud',
'oc.lazyLoad',
// 'ngMaterial',
'angularMoment'
];

View File

@ -2,7 +2,9 @@ import ngModule from '../../module';
import './style.scss';
export default class LeftMenu {
constructor($state, $transitions, aclService) {
constructor($state, $transitions, aclService, $timeout, $element) {
this.$element = $element;
this.$timeout = $timeout;
this.$state = $state;
this.deregisterCallback = $transitions.onSuccess({},
() => this.activateItem());
@ -89,13 +91,19 @@ export default class LeftMenu {
setActive(item) {
if (item.state) return;
item.active = !item.active;
this.$timeout(() => {
let element = this.$element[0].querySelector('a[class="expanded"]');
if (element)
element.scrollIntoView();
});
}
$onDestroy() {
this.deregisterCallback();
}
}
LeftMenu.$inject = ['$state', '$transitions', 'aclService'];
LeftMenu.$inject = ['$state', '$transitions', 'aclService', '$timeout', '$element'];
ngModule.component('vnLeftMenu', {
template: require('./left-menu.html'),

View File

@ -2,16 +2,18 @@ import './left-menu.js';
describe('Component vnLeftMenu', () => {
let controller;
let $element;
beforeEach(angular.mock.module('salix', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($componentController, $state, $window) => {
$element = angular.element('<div></div>');
$state.current.name = 'client.card.summary';
$state.current.data = {moduleIndex: 0};
$window.routes = [{menu: []}];
controller = $componentController('vnLeftMenu', {$state, $window});
controller = $componentController('vnLeftMenu', {$state, $window, $element});
controller.items = [
{description: 'Client', state: 'client', icon: null, childs: []},
{description: 'Client', state: 'client.card', icon: null, childs: []},

View File

@ -14,8 +14,6 @@ Push on applications menu: Para abrir un módulo pulsa en el menú de aplicacion
Return to module index: Volver a la página principal del módulo
What is new: Novedades de la versión
Settings: Ajustes
Enter a new search: Introduce una nueva búsqueda
No results: Sin resultados
# Actions

View File

@ -15,3 +15,4 @@ import './descriptor.scss';
import './list.scss';
import './modal-form.scss';
import './photo-list.scss';
import './width.scss';

View File

@ -1,7 +1,7 @@
@import "./effects";
.vn-list {
max-width: 36em;
max-width: $width-sm;
margin: 0 auto;
a.vn-list-item {

View File

@ -47,7 +47,6 @@ vn-bg-title {
justify-content: center;
align-items: center;
padding: 18px;
margin-bottom: 10px;
max-width: 12em;
}
.form {
@ -99,11 +98,6 @@ html [pointer], .pointer{
html [noDrop], .noDrop{
cursor: no-drop;
}
html [compact], .compact{
max-width: $width-compact;
margin-left: auto;
margin-right: auto;
}
button {
@extend %clickable;
}
@ -147,6 +141,12 @@ fieldset[disabled] .mdl-textfield .mdl-textfield__label,
font-size: 0.7em
}
}
[compact], .compact {
margin-left: auto;
margin-right: auto;
max-width: $width-md;
}
.vn-grid {
border-collapse: collapse;
width: 100%;

View File

@ -17,6 +17,8 @@
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),
0 3px 1px -2px rgba(0,0,0,.2),
0 1px 5px 0 rgba(0,0,0,.12);
background: no-repeat center center fixed;
background-size: cover !important;
overflow: hidden;
cursor: zoom-in;
height: 100%;

View File

@ -1,3 +1,4 @@
@import "variables";
/* Desktop - Laptop 1360x768 */
@media (max-resolution: 119dpi) and (min-device-width: 1340px) and (max-device-width: 1899px)
@ -46,3 +47,9 @@
{
body { font-size: 11pt; }
}
.vn-hide-narrow {
@media (max-width: $mobile-width) {
display: none;
}
}

View File

@ -2,12 +2,15 @@
$menu-width: 16em;
$topbar-height: 4em;
$mobile-width: 800px;
$input-font-size: 16px;
// Width
$width-small: 36em;
$width-compact: 60em;
$width-large: 80em;
$width-xs: 25em;
$width-sm: 34em;
$width-md: 50em;
$width-lg: 80em;
$width-xl: 100em;
// Padding
@ -29,7 +32,8 @@ $margin-huge: 100px;
$color-header: #3d3d3d;
$color-bg: #e5e5e5;
$color-bg-dark: #3d3d3d;
$color-font: #222222;
$color-font: #222;
$color-font-light: #555;
$color-font-secondary: #9b9b9b;
$color-font-dark: white;
$color-font-bg: rgba(0, 0, 0, .7);
@ -46,8 +50,9 @@ $color-alert: #f42121;
$color-spacer: rgba(0, 0, 0, .3);
$color-spacer-light: rgba(0, 0, 0, .12);
$color-input-underline: rgba(0, 0, 0, .12);
$color-input-underline-hover: rgba(0, 0, 0, .6);
$color-shadow: rgba(0, 0, 0, .2);
$color-hightlight: rgba(0, 0, 0, .15);
$color-hightlight: rgba(0, 0, 0, .05);
$color-hover-cd: rgba(0, 0, 0, .1);
$color-hover-dc: .7;
$color-disabled: .6;
@ -70,6 +75,7 @@ $color-header: #3d3d3d;
$color-bg: #222;
$color-bg-dark: #222;
$color-font: white;
$color-font-light: #aaa;
$color-font-secondary: #777;
$color-font-dark: white;
$color-font-bg: rgba(0, 0, 0, .8);
@ -82,6 +88,7 @@ $color-secondary: #ccc;
$color-success: #a3d131;
$color-notice: #32b1ce;
$color-alert: #f42121;
$color-spacer: rgba(255, 255, 255, .3);
$color-spacer-light: rgba(255, 255, 255, .12);
$color-input-underline: rgba(255, 255, 255, .12);
@ -104,5 +111,5 @@ $color-alert-light: darken($color-alert, 35%);
// Border
$border-thin: .1em solid $color-spacer;
$border-thin-light: .1em solid $color-spacer-light;
$border-thin: .05em solid $color-spacer;
$border-thin-light: .05em solid $color-spacer-light;

View File

@ -0,0 +1,26 @@
@import "./variables";
%margin-auto {
margin-left: auto;
margin-right: auto;
}
.vn-w-xs {
@extend %margin-auto;
max-width: $width-xs;
}
.vn-w-sm {
@extend %margin-auto;
max-width: $width-sm;
}
.vn-w-md {
@extend %margin-auto;
max-width: $width-md;
}
.vn-w-lg {
@extend %margin-auto;
max-width: $width-lg;
}
.vn-w-xl {
@extend %margin-auto;
max-width: $width-xl;
}

View File

@ -5,7 +5,10 @@
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
<form
name="form"
ng-submit="$ctrl.onSubmit()"
class="vn-w-md">
<vn-card pad-large>
<vn-horizontal>
<vn-textfield
@ -73,7 +76,14 @@
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit label="Save" vn-acl="deliveryBoss"></vn-submit>
<vn-button label="Undo changes" ng-if="watcher.dataChanged()" ng-click="watcher.loadOriginalData()"></vn-button>
<vn-submit
label="Save"
vn-acl="deliveryBoss">
</vn-submit>
<vn-button
label="Undo changes"
ng-if="watcher.dataChanged()"
ng-click="watcher.loadOriginalData()">
</vn-button>
</vn-button-bar>
</form>

View File

@ -3,6 +3,7 @@
skip="2"
has-events="$ctrl.hasEvents($day)"
get-class="$ctrl.getClass($day)"
on-selection="$ctrl.onSelection($days, $type, $weekday)"
on-move-next="ndMonth.moveNext(2)"
on-move-previous="ndMonth.movePrevious(2)"
vn-acl="deliveryBoss"
@ -13,6 +14,7 @@
skip="2"
has-events="$ctrl.hasEvents($day)"
get-class="$ctrl.getClass($day)"
on-selection="$ctrl.onSelection($days, $type, $weekday)"
default-date="$ctrl.ndMonthDate"
vn-acl="deliveryBoss"
display-controls="false"

View File

@ -1,12 +1,10 @@
import ngModule from '../module';
import Section from 'core/lib/section';
import './style.scss';
class Controller {
constructor($, $stateParams) {
Object.assign(this, {
$,
$stateParams
});
class Controller extends Section {
constructor($el, $, $t, $http, $state) {
super($el, $, $t, $http, $state);
this.excls = {};
this.resetEvents();
@ -14,6 +12,10 @@ class Controller {
this.ndMonthDate.setMonth(this.ndMonthDate.getMonth() + 1);
}
onSelection($days, $type, $weekday) {
this.emit('selection', {$days, $type, $weekday});
}
resetEvents() {
this.wdays = [];
this.days = {};
@ -96,8 +98,6 @@ class Controller {
}
}
Controller.$inject = ['$scope', '$stateParams'];
ngModule.component('vnZoneCalendar', {
template: require('./index.html'),
controller: Controller,

View File

@ -2,4 +2,4 @@
<vn-zone-descriptor zone="$ctrl.zone"></vn-zone-descriptor>
<vn-left-menu></vn-left-menu>
</vn-side-menu>
<div class="content-block" ui-view></div>
<div ui-view></div>

View File

@ -1,6 +1,10 @@
<div class="main-with-right-menu">
<div class="vn-list" style="max-width: 30em;">
<vn-card ng-if="data.length">
<vn-data-viewer
data="data"
is-loading="!data"
class="vn-w-sm">
<vn-card>
<div class="vn-list">
<a
ng-repeat="row in data"
translate-attr="{title: 'Edit'}"
@ -52,35 +56,23 @@
</vn-horizontal>
</vn-horizontal>
</a>
</div>
</vn-card>
</div>
<vn-bg-title ng-if="!data">
<vn-spinner enable="true"></vn-spinner>
</vn-bg-title>
<vn-bg-title ng-if="data.length == 0" translate>
No records found
</vn-bg-title>
</vn-data-viewer>
</div>
<vn-side-menu side="right">
<vn-zone-calendar
events="data"
exclusions="exclusions">
exclusions="exclusions"
on-selection="$ctrl.onCreate($days, $type, $weekday)">
</vn-zone-calendar>
</vn-side-menu>
<vn-float-button
icon="add"
translate-attr="{title: 'Add'}"
vn-bind="+"
ng-click="$ctrl.onCreate()"
fixed-bottom-right
style="z-index: 10;">
</vn-float-button>
<vn-dialog
vn-id="dialog"
on-response="$ctrl.onSave(response)">
<tpl-body>
<vn-vertical>
<vn-vertical>
<vn-vertical pad-medium-bottom>
<vn-radio
field="$ctrl.eventType"
label="One day"
@ -88,13 +80,13 @@
</vn-radio>
<vn-radio
field="$ctrl.eventType"
label="Range of dates"
val="range">
label="Indefinitely"
val="indefinitely">
</vn-radio>
<vn-radio
field="$ctrl.eventType"
label="Indefinitely"
val="indefinitely">
label="Range of dates"
val="range">
</vn-radio>
</vn-vertical>
<div

View File

@ -1,13 +1,10 @@
import ngModule from '../module';
import Section from 'core/lib/section';
import './style.scss';
class Controller {
constructor($, _, $http, $stateParams) {
Object.assign(this, {
$,
_,
$http
});
class Controller extends Section {
constructor($el, $, $t, $http, $state) {
super($el, $, $t, $http, $state);
this.wdays = [
{
@ -36,15 +33,15 @@ class Controller {
this.abrWdays = {};
for (let wday of this.wdays) {
let locale = _.instant(wday.name);
let locale = this._(wday.name);
this.abrWdays[wday.code] = locale.substr(0, 3);
wday.abr = locale.substr(0, 1);
}
this.$http.get(`/api/Zones/${$stateParams.id}/exclusions`)
this.$http.get(`/api/Zones/${this.$stateParams.id}/exclusions`)
.then(res => this.$.exclusions = res.data);
this.path = `/api/Zones/${$stateParams.id}/events`;
this.path = `/api/Zones/${this.$stateParams.id}/events`;
this.refresh();
}
@ -62,7 +59,7 @@ class Controller {
return abrWdays.length < 7
? abrWdays.join(', ')
: this._.instant('Everyday');
: this._('Everyday');
}
onEdit(row, event) {
@ -89,10 +86,19 @@ class Controller {
this.$.dialog.show();
}
onCreate() {
onCreate($day, $type, $weekday) {
this.isNew = true;
this.eventType = 'day';
this.selected = {};
this.eventType = $type == 'day' ? 'day' : 'indefinitely';
if ($type == 'weekday') {
let wdays = [];
let index = $weekday - 1;
if (index < 0) index = 7 - index;
wdays[this.wdays[index].code] = true;
this.selected = {wdays};
} else
this.selected = {from: $day[0]};
this.$.dialog.show();
}
@ -153,7 +159,6 @@ class Controller {
});
}
}
Controller.$inject = ['$scope', '$translate', '$http', '$stateParams'];
ngModule.component('vnZoneEvents', {
template: require('./index.html'),

View File

@ -1,50 +1,33 @@
<vn-card
ng-if="data.length"
style="max-width: 25em; margin: 0 auto;">
<vn-table>
<vn-tbody>
<div class="main-with-right-menu">
<vn-data-viewer
data="data"
is-loading="!data"
class="vn-w-xs">
<vn-card>
<vn-table>
<vn-tbody>
<vn-tr ng-repeat="row in data | orderBy:'day'">
<vn-td>{{::row.day | dateTime:'dd/MM/yyyy'}}</vn-td>
<vn-td style="width: 1px; text-align: center">
<vn-icon-button
icon="delete"
translate-attr="{title: 'Delete'}"
ng-click="$ctrl.onDelete($index)">
ng-click="$ctrl.onDelete(row.id)">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
<vn-bg-title ng-if="!data">
<vn-spinner enable="true"></vn-spinner>
</vn-bg-title>
<vn-bg-title ng-if="data.length == 0" translate>
No records found
</vn-bg-title>
<vn-float-button
icon="add"
translate-attr="{title: 'Add'}"
vn-bind="+"
ng-click="$ctrl.onCreate()"
fixed-bottom-right>
</vn-float-button>
<vn-dialog
vn-id="dialog"
on-response="$ctrl.onSave(response)">
<tpl-body>
<vn-vertical>
<vn-date-picker
label="Day"
model="$ctrl.selected.day">
</vn-date-picker>
</vn-vertical>
</tpl-body>
<tpl-buttons>
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
<button response="ACCEPT" translate>Save</button>
</tpl-buttons>
</vn-dialog>
</vn-tbody>
</vn-table>
</vn-card>
</vn-data-viewer>
</div>
<vn-side-menu side="right">
<vn-zone-calendar
events="events"
exclusions="data"
on-selection="$ctrl.onCreate($days)">
</vn-zone-calendar>
</vn-side-menu>
<vn-confirm
vn-id="confirm"
message="This item will be deleted"

View File

@ -1,13 +1,14 @@
import ngModule from '../module';
import Section from 'core/lib/section';
class Controller {
constructor($, $http, $stateParams) {
Object.assign(this, {
$,
$http
});
class Controller extends Section {
constructor($el, $, $t, $http, $state) {
super($el, $, $t, $http, $state);
this.path = `/api/Zones/${$stateParams.id}/exclusions`;
this.$http.get(`/api/Zones/${this.$stateParams.id}/events`)
.then(res => this.$.events = res.data);
this.path = `/api/Zones/${this.$stateParams.id}/exclusions`;
this.refresh();
}
@ -16,43 +17,26 @@ class Controller {
.then(res => this.$.data = res.data);
}
onCreate() {
this.isNew = true;
this.selected = {};
this.$.dialog.show();
onCreate($days) {
this.$http.post(this.path, {day: $days[0]})
.then(() => this.refresh());
}
onSave(response) {
if (response != 'ACCEPT') return;
this.$http.post(this.path, this.selected)
.then(() => {
this.selected = null;
this.isNew = null;
this.$.dialog.hide();
this.refresh();
});
return false;
}
onDelete(index) {
onDelete(id) {
this.$.confirm.show();
this.deleteIndex = index;
this.deleteId = id;
}
delete(response) {
if (response != 'ACCEPT') return;
let id = this.$.data[this.deleteIndex].id;
if (!id) return;
this.$http.delete(`${this.path}/${id}`)
if (!this.deleteId) return;
this.$http.delete(`${this.path}/${this.deleteId}`)
.then(() => {
this.$.data.splice(this.deleteIndex, 1);
this.deleteIndex = null;
this.refresh();
this.deleteId = null;
});
}
}
Controller.$inject = ['$scope', '$http', '$stateParams'];
ngModule.component('vnZoneExclusions', {
template: require('./index.html'),

View File

@ -4,21 +4,24 @@
filter="::$ctrl.filter"
limit="20"
data="zones"
auto-load="false">
auto-load="true">
</vn-crud-model>
<div class="content-block">
<div class="vn-list">
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-zone-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)"
info="Search zone by id or name"
vn-focus>
</vn-searchbar>
</vn-card>
</div>
<vn-card margin-medium-v margin-huge-bottom compact>
<div>
<vn-card class="vn-w-sm pad-medium-h">
<vn-searchbar
panel="vn-zone-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)"
info="Search zone by id or name"
vn-focus>
</vn-searchbar>
</vn-card>
<vn-data-viewer
model="model"
class="vn-w-md"
margin-medium-top
margin-huge-bottom>
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
@ -59,8 +62,8 @@
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
<vn-pagination model="model"></vn-pagination>
</vn-card>
</vn-data-viewer>
</div>
<vn-dialog
vn-id="summary"

View File

@ -3,7 +3,7 @@
url="/api/Zones/{{$ctrl.$stateParams.id}}/getLeaves"
filter="::$ctrl.filter">
</vn-crud-model>
<div compact>
<div class="vn-w-md">
<vn-card pad-large-h>
<vn-searchbar auto-load="false"
on-search="$ctrl.onSearch($params)"

View File

@ -1,12 +1,8 @@
import ngModule from '../module';
import Section from 'core/lib/section';
import './style.scss';
class Controller {
constructor($, $http, $stateParams) {
this.$ = $;
this.$http = $http;
this.$stateParams = $stateParams;
}
class Controller extends Section {
onSearch(params) {
this.$.model.applyFilter({}, params).then(() => {
const data = this.$.model.data;
@ -49,8 +45,6 @@ class Controller {
}
}
Controller.$inject = ['$scope', '$http', '$stateParams'];
ngModule.component('vnZoneLocation', {
template: require('./index.html'),
controller: Controller,

View File

@ -0,0 +1,14 @@
@import "variables";
vn-treeview-content {
& > vn-check:not(.indeterminate) {
color: $color-main;
& > .btn {
border-color: $color-main;
}
}
& > vn-check.checked {
color: $color-main;
}
}

View File

@ -1,6 +1,8 @@
<vn-card
ng-if="data.length"
style="max-width: 25em; margin: 0 auto;">
<vn-data-viewer
data="data"
is-loading="!data"
class="vn-w-xs">
<vn-card>
<vn-table>
<vn-tbody>
<vn-tr ng-repeat="row in data | orderBy:'warehouse.name'">
@ -15,13 +17,8 @@
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
<vn-bg-title ng-if="!data">
<vn-spinner enable="true"></vn-spinner>
</vn-bg-title>
<vn-bg-title ng-if="data.length == 0" translate>
No records found
</vn-bg-title>
</vn-card>
</vn-data-viewer>
<vn-float-button
icon="add"
translate-attr="{title: 'Add'}"

View File

@ -1,13 +1,11 @@
import ngModule from '../module';
import Section from 'core/lib/section';
class Controller {
constructor($, _, $http, $stateParams) {
Object.assign(this, {
$,
$http
});
class Controller extends Section {
constructor($el, $, $t, $http, $state) {
super($el, $, $t, $http, $state);
this.path = `/api/Zones/${$stateParams.id}/warehouses`;
this.path = `/api/Zones/${this.$stateParams.id}/warehouses`;
this.refresh();
}
@ -52,7 +50,6 @@ class Controller {
});
}
}
Controller.$inject = ['$scope', '$translate', '$http', '$stateParams'];
ngModule.component('vnZoneWarehouses', {
template: require('./index.html'),

View File

@ -4,7 +4,13 @@
limit="20"
data="$ctrl.photos">
</vn-crud-model>
<vn-horizontal class="photo-list" vn-droppable="true" on-drop="$ctrl.onDrop(event)">
<section class="drop-zone" vn-droppable="true" on-drop="$ctrl.onDrop(event)">
<section><vn-icon icon="add_circle"></vn-icon></section>
<section translate>Drag & Drop files here...</section>
</section>
<vn-horizontal class="photo-list">
<section class="photo" ng-repeat="photo in $ctrl.photos">
<section class="image mdl-shadow--2dp" on-error-src
ng-style="{'background': 'url(/api/dms/' + photo.dmsFk + '/downloadFile?access_token=' + $ctrl.accessToken + ')'}"

View File

@ -1,10 +1,22 @@
@import "./variables";
vn-claim-dms-index {
.photo-list {
.drop-zone {
border: 2px dashed $color-font-secondary;
color: $color-font-secondary;
box-sizing: border-box;
padding: 2em $pad-medium;
border-radius: 0.5em;
text-align: center;
font-size: 1.4em;
vn-icon {
font-size: 3em
}
}
.photo-list {
padding: $pad-medium;
min-height: 100%;
@ -13,9 +25,4 @@ vn-claim-dms-index {
height: 18em;
}
}
vn-empty-rows {
color: $color-font-secondary;
font-size: 2em
}
}

View File

@ -1,4 +1,4 @@
Are you sure you want to continue?: ¿Seguro que quieres continuar?
Drag & Drop files here...: Arrasta y suelta archivos aquí...
Drag & Drop files here...: Arrastra y suelta archivos aquí...
Photo deleted: Foto eliminada
Photo uploaded!: Foto subida!

View File

@ -3,20 +3,23 @@
url="/claim/api/Claims/filter"
limit="20"
data="claims"
order="claimStateFk ASC, created DESC">
order="claimStateFk ASC, created DESC"
auto-load="true">
</vn-crud-model>
<div class="content-block">
<div class="vn-list">
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-claim-search-panel"
on-search="$ctrl.onSearch($params)"
info="Search claim by id or client name"
vn-focus>
</vn-searchbar>
</vn-card>
</div>
<vn-card margin-medium-v compact>
<vn-card pad-medium-h class="vn-w-sm">
<vn-searchbar
panel="vn-claim-search-panel"
on-search="$ctrl.onSearch($params)"
info="Search claim by id or client name"
vn-focus>
</vn-searchbar>
</vn-card>
<vn-data-viewer
model="model"
class="vn-w-md"
margin-medium-v>
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
@ -62,10 +65,12 @@
</a>
</vn-tbody>
</vn-table>
</vn-card>
<vn-pagination model="model"></vn-pagination>
</vn-card>
</vn-data-viewer>
</div>
<vn-client-descriptor-popover vn-id="clientDescriptor"></vn-client-descriptor-popover>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
worker-fk="$ctrl.selectedWorker">

View File

@ -168,7 +168,7 @@ module.exports = Self => {
}
function isAlpha(value) {
const regexp = new RegExp(/^[ñça-zA-Z0-9\s]*$/);
const regexp = new RegExp(/^[ñça-zA-Z0-9\s]*$/i);
return regexp.test(value);
}

View File

@ -6,75 +6,70 @@
data="$ctrl.addresses"
auto-load="true">
</vn-crud-model>
<div compact>
<vn-card pad-large>
<div
ng-repeat="address in $ctrl.addresses"
class="address">
<a
ui-sref="client.card.address.edit({addressId: {{::address.id}}})"
class="pad-small border-solid"
ng-class="{
'item-hightlight': $ctrl.isDefaultAddress(address),
'item-disabled': !address.isActive && !$ctrl.isDefaultAddress(address)
}"
translate-attr="{title: 'Edit address'}"
border-radius>
<vn-none
pad-small-right
ng-click="$ctrl.onStarClick($event)">
<vn-icon-button
icon="star"
ng-if="$ctrl.isDefaultAddress(address)">
</vn-icon-button>
<vn-icon-button
ng-if="!address.isActive && !$ctrl.isDefaultAddress(address)"
icon="star_border"
vn-tooltip="Active first to set as default">
</vn-icon-button>
<vn-icon-button
ng-if="address.isActive && !$ctrl.isDefaultAddress(address)"
icon="star_border"
vn-tooltip="Set as default"
ng-click="$ctrl.setDefault(address)">
</vn-icon-button>
</vn-none>
<vn-one
style="overflow: hidden; min-width: 14em;">
<div class="ellipsize"><b>{{::address.nickname}}</b></div>
<div class="ellipsize" name="street">{{::address.street}}</div>
<div class="ellipsize">{{::address.city}}, {{::address.province.name}}</div>
<div class="ellipsize">
{{::address.phone}}<span ng-if="::address.mobile">, </span>
{{::address.mobile}}
</div>
<vn-check
vn-one label="Is equalizated"
field="address.isEqualizated"
disabled="true">
</vn-check>
<vn-data-viewer
model="model"
class="vn-w-md">
<vn-card pad-medium>
<div
ng-repeat="address in $ctrl.addresses"
class="address">
<a
ui-sref="client.card.address.edit({addressId: {{::address.id}}})"
class="pad-small border-solid"
ng-class="{'item-disabled': !address.isActive}"
translate-attr="{title: 'Edit address'}"
border-radius>
<vn-none
pad-small-right
ng-click="$ctrl.onStarClick($event)">
<vn-icon-button
ng-if="$ctrl.isDefaultAddress(address)"
icon="star"
translate-attr="{title: 'Default address'}">
</vn-icon-button>
<vn-icon-button
ng-if="!$ctrl.isDefaultAddress(address)"
icon="star_border"
ng-click="$ctrl.setDefault(address)"
translate-attr="{title: 'Set as default'}">
</vn-icon-button>
</vn-none>
<vn-one
style="overflow: hidden; min-width: 14em;">
<div class="ellipsize"><b>{{::address.nickname}}</b></div>
<div class="ellipsize" name="street">{{::address.street}}</div>
<div class="ellipsize">{{::address.city}}, {{::address.province.name}}</div>
<div class="ellipsize">
{{::address.phone}}<span ng-if="::address.mobile">, </span>
{{::address.mobile}}
</div>
<vn-check
vn-one label="Is equalizated"
field="address.isEqualizated"
disabled="true">
</vn-check>
</vn-one>
<vn-vertical
vn-one
ng-if="address.observations.length"
border-solid-left
pad-medium-h
class="vn-hide-narrow"
style="height: 6em; overflow: auto;">
<vn-one ng-repeat="observation in address.observations track by $index" ng-class="{'pad-small-top': $index}">
<b>{{::observation.observationType.description}}:</b>
<span>{{::observation.description}}</span>
</vn-one>
<vn-vertical
vn-one
ng-if="address.observations.length"
border-solid-left
pad-medium-h
style="height: 6em; overflow: auto;">
<vn-one ng-repeat="observation in address.observations track by $index" ng-class="{'pad-small-top': $index}">
<b>{{::observation.observationType.description}}:</b>
<span>{{::observation.description}}</span>
</vn-one>
</vn-vertical>
</a>
</div>
</vn-card>
<vn-float-button
vn-bind="+"
fixed-bottom-right
vn-tooltip="New address"
ui-sref="client.card.address.create"
icon="add"
label="Add">
</vn-float-button>
<vn-pagination model="model"></vn-pagination>
</div>
</vn-vertical>
</a>
</div>
</vn-card>
</vn-data-viewer>
<vn-float-button
vn-bind="+"
fixed-bottom-right
vn-tooltip="New address"
ui-sref="client.card.address.create"
icon="add"
label="Add">
</vn-float-button>

View File

@ -56,8 +56,7 @@ class Controller {
}
isDefaultAddress(address) {
if (this.client)
return this.client.defaultAddressFk === address.id;
return this.client && this.client.defaultAddressFk === address.id;
}
/**

View File

@ -3,7 +3,8 @@
url="/client/api/receipts/filter"
params="$ctrl.params"
limit="20"
data="$ctrl.balances">
data="$ctrl.balances"
auto-load="true">
</vn-crud-model>
<vn-crud-model
vn-id="riskModel"
@ -11,9 +12,10 @@
filter="$ctrl.filter"
data="$ctrl.clientRisks">
</vn-crud-model>
<vn-vertical>
<vn-card pad-large>
<vn-horizontal>
<div class="vn-w-lg">
<vn-card class="pad-medium margin-medium-bottom">
<vn-horizontal
style="align-items: center;">
<vn-one></vn-one>
<vn-one>
<vn-autocomplete
@ -23,7 +25,7 @@
url="/client/api/Companies"
show-field="code"
value-field="id"
label="Select company">
label="Company">
</vn-autocomplete>
</vn-one>
<vn-one>
@ -38,68 +40,68 @@
</div>
</vn-one>
</vn-horizontal>
<vn-vertical>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th default-order>Date</vn-th>
<vn-th>Creation date</vn-th>
<vn-th>Employee</vn-th>
<vn-th>Reference</vn-th>
<vn-th number>Bank</vn-th>
<vn-th number>Debit</vn-th>
<vn-th number>Havings</vn-th>
<vn-th number>Balance</vn-th>
<vn-th center>Conciliated</vn-th>
<vn-th></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="balance in $ctrl.balances">
<vn-td>{{::balance.payed | dateTime:'dd/MM/yyyy'}}</vn-td>
<vn-td>{{::balance.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
<vn-td>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, balance.workerFk)">
{{::balance.userNickname}}
</span>
</vn-td>
<vn-td>
<span
ng-class="{'link': balance.isInvoice}"
ng-click="$ctrl.showInvoiceOutDescriptor($event, balance)"
ng-show="balance.ref">{{balance.isInvoice ? 'BILL' : balance.ref | translate: {ref: balance.ref} }}
</span>
</vn-td>
<vn-td number>{{::balance.bankFk}}</vn-td>
<vn-td number>{{::balance.debit | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::balance.credit | currency: 'EUR':2}}</vn-td>
<vn-td number>{{balance.balance | currency: 'EUR':2}}</vn-td>
<vn-td center>
<vn-check
field="balance.isConciliate"
disabled="true">
</vn-check>
</vn-td>
<vn-td center>
<a ng-show="balance.hasPdf"
target="_blank"
href="api/InvoiceOuts/{{::balance.id}}/download?access_token={{::$ctrl.accessToken}}">
<vn-icon-button
icon="cloud_download"
title="{{'Download PDF' | translate}}">
</vn-icon-button>
</a>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
</vn-card>
</vn-vertical>
<vn-data-viewer model="model">
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th>Date</vn-th>
<vn-th>Creation date</vn-th>
<vn-th>Employee</vn-th>
<vn-th>Reference</vn-th>
<vn-th number>Bank</vn-th>
<vn-th number>Debit</vn-th>
<vn-th number>Havings</vn-th>
<vn-th number>Balance</vn-th>
<vn-th center>Conciliated</vn-th>
<vn-th></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="balance in $ctrl.balances">
<vn-td>{{::balance.payed | dateTime:'dd/MM/yyyy'}}</vn-td>
<vn-td>{{::balance.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
<vn-td>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, balance.workerFk)">
{{::balance.userNickname}}
</span>
</vn-td>
<vn-td>
<span
ng-class="{'link': balance.isInvoice}"
ng-click="$ctrl.showInvoiceOutDescriptor($event, balance)"
ng-show="balance.ref">{{balance.isInvoice ? 'BILL' : balance.ref | translate: {ref: balance.ref} }}
</span>
</vn-td>
<vn-td number>{{::balance.bankFk}}</vn-td>
<vn-td number>{{::balance.debit | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::balance.credit | currency: 'EUR':2}}</vn-td>
<vn-td number>{{balance.balance | currency: 'EUR':2}}</vn-td>
<vn-td center>
<vn-check
field="balance.isConciliate"
disabled="true">
</vn-check>
</vn-td>
<vn-td center>
<a ng-show="balance.hasPdf"
target="_blank"
href="api/InvoiceOuts/{{::balance.id}}/download?access_token={{::$ctrl.accessToken}}">
<vn-icon-button
icon="cloud_download"
title="{{'Download PDF' | translate}}">
</vn-icon-button>
</a>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-data-viewer>
</div>
<vn-float-button
vn-acl="administrative"
vn-acl-action="remove"
@ -109,15 +111,13 @@
fixed-bottom-right
ng-click="$ctrl.openCreateDialog()">
</vn-float-button>
<vn-client-balance-create vn-id="balanceCreateDialog">
<vn-client-balance-create
vn-id="balanceCreateDialog">
</vn-client-balance-create>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
worker-fk="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>
<vn-invoice-out-descriptor-popover
vn-id="invoiceOutDescriptor"
invoice-out-id="$ctrl.selectedInvoiceOut">

View File

@ -1,67 +1,64 @@
<div compact>
<vn-card pad-large>
<vn-horizontal
ng-repeat="classification in $ctrl.classifications track by classification.id"
class="pad-medium-top"
style="align-items: center;">
<vn-one
border-radius
class="pad-small border-solid"
ng-class="{'item-hightlight': !classification.finished,'item-disabled': classification.finished}">
<vn-horizontal style="align-items: center;">
<vn-none pad-medium-h>
<vn-icon-button
ng-if="!classification.finished"
icon="lock"
vn-tooltip="Close contract"
ng-click="$ctrl.closeContract(classification)">
</vn-icon-button>
</vn-none>
<vn-one border-solid-right>
<div><vn-label translate>Since</vn-label> {{::classification.started | dateTime:'dd/MM/yyyy'}}</div>
<div><vn-label translate>To</vn-label> {{classification.finished | dateTime:'dd/MM/yyyy'}}</div>
</vn-one>
<vn-vertical vn-one pad-medium-h>
<vn-horizontal ng-repeat="insurance in classification.insurances track by insurance.id">
<vn-one>
<vn-label-value label="Credit"
value="{{::insurance.credit}}">
</vn-label-value>
</vn-one>
<vn-one>
<vn-label-value label="Grade"
value="{{::insurance.grade}}">
</vn-label-value>
</vn-one>
<vn-one>
<vn-label-value label="Date"
value="{{::insurance.created | dateTime:'dd/MM/yyyy' }}">
</vn-label-value>
</vn-one>
</vn-horizontal>
</vn-vertical>
<a vn-auto ui-sref="client.card.creditInsurance.insurance.index({classificationId: {{classification.id}}})">
<vn-icon-button icon="desktop_windows" vn-tooltip="View credits"></vn-icon-button>
</a>
</vn-horizontal>
</vn-one>
</vn-horizontal>
<vn-horizontal ng-if="model.data.length == 0">
<vn-one ad-small translate>
No results
</vn-one>
</vn-horizontal>
<vn-data-viewer
data="$ctrl.classifications"
class="vn-w-md">
<vn-card pad-medium>
<vn-horizontal
ng-repeat="classification in $ctrl.classifications track by classification.id"
class="pad-medium-bottom insurance"
style="align-items: center;">
<vn-one
border-radius
class="pad-small border-solid"
ng-class="{'item-hightlight': !classification.finished,'item-disabled': classification.finished}">
<vn-horizontal style="align-items: center;">
<vn-none pad-medium-h>
<vn-icon-button
ng-if="!classification.finished"
icon="lock"
vn-tooltip="Close contract"
ng-click="$ctrl.closeContract(classification)">
</vn-icon-button>
</vn-none>
<vn-one border-solid-right>
<div><vn-label translate>Since</vn-label> {{::classification.started | dateTime:'dd/MM/yyyy'}}</div>
<div><vn-label translate>To</vn-label> {{classification.finished | dateTime:'dd/MM/yyyy'}}</div>
</vn-one>
<vn-vertical vn-one pad-medium-h>
<vn-horizontal ng-repeat="insurance in classification.insurances track by insurance.id">
<vn-one>
<vn-label-value label="Credit"
value="{{::insurance.credit}}">
</vn-label-value>
</vn-one>
<vn-one>
<vn-label-value label="Grade"
value="{{::insurance.grade}}">
</vn-label-value>
</vn-one>
<vn-one>
<vn-label-value label="Date"
value="{{::insurance.created | dateTime:'dd/MM/yyyy' }}">
</vn-label-value>
</vn-one>
</vn-horizontal>
</vn-vertical>
<a vn-auto ui-sref="client.card.creditInsurance.insurance.index({classificationId: {{classification.id}}})">
<vn-icon-button icon="desktop_windows" vn-tooltip="View credits"></vn-icon-button>
</a>
</vn-horizontal>
</vn-one>
</vn-horizontal>
</vn-card>
<vn-float-button
ng-if="$ctrl.canCreateNew()"
vn-tooltip="New contract"
fixed-bottom-right
ui-sref="client.card.creditInsurance.create"
icon="add"
vn-bind="+"
label="Add">
</vn-float-button>
</div>
</vn-data-viewer>
<vn-float-button
ng-if="$ctrl.canCreateNew()"
vn-tooltip="New contract"
fixed-bottom-right
ui-sref="client.card.creditInsurance.create"
icon="add"
vn-bind="+"
label="Add">
</vn-float-button>
<vn-confirm
vn-id="close-contract"
on-response="$ctrl.returnDialog(response)"

View File

@ -1,7 +1,7 @@
import ngModule from '../../module';
import './style.scss';
class Controller {
constructor($http, $scope) {
this.$http = $http;
this.$scope = $scope;

View File

@ -0,0 +1,5 @@
vn-client-credit-insurance-index{
.insurance:last-child {
padding-bottom: 0;
}
}

View File

@ -4,36 +4,38 @@
filter="::$ctrl.filter"
link="{clientFk: $ctrl.$stateParams.id}"
limit="20"
data="credits" auto-load="false">
data="credits"
order="created DESC"
auto-load="true">
</vn-crud-model>
<vn-vertical compact>
<vn-card pad-large>
<vn-vertical>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="amount">Credit</vn-th>
<vn-th field="created" default-order="DESC">Since</vn-th>
<vn-th>Employee</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="credit in credits track by credit.id">
<vn-td>{{::credit.amount | number:2}} €</vn-td>
<vn-td>{{::credit.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
<vn-td>{{::credit.worker.user.nickname}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
<vn-data-viewer
model="model"
class="vn-w-md">
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="created">Since</vn-th>
<vn-th field="workerFk">Employee</vn-th>
<vn-th field="amount" number>Credit</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="credit in credits track by credit.id">
<vn-td>{{::credit.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
<vn-td>{{::credit.worker.user.nickname}}</vn-td>
<vn-td number>{{::credit.amount | currency:'EUR':2}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-vertical>
<vn-float-button icon="add" fixed-bottom-right
</vn-data-viewer>
<vn-float-button
icon="add"
ui-sref="client.card.credit.create"
vn-acl="teamBoss"
vn-acl-action="remove"
vn-tooltip="New credit"
vn-bind="+">
vn-bind="+"
fixed-bottom-right>
</vn-float-button>

View File

@ -1,3 +1,2 @@
Since : Desde
Employee : Empleado
No results: Sin resultados

View File

@ -4,101 +4,102 @@
link="{clientFk: $ctrl.$stateParams.id}"
filter="::$ctrl.filter"
limit="20"
data="$ctrl.clientDms">
data="$ctrl.clientDms"
order="dmsFk DESC"
auto-load="true">
</vn-crud-model>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="dmsFk" default-order="DESC" shrink>Id</vn-th>
<vn-th field="dmsTypeFk" shrink>Type</vn-th>
<vn-th field="hardCopyNumber" shrink number>Order</vn-th>
<vn-th field="reference" shrink>Reference</vn-th>
<vn-th expand>Description</vn-th>
<vn-th field="hasFile" shrink>Original</vn-th>
<vn-th shrink>File</vn-th>
<vn-th shrink>Employee</vn-th>
<vn-th field="created">Created</vn-th>
<vn-th shrink></vn-th>
<vn-th shrink></vn-th>
<vn-th shrink></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="document in $ctrl.clientDms">
<vn-td number shrink>{{::document.dmsFk}}</vn-td>
<vn-td shrink>
<span title="{{::document.dms.dmsType.name}}">
{{::document.dms.dmsType.name}}
</span>
</vn-td>
<vn-td shrink number>
<span class="chip" title="{{::document.dms.hardCopyNumber}}"
ng-class="{'message': document.dms.hardCopyNumber}">
{{::document.dms.hardCopyNumber}}
</span>
</vn-td>
<vn-td shrink>
<span title="{{::document.dms.reference}}">
{{::document.dms.reference}}
</span>
</vn-td>
<vn-td expand>
<span title="{{::document.dms.description}}">
{{::document.dms.description}}
</span>
</vn-td>
<vn-td shrink>
<vn-check disabled="true"
field="document.dms.hasFile">
</vn-check>
</vn-td>
<vn-td shrink>
<a target="_blank"
title="{{'Download file' | translate}}"
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">{{::document.dms.file}}
</a>
</vn-td>
<vn-td shrink>
<span class="link"
ng-click="$ctrl.showWorkerDescriptor($event, document.dms.workerFk)">
{{::document.dms.worker.user.nickname | dashIfEmpty}}
</span></vn-td>
<vn-td>
{{::document.dms.created | dateTime:'dd/MM/yyyy HH:mm'}}
</vn-td>
<vn-td shrink>
<a target="_blank"
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
<vn-icon-button
icon="cloud_download"
title="{{'Download file' | translate}}">
</vn-icon-button>
</a>
</vn-td>
<vn-td shrink>
<vn-icon-button ui-sref="client.card.dms.edit({dmsId: {{::document.dmsFk}}})"
icon="edit"
title="{{'Edit file' | translate}}">
</vn-icon-button>
</vn-td>
<vn-td shrink>
<vn-icon-button
icon="delete"
ng-click="$ctrl.showDeleteConfirm($index)"
title="{{'Remove file' | translate}}"
tabindex="-1">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
<vn-data-viewer
model="model"
class="vn-w-lg">
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="dmsFk" shrink>Id</vn-th>
<vn-th field="dmsTypeFk" shrink>Type</vn-th>
<vn-th field="hardCopyNumber" shrink number>Order</vn-th>
<vn-th field="reference" shrink>Reference</vn-th>
<vn-th expand>Description</vn-th>
<vn-th field="hasFile" shrink>Original</vn-th>
<vn-th shrink>File</vn-th>
<vn-th shrink>Employee</vn-th>
<vn-th field="created">Created</vn-th>
<vn-th shrink></vn-th>
<vn-th shrink></vn-th>
<vn-th shrink></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="document in $ctrl.clientDms">
<vn-td number shrink>{{::document.dmsFk}}</vn-td>
<vn-td shrink>
<span title="{{::document.dms.dmsType.name}}">
{{::document.dms.dmsType.name}}
</span>
</vn-td>
<vn-td shrink number>
<span class="chip" title="{{::document.dms.hardCopyNumber}}"
ng-class="{'message': document.dms.hardCopyNumber}">
{{::document.dms.hardCopyNumber}}
</span>
</vn-td>
<vn-td shrink>
<span title="{{::document.dms.reference}}">
{{::document.dms.reference}}
</span>
</vn-td>
<vn-td expand>
<span title="{{::document.dms.description}}">
{{::document.dms.description}}
</span>
</vn-td>
<vn-td shrink>
<vn-check disabled="true"
field="document.dms.hasFile">
</vn-check>
</vn-td>
<vn-td shrink>
<a target="_blank"
title="{{'Download file' | translate}}"
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">{{::document.dms.file}}
</a>
</vn-td>
<vn-td shrink>
<span class="link"
ng-click="$ctrl.showWorkerDescriptor($event, document.dms.workerFk)">
{{::document.dms.worker.user.nickname | dashIfEmpty}}
</span></vn-td>
<vn-td>
{{::document.dms.created | dateTime:'dd/MM/yyyy HH:mm'}}
</vn-td>
<vn-td shrink>
<a target="_blank"
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
<vn-icon-button
icon="cloud_download"
title="{{'Download file' | translate}}">
</vn-icon-button>
</a>
</vn-td>
<vn-td shrink>
<vn-icon-button ui-sref="client.card.dms.edit({dmsId: {{::document.dmsFk}}})"
icon="edit"
title="{{'Edit file' | translate}}">
</vn-icon-button>
</vn-td>
<vn-td shrink>
<vn-icon-button
icon="delete"
ng-click="$ctrl.showDeleteConfirm($index)"
title="{{'Remove file' | translate}}"
tabindex="-1">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-vertical>
</vn-data-viewer>
<vn-worker-descriptor-popover
vn-id="workerDescriptor">
</vn-worker-descriptor-popover>

View File

@ -4,49 +4,54 @@
filter="::$ctrl.filter"
link="{clientFk: $ctrl.$stateParams.id}"
limit="20"
data="greuges" auto-load="true">
data="greuges"
auto-load="true">
</vn-crud-model>
<mg-ajax
path="/client/api/greuges/{{$ctrl.$stateParams.id}}/sumAmount"
options="mgEdit">
</mg-ajax>
<vn-vertical compact>
<vn-card pad-large>
<vn-horizontal>
<div class="totalBox" ng-if="model.data.length > 0">
<vn-label-value label="Total"
value="{{edit.model.sumAmount | currency: 'EUR': 2}}">
</vn-label-value>
</div>
</vn-horizontal>
<vn-data-viewer
model="model"
class="vn-w-md">
<vn-card
ng-if="model.data.length > 0"
style="text-align: right;"
class="margin-medium-bottom pad-large">
<vn-label-value
label="Total"
value="{{edit.model.sumAmount | currency: 'EUR': 2}}">
</vn-label-value>
</vn-card>
<vn-card>
<vn-vertical>
<vn-table model="model" auto-load="false">
<vn-thead>
<vn-tr>
<vn-th field="shipped" default-order="DESC">Date</vn-th>
<vn-th field="description">Comment</vn-th>
<vn-th field="amount" >Amount</vn-th>
<vn-th field="greugeTypeFk">Type</vn-th>
<vn-th field="amount" number>Amount</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="greuge in greuges">
<vn-td>{{::greuge.shipped | dateTime:'dd/MM/yyyy HH:mm' }}</vn-td>
<vn-td>{{::greuge.description}}</vn-td>
<vn-td>{{::greuge.amount | currency: 'EUR': 2}}</vn-td>
<vn-td>{{::greuge.greugeType.name}}</vn-td>
<vn-td number>{{::greuge.amount | currency: 'EUR': 2}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
</vn-card>
</vn-vertical>
<vn-float-button icon="add" fixed-bottom-right
</vn-data-viewer>
<vn-float-button
icon="add"
ui-sref="client.card.greuge.create"
vn-tooltip="New greuge"
vn-acl="salesAssistant"
vn-acl-action="remove"
vn-bind="+">
vn-bind="+"
fixed-bottom-right>
</vn-float-button>

View File

@ -3,73 +3,74 @@
url="/item/api/Clients"
order="id DESC"
limit="8"
data="clients"
auto-load="false">
data="clients">
</vn-crud-model>
<div class="content-block">
<div class="vn-list">
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-client-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)"
info="Search client by id or name"
vn-focus>
</vn-searchbar>
</vn-card>
<vn-card margin-medium-v>
<a
ng-repeat="client in clients track by client.id"
ui-sref="client.card.summary({ id: {{::client.id}} })"
translate-attr="{title: 'View client'}"
class="vn-list-item searchResult">
<vn-horizontal ng-click="$ctrl.onClick($event)">
<vn-one>
<h6>{{::client.name}}</h6>
<vn-label-value label="Id"
value="{{::client.id}}">
</vn-label-value>
<vn-label-value label="Phone"
value="{{::client.phone | phone}}">
</vn-label-value>
<vn-label-value label="Town/City"
value="{{::client.city}}">
</vn-label-value>
<vn-label-value label="Email"
value="{{::client.email}}">
</vn-label-value>
</vn-one>
<vn-horizontal class="buttons">
<vn-icon-button
ng-click="$ctrl.filterTickets(client, $event)"
vn-tooltip="Client tickets"
icon="icon-ticket">
</vn-icon-button>
<vn-icon-button
ng-click="$ctrl.openSummary(client, $event)"
vn-tooltip="Preview"
icon="desktop_windows">
</vn-icon-button>
</vn-horizontal>
<div class="content-block vn-w-sm">
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-client-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)"
info="Search client by id or name"
vn-focus>
</vn-searchbar>
</vn-card>
<vn-data-viewer
model="model"
margin-medium-v>
<vn-card>
<div class="vn-list">
<a
ng-repeat="client in clients track by client.id"
ui-sref="client.card.summary({ id: {{::client.id}} })"
translate-attr="{title: 'View client'}"
class="vn-list-item searchResult">
<vn-horizontal ng-click="$ctrl.onClick($event)">
<vn-one>
<h6>{{::client.name}}</h6>
<vn-label-value label="Id"
value="{{::client.id}}">
</vn-label-value>
<vn-label-value label="Phone"
value="{{::client.phone | phone}}">
</vn-label-value>
<vn-label-value label="Town/City"
value="{{::client.city}}">
</vn-label-value>
<vn-label-value label="Email"
value="{{::client.email}}">
</vn-label-value>
</vn-one>
<vn-horizontal class="buttons">
<vn-icon-button
ng-click="$ctrl.filterTickets(client, $event)"
vn-tooltip="Client tickets"
icon="icon-ticket">
</vn-icon-button>
<vn-icon-button
ng-click="$ctrl.openSummary(client, $event)"
vn-tooltip="Preview"
icon="desktop_windows">
</vn-icon-button>
</vn-horizontal>
</a>
<vn-empty-rows translate ng-if="model.data.length === 0">
No results
</vn-empty-rows>
<vn-empty-rows translate ng-if="model.data === null">
Enter a new search
</vn-empty-rows>
</vn-horizontal>
</a>
</div>
</vn-card>
<vn-pagination model="model"></vn-pagination>
</div>
</vn-data-viewer>
</div>
<a ui-sref="client.create" vn-tooltip="New client" vn-bind="+" fixed-bottom-right>
<a ui-sref="client.create"
vn-tooltip="New client"
vn-bind="+"
fixed-bottom-right>
<vn-float-button icon="person_add"></vn-float-button>
</a>
<vn-dialog class="dialog-summary"
vn-id="dialog-summary-client">
<tpl-body>
<vn-client-summary client="$ctrl.clientSelected"></vn-client-summary>
<vn-client-summary
client="$ctrl.clientSelected">
</vn-client-summary>
</tpl-body>
</vn-dialog>
<vn-scroll-up></vn-scroll-up>

View File

@ -4,32 +4,33 @@
filter="::$ctrl.filter"
link="{clientFk: $ctrl.$stateParams.id}"
limit="20"
data="mandates" auto-load="false">
data="mandates"
order="created DESC"
auto-load="true">
</vn-crud-model>
<vn-vertical compact>
<vn-card pad-large>
<vn-vertical>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="id">Id</vn-th>
<vn-th field="companyFk">Company</vn-th>
<vn-th field="mandateTypeFk">Type</vn-th>
<vn-th field="created" default-order="DESC">Register date</vn-th>
<vn-th field="finished">End date</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="mandate in mandates">
<vn-td>{{::mandate.id}}</vn-td>
<vn-td>{{::mandate.company.code}}</vn-td>
<vn-td>{{::mandate.mandateType.name}}</vn-td>
<vn-td>{{::mandate.created | dateTime:'dd/MM/yyyy HH:mm' }}</vn-td>
<vn-td>{{::mandate.finished | dateTime:'dd/MM/yyyy HH:mm' || '-'}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
<vn-data-viewer
model="model"
class="vn-w-md">
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="id" number>Id</vn-th>
<vn-th field="companyFk">Company</vn-th>
<vn-th field="mandateTypeFk">Type</vn-th>
<vn-th field="created">Register date</vn-th>
<vn-th field="finished">End date</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="mandate in mandates">
<vn-td number>{{::mandate.id}}</vn-td>
<vn-td>{{::mandate.company.code}}</vn-td>
<vn-td>{{::mandate.mandateType.name}}</vn-td>
<vn-td>{{::mandate.created | dateTime:'dd/MM/yyyy HH:mm' }}</vn-td>
<vn-td>{{::mandate.finished | dateTime:'dd/MM/yyyy HH:mm' || '-'}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-vertical>
</vn-data-viewer>

View File

@ -6,15 +6,14 @@ class Controller {
this.filter = {
include: [
{
relation: "mandateType",
relation: 'mandateType',
scope: {
fields: ["id", "name"]
fields: ['id', 'name']
}
},
{
relation: "company",
}, {
relation: 'company',
scope: {
fields: ["id", "code"]
fields: ['id', 'code']
}
}
]

View File

@ -6,9 +6,11 @@
data="notes"
auto-load="true">
</vn-crud-model>
<vn-vertical compact>
<vn-card pad-large>
<vn-vertical
<vn-data-viewer
model="model"
class="vn-w-md">
<vn-card pad-medium>
<div class="note"
ng-repeat="note in notes"
pad-small
border-solid
@ -21,15 +23,9 @@
<vn-horizontal class="text">
{{::note.text}}
</vn-horizontal>
</vn-vertical>
<vn-horizontal ng-if="model.data.length == 0">
<vn-one ad-small translate>
No results
</vn-one>
</vn-horizontal>
</div>
</vn-card>
</vn-vertical>
</vn-data-viewer>
<a vn-tooltip="New note"
ui-sref="client.card.note.create({id: $ctrl.$stateParams.id})"
vn-bind="+"

View File

@ -1,4 +1,5 @@
import ngModule from '../../module';
import './style.scss';
export default class Controller {
constructor($stateParams) {

View File

@ -0,0 +1,5 @@
vn-client-note {
.note:last-child {
margin-bottom: 0;
}
}

View File

@ -1,48 +1,50 @@
<vn-crud-model
vn-id="model"
url="/client/api/Recoveries"
filter="{}"
link="{clientFk: $ctrl.$stateParams.id}"
limit="20"
data="recoveries" auto-load="false">
data="recoveries"
order="started DESC"
auto-load="true">
</vn-crud-model>
<vn-vertical compact>
<vn-card pad-large>
<vn-vertical>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th></vn-th>
<vn-th field="started" default-order="DESC">Since</vn-th>
<vn-th field="finished">To</vn-th>
<vn-th field="amount">Amount</vn-th>
<vn-th field="period">Period</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="recovery in recoveries">
<vn-td>
<vn-icon-button icon="lock"
vn-acl="administrative"
vn-acl-action="remove"
vn-tooltip="Finish that recovery period"
ng-if="!recovery.finished"
ng-click="$ctrl.setFinished(recovery)">
</vn-icon-button>
</vn-td>
<vn-td>{{::recovery.started | dateTime:'dd/MM/yyyy' }}</vn-td>
<vn-td>{{recovery.finished | dateTime:'dd/MM/yyyy' }}</vn-td>
<vn-td>{{::recovery.amount | currency: 'EUR': 0}}</vn-td>
<vn-td>{{::recovery.period}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
<vn-data-viewer
model="model"
class="vn-w-md">
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th></vn-th>
<vn-th field="started">Since</vn-th>
<vn-th field="finished">To</vn-th>
<vn-th field="amount" number>Amount</vn-th>
<vn-th field="period" number>Period</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="recovery in recoveries">
<vn-td>
<vn-icon-button
icon="lock"
vn-acl="administrative"
vn-acl-action="remove"
vn-tooltip="Finish that recovery period"
ng-if="!recovery.finished"
ng-click="$ctrl.setFinished(recovery)">
</vn-icon-button>
</vn-td>
<vn-td>{{::recovery.started | dateTime:'dd/MM/yyyy' }}</vn-td>
<vn-td>{{recovery.finished | dateTime:'dd/MM/yyyy' }}</vn-td>
<vn-td number>{{::recovery.amount | currency: 'EUR': 0}}</vn-td>
<vn-td number>{{::recovery.period}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-vertical>
<vn-float-button icon="add" fixed-bottom-right
</vn-data-viewer>
<vn-float-button
icon="add"
fixed-bottom-right
vn-tooltip="New recovery"
vn-bind="+"
vn-acl="administrative"

View File

@ -1,5 +1,4 @@
Since: Desde
Employee: Empleado
No results: Sin resultados
To: Hasta
Finish that recovery period: Terminar el recobro

View File

@ -4,49 +4,51 @@
filter="::$ctrl.filter"
link="{clientFk: $ctrl.$stateParams.id}"
limit="20"
data="samples" auto-load="false">
data="samples"
order="created DESC"
auto-load="true">
</vn-crud-model>
<vn-vertical compact>
<vn-card pad-large>
<vn-horizontal>
</vn-horizontal>
<vn-vertical>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="created" default-order="DESC">Sent</vn-th>
<vn-th>Description</vn-th>
<vn-th field="workerFk">Worker</vn-th>
<vn-th field="companyFk">Company</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="sample in samples">
<vn-td>{{::sample.created | dateTime:'dd/MM/yyyy HH:mm' }}</vn-td>
<vn-td
title="{{::sample.type.description}}">
{{::sample.type.description}}
</vn-td>
<vn-td>
<span class="link"
ng-click="$ctrl.showWorkerDescriptor($event, sample.worker.id)">
{{::sample.worker.user.nickname}}
</span>
</vn-td>
<vn-td>{{::sample.company.code}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
<vn-data-viewer
model="model"
class="vn-w-md">
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="created">Sent</vn-th>
<vn-th>Description</vn-th>
<vn-th field="workerFk">Worker</vn-th>
<vn-th field="companyFk">Company</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="sample in samples">
<vn-td>{{::sample.created | dateTime:'dd/MM/yyyy HH:mm' }}</vn-td>
<vn-td
title="{{::sample.type.description}}">
{{::sample.type.description}}
</vn-td>
<vn-td>
<span class="link"
ng-click="$ctrl.showWorkerDescriptor($event, sample.worker.id)">
{{::sample.worker.user.nickname}}
</span>
</vn-td>
<vn-td>{{::sample.company.code}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-vertical>
</vn-data-viewer>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
worker-fk="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>
<a ui-sref="client.card.sample.create" vn-tooltip="Send sample"
vn-bind="+" fixed-bottom-right>
<a
ui-sref="client.card.sample.create"
vn-tooltip="Send sample"
vn-bind="+"
fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -1,4 +1,4 @@
Default address: Consignatario pred.
Default address: Consignatario predeterminado
Total greuge: Greuge total
Financial information: Datos financieros
Mana: Maná

View File

@ -3,52 +3,53 @@
url="/client/api/clients/getTransactions"
link="{clientFk: $ctrl.$stateParams.id}"
limit="20"
data="transactions" auto-load="false">
data="transactions"
order="created DESC"
auto-load="true">
</vn-crud-model>
<vn-vertical compact>
<vn-card pad-large>
<vn-vertical>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th>State</vn-th>
<vn-th field="id">Id</vn-th>
<vn-th field="amount" number>Amount</vn-th>
<vn-th field="created" default-order="DESC">Payed</vn-th>
<vn-th>Confirm</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="transaction in transactions">
<vn-td style="width: 3em; text-align: center">
<vn-icon
vn-tooltip="{{$ctrl.getFormattedMessage(transaction)}}"
ng-show="::((transaction.errorMessage || transaction.responseMessage) && !transaction.isConfirmed)"
icon="clear">
</vn-icon>
<vn-icon
vn-tooltip="Confirmed"
ng-show="::(transaction.isConfirmed)"
icon="check">
</vn-icon>
</vn-td>
<vn-td>{{::transaction.id}}</vn-td>
<vn-td number>{{::transaction.amount | currency: 'EUR':2}}</vn-td>
<vn-td>{{::transaction.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
<vn-td style="width: 3em; text-align: center">
<vn-icon-button
icon="done_all"
vn-acl="administrative"
vn-acl-action="remove"
vn-tooltip="Confirm transaction"
ng-show="::!transaction.isConfirmed"
ng-click="$ctrl.confirm(transaction)">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-vertical>
<vn-pagination model="model"></vn-pagination>
<vn-data-viewer
model="model"
class="vn-w-md">
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th shrink>State</vn-th>
<vn-th field="id" number>Id</vn-th>
<vn-th field="created">Date</vn-th>
<vn-th field="amount" number>Amount</vn-th>
<vn-th shrink></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="transaction in transactions">
<vn-td shrink>
<vn-icon
vn-tooltip="{{$ctrl.getFormattedMessage(transaction)}}"
ng-show="::((transaction.errorMessage || transaction.responseMessage) && !transaction.isConfirmed)"
icon="clear">
</vn-icon>
<vn-icon
vn-tooltip="Confirmed"
ng-show="::(transaction.isConfirmed)"
icon="check">
</vn-icon>
</vn-td>
<vn-td number>{{::transaction.id}}</vn-td>
<vn-td>{{::transaction.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
<vn-td number>{{::transaction.amount | currency: 'EUR':2}}</vn-td>
<vn-td shrink>
<vn-icon-button
icon="done_all"
vn-acl="administrative"
vn-acl-action="remove"
translate-attr="{title: 'Confirm transaction'}"
ng-show="::!transaction.isConfirmed"
ng-click="$ctrl.confirm(transaction)">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
</vn-vertical>
</vn-data-viewer>

View File

@ -1,6 +1,5 @@
Web Payment: Pago Web
Confirmed: Confirmado
Payed: Pagado
Confirm transaction: Confirmar transacción
Confirm: Confirmar
State: Estado

View File

@ -7,7 +7,7 @@
</vn-crud-model>
<div class="content-block">
<div class="vn-list">
<vn-card pad-medium-h>
<vn-card pad-medium-h class="vn-w-sm">
<vn-searchbar
panel="vn-invoice-search-panel"
on-search="$ctrl.onSearch($params)"
@ -16,8 +16,12 @@
</vn-searchbar>
</vn-card>
</div>
<vn-card margin-medium-v compact>
<vn-table model="model" auto-load="false">
<vn-data-viewer
model="model"
class="vn-w-md"
margin-medium-v>
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="ref">Reference</vn-th>
@ -67,15 +71,19 @@
</a>
</vn-tbody>
</vn-table>
</vn-card>
<vn-pagination model="model"></vn-pagination>
</vn-card>
</vn-data-viewer>
</div>
<vn-dialog
vn-id="summary"
class="dialog-summary">
<tpl-body>
<vn-invoice-out-summary invoice-out="$ctrl.selectedInvoiceOut"></vn-invoice-out-summary>
<vn-invoice-out-summary
invoice-out="$ctrl.selectedInvoiceOut">
</vn-invoice-out-summary>
</tpl-body>
</vn-dialog>
<vn-client-descriptor-popover vn-id="clientDescriptor"></vn-client-descriptor-popover>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>
<vn-scroll-up></vn-scroll-up>

View File

@ -2,7 +2,7 @@
vn-invoice-out-summary .summary {
max-width: $width-large;
max-width: $width-lg;
vn-icon[icon=insert_drive_file]{
color: $color-font-secondary;

View File

@ -62,13 +62,26 @@ module.exports = Self => {
Self.filter = async(ctx, filter) => {
let conn = Self.dataSource.connector;
let codeWhere;
if (ctx.args.search) {
let items = await Self.app.models.ItemBarcode.find({
where: {code: ctx.args.search},
fields: ['itemFk']
});
let itemIds = [];
for (const item of items)
itemIds.push(item.itemFk);
codeWhere = {'i.id': {inq: itemIds}};
}
let where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {or: [{'i.id': value}, {'ib.code': value}]}
: {or: [{'i.name': {like: `%${value}%`}}, {'ib.code': value}]};
? {or: [{'i.id': value}, codeWhere]}
: {or: [{'i.name': {like: `%${value}%`}}, codeWhere]};
case 'id':
return {'i.id': value};
case 'description':
@ -83,8 +96,8 @@ module.exports = Self => {
return {'i.isActive': value};
}
});
filter = mergeFilters(filter, {where});
let stmts = [];
let stmt;
@ -123,8 +136,7 @@ module.exports = Self => {
LEFT JOIN origin ori ON ori.id = i.originFk
LEFT JOIN cache.last_buy lb ON lb.item_id = i.id AND lb.warehouse_id = t.warehouseFk
LEFT JOIN vn.buy b ON b.id = lb.buy_id
LEFT JOIN itemPlacement itn ON itn.itemFk = i.id AND itn.warehouseFk = t.warehouseFk
LEFT JOIN itemBarcode ib ON ib.itemFk = i.id`
LEFT JOIN itemPlacement itn ON itn.itemFk = i.id AND itn.warehouseFk = t.warehouseFk`
);
if (ctx.args.tags) {
@ -150,7 +162,6 @@ module.exports = Self => {
}
stmt.merge(conn.makeWhere(filter.where));
stmt.merge(`GROUP BY i.id`);
stmt.merge(conn.makePagination(filter));
let itemsIndex = stmts.push(stmt) - 1;

View File

@ -3,35 +3,39 @@
url="/item/api/Items/filter"
limit="12"
order="isActive DESC, name, id"
data="items"
auto-load="false">
data="items">
</vn-crud-model>
<div class="content-block">
<div class="vn-list">
<vn-card pad-medium-h>
<vn-horizontal>
<vn-searchbar
vn-three
panel="vn-item-search-panel"
on-search="$ctrl.onSearch($params)"
info="Search items by id, name or barcode"
suggested-filter="{isActive: true}"
vn-focus>
</vn-searchbar>
<vn-icon-menu
vn-id="more-button"
icon="more_vert"
show-filter="false"
value-field="callback"
translate-fields="['name']"
on-change="$ctrl.onMoreChange(value)"
on-open="$ctrl.onMoreOpen()">
</vn-icon-menu>
</vn-horizontal>
</vn-card>
</div>
<vn-card margin-medium-v margin-huge-bottom>
<vn-table model="model" auto-load="false" show-fields="$ctrl.showFields" vn-uvc="itemIndex">
<vn-card pad-medium-h class="vn-w-sm">
<vn-horizontal>
<vn-searchbar
vn-three
panel="vn-item-search-panel"
on-search="$ctrl.onSearch($params)"
info="Search items by id, name or barcode"
suggested-filter="{isActive: true}"
vn-focus>
</vn-searchbar>
<vn-icon-menu
vn-id="more-button"
icon="more_vert"
show-filter="false"
value-field="callback"
translate-fields="['name']"
on-change="$ctrl.onMoreChange(value)"
on-open="$ctrl.onMoreOpen()">
</vn-icon-menu>
</vn-horizontal>
</vn-card>
<vn-data-viewer
model="model"
margin-medium-v
margin-huge-bottom>
<vn-card>
<vn-table
model="model"
show-fields="$ctrl.showFields"
vn-uvc="itemIndex">
<vn-thead>
<vn-tr>
<vn-th th-id="picture" shrink></vn-th>
@ -124,8 +128,8 @@
</a>
</vn-tbody>
</vn-table>
</vn-card>
<vn-pagination model="model"></vn-pagination>
</vn-card>
</vn-data-viewer>
</div>
<a ui-sref="item.create" vn-tooltip="New item" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>

View File

@ -33,8 +33,6 @@ Remove niche: Quitar nicho
Add barcode: Añadir código de barras
Remove barcode: Quitar código de barras
Buyer: Comprador
No results: Sin resultados
Enter a new search: Introduce una nueva búsqueda
Tag: Etiqueta
Worker: Trabajador
Available: Disponible

View File

@ -131,7 +131,7 @@ class Controller {
}
get isRefreshing() {
return this.$scope.model && this.$scope.model.isRefreshing;
return this.$scope.model && this.$scope.model.status == 'loading';
}
}

View File

@ -3,24 +3,23 @@
url="/api/Orders/filter"
limit="20"
data="orders"
order="landed DESC, clientFk"
auto-load="false">
order="landed DESC, clientFk">
</vn-crud-model>
<div class="content-block">
<div class="vn-list">
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-order-search-panel"
on-search="$ctrl.onSearch($params)"
info="Search orders by id"
vn-focus>
</vn-searchbar>
</vn-card>
</div>
<vn-card margin-medium-v>
<vn-table
model="model"
auto-load="false">
<vn-card pad-medium-h class="vn-w-sm">
<vn-searchbar
panel="vn-order-search-panel"
on-search="$ctrl.onSearch($params)"
info="Search orders by id"
vn-focus>
</vn-searchbar>
</vn-card>
<vn-data-viewer
model="model"
margin-medium-v
margin-huge-bottom>
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="id" number>Id</vn-th>
@ -71,8 +70,8 @@
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
<vn-pagination model="model"></vn-pagination>
</vn-card>
</vn-data-viewer>
</div>
<a ui-sref="order.create" vn-bind="+" vn-tooltip="New order" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>

Some files were not shown because too many files have changed in this diff Show More