Motion detail with routing
For small screens only
This commit is contained in:
parent
7856b7e07f
commit
f01d3a5f6a
@ -8,7 +8,11 @@
|
|||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"prefix": "app",
|
"prefix": "app",
|
||||||
"schematics": {},
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"styleext": "scss"
|
||||||
|
}
|
||||||
|
},
|
||||||
"architect": {
|
"architect": {
|
||||||
"build": {
|
"build": {
|
||||||
"builder": "@angular-devkit/build-angular:browser",
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
@ -17,4 +17,8 @@ export class Category extends BaseModel {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
this.prefix = prefix;
|
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 { MotionLog } from './motion-log';
|
||||||
import { Config } from '../core/config';
|
import { Config } from '../core/config';
|
||||||
import { Workflow } from './workflow';
|
import { Workflow } from './workflow';
|
||||||
|
import { User } from '../users/user';
|
||||||
|
import { Category } from './category';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of Motion.
|
* Representation of Motion.
|
||||||
@ -78,6 +80,31 @@ export class Motion extends BaseModel {
|
|||||||
this.log_messages = log_messages;
|
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
|
* return the submitters as uses objects
|
||||||
*/
|
*/
|
||||||
@ -86,14 +113,39 @@ export class Motion extends BaseModel {
|
|||||||
this.submitters.forEach(submitter => {
|
this.submitters.forEach(submitter => {
|
||||||
submitterIds.push(submitter.user_id);
|
submitterIds.push(submitter.user_id);
|
||||||
});
|
});
|
||||||
const users = this.DS.get('users/user', ...submitterIds);
|
const users = this.DS.get(User, ...submitterIds);
|
||||||
return users;
|
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
|
* return the workflow state
|
||||||
*
|
*
|
||||||
* Right now only the default workflow is assumes
|
* Right now only the default workflow is assumes
|
||||||
|
* TODO: Motion workflow needs to be specific on the server
|
||||||
*/
|
*/
|
||||||
get stateName() {
|
get stateName() {
|
||||||
//get the default workflow
|
//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'>
|
<div class='custom-table-header on-transition-fade'>
|
||||||
<button mat-button>
|
<button mat-button>
|
||||||
SORIEREN NACH
|
<span translate>SORT</span>
|
||||||
</button>
|
</button>
|
||||||
<button mat-button>
|
<button mat-button>
|
||||||
FILTER
|
<span translate>FILTER</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-table class='on-transition-fade' [dataSource]="dataSource" matSort>
|
<mat-table class='on-transition-fade' [dataSource]="dataSource" matSort>
|
||||||
<!-- identifier column -->
|
<!-- identifier column -->
|
||||||
<ng-container matColumnDef="identifier">
|
<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">
|
<mat-cell *matCellDef="let motion">
|
||||||
<div class='innerTable'>
|
<div class='innerTable'>
|
||||||
{{motion.identifier}}
|
{{motion.identifier}}
|
||||||
@ -36,13 +36,13 @@
|
|||||||
|
|
||||||
<!-- title column -->
|
<!-- title column -->
|
||||||
<ng-container matColumnDef="title">
|
<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">
|
<mat-cell *matCellDef="let motion">
|
||||||
<div class='innerTable'>
|
<div class='innerTable'>
|
||||||
<span class='motion-list-title'>{{motion.versions[0].title}}</span>
|
<span class='motion-list-title'>{{motion.versions[0].title}}</span>
|
||||||
<br>
|
<br>
|
||||||
<span class='motion-list-from'>
|
<span class='motion-list-from'>
|
||||||
<span translate>von</span>
|
<span translate>by</span>
|
||||||
{{motion.submitterAsUser.username}}
|
{{motion.submitterAsUser.username}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -51,13 +51,10 @@
|
|||||||
|
|
||||||
<!-- state column -->
|
<!-- state column -->
|
||||||
<ng-container matColumnDef="state">
|
<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">
|
<mat-cell *matCellDef="let motion">
|
||||||
<div class='innerTable'>
|
<div class='innerTable'>
|
||||||
<fa-icon icon={{getStateIcon(motion.stateName)}}></fa-icon>
|
<fa-icon icon={{getStateIcon(motion.stateName)}}></fa-icon>
|
||||||
<!-- <span class='motion.list.state'>
|
|
||||||
{{motion.stateName}}
|
|
||||||
</span> -->
|
|
||||||
</div>
|
</div>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -28,6 +28,11 @@ mat-table {
|
|||||||
height: 60px;
|
height: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mat-row:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: rgba(0, 0, 0, 0.025);
|
||||||
|
}
|
||||||
|
|
||||||
/** identifier */
|
/** identifier */
|
||||||
.mat-column-identifier {
|
.mat-column-identifier {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { BaseComponent } from 'app/base.component';
|
import { BaseComponent } from 'app/base.component';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
@ -45,7 +46,12 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
|||||||
* @param titleService
|
* @param titleService
|
||||||
* @param translate
|
* @param translate
|
||||||
*/
|
*/
|
||||||
constructor(titleService: Title, protected translate: TranslateService) {
|
constructor(
|
||||||
|
public router: Router,
|
||||||
|
titleService: Title,
|
||||||
|
protected translate: TranslateService,
|
||||||
|
private route: ActivatedRoute
|
||||||
|
) {
|
||||||
super(titleService, translate);
|
super(titleService, translate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +78,8 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
|||||||
|
|
||||||
selectMotion(motion) {
|
selectMotion(motion) {
|
||||||
console.log('clicked a row, :', 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 { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule } from '@angular/router';
|
import { Routes, RouterModule } from '@angular/router';
|
||||||
import { MotionListComponent } from './motion-list/motion-list.component';
|
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({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
@ -4,9 +4,10 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { MotionsRoutingModule } from './motions-routing.module';
|
import { MotionsRoutingModule } from './motions-routing.module';
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
import { SharedModule } from '../../shared/shared.module';
|
||||||
import { MotionListComponent } from './motion-list/motion-list.component';
|
import { MotionListComponent } from './motion-list/motion-list.component';
|
||||||
|
import { MotionDetailComponent } from './motion-detail/motion-detail.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule, MotionsRoutingModule, SharedModule],
|
imports: [CommonModule, MotionsRoutingModule, SharedModule],
|
||||||
declarations: [MotionListComponent]
|
declarations: [MotionListComponent, MotionDetailComponent]
|
||||||
})
|
})
|
||||||
export class MotionsModule {}
|
export class MotionsModule {}
|
||||||
|
@ -48,6 +48,10 @@ router-outlet ~ * {
|
|||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.generic-mini-button {
|
||||||
|
bottom: -28px;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
.os-card {
|
.os-card {
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
Loading…
Reference in New Issue
Block a user