Merge pull request #3867 from FinnStutzenstein/baseRepo
first work for BaseRepo
This commit is contained in:
commit
34412c7d9e
127
client/src/app/site/base-repository.ts
Normal file
127
client/src/app/site/base-repository.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import { OpenSlidesComponent } from '../openslides.component';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { BaseViewModel } from './base-view-model';
|
||||
import { BaseModel, ModelConstructor } from '../shared/models/base.model';
|
||||
import { CollectionStringModelMapperService } from '../core/services/collectionStringModelMapper.service';
|
||||
|
||||
export abstract class BaseRepository<V extends BaseViewModel, M extends BaseModel> extends OpenSlidesComponent {
|
||||
/**
|
||||
* Stores all the viewModel in an object
|
||||
*/
|
||||
protected viewModelStore: { [modelId: number]: V } = {};
|
||||
|
||||
/**
|
||||
* Stores subjects to viewModels in a list
|
||||
*/
|
||||
protected viewModelSubjects: { [modelId: number]: BehaviorSubject<V> } = {};
|
||||
|
||||
/**
|
||||
* Observable subject for the whole list
|
||||
*/
|
||||
protected viewModelListSubject: BehaviorSubject<V[]> = new BehaviorSubject<V[]>(null);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param baseModelCtor The model constructor of which this repository is about.
|
||||
* @param depsModelCtors A list of constructors that are used in the view model.
|
||||
* If one of those changes, the view models will be updated.
|
||||
*/
|
||||
public constructor(
|
||||
protected baseModelCtor: ModelConstructor<M>,
|
||||
protected depsModelCtors: ModelConstructor<BaseModel>[]
|
||||
) {
|
||||
super();
|
||||
|
||||
// Populate the local viewModelStore with ViewModel Objects.
|
||||
this.DS.getAll(baseModelCtor).forEach((model: M) => {
|
||||
this.viewModelStore[model.id] = this.createViewModel(model);
|
||||
this.updateViewModelObservable(model.id);
|
||||
});
|
||||
this.updateViewModelListObservable();
|
||||
|
||||
// Could be raise in error if the root injector is not known
|
||||
this.DS.changeObservable.subscribe(model => {
|
||||
if (model instanceof this.baseModelCtor) {
|
||||
// Add new and updated motions to the viewModelStore
|
||||
this.viewModelStore[model.id] = this.createViewModel(model as M);
|
||||
this.updateAllObservables(model.id);
|
||||
} else {
|
||||
const dependencyChanged: boolean = this.depsModelCtors.some(ctor => {
|
||||
return model instanceof ctor;
|
||||
});
|
||||
if (dependencyChanged) {
|
||||
// if an domain object we need was added or changed, update viewModelStore
|
||||
this.getViewModelList().forEach(viewModel => {
|
||||
viewModel.updateValues(model);
|
||||
});
|
||||
this.updateAllObservables(model.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Watch the Observables for deleting
|
||||
this.DS.deletedObservable.subscribe(model => {
|
||||
if (model.collection === CollectionStringModelMapperService.getCollectionString(baseModelCtor)) {
|
||||
delete this.viewModelStore[model.id];
|
||||
this.updateAllObservables(model.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract createViewModel(model: M): V;
|
||||
|
||||
/**
|
||||
* helper function to return one viewModel
|
||||
*/
|
||||
protected getViewModel(id: number): V {
|
||||
return this.viewModelStore[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* helper function to return the viewModel as array
|
||||
*/
|
||||
protected getViewModelList(): V[] {
|
||||
return Object.values(this.viewModelStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the current observable for one viewModel
|
||||
*/
|
||||
public getViewModelObservable(id: number): Observable<V> {
|
||||
if (!this.viewModelSubjects[id]) {
|
||||
this.viewModelSubjects[id] = new BehaviorSubject<V>(this.viewModelStore[id]);
|
||||
}
|
||||
return this.viewModelSubjects[id].asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the Observable of the whole store
|
||||
*/
|
||||
public getViewModelListObservable(): Observable<V[]> {
|
||||
return this.viewModelListSubject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ViewModel observable using a ViewModel corresponding to the id
|
||||
*/
|
||||
protected updateViewModelObservable(id: number): void {
|
||||
if (this.viewModelSubjects[id]) {
|
||||
this.viewModelSubjects[id].next(this.viewModelStore[id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update the observable of the list
|
||||
*/
|
||||
protected updateViewModelListObservable(): void {
|
||||
this.viewModelListSubject.next(this.getViewModelList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers both the observable update routines
|
||||
*/
|
||||
protected updateAllObservables(id: number): void {
|
||||
this.updateViewModelListObservable();
|
||||
this.updateViewModelObservable(id);
|
||||
}
|
||||
}
|
39
client/src/app/site/base-view-model.ts
Normal file
39
client/src/app/site/base-view-model.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { BaseModel } from '../shared/models/base.model';
|
||||
|
||||
/**
|
||||
* Base class for view models. alls view models should have titles.
|
||||
*/
|
||||
export abstract class BaseViewModel {
|
||||
public abstract updateValues(update: BaseModel): void;
|
||||
|
||||
/**
|
||||
* Should return the title for the detail view.
|
||||
* @param translate
|
||||
*/
|
||||
public abstract getTitle(translate: TranslateService): string;
|
||||
|
||||
/**
|
||||
* Should return the title for the list view.
|
||||
* @param translate
|
||||
*/
|
||||
public getListTitle(translate: TranslateService): string {
|
||||
return this.getTitle(translate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return the title for the projector.
|
||||
* @param translate
|
||||
*/
|
||||
public getProjector(translate: TranslateService): string {
|
||||
return this.getTitle(translate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return the title for the agenda list view.
|
||||
* @param translate
|
||||
*/
|
||||
public getAgendaTitle(translate: TranslateService): string {
|
||||
return this.getTitle(translate);
|
||||
}
|
||||
}
|
@ -90,7 +90,7 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
|
||||
} else {
|
||||
// load existing motion
|
||||
this.route.params.subscribe(params => {
|
||||
this.repo.getViewMotionObservable(params.id).subscribe(newViewMotion => {
|
||||
this.repo.getViewModelObservable(params.id).subscribe(newViewMotion => {
|
||||
this.motion = newViewMotion;
|
||||
});
|
||||
});
|
||||
|
@ -97,7 +97,7 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
|
||||
this.repo.getViewMotionListObservable().subscribe(newMotions => {
|
||||
this.repo.getViewModelListObservable().subscribe(newMotions => {
|
||||
this.dataSource.data = newMotions;
|
||||
});
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import { User } from '../../../shared/models/users/user';
|
||||
import { Workflow } from '../../../shared/models/motions/workflow';
|
||||
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
|
||||
import { BaseModel } from '../../../shared/models/base.model';
|
||||
import { BaseViewModel } from '../../base-view-model';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
/**
|
||||
* Motion class for the View
|
||||
@ -12,7 +14,7 @@ import { BaseModel } from '../../../shared/models/base.model';
|
||||
* Provides "safe" access to variables and functions in {@link Motion}
|
||||
* @ignore
|
||||
*/
|
||||
export class ViewMotion {
|
||||
export class ViewMotion extends BaseViewModel {
|
||||
private _motion: Motion;
|
||||
private _category: Category;
|
||||
private _submitters: User[];
|
||||
@ -70,7 +72,7 @@ export class ViewMotion {
|
||||
|
||||
public get categoryId(): number {
|
||||
if (this._motion && this._motion.category_id) {
|
||||
return this.category.id;
|
||||
return this._motion.category_id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -147,6 +149,8 @@ export class ViewMotion {
|
||||
workflow?: Workflow,
|
||||
state?: WorkflowState
|
||||
) {
|
||||
super();
|
||||
|
||||
this._motion = motion;
|
||||
this._category = category;
|
||||
this._submitters = submitters;
|
||||
@ -155,6 +159,10 @@ export class ViewMotion {
|
||||
this._state = state;
|
||||
}
|
||||
|
||||
public getTitle(translate?: TranslateService): string {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the local objects if required
|
||||
* @param update
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { DataSendService } from '../../../core/services/data-send.service';
|
||||
import { OpenSlidesComponent } from '../../../openslides.component';
|
||||
import { Motion } from '../../../shared/models/motions/motion';
|
||||
import { User } from '../../../shared/models/users/user';
|
||||
import { Category } from '../../../shared/models/motions/category';
|
||||
import { Workflow } from '../../../shared/models/motions/workflow';
|
||||
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
import { Observable, BehaviorSubject } from 'rxjs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { BaseRepository } from '../../base-repository';
|
||||
|
||||
/**
|
||||
* Repository Services for motions (and potentially categories)
|
||||
@ -23,22 +23,7 @@ import { Observable, BehaviorSubject } from 'rxjs';
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MotionRepositoryService extends OpenSlidesComponent {
|
||||
/**
|
||||
* Stores all the viewMotion in an object
|
||||
*/
|
||||
private viewMotionStore: { [motionId: number]: ViewMotion } = {};
|
||||
|
||||
/**
|
||||
* Stores subjects to viewMotions in a list
|
||||
*/
|
||||
private viewMotionSubjects: { [motionId: number]: BehaviorSubject<ViewMotion> } = {};
|
||||
|
||||
/**
|
||||
* Observable subject for the whole list
|
||||
*/
|
||||
private viewMotionListSubject: BehaviorSubject<ViewMotion[]> = new BehaviorSubject<ViewMotion[]>(null);
|
||||
|
||||
export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion> {
|
||||
/**
|
||||
* Creates a MotionRepository
|
||||
*
|
||||
@ -47,46 +32,7 @@ export class MotionRepositoryService extends OpenSlidesComponent {
|
||||
* @param DataSend
|
||||
*/
|
||||
public constructor(private dataSend: DataSendService) {
|
||||
super();
|
||||
|
||||
this.populateViewMotions();
|
||||
|
||||
// Could be raise in error if the root injector is not known
|
||||
this.DS.changeObservable.subscribe(model => {
|
||||
if (model instanceof Motion) {
|
||||
// Add new and updated motions to the viewMotionStore
|
||||
this.AddViewMotion(model);
|
||||
this.updateObservables(model.id);
|
||||
} else if (model instanceof Category || model instanceof User || model instanceof Workflow) {
|
||||
// if an domain object we need was added or changed, update ViewMotionStore
|
||||
this.getViewMotionList().forEach(viewMotion => {
|
||||
viewMotion.updateValues(model);
|
||||
});
|
||||
this.updateObservables(model.id);
|
||||
}
|
||||
});
|
||||
|
||||
// Watch the Observables for deleting
|
||||
this.DS.deletedObservable.subscribe(model => {
|
||||
if (model.collection === 'motions/motion') {
|
||||
delete this.viewMotionStore[model.id];
|
||||
this.updateObservables(model.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* called from the constructor.
|
||||
*
|
||||
* Populate the local viewMotionStore with ViewMotion Objects.
|
||||
* Does nothing if the database was not created yet.
|
||||
*/
|
||||
private populateViewMotions(): void {
|
||||
this.DS.getAll<Motion>(Motion).forEach(motion => {
|
||||
this.AddViewMotion(motion);
|
||||
this.updateViewMotionObservable(motion.id);
|
||||
});
|
||||
this.updateViewMotionListObservable();
|
||||
super(Motion, [Category, User, Workflow]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,7 +43,7 @@ export class MotionRepositoryService extends OpenSlidesComponent {
|
||||
*
|
||||
* @param motion blank motion domain object
|
||||
*/
|
||||
private AddViewMotion(motion: Motion): void {
|
||||
protected createViewModel(motion: Motion): ViewMotion {
|
||||
const category = this.DS.get(Category, motion.category_id);
|
||||
const submitters = this.DS.getMany(User, motion.submitterIds);
|
||||
const supporters = this.DS.getMany(User, motion.supporters_id);
|
||||
@ -106,7 +52,7 @@ export class MotionRepositoryService extends OpenSlidesComponent {
|
||||
if (workflow) {
|
||||
state = workflow.getStateById(motion.state_id);
|
||||
}
|
||||
this.viewMotionStore[motion.id] = new ViewMotion(motion, category, submitters, supporters, workflow, state);
|
||||
return new ViewMotion(motion, category, submitters, supporters, workflow, state);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,23 +78,6 @@ export class MotionRepositoryService extends OpenSlidesComponent {
|
||||
return this.dataSend.saveModel(updateMotion);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the current observable MotionView
|
||||
*/
|
||||
public getViewMotionObservable(id: number): Observable<ViewMotion> {
|
||||
if (!this.viewMotionSubjects[id]) {
|
||||
this.updateViewMotionObservable(id);
|
||||
}
|
||||
return this.viewMotionSubjects[id].asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the Observable of the whole store
|
||||
*/
|
||||
public getViewMotionListObservable(): Observable<ViewMotion[]> {
|
||||
return this.viewMotionListSubject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deleting a motion.
|
||||
*
|
||||
@ -159,36 +88,4 @@ export class MotionRepositoryService extends OpenSlidesComponent {
|
||||
public deleteMotion(viewMotion: ViewMotion): Observable<any> {
|
||||
return this.dataSend.delete(viewMotion.motion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ViewMotion observable using a ViewMotion corresponding to the id
|
||||
*/
|
||||
private updateViewMotionObservable(id: number): void {
|
||||
if (!this.viewMotionSubjects[id]) {
|
||||
this.viewMotionSubjects[id] = new BehaviorSubject<ViewMotion>(null);
|
||||
}
|
||||
this.viewMotionSubjects[id].next(this.viewMotionStore[id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* helper function to return the viewMotions as array
|
||||
*/
|
||||
private getViewMotionList(): ViewMotion[] {
|
||||
return Object.values(this.viewMotionStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* update the observable of the list
|
||||
*/
|
||||
private updateViewMotionListObservable(): void {
|
||||
this.viewMotionListSubject.next(this.getViewMotionList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers both the observable update routines
|
||||
*/
|
||||
private updateObservables(id: number): void {
|
||||
this.updateViewMotionListObservable();
|
||||
this.updateViewMotionObservable(id);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user