Move up all sources in src directory.
This commit is contained in:
563
src/operations/index.js
Normal file
563
src/operations/index.js
Normal file
@ -0,0 +1,563 @@
|
||||
// vim: set tw=80 ts=4 sw=4 sts=4:
|
||||
/*
|
||||
This file is part of Accountant.
|
||||
|
||||
Accountant is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Accountant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* jshint node: true */
|
||||
'use strict';
|
||||
|
||||
var moment = require('moment'),
|
||||
Highcharts = require('highstock-release');
|
||||
|
||||
var angular = require('angular');
|
||||
|
||||
var operationFormTmpl = require('./operation.form.tmpl.html');
|
||||
|
||||
var ngResource = require('angular-resource'),
|
||||
ngMessages = require('angular-messages'),
|
||||
ngUiNotification = require('angular-ui-notification'),
|
||||
ngBootbox = require('ngbootbox'),
|
||||
ngStrap = require('angular-strap');
|
||||
|
||||
// Note: ngBootbox seems to have no module.exports.
|
||||
ngBootbox = 'ngBootbox';
|
||||
|
||||
var accountModule = require('../accounts');
|
||||
|
||||
var operationModule = angular.module('accountant.operations', [
|
||||
accountModule.name,
|
||||
ngResource,
|
||||
ngMessages,
|
||||
ngUiNotification,
|
||||
ngBootbox,
|
||||
ngStrap
|
||||
])
|
||||
|
||||
.config(function($resourceProvider) {
|
||||
// Keep trailing slashes to avoid redirect by flask..
|
||||
$resourceProvider.defaults.stripTrailingSlashes = false;
|
||||
})
|
||||
|
||||
.factory('Operation', function($resource) {
|
||||
return $resource(
|
||||
'/api/operation/:id', {
|
||||
id: '@id'
|
||||
}
|
||||
);
|
||||
})
|
||||
|
||||
.factory('OHLC', function($resource, $routeParams) {
|
||||
return $resource(
|
||||
'/api/account/:account_id/ohlc', {
|
||||
// eslint-disable-next-line camelcase
|
||||
account_id: $routeParams.accountId
|
||||
}
|
||||
);
|
||||
})
|
||||
|
||||
.factory('Category', function($resource, $routeParams) {
|
||||
return $resource(
|
||||
'/api/account/:account_id/category', {
|
||||
// eslint-disable-next-line camelcase
|
||||
account_id: $routeParams.accountId
|
||||
}
|
||||
);
|
||||
})
|
||||
|
||||
.factory('Balance', function($resource, $routeParams) {
|
||||
return $resource(
|
||||
'/api/account/:account_id/balance', {
|
||||
// eslint-disable-next-line camelcase
|
||||
account_id: $routeParams.accountId
|
||||
}
|
||||
);
|
||||
})
|
||||
|
||||
/*
|
||||
* Controller for category chart.
|
||||
*/
|
||||
.controller('CategoryChartController',
|
||||
function($rootScope, Category, Balance) {
|
||||
var vm = this;
|
||||
|
||||
var colors = Highcharts.getOptions().colors;
|
||||
vm.revenueColor = colors[2];
|
||||
vm.expenseColor = colors[3];
|
||||
|
||||
// Configure pie chart for categories.
|
||||
vm.config = {
|
||||
options: {
|
||||
chart: {
|
||||
type: 'pie',
|
||||
animation: {
|
||||
duration: 500
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
startAngle: -90
|
||||
},
|
||||
series: {
|
||||
allowPointSelect: 0
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
valueDecimals: 2,
|
||||
valueSuffix: '€'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
title: {
|
||||
text: 'Categories'
|
||||
}
|
||||
},
|
||||
title: {
|
||||
text: 'Répartition dépenses/recettes'
|
||||
},
|
||||
series: [{
|
||||
name: 'Value',
|
||||
data: [],
|
||||
innerSize: '33%',
|
||||
size: '60%',
|
||||
dataLabels: {
|
||||
formatter: function() {
|
||||
// eslint-disable-next-line angular/controller-as-vm
|
||||
return this.point.name;
|
||||
},
|
||||
distance: -40
|
||||
}
|
||||
}, {
|
||||
name: 'Value',
|
||||
data: [],
|
||||
innerSize: '66%',
|
||||
size: '60%',
|
||||
dataLabels: {
|
||||
formatter: function() {
|
||||
// eslint-disable-next-line angular/controller-as-vm
|
||||
if (this.point.name !== null && this.percentage >= 2.5) {
|
||||
// eslint-disable-next-line angular/controller-as-vm
|
||||
return this.point.name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
vm.brightenColor = function(color) {
|
||||
var brightness = 0.2;
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
return Highcharts.Color(color).brighten(brightness).get();
|
||||
};
|
||||
|
||||
// Load categories, mainly to populate the pie chart.
|
||||
vm.load = function(begin, end) {
|
||||
vm.config.loading = true;
|
||||
|
||||
Category.query({
|
||||
begin: begin.format('YYYY-MM-DD'),
|
||||
end: end.format('YYYY-MM-DD')
|
||||
}, function(data) {
|
||||
var expenses = [];
|
||||
var revenues = [];
|
||||
|
||||
var expenseColor = vm.brightenColor(vm.expenseColor);
|
||||
var revenueColor = vm.brightenColor(vm.revenueColor);
|
||||
|
||||
angular.forEach(angular.fromJson(data), function(category) {
|
||||
expenses.push({
|
||||
name: category.category,
|
||||
y: -category.expenses,
|
||||
color: expenseColor
|
||||
});
|
||||
|
||||
revenues.push({
|
||||
name: category.category,
|
||||
y: category.revenues,
|
||||
color: revenueColor
|
||||
});
|
||||
});
|
||||
|
||||
// Note: expenses and revenues must be in the same order than in series[0].
|
||||
vm.config.series[1].data = revenues.concat(expenses);
|
||||
|
||||
vm.config.loading = false;
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Get account balance.
|
||||
*/
|
||||
vm.getBalance = function(begin, end) {
|
||||
Balance.get({
|
||||
begin: begin.format('YYYY-MM-DD'),
|
||||
end: end.format('YYYY-MM-DD')
|
||||
}, function(balance) {
|
||||
// Update pie chart subtitle with Balance.
|
||||
vm.config.subtitle = {
|
||||
text: 'Balance: ' + balance.balance
|
||||
};
|
||||
|
||||
vm.config.series[0].data = [{
|
||||
name: 'Revenues',
|
||||
y: balance.revenues,
|
||||
color: vm.revenueColor
|
||||
}, {
|
||||
name: 'Expenses',
|
||||
y: -balance.expenses,
|
||||
color: vm.expenseColor
|
||||
}];
|
||||
});
|
||||
};
|
||||
|
||||
// Reload categories and account status on range selection.
|
||||
vm.onRangeSelected = $rootScope.$on('rangeSelectedEvent', function(e, args) {
|
||||
vm.load(args.begin, args.end);
|
||||
vm.getBalance(args.begin, args.end);
|
||||
});
|
||||
|
||||
$rootScope.$on('$destroy', function(){
|
||||
vm.onRangeSelected = angular.noop();
|
||||
});
|
||||
}
|
||||
)
|
||||
|
||||
/*
|
||||
* Controller for the sold chart.
|
||||
*/
|
||||
.controller('SoldChartController', function($rootScope, $scope, OHLC) {
|
||||
var vm = this;
|
||||
|
||||
// Configure chart for operations.
|
||||
vm.config = {
|
||||
options: {
|
||||
chart: {
|
||||
zoomType: 'x'
|
||||
},
|
||||
rangeSelector: {
|
||||
buttons: [{
|
||||
type: 'month',
|
||||
count: 1,
|
||||
text: '1m'
|
||||
}, {
|
||||
type: 'month',
|
||||
count: 3,
|
||||
text: '3m'
|
||||
}, {
|
||||
type: 'month',
|
||||
count: 6,
|
||||
text: '6m'
|
||||
}, {
|
||||
type: 'year',
|
||||
count: 1,
|
||||
text: '1y'
|
||||
}, {
|
||||
type: 'all',
|
||||
text: 'All'
|
||||
}],
|
||||
selected: 0
|
||||
},
|
||||
navigator: {
|
||||
enabled: true
|
||||
},
|
||||
tooltip: {
|
||||
crosshairs: true,
|
||||
shared: true,
|
||||
valueDecimals: 2,
|
||||
valueSuffix: '€'
|
||||
},
|
||||
scrollbar: {
|
||||
liveRedraw: false
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
type: 'ohlc',
|
||||
name: 'Sold',
|
||||
data: [],
|
||||
dataGrouping: {
|
||||
units: [[
|
||||
'week', // unit name
|
||||
[1] // allowed multiples
|
||||
], [
|
||||
'month',
|
||||
[1, 2, 3, 4, 6]
|
||||
]]
|
||||
}
|
||||
}],
|
||||
title: {
|
||||
text: 'Sold evolution'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
dateTimeLabelFormats: {
|
||||
month: '%e. %b',
|
||||
year: '%Y'
|
||||
},
|
||||
minRange: 3600 * 1000 * 24 * 14, // 2 weeks
|
||||
events: {
|
||||
afterSetExtremes: function(e) {
|
||||
$scope.$emit('rangeSelectedEvent', {
|
||||
begin: moment.utc(e.min), end: moment.utc(e.max)
|
||||
});
|
||||
}
|
||||
},
|
||||
currentMin: moment.utc().startOf('month'),
|
||||
currentMax: moment.utc().endOf('month')
|
||||
},
|
||||
yAxis: {
|
||||
plotLines: [{
|
||||
color: 'orange',
|
||||
width: 2,
|
||||
value: 0.0
|
||||
}, {
|
||||
color: 'red',
|
||||
width: 2,
|
||||
value: 0.0
|
||||
}]
|
||||
},
|
||||
useHighStocks: true
|
||||
};
|
||||
|
||||
vm.loadSolds = function() {
|
||||
vm.config.loading = true;
|
||||
|
||||
OHLC.query({}, function(data) {
|
||||
vm.config.series[0].data = [];
|
||||
|
||||
angular.forEach(data, function(operation) {
|
||||
vm.config.series[0].data.push([
|
||||
moment.utc(operation.operation_date).valueOf(),
|
||||
operation.open, operation.high, operation.low, operation.close
|
||||
]);
|
||||
});
|
||||
|
||||
$scope.$emit('rangeSelectedEvent', {
|
||||
begin: vm.config.xAxis.currentMin,
|
||||
end: vm.config.xAxis.currentMax
|
||||
});
|
||||
|
||||
vm.config.loading = false;
|
||||
});
|
||||
};
|
||||
|
||||
// Reload solds when an operation is saved.
|
||||
vm.onOperationSaved = $rootScope.$on('operationSavedEvent', function() {
|
||||
vm.loadSolds();
|
||||
});
|
||||
|
||||
// Reload solds when an operation is deleted.
|
||||
vm.onOperationDeleted = $rootScope.$on('operationDeletedEvent', function() {
|
||||
vm.loadSolds();
|
||||
});
|
||||
|
||||
// Update authorized overdraft on account loading.
|
||||
vm.onAccountLoaded = $rootScope.$on('accountLoadedEvent', function(e, account) {
|
||||
vm.config.yAxis.plotLines[1].value = account.authorized_overdraft;
|
||||
});
|
||||
|
||||
$rootScope.$on('$destroy', function() {
|
||||
vm.onOperationSaved = angular.noop();
|
||||
vm.onOperationDeleted = angular.noop();
|
||||
vm.onAccountLoaded = angular.noop();
|
||||
});
|
||||
|
||||
// Select beginning and end of month.
|
||||
vm.loadSolds();
|
||||
})
|
||||
|
||||
/*
|
||||
* Controller for the operations.
|
||||
*/
|
||||
.controller('OperationController', function($rootScope, $scope, $routeParams, $ngBootbox, Notification, Account, Operation) {
|
||||
var vm = this;
|
||||
|
||||
// List of operations.
|
||||
vm.operations = [];
|
||||
|
||||
/*
|
||||
* Add an empty operation.
|
||||
*/
|
||||
vm.add = function() {
|
||||
var operation = new Operation({
|
||||
// eslint-disable-next-line camelcase
|
||||
account_id: $routeParams.accountId
|
||||
});
|
||||
|
||||
vm.operations.splice(0, 0, operation);
|
||||
};
|
||||
|
||||
/*
|
||||
* Load operations.
|
||||
*/
|
||||
vm.load = function(begin, end) {
|
||||
vm.operations = Operation.query({
|
||||
// eslint-disable-next-line camelcase
|
||||
account_id: $routeParams.accountId,
|
||||
begin: begin.format('YYYY-MM-DD'),
|
||||
end: end.format('YYYY-MM-DD')
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Cancel edition.
|
||||
*/
|
||||
vm.cancelEdit = function(operation, rowform, $index) {
|
||||
if (operation.id) {
|
||||
rowform.$cancel();
|
||||
} else {
|
||||
vm.operations.splice($index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Toggle pointed indicator for an operation.
|
||||
*/
|
||||
vm.togglePointed = function(operation, rowform) {
|
||||
operation.pointed = !operation.pointed;
|
||||
|
||||
// Save operation if not editing it.
|
||||
if (!rowform.$visible) {
|
||||
vm.save(operation);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Toggle cancel indicator for an operation.
|
||||
*/
|
||||
vm.toggleCanceled = function(operation) {
|
||||
operation.canceled = !operation.canceled;
|
||||
|
||||
vm.save(operation);
|
||||
};
|
||||
|
||||
/*
|
||||
* Save an operation and emit operationSavedEvent.
|
||||
*/
|
||||
vm.save = function($data, $index) {
|
||||
// Check if $data is already a resource.
|
||||
var operation;
|
||||
|
||||
if ($data.$save) {
|
||||
operation = $data;
|
||||
} else {
|
||||
operation = vm.operations[$index];
|
||||
operation = angular.merge(operation, $data);
|
||||
}
|
||||
|
||||
operation.confirmed = true;
|
||||
|
||||
return operation.$save().then(function(data) {
|
||||
Notification.success('Operation #' + data.id + ' saved.');
|
||||
|
||||
$scope.$emit('operationSavedEvent', data);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Delete an operation and emit operationDeletedEvent.
|
||||
*/
|
||||
vm.delete = function(operation, $index) {
|
||||
var id = operation.id;
|
||||
|
||||
$ngBootbox.confirm(
|
||||
'Voulez-vous supprimer l\'opération \\\'' + operation.label + '\\\' ?',
|
||||
function(result) {
|
||||
if (result) {
|
||||
operation.$delete().then(function() {
|
||||
Notification.success('Operation #' + id + ' deleted.');
|
||||
|
||||
// Remove operation from array.
|
||||
vm.operation.splice($index, 1);
|
||||
|
||||
$scope.$emit('operationDeletedEvent', operation);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
vm.account = Account.get({
|
||||
id: $routeParams.accountId
|
||||
});
|
||||
|
||||
/*
|
||||
* Reload operations on rangeSelectedEvent.
|
||||
*/
|
||||
vm.onRangeSelected = $rootScope.$on('rangeSelectedEvent', function(e, args) {
|
||||
vm.load(args.begin, args.end);
|
||||
});
|
||||
|
||||
$rootScope.$on('$destroy', function() {
|
||||
vm.onRangeSelected = angular.noop;
|
||||
});
|
||||
|
||||
vm.load(moment().date(1).year(2000), moment());
|
||||
})
|
||||
|
||||
.directive('operationFormDialog', function($log, $ngBootbox) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
scope: {
|
||||
operation: '=ngModel'
|
||||
},
|
||||
link: function(scope, element) {
|
||||
var title = 'Operation';
|
||||
|
||||
if (scope.operation && scope.operation.id) {
|
||||
title = title + ' #' + scope.operation.id;
|
||||
}
|
||||
|
||||
scope.form = {};
|
||||
|
||||
element.on('click', function() {
|
||||
scope.data = {};
|
||||
angular.copy(scope.operation, scope.data);
|
||||
|
||||
// Open dialog with form.
|
||||
$ngBootbox.customDialog({
|
||||
scope: scope,
|
||||
title: title,
|
||||
templateUrl: operationFormTmpl,
|
||||
onEscape: true,
|
||||
buttons: {
|
||||
save: {
|
||||
label: 'Save',
|
||||
className: 'btn-success',
|
||||
callback: function() {
|
||||
// Validate form
|
||||
$log.log(scope.form);
|
||||
|
||||
// Save operation
|
||||
$log.log(scope.operation);
|
||||
|
||||
// TODO Alexis Lahouze 2016-05-24 Save operation, handle return.
|
||||
return false;
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
label: 'Cancel',
|
||||
className: 'btn-default',
|
||||
callback: true
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
module.exports = operationModule;
|
58
src/operations/operation.form.tmpl.html
Normal file
58
src/operations/operation.form.tmpl.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!--
|
||||
This file is part of Accountant.
|
||||
|
||||
Accountant is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Accountant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<!-- vim: set tw=80 ts=2 sw=2 sts=2: -->
|
||||
<!-- kate: space-indent on; indent-width 2; mixedindent off; -->
|
||||
<form class="form-horizontal" role="form" name="form">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label" for="operation-date">Date</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" id="operation-date" name="operation_date" ng-model="data.operation_date"
|
||||
type="text" bs-datepicker data-date-format="yyyy-MM-dd"
|
||||
placeholder="Operation date">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label" for="label">Label</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" id="label" name="label"
|
||||
ng-model="data.label"
|
||||
type="text" placeholder="Label">
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label" for="value">Montant</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" id="value" name="value"
|
||||
ng-model="data.value"
|
||||
type="number" placeholder="Value">
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label" for="category">Catégorie</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" id="category" name="category"
|
||||
ng-model="data.category"
|
||||
type="text" placeholder="Category">
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
103
src/operations/operations.html
Normal file
103
src/operations/operations.html
Normal file
@ -0,0 +1,103 @@
|
||||
<!-- vim: set tw=80 ts=2 sw=2 sts=2: -->
|
||||
<!--
|
||||
This file is part of Accountant.
|
||||
|
||||
Accountant is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Accountant is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<div>
|
||||
<div class="row">
|
||||
<table class="table table-striped table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-1">Date d'op.</th>
|
||||
<th>Libellé de l'opération</th>
|
||||
<th class="col-md-1">Montant</th>
|
||||
<th class="col-md-1">Solde</th>
|
||||
<th class="col-md-2">Catégorie</th>
|
||||
<th class="col-md-2">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<button class="btn btn-success" ng-click="operationsCtrl.add()">
|
||||
Ajouter
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id="{{ operation.id }}" class="form-inline"
|
||||
ng-class="{stroke: operation.canceled, italic: !operation.confirmed,
|
||||
warning: operation.sold < 0, danger: operation.sold < operationsCtrl.account.authorized_overdraft}"
|
||||
ng-repeat="operation in operationsCtrl.operations | orderBy:['-operation_date', '-value', 'label']">
|
||||
<td>
|
||||
{{ operation.operation_date | date:"yyyy-MM-dd" }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ operation.label }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ operation.value | currency:"€" }}
|
||||
</td>
|
||||
|
||||
<td ng-class="{'text-warning': operation.sold < 0, 'text-danger':
|
||||
operation.sold < operationsCtrl.account.authorized_overdraft}">
|
||||
{{ operation.sold | currency:"€" }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ operation.category }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="btn-group btn-group-xs">
|
||||
<!-- Edit operation, for non-canceled operation. -->
|
||||
<button type="button" class="btn btn-default"
|
||||
ng-if="!operation.canceled"
|
||||
operation-form-dialog ng-model="operation" title="edit">
|
||||
<span class="fa fa-pencil-square-o"></span>
|
||||
</button>
|
||||
|
||||
<!-- Toggle pointed operation, for non-canceled operations. -->
|
||||
<button type="button" class="btn btn-default"
|
||||
ng-if="!operation.canceled"
|
||||
ng-click="operationsCtrl.togglePointed(operation, rowform)"
|
||||
ng-class="{active: operation.pointed}" title="point">
|
||||
<span ng-class="{'fa fa-check-square-o': operation.pointed, 'fa fa-square-o': !operation.pointed}"></span>
|
||||
</button>
|
||||
|
||||
<!-- Toggle canceled operation. -->
|
||||
<button type="button" class="btn btn-default"
|
||||
ng-click="operationsCtrl.toggleCanceled(operation)"
|
||||
ng-if="operation.scheduled_operation_id && !rowform.$visible"
|
||||
ng-class="{active: operation.canceled}" title="cancel">
|
||||
<span class="fa fa-remove"></span>
|
||||
</button>
|
||||
|
||||
<!-- Delete operation, with confirm. -->
|
||||
<button type="button" class="btn btn-default"
|
||||
ng-if="operation.id && !operation.scheduled_operation_id"
|
||||
ng-click="operationsCtrl.delete(operation, $index)">
|
||||
<span class="fa fa-trash-o"></span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
Reference in New Issue
Block a user