Motion detail with routing
For small screens only
This commit is contained in:
parent
7856b7e07f
commit
f01d3a5f6a
@ -8,7 +8,11 @@
|
||||
"sourceRoot": "src",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"schematics": {},
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"styleext": "scss"
|
||||
}
|
||||
},
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
|
@ -17,4 +17,8 @@ export class Category extends BaseModel {
|
||||
this.name = name;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public toString = (): string => {
|
||||
return this.prefix + ' - ' + this.name;
|
||||
};
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import { MotionSubmitter } from './motion-submitter';
|
||||
import { MotionLog } from './motion-log';
|
||||
import { Config } from '../core/config';
|
||||
import { Workflow } from './workflow';
|
||||
import { User } from '../users/user';
|
||||
import { Category } from './category';
|
||||
|
||||
/**
|
||||
* Representation of Motion.
|
||||
@ -78,6 +80,31 @@ export class Motion extends BaseModel {
|
||||
this.log_messages = log_messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the most current title from versions
|
||||
*/
|
||||
get currentTitle() {
|
||||
if (this.versions[0]) {
|
||||
return this.versions[0].title;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the most current motion text from versions
|
||||
*/
|
||||
get currentText() {
|
||||
return this.versions[0].text;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the most current motion reason text from versions
|
||||
*/
|
||||
get currentReason() {
|
||||
return this.versions[0].reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the submitters as uses objects
|
||||
*/
|
||||
@ -86,14 +113,39 @@ export class Motion extends BaseModel {
|
||||
this.submitters.forEach(submitter => {
|
||||
submitterIds.push(submitter.user_id);
|
||||
});
|
||||
const users = this.DS.get('users/user', ...submitterIds);
|
||||
const users = this.DS.get(User, ...submitterIds);
|
||||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the name of the first submitter
|
||||
*/
|
||||
get submitterName() {
|
||||
const mainSubmitter = this.DS.get(User, this.submitters[0].user_id) as User;
|
||||
if (mainSubmitter) {
|
||||
return mainSubmitter.username;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the category of a motion as object
|
||||
*/
|
||||
get category() {
|
||||
if (this.category_id) {
|
||||
const motionCategory = this.DS.get(Category, this.category_id);
|
||||
return motionCategory;
|
||||
} else {
|
||||
return 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the workflow state
|
||||
*
|
||||
* Right now only the default workflow is assumes
|
||||
* TODO: Motion workflow needs to be specific on the server
|
||||
*/
|
||||
get stateName() {
|
||||
//get the default workflow
|
||||
|
@ -0,0 +1,63 @@
|
||||
<mat-toolbar color='primary'>
|
||||
|
||||
<button class='generic-mini-button on-transition-fade' mat-mini-fab>
|
||||
<fa-icon icon='pen'></fa-icon>
|
||||
</button>
|
||||
|
||||
<!-- motion.identifier -->
|
||||
<!-- motion.versions[0].title -->
|
||||
<div class='motion-title on-transition-fade'>
|
||||
<span translate>Motion</span> {{motion.identifier}} {{motion.currentTitle}}
|
||||
<br>
|
||||
<div class='motion-submitter'>
|
||||
<span translate>by</span> {{motion.submitterName}}
|
||||
</div>
|
||||
</div>
|
||||
</mat-toolbar>
|
||||
|
||||
<mat-accordion multi='true' class='on-transition-fade'>
|
||||
<mat-expansion-panel [expanded]='true' class='meta-info-panel'>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<fa-icon icon='info-circle' [fixedWidth]="true"></fa-icon>
|
||||
<span translate>Meta information</span>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<div class='meta-info-panel-body'>
|
||||
<h3 translate>Submitters</h3>
|
||||
{{motion.submitterName}}
|
||||
<h3 translate>Supporters</h3>
|
||||
<h3 translate>Status</h3>
|
||||
{{motion.stateName}}
|
||||
<h3 translate>Empfehlung der ABK</h3>
|
||||
<h3 translate>Category</h3>
|
||||
{{motion.category}}
|
||||
<h3 translate>Origin</h3>
|
||||
<h3 translate>Voting</h3>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
<mat-expansion-panel [expanded]='true'>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<fa-icon icon='file-signature' [fixedWidth]="true"></fa-icon>
|
||||
<span translate>Personal note</span>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
TEST
|
||||
</mat-expansion-panel>
|
||||
<mat-expansion-panel [expanded]='true' class='content-panel'>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<fa-icon icon='align-left' [fixedWidth]="true"></fa-icon>
|
||||
<span translate>Content</span>
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<h3 translate>The assembly may decide:</h3>
|
||||
<div [innerHtml]='motion.currentText'></div>
|
||||
|
||||
<h4 translate class='motion-reason-label'>Reason</h4>
|
||||
<div [innerHtml]='motion.currentReason'></div>
|
||||
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
@ -0,0 +1,47 @@
|
||||
span {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.motion-title {
|
||||
padding-left: 20px;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
.motion-submitter {
|
||||
display: inline;
|
||||
font-weight: bold;
|
||||
font-size: 70%;
|
||||
}
|
||||
|
||||
mat-panel-title {
|
||||
fa-icon {
|
||||
margin-right: 35px; //on line with text
|
||||
}
|
||||
}
|
||||
|
||||
.meta-info-panel {
|
||||
padding-top: 25px;
|
||||
h3 {
|
||||
display: block;
|
||||
font-size: 80%;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.meta-info-panel-body {
|
||||
padding-left: 55px;
|
||||
}
|
||||
}
|
||||
|
||||
.content-panel {
|
||||
h3 {
|
||||
font-weight: initial;
|
||||
font-size: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
h4 {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
font-size: 100%;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MotionDetailComponent } from './motion-detail.component';
|
||||
|
||||
describe('MotionDetailComponent', () => {
|
||||
let component: MotionDetailComponent;
|
||||
let fixture: ComponentFixture<MotionDetailComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MotionDetailComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MotionDetailComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,43 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { OpenSlidesComponent } from '../../../openslides.component';
|
||||
import { BaseComponent } from '../../../base.component';
|
||||
import { Motion } from '../../../shared/models/motions/motion';
|
||||
|
||||
@Component({
|
||||
selector: 'app-motion-detail',
|
||||
templateUrl: './motion-detail.component.html',
|
||||
styleUrls: ['./motion-detail.component.scss']
|
||||
})
|
||||
export class MotionDetailComponent extends BaseComponent implements OnInit {
|
||||
motion: Motion;
|
||||
|
||||
constructor(private route: ActivatedRoute) {
|
||||
super();
|
||||
this.route.params.subscribe(params => {
|
||||
console.log(params.id);
|
||||
|
||||
// has the motion of the DataStore was initialized before.
|
||||
// Otherwise we need to observe DS
|
||||
this.motion = this.DS.get(Motion, params.id) as Motion;
|
||||
|
||||
// Observe motion to get the motion in the parameter and also get the changes
|
||||
this.DS.getObservable().subscribe(newModel => {
|
||||
if (newModel instanceof Motion) {
|
||||
if (newModel.id === +params.id) {
|
||||
this.motion = newModel as Motion;
|
||||
console.log('this.motion = ', this.motion);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
console.log('(init)the motion: ', this.motion);
|
||||
}
|
||||
|
||||
downloadSingleMotionButton() {
|
||||
console.log('Download this motion');
|
||||
}
|
||||
}
|
@ -16,17 +16,17 @@
|
||||
|
||||
<div class='custom-table-header on-transition-fade'>
|
||||
<button mat-button>
|
||||
SORIEREN NACH
|
||||
<span translate>SORT</span>
|
||||
</button>
|
||||
<button mat-button>
|
||||
FILTER
|
||||
<span translate>FILTER</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-table class='on-transition-fade' [dataSource]="dataSource" matSort>
|
||||
<!-- identifier column -->
|
||||
<ng-container matColumnDef="identifier">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Bezeichner </mat-header-cell>
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Identifier </mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class='innerTable'>
|
||||
{{motion.identifier}}
|
||||
@ -36,13 +36,13 @@
|
||||
|
||||
<!-- title column -->
|
||||
<ng-container matColumnDef="title">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Titel </mat-header-cell>
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Title </mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class='innerTable'>
|
||||
<span class='motion-list-title'>{{motion.versions[0].title}}</span>
|
||||
<br>
|
||||
<span class='motion-list-from'>
|
||||
<span translate>von</span>
|
||||
<span translate>by</span>
|
||||
{{motion.submitterAsUser.username}}
|
||||
</span>
|
||||
</div>
|
||||
@ -51,13 +51,10 @@
|
||||
|
||||
<!-- state column -->
|
||||
<ng-container matColumnDef="state">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Status </mat-header-cell>
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> State </mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class='innerTable'>
|
||||
<fa-icon icon={{getStateIcon(motion.stateName)}}></fa-icon>
|
||||
<!-- <span class='motion.list.state'>
|
||||
{{motion.stateName}}
|
||||
</span> -->
|
||||
</div>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
@ -28,6 +28,11 @@ mat-table {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
mat-row:hover {
|
||||
cursor: pointer;
|
||||
background-color: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
|
||||
/** identifier */
|
||||
.mat-column-identifier {
|
||||
padding-left: 10px;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { BaseComponent } from 'app/base.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
@ -45,7 +46,12 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
||||
* @param titleService
|
||||
* @param translate
|
||||
*/
|
||||
constructor(titleService: Title, protected translate: TranslateService) {
|
||||
constructor(
|
||||
public router: Router,
|
||||
titleService: Title,
|
||||
protected translate: TranslateService,
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
super(titleService, translate);
|
||||
}
|
||||
|
||||
@ -72,6 +78,8 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
||||
|
||||
selectMotion(motion) {
|
||||
console.log('clicked a row, :', motion);
|
||||
|
||||
this.router.navigate(['./' + motion.id], { relativeTo: this.route });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { MotionListComponent } from './motion-list/motion-list.component';
|
||||
import { MotionDetailComponent } from './motion-detail/motion-detail.component';
|
||||
|
||||
const routes: Routes = [{ path: '', component: MotionListComponent }];
|
||||
const routes: Routes = [
|
||||
{ path: '', component: MotionListComponent },
|
||||
{ path: 'dummy', component: MotionDetailComponent },
|
||||
{ path: ':id', component: MotionDetailComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
|
@ -4,9 +4,10 @@ import { CommonModule } from '@angular/common';
|
||||
import { MotionsRoutingModule } from './motions-routing.module';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { MotionListComponent } from './motion-list/motion-list.component';
|
||||
import { MotionDetailComponent } from './motion-detail/motion-detail.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, MotionsRoutingModule, SharedModule],
|
||||
declarations: [MotionListComponent]
|
||||
declarations: [MotionListComponent, MotionDetailComponent]
|
||||
})
|
||||
export class MotionsModule {}
|
||||
|
@ -48,6 +48,10 @@ router-outlet ~ * {
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.generic-mini-button {
|
||||
bottom: -28px;
|
||||
z-index: 100;
|
||||
}
|
||||
.os-card {
|
||||
max-width: 90%;
|
||||
margin-top: 10px;
|
||||
|
Loading…
Reference in New Issue
Block a user