Skip to content

Commit

Permalink
Adds bulk actions for motions
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrielInTheWorld committed Nov 6, 2020
1 parent d6f51bd commit 6ab4acf
Show file tree
Hide file tree
Showing 38 changed files with 621 additions and 454 deletions.
3 changes: 3 additions & 0 deletions client/src/app/core/actions/agenda-item-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export namespace AgendaItemAction {
export const DELETE = 'agenda_item.delete';
export const SORT = 'agenda_item.sort';
export const NUMBERING = 'agenda_item.numbering';
export const ASSIGN = 'agenda_item.assign';

interface OptionalPayload {
item_number?: string;
Expand All @@ -29,6 +30,8 @@ export namespace AgendaItemAction {
}

export interface UpdatePayload extends Identifiable, OptionalPayload {}
export interface DeletePayload extends Identifiable {}

export interface AssignPayload extends HasMeetingId {
ids: Id[];
parent_id: Id;
Expand Down
1 change: 1 addition & 0 deletions client/src/app/core/core-services/action.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class ActionService {
}

private async _sendRequest<T>(request: RequestInfo): Promise<T> {
console.log('sendRequest', request);
return await this.http.post<T>(this.ACTION_URL, [request]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export interface AgendaListTitle {
subtitle?: string;
}

export type AgendaItemType = 1 | 2 | 3;

/**
* Repository service for items
*
Expand Down Expand Up @@ -178,4 +180,24 @@ export class AgendaItemRepositoryService extends BaseRepositoryWithActiveMeeting
});
return duration;
}

public bulkOpenItems(items: ViewAgendaItem[]): Promise<void> {
const payload: AgendaItemAction.UpdatePayload[] = items.map(item => ({ closed: false, id: item.id }));
return this.sendBulkActionToBackend(AgendaItemAction.UPDATE, payload);
}

public bulkCloseItems(items: ViewAgendaItem[]): Promise<void> {
const payload: AgendaItemAction.UpdatePayload[] = items.map(item => ({ closed: true, id: item.id }));
return this.sendBulkActionToBackend(AgendaItemAction.UPDATE, payload);
}

public bulkSetAgendaType(items: ViewAgendaItem[], agendaType: AgendaItemType): Promise<void> {
const payload: AgendaItemAction.UpdatePayload[] = items.map(item => ({ id: item.id, type: agendaType }));
return this.sendBulkActionToBackend(AgendaItemAction.UPDATE, payload);
}

public bulkRemoveItemsFromAgenda(items: ViewAgendaItem[]): Promise<void> {
const payload: AgendaItemAction.DeletePayload[] = items.map(item => ({ id: item.id }));
return this.sendBulkActionToBackend(AgendaItemAction.DELETE, payload);
}
}
5 changes: 3 additions & 2 deletions client/src/app/core/repositories/base-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,9 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
});
}

protected raiseError = (errorMessage: string | Error) => {
this.repositoryServiceCollector.errorService.showError(errorMessage);
protected raiseError = (error: Error) => {
this.repositoryServiceCollector.errorService.showError(error);
throw error;
};

protected sendActionToBackend(action: string, payload: any): Promise<any> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ export class MotionBlockRepositoryService extends BaseIsAgendaItemAndListOfSpeak
}

public create(partialModel: Partial<MotionBlockAction.CreatePayload>): Promise<Identifiable> {
const payload: MotionBlockAction.CreatePayload = {
meeting_id: this.activeMeetingIdService.meetingId,
title: partialModel.title,
internal: partialModel.internal,
...createAgendaItem(partialModel)
};
const payload: MotionBlockAction.CreatePayload = this.getCreatePayload(partialModel);
return this.sendActionToBackend(MotionBlockAction.CREATE, payload);
}

public bulkCreate(motionBlocks: Partial<MotionBlock>[]): Promise<Identifiable[]> {
const payload: MotionBlockAction.CreatePayload[] = motionBlocks.map(block => this.getCreatePayload(block));
return this.sendBulkActionToBackend(MotionBlockAction.CREATE, payload);
}

public update(update: Partial<MotionBlock>, viewModel: ViewMotionBlock): Promise<void> {
const payload: MotionBlockAction.UpdatePayload = {
id: viewModel.id,
Expand Down Expand Up @@ -116,4 +116,13 @@ export class MotionBlockRepositoryService extends BaseIsAgendaItemAndListOfSpeak
return this.languageCollator.compare(a.title, b.title);
});
}

private getCreatePayload(partialModel: Partial<MotionBlockAction.CreatePayload>): MotionBlockAction.CreatePayload {
return {
meeting_id: this.activeMeetingIdService.meetingId,
title: partialModel.title,
internal: partialModel.internal,
...createAgendaItem(partialModel)
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@ export class MotionCategoryRepositoryService extends BaseRepositoryWithActiveMee
}

public create(partialCategory: Partial<MotionCategory>): Promise<Identifiable> {
const payload: MotionCategoryAction.CreatePayload = {
meeting_id: this.activeMeetingIdService.meetingId,
name: partialCategory.name,
prefix: partialCategory.prefix,
parent_id: partialCategory.parent_id
};
const payload: MotionCategoryAction.CreatePayload = this.getCreatePayload(partialCategory);
return this.sendActionToBackend(MotionCategoryAction.CREATE, payload);
}

public bulkCreate(categories: Partial<MotionCategoryAction.CreatePayload>[]): Promise<Identifiable[]> {
const payload: MotionCategoryAction.CreatePayload[] = categories.map(category =>
this.getCreatePayload(category)
);
return this.sendBulkActionToBackend(MotionCategoryAction.CREATE, payload);
}

public update(update: Partial<MotionCategory>, viewModel: ViewMotionCategory): Promise<void> {
const payload: MotionCategoryAction.UpdatePayload = {
id: viewModel.id,
Expand Down Expand Up @@ -116,4 +118,13 @@ export class MotionCategoryRepositoryService extends BaseRepositoryWithActiveMee
};
return this.actions.sendRequest(MotionCategoryAction.SORT, payload);
}

private getCreatePayload(partialCategory: Partial<MotionCategory>): MotionCategoryAction.CreatePayload {
return {
meeting_id: this.activeMeetingIdService.meetingId,
name: partialCategory.name,
prefix: partialCategory.prefix,
parent_id: partialCategory.parent_id
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
return this.sendActionToBackend(MotionAction.CREATE, payload);
}

public update(update: Partial<Motion>, viewModel: ViewMotion): Promise<void> {
public update(update: Partial<MotionAction.UpdatePayload>, viewModel: ViewMotion): Promise<void> {
const payload: MotionAction.UpdatePayload = {
id: viewModel.id,
number: update.number,
Expand All @@ -144,7 +144,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
return this.sendActionToBackend(MotionAction.UPDATE, payload);
}

private updateMetadata(update: Partial<MotionAction.UpdateMetadataPayload>, viewMotion: ViewMotion): Promise<void> {
public updateMetadata(update: Partial<MotionAction.UpdateMetadataPayload>, viewMotion: ViewMotion): Promise<void> {
const payload: MotionAction.UpdateMetadataPayload = {
id: viewMotion.id,
attachment_ids: update.attachment_ids,
Expand Down Expand Up @@ -222,7 +222,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
public getAgendaListTitle = (viewMotion: ViewMotion) => {
const numberPrefix = this.agendaItemRepo.getItemNumberPrefix(viewMotion);
// Append the verbose name only, if not the special format 'Motion <number>' is used.
let title;
let title: string;
if (viewMotion.number) {
title = `${numberPrefix}${this.translate.instant('Motion')} ${viewMotion.number} · ${viewMotion.title}`;
} else {
Expand Down Expand Up @@ -305,45 +305,6 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
return this.sendActionToBackend(MotionAction.RESET_RECOMMENDATION, payload);
}

/**
* Set the state of motions in bulk
*
* @param viewMotions target motions
* @param stateId the number that indicates the state
*/
public async setMultiState(viewMotions: ViewMotion[], stateId: number): Promise<void> {
const payload: MotionAction.SetStatePayload[] = viewMotions.map(motion => {
return { id: motion.id, state_id: stateId };
});
await this.sendBulkActionToBackend(MotionAction.UPDATE_METADATA, payload);
}

/**
* Set the motion blocks of motions in bulk
*
* @param viewMotions target motions
* @param motionblockId the number that indicates the motion block
*/
public async setMultiMotionBlock(viewMotions: ViewMotion[], motionblockId: number): Promise<void> {
const payload: MotionAction.UpdateMetadataPayload[] = viewMotions.map(motion => {
return { id: motion.id, block_id: motionblockId };
});
await this.sendBulkActionToBackend(MotionAction.UPDATE_METADATA, payload);
}

/**
* Set the category of motions in bulk
*
* @param viewMotions target motions
* @param categoryId the number that indicates the category
*/
public async setMultiCategory(viewMotions: ViewMotion[], categoryId: number): Promise<void> {
const payload: MotionAction.UpdateMetadataPayload[] = viewMotions.map(motion => {
return { id: motion.id, category_id: categoryId };
});
await this.sendBulkActionToBackend(MotionAction.UPDATE_METADATA, payload);
}

/**
* Set the category of a motion
*
Expand Down Expand Up @@ -384,16 +345,6 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
return this.updateMetadata({ tag_ids: tag_ids }, viewMotion);
}

/**
* Sets the submitters by sending a request to the server,
*
* @param viewMotion The motion to change the submitters from
* @param submitterUserIds The submitters to set
*/
public async setSubmitters(viewMotion: ViewMotion, submitterUserIds: number[]): Promise<void> {
return this.update({ submitter_ids: submitterUserIds }, viewMotion);
}

/**
* Sends the changed nodes to the server.
*
Expand Down Expand Up @@ -637,7 +588,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
public getParagraphsToChoose(motion: ViewMotion, lineLength: number): ParagraphToChoose[] {
const parent = motion.hasLeadMotion ? motion.lead_motion : motion;
return this.getTextParagraphs(parent, true, lineLength).map((paragraph: string, index: number) => {
let localParagraph;
let localParagraph: string;
if (motion.hasLeadMotion) {
localParagraph = motion.amendment_paragraph(index) ? motion.amendment_paragraph(index) : paragraph;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';

import { MotionWorkflowAction } from 'app/core/actions/motion-workflow-action';
import { DEFAULT_FIELDSET, Fieldsets } from 'app/core/core-services/model-request-builder.service';
import { Id } from 'app/core/definitions/key-types';
import { Identifiable } from 'app/shared/models/base/identifiable';
import { MotionWorkflow } from 'app/shared/models/motions/motion-workflow';
import { ViewMotion } from 'app/site/motions/models/view-motion';
Expand Down Expand Up @@ -31,6 +32,16 @@ export class MotionWorkflowRepositoryService extends BaseRepositoryWithActiveMee
super(repositoryServiceCollector, MotionWorkflow);
}

public getFieldsets(): Fieldsets<MotionWorkflow> {
const nameFields: (keyof MotionWorkflow)[] = ['name'];
const listFields: (keyof MotionWorkflow)[] = nameFields;
return {
[DEFAULT_FIELDSET]: listFields,
name: nameFields,
list: listFields
};
}

public getTitle = (viewMotionWorkflow: ViewMotionWorkflow) => {
return viewMotionWorkflow.name;
};
Expand All @@ -43,28 +54,22 @@ export class MotionWorkflowRepositoryService extends BaseRepositoryWithActiveMee
* Returns all workflowStates that cover the list of viewMotions given
*
* @param motions The motions to get the workflows from
*
* @returns The workflow states to the given motion
*/
public getWorkflowStatesForMotions(motions: ViewMotion[]): ViewMotionState[] {
let states: ViewMotionState[] = [];
const workflowIds = motions
.map(motion => motion.workflow_id)
.filter((value, index, self) => self.indexOf(value) === index);
workflowIds.forEach(id => {
const workflow = this.getViewModel(id);
states = states.concat(workflow.states);
});
return states;
const workflows: ViewMotionWorkflow[] = [];
for (const motion of motions) {
const motionState = motion.state;
if (motionState && workflows.indexOf(motionState.workflow) === -1) {
workflows.push(motionState.workflow);
}
}
return workflows.flatMap((workflow: ViewMotionWorkflow) => workflow.states);
}

public getFieldsets(): Fieldsets<MotionWorkflow> {
const nameFields: (keyof MotionWorkflow)[] = ['name'];
const listFields: (keyof MotionWorkflow)[] = nameFields;
return {
[DEFAULT_FIELDSET]: listFields,
name: nameFields,
list: listFields
};
public getWorkflowByStateId(stateId: Id): ViewMotionWorkflow {
return this.getViewModelList().find(workflow => workflow.state_ids.includes(stateId));
}

public create(partialModel: Partial<MotionWorkflow>): Promise<Identifiable> {
Expand Down
17 changes: 13 additions & 4 deletions client/src/app/core/repositories/tags/tag-repository.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ export class TagRepositoryService extends BaseRepositoryWithActiveMeeting<ViewTa
}

public async create(partialTag: Partial<Tag>): Promise<Identifiable> {
const payload: TagAction.CreatePayload = {
name: partialTag.name,
meeting_id: this.activeMeetingIdService.meetingId
};
const payload: TagAction.CreatePayload = this.getCreatePayload(partialTag);
return this.sendActionToBackend(TagAction.CREATE, payload);
}

public bulkCreate(tags: Partial<Tag>[]): Promise<Identifiable[]> {
const payload: TagAction.CreatePayload[] = tags.map(tag => this.getCreatePayload(tag));
return this.sendBulkActionToBackend(TagAction.CREATE, payload);
}

public async update(update: Partial<Tag>, viewModel: ViewTag): Promise<void> {
const payload: TagAction.UpdatePayload = {
id: viewModel.id,
Expand Down Expand Up @@ -69,4 +71,11 @@ export class TagRepositoryService extends BaseRepositoryWithActiveMeeting<ViewTa
return this.languageCollator.compare(a.name, b.name);
});
}

private getCreatePayload(partialTag: Partial<Tag>): TagAction.CreatePayload {
return {
name: partialTag.name,
meeting_id: this.activeMeetingIdService.meetingId
};
}
}
Loading

0 comments on commit 6ab4acf

Please sign in to comment.