Merge pull request #1557 from emanuelschuetze/angular-motions

Updated motion list, form and detail views.
This commit is contained in:
Oskar Hahn 2015-06-22 14:18:09 +02:00
commit 2d6cdfa168
5 changed files with 133 additions and 16 deletions

View File

@ -3,7 +3,29 @@ angular.module('OpenSlidesApp.motions', [])
.factory('Motion', function(DS) { .factory('Motion', function(DS) {
return DS.defineResource({ return DS.defineResource({
name: 'motions/motion', name: 'motions/motion',
endpoint: '/rest/motions/motion/' endpoint: '/rest/motions/motion/',
methods: {
getVersion: function(versionId) {
versionId = versionId || this.active_version;
if (versionId == -1) {
index = this.versions.length - 1;
} else {
index = _.findIndex(this.versions, function(element) {
return element.id == versionId
});
}
return this.versions[index];
},
getTitle: function(versionId) {
return this.getVersion(versionId).title;
},
getText: function(versionId) {
return this.getVersion(versionId).text;
},
getReason: function(versionId) {
return this.getVersion(versionId).reason;
}
}
}); });
}) })
.factory('Category', function(DS) { .factory('Category', function(DS) {
@ -39,6 +61,12 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
resolve: { resolve: {
motions: function(Motion) { motions: function(Motion) {
return Motion.findAll(); return Motion.findAll();
},
categories: function(Category) {
return Category.findAll();
},
users: function(User) {
return User.findAll();
} }
} }
}) })
@ -68,6 +96,12 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
resolve: { resolve: {
motion: function(Motion, $stateParams) { motion: function(Motion, $stateParams) {
return Motion.find($stateParams.id); return Motion.find($stateParams.id);
},
categories: function(Category) {
return Category.findAll();
},
users: function(User) {
return User.findAll();
} }
} }
}) })
@ -128,8 +162,10 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
}) })
}) })
.controller('MotionListCtrl', function($scope, Motion) { .controller('MotionListCtrl', function($scope, Motion, Category, User) {
Motion.bindAll({}, $scope, 'motions'); Motion.bindAll({}, $scope, 'motions');
Category.bindAll({}, $scope, 'categories');
User.bindAll({}, $scope, 'users');
// setup table sorting // setup table sorting
$scope.sortColumn = 'identifier'; $scope.sortColumn = 'identifier';
@ -157,8 +193,10 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
}; };
}) })
.controller('MotionDetailCtrl', function($scope, Motion, motion) { .controller('MotionDetailCtrl', function($scope, Motion, Category, User, motion) {
Motion.bindOne(motion.id, $scope, 'motion'); Motion.bindOne(motion.id, $scope, 'motion');
Category.bindAll({}, $scope, 'categories');
User.bindAll({}, $scope, 'users');
}) })
.controller('MotionCreateCtrl', .controller('MotionCreateCtrl',
@ -174,6 +212,9 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
$scope.save = function (motion) { $scope.save = function (motion) {
motion.tags = []; // TODO: REST API should do it! (Bug in Django REST framework) motion.tags = []; // TODO: REST API should do it! (Bug in Django REST framework)
motion.attachments = []; // TODO: REST API should do it! (Bug in Django REST framework) motion.attachments = []; // TODO: REST API should do it! (Bug in Django REST framework)
if (!motion.supporters) {
motion.supporters = []; // TODO: REST API should do it! (Bug in Django REST framework)
}
Motion.create(motion).then( Motion.create(motion).then(
function(success) { function(success) {
$state.go('motions.motion.list'); $state.go('motions.motion.list');
@ -192,6 +233,11 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions'])
Mediafile.bindAll({}, $scope, 'mediafiles'); Mediafile.bindAll({}, $scope, 'mediafiles');
$scope.motion = motion; $scope.motion = motion;
// get latest version for edit
$scope.motion.title = $scope.motion.getTitle(-1);
$scope.motion.text = $scope.motion.getText(-1);
$scope.motion.reason = $scope.motion.getReason(-1);
$scope.save = function (motion) { $scope.save = function (motion) {
motion.tags = []; // TODO: REST API should do it! (Bug in Django REST framework) motion.tags = []; // TODO: REST API should do it! (Bug in Django REST framework)
motion.attachments = []; // TODO: REST API should do it! (Bug in Django REST framework) motion.attachments = []; // TODO: REST API should do it! (Bug in Django REST framework)

View File

@ -1,4 +1,10 @@
<h1>{{ motion.identifier }}</h1> <h1>
{{ motion.getTitle() }}
<small>
<translate>Motion</translate> {{ motion.identifier }}
<span ng-if="motion.versions.length > 1" >| Version {{ (motion.versions | filter: {id: motion.active_version})[0].version_number }}</span>
</small>
</h1>
<div id="submenu"> <div id="submenu">
<a ui-sref="motions.motion.list" class="btn btn-sm btn-default"> <a ui-sref="motions.motion.list" class="btn btn-sm btn-default">
@ -14,16 +20,34 @@
<i class="fa fa-video-camera"></i> <i class="fa fa-video-camera"></i>
</a> </a>
<!-- edit --> <!-- edit -->
<a ui-sref="motion.detail.update({id: motion.id })" os-perms="motions.can_manage" <a ui-sref="motions.motion.detail.update({id: motion.id })" os-perms="motions.can_manage"
class="btn btn-default btn-sm" class="btn btn-default btn-sm"
title="{{ 'Edit' | translate}}"> title="{{ 'Edit' | translate}}">
<i class="fa fa-pencil"></i> <i class="fa fa-pencil"></i>
</a> </a>
</div> </div>
<div class="row">
<div class="col-sm-8">
<h3 translate>Text</h3>
{{ motion.getText() }}
<h3 translate>Reason</h3>
{{ motion.getReason() }}
</div>
<div class="col-sm-4">
<div class="well">
<h3 translate>Submitters</h3>
<div ng-repeat="submitter in motion.submitters">
{{ (users | filter: {id: submitter})[0].get_full_name() }}<br>
</div>
<h3 translate>Category</h3> <h3 translate>Category</h3>
{{ motion.category }} {{ (categories | filter: {id: motion.category})[0].name }}</a>
<h3 translate>Submitters</h3> <h3 translate>Voting result</h3>
<!-- TODO --> -
</div>
</div>
</div>

View File

@ -21,7 +21,11 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="selectSubmitter" translate>Submitter</label> <label for="selectSubmitter" translate>Submitter</label>
<ui-select ng-model="motion.submitter" theme="bootstrap" name="selectSubmitter"> <select multiple size="3" ng-options="user.id as user.get_short_name() for user in users"
ng-model="motion.submitters" class="form-control" name="selectSubmitter" required>
</select>
<!-- TODO: use modern ui-select component with more information per user
<ui-select multipe ng-model="motion.submitter" theme="bootstrap" name="selectSubmitter">
<ui-select-match placeholder="{{ 'Select or search a participant...' | translate }}"> <ui-select-match placeholder="{{ 'Select or search a participant...' | translate }}">
{{ $select.selected.get_short_name() }} {{ $select.selected.get_short_name() }}
</ui-select-match> </ui-select-match>
@ -29,15 +33,15 @@
<div ng-bind-html="user.get_short_name() | highlight: $select.search"></div> <div ng-bind-html="user.get_short_name() | highlight: $select.search"></div>
<small ng-bind-html="user.structure_level | highlight: $select.search"></small> <small ng-bind-html="user.structure_level | highlight: $select.search"></small>
</ui-select-choices> </ui-select-choices>
</ui-select> </ui-select>-->
</div> </div>
<div class="form-group" ng-class="{'has-error has-feedback': motionForm.inputTitle.$error.required}"> <div class="form-group">
<label for="inputName" translate>Title</label> <label for="inputName" translate>Title</label>
<input type="text" ng-model="motion.title" class="form-control" name="inputTitle" ng-required="true"> <input type="text" ng-model="motion.title" class="form-control" name="inputTitle" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="textText" translate>Text</label> <label for="textText" translate>Text</label>
<textarea ng-model="motion.text" class="form-control" name="textText" /> <textarea ng-model="motion.text" class="form-control" name="textText" required />
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="textReason" translate>Reason</label> <label for="textReason" translate>Reason</label>

View File

@ -32,11 +32,27 @@
<table class="table table-striped table-bordered table-hover"> <table class="table table-striped table-bordered table-hover">
<thead> <thead>
<tr> <tr>
<th ng-click="toggleSort('identifier')" class="sortable"> <!-- TODO: Add motion.agenda_item to rest api -->
<th ng-click="toggleSort('agenda_item')" class="sortable minimum">
<translate>Agenda item</translate>
<i class="pull-right fa" ng-show="sortColumn === 'agenda_item' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i>
<th ng-click="toggleSort('identifier')" class="sortable minimum">
<translate>Identifier</translate> <translate>Identifier</translate>
<i class="pull-right fa" ng-show="sortColumn === 'identifier' && header.sortable != false" <i class="pull-right fa" ng-show="sortColumn === 'identifier' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'"> ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i> </i>
<th ng-click="toggleSort('title')" class="sortable">
<translate>Title</translate>
<i class="pull-right fa" ng-show="sortColumn === 'title' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i>
<th ng-click="toggleSort('submitters')" class="sortable">
<translate>Submitters</translate>
<i class="pull-right fa" ng-show="sortColumn === 'submitters' && header.sortable != false"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
</i>
<th ng-click="toggleSort('category')" class="sortable"> <th ng-click="toggleSort('category')" class="sortable">
<translate>Category</translate> <translate>Category</translate>
<i class="pull-right fa" ng-show="sortColumn === 'category' && header.sortable != false" <i class="pull-right fa" ng-show="sortColumn === 'category' && header.sortable != false"
@ -47,8 +63,17 @@
<tbody> <tbody>
<tr ng-repeat="motion in motions | filter: filter.search | <tr ng-repeat="motion in motions | filter: filter.search |
orderBy: sortColumn:reverse"> orderBy: sortColumn:reverse">
<td> <!--TOOD: add agenda item reference -->
<td><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.identifier }}</a> <td><a ui-sref="motions.motion.detail({id: motion.id})">{{ motion.identifier }}</a>
<td class="optional">{{ motion.category }} <td><a ui-sref="motions.motion.detail({id: motion.id})">
<!-- TODO: make it easier to get active version -->
{{ (motion.versions | filter: {id: motion.active_version})[0].title }}</a>
<td class="optional">
<div ng-repeat="submitter in motion.submitters">
{{ (users | filter: {id: submitter})[0].get_full_name() }}<br>
</div>
<td class="optional">
{{ (categories | filter: {id: motion.category})[0].name }}</a>
<td os-perms="motions.can_manage core.can_manage_projector" class="nobr"> <td os-perms="motions.can_manage core.can_manage_projector" class="nobr">
<!-- projector, TODO: add link to activate slide --> <!-- projector, TODO: add link to activate slide -->
<a href="#TODO" os-perms="core.can_manage_projector" class="btn btn-default btn-sm" <a href="#TODO" os-perms="core.can_manage_projector" class="btn btn-default btn-sm"

View File

@ -19,6 +19,24 @@ angular.module('OpenSlidesApp.users', [])
} }
return name; return name;
}, },
get_full_name: function() {
// should be the same as in the python user model.
var firstName = _.trim(this.first_name),
lastName = _.trim(this.last_name),
structure_level = _.trim(this.structure_level),
name;
if (firstName && lastName) {
// TODO: check config
name = [firstName, lastName].join(' ');
} else {
name = firstName || lastName || this.username;
}
if (structure_level) {
name = name + " (" + structure_level + ")";
}
return name;
},
getPerms: function() { getPerms: function() {
var allPerms = []; var allPerms = [];
_.forEach(this.groups, function(groupId) { _.forEach(this.groups, function(groupId) {