Unify motion block detail
Changes motion block list to look and feel like all the other lists
This commit is contained in:
parent
a1b7b1c69d
commit
1fc0ec02a9
@ -13,70 +13,79 @@
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Extra Controls -->
|
||||
<div class="extra-controls-slot" *ngIf="!vp.isMobile">
|
||||
<button
|
||||
*osPerms="['motions.can_manage', 'motions.can_manage_metadata']"
|
||||
mat-button
|
||||
(click)="onFollowRecButton()"
|
||||
[disabled]="isFollowingProhibited()"
|
||||
>
|
||||
<os-icon-container icon="done_all">
|
||||
<span translate>Follow recommendations for all motions</span>
|
||||
</os-icon-container>
|
||||
</button>
|
||||
</div>
|
||||
</os-head-bar>
|
||||
|
||||
<mat-card>
|
||||
<button
|
||||
*osPerms="['motions.can_manage', 'motions.can_manage_metadata']"
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
(click)="onFollowRecButton()"
|
||||
[disabled]="isFollowingProhibited()"
|
||||
>
|
||||
<mat-icon>done_all</mat-icon>
|
||||
<span translate>Follow recommendations for all motions</span>
|
||||
</button>
|
||||
<os-list-view-table
|
||||
[repo]="motionRepo"
|
||||
[filterService]="filterService"
|
||||
[columns]="tableColumnDefinition"
|
||||
[filterProps]="filterProps"
|
||||
(dataSourceChange)="onDataSourceChange($event)"
|
||||
>
|
||||
<!-- Title column -->
|
||||
<div *pblNgridCellDef="'title'; row as motion; rowContext as rowContext" class="cell-slot fill motion-block-title">
|
||||
<a class="detail-link" [routerLink]="motion.getDetailStateURL()" *ngIf="!isMultiSelect"></a>
|
||||
<span>{{ motion.getTitle() }}</span>
|
||||
</div>
|
||||
|
||||
<pbl-ngrid
|
||||
class="block-detail-table"
|
||||
cellTooltip
|
||||
showHeader="true"
|
||||
vScrollFixed="80"
|
||||
[dataSource]="dataSource"
|
||||
[columns]="columnSet"
|
||||
>
|
||||
<!-- Title column -->
|
||||
<div
|
||||
*pblNgridCellDef="'title'; row as motion; rowContext as rowContext"
|
||||
class="cell-slot fill motion-block-title"
|
||||
>
|
||||
<a class="detail-link" [routerLink]="motion.getDetailStateURL()" *ngIf="!isMultiSelect"></a>
|
||||
<span>{{ motion.getTitle() }}</span>
|
||||
</div>
|
||||
|
||||
<!-- State column -->
|
||||
<div *pblNgridCellDef="'state'; row as motion" class="cell-slot fill">
|
||||
<div class="chip-container">
|
||||
<mat-basic-chip disableRipple [ngClass]="motion.stateCssColor">
|
||||
{{ getStateLabel(motion) }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recommendation column -->
|
||||
<div *pblNgridCellDef="'recommendation'; row as motion" class="cell-slot fill">
|
||||
<mat-basic-chip *ngIf="!!motion.recommendation" disableRipple class="bluegrey">
|
||||
{{ getRecommendationLabel(motion) }}
|
||||
<!-- State column -->
|
||||
<div *pblNgridCellDef="'state'; row as motion" class="cell-slot fill">
|
||||
<div class="chip-container">
|
||||
<mat-basic-chip disableRipple [ngClass]="motion.stateCssColor">
|
||||
{{ getStateLabel(motion) }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Remove from block column -->
|
||||
<div *pblNgridCellDef="'remove'; row as motion" class="cell-slot fill">
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
matTooltip="{{ 'Remove from motion block' | translate }}"
|
||||
(click)="onRemoveMotionButton(motion)"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</pbl-ngrid>
|
||||
</mat-card>
|
||||
<!-- Recommendation column -->
|
||||
<div *pblNgridCellDef="'recommendation'; row as motion" class="cell-slot fill">
|
||||
<mat-basic-chip *ngIf="!!motion.recommendation" disableRipple class="bluegrey">
|
||||
{{ getRecommendationLabel(motion) }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
|
||||
<!-- Remove from block column -->
|
||||
<div *pblNgridCellDef="'remove'; row as motion" class="cell-slot fill">
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
matTooltip="{{ 'Remove from motion block' | translate }}"
|
||||
(click)="onRemoveMotionButton(motion)"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</os-list-view-table>
|
||||
|
||||
<!-- The menu content -->
|
||||
<mat-menu #motionBlockMenu="matMenu">
|
||||
<div *ngIf="vp.isMobile">
|
||||
<button
|
||||
*osPerms="['motions.can_manage', 'motions.can_manage_metadata']"
|
||||
mat-menu-item
|
||||
(click)="onFollowRecButton()"
|
||||
[disabled]="isFollowingProhibited()"
|
||||
>
|
||||
<mat-icon>done_all</mat-icon>
|
||||
<span translate>Follow recommendations for all motions</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<os-speaker-button [menuItem]="true" [object]="block"></os-speaker-button>
|
||||
|
||||
<os-projector-button *ngIf="block" [object]="block" [menuItem]="true"></os-projector-button>
|
||||
|
@ -1,30 +1,5 @@
|
||||
@import '~assets/styles/tables.scss';
|
||||
|
||||
.block-detail-table {
|
||||
margin-top: 10px;
|
||||
height: calc(100vh - 250px);
|
||||
|
||||
::ng-deep .pbl-ngrid-row {
|
||||
height: 80px !important;
|
||||
}
|
||||
|
||||
.pbl-ngrid-column-title {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 960px) {
|
||||
.block-detail-table {
|
||||
height: calc(100vh - 186px);
|
||||
}
|
||||
}
|
||||
|
||||
.motion-block-title {
|
||||
&.pbl-ngrid-cell {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-form {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -6,17 +6,20 @@ import { Title } from '@angular/platform-browser';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { columnFactory, createDS, PblColumnDefinition, PblDataSource } from '@pebula/ngrid';
|
||||
import { PblColumnDefinition } from '@pebula/ngrid';
|
||||
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
|
||||
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import { infoDialogSettings } from 'app/shared/utils/dialog-settings';
|
||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||
import { BaseListViewComponent } from 'app/site/base/base-list-view';
|
||||
import { ViewMotion } from 'app/site/motions/models/view-motion';
|
||||
import { ViewMotionBlock } from 'app/site/motions/models/view-motion-block';
|
||||
import { BlockDetailFilterListService } from 'app/site/motions/services/block-detail-filter-list.service';
|
||||
|
||||
/**
|
||||
* Detail component to display one motion block
|
||||
@ -26,52 +29,48 @@ import { ViewMotionBlock } from 'app/site/motions/models/view-motion-block';
|
||||
templateUrl: './motion-block-detail.component.html',
|
||||
styleUrls: ['./motion-block-detail.component.scss']
|
||||
})
|
||||
export class MotionBlockDetailComponent extends BaseViewComponent implements OnInit {
|
||||
export class MotionBlockDetailComponent extends BaseListViewComponent<ViewMotion> implements OnInit {
|
||||
/**
|
||||
* Holds the block ID
|
||||
*/
|
||||
private blockId: number;
|
||||
|
||||
/**
|
||||
* Determines the block id from the given URL
|
||||
*/
|
||||
public block: ViewMotionBlock;
|
||||
|
||||
/**
|
||||
* Data source for the motions in the block
|
||||
* To quick-filter the list
|
||||
*/
|
||||
public dataSource: PblDataSource<ViewMotion>;
|
||||
public filterProps = ['submitters', 'title', 'identifier'];
|
||||
|
||||
/**
|
||||
* Columns to display in table when desktop view is available
|
||||
* Define the columns to show
|
||||
*/
|
||||
public tableColumnDefinition: PblColumnDefinition[] = [];
|
||||
|
||||
/**
|
||||
* Define the columns to show
|
||||
* TODO: The translation will not update when the
|
||||
*/
|
||||
public columnSet = columnFactory()
|
||||
.table(
|
||||
{
|
||||
prop: 'title',
|
||||
label: this.translate.instant('Title'),
|
||||
width: 'auto'
|
||||
},
|
||||
{
|
||||
prop: 'state',
|
||||
label: this.translate.instant('State'),
|
||||
width: '30%',
|
||||
minWidth: 60
|
||||
},
|
||||
{
|
||||
prop: 'recommendation',
|
||||
label: this.translate.instant('Recommendation'),
|
||||
width: '30%',
|
||||
minWidth: 60
|
||||
},
|
||||
{
|
||||
prop: 'remove',
|
||||
label: '',
|
||||
width: '40px'
|
||||
}
|
||||
)
|
||||
.build();
|
||||
public tableColumnDefinition: PblColumnDefinition[] = [
|
||||
{
|
||||
prop: 'title',
|
||||
width: 'auto'
|
||||
},
|
||||
{
|
||||
prop: 'state',
|
||||
width: '30%',
|
||||
minWidth: 60
|
||||
},
|
||||
{
|
||||
prop: 'recommendation',
|
||||
label: this.translate.instant('Recommendation'),
|
||||
width: '30%',
|
||||
minWidth: 60
|
||||
},
|
||||
{
|
||||
prop: 'remove',
|
||||
label: '',
|
||||
width: '40px'
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* The form to edit blocks
|
||||
@ -105,13 +104,18 @@ export class MotionBlockDetailComponent extends BaseViewComponent implements OnI
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
protected repo: MotionBlockRepositoryService,
|
||||
protected motionRepo: MotionRepositoryService,
|
||||
public motionRepo: MotionRepositoryService,
|
||||
private promptService: PromptService,
|
||||
private fb: FormBuilder,
|
||||
private dialog: MatDialog,
|
||||
private itemRepo: ItemRepositoryService
|
||||
private itemRepo: ItemRepositoryService,
|
||||
storage: StorageService,
|
||||
public filterService: BlockDetailFilterListService,
|
||||
public vp: ViewportService
|
||||
) {
|
||||
super(titleService, translate, matSnackBar);
|
||||
super(titleService, translate, matSnackBar, storage);
|
||||
this.blockId = parseInt(this.route.snapshot.params.id, 10);
|
||||
this.filterService.blockId = this.blockId;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,22 +123,12 @@ export class MotionBlockDetailComponent extends BaseViewComponent implements OnI
|
||||
* Sets the title, observes the block and the motions belonging in this block
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
super.setTitle('Motion block');
|
||||
|
||||
const blockId = parseInt(this.route.snapshot.params.id, 10);
|
||||
|
||||
// pseudo filter
|
||||
this.subscriptions.push(
|
||||
this.repo.getViewModelObservable(blockId).subscribe(newBlock => {
|
||||
this.repo.getViewModelObservable(this.blockId).subscribe(newBlock => {
|
||||
if (newBlock) {
|
||||
super.setTitle(newBlock.getTitle());
|
||||
super.setTitle(`${this.translate.instant('Motion block')} - ${newBlock.getTitle()}`);
|
||||
this.block = newBlock;
|
||||
|
||||
this.dataSource = createDS<ViewMotion>()
|
||||
.onTrigger(() => {
|
||||
return this.block.motions;
|
||||
})
|
||||
.create();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -0,0 +1,18 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { BlockDetailFilterListService } from './block-detail-filter-list.service';
|
||||
|
||||
describe('BlockDetailFilterListService', () => {
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: BlockDetailFilterListService = TestBed.get(BlockDetailFilterListService);
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,83 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { OpenSlidesStatusService } from 'app/core/core-services/openslides-status.service';
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
|
||||
import { MotionCommentSectionRepositoryService } from 'app/core/repositories/motions/motion-comment-section-repository.service';
|
||||
import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service';
|
||||
import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { MotionFilterListService } from './motion-filter-list.service';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
|
||||
/**
|
||||
* Filter service for motion blocks
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class BlockDetailFilterListService extends MotionFilterListService {
|
||||
/**
|
||||
* Private acessor for the blockId
|
||||
*/
|
||||
private _blockId: number;
|
||||
|
||||
/**
|
||||
* setter for the blockId
|
||||
*/
|
||||
public set blockId(id: number) {
|
||||
this._blockId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param store
|
||||
* @param OSStatus
|
||||
* @param categoryRepo
|
||||
* @param motionBlockRepo
|
||||
* @param commentRepo
|
||||
* @param tagRepo
|
||||
* @param workflowRepo
|
||||
* @param translate
|
||||
* @param operator
|
||||
* @param config
|
||||
*/
|
||||
public constructor(
|
||||
store: StorageService,
|
||||
OSStatus: OpenSlidesStatusService,
|
||||
categoryRepo: CategoryRepositoryService,
|
||||
motionBlockRepo: MotionBlockRepositoryService,
|
||||
commentRepo: MotionCommentSectionRepositoryService,
|
||||
tagRepo: TagRepositoryService,
|
||||
workflowRepo: WorkflowRepositoryService,
|
||||
translate: TranslateService,
|
||||
operator: OperatorService,
|
||||
config: ConfigService
|
||||
) {
|
||||
super(
|
||||
store,
|
||||
OSStatus,
|
||||
categoryRepo,
|
||||
motionBlockRepo,
|
||||
commentRepo,
|
||||
tagRepo,
|
||||
workflowRepo,
|
||||
translate,
|
||||
operator,
|
||||
config
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override from parent
|
||||
* @param viewMotions
|
||||
* @return
|
||||
*/
|
||||
protected preFilter(viewMotions: ViewMotion[]): ViewMotion[] {
|
||||
return viewMotions.filter(motion => motion.motion_block_id === this._blockId);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user