Merge pull request #2592 from FinnStutzenstein/UserTable
New table design for users
This commit is contained in:
commit
7ad81274d0
@ -866,23 +866,23 @@ img {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Motion **/
|
/** Motion **/
|
||||||
#motion-table .row {
|
#motion-os-table .identifier-col {
|
||||||
border: 1px solid #ddd;
|
width: 50px;
|
||||||
border-top: 0px;
|
min-height: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .data-row:hover {
|
#motion-os-table .identifier-col > div {
|
||||||
background-color: #f5f5f5;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .data-row > div {
|
#motion-os-table .title-col {
|
||||||
padding: 10px 0px 10px 8px;
|
width: calc(100% - 50px);
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .header-row {
|
#motion-os-table .title-col, .os-table small {
|
||||||
border-top: 1px solid #ddd;
|
color: #555;
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.motion-toolbar, .speakers-toolbar {
|
.motion-toolbar, .speakers-toolbar {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
border-bottom: 1px solid #ddd;
|
border-bottom: 1px solid #ddd;
|
||||||
@ -890,6 +890,7 @@ img {
|
|||||||
height: 54px;
|
height: 54px;
|
||||||
margin: -20px -5px 50px -5px;
|
margin: -20px -5px 50px -5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.motion-toolbar:first-child {
|
.motion-toolbar:first-child {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
@ -899,77 +900,78 @@ img {
|
|||||||
padding: 12px 15px 10px 15px;
|
padding: 12px 15px 10px 15px;
|
||||||
|
|
||||||
}
|
}
|
||||||
.header-row > div {
|
|
||||||
|
/** OS-Table **/
|
||||||
|
.os-table .row {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.os-table .data-row:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.os-table .data-row > div {
|
||||||
|
padding: 10px 0px 10px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.os-table .header-row {
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.os-table .header-row > div {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .main-header {
|
.os-table .main-header {
|
||||||
width: calc(100% - 50px);
|
width: calc(100% - 50px);
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .main-header .form-inline {
|
.os-table .main-header .form-inline {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .content > div {
|
.os-table .content > div { /* horizontal blocks */
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .identifier-col {
|
.os-table .content > div > div { /* vertival blocks */
|
||||||
width: 50px;
|
|
||||||
min-height: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#motion-table .identifier-col > div {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#motion-table .title-col {
|
|
||||||
width: calc(100% - 50px);
|
|
||||||
}
|
|
||||||
|
|
||||||
#motion-table .title-col, #motion-table small {
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
#motion-table .content > div > div {
|
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .content > div > div:last-child {
|
.os-table .content > div > div:last-child {
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .row .centered {
|
.os-table .row .centered {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .row .col-xs-1 {
|
.os-table .row .col-xs-1 {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .row .col-xs-4 {
|
.os-table .projector {
|
||||||
|
width: 70px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.os-table .row .col-xs-4 {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .dropdown {
|
.os-table .dropdown {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .header-row .dropdown > span, #motion-table .sort-spacer {
|
.os-table .header-row .dropdown > span, .os-table .sort-spacer {
|
||||||
padding: 5px 10px 5px 10px;
|
padding: 5px 10px 5px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#motion-table .dropdown-entry {
|
.os-table .title {
|
||||||
padding: 5px 10px 5px 10px;
|
font-size: 115%;
|
||||||
display: inline-block;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#motion-table .title {
|
|
||||||
font-size: 110%;
|
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -699,32 +699,6 @@ angular.module('OpenSlidesApp.core', [
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
/*
|
|
||||||
* This filter filters all items in an array. If the filterArray is empty, the
|
|
||||||
* array is passed. The filterArray contains numbers of the multiselect, e. g. [1, 3, 4].
|
|
||||||
* Then, all items in the array are passed, if the item_id (get with id_function) matches
|
|
||||||
* one of the ids in filterArray. id_function could also return a list of ids. Example:
|
|
||||||
* Item 1 has two tags with ids [1, 4]. filterArray == [3, 4] --> match
|
|
||||||
*/
|
|
||||||
.filter('SelectMultipleFilter', [
|
|
||||||
function () {
|
|
||||||
return function (array, filterArray, idFunction) {
|
|
||||||
if (filterArray.length === 0) {
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
return Array.prototype.filter.call(array, function (item) {
|
|
||||||
var id = idFunction(item);
|
|
||||||
if (!id) {
|
|
||||||
return false;
|
|
||||||
} else if (typeof id === 'number') {
|
|
||||||
id = [id];
|
|
||||||
}
|
|
||||||
return _.intersection(id, filterArray).length > 0;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
// mark HTML as "trusted"
|
// mark HTML as "trusted"
|
||||||
.filter('trusted', [
|
.filter('trusted', [
|
||||||
'$sce',
|
'$sce',
|
||||||
|
@ -342,6 +342,91 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
.factory('Multiselect', [
|
||||||
|
function () {
|
||||||
|
var instance = function () {
|
||||||
|
var areFiltersSet = function () {
|
||||||
|
var areFiltersSet = false;
|
||||||
|
_.forEach(self.filters, function (filterList, filter) {
|
||||||
|
if (filterList.length > 0) {
|
||||||
|
areFiltersSet = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return areFiltersSet;
|
||||||
|
};
|
||||||
|
var resetFilters = function () {
|
||||||
|
_.forEach(self.filters, function (filterList, filter) {
|
||||||
|
self.filters[filter] = [];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var getFilterString = function (obj) {
|
||||||
|
var newList = [];
|
||||||
|
_.forEach(self.propertyList, function (property) {
|
||||||
|
newList.push(obj[property]);
|
||||||
|
});
|
||||||
|
_.forEach(self.propertyFunctionList, function (fn) {
|
||||||
|
newList.push(fn(obj));
|
||||||
|
});
|
||||||
|
_.forEach(self.propertyDict, function (idFunction, property) {
|
||||||
|
newList.push(_.map(obj[property], idFunction).join(' '));
|
||||||
|
});
|
||||||
|
return newList.join(' ');
|
||||||
|
};
|
||||||
|
var operate = function (filter, id) {
|
||||||
|
if (_.indexOf(self.filters[filter], id) > -1) {
|
||||||
|
// remove id
|
||||||
|
self.filters[filter] = _.filter(self.filters[filter], function (_id) {
|
||||||
|
return _id != id;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// add id
|
||||||
|
self.filters[filter].push(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var self = {
|
||||||
|
filters: {},
|
||||||
|
areFiltersSet: areFiltersSet,
|
||||||
|
resetFilters: resetFilters,
|
||||||
|
operate: operate,
|
||||||
|
getFilterString: getFilterString,
|
||||||
|
};
|
||||||
|
resetFilters(); //Initiate filters
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
instance: instance
|
||||||
|
};
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This filter filters all items in an array. If the filterArray is empty, the
|
||||||
|
* array is passed. The filterArray contains numbers of the multiselect, e. g. [1, 3, 4].
|
||||||
|
* Then, all items in the array are passed, if the item_id (get with id_function) matches
|
||||||
|
* one of the ids in filterArray. id_function could also return a list of ids. Example:
|
||||||
|
* Item 1 has two tags with ids [1, 4]. filterArray == [3, 4] --> match
|
||||||
|
*/
|
||||||
|
.filter('MultiselectFilter', [
|
||||||
|
function () {
|
||||||
|
return function (array, filterArray, idFunction) {
|
||||||
|
if (filterArray.length === 0) {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
return Array.prototype.filter.call(array, function (item) {
|
||||||
|
var id = idFunction(item);
|
||||||
|
if (!id) {
|
||||||
|
return false;
|
||||||
|
} else if (typeof id === 'number') {
|
||||||
|
id = [id];
|
||||||
|
}
|
||||||
|
return _.intersection(id, filterArray).length > 0;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
// Load the django url patterns
|
// Load the django url patterns
|
||||||
.run([
|
.run([
|
||||||
'runtimeStates',
|
'runtimeStates',
|
||||||
|
@ -653,6 +653,33 @@ angular.module('OpenSlidesApp.motions.site', [
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
.factory('MotionCsvExport', [
|
||||||
|
function () {
|
||||||
|
return function (element, motions) {
|
||||||
|
var csvRows = [
|
||||||
|
['identifier', 'title', 'text', 'reason', 'submitter', 'category', 'origin'],
|
||||||
|
];
|
||||||
|
_.forEach(motions, function (motion) {
|
||||||
|
var row = [];
|
||||||
|
row.push('"' + motion.identifier + '"');
|
||||||
|
row.push('"' + motion.getTitle() + '"');
|
||||||
|
row.push('"' + motion.getText() + '"');
|
||||||
|
row.push('"' + motion.getReason() + '"');
|
||||||
|
row.push('"' + motion.submitters[0].get_full_name() + '"');
|
||||||
|
var category = motion.category ? motion.category.name : '';
|
||||||
|
row.push('"' + category + '"');
|
||||||
|
row.push('"' + motion.origin + '"');
|
||||||
|
csvRows.push(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
var csvString = csvRows.join("%0A");
|
||||||
|
element.href = 'data:text/csv;charset=utf-8,' + csvString;
|
||||||
|
element.download = 'motions-export.csv';
|
||||||
|
element.target = '_blank';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
// Cache for MotionPollDetailCtrl so that users choices are keeped during user actions (e. g. save poll form).
|
// Cache for MotionPollDetailCtrl so that users choices are keeped during user actions (e. g. save poll form).
|
||||||
.value('MotionPollDetailCtrlCache', {})
|
.value('MotionPollDetailCtrlCache', {})
|
||||||
|
|
||||||
@ -723,9 +750,11 @@ angular.module('OpenSlidesApp.motions.site', [
|
|||||||
'HTMLValidizer',
|
'HTMLValidizer',
|
||||||
'Projector',
|
'Projector',
|
||||||
'ProjectionDefault',
|
'ProjectionDefault',
|
||||||
|
'MotionCsvExport',
|
||||||
|
'Multiselect',
|
||||||
function($scope, $state, $http, ngDialog, MotionForm, Motion, Category, Tag, Workflow, User, Agenda, MotionBlock,
|
function($scope, $state, $http, ngDialog, MotionForm, Motion, Category, Tag, Workflow, User, Agenda, MotionBlock,
|
||||||
MotionDocxExport, MotionContentProvider, MotionCatalogContentProvider, PdfMakeConverter, PdfMakeDocumentProvider,
|
MotionDocxExport, MotionContentProvider, MotionCatalogContentProvider, PdfMakeConverter, PdfMakeDocumentProvider,
|
||||||
gettextCatalog, HTMLValidizer, Projector, ProjectionDefault) {
|
gettextCatalog, HTMLValidizer, Projector, ProjectionDefault, MotionCsvExport, Multiselect) {
|
||||||
Motion.bindAll({}, $scope, 'motions');
|
Motion.bindAll({}, $scope, 'motions');
|
||||||
Category.bindAll({}, $scope, 'categories');
|
Category.bindAll({}, $scope, 'categories');
|
||||||
MotionBlock.bindAll({}, $scope, 'motionBlocks');
|
MotionBlock.bindAll({}, $scope, 'motionBlocks');
|
||||||
@ -743,35 +772,65 @@ angular.module('OpenSlidesApp.motions.site', [
|
|||||||
});
|
});
|
||||||
$scope.alert = {};
|
$scope.alert = {};
|
||||||
|
|
||||||
// setup table sorting
|
$scope.multiselect = Multiselect.instance();
|
||||||
$scope.sortColumn = 'identifier';
|
$scope.multiselect.filters = {
|
||||||
$scope.filterPresent = '';
|
|
||||||
$scope.reverse = false;
|
|
||||||
|
|
||||||
$scope.multiselectFilter = {
|
|
||||||
state: [],
|
state: [],
|
||||||
category: [],
|
category: [],
|
||||||
motionBlock: [],
|
motionBlock: [],
|
||||||
tag: []
|
tag: []
|
||||||
};
|
};
|
||||||
|
$scope.multiselect.propertyList = ['identifier', 'origin'];
|
||||||
|
$scope.multiselect.propertyFunctionList = [
|
||||||
|
function (motion) {return motion.getTitle();},
|
||||||
|
function (motion) {return motion.getText();},
|
||||||
|
function (motion) {return motion.getReason();},
|
||||||
|
function (motion) {return motion.category ? motion.category.name : '';},
|
||||||
|
function (motion) {return motion.motionBlock ? motion.motionBlock.name : '';},
|
||||||
|
];
|
||||||
|
$scope.multiselect.PropertyDict = {
|
||||||
|
'submitters' : function (submitter) {
|
||||||
|
return submitter.get_short_name();
|
||||||
|
},
|
||||||
|
'supporters' : function (submitter) {
|
||||||
|
return supporter.get_short_name();
|
||||||
|
},
|
||||||
|
'tags' : function (tag) {
|
||||||
|
return tag.name;
|
||||||
|
},
|
||||||
|
};
|
||||||
$scope.getItemId = {
|
$scope.getItemId = {
|
||||||
state: function (motion) {return motion.state_id;},
|
state: function (motion) {return motion.state_id;},
|
||||||
category: function (motion) {return motion.category_id;},
|
category: function (motion) {return motion.category_id;},
|
||||||
motionBlock: function (motion) {return motion.motion_block_id;},
|
motionBlock: function (motion) {return motion.motion_block_id;},
|
||||||
tag: function (motion) {return motion.tags_id;}
|
tag: function (motion) {return motion.tags_id;}
|
||||||
};
|
};
|
||||||
|
// setup table sorting
|
||||||
|
$scope.sortOptions = [
|
||||||
|
{name: 'identifier',
|
||||||
|
display_name: 'Identifier'},
|
||||||
|
{name: 'getTitle()',
|
||||||
|
display_name: 'Title'},
|
||||||
|
{name: 'submitters',
|
||||||
|
display_name: 'Submitters'},
|
||||||
|
{name: 'category.name',
|
||||||
|
display_name: 'Category'},
|
||||||
|
{name: 'motionBlock.title',
|
||||||
|
display_name: 'Motion block'},
|
||||||
|
{name: 'state.name',
|
||||||
|
display_name: 'State'},
|
||||||
|
{name: 'log_messages[log_messages.length-1].time',
|
||||||
|
display_name: 'Creation date'},
|
||||||
|
{name: 'log_messages[0].time',
|
||||||
|
display_name: 'Last modified'},
|
||||||
|
];
|
||||||
|
$scope.sortColumn = 'identifier';
|
||||||
|
$scope.filterPresent = '';
|
||||||
|
$scope.reverse = false;
|
||||||
|
|
||||||
// function to operate the multiselectFilter
|
// function to operate the multiselectFilter
|
||||||
$scope.operateMultiselectFilter = function (filter, id) {
|
$scope.operateMultiselectFilter = function (filter, id) {
|
||||||
if (!$scope.isDeleteMode) {
|
if (!$scope.isDeleteMode) {
|
||||||
if (_.indexOf($scope.multiselectFilter[filter], id) > -1) {
|
$scope.multiselect.operate(filter, id);
|
||||||
// remove id
|
|
||||||
$scope.multiselectFilter[filter] = _.filter($scope.multiselectFilter[filter], function (_id) {
|
|
||||||
return _id != id;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// add id
|
|
||||||
$scope.multiselectFilter[filter].push(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// function to sort by clicked column
|
// function to sort by clicked column
|
||||||
@ -781,61 +840,15 @@ angular.module('OpenSlidesApp.motions.site', [
|
|||||||
}
|
}
|
||||||
$scope.sortColumn = column;
|
$scope.sortColumn = column;
|
||||||
};
|
};
|
||||||
// define custom search filter string
|
|
||||||
$scope.getFilterString = function (motion) {
|
|
||||||
var category = '';
|
|
||||||
if (motion.category) {
|
|
||||||
category = motion.category.name;
|
|
||||||
}
|
|
||||||
var motionBlock = '';
|
|
||||||
if (motion.motionBlock) {
|
|
||||||
motionBlock = motion.motionBlock.title;
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
motion.identifier,
|
|
||||||
motion.getTitle(),
|
|
||||||
motion.getText(),
|
|
||||||
motion.getReason(),
|
|
||||||
motion.origin,
|
|
||||||
_.map(
|
|
||||||
motion.submitters,
|
|
||||||
function (submitter) {
|
|
||||||
return submitter.get_short_name();
|
|
||||||
}
|
|
||||||
).join(" "),
|
|
||||||
_.map(
|
|
||||||
motion.supporters,
|
|
||||||
function (supporter) {
|
|
||||||
return supporter.get_short_name();
|
|
||||||
}
|
|
||||||
).join(" "),
|
|
||||||
_.map(
|
|
||||||
motion.tags,
|
|
||||||
function (tag) {
|
|
||||||
return tag.name;
|
|
||||||
}
|
|
||||||
).join(" "),
|
|
||||||
category,
|
|
||||||
motionBlock
|
|
||||||
].join(" ");
|
|
||||||
};
|
|
||||||
// for reset-button
|
// for reset-button
|
||||||
$scope.reset_filters = function () {
|
$scope.resetFilters = function () {
|
||||||
$scope.multiselectFilter = {
|
$scope.multiselect.resetFilters();
|
||||||
state: [],
|
|
||||||
category: [],
|
|
||||||
motionBlock: [],
|
|
||||||
tag: []
|
|
||||||
};
|
|
||||||
if ($scope.filter) {
|
if ($scope.filter) {
|
||||||
$scope.filter.search = '';
|
$scope.filter.search = '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
$scope.are_filters_set = function () {
|
$scope.areFiltersSet = function () {
|
||||||
return $scope.multiselectFilter.state.length > 0 ||
|
return $scope.multiselect.areFiltersSet() ||
|
||||||
$scope.multiselectFilter.category.length > 0 ||
|
|
||||||
$scope.multiselectFilter.motionBlock.length > 0 ||
|
|
||||||
$scope.multiselectFilter.tag.length > 0 ||
|
|
||||||
($scope.filter ? $scope.filter.search : false);
|
($scope.filter ? $scope.filter.search : false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -910,7 +923,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Export as a pdf file
|
// Export as a pdf file
|
||||||
$scope.pdf_export = function() {
|
$scope.pdfExport = function() {
|
||||||
var filename = gettextCatalog.getString("Motions") + ".pdf";
|
var filename = gettextCatalog.getString("Motions") + ".pdf";
|
||||||
var image_sources = [];
|
var image_sources = [];
|
||||||
|
|
||||||
@ -940,31 +953,12 @@ angular.module('OpenSlidesApp.motions.site', [
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Export as a csv file
|
// Export as a csv file
|
||||||
$scope.csv_export = function () {
|
$scope.csvExport = function () {
|
||||||
var element = document.getElementById('downloadLinkCSV');
|
var element = document.getElementById('downloadLinkCSV');
|
||||||
var csvRows = [
|
MotionCsvExport(element, $scope.motionsFiltered);
|
||||||
['identifier', 'title', 'text', 'reason', 'submitter', 'category', 'origin'],
|
|
||||||
];
|
|
||||||
angular.forEach($scope.motionsFiltered, function (motion) {
|
|
||||||
var row = [];
|
|
||||||
row.push('"' + motion.identifier + '"');
|
|
||||||
row.push('"' + motion.getTitle() + '"');
|
|
||||||
row.push('"' + motion.getText() + '"');
|
|
||||||
row.push('"' + motion.getReason() + '"');
|
|
||||||
row.push('"' + motion.submitters[0].get_full_name() + '"');
|
|
||||||
var category = motion.category ? motion.category.name : '';
|
|
||||||
row.push('"' + category + '"');
|
|
||||||
row.push('"' + motion.origin + '"');
|
|
||||||
csvRows.push(row);
|
|
||||||
});
|
|
||||||
|
|
||||||
var csvString = csvRows.join("%0A");
|
|
||||||
element.href = 'data:text/csv;charset=utf-8,' + csvString;
|
|
||||||
element.download = 'motions-export.csv';
|
|
||||||
element.target = '_blank';
|
|
||||||
};
|
};
|
||||||
// Export as docx file
|
// Export as docx file
|
||||||
$scope.docx_export = function () {
|
$scope.docxExport = function () {
|
||||||
MotionDocxExport.export($scope.motionsFiltered, $scope.categories);
|
MotionDocxExport.export($scope.motionsFiltered, $scope.categories);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownExport">
|
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownExport">
|
||||||
<!-- PDF export -->
|
<!-- PDF export -->
|
||||||
<li>
|
<li>
|
||||||
<a href="" ng-click="pdf_export()">
|
<a href="" ng-click="pdfExport()">
|
||||||
<i class="fa fa-file-pdf-o fa-lg"></i>
|
<i class="fa fa-file-pdf-o fa-lg"></i>
|
||||||
PDF
|
PDF
|
||||||
</a>
|
</a>
|
||||||
@ -59,14 +59,14 @@
|
|||||||
<!-- CSV export -->
|
<!-- CSV export -->
|
||||||
<li>
|
<li>
|
||||||
<a href="" id="downloadLinkCSV"
|
<a href="" id="downloadLinkCSV"
|
||||||
ng-click="csv_export()">
|
ng-click="csvExport()">
|
||||||
<i class="fa fa-file-text-o fa-lg"></i>
|
<i class="fa fa-file-text-o fa-lg"></i>
|
||||||
CSV
|
CSV
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<!-- DOCX export -->
|
<!-- DOCX export -->
|
||||||
<li>
|
<li>
|
||||||
<a href="" ng-click="docx_export()">
|
<a href="" ng-click="docxExport()">
|
||||||
<i class="fa fa-file-word-o fa-lg"></i>
|
<i class="fa fa-file-word-o fa-lg"></i>
|
||||||
DOCX
|
DOCX
|
||||||
</a>
|
</a>
|
||||||
@ -95,7 +95,7 @@
|
|||||||
{{(motions|filter:{selected:true}).length}} {{ "selected" | translate }}</span>
|
{{(motions|filter:{selected:true}).length}} {{ "selected" | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="motion-table" class="container-fluid">
|
<div id="motion-os-table" class="os-table container-fluid">
|
||||||
<div class="row header-row">
|
<div class="row header-row">
|
||||||
<div class="col-xs-1 centered" ng-show="isDeleteMode">
|
<div class="col-xs-1 centered" ng-show="isDeleteMode">
|
||||||
<i class="fa text-danger pointer" ng-class=" selectedAll ? 'fa-check-square-o' : 'fa-square-o'"
|
<i class="fa text-danger pointer" ng-class=" selectedAll ? 'fa-check-square-o' : 'fa-square-o'"
|
||||||
@ -103,8 +103,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-xs-11 main-header">
|
<div class="col-xs-11 main-header">
|
||||||
<span class="form-inline text-right pull-right">
|
<span class="form-inline text-right pull-right">
|
||||||
<span class="sort-spacer pointer" ng-click="reset_filters()"
|
<span class="sort-spacer pointer" ng-click="resetFilters()"
|
||||||
ng-if="are_filters_set()" ng-disabled="isDeleteMode"
|
ng-if="areFiltersSet()" ng-disabled="isDeleteMode"
|
||||||
ng-class="{'disabled': isDeleteMode}">
|
ng-class="{'disabled': isDeleteMode}">
|
||||||
<i class="fa fa-times-circle"></i>
|
<i class="fa fa-times-circle"></i>
|
||||||
<translate>Filter</translate>
|
<translate>Filter</translate>
|
||||||
@ -112,19 +112,19 @@
|
|||||||
<!-- State filter -->
|
<!-- State filter -->
|
||||||
<span class="dropdown" uib-dropdown>
|
<span class="dropdown" uib-dropdown>
|
||||||
<span class="pointer" id="dropdownState" uib-dropdown-toggle
|
<span class="pointer" id="dropdownState" uib-dropdown-toggle
|
||||||
ng-class="{'bold': multiselectFilter.state.length > 0, 'disabled': isDeleteMode}"
|
ng-class="{'bold': multiselect.filters.state.length > 0, 'disabled': isDeleteMode}"
|
||||||
ng-disabled="isDeleteMode">
|
ng-disabled="isDeleteMode">
|
||||||
<translate>State</translate>
|
<translate>State</translate>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</span>
|
</span>
|
||||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownState">
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownState">
|
||||||
<li ng-repeat="state in states" ng-class="state.workflowHeader ? 'dropdown-header' : ''">
|
<li ng-repeat="state in states" ng-class="state.workflowHeader ? 'dropdown-header' : ''">
|
||||||
<div class="dropdown-entry pointer" ng-if="state.workflowHeader">
|
<div ng-if="state.workflowHeader">
|
||||||
{{ state.name | translate }}
|
{{ state.name | translate }}
|
||||||
</div>
|
</div>
|
||||||
<div class="dropdown-entry pointer" ng-if="!state.workflowHeader"
|
<div ng-if="!state.workflowHeader"
|
||||||
ng-click="operateMultiselectFilter('state', state.id)">
|
ng-click="operateMultiselectFilter('state', state.id)">
|
||||||
<i class="fa fa-check" ng-if="multiselectFilter.state.indexOf(state.id) > -1"></i>
|
<i class="fa fa-check" ng-if="multiselect.filters.state.indexOf(state.id) > -1"></i>
|
||||||
{{ state.name | translate }}
|
{{ state.name | translate }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -133,17 +133,16 @@
|
|||||||
<!-- Category filter -->
|
<!-- Category filter -->
|
||||||
<span class="dropdown" uib-dropdown ng-if="categories.length > 0">
|
<span class="dropdown" uib-dropdown ng-if="categories.length > 0">
|
||||||
<span class="pointer" id="dropdownCategory" uib-dropdown-toggle
|
<span class="pointer" id="dropdownCategory" uib-dropdown-toggle
|
||||||
ng-class="{'bold': multiselectFilter.category.length > 0, 'disabled': isDeleteMode}"
|
ng-class="{'bold': multiselect.filters.category.length > 0, 'disabled': isDeleteMode}"
|
||||||
ng-disabled="isDeleteMode">
|
ng-disabled="isDeleteMode">
|
||||||
<translate>Category</translate>
|
<translate>Category</translate>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</span>
|
</span>
|
||||||
<ul class="dropdown-menu dropdown-menu-right"
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries"
|
||||||
aria-labelledby="dropdownCategory">
|
aria-labelledby="dropdownCategory">
|
||||||
<li ng-repeat="category in categories">
|
<li ng-repeat="category in categories">
|
||||||
<div class="dropdown-entry pointer"
|
<div ng-click="operateMultiselectFilter('category', category.id)">
|
||||||
ng-click="operateMultiselectFilter('category', category.id)">
|
<i class="fa fa-check" ng-if="multiselect.filters.category.indexOf(category.id) > -1"></i>
|
||||||
<i class="fa fa-check" ng-if="multiselectFilter.category.indexOf(category.id) > -1"></i>
|
|
||||||
{{ category.name }}
|
{{ category.name }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -152,17 +151,16 @@
|
|||||||
<!-- Motion block filter -->
|
<!-- Motion block filter -->
|
||||||
<span class="dropdown" uib-dropdown ng-if="motionBlocks.length > 0">
|
<span class="dropdown" uib-dropdown ng-if="motionBlocks.length > 0">
|
||||||
<span class="pointer" id="dropdownBlock" uib-dropdown-toggle
|
<span class="pointer" id="dropdownBlock" uib-dropdown-toggle
|
||||||
ng-class="{'bold': multiselectFilter.motionBlock.length > 0, 'disabled': isDeleteMode}"
|
ng-class="{'bold': multiselect.filters.motionBlock.length > 0, 'disabled': isDeleteMode}"
|
||||||
ng-disabled="isDeleteMode">
|
ng-disabled="isDeleteMode">
|
||||||
<translate>Motion block</translate>
|
<translate>Motion block</translate>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</span>
|
</span>
|
||||||
<ul class="dropdown-menu dropdown-menu-right"
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries"
|
||||||
aria-labelledby="dropdownBlock">
|
aria-labelledby="dropdownBlock">
|
||||||
<li ng-repeat="block in motionBlocks">
|
<li ng-repeat="block in motionBlocks">
|
||||||
<div class="dropdown-entry pointer"
|
<div ng-click="operateMultiselectFilter('motionBlock', block.id)">
|
||||||
ng-click="operateMultiselectFilter('motionBlock', block.id)">
|
<i class="fa fa-check" ng-if="multiselect.filters.motionBlock.indexOf(block.id) > -1"></i>
|
||||||
<i class="fa fa-check" ng-if="multiselectFilter.motionBlock.indexOf(block.id) > -1"></i>
|
|
||||||
{{ block.title }}
|
{{ block.title }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -171,17 +169,16 @@
|
|||||||
<!-- Tag filter -->
|
<!-- Tag filter -->
|
||||||
<span class="dropdown" uib-dropdown ng-if="tags.length > 0">
|
<span class="dropdown" uib-dropdown ng-if="tags.length > 0">
|
||||||
<span class="pointer" id="dropdownTag" uib-dropdown-toggle
|
<span class="pointer" id="dropdownTag" uib-dropdown-toggle
|
||||||
ng-class="{'bold': multiselectFilter.tag.length > 0, 'disabled': isDeleteMode}"
|
ng-class="{'bold': multiselect.filters.tag.length > 0, 'disabled': isDeleteMode}"
|
||||||
ng-disabled="isDeleteMode">
|
ng-disabled="isDeleteMode">
|
||||||
<translate>Tag</translate>
|
<translate>Tag</translate>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</span>
|
</span>
|
||||||
<ul class="dropdown-menu dropdown-menu-right"
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries"
|
||||||
aria-labelledby="dropdownTag">
|
aria-labelledby="dropdownTag">
|
||||||
<li ng-repeat="tag in tags">
|
<li ng-repeat="tag in tags">
|
||||||
<div class="dropdown-entry pointer"
|
<div ng-click="operateMultiselectFilter('tag', tag.id)">
|
||||||
ng-click="operateMultiselectFilter('tag', tag.id)">
|
<i class="fa fa-check" ng-if="multiselect.filters.tag.indexOf(tag.id) > -1"></i>
|
||||||
<i class="fa fa-check" ng-if="multiselectFilter.tag.indexOf(tag.id) > -1"></i>
|
|
||||||
{{ tag.name }}
|
{{ tag.name }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
@ -195,106 +192,29 @@
|
|||||||
<translate>Sort</translate>
|
<translate>Sort</translate>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</span>
|
</span>
|
||||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownSort">
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownSort">
|
||||||
<li>
|
|
||||||
<!-- item -->
|
<!-- item -->
|
||||||
<div class="pointer dropdown-entry" ng-click="toggleSort('agenda_item.getItemNumberWithAncestors()')">
|
<li>
|
||||||
|
<div ng-click="toggleSort('agenda_item.getItemNumberWithAncestors()')">
|
||||||
<translate translate-comment="short form of agenda item">Item</translate>
|
<translate translate-comment="short form of agenda item">Item</translate>
|
||||||
<span class="spacer-right pull-right"></span>
|
<span class="spacer-right pull-right"></span>
|
||||||
<i class="pull-right fa"
|
<i class="pull-right fa"
|
||||||
ng-style="{'visibility': sortColumn === 'agenda_item.getItemNumberWithAncestors()' && header.sortable != false ? 'visible' : 'hidden'}"
|
ng-style="{'visibility': sortColumn === 'agenda_item.getItemNumberWithAncestors()' ? 'visible' : 'hidden'}"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<!-- all other sortOptions -->
|
||||||
<!-- indentifier -->
|
<li ng-repeat="option in sortOptions">
|
||||||
<div class="pointer dropdown-entry" ng-click="toggleSort('identifier')">
|
<div ng-click="toggleSort(option.name)">
|
||||||
<translate>Identifier</translate>
|
{{ option.display_name | translate }}
|
||||||
<span class="spacer-right pull-right"></span>
|
<span class="spacer-right pull-right"></span>
|
||||||
<i class="pull-right fa"
|
<i class="pull-right fa"
|
||||||
ng-style="{'visibility': sortColumn === 'identifier' && header.sortable != false ? 'visible' : 'hidden'}"
|
ng-style="{'visibility': sortColumn === option.name ? 'visible' : 'hidden'}"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<!-- title -->
|
|
||||||
<div class="pointer dropdown-entry" ng-click="toggleSort('getTitle()')">
|
|
||||||
<translate>Title</translate>
|
|
||||||
<span class="spacer-right pull-right"></span>
|
|
||||||
<i class="pull-right fa"
|
|
||||||
ng-style="{'visibility': sortColumn === 'getTitle()' && header.sortable != false ? 'visible' : 'hidden'}"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<!-- submitters -->
|
|
||||||
<div class="pointer dropdown-entry" ng-click="toggleSort('submitters')">
|
|
||||||
<translate>Submitters</translate>
|
|
||||||
<span class="spacer-right pull-right"></span>
|
|
||||||
<i class="pull-right fa"
|
|
||||||
ng-style="{'visibility': sortColumn === 'submitters' && header.sortable != false ? 'visible' : 'hidden'}"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<!-- category -->
|
|
||||||
<div class="pointer dropdown-entry" ng-click="toggleSort('category.name')">
|
|
||||||
<translate>Category</translate>
|
|
||||||
<span class="spacer-right pull-right"></span>
|
|
||||||
<i class="pull-right fa"
|
|
||||||
ng-style="{'visibility': sortColumn === 'category.name' && header.sortable != false ? 'visible' : 'hidden'}"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<!-- motion block -->
|
|
||||||
<div class="pointer dropdown-entry" ng-click="toggleSort('motionBlock.title')">
|
|
||||||
<translate>Motion block</translate>
|
|
||||||
<span class="spacer-right pull-right"></span>
|
|
||||||
<i class="pull-right fa"
|
|
||||||
ng-style="{'visibility': sortColumn === 'motionBlock.title' && header.sortable != false ? 'visible' : 'hidden'}"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<!-- state -->
|
|
||||||
<div class="pointer dropdown-entry" ng-click="toggleSort('state.name')">
|
|
||||||
<translate>State</translate>
|
|
||||||
<span class="spacer-right pull-right"></span>
|
|
||||||
<i class="pull-right fa"
|
|
||||||
ng-style="{'visibility': sortColumn === 'state.name' && header.sortable != false ? 'visible' : 'hidden'}"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<!-- creation date -->
|
|
||||||
<div class="pointer dropdown-entry" ng-click="toggleSort('log_messages[log_messages.length-1].time')">
|
|
||||||
<translate>Creation date</translate>
|
|
||||||
<span class="spacer-right pull-right"></span>
|
|
||||||
<i class="pull-right fa"
|
|
||||||
ng-style="{'visibility': sortColumn === 'log_messages[log_messages.length-1].time' && header.sortable != false ? 'visible' : 'hidden'}"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<!-- last modified -->
|
|
||||||
<div class="pointer dropdown-entry" ng-click="toggleSort('log_messages[0].time')">
|
|
||||||
<translate>Last modified</translate>
|
|
||||||
<span class="spacer-right pull-right"></span>
|
|
||||||
<i class="pull-right fa"
|
|
||||||
ng-style="{'visibility': sortColumn === 'log_messages[0].time' && header.sortable != false ? 'visible' : 'hidden'}"
|
|
||||||
ng-class="reverse ? 'fa-sort-asc' : 'fa-sort-desc'">
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</span>
|
</span>
|
||||||
<!-- search field -->
|
<!-- search field -->
|
||||||
@ -309,7 +229,7 @@
|
|||||||
<!-- show all selected multiselectoptions -->
|
<!-- show all selected multiselectoptions -->
|
||||||
<span>
|
<span>
|
||||||
<span ng-repeat="state in states" class="pointer spacer-left-lg"
|
<span ng-repeat="state in states" class="pointer spacer-left-lg"
|
||||||
ng-if="!state.workflowHeader && multiselectFilter.state.indexOf(state.id) > -1"
|
ng-if="!state.workflowHeader && multiselect.filters.state.indexOf(state.id) > -1"
|
||||||
ng-click="operateMultiselectFilter('state', state.id)"
|
ng-click="operateMultiselectFilter('state', state.id)"
|
||||||
ng-class="{'disabled': isDeleteMode}">
|
ng-class="{'disabled': isDeleteMode}">
|
||||||
<span class="nobr">
|
<span class="nobr">
|
||||||
@ -318,7 +238,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span ng-repeat="category in categories" class="pointer spacer-left-lg"
|
<span ng-repeat="category in categories" class="pointer spacer-left-lg"
|
||||||
ng-if="multiselectFilter.category.indexOf(category.id) > -1"
|
ng-if="multiselect.filters.category.indexOf(category.id) > -1"
|
||||||
ng-click="operateMultiselectFilter('category', category.id)"
|
ng-click="operateMultiselectFilter('category', category.id)"
|
||||||
ng-class="{'disabled': isDeleteMode}">
|
ng-class="{'disabled': isDeleteMode}">
|
||||||
<span class="nobr">
|
<span class="nobr">
|
||||||
@ -327,7 +247,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span ng-repeat="motionBlock in motionBlocks" class="pointer spacer-left-lg"
|
<span ng-repeat="motionBlock in motionBlocks" class="pointer spacer-left-lg"
|
||||||
ng-if="multiselectFilter.motionBlock.indexOf(motionBlock.id) > -1"
|
ng-if="multiselect.filters.motionBlock.indexOf(motionBlock.id) > -1"
|
||||||
ng-click="operateMultiselectFilter('motionBlock', motionBlock.id)"
|
ng-click="operateMultiselectFilter('motionBlock', motionBlock.id)"
|
||||||
ng-class="{'disabled': isDeleteMode}">
|
ng-class="{'disabled': isDeleteMode}">
|
||||||
<span class="nobr">
|
<span class="nobr">
|
||||||
@ -336,7 +256,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span ng-repeat="tag in tags" class="pointer spacer-left-lg"
|
<span ng-repeat="tag in tags" class="pointer spacer-left-lg"
|
||||||
ng-if="multiselectFilter.tag.indexOf(tag.id) > -1"
|
ng-if="multiselect.flters.tag.indexOf(tag.id) > -1"
|
||||||
ng-click="operateMultiselectFilter('tag', tag.id)"
|
ng-click="operateMultiselectFilter('tag', tag.id)"
|
||||||
ng-class="{'disabled': isDeleteMode}">
|
ng-class="{'disabled': isDeleteMode}">
|
||||||
<span class="nobr">
|
<span class="nobr">
|
||||||
@ -349,27 +269,25 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- main table -->
|
<!-- main table -->
|
||||||
<!-- data row -->
|
|
||||||
<div class="row data-row" ng-mouseover="motion.hover=true"
|
<div class="row data-row" ng-mouseover="motion.hover=true"
|
||||||
ng-mouseleave="motion.hover=false"
|
ng-mouseleave="motion.hover=false"
|
||||||
ng-class="{'projected': motion.isProjected().length}"
|
ng-class="{'projected': motion.isProjected().length}"
|
||||||
ng-repeat="motion in motionsFiltered = (motions
|
ng-repeat="motion in motionsFiltered = (motions
|
||||||
| osFilter: filter.search : getFilterString
|
| osFilter: filter.search : multiselect.getFilterString
|
||||||
| SelectMultipleFilter: multiselectFilter.state : getItemId.state
|
| MultiselectFilter: multiselect.filters.state : getItemId.state
|
||||||
| SelectMultipleFilter: multiselectFilter.category : getItemId.category
|
| MultiselectFilter: multiselect.filters.category : getItemId.category
|
||||||
| SelectMultipleFilter: multiselectFilter.motionBlock : getItemId.motionBlock
|
| MultiselectFilter: multiselect.filters.motionBlock : getItemId.motionBlock
|
||||||
| SelectMultipleFilter: multiselectFilter.tag : getItemId.tag
|
| MultiselectFilter: multiselect.filters.tag : getItemId.tag
|
||||||
| toArray
|
| toArray
|
||||||
| orderBy: sortColumn : reverse)">
|
| orderBy: sortColumn : reverse)">
|
||||||
|
|
||||||
<!-- select column -->
|
<!-- select column -->
|
||||||
<div ng-show="isDeleteMode" os-perms="motions.can_manage"
|
<div ng-show="isDeleteMode" os-perms="motions.can_manage" class="col-xs-1 centered">
|
||||||
class="col-xs-1 centered" ng-class="{'deleteColumn' : motion.selected}">
|
|
||||||
<i class="fa text-danger pointer" ng-click="motion.selected=!motion.selected"
|
<i class="fa text-danger pointer" ng-click="motion.selected=!motion.selected"
|
||||||
ng-class="motion.selected ? 'fa-check-square-o' : 'fa-square-o'"></i>
|
ng-class="motion.selected ? 'fa-check-square-o' : 'fa-square-o'"></i>
|
||||||
</div>
|
</div>
|
||||||
<!-- projector column -->
|
<!-- projector column -->
|
||||||
<div class="col-xs-1 centered" os-perms="core.can_manage_projector">
|
<div class="col-xs-1 centered projector" os-perms="core.can_manage_projector">
|
||||||
<projector-button model="motion", default-projector-id="defaultProjectorId">
|
<projector-button model="motion", default-projector-id="defaultProjectorId">
|
||||||
</projector-button>
|
</projector-button>
|
||||||
</div>
|
</div>
|
||||||
@ -437,7 +355,7 @@
|
|||||||
<!-- additional content column -->
|
<!-- additional content column -->
|
||||||
<style>
|
<style>
|
||||||
#motion-table .row .col-xs-4 {
|
#motion-table .row .col-xs-4 {
|
||||||
width: calc(50% - {{ isDeleteMode ? '100' : '50' }}px);
|
width: calc(50% - {{ isDeleteMode ? '120' : '70' }}px);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="col-xs-4 content">
|
<div class="col-xs-4 content">
|
||||||
@ -447,7 +365,7 @@
|
|||||||
<div os-perms="motions.can_manage" ng-show="categories.length > 0"
|
<div os-perms="motions.can_manage" ng-show="categories.length > 0"
|
||||||
ng-mouseover="motion.categoryHover=true"
|
ng-mouseover="motion.categoryHover=true"
|
||||||
ng-mouseleave="motion.categoryHover=false">
|
ng-mouseleave="motion.categoryHover=false">
|
||||||
<span uib-dropdown >
|
<span uib-dropdown>
|
||||||
<span id="dropdown-category{{ motion.id }}" class="pointer"
|
<span id="dropdown-category{{ motion.id }}" class="pointer"
|
||||||
uib-dropdown-toggle uib-tooltip="{{ 'Set a category' | translate }}"
|
uib-dropdown-toggle uib-tooltip="{{ 'Set a category' | translate }}"
|
||||||
tooltip-class="nobr">
|
tooltip-class="nobr">
|
||||||
@ -461,10 +379,9 @@
|
|||||||
<i class="fa fa-cog fa-lg spacer-left" ng-show="motion.categoryHover"></i>
|
<i class="fa fa-cog fa-lg spacer-left" ng-show="motion.categoryHover"></i>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdown-category{{ motion.id }}">
|
<ul class="dropdown-menu dropdown-entries" aria-labelledby="dropdown-category{{ motion.id }}">
|
||||||
<li ng-repeat="category in categories">
|
<li ng-repeat="category in categories">
|
||||||
<div class="dropdown-entry pointer"
|
<div ng-click="toggle_category(motion, category)">
|
||||||
ng-click="toggle_category(motion, category)">
|
|
||||||
<i class="fa fa-check" ng-if="category.id == motion.category.id"></i>
|
<i class="fa fa-check" ng-if="category.id == motion.category.id"></i>
|
||||||
{{ category.name }}
|
{{ category.name }}
|
||||||
</div>
|
</div>
|
||||||
@ -482,7 +399,7 @@
|
|||||||
<div os-perms="motions.can_manage" ng-show="motionBlocks.length > 0"
|
<div os-perms="motions.can_manage" ng-show="motionBlocks.length > 0"
|
||||||
ng-mouseover="motion.motionBlockHover=true"
|
ng-mouseover="motion.motionBlockHover=true"
|
||||||
ng-mouseleave="motion.motionBlockHover=false">
|
ng-mouseleave="motion.motionBlockHover=false">
|
||||||
<span uib-dropdown >
|
<span uib-dropdown>
|
||||||
<span id="dropdown-motionBlock{{ motion.id }}" class="pointer"
|
<span id="dropdown-motionBlock{{ motion.id }}" class="pointer"
|
||||||
uib-dropdown-toggle uib-tooltip="{{ 'Set a motion block' | translate }}"
|
uib-dropdown-toggle uib-tooltip="{{ 'Set a motion block' | translate }}"
|
||||||
tooltip-class="nobr">
|
tooltip-class="nobr">
|
||||||
@ -496,10 +413,9 @@
|
|||||||
<i class="fa fa-cog fa-lg spacer-left" ng-show="motion.motionBlockHover"></i>
|
<i class="fa fa-cog fa-lg spacer-left" ng-show="motion.motionBlockHover"></i>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdown-motionBlock{{ motion.id }}">
|
<ul class="dropdown-menu dropdown-entries" aria-labelledby="dropdown-motionBlock{{ motion.id }}">
|
||||||
<li ng-repeat="motionBlock in motionBlocks">
|
<li ng-repeat="motionBlock in motionBlocks">
|
||||||
<div class="dropdown-entry pointer"
|
<div ng-click="toggle_motionBlock(motion, motionBlock)">
|
||||||
ng-click="toggle_motionBlock(motion, motionBlock)">
|
|
||||||
<i class="fa fa-check" ng-if="motionBlock.id == motion.motionBlock.id"></i>
|
<i class="fa fa-check" ng-if="motionBlock.id == motion.motionBlock.id"></i>
|
||||||
{{ motionBlock.title }}
|
{{ motionBlock.title }}
|
||||||
</div>
|
</div>
|
||||||
@ -533,9 +449,9 @@
|
|||||||
<i class="fa fa-cog fa-lg spacer-left" ng-show="motion.tagHover"></i>
|
<i class="fa fa-cog fa-lg spacer-left" ng-show="motion.tagHover"></i>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdown-tags{{ motion.id }}">
|
<ul class="dropdown-menu dropdown-entries" aria-labelledby="dropdown-tags{{ motion.id }}">
|
||||||
<li ng-repeat="tag in tags">
|
<li ng-repeat="tag in tags">
|
||||||
<div class="dropdown-entry pointer" ng-click="toggle_tag(motion, tag)">
|
<div ng-click="toggle_tag(motion, tag)">
|
||||||
<i class="fa fa-check" ng-if="has_tag(motion, tag)"></i>
|
<i class="fa fa-check" ng-if="has_tag(motion, tag)"></i>
|
||||||
{{ tag.name }}
|
{{ tag.name }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,12 +11,12 @@ def get_config_variables():
|
|||||||
# Sorting
|
# Sorting
|
||||||
yield ConfigVariable(
|
yield ConfigVariable(
|
||||||
name='users_sort_by',
|
name='users_sort_by',
|
||||||
default_value='firstName',
|
default_value='first_name',
|
||||||
input_type='choice',
|
input_type='choice',
|
||||||
label='Sort name of participants by',
|
label='Sort name of participants by',
|
||||||
choices=(
|
choices=(
|
||||||
{'value': 'firstName', 'display_name': 'First name'},
|
{'value': 'first_name', 'display_name': 'First name'},
|
||||||
{'value': 'lastName', 'display_name': 'Last name'}),
|
{'value': 'last_name', 'display_name': 'Last name'}),
|
||||||
weight=510,
|
weight=510,
|
||||||
group='Participants',
|
group='Participants',
|
||||||
subgroup='General')
|
subgroup='General')
|
||||||
|
@ -101,7 +101,7 @@ angular.module('OpenSlidesApp.users', [])
|
|||||||
firstName = _.trim(this.first_name),
|
firstName = _.trim(this.first_name),
|
||||||
lastName = _.trim(this.last_name),
|
lastName = _.trim(this.last_name),
|
||||||
name = '';
|
name = '';
|
||||||
if (Config.get('users_sort_by') && Config.get('users_sort_by').value == 'lastName') {
|
if (Config.get('users_sort_by') && Config.get('users_sort_by').value == 'last_name') {
|
||||||
if (lastName && firstName) {
|
if (lastName && firstName) {
|
||||||
name += [lastName, firstName].join(', ');
|
name += [lastName, firstName].join(', ');
|
||||||
} else {
|
} else {
|
||||||
|
@ -416,6 +416,35 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
.factory('UserCsvExport', [
|
||||||
|
function () {
|
||||||
|
return function (element, users) {
|
||||||
|
var csvRows = [
|
||||||
|
['title', 'first_name', 'last_name', 'structure_level', 'number', 'groups', 'comment', 'is_active', 'is_present', 'is_committee'],
|
||||||
|
];
|
||||||
|
_.forEach(users, function (user) {
|
||||||
|
var row = [];
|
||||||
|
row.push('"' + user.title + '"');
|
||||||
|
row.push('"' + user.first_name + '"');
|
||||||
|
row.push('"' + user.last_name + '"');
|
||||||
|
row.push('"' + user.structure_level + '"');
|
||||||
|
row.push('"' + user.number + '"');
|
||||||
|
row.push('"' + user.groups_id.join(',') + '"');
|
||||||
|
row.push('"' + user.comment + '"');
|
||||||
|
row.push(user.is_active ? '1' : '0');
|
||||||
|
row.push(user.is_present ? '1' : '0');
|
||||||
|
row.push(user.is_committee ? '1' : '0');
|
||||||
|
csvRows.push(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
var csvString = csvRows.join("%0A");
|
||||||
|
element.href = 'data:text/csv;charset=utf-8,' + csvString;
|
||||||
|
element.download = 'users-export.csv';
|
||||||
|
element.target = '_blank';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
.controller('UserListCtrl', [
|
.controller('UserListCtrl', [
|
||||||
'$scope',
|
'$scope',
|
||||||
'$state',
|
'$state',
|
||||||
@ -432,8 +461,11 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
'UserAccessDataListContentProvider',
|
'UserAccessDataListContentProvider',
|
||||||
'PdfMakeDocumentProvider',
|
'PdfMakeDocumentProvider',
|
||||||
'gettextCatalog',
|
'gettextCatalog',
|
||||||
|
'UserCsvExport',
|
||||||
|
'Multiselect',
|
||||||
function($scope, $state, $http, ngDialog, UserForm, User, Group, PasswordGenerator, Projector, ProjectionDefault,
|
function($scope, $state, $http, ngDialog, UserForm, User, Group, PasswordGenerator, Projector, ProjectionDefault,
|
||||||
UserListContentProvider, Config, UserAccessDataListContentProvider, PdfMakeDocumentProvider, gettextCatalog) {
|
UserListContentProvider, Config, UserAccessDataListContentProvider, PdfMakeDocumentProvider, gettextCatalog,
|
||||||
|
UserCsvExport, Multiselect) {
|
||||||
User.bindAll({}, $scope, 'users');
|
User.bindAll({}, $scope, 'users');
|
||||||
Group.bindAll({where: {id: {'>': 1}}}, $scope, 'groups');
|
Group.bindAll({where: {id: {'>': 1}}}, $scope, 'groups');
|
||||||
$scope.$watch(function () {
|
$scope.$watch(function () {
|
||||||
@ -445,10 +477,40 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
$scope.alert = {};
|
$scope.alert = {};
|
||||||
$scope.groupFilter = undefined;
|
|
||||||
|
|
||||||
|
$scope.multiselect = Multiselect.instance();
|
||||||
|
$scope.multiselect.filters = {
|
||||||
|
group: [],
|
||||||
|
};
|
||||||
|
$scope.multiselect.propertyList = ['first_name', 'last_name', 'title', 'number', 'comment', 'structure_level'];
|
||||||
|
$scope.multiselect.PropertyDict = {
|
||||||
|
'groups_id' : function (group_id) {
|
||||||
|
return Group.get(group_id).name;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
$scope.getItemId = {
|
||||||
|
group: function (user) {return user.groups_id;},
|
||||||
|
};
|
||||||
// setup table sorting
|
// setup table sorting
|
||||||
$scope.sortColumn = 'first_name'; //TODO: sort by first OR last name
|
$scope.sortOptions = [
|
||||||
|
{name: 'first_name',
|
||||||
|
display_name: 'First name'},
|
||||||
|
{name: 'last_name',
|
||||||
|
display_name: 'Last name'},
|
||||||
|
{name: 'is_present',
|
||||||
|
display_name: 'Present'},
|
||||||
|
{name: 'is_active',
|
||||||
|
display_name: 'Active'},
|
||||||
|
{name: 'is_committee',
|
||||||
|
display_name: 'Committee'},
|
||||||
|
{name: 'number',
|
||||||
|
display_name: 'Number'},
|
||||||
|
{name: 'structure_level',
|
||||||
|
display_name: 'Structure level'},
|
||||||
|
{name: 'comment',
|
||||||
|
display_name: 'Comment'},
|
||||||
|
];
|
||||||
|
$scope.sortColumn = $scope.config('users_sort_by');
|
||||||
$scope.filterPresent = '';
|
$scope.filterPresent = '';
|
||||||
$scope.reverse = false;
|
$scope.reverse = false;
|
||||||
// function to sort by clicked column
|
// function to sort by clicked column
|
||||||
@ -458,6 +520,29 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
}
|
}
|
||||||
$scope.sortColumn = column;
|
$scope.sortColumn = column;
|
||||||
};
|
};
|
||||||
|
// function to operate the multiselectFilter
|
||||||
|
$scope.operateMultiselectFilter = function (filter, id) {
|
||||||
|
if (!$scope.isSelectMode) {
|
||||||
|
$scope.multiselect.operate(filter, id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// for reset-button
|
||||||
|
$scope.resetFilters = function () {
|
||||||
|
$scope.multiselect.resetFilters();
|
||||||
|
if ($scope.filter) {
|
||||||
|
$scope.filter.search = '';
|
||||||
|
}
|
||||||
|
$scope.isPresentFilter = undefined;
|
||||||
|
$scope.isActiveFilter = undefined;
|
||||||
|
$scope.isCommitteeFilter = undefined;
|
||||||
|
};
|
||||||
|
$scope.areFiltersSet = function () {
|
||||||
|
return $scope.multiselect.areFiltersSet() ||
|
||||||
|
$scope.isPresentFilter ||
|
||||||
|
$scope.isActiveFilter ||
|
||||||
|
$scope.isCommitteeFilter ||
|
||||||
|
($scope.filter ? $scope.filter.search : false);
|
||||||
|
};
|
||||||
|
|
||||||
// pagination
|
// pagination
|
||||||
$scope.currentPage = 1;
|
$scope.currentPage = 1;
|
||||||
@ -467,6 +552,17 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
$scope.limitBegin = ($scope.currentPage - 1) * $scope.itemsPerPage;
|
$scope.limitBegin = ($scope.currentPage - 1) * $scope.itemsPerPage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Toggle group from user
|
||||||
|
$scope.toggleGroup = function (user, group) {
|
||||||
|
if (_.indexOf(user.groups_id, group.id) > -1) {
|
||||||
|
user.groups_id = _.filter(user.groups_id, function (group_id) {
|
||||||
|
return group_id != group.id;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
user.groups_id.push(group.id);
|
||||||
|
}
|
||||||
|
$scope.save(user);
|
||||||
|
};
|
||||||
// open new/edit dialog
|
// open new/edit dialog
|
||||||
$scope.openDialog = function (user) {
|
$scope.openDialog = function (user) {
|
||||||
ngDialog.open(UserForm.getDialog(user));
|
ngDialog.open(UserForm.getDialog(user));
|
||||||
@ -490,7 +586,8 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
$scope.isSelectMode = false;
|
$scope.isSelectMode = false;
|
||||||
// check all checkboxes
|
// check all checkboxes
|
||||||
$scope.checkAll = function () {
|
$scope.checkAll = function () {
|
||||||
angular.forEach($scope.users, function (user) {
|
$scope.selectedAll = !$scope.selectedAll;
|
||||||
|
_.forEach($scope.usersFiltered, function (user) {
|
||||||
user.selected = $scope.selectedAll;
|
user.selected = $scope.selectedAll;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -559,20 +656,25 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
$scope.uncheckAll();
|
$scope.uncheckAll();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.makePDF_userList = function () {
|
// Export as PDF
|
||||||
|
$scope.pdfExportUserList = function () {
|
||||||
var filename = gettextCatalog.getString("List of participants")+".pdf";
|
var filename = gettextCatalog.getString("List of participants")+".pdf";
|
||||||
var userListContentProvider = UserListContentProvider.createInstance($scope.users, $scope.groups);
|
var userListContentProvider = UserListContentProvider.createInstance($scope.usersFiltered, $scope.groups);
|
||||||
var documentProvider = PdfMakeDocumentProvider.createInstance(userListContentProvider);
|
var documentProvider = PdfMakeDocumentProvider.createInstance(userListContentProvider);
|
||||||
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
||||||
};
|
};
|
||||||
|
$scope.pdfExportUserAccessDataList = function () {
|
||||||
$scope.makePDF_userAccessDataList = function () {
|
|
||||||
var filename = gettextCatalog.getString("List of access data")+".pdf";
|
var filename = gettextCatalog.getString("List of access data")+".pdf";
|
||||||
var userAccessDataListContentProvider = UserAccessDataListContentProvider.createInstance(
|
var userAccessDataListContentProvider = UserAccessDataListContentProvider.createInstance(
|
||||||
$scope.users, $scope.groups, Config);
|
$scope.usersFiltered, $scope.groups, Config);
|
||||||
var documentProvider = PdfMakeDocumentProvider.createInstance(userAccessDataListContentProvider);
|
var documentProvider = PdfMakeDocumentProvider.createInstance(userAccessDataListContentProvider);
|
||||||
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
||||||
};
|
};
|
||||||
|
// Export as a csv file
|
||||||
|
$scope.csvExport = function () {
|
||||||
|
var element = document.getElementById('downloadLinkCSV');
|
||||||
|
UserCsvExport(element, $scope.usersFiltered);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -13,26 +13,6 @@
|
|||||||
<i class="fa fa-download fa-lg"></i>
|
<i class="fa fa-download fa-lg"></i>
|
||||||
<translate>Import</translate>
|
<translate>Import</translate>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown pull-right" uib-dropdown>
|
|
||||||
<button os-perms="users.can_manage" class="btn btn-default btn-sm" uib-dropdown-toggle
|
|
||||||
id="user-pdf-dropdown">
|
|
||||||
<i class="fa fa-file-pdf-o fa-lg"></i>
|
|
||||||
<translate>PDF</translate>
|
|
||||||
<span class="caret"></span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" dropdown-menu-right aria-labelledby="user-pdf-dropdown">
|
|
||||||
<li>
|
|
||||||
<a href="" ng-click="makePDF_userList()">
|
|
||||||
<i class="fa fa-list fa-fw"></i>
|
|
||||||
<translate>List of participants</translate>
|
|
||||||
</a>
|
|
||||||
<li os-perms="users.can_manage">
|
|
||||||
<a href="" ng-click="makePDF_userAccessDataList()">
|
|
||||||
<i class="fa fa-qrcode fa-fw"></i>
|
|
||||||
<translate>List of access data</translate>
|
|
||||||
</a>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<h1 translate>Participants</h1>
|
<h1 translate>Participants</h1>
|
||||||
</div>
|
</div>
|
||||||
@ -50,35 +30,36 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="form-inline text-right">
|
<div class="dropdown pull-right" uib-dropdown>
|
||||||
<div class="form-group">
|
<button os-perms="users.can_manage" class="btn btn-default" uib-dropdown-toggle
|
||||||
<div class="input-group">
|
id="user-pdf-dropdown">
|
||||||
<div class="input-group-addon"><i class="fa fa-search"></i></div>
|
<i class="fa fa-upload"></i>
|
||||||
<input type="text" ng-model="filter.search" ng-model-options="{debounce: 500}" class="form-control"
|
<span ng-if="usersFiltered.length == users.length" translate>
|
||||||
placeholder="{{ 'Search' | translate}}">
|
Export all
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-default" ng-click="$parent.isFilterOpen = !$parent.isFilterOpen"
|
|
||||||
ng-class="$parent.isFilterOpen ? 'btn-primary' : 'btn-default'">
|
|
||||||
<i class="fa fa-filter"></i>
|
|
||||||
<translate>Filter ...</translate>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div uib-collapse="!$parent.isFilterOpen" class="row spacer">
|
|
||||||
<div class="col-sm-6 text-right"></div>
|
|
||||||
<div class="col-sm-6 text-right form-inline">
|
|
||||||
<!-- group filter -->
|
|
||||||
<select ng-model="groupFilter" class="form-control" id="groupFilter">
|
|
||||||
<option ng-click="groupFilter = undefined" value="" translate>--- Select group ---</option>
|
|
||||||
<option ng-repeat="group in groups" value="{{ group.id }}">{{ group.name | translate }}</option>
|
|
||||||
</select>
|
|
||||||
<!-- isPresent filter -->
|
|
||||||
<span os-perms="users.can_see_extra_data">
|
|
||||||
<input type="checkbox" ng-model="$parent.filterPresent" ng-false-value="''">
|
|
||||||
<translate>Is present</translate>
|
|
||||||
</span>
|
</span>
|
||||||
|
<span ng-if="usersFiltered.length != users.length" translate>
|
||||||
|
Export filtered
|
||||||
|
</span>
|
||||||
|
<span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" dropdown-menu-right aria-labelledby="user-pdf-dropdown">
|
||||||
|
<li>
|
||||||
|
<a href="" ng-click="pdfExportUserList()">
|
||||||
|
<i class="fa fa-list fa-fw"></i>
|
||||||
|
<translate>List of participants</translate> (PDF)
|
||||||
|
</a>
|
||||||
|
<li os-perms="users.can_manage">
|
||||||
|
<a href="" ng-click="pdfExportUserAccessDataList()">
|
||||||
|
<i class="fa fa-qrcode fa-fw"></i>
|
||||||
|
<translate>List of access data</translate> (PDF)
|
||||||
|
</a>
|
||||||
|
<li>
|
||||||
|
<a href="" id="downloadLinkCSV" ng-click="csvExport()">
|
||||||
|
<i class="fa fa-file-text-o fa-fw"></i>
|
||||||
|
CSV
|
||||||
|
</a>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div uib-collapse="!isSelectMode" class="row spacer">
|
<div uib-collapse="!isSelectMode" class="row spacer">
|
||||||
@ -134,94 +115,311 @@
|
|||||||
|
|
||||||
<!-- filter users (for user with 'can_see_extra_data' permission) - consider present filter -->
|
<!-- filter users (for user with 'can_see_extra_data' permission) - consider present filter -->
|
||||||
<div os-perms="users.can_see_extra_data">
|
<div os-perms="users.can_see_extra_data">
|
||||||
<span ng-repeat="user in $parent.usersFiltered = (users | filter: filter.search | filter: {groups_id: groupFilter} |
|
<span ng-repeat="user in $parent.usersFiltered = (users
|
||||||
filter: {is_present: filterPresent} | orderBy: sortColumn:reverse)"></span>
|
| osFilter: filter.search : multiselect.getFilterString
|
||||||
|
| filter: {is_present: isPresentFilter}
|
||||||
|
| filter: {is_active: isActiveFilter}
|
||||||
|
| filter: {is_committee: isCommitteeFilter}
|
||||||
|
| MultiselectFilter: multiselect.filters.group : getItemId.group
|
||||||
|
| orderBy: sortColumn:reverse)"></span>
|
||||||
</div>
|
</div>
|
||||||
<!-- filter users (for user without 'can_see_extra_data' permission) -->
|
<!-- filter users (for user without 'can_see_extra_data' permission) -->
|
||||||
<div os-perms="!users.can_see_extra_data"
|
<div os-perms="!users.can_see_extra_data"
|
||||||
ng-repeat="user in $parent.usersFiltered = (users | filter: filter.search | filter: {groups_id: groupFilter} |
|
ng-repeat="user in $parent.usersFiltered = (users
|
||||||
orderBy: sortColumn:reverse)"></div>
|
| osFilter: filter.search : multiselect.getFilterString
|
||||||
|
| filter: {is_committee: isCommitteeFilter}
|
||||||
|
| MultiselectFilter: multiselect.filters.group : getItemId.group
|
||||||
|
| orderBy: sortColumn:reverse)"></div>
|
||||||
|
|
||||||
<table class="table table-striped table-bordered table-hover">
|
<div class="os-table container-fluid">
|
||||||
<thead>
|
<div class="row header-row">
|
||||||
<tr>
|
<div class="col-xs-1 centered" ng-show="isSelectMode" os-perms="users.can_manage">
|
||||||
<!-- projector column -->
|
<i class="fa text-danger pointer" ng-class="selectedAll ? 'fa-check-square-o' : 'fa-square-o'"
|
||||||
<th ng-show="!isSelectMode" os-perms="core.can_manage_projector" class="minimum">
|
ng-click="checkAll()"></i>
|
||||||
|
|
||||||
<!-- selection column -->
|
|
||||||
<th ng-show="isSelectMode" os-perms="users.can_manage" class="minimum deleteColumn">
|
|
||||||
<input type="checkbox" ng-model="$parent.selectedAll" ng-change="checkAll()">
|
|
||||||
|
|
||||||
<!-- name column -->
|
|
||||||
<th ng-click="toggleSort('first_name')" class="sortable">
|
|
||||||
<translate>Name</translate>
|
|
||||||
<!-- TODO: sort by first OR last name -->
|
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'first_name' && header.sortable != false"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
|
|
||||||
<!-- structure level column -->
|
|
||||||
<th ng-click="toggleSort('structure_level')" class="sortable optional">
|
|
||||||
<translate>Structure level</translate>
|
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'structure_level' && header.sortable != false"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
|
|
||||||
<!-- groups column -->
|
|
||||||
<th ng-click="toggleSort('groups')" class="sortable optional">
|
|
||||||
<translate>Groups</translate>
|
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'groups' && header.sortable != false"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
|
|
||||||
<!-- present column -->
|
|
||||||
<th os-perms="users.can_see_extra_data" ng-click="toggleSort('is_present')" class="sortable minimum">
|
|
||||||
<translate>Present</translate>
|
|
||||||
<i class="pull-right fa" ng-show="sortColumn === 'is_present' && header.sortable != false"
|
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
|
||||||
</i>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="user in usersFiltered | limitTo : itemsPerPage : limitBegin" class="animate-item"
|
|
||||||
ng-class="{ 'activeline': user.isProjected().length, 'selected': user.selected }">
|
|
||||||
<!-- projector column -->
|
|
||||||
<td ng-show="!isSelectMode" os-perms="core.can_manage_projector">
|
|
||||||
<projector-button model="user" default-projector-id="defaultProjectorId">
|
|
||||||
</projector-button>
|
|
||||||
<!-- selection column -->
|
|
||||||
<td ng-show="isSelectMode" os-perms="users.can_manage" class="deleteColumn">
|
|
||||||
<input type="checkbox" ng-model="user.selected">
|
|
||||||
<!-- user data colums -->
|
|
||||||
<td ng-mouseover="user.hover=true" ng-mouseleave="user.hover=false">
|
|
||||||
<strong>
|
|
||||||
<i ng-show="user.is_active === false" class="fa fa-ban"
|
|
||||||
title="{{ 'Is inactive' | translate }}"></i>
|
|
||||||
<i ng-show="user.is_committee" class="fa fa-users"
|
|
||||||
title="{{ 'Is a committee' | translate }}"></i>
|
|
||||||
<a ui-sref="users.user.detail({id: user.id})">{{ user.get_short_name() }}</a>
|
|
||||||
</strong>
|
|
||||||
<div ng-if="user.comment">
|
|
||||||
<small><i class="fa fa-info-circle"></i> {{ user.comment }}</small>
|
|
||||||
</div>
|
</div>
|
||||||
<div ng-if="user.number"> {{ user.number }} </div>
|
<div class="col-xs-11 main-header">
|
||||||
<div os-perms="users.can_manage" class="hoverActions" ng-class="{'hiddenDiv': !user.hover}">
|
<span class="form-inline text-right pull-right">
|
||||||
<a href="" ng-click="openDialog(user)" translate>Edit</a> |
|
<!-- reset Filters -->
|
||||||
<a ui-sref="users.user.change-password({id: user.id})" translate>Change password</a> |
|
<span class="sort-spacer pointer" ng-click="resetFilters()"
|
||||||
|
ng-if="areFiltersSet()" ng-disabled="isSelectMode"
|
||||||
|
ng-class="{'disabled': isSelectMode}">
|
||||||
|
<i class="fa fa-times-circle"></i>
|
||||||
|
<translate>Filter</translate>
|
||||||
|
</span>
|
||||||
|
<!-- Group filter -->
|
||||||
|
<span class="dropdown" uib-dropdown>
|
||||||
|
<span class="pointer" id="dropdownGroup" uib-dropdown-toggle
|
||||||
|
ng-class="{'bold': multiselect.filters.group.length > 0, 'disabled': isSelectMode}"
|
||||||
|
ng-disabled="isSelectMode">
|
||||||
|
<translate>Groups</translate>
|
||||||
|
<span class="caret"></span>
|
||||||
|
</span>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownGroup">
|
||||||
|
<li ng-repeat="group in groups">
|
||||||
|
<div ng-click="operateMultiselectFilter('group', group.id)">
|
||||||
|
<i class="fa fa-check" ng-if="multiselect.filters.group.indexOf(group.id) > -1"></i>
|
||||||
|
{{ group.name | translate }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
<!-- Present filter -->
|
||||||
|
<span class="dropdown" uib-dropdown>
|
||||||
|
<span class="pointer" id="dropdownPresent" uib-dropdown-toggle
|
||||||
|
ng-class="{'bold': isPresentFilter !== undefined, 'disabled': isSelectMode}"
|
||||||
|
ng-disabled="isSelectMode">
|
||||||
|
<translate>Present</translate>
|
||||||
|
<span class="caret"></span>
|
||||||
|
</span>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownPresent">
|
||||||
|
<li>
|
||||||
|
<div ng-click="isPresentFilter = (isPresentFilter ? undefined : true)">
|
||||||
|
<i class="fa" ng-class="{'fa-check': isPresentFilter === true}"></i>
|
||||||
|
<translate>Is present</translate>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div ng-click="isPresentFilter = (isPresentFilter === false) ? undefined : false">
|
||||||
|
<i class="fa" ng-class="{'fa-check': isPresentFilter === false}"></i>
|
||||||
|
<translate>Is not present</translate>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
<!-- Active filter -->
|
||||||
|
<span class="dropdown" uib-dropdown>
|
||||||
|
<span class="pointer" id="dropdownActive" uib-dropdown-toggle
|
||||||
|
ng-class="{'bold': isActiveFilter !== undefined, 'disabled': isSelectMode}"
|
||||||
|
ng-disabled="isSelecteMode">
|
||||||
|
<translate>Active</translate>
|
||||||
|
<span class="caret"></span>
|
||||||
|
</span>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownActive">
|
||||||
|
<li>
|
||||||
|
<div ng-click="isActiveFilter = (isActiveFilter ? undefined : true)">
|
||||||
|
<i class="fa" ng-class="{'fa-check': isActiveFilter === true}"></i>
|
||||||
|
<translate>Is active</translate>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div ng-click="isActiveFilter = (isActiveFilter === false ? undefined : false)">
|
||||||
|
<i class="fa" ng-class="{'fa-check': isActiveFilter === false}"></i>
|
||||||
|
<translate>Is not active</translate>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
<!-- Committee filter -->
|
||||||
|
<span class="dropdown" uib-dropdown>
|
||||||
|
<span class="pointer" id="dropdownCommittee" uib-dropdown-toggle
|
||||||
|
ng-class="{'bold': isCommitteeFilter !== undefined, 'disabled': isSelectMode}"
|
||||||
|
ng-disabled="isSelecteMode">
|
||||||
|
<translate>Committee</translate>
|
||||||
|
<span class="caret"></span>
|
||||||
|
</span>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownCommittee">
|
||||||
|
<li>
|
||||||
|
<div ng-click="isCommitteeFilter = (isCommitteeFilter ? undefined : true)">
|
||||||
|
<i class="fa" ng-class="{'fa-check': isCommitteeFilter === true}"></i>
|
||||||
|
<translate>Yes</translate>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div ng-click="isCommitteeFilter = (isCommitteeFilter === false ? undefined : false)">
|
||||||
|
<i class="fa" ng-class="{'fa-check': isCommitteeFilter === false}"></i>
|
||||||
|
<translate>No</translate>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
<!-- dropdown sort -->
|
||||||
|
<span class="dropdown" uib-dropdown>
|
||||||
|
<span class="pointer" id="dropdownSort" uib-dropdown-toggle
|
||||||
|
ng-class="{'disabled': isSelectMode}"
|
||||||
|
ng-disabled="isSelectMode">
|
||||||
|
<translate>Sort</translate>
|
||||||
|
<span class="caret"></span>
|
||||||
|
</span>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-right dropdown-entries" aria-labelledby="dropdownSort">
|
||||||
|
<li ng-repeat="option in sortOptions">
|
||||||
|
<div ng-click="toggleSort(option.name)">
|
||||||
|
{{ option.display_name | translate }}
|
||||||
|
<span class="spacer-right pull-right"></span>
|
||||||
|
<i class="pull-right fa"
|
||||||
|
ng-style="{'visibility': sortColumn === option.name ? 'visible' : 'hidden'}"
|
||||||
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
<!-- search field -->
|
||||||
|
<span class="form-group">
|
||||||
|
<span class="input-group">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-search"></i></span>
|
||||||
|
<input type="text" ng-model="filter.search" class="form-control" ng-model-options="{debounce: 500}"
|
||||||
|
placeholder="{{ 'Search' | translate}}" ng-disabled="isSelectMode">
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<!-- show all selected multiselectoptions -->
|
||||||
|
<span>
|
||||||
|
<span ng-repeat="group in groups" class="pointer spacer-left-lg"
|
||||||
|
ng-if="multiselect.filters.group.indexOf(group.id) > -1"
|
||||||
|
ng-click="operateMultiselectFilter('group', group.id)"
|
||||||
|
ng-class="{'disabled': isSelectMode}">
|
||||||
|
<span class="nobr">
|
||||||
|
<i class="fa fa-times-circle"></i>
|
||||||
|
{{ group.name | translate }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span ng-hide="isPresentFilter === undefined"
|
||||||
|
class="pointer spacer-left-lg"
|
||||||
|
ng-click="isPresentFilter = undefined;"
|
||||||
|
ng-class="{'disabled': isSelectMode}">
|
||||||
|
<span class="nobr">
|
||||||
|
<i class="fa fa-times-circle"></i>
|
||||||
|
{{ isPresentFilter ? 'Is present' : 'Is not present' | translate }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span ng-hide="isActiveFilter === undefined"
|
||||||
|
class="pointer spacer-left-lg"
|
||||||
|
ng-click="isActiveFilter = undefined;"
|
||||||
|
ng-class="{'disabled': isSelectMode}">
|
||||||
|
<span class="nobr">
|
||||||
|
<i class="fa fa-times-circle"></i>
|
||||||
|
{{ isActiveFilter ? 'Is active' : 'Is not active' | translate }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span ng-hide="isCommitteeFilter === undefined"
|
||||||
|
class="pointer spacer-left-lg"
|
||||||
|
ng-click="isCommitteeFilter = undefined;"
|
||||||
|
ng-class="{'disabled': isSelectMode}">
|
||||||
|
<span class="nobr">
|
||||||
|
<i class="fa fa-times-circle"></i>
|
||||||
|
{{ isCommitteeFilter ? 'Is committee' : 'Is not committee' | translate }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- main table -->
|
||||||
|
<div class="row data-row" ng-mouseover="user.hover=true"
|
||||||
|
ng-mouseleave="user.hover=false"
|
||||||
|
ng-class="{'projected': user.isProjected().length}"
|
||||||
|
ng-repeat="user in usersFiltered
|
||||||
|
| limitTo : itemsPerPage : limitBegin">
|
||||||
|
|
||||||
|
<!-- select column -->
|
||||||
|
<div ng-show="isSelectMode" os-perms="users.can_manage" class="col-xs-1 centered">
|
||||||
|
<i class="fa text-danger pointer" ng-click="user.selected=!user.selected"
|
||||||
|
ng-class="user.selected ? 'fa-check-square-o' : 'fa-square-o'"></i>
|
||||||
|
</div>
|
||||||
|
<!-- projector column -->
|
||||||
|
<div class="col-xs-1 centered projector" os-perms="core.can_manage_projector">
|
||||||
|
<projector-button model="user", default-projector-id="defaultProjectorId">
|
||||||
|
</projector-button>
|
||||||
|
</div>
|
||||||
|
<!-- main content column -->
|
||||||
|
<div class="col-xs-6 content">
|
||||||
|
<div class="spacer-right"> <!-- horizontal block -->
|
||||||
|
<strong>
|
||||||
|
<i ng-style="{'visibility': user.is_active === false ? 'visible' : 'hidden'}" class="fa fa-ban"
|
||||||
|
title="{{ 'Is inactive' | translate }}"></i>
|
||||||
|
<i ng-style="{'visibility': user.is_committee ? 'visible' : 'hidden'}" class="fa fa-university"
|
||||||
|
title="{{ 'Is a committee' | translate }}"></i>
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div> <!-- vertical block -->
|
||||||
|
<strong>
|
||||||
|
<a ui-sref="users.user.detail({id: user.id})" class="title">{{ user.get_short_name() }}</a>
|
||||||
|
</strong>
|
||||||
|
</div>
|
||||||
|
<div ng-if="user.number"><translate>No.</translate> {{ user.number }} </div>
|
||||||
|
<div os-perms="users.can_manage" ng-class="{'hiddenDiv': !user.hover}">
|
||||||
|
<small>
|
||||||
|
<a href="" ng-click="openDialog(user)" translate>Edit</a> ·
|
||||||
|
<a ui-sref="users.user.change-password({id: user.id})" translate>Change password</a> ·
|
||||||
<a href="" class="text-danger"
|
<a href="" class="text-danger"
|
||||||
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
|
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
|
||||||
<b>{{ user.get_short_name() }}</b>"
|
<b>{{ user.get_short_name() }}</b>"
|
||||||
ng-bootbox-confirm-action="delete(user)" translate>Delete</a>
|
ng-bootbox-confirm-action="delete(user)" translate>Delete</a>
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<td class="optional">{{ user.structure_level }}
|
|
||||||
<td class="optional">
|
|
||||||
<div ng-repeat="group in user.groups_id">
|
|
||||||
{{ (groups | filter: {id: group})[0].name | translate }}
|
|
||||||
</div>
|
</div>
|
||||||
<td os-perms="users.can_see_extra_data">
|
</div>
|
||||||
<span os-perms="!users.can_manage">
|
<!-- additional content column -->
|
||||||
<i ng-if="user.is_present" class="fa fa-check-square-o"></i>
|
<style>
|
||||||
|
.os-table .row .col-xs-4 {
|
||||||
|
width: calc(50% - {{ isSelectMode ? '120' : '70' }}px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="col-xs-4 content">
|
||||||
|
<div style="width: 60%;" class="optional">
|
||||||
|
<small>
|
||||||
|
<!-- Group dropdown for manage user -->
|
||||||
|
<div os-perms="users.can_manage" ng-show="groups.length > 0"
|
||||||
|
uib-tooltip="{{ 'Groups' | translate }}" tooltip-placement="top-left"
|
||||||
|
ng-mouseover="user.groupHover=true"
|
||||||
|
ng-mouseleave="user.groupHover=false">
|
||||||
|
<span uib-dropdown>
|
||||||
|
<span id="dropdown-group{{ user.id }}" class="pointer" uib-dropdown-toggle>
|
||||||
|
<span ng-if="!user.groups_id.length" ng-show="user.hover">
|
||||||
|
<i class="fa fa-users"></i>
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
</span>
|
</span>
|
||||||
<input os-perms="users.can_manage" type="checkbox" ng-model="user.is_present" ng-click="save(user)">
|
<span ng-if="user.groups_id.length">
|
||||||
</table>
|
<i class="fa fa-users"></i>
|
||||||
|
<span ng-repeat="group in user.groups_id | limitTo:2">
|
||||||
|
{{ (groups | filter: {id: group})[0].name | translate }}<span ng-if="!$last">,</span></span><span ng-if="user.groups_id.length > 2">,
|
||||||
|
... [+{{ user.groups_id.length - 2}}]</span>
|
||||||
|
<i class="fa fa-cog fa-lg spcaer-left" ng-show="user.groupHover"></i>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<ul class="dropdown-menu dropdown-entries" aria-labelledby="dropdown-group{{ user.id }}">
|
||||||
|
<li ng-repeat="group in groups">
|
||||||
|
<div ng-click="toggleGroup(user, group)">
|
||||||
|
<i class="fa fa-check" ng-if="inArray(user.groups_id, group.id)"></i>
|
||||||
|
{{ group.name | translate }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- Group dropdown for normal user -->
|
||||||
|
<div os-perms="!users.can_manage" ng-show="user.groups_id.length"
|
||||||
|
uib-tooltip="{{ 'Groups' | translate }}" tooltip-placement="top-left">
|
||||||
|
<i class="fa fa-users"></i>
|
||||||
|
<span ng-repeat="group in user.groups_id | limitTo:2">
|
||||||
|
{{ (groups | filter: {id: group})[0].name | translate }}<span ng-if="!$last">,</span></span><span ng-if="user.groups_id.length > 2">,
|
||||||
|
... [+{{ user.groups_id.length - 2}}]</span>
|
||||||
|
<!-- sorry for merging them together, but otherwise there would be a whitespace because of the new line -->
|
||||||
|
</div>
|
||||||
|
<div ng-if="user.structure_level" uib-tooltip="{{ 'Structure level' | translate }}" tooltip-placement="top-left">
|
||||||
|
<i class="fa fa-flag"></i>
|
||||||
|
{{ user.structure_level }}
|
||||||
|
</div>
|
||||||
|
<div ng-if="user.comment" uib-tooltip="{{ 'Comment' | translate }}" tooltip-placement="top-left">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
|
{{ user.comment | limitTo:25}}{{ user.comment.length > 25 ? '...' : '' }}
|
||||||
|
</div>
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<div style="width: 40%;" class="pull-right" os-perms="users.can_see_extra_data">
|
||||||
|
<div os-perms="users.can_manage">
|
||||||
|
<span class="pointer" ng-click="user.is_present = !user.is_present; save(user);">
|
||||||
|
<i class="fa" ng-class="user.is_present ? 'fa-check-square-o' : 'fa-square-o'"></i>
|
||||||
|
<span class="spacer-left" translate>Present</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div><!-- end data row -->
|
||||||
|
</div><!-- end os-table -->
|
||||||
|
|
||||||
<ul uib-pagination
|
<ul uib-pagination
|
||||||
total-items="usersFiltered.length"
|
total-items="usersFiltered.length"
|
||||||
items-per-page="itemsPerPage"
|
items-per-page="itemsPerPage"
|
||||||
|
Loading…
Reference in New Issue
Block a user