Merge pull request #4662 from FinnStutzenstein/repoSpeed
Speedup DS and repo updates, DSUpdateSlots, lazyloading history objects
This commit is contained in:
commit
d218a86f69
@ -3,7 +3,7 @@ import { Injectable, Injector } from '@angular/core';
|
||||
import { plugins } from '../../../plugins';
|
||||
import { CommonAppConfig } from '../../site/common/common.config';
|
||||
import { AppConfig, SearchableModelEntry, ModelEntry } from '../app-config';
|
||||
import { CollectionStringMapperService } from './collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from './collection-string-mapper.service';
|
||||
import { MediafileAppConfig } from '../../site/mediafiles/mediafile.config';
|
||||
import { MotionsAppConfig } from '../../site/motions/motions.config';
|
||||
import { ConfigAppConfig } from '../../site/config/config.config';
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { WebsocketService } from './websocket.service';
|
||||
import { CollectionStringMapperService } from './collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from './collection-string-mapper.service';
|
||||
import { DataStoreService } from './data-store.service';
|
||||
import { BaseModel } from '../../shared/models/base/base-model';
|
||||
import { DataStoreUpdateManagerService } from './data-store-update-manager.service';
|
||||
|
||||
interface AutoupdateFormat {
|
||||
/**
|
||||
@ -54,7 +55,8 @@ export class AutoupdateService {
|
||||
public constructor(
|
||||
private websocketService: WebsocketService,
|
||||
private DS: DataStoreService,
|
||||
private modelMapper: CollectionStringMapperService
|
||||
private modelMapper: CollectionStringMapperService,
|
||||
private DSUpdateManager: DataStoreUpdateManagerService
|
||||
) {
|
||||
this.websocketService.getOberservable<AutoupdateFormat>('autoupdate').subscribe(response => {
|
||||
this.storeResponse(response);
|
||||
@ -105,6 +107,8 @@ export class AutoupdateService {
|
||||
|
||||
// Normal autoupdate
|
||||
if (autoupdate.from_change_id <= maxChangeId + 1 && autoupdate.to_change_id > maxChangeId) {
|
||||
const updateSlot = await this.DSUpdateManager.getNewUpdateSlot(this.DS);
|
||||
|
||||
// Delete the removed objects from the DataStore
|
||||
for (const collection of Object.keys(autoupdate.deleted)) {
|
||||
await this.DS.remove(collection, autoupdate.deleted[collection]);
|
||||
@ -120,6 +124,8 @@ export class AutoupdateService {
|
||||
}
|
||||
|
||||
await this.DS.flushToStorage(autoupdate.to_change_id);
|
||||
|
||||
this.DSUpdateManager.commit(updateSlot);
|
||||
} else {
|
||||
// autoupdate fully in the future. we are missing something!
|
||||
this.requestChanges();
|
||||
|
@ -0,0 +1,17 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { E2EImportsModule } from '../../../e2e-imports.module';
|
||||
import { CollectionStringMapperService } from './collection-string-mapper.service';
|
||||
|
||||
describe('CollectionStringMapperService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [CollectionStringMapperService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([CollectionStringMapperService], (service: CollectionStringMapperService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
@ -17,6 +17,12 @@ interface UnifiedConstructors {
|
||||
*/
|
||||
type TypeIdentifier = UnifiedConstructors | BaseRepository<any, any> | string;
|
||||
|
||||
type CollectionStringMappedTypes = [
|
||||
ModelConstructor<BaseModel>,
|
||||
ViewModelConstructor<BaseViewModel>,
|
||||
BaseRepository<BaseViewModel, BaseModel>
|
||||
];
|
||||
|
||||
/**
|
||||
* Registeres the mapping between collection strings, models constructors, view
|
||||
* model constructors and repositories.
|
||||
@ -30,11 +36,7 @@ export class CollectionStringMapperService {
|
||||
* Maps collection strings to mapping entries
|
||||
*/
|
||||
private collectionStringMapping: {
|
||||
[collectionString: string]: [
|
||||
ModelConstructor<BaseModel>,
|
||||
ViewModelConstructor<BaseViewModel>,
|
||||
BaseRepository<BaseViewModel, BaseModel>
|
||||
];
|
||||
[collectionString: string]: CollectionStringMappedTypes;
|
||||
} = {};
|
||||
|
||||
public constructor() {}
|
||||
@ -65,6 +67,9 @@ export class CollectionStringMapperService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns true, if the given collection is known by this service.
|
||||
*/
|
||||
public isCollectionRegistered(collectionString: string): boolean {
|
||||
return !!this.collectionStringMapping[collectionString];
|
||||
}
|
||||
@ -100,4 +105,11 @@ export class CollectionStringMapperService {
|
||||
return this.collectionStringMapping[this.getCollectionString(obj)][2] as BaseRepository<V, M>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns all registered repositories.
|
||||
*/
|
||||
public getAllRepositories(): BaseRepository<any, any>[] {
|
||||
return Object.values(this.collectionStringMapping).map((types: CollectionStringMappedTypes) => types[2]);
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
describe('CollectionStringModelMapperService', () => {
|
||||
beforeEach(() => {});
|
||||
});
|
@ -0,0 +1,17 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { E2EImportsModule } from '../../../e2e-imports.module';
|
||||
import { DataStoreUpdateManagerService } from './data-store-update-manager.service';
|
||||
|
||||
describe('DataStoreUpdateManagerService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
providers: [DataStoreUpdateManagerService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([DataStoreUpdateManagerService], (service: DataStoreUpdateManagerService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
@ -0,0 +1,182 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Deferred } from '../deferred';
|
||||
import { DataStoreService } from './data-store.service';
|
||||
import { CollectionStringMapperService } from './collection-string-mapper.service';
|
||||
|
||||
export interface CollectionIds {
|
||||
[collection: string]: number[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for collecting data during the update phase of the DataStore.
|
||||
*/
|
||||
export class UpdateSlot {
|
||||
/**
|
||||
* Count instnaces of this class to easily compare them.
|
||||
*/
|
||||
private static ID_COUTNER = 1;
|
||||
|
||||
/**
|
||||
* Mapping of changed model ids to their collection.
|
||||
*/
|
||||
private changedModels: CollectionIds = {};
|
||||
|
||||
/**
|
||||
* Mapping of deleted models to their collection.
|
||||
*/
|
||||
private deletedModels: CollectionIds = {};
|
||||
|
||||
/**
|
||||
* The object's id.
|
||||
*/
|
||||
private _id: number;
|
||||
|
||||
/**
|
||||
* @param DS Carries the DataStore: TODO (see below `DataStoreUpdateManagerService.getNewUpdateSlot`)
|
||||
*/
|
||||
public constructor(public readonly DS: DataStoreService) {
|
||||
this._id = UpdateSlot.ID_COUTNER++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds changed model information
|
||||
*
|
||||
* @param collection The collection
|
||||
* @param id The id
|
||||
*/
|
||||
public addChangedModel(collection: string, id: number): void {
|
||||
if (!this.changedModels[collection]) {
|
||||
this.changedModels[collection] = [];
|
||||
}
|
||||
this.changedModels[collection].push(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds deleted model information
|
||||
*
|
||||
* @param collection The collection
|
||||
* @param id The id
|
||||
*/
|
||||
public addDeletedModel(collection: string, id: number): void {
|
||||
if (!this.deletedModels[collection]) {
|
||||
this.deletedModels[collection] = [];
|
||||
}
|
||||
this.deletedModels[collection].push(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param collection The collection
|
||||
* @returns the list of changed model ids for the collection
|
||||
*/
|
||||
public getChangedModelIdsForCollection(collection: string): number[] {
|
||||
return this.changedModels[collection] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the mapping of all changed models
|
||||
*/
|
||||
public getChangedModels(): CollectionIds {
|
||||
return this.changedModels;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param collection The collection
|
||||
* @returns the list of deleted model ids for the collection
|
||||
*/
|
||||
public getDeletedModelIdsForCollection(collection: string): number[] {
|
||||
return this.deletedModels[collection] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object to another update slot.
|
||||
*/
|
||||
public equal(other: UpdateSlot): boolean {
|
||||
return this._id === other._id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages updates in the DS. Collects all ids for changed and deleted models and bulk-update
|
||||
* affected repositories.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DataStoreUpdateManagerService {
|
||||
/**
|
||||
* The current update slot
|
||||
*/
|
||||
private currentUpdateSlot: UpdateSlot | null = null;
|
||||
|
||||
/**
|
||||
* Requests for getting an update slot.
|
||||
*/
|
||||
private updateSlotRequests: Deferred[] = [];
|
||||
|
||||
/**
|
||||
* @param mapperService
|
||||
*/
|
||||
public constructor(private mapperService: CollectionStringMapperService) {}
|
||||
|
||||
/**
|
||||
* Retrieve the current update slot.
|
||||
*/
|
||||
public getCurrentUpdateSlot(): UpdateSlot | null {
|
||||
return this.currentUpdateSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new update slot. Returns a promise that must be awaited, if there is another
|
||||
* update in progress.
|
||||
*
|
||||
* @param DS The DataStore. This is a hack, becuase we cannot use the DataStore
|
||||
* here, because these are cyclic dependencies... --> TODO
|
||||
*/
|
||||
public async getNewUpdateSlot(DS: DataStoreService): Promise<UpdateSlot> {
|
||||
if (this.currentUpdateSlot) {
|
||||
const request = new Deferred();
|
||||
this.updateSlotRequests.push(request);
|
||||
await request.promise;
|
||||
}
|
||||
this.currentUpdateSlot = new UpdateSlot(DS);
|
||||
return this.currentUpdateSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits the given update slot. THis slot must be the current one. If there are requests
|
||||
* for update slots queued, the next one will be served.
|
||||
*
|
||||
* Note: I added this param to make sure, that only the user of the slot
|
||||
* can commit the update and no one else.
|
||||
*
|
||||
* @param slot The slot to commit
|
||||
*/
|
||||
public commit(slot: UpdateSlot): void {
|
||||
if (!this.currentUpdateSlot || !this.currentUpdateSlot.equal(slot)) {
|
||||
throw new Error('No or wrong update slot to be finished!');
|
||||
}
|
||||
this.currentUpdateSlot = null;
|
||||
|
||||
// notify repositories in two phases
|
||||
const repositories = this.mapperService.getAllRepositories();
|
||||
|
||||
// Phase 1: deleting and creating of view models (in this order)
|
||||
repositories.forEach(repo => {
|
||||
repo.deleteModels(slot.getDeletedModelIdsForCollection(repo.collectionString));
|
||||
repo.changedModels(slot.getChangedModelIdsForCollection(repo.collectionString));
|
||||
});
|
||||
|
||||
// Phase 2: updating dependencies
|
||||
repositories.forEach(repo => {
|
||||
repo.updateDependencies(slot.getChangedModels());
|
||||
});
|
||||
|
||||
slot.DS.triggerModifiedObservable();
|
||||
|
||||
// serve next slot request
|
||||
if (this.updateSlotRequests.length > 0) {
|
||||
const request = this.updateSlotRequests.pop();
|
||||
request.resolve();
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,8 @@ import { Observable, Subject } from 'rxjs';
|
||||
|
||||
import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
|
||||
import { StorageService } from './storage.service';
|
||||
import { CollectionStringMapperService } from './collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from './collection-string-mapper.service';
|
||||
import { DataStoreUpdateManagerService } from './data-store-update-manager.service';
|
||||
|
||||
/**
|
||||
* Represents information about a deleted model.
|
||||
@ -68,59 +69,23 @@ export class DataStoreService {
|
||||
private jsonStore: JsonStorage = {};
|
||||
|
||||
/**
|
||||
* Observable subject for changed models in the datastore.
|
||||
* Subjects for changed elements (notified, even if there is a current update slot) for
|
||||
* a specific collection.
|
||||
*/
|
||||
private readonly changedSubject: Subject<BaseModel> = new Subject<BaseModel>();
|
||||
|
||||
/**
|
||||
* This is subject notify all subscribers _before_ the `secondaryModelChangeSubject`.
|
||||
* It's the same subject as the changedSubject.
|
||||
*/
|
||||
public readonly primaryModelChangeSubject = new Subject<BaseModel>();
|
||||
|
||||
/**
|
||||
* This is subject notify all subscribers _after_ the `primaryModelChangeSubject`.
|
||||
* It's the same subject as the changedSubject.
|
||||
*/
|
||||
public readonly secondaryModelChangeSubject = new Subject<BaseModel>();
|
||||
|
||||
/**
|
||||
* Observe the datastore for changes.
|
||||
*
|
||||
* @return an observable for changed models
|
||||
*/
|
||||
public get changeObservable(): Observable<BaseModel> {
|
||||
return this.changedSubject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Observable subject for changed models in the datastore.
|
||||
*/
|
||||
private readonly deletedSubject: Subject<DeletedInformation> = new Subject<DeletedInformation>();
|
||||
|
||||
/**
|
||||
* Observe the datastore for deletions.
|
||||
*
|
||||
* @return an observable for deleted objects.
|
||||
*/
|
||||
public get deletedObservable(): Observable<DeletedInformation> {
|
||||
return this.deletedSubject.asObservable();
|
||||
}
|
||||
private changedSubjects: { [collection: string]: Subject<BaseModel> } = {};
|
||||
|
||||
/**
|
||||
* Observable subject for changed or deleted models in the datastore.
|
||||
*/
|
||||
private readonly changedOrDeletedSubject: Subject<BaseModel | DeletedInformation> = new Subject<
|
||||
BaseModel | DeletedInformation
|
||||
>();
|
||||
private readonly modifiedSubject: Subject<void> = new Subject<void>();
|
||||
|
||||
/**
|
||||
* Observe the datastore for changes and deletions.
|
||||
*
|
||||
* @return an observable for changed and deleted objects.
|
||||
*/
|
||||
public get changedOrDeletedObservable(): Observable<BaseModel | DeletedInformation> {
|
||||
return this.changedOrDeletedSubject.asObservable();
|
||||
public get modifiedObservable(): Observable<void> {
|
||||
return this.modifiedSubject.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,12 +117,26 @@ export class DataStoreService {
|
||||
/**
|
||||
* @param storageService use StorageService to preserve the DataStore.
|
||||
* @param modelMapper
|
||||
* @param DSUpdateManager
|
||||
*/
|
||||
public constructor(private storageService: StorageService, private modelMapper: CollectionStringMapperService) {
|
||||
this.changeObservable.subscribe(model => {
|
||||
this.primaryModelChangeSubject.next(model);
|
||||
this.secondaryModelChangeSubject.next(model);
|
||||
});
|
||||
public constructor(
|
||||
private storageService: StorageService,
|
||||
private modelMapper: CollectionStringMapperService,
|
||||
private DSUpdateManager: DataStoreUpdateManagerService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get an model observable for models from a given collection. These observable will be notified,
|
||||
* even if there is an active update slot. So use this with caution (-> only collections with less models).
|
||||
*
|
||||
* @param collectionType The collection
|
||||
*/
|
||||
public getChangeObservable<T extends BaseModel>(collectionType: ModelConstructor<T> | string): Observable<T> {
|
||||
const collection = this.getCollectionString(collectionType);
|
||||
if (!this.changedSubjects[collection]) {
|
||||
this.changedSubjects[collection] = new Subject();
|
||||
}
|
||||
return this.changedSubjects[collection].asObservable() as Observable<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,12 +144,15 @@ export class DataStoreService {
|
||||
* @returns The max change id.
|
||||
*/
|
||||
public async initFromStorage(): Promise<number> {
|
||||
// This promise will be resolved with the maximal change id of the cache.
|
||||
// This promise will be resolved with cached datastore.
|
||||
const store = await this.storageService.get<JsonStorage>(DataStoreService.cachePrefix + 'DS');
|
||||
if (store) {
|
||||
const updateSlot = await this.DSUpdateManager.getNewUpdateSlot(this);
|
||||
|
||||
// There is a store. Deserialize it
|
||||
this.jsonStore = store;
|
||||
this.modelStore = this.deserializeJsonStore(this.jsonStore);
|
||||
|
||||
// Get the maxChangeId from the cache
|
||||
let maxChangeId = await this.storageService.get<number>(DataStoreService.cachePrefix + 'maxChangeId');
|
||||
if (!maxChangeId) {
|
||||
@ -184,6 +166,8 @@ export class DataStoreService {
|
||||
this.publishChangedInformation(this.modelStore[collection][id]);
|
||||
});
|
||||
});
|
||||
|
||||
this.DSUpdateManager.commit(updateSlot);
|
||||
} else {
|
||||
await this.clear();
|
||||
}
|
||||
@ -414,8 +398,17 @@ export class DataStoreService {
|
||||
* @param model The model to publish
|
||||
*/
|
||||
private publishChangedInformation(model: BaseModel): void {
|
||||
this.changedSubject.next(model);
|
||||
this.changedOrDeletedSubject.next(model);
|
||||
const slot = this.DSUpdateManager.getCurrentUpdateSlot();
|
||||
if (slot) {
|
||||
slot.addChangedModel(model.collectionString, model.id);
|
||||
// triggerModifiedObservable will be called by committing the update slot.
|
||||
} else {
|
||||
this.triggerModifiedObservable();
|
||||
}
|
||||
|
||||
if (this.changedSubjects[model.collectionString]) {
|
||||
this.changedSubjects[model.collectionString].next(model);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -424,8 +417,20 @@ export class DataStoreService {
|
||||
* @param information The information about the deleted model
|
||||
*/
|
||||
private publishDeletedInformation(information: DeletedInformation): void {
|
||||
this.deletedSubject.next(information);
|
||||
this.changedOrDeletedSubject.next(information);
|
||||
const slot = this.DSUpdateManager.getCurrentUpdateSlot();
|
||||
if (slot) {
|
||||
slot.addDeletedModel(information.collection, information.id);
|
||||
// triggerModifiedObservable will be called by committing the update slot.
|
||||
} else {
|
||||
this.triggerModifiedObservable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the modified subject.
|
||||
*/
|
||||
public triggerModifiedObservable(): void {
|
||||
this.modifiedSubject.next();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,7 +12,7 @@ import { OpenSlidesStatusService } from './openslides-status.service';
|
||||
import { ViewUser } from 'app/site/users/models/view-user';
|
||||
import { OnAfterAppsLoaded } from '../onAfterAppsLoaded';
|
||||
import { UserRepositoryService } from '../repositories/users/user-repository.service';
|
||||
import { CollectionStringMapperService } from './collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from './collection-string-mapper.service';
|
||||
import { StorageService } from './storage.service';
|
||||
import { HttpService } from './http.service';
|
||||
import { filter, auditTime } from 'rxjs/operators';
|
||||
@ -139,23 +139,23 @@ export class OperatorService implements OnAfterAppsLoaded {
|
||||
private storageService: StorageService,
|
||||
private OSStatus: OpenSlidesStatusService
|
||||
) {
|
||||
this.DS.changeObservable.subscribe(newModel => {
|
||||
if (this._user && newModel instanceof User && this._user.id === newModel.id) {
|
||||
this.DS.getChangeObservable(User).subscribe(newModel => {
|
||||
if (this._user && this._user.id === newModel.id) {
|
||||
this._user = newModel;
|
||||
this.updateUserInCurrentWhoAmI();
|
||||
}
|
||||
});
|
||||
this.DS.changeObservable
|
||||
this.DS.getChangeObservable(Group)
|
||||
.pipe(
|
||||
filter(
|
||||
model =>
|
||||
// Any group has changed if we have an operator or
|
||||
// group 1 (default) for anonymous changed
|
||||
model instanceof Group && (!!this._user || model.id === 1)
|
||||
!!this._user || model.id === 1
|
||||
),
|
||||
auditTime(10)
|
||||
)
|
||||
.subscribe(newModel => this.updatePermissions());
|
||||
.subscribe(_ => this.updatePermissions());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { environment } from 'environments/environment';
|
||||
import { CollectionStringMapperService } from './collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from './collection-string-mapper.service';
|
||||
import { History } from 'app/shared/models/core/history';
|
||||
import { DataStoreService } from './data-store.service';
|
||||
import { WebsocketService } from './websocket.service';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CollectionStringMapperService } from './collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from './collection-string-mapper.service';
|
||||
import { BaseViewModel, ViewModelConstructor } from 'app/site/base/base-view-model';
|
||||
import { BaseRepository } from '../repositories/base-repository';
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
* //
|
||||
* ```
|
||||
*/
|
||||
export class Deferred<T> {
|
||||
export class Deferred<T = void> {
|
||||
/**
|
||||
* The promise to wait for
|
||||
*/
|
||||
@ -22,7 +22,7 @@ export class Deferred<T> {
|
||||
/**
|
||||
* custom resolve function
|
||||
*/
|
||||
private _resolve: () => void;
|
||||
private _resolve: (val?: T) => void;
|
||||
|
||||
/**
|
||||
* Creates the promise and overloads the resolve function
|
||||
@ -36,7 +36,7 @@ export class Deferred<T> {
|
||||
/**
|
||||
* Entry point for the resolve function
|
||||
*/
|
||||
public resolve(): void {
|
||||
this._resolve();
|
||||
public resolve(val?: T): void {
|
||||
this._resolve(val);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import { Observable } from 'rxjs';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
@ -17,6 +17,10 @@ import { BaseAgendaViewModel } from 'app/site/base/base-agenda-view-model';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
import { BaseViewModel } from 'app/site/base/base-view-model';
|
||||
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
|
||||
import { Motion } from 'app/shared/models/motions/motion';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import { Topic } from 'app/shared/models/topics/topic';
|
||||
import { Assignment } from 'app/shared/models/assignments/assignment';
|
||||
|
||||
/**
|
||||
* Repository service for users
|
||||
@ -47,25 +51,18 @@ export class ItemRepositoryService extends BaseRepository<ViewItem, Item> {
|
||||
private config: ConfigService,
|
||||
private treeService: TreeService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Item);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Item, [
|
||||
Topic,
|
||||
Assignment,
|
||||
Motion,
|
||||
MotionBlock
|
||||
]);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
return this.translate.instant(plural ? 'Items' : 'Item');
|
||||
};
|
||||
|
||||
protected setupDependencyObservation(): void {
|
||||
this.DS.secondaryModelChangeSubject.subscribe(model => {
|
||||
const viewModel = this.viewModelStoreService.get(model.collectionString, model.id);
|
||||
const somethingChanged = this.getViewModelList().some(ownViewModel => {
|
||||
return ownViewModel.updateDependencies(viewModel);
|
||||
});
|
||||
if (somethingChanged) {
|
||||
this.updateAllObservables(model.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the viewItem out of a given item
|
||||
*
|
||||
|
@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
|
||||
import { DataStoreService } from 'app/core/core-services/data-store.service';
|
||||
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
import { Item } from 'app/shared/models/agenda/item';
|
||||
|
@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { Assignment } from 'app/shared/models/assignments/assignment';
|
||||
import { AssignmentRelatedUser } from 'app/shared/models/assignments/assignment-related-user';
|
||||
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
|
@ -2,7 +2,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseViewModel } from '../../site/base/base-view-model';
|
||||
import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
|
||||
import { CollectionStringMapperService } from '../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../core-services/collection-string-mapper.service';
|
||||
import { DataSendService } from '../core-services/data-send.service';
|
||||
import { DataStoreService } from '../core-services/data-store.service';
|
||||
import { ViewModelStoreService } from '../core-services/view-model-store.service';
|
||||
|
@ -3,7 +3,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseViewModel } from '../../site/base/base-view-model';
|
||||
import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
|
||||
import { CollectionStringMapperService } from '../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../core-services/collection-string-mapper.service';
|
||||
import { DataSendService } from '../core-services/data-send.service';
|
||||
import { DataStoreService } from '../core-services/data-store.service';
|
||||
import { Identifiable } from '../../shared/models/base/identifiable';
|
||||
@ -11,6 +11,7 @@ import { auditTime } from 'rxjs/operators';
|
||||
import { ViewModelStoreService } from '../core-services/view-model-store.service';
|
||||
import { OnAfterAppsLoaded } from '../onAfterAppsLoaded';
|
||||
import { Collection } from 'app/shared/models/base/collection';
|
||||
import { CollectionIds } from '../core-services/data-store-update-manager.service';
|
||||
|
||||
export abstract class BaseRepository<V extends BaseViewModel, M extends BaseModel>
|
||||
implements OnAfterAppsLoaded, Collection {
|
||||
@ -107,6 +108,10 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
this.updateViewModelListObservable();
|
||||
});
|
||||
|
||||
this.loadInitialFromDS();
|
||||
}
|
||||
|
||||
protected loadInitialFromDS(): void {
|
||||
// Populate the local viewModelStore with ViewModel Objects.
|
||||
this.DS.getAll(this.baseModelCtor).forEach((model: M) => {
|
||||
this.viewModelStore[model.id] = this.createViewModel(model);
|
||||
@ -117,61 +122,72 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
this.DS.getAll(this.baseModelCtor).forEach((model: M) => {
|
||||
this.updateViewModelObservable(model.id);
|
||||
});
|
||||
|
||||
// Could be raise in error if the root injector is not known
|
||||
this.DS.primaryModelChangeSubject.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);
|
||||
}
|
||||
});
|
||||
|
||||
this.setupDependencyObservation();
|
||||
|
||||
// Watch the Observables for deleting
|
||||
// TODO: What happens, if some related object was deleted?
|
||||
// My quess: This must trigger an autoupdate also for this model, because some IDs changed, so the
|
||||
// affected models will be newly created by the primaryModelChangeSubject.
|
||||
this.DS.deletedObservable.subscribe(model => {
|
||||
if (model.collection === this.collectionStringMapperService.getCollectionString(this.baseModelCtor)) {
|
||||
delete this.viewModelStore[model.id];
|
||||
this.updateAllObservables(model.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the observation of dependency subjects.
|
||||
*/
|
||||
protected setupDependencyObservation(): void {
|
||||
if (this.depsModelCtors) {
|
||||
this.DS.secondaryModelChangeSubject.subscribe(model => {
|
||||
const dependencyChanged: boolean = this.depsModelCtors.some(ctor => {
|
||||
return model instanceof ctor;
|
||||
});
|
||||
if (dependencyChanged) {
|
||||
const viewModel = this.viewModelStoreService.get(model.collectionString, model.id);
|
||||
this.updateDependency(viewModel);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all models with the provided `update` which is a dependency.
|
||||
* Deletes all models from the repository (internally, no requests). Informs all subjects.
|
||||
*
|
||||
* @param update The dependency to update.
|
||||
* @param ids All model ids
|
||||
*/
|
||||
protected updateDependency(update: BaseViewModel): void {
|
||||
// if an domain object we need was added or changed, update viewModelStore
|
||||
this.getViewModelList().forEach(ownViewModel => {
|
||||
ownViewModel.updateDependencies(update);
|
||||
this.updateViewModelObservable(ownViewModel.id);
|
||||
public deleteModels(ids: number[]): void {
|
||||
ids.forEach(id => {
|
||||
delete this.viewModelStore[id];
|
||||
this.updateViewModelObservable(id);
|
||||
});
|
||||
this.updateViewModelListObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates or creates all given models in the repository (internally, no requests).
|
||||
* Informs all subjects.
|
||||
*
|
||||
* @param ids All model ids.
|
||||
*/
|
||||
public changedModels(ids: number[]): void {
|
||||
ids.forEach(id => {
|
||||
this.viewModelStore[id] = this.createViewModel(this.DS.get(this.collectionString, id));
|
||||
this.updateViewModelObservable(id);
|
||||
});
|
||||
this.updateViewModelListObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all models in this repository with all changed models.
|
||||
*
|
||||
* @param changedModels A mapping of collections to ids of all changed models.
|
||||
*/
|
||||
public updateDependencies(changedModels: CollectionIds): void {
|
||||
if (!this.depsModelCtors || this.depsModelCtors.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all viewModels from this repo once.
|
||||
const viewModels = this.getViewModelList();
|
||||
let somethingUpdated = false;
|
||||
Object.keys(changedModels).forEach(collection => {
|
||||
const dependencyChanged: boolean = this.depsModelCtors.some(ctor => {
|
||||
return ctor.COLLECTIONSTRING === collection;
|
||||
});
|
||||
if (collection === this.collectionString || !dependencyChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ok, we are affected by this collection. Update all viewModels from this repo.
|
||||
viewModels.forEach(ownViewModel => {
|
||||
changedModels[collection].forEach(id => {
|
||||
ownViewModel.updateDependencies(this.viewModelStoreService.get(collection, id));
|
||||
});
|
||||
});
|
||||
somethingUpdated = true;
|
||||
});
|
||||
if (somethingUpdated) {
|
||||
viewModels.forEach(ownViewModel => {
|
||||
this.updateViewModelObservable(ownViewModel.id);
|
||||
});
|
||||
this.updateViewModelListObservable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the (full) update to an existing model. So called "update"-function
|
||||
* Provides a default procedure, but can be overwritten if required
|
||||
|
@ -10,7 +10,7 @@ import { DataStoreService } from 'app/core/core-services/data-store.service';
|
||||
import { ConstantsService } from 'app/core/core-services/constants.service';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
import { ViewConfig } from 'app/site/config/models/view-config';
|
||||
|
||||
@ -88,6 +88,16 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
|
||||
*/
|
||||
protected configListSubject: BehaviorSubject<ConfigGroup[]> = new BehaviorSubject<ConfigGroup[]>(null);
|
||||
|
||||
/**
|
||||
* Saves, if we got config variables (the structure) from the server.
|
||||
*/
|
||||
protected gotConfigsVariables = false;
|
||||
|
||||
/**
|
||||
* Saves, if we got first configs via autoupdate or cache.
|
||||
*/
|
||||
protected gotFirstUpdate = false;
|
||||
|
||||
/**
|
||||
* Constructor for ConfigRepositoryService. Requests the constants from the server and creates the config group structure.
|
||||
*
|
||||
@ -109,7 +119,9 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
|
||||
|
||||
this.constantsService.get('ConfigVariables').subscribe(constant => {
|
||||
this.createConfigStructure(constant);
|
||||
this.updateConfigStructure(true, ...Object.values(this.viewModelStore));
|
||||
this.updateConfigStructure(false, ...Object.values(this.viewModelStore));
|
||||
this.gotConfigsVariables = true;
|
||||
this.checkConfigStructure();
|
||||
this.updateConfigListObservable();
|
||||
});
|
||||
}
|
||||
@ -146,30 +158,23 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
|
||||
throw new Error('Config variables cannot be created');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwritten setup. Does only care about the custom list observable and inserts changed configs into the
|
||||
* config group structure.
|
||||
*/
|
||||
public onAfterAppsLoaded(): void {
|
||||
if (!this.configListSubject) {
|
||||
this.configListSubject = new BehaviorSubject<ConfigGroup[]>(null);
|
||||
}
|
||||
|
||||
protected loadInitialFromDS(): void {
|
||||
this.DS.getAll(Config).forEach((config: Config) => {
|
||||
this.viewModelStore[config.id] = this.createViewModel(config);
|
||||
this.updateConfigStructure(false, this.viewModelStore[config.id]);
|
||||
});
|
||||
this.updateConfigListObservable();
|
||||
}
|
||||
|
||||
// Could be raise in error if the root injector is not known
|
||||
// TODO go over repo
|
||||
this.DS.changeObservable.subscribe(model => {
|
||||
if (model instanceof Config) {
|
||||
this.viewModelStore[model.id] = this.createViewModel(model as Config);
|
||||
this.updateConfigStructure(false, this.viewModelStore[model.id]);
|
||||
this.updateConfigListObservable();
|
||||
}
|
||||
public changedModels(ids: number[]): void {
|
||||
super.changedModels(ids);
|
||||
|
||||
ids.forEach(id => {
|
||||
this.updateConfigStructure(false, this.viewModelStore[id]);
|
||||
});
|
||||
this.gotFirstUpdate = true;
|
||||
this.checkConfigStructure();
|
||||
this.updateConfigListObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,6 +200,16 @@ export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config>
|
||||
return this.configs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the config structure, if we got configs (first data) and the
|
||||
* structure (config variables)
|
||||
*/
|
||||
protected checkConfigStructure(): void {
|
||||
if (this.gotConfigsVariables && this.gotFirstUpdate) {
|
||||
this.updateConfigStructure(true, ...Object.values(this.viewModelStore));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* With a given (and maybe partially filled) config structure, all given view configs are put into it.
|
||||
* @param check Whether to check, if all given configs are there (according to the config structure).
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
|
||||
import { DataStoreService } from 'app/core/core-services/data-store.service';
|
||||
import { BaseRepository } from 'app/core/repositories/base-repository';
|
||||
import { History } from 'app/shared/models/core/history';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { User } from 'app/shared/models/users/user';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
import { ViewHistory } from 'app/site/history/models/view-history';
|
||||
import { ViewHistory, ProxyHistory } from 'app/site/history/models/view-history';
|
||||
import { TimeTravelService } from 'app/core/core-services/time-travel.service';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
import { ViewUser } from 'app/site/users/models/view-user';
|
||||
@ -40,7 +39,7 @@ export class HistoryRepositoryService extends BaseRepository<ViewHistory, Histor
|
||||
private httpService: HttpService,
|
||||
private timeTravel: TimeTravelService
|
||||
) {
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, History, [User]);
|
||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, History);
|
||||
}
|
||||
|
||||
public getVerboseName = (plural: boolean = false) => {
|
||||
@ -54,12 +53,29 @@ export class HistoryRepositoryService extends BaseRepository<ViewHistory, Histor
|
||||
* @return a new ViewHistory object
|
||||
*/
|
||||
public createViewModel(history: History): ViewHistory {
|
||||
const user = this.viewModelStoreService.get(ViewUser, history.user_id);
|
||||
const viewHistory = new ViewHistory(history, user);
|
||||
const viewHistory = new ViewHistory(this.createProxyHistory(history));
|
||||
viewHistory.getVerboseName = this.getVerboseName;
|
||||
return viewHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ProxyHistory from a History by wrapping it and give access to the user.
|
||||
*
|
||||
* @param history The History object
|
||||
* @returns the ProxyHistory
|
||||
*/
|
||||
private createProxyHistory(history: History): ProxyHistory {
|
||||
return new Proxy(history, {
|
||||
get: (instance, property) => {
|
||||
if (property === 'user') {
|
||||
return this.viewModelStoreService.get(ViewUser, instance.user_id);
|
||||
} else {
|
||||
return instance[property];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the default procedure
|
||||
*
|
||||
|
@ -6,7 +6,7 @@ import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { User } from 'app/shared/models/users/user';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
import { HttpHeaders } from '@angular/common/http';
|
||||
|
@ -4,7 +4,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { Category } from 'app/shared/models/motions/category';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { DataSendService } from '../../core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
|
@ -13,7 +13,7 @@ import { DataStoreService } from 'app/core/core-services/data-store.service';
|
||||
import { MotionChangeRecommendation } from 'app/shared/models/motions/motion-change-reco';
|
||||
import { ViewMotionChangeRecommendation } from 'app/site/motions/models/view-change-recommendation';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@ import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
|
||||
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
import { DataStoreService } from 'app/core/core-services/data-store.service';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
|
@ -6,7 +6,7 @@ import { BaseRepository } from '../base-repository';
|
||||
import { ViewMotionCommentSection } from 'app/site/motions/models/view-motion-comment-section';
|
||||
import { MotionCommentSection } from 'app/shared/models/motions/motion-comment-section';
|
||||
import { Group } from 'app/shared/models/users/group';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
import { ViewGroup } from 'app/site/users/models/view-group';
|
||||
|
@ -7,7 +7,7 @@ import { tap, map } from 'rxjs/operators';
|
||||
|
||||
import { Category } from 'app/shared/models/motions/category';
|
||||
import { ChangeRecoMode, ViewMotion } from 'app/site/motions/models/view-motion';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
|
||||
import { DataSendService } from '../../core-services/data-send.service';
|
||||
@ -39,10 +39,10 @@ import { ViewMotionBlock } from 'app/site/motions/models/view-motion-block';
|
||||
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||
import { ViewTag } from 'app/site/tags/models/view-tag';
|
||||
import { BaseAgendaContentObjectRepository } from '../base-agenda-content-object-repository';
|
||||
import { BaseViewModel } from 'app/site/base/base-view-model';
|
||||
import { PersonalNote, PersonalNoteContent } from 'app/shared/models/users/personal-note';
|
||||
import { ViewPersonalNote } from 'app/site/users/models/view-personal-note';
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
import { CollectionIds } from 'app/core/core-services/data-store-update-manager.service';
|
||||
|
||||
type SortProperty = 'callListWeight' | 'identifier';
|
||||
|
||||
@ -261,30 +261,48 @@ export class MotionRepositoryService extends BaseAgendaContentObjectRepository<V
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param update
|
||||
*
|
||||
* @overwrite
|
||||
* Special handling of updating personal notes.
|
||||
* @override
|
||||
*/
|
||||
protected updateDependency(update: BaseViewModel): void {
|
||||
if (update instanceof ViewPersonalNote) {
|
||||
if (this.operator.isAnonymous || update.userId !== this.operator.user.id) {
|
||||
public updateDependencies(changedModels: CollectionIds): void {
|
||||
if (!this.depsModelCtors || this.depsModelCtors.length === 0) {
|
||||
return;
|
||||
}
|
||||
const viewModels = this.getViewModelList();
|
||||
let somethingUpdated = false;
|
||||
Object.keys(changedModels).forEach(collection => {
|
||||
const dependencyChanged: boolean = this.depsModelCtors.some(ctor => {
|
||||
return ctor.COLLECTIONSTRING === collection;
|
||||
});
|
||||
if (collection === this.collectionString || !dependencyChanged) {
|
||||
return;
|
||||
}
|
||||
const notes = update.notes;
|
||||
const collection = Motion.COLLECTIONSTRING;
|
||||
|
||||
this.getViewModelList().forEach(ownViewModel => {
|
||||
if (notes && notes[collection] && notes[collection][ownViewModel.id]) {
|
||||
ownViewModel.personalNote = notes[collection][ownViewModel.id];
|
||||
} else {
|
||||
ownViewModel.personalNote = null;
|
||||
}
|
||||
// Do not update personal notes, if the operator is anonymous
|
||||
if (collection === PersonalNote.COLLECTIONSTRING && this.operator.isAnonymous) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewModels.forEach(ownViewModel => {
|
||||
changedModels[collection].forEach(id => {
|
||||
const viewModel = this.viewModelStoreService.get(collection, id);
|
||||
// Only update the personal note, if the operator is the right user.
|
||||
if (
|
||||
collection === PersonalNote.COLLECTIONSTRING &&
|
||||
(<ViewPersonalNote>viewModel).userId !== this.operator.user.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
ownViewModel.updateDependencies(viewModel);
|
||||
});
|
||||
});
|
||||
somethingUpdated = true;
|
||||
});
|
||||
if (somethingUpdated) {
|
||||
viewModels.forEach(ownViewModel => {
|
||||
this.updateViewModelObservable(ownViewModel.id);
|
||||
});
|
||||
this.updateViewModelListObservable();
|
||||
} else {
|
||||
super.updateDependency(update);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { ViewStatuteParagraph } from 'app/site/motions/models/view-statute-paragraph';
|
||||
import { StatuteParagraph } from 'app/shared/models/motions/statute-paragraph';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { ViewWorkflow } from 'app/site/motions/models/view-workflow';
|
||||
import { DataSendService } from '../../core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { WorkflowState } from 'app/shared/models/motions/workflow-state';
|
||||
import { ViewMotion } from 'app/site/motions/models/view-motion';
|
||||
import { HttpService } from 'app/core/core-services/http.service';
|
||||
|
@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { DataSendService } from '../../core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { ViewCountdown } from 'app/site/projector/models/view-countdown';
|
||||
import { Countdown } from 'app/shared/models/core/countdown';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
|
@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { DataSendService } from '../../core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { ProjectorMessage } from 'app/shared/models/core/projector-message';
|
||||
import { ViewProjectorMessage } from 'app/site/projector/models/view-projector-message';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { DataSendService } from '../../core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
|
@ -5,7 +5,7 @@ import { ViewTag } from 'app/site/tags/models/view-tag';
|
||||
import { DataSendService } from '../../core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { ConstantsService } from '../../core-services/constants.service';
|
||||
import { DataSendService } from '../../core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
|
@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { DataSendService } from 'app/core/core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { Identifiable } from 'app/shared/models/base/identifiable';
|
||||
import { PersonalNote } from 'app/shared/models/users/personal-note';
|
||||
import { ViewPersonalNote } from 'app/site/users/models/view-personal-note';
|
||||
|
@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseRepository } from '../base-repository';
|
||||
import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from '../../core-services/collection-string-mapper.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { DataSendService } from '../../core-services/data-send.service';
|
||||
import { DataStoreService } from '../../core-services/data-store.service';
|
||||
|
@ -33,9 +33,9 @@ export class ConfigService {
|
||||
* Listen for changes of config variables.
|
||||
*/
|
||||
public constructor(private DS: DataStoreService) {
|
||||
this.DS.changeObservable.subscribe(data => {
|
||||
this.DS.getChangeObservable(Config).subscribe(data => {
|
||||
// on changes notify the observers for specific keys.
|
||||
if (data instanceof Config && this.configSubjects[data.key]) {
|
||||
if (this.configSubjects[data.key]) {
|
||||
this.configSubjects[data.key].next(data.value);
|
||||
}
|
||||
});
|
||||
|
@ -24,10 +24,8 @@ export class PersonalNoteService {
|
||||
*/
|
||||
public constructor(private operator: OperatorService, private DS: DataStoreService, private http: HttpService) {
|
||||
operator.getUserObservable().subscribe(() => this.updatePersonalNoteObject());
|
||||
this.DS.changeObservable.subscribe(model => {
|
||||
if (model instanceof PersonalNote) {
|
||||
this.updatePersonalNoteObject();
|
||||
}
|
||||
this.DS.getChangeObservable(PersonalNote).subscribe(_ => {
|
||||
this.updatePersonalNoteObject();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ import { UserRepositoryService } from 'app/core/repositories/users/user-reposito
|
||||
import { DurationService } from 'app/core/ui-services/duration.service';
|
||||
import { CurrentAgendaItemService } from 'app/site/projector/services/current-agenda-item.service';
|
||||
import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
|
||||
import { CurrentListOfSpeakersSlideService } from 'app/site/projector/services/current-list-of-of-speakers-slide.service';
|
||||
import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
||||
|
||||
|
@ -80,7 +80,7 @@ export class SearchComponent extends BaseViewComponent implements OnInit {
|
||||
|
||||
this.registeredModels = this.searchService.getRegisteredModels().map(rm => ({ ...rm, enabled: true }));
|
||||
|
||||
this.DS.changedOrDeletedObservable.pipe(auditTime(100)).subscribe(() => this.search());
|
||||
this.DS.modifiedObservable.pipe(auditTime(100)).subscribe(() => this.search());
|
||||
this.quickSearchSubject.pipe(debounceTime(250)).subscribe(query => this.search(query));
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
<!-- User -->
|
||||
<ng-container matColumnDef="user">
|
||||
<mat-header-cell *matHeaderCellDef translate>Changed by</mat-header-cell>
|
||||
<mat-cell *matCellDef="let history">{{ history.user }}</mat-cell>
|
||||
<mat-cell *matCellDef="let history">{{ history.user_full_name }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="getRowDef()"></mat-header-row>
|
||||
|
@ -2,6 +2,8 @@ import { BaseViewModel } from 'app/site/base/base-view-model';
|
||||
import { History } from 'app/shared/models/core/history';
|
||||
import { ViewUser } from 'app/site/users/models/view-user';
|
||||
|
||||
export type ProxyHistory = History & { user?: ViewUser };
|
||||
|
||||
/**
|
||||
* View model for history objects
|
||||
*/
|
||||
@ -11,38 +13,39 @@ export class ViewHistory extends BaseViewModel {
|
||||
/**
|
||||
* Private BaseModel of the history
|
||||
*/
|
||||
private _history: History;
|
||||
|
||||
/**
|
||||
* Real representation of the user who altered the history.
|
||||
* Determined from `History.user_id`
|
||||
*/
|
||||
private _user: ViewUser | null;
|
||||
private _history: ProxyHistory;
|
||||
|
||||
/**
|
||||
* Read the history property
|
||||
*/
|
||||
public get history(): History {
|
||||
public get history(): ProxyHistory {
|
||||
return this._history;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the user property
|
||||
* Gets the users ViewUser.
|
||||
*/
|
||||
public get user(): ViewUser {
|
||||
return this._user ? this._user : null;
|
||||
public get user(): ViewUser | null {
|
||||
return this.history.user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the history object
|
||||
* Get the id of the history object
|
||||
* Required by BaseViewModel
|
||||
*
|
||||
* @returns the ID as number
|
||||
* @returns the id as number
|
||||
*/
|
||||
public get id(): number {
|
||||
return this.history.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the users full name
|
||||
*/
|
||||
public get user_full_name(): string {
|
||||
return this.history.user ? this.history.user.full_name : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the elementIDs of the history object
|
||||
*
|
||||
@ -81,10 +84,9 @@ export class ViewHistory extends BaseViewModel {
|
||||
* @param history the real history BaseModel
|
||||
* @param user the real user BaseModel
|
||||
*/
|
||||
public constructor(history: History, user?: ViewUser) {
|
||||
public constructor(history: ProxyHistory) {
|
||||
super(History.COLLECTIONSTRING);
|
||||
this._history = history;
|
||||
this._user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,14 +119,5 @@ export class ViewHistory extends BaseViewModel {
|
||||
return this.history;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the history object with new values
|
||||
*
|
||||
* @param update potentially the new values for history or it's components.
|
||||
*/
|
||||
public updateDependencies(update: BaseViewModel): void {
|
||||
if (update instanceof ViewUser && this.history.user_id === update.id) {
|
||||
this._user = update;
|
||||
}
|
||||
}
|
||||
public updateDependencies(update: BaseViewModel): void {}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { Component } from '@angular/core';
|
||||
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { CommonListOfSpeakersSlideData } from './common-list-of-speakers-slide-data';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
|
||||
import { isBaseAgendaContentObjectRepository } from 'app/core/repositories/base-agenda-content-object-repository';
|
||||
|
||||
@Component({
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { ItemListSlideData, SlideItem } from './item-list-slide-data';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collectionStringMapper.service';
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
|
||||
import { isBaseAgendaContentObjectRepository } from 'app/core/repositories/base-agenda-content-object-repository';
|
||||
|
||||
@Component({
|
||||
|
Loading…
Reference in New Issue
Block a user