diff --git a/client/package-lock.json b/client/package-lock.json index f88cb9eb2..61cc07ec9 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -4779,13 +4779,15 @@ "version": "1.0.0", "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4808,7 +4810,8 @@ "version": "0.0.1", "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", @@ -4975,6 +4978,7 @@ "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } diff --git a/client/src/app/core/services/data-store.service.ts b/client/src/app/core/services/data-store.service.ts index 063703330..713e0667a 100644 --- a/client/src/app/core/services/data-store.service.ts +++ b/client/src/app/core/services/data-store.service.ts @@ -182,7 +182,7 @@ export class DataStoreService { }); } - private getCollectionString(collectionType: ModelConstructor | string): string { + private getCollectionString>(collectionType: ModelConstructor | string): string { if (typeof collectionType === 'string') { return collectionType; } else { @@ -199,7 +199,7 @@ export class DataStoreService { * @example: this.DS.get(User, 1) * @example: this.DS.get('core/countdown', 2) */ - public get(collectionType: ModelConstructor | string, id: number): T { + public get>(collectionType: ModelConstructor | string, id: number): T { const collectionString = this.getCollectionString(collectionType); const collection: ModelCollection = this.modelStore[collectionString]; @@ -219,7 +219,7 @@ export class DataStoreService { * @example: this.DS.getMany(User, [1,2,3,4,5]) * @example: this.DS.getMany('users/user', [1,2,3,4,5]) */ - public getMany(collectionType: ModelConstructor | string, ids: number[]): T[] { + public getMany>(collectionType: ModelConstructor | string, ids: number[]): T[] { const collectionString = this.getCollectionString(collectionType); const collection: ModelCollection = this.modelStore[collectionString]; @@ -242,7 +242,7 @@ export class DataStoreService { * @example: this.DS.getAll(User) * @example: this.DS.getAll('users/user') */ - public getAll(collectionType: ModelConstructor | string): T[] { + public getAll>(collectionType: ModelConstructor | string): T[] { const collectionString = this.getCollectionString(collectionType); const collection: ModelCollection = this.modelStore[collectionString]; @@ -261,7 +261,7 @@ export class DataStoreService { * @return The BaseModel-list corresponding to the filter function * @example this.DS.filter(User, myUser => myUser.first_name === "Max") */ - public filter( + public filter>( collectionType: ModelConstructor | string, callback: (model: T) => boolean ): T[] { diff --git a/client/src/app/shared/components/head-bar/head-bar.component.html b/client/src/app/shared/components/head-bar/head-bar.component.html index c92a32747..aab8a6cb8 100644 --- a/client/src/app/shared/components/head-bar/head-bar.component.html +++ b/client/src/app/shared/components/head-bar/head-bar.component.html @@ -1,5 +1,6 @@ - diff --git a/client/src/app/shared/components/head-bar/head-bar.component.scss b/client/src/app/shared/components/head-bar/head-bar.component.scss index e69de29bb..f1b01bb55 100644 --- a/client/src/app/shared/components/head-bar/head-bar.component.scss +++ b/client/src/app/shared/components/head-bar/head-bar.component.scss @@ -0,0 +1,4 @@ +.head-button { + bottom: -30px; + z-index: 100; +} diff --git a/client/src/app/shared/components/head-bar/head-bar.component.ts b/client/src/app/shared/components/head-bar/head-bar.component.ts index 8ee96c415..539f4e90f 100644 --- a/client/src/app/shared/components/head-bar/head-bar.component.ts +++ b/client/src/app/shared/components/head-bar/head-bar.component.ts @@ -16,7 +16,7 @@ import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; * ```html * @@ -54,29 +54,34 @@ export class HeadBarComponent implements OnInit { /** * Input declaration for the app name */ - @Input() public appName: string; + @Input() + public appName: string; /** * Determine if there should be a plus button. */ - @Input() public plusButton: false; + @Input() + public plusButton: false; /** * If not empty shows a ellipsis menu on the right side * * The parent needs to provide a menu, i.e `[menuList]=myMenu`. */ - @Input() public menuList: any[]; + @Input() + public menuList: any[]; /** * Emit a signal to the parent component if the plus button was clicked */ - @Output() public plusButtonClicked = new EventEmitter(); + @Output() + public plusButtonClicked = new EventEmitter(); /** * Emit a signal to the parent of an item in the menuList was selected. */ - @Output() public ellipsisMenuItem = new EventEmitter(); + @Output() + public ellipsisMenuItem = new EventEmitter(); /** * Empty constructor diff --git a/client/src/app/shared/components/search-value-selector/search-value-selector.component.html b/client/src/app/shared/components/search-value-selector/search-value-selector.component.html index cfedb9bfb..288cf7bfd 100644 --- a/client/src/app/shared/components/search-value-selector/search-value-selector.component.html +++ b/client/src/app/shared/components/search-value-selector/search-value-selector.component.html @@ -1,7 +1,11 @@ - + - +
+ None + +
+ {{selectedItem.getTitle(translate)}}
diff --git a/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts b/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts index c7f24ab38..6fd927660 100644 --- a/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts +++ b/client/src/app/shared/components/search-value-selector/search-value-selector.component.ts @@ -1,10 +1,13 @@ import { Component, OnInit, Input, ViewChild } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; -import { ReplaySubject, Subject } from 'rxjs'; +import { Subject, ReplaySubject, BehaviorSubject } from 'rxjs'; import { MatSelect } from '@angular/material'; import { takeUntil } from 'rxjs/operators'; import { Displayable } from '../../models/base/displayable'; import { TranslateService } from '@ngx-translate/core'; +import { Identifiable } from '../../models/base/identifiable'; + +type Selectable = Displayable & Identifiable; /** * Reusable Searchable Value Selector @@ -20,7 +23,7 @@ import { TranslateService } from '@ngx-translate/core'; * ```html * = new ReplaySubject(1); + public filteredItems: ReplaySubject = new ReplaySubject(1); /** * Decide if this should be a single or multi-select-field @@ -62,7 +65,7 @@ export class SearchValueSelectorComponent implements OnInit { * The Input List Values */ @Input() - public InputListValues: Displayable[]; + public InputListValues: BehaviorSubject; /** * Placeholder of the List @@ -111,13 +114,11 @@ export class SearchValueSelectorComponent implements OnInit { * onInit with filter ans subscription on filter */ public ngOnInit(): void { - // load the initial item list - this.filteredItems.next(this.InputListValues.slice()); + this.filteredItems.next(this.InputListValues.getValue()); // listen to value changes this.filterControl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => { this.filterItems(); }); - // this.multiSelect.stateChanges.subscribe(fn => console.log('ive changed')); } /** @@ -130,14 +131,14 @@ export class SearchValueSelectorComponent implements OnInit { // get the search keyword let search = this.filterControl.value; if (!search) { - this.filteredItems.next(this.InputListValues.slice()); + this.filteredItems.next(this.InputListValues.getValue()); return; } else { search = search.toLowerCase(); } // filter the values this.filteredItems.next( - this.InputListValues.filter( + this.InputListValues.getValue().filter( selectedItem => selectedItem .toString() @@ -154,7 +155,7 @@ export class SearchValueSelectorComponent implements OnInit { * places, but can't reflect the changes in both places. Until this can be done this will be unused code * @param item the selected item to be removed */ - public remove(item: Displayable): void { + public remove(item: Selectable): void { const myArr = this.thisSelector.value; const index = myArr.indexOf(item, 0); // my model was the form according to fix diff --git a/client/src/app/shared/models/base/base-model.ts b/client/src/app/shared/models/base/base-model.ts index ddc7fab76..20d59de10 100644 --- a/client/src/app/shared/models/base/base-model.ts +++ b/client/src/app/shared/models/base/base-model.ts @@ -2,15 +2,18 @@ import { OpenSlidesComponent } from 'app/openslides.component'; import { Deserializable } from './deserializable'; import { CollectionStringModelMapperService } from '../../../core/services/collectionStringModelMapper.service'; import { Displayable } from './displayable'; +import { Identifiable } from './identifiable'; -export interface ModelConstructor { +export interface ModelConstructor> { new (...args: any[]): T; } /** * Abstract parent class to set rules and functions for all models. + * When inherit from this class, give the subclass as the type. E.g. `class Motion extends BaseModel` */ -export abstract class BaseModel extends OpenSlidesComponent implements Deserializable, Displayable { +export abstract class BaseModel extends OpenSlidesComponent + implements Deserializable, Displayable, Identifiable { /** * Register the collection string to the type. * @param collectionString @@ -57,6 +60,10 @@ export abstract class BaseModel extends OpenSlidesComponent implements Deseriali }); } + public patchValues(update: Partial): void { + Object.assign(this, update); + } + public abstract getTitle(): string; public getListTitle(): string { diff --git a/client/src/app/shared/models/base/deserializable.ts b/client/src/app/shared/models/base/deserializable.ts index 7d2cfd844..503d8ad5c 100644 --- a/client/src/app/shared/models/base/deserializable.ts +++ b/client/src/app/shared/models/base/deserializable.ts @@ -13,5 +13,5 @@ export interface Deserializable { * should be used to assign JSON values to the object itself. * @param input */ - deserialize(input: any): void; + deserialize(input: object): void; } diff --git a/client/src/app/shared/models/base/identifiable.ts b/client/src/app/shared/models/base/identifiable.ts new file mode 100644 index 000000000..962b8184f --- /dev/null +++ b/client/src/app/shared/models/base/identifiable.ts @@ -0,0 +1,9 @@ +/** + * Every object implementing this interface has an id. + */ +export interface Identifiable { + /** + * The objects id. + */ + id: number; +} diff --git a/client/src/app/shared/models/base/projectable-base-model.ts b/client/src/app/shared/models/base/projectable-base-model.ts index fc10e11d3..afc57c66e 100644 --- a/client/src/app/shared/models/base/projectable-base-model.ts +++ b/client/src/app/shared/models/base/projectable-base-model.ts @@ -1,7 +1,7 @@ import { BaseModel } from './base-model'; import { Projectable } from './projectable'; -export abstract class ProjectableBaseModel extends BaseModel implements Projectable { +export abstract class ProjectableBaseModel extends BaseModel implements Projectable { protected constructor(collectionString: string, input?: any) { super(collectionString, input); } diff --git a/client/src/app/shared/models/core/chat-message.ts b/client/src/app/shared/models/core/chat-message.ts index 146186195..f9e377298 100644 --- a/client/src/app/shared/models/core/chat-message.ts +++ b/client/src/app/shared/models/core/chat-message.ts @@ -4,7 +4,7 @@ import { BaseModel } from '../base/base-model'; * Representation of chat messages. * @ignore */ -export class ChatMessage extends BaseModel { +export class ChatMessage extends BaseModel { public id: number; public message: string; public timestamp: string; // TODO: Type for timestamp diff --git a/client/src/app/shared/models/core/projector.ts b/client/src/app/shared/models/core/projector.ts index d2b692469..f2200aa61 100644 --- a/client/src/app/shared/models/core/projector.ts +++ b/client/src/app/shared/models/core/projector.ts @@ -4,7 +4,7 @@ import { BaseModel } from '../base/base-model'; * Representation of a projector. Has the nested property "projectiondefaults" * @ignore */ -export class Projector extends BaseModel { +export class Projector extends BaseModel { public id: number; public elements: Object; public scale: number; diff --git a/client/src/app/shared/models/core/tag.ts b/client/src/app/shared/models/core/tag.ts index 44e0fd75a..b8e05d918 100644 --- a/client/src/app/shared/models/core/tag.ts +++ b/client/src/app/shared/models/core/tag.ts @@ -4,7 +4,7 @@ import { BaseModel } from '../base/base-model'; * Representation of a tag. * @ignore */ -export class Tag extends BaseModel { +export class Tag extends BaseModel { public id: number; public name: string; diff --git a/client/src/app/shared/models/motions/category.ts b/client/src/app/shared/models/motions/category.ts index d772a8925..7dfee4f21 100644 --- a/client/src/app/shared/models/motions/category.ts +++ b/client/src/app/shared/models/motions/category.ts @@ -4,7 +4,7 @@ import { BaseModel } from '../base/base-model'; * Representation of a motion category. Has the nested property "File" * @ignore */ -export class Category extends BaseModel { +export class Category extends BaseModel { public id: number; public name: string; public prefix: string; diff --git a/client/src/app/shared/models/motions/motion-change-reco.ts b/client/src/app/shared/models/motions/motion-change-reco.ts index a562f7b36..6f2f24393 100644 --- a/client/src/app/shared/models/motions/motion-change-reco.ts +++ b/client/src/app/shared/models/motions/motion-change-reco.ts @@ -4,7 +4,7 @@ import { BaseModel } from '../base/base-model'; * Representation of a motion change recommendation. * @ignore */ -export class MotionChangeReco extends BaseModel { +export class MotionChangeReco extends BaseModel { public id: number; public motion_version_id: number; public rejected: boolean; diff --git a/client/src/app/shared/models/motions/motion-comment-section.ts b/client/src/app/shared/models/motions/motion-comment-section.ts index 24fff9c02..8217db479 100644 --- a/client/src/app/shared/models/motions/motion-comment-section.ts +++ b/client/src/app/shared/models/motions/motion-comment-section.ts @@ -4,7 +4,7 @@ import { BaseModel } from '../base/base-model'; * Representation of a motion category. Has the nested property "File" * @ignore */ -export class MotionCommentSection extends BaseModel { +export class MotionCommentSection extends BaseModel { public id: number; public name: string; public read_groups_id: number[]; diff --git a/client/src/app/shared/models/motions/motion.ts b/client/src/app/shared/models/motions/motion.ts index 35cf26909..3f1427870 100644 --- a/client/src/app/shared/models/motions/motion.ts +++ b/client/src/app/shared/models/motions/motion.ts @@ -44,13 +44,6 @@ export class Motion extends AgendaBaseModel { super('motions/motion', 'Motion', input); } - /** - * update the values of the motion with new values - */ - public patchValues(update: object): void { - Object.assign(this, update); - } - /** * returns the motion submitters userIDs */ diff --git a/client/src/app/shared/models/motions/workflow.ts b/client/src/app/shared/models/motions/workflow.ts index 8e8f30ac7..5e8de65cd 100644 --- a/client/src/app/shared/models/motions/workflow.ts +++ b/client/src/app/shared/models/motions/workflow.ts @@ -5,7 +5,7 @@ import { WorkflowState } from './workflow-state'; * Representation of a motion workflow. Has the nested property 'states' * @ignore */ -export class Workflow extends BaseModel { +export class Workflow extends BaseModel { public id: number; public name: string; public states: WorkflowState[]; diff --git a/client/src/app/shared/models/users/group.ts b/client/src/app/shared/models/users/group.ts index 4b52724d6..fdca2c193 100644 --- a/client/src/app/shared/models/users/group.ts +++ b/client/src/app/shared/models/users/group.ts @@ -4,7 +4,7 @@ import { BaseModel } from '../base/base-model'; * Representation of user group. * @ignore */ -export class Group extends BaseModel { +export class Group extends BaseModel { public id: number; public name: string; public permissions: string[]; diff --git a/client/src/app/shared/models/users/personal-note.ts b/client/src/app/shared/models/users/personal-note.ts index a9a0bd434..e9cd607ed 100644 --- a/client/src/app/shared/models/users/personal-note.ts +++ b/client/src/app/shared/models/users/personal-note.ts @@ -4,7 +4,7 @@ import { BaseModel } from '../base/base-model'; * Representation of users personal note. * @ignore */ -export class PersonalNote extends BaseModel { +export class PersonalNote extends BaseModel { public id: number; public user_id: number; public notes: Object; diff --git a/client/src/app/site/agenda/models/view-item.ts b/client/src/app/site/agenda/models/view-item.ts index cf221d8b6..b1731ea67 100644 --- a/client/src/app/site/agenda/models/view-item.ts +++ b/client/src/app/site/agenda/models/view-item.ts @@ -1,6 +1,5 @@ import { BaseViewModel } from '../../base/base-view-model'; import { Item } from '../../../shared/models/agenda/item'; -import { BaseModel } from '../../../shared/models/base/base-model'; import { AgendaBaseModel } from '../../../shared/models/base/agenda-base-model'; export class ViewItem extends BaseViewModel { @@ -46,8 +45,8 @@ export class ViewItem extends BaseViewModel { } } - public updateValues(update: BaseModel): void { - if (update instanceof Item && this.id === update.id) { + public updateValues(update: Item): void { + if (this.id === update.id) { this._item = update; } } diff --git a/client/src/app/site/agenda/services/agenda-repository.service.ts b/client/src/app/site/agenda/services/agenda-repository.service.ts index d49400ff0..fb01cfd70 100644 --- a/client/src/app/site/agenda/services/agenda-repository.service.ts +++ b/client/src/app/site/agenda/services/agenda-repository.service.ts @@ -49,7 +49,7 @@ export class AgendaRepositoryService extends BaseRepository { * * TODO: used over not-yet-existing detail view */ - public save(item: Item, viewUser: ViewItem): Observable { + public update(item: Partial, viewUser: ViewItem): Observable { return null; } @@ -67,7 +67,7 @@ export class AgendaRepositoryService extends BaseRepository { * * TODO: used over not-yet-existing detail view */ - public create(item: Item, viewItem: ViewItem): Observable { + public create(item: Item): Observable { return null; } diff --git a/client/src/app/site/assignments/models/view-assignment.ts b/client/src/app/site/assignments/models/view-assignment.ts index 32373a663..561569136 100644 --- a/client/src/app/site/assignments/models/view-assignment.ts +++ b/client/src/app/site/assignments/models/view-assignment.ts @@ -10,6 +10,10 @@ export class ViewAssignment extends BaseViewModel { private _agendaItem: Item; private _tags: Tag[]; + public get id(): number { + return this._assignment ? this._assignment.id : null; + } + public get assignment(): Assignment { return this._assignment; } diff --git a/client/src/app/site/assignments/services/assignment-repository.service.ts b/client/src/app/site/assignments/services/assignment-repository.service.ts index 135b725a7..98a7ffb16 100644 --- a/client/src/app/site/assignments/services/assignment-repository.service.ts +++ b/client/src/app/site/assignments/services/assignment-repository.service.ts @@ -25,7 +25,7 @@ export class AssignmentRepositoryService extends BaseRepository { + public update(assignment: Partial, viewAssignment: ViewAssignment): Observable { return null; } @@ -33,7 +33,7 @@ export class AssignmentRepositoryService extends BaseRepository { + public create(assignment: Assignment): Observable { return null; } diff --git a/client/src/app/site/base/base-repository.ts b/client/src/app/site/base/base-repository.ts index 10d1c2846..6ff8c2a6d 100644 --- a/client/src/app/site/base/base-repository.ts +++ b/client/src/app/site/base/base-repository.ts @@ -75,7 +75,7 @@ export abstract class BaseRepository; + public abstract update(update: Partial, viewModel: V): Observable; /** * Deletes a given Model @@ -90,7 +90,7 @@ export abstract class BaseRepository; + public abstract create(update: M): Observable; /** * Creates a view model out of a base model. diff --git a/client/src/app/site/base/base-view-model.ts b/client/src/app/site/base/base-view-model.ts index 89ae92895..d223e416d 100644 --- a/client/src/app/site/base/base-view-model.ts +++ b/client/src/app/site/base/base-view-model.ts @@ -1,10 +1,16 @@ import { BaseModel } from '../../shared/models/base/base-model'; import { Displayable } from '../../shared/models/base/displayable'; +import { Identifiable } from '../../shared/models/base/identifiable'; /** * Base class for view models. alls view models should have titles. */ -export abstract class BaseViewModel implements Displayable { +export abstract class BaseViewModel implements Displayable, Identifiable { + /** + * Force children to have an id. + */ + public abstract id: number; + public abstract updateValues(update: BaseModel): void; public abstract getTitle(): string; diff --git a/client/src/app/site/mediafiles/models/view-mediafile.ts b/client/src/app/site/mediafiles/models/view-mediafile.ts index f08989c17..725cf2c94 100644 --- a/client/src/app/site/mediafiles/models/view-mediafile.ts +++ b/client/src/app/site/mediafiles/models/view-mediafile.ts @@ -1,12 +1,15 @@ import { BaseViewModel } from '../../base/base-view-model'; import { Mediafile } from '../../../shared/models/mediafiles/mediafile'; import { User } from '../../../shared/models/users/user'; -import { BaseModel } from '../../../shared/models/base/base-model'; export class ViewMediafile extends BaseViewModel { private _mediafile: Mediafile; private _uploader: User; + public get id(): number { + return this._mediafile ? this._mediafile.id : null; + } + public get mediafile(): Mediafile { return this._mediafile; } @@ -49,11 +52,9 @@ export class ViewMediafile extends BaseViewModel { return this.title; } - public updateValues(update: BaseModel): void { - if (update instanceof Mediafile) { - if (this.mediafile.id === update.id) { - this._mediafile = update; - } + public updateValues(update: Mediafile): void { + if (this.mediafile.id === update.id) { + this._mediafile = update; } } } diff --git a/client/src/app/site/mediafiles/services/mediafile-repository.service.ts b/client/src/app/site/mediafiles/services/mediafile-repository.service.ts index 09e5ab70d..c4a03adee 100644 --- a/client/src/app/site/mediafiles/services/mediafile-repository.service.ts +++ b/client/src/app/site/mediafiles/services/mediafile-repository.service.ts @@ -27,7 +27,7 @@ export class MediafileRepositoryService extends BaseRepository { + public update(file: Partial, viewFile: ViewMediafile): Observable { return null; } @@ -45,7 +45,7 @@ export class MediafileRepositoryService extends BaseRepository { + public create(file: Mediafile): Observable { return null; } diff --git a/client/src/app/site/motions/components/category-list/category-list.component.html b/client/src/app/site/motions/components/category-list/category-list.component.html index 1194f89bf..b36668ae2 100644 --- a/client/src/app/site/motions/components/category-list/category-list.component.html +++ b/client/src/app/site/motions/components/category-list/category-list.component.html @@ -1,19 +1,58 @@ - + - - - - - Name - {{category.name}} - - - - - Prefix - {{category.prefix}} - - - - - +
+ +
+ + + + + {{category.name}} + + + {{this.formGroup.get('name').value}} + + + {{category.prefix}} + + + {{this.formGroup.get('prefix').value}} + + +
+ Edit category details:
+ + + + Required + + + + + + Required + + +
+ + + + + + +
+
diff --git a/client/src/app/site/motions/components/category-list/category-list.component.scss b/client/src/app/site/motions/components/category-list/category-list.component.scss index e69de29bb..1826997c7 100644 --- a/client/src/app/site/motions/components/category-list/category-list.component.scss +++ b/client/src/app/site/motions/components/category-list/category-list.component.scss @@ -0,0 +1,44 @@ +.button-side { + right: 0; + top: 0px; + float: right; +} + +.text-side { + size: 50%; +} + +.content-row { + size: 100%; +} + +.new { + // put in theme later + background-color: lightblue; +} + +.mini-button { + top: 0px; + width: 20px; + height: 20px; + min-height: 20px; + font-size: 10px; + box-shadow: none; + vertical-align: top; + padding: 0 0; + margin: 0; +} + +.onethird { + width: 33%; +} + +.custom-table-header { + // display: none; + width: 100%; + height: 60px; + line-height: 60px; + text-align: right; + background: white; + border-bottom: 1px solid rgba(0, 0, 0, 0.12); +} diff --git a/client/src/app/site/motions/components/category-list/category-list.component.ts b/client/src/app/site/motions/components/category-list/category-list.component.ts index 2923a1761..64f5ae8c6 100644 --- a/client/src/app/site/motions/components/category-list/category-list.component.ts +++ b/client/src/app/site/motions/components/category-list/category-list.component.ts @@ -1,59 +1,98 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit, OnDestroy } from '@angular/core'; import { Title } from '@angular/platform-browser'; -import { MatSort, MatTable, MatTableDataSource } from '@angular/material'; import { TranslateService } from '@ngx-translate/core'; import { BaseComponent } from '../../../../base.component'; import { Category } from '../../../../shared/models/motions/category'; -import { DataStoreService } from '../../../../core/services/data-store.service'; +import { CategoryRepositoryService } from '../../services/category-repository.service'; +import { ViewCategory } from '../../models/view-category'; +import { FormGroup, FormBuilder, Validators } from '@angular/forms'; /** * List view for the categories. - * - * TODO: Creation of new Categories */ @Component({ selector: 'os-category-list', templateUrl: './category-list.component.html', styleUrls: ['./category-list.component.scss'] }) -export class CategoryListComponent extends BaseComponent implements OnInit { +export class CategoryListComponent extends BaseComponent implements OnInit, OnDestroy { /** - * Store the categories + * States the edit mode */ - public categoryArray: Array; + public editMode = false; /** - * Will be processed by the mat-table + * Source of the Data */ - public dataSource: MatTableDataSource; + public dataSource: Array; /** - * The table itself. + * The current focussed formgroup */ - @ViewChild(MatTable) - public table: MatTable; - - /** - * Sort the Table - */ - @ViewChild(MatSort) - public sort: MatSort; + public formGroup: FormGroup; /** * The usual component constructor * @param titleService * @param translate + * @param repo + * @param formBuilder */ public constructor( protected titleService: Title, protected translate: TranslateService, - protected DS: DataStoreService + private repo: CategoryRepositoryService, + private formBuilder: FormBuilder ) { super(titleService, translate); + this.formGroup = this.formBuilder.group({ + name: ['', Validators.required], + prefix: ['', Validators.required] + }); } + /** + * On Destroy Function + * + * Saves the edits + */ + public ngOnDestroy(): void { + this.dataSource.forEach(viewCategory => { + if (viewCategory.edit && viewCategory.opened) { + const nameControl = this.formGroup.get('name'); + const prefixControl = this.formGroup.get('prefix'); + const nameValue = nameControl.value; + const prefixValue = prefixControl.value; + viewCategory.name = nameValue; + viewCategory.prefix = prefixValue; + this.saveCategory(viewCategory); + } + }); + } + + /** + * Event on Key Down in form + */ + public keyDownFunction(event: KeyboardEvent, viewCategory: ViewCategory): void { + if (event.keyCode === 13) { + this.onSaveButton(viewCategory); + } + } + + /** + * Stores the Datamodel in the repo + * @param viewCategory + */ + private saveCategory(viewCategory: ViewCategory): void { + if (this.repo.osInDataStore(viewCategory)) { + this.repo.update(viewCategory.category).subscribe(); + } else { + this.repo.create(viewCategory.category, viewCategory).subscribe(); + } + viewCategory.edit = false; + } /** * Init function. * @@ -61,26 +100,127 @@ export class CategoryListComponent extends BaseComponent implements OnInit { */ public ngOnInit(): void { super.setTitle('Category'); - this.categoryArray = this.DS.getAll(Category); - this.dataSource = new MatTableDataSource(this.categoryArray); - this.dataSource.sort = this.sort; + this.repo.getViewModelListObservable().subscribe(newViewCategories => { + this.dataSource = newViewCategories; + }); + this.sortDataSource(); + } - // Observe DataStore for motions. Initially, executes once for every motion. - // The alternative approach is to put the observable as DataSource to the table - this.DS.changeObservable.subscribe(newModel => { - if (newModel instanceof Category) { - this.categoryArray = this.DS.getAll(Category); - this.dataSource.data = this.categoryArray; + /** + * Add a new Category. + */ + public onPlusButton(): void { + let noNewOnes = true; + this.dataSource.forEach(viewCategory => { + if (viewCategory.id === undefined) { + noNewOnes = false; + } + }); + if (noNewOnes) { + const newCategory = new Category(); + newCategory.id = undefined; + newCategory.name = this.translate.instant('Name'); + newCategory.prefix = this.translate.instant('Prefix'); + const newViewCategory = new ViewCategory(newCategory); + newViewCategory.opened = true; + this.dataSource.reverse(); + this.dataSource.push(newViewCategory); + this.dataSource.reverse(); + this.editMode = true; + } + } + + /** + * Executed on edit button + * @param viewCategory + */ + public onEditButton(viewCategory: ViewCategory): void { + viewCategory.edit = true; + viewCategory.synced = false; + this.editMode = true; + const nameControl = this.formGroup.get('name'); + const prefixControl = this.formGroup.get('prefix'); + nameControl.setValue(viewCategory.name); + prefixControl.setValue(viewCategory.prefix); + } + + /** + * Saves the categories + */ + public onSaveButton(viewCategory: ViewCategory): void { + if (this.formGroup.controls.name.valid && this.formGroup.controls.prefix.valid) { + this.editMode = false; + const nameControl = this.formGroup.get('name'); + const prefixControl = this.formGroup.get('prefix'); + const nameValue = nameControl.value; + const prefixValue = prefixControl.value; + if ( + viewCategory.id === undefined || + nameValue !== viewCategory.name || + prefixValue !== viewCategory.prefix + ) { + viewCategory.prefix = prefixValue; + viewCategory.name = nameValue; + this.saveCategory(viewCategory); + } + } + this.sortDataSource(); + } + + /** + * sorts the datasource by prefix alphabetically + */ + protected sortDataSource(): void { + this.dataSource.sort((viewCategory1, viewCategory2) => { + if (viewCategory1.prefix > viewCategory2.prefix) { + return 1; + } + if (viewCategory1.prefix < viewCategory2.prefix) { + return -1; } }); } /** - * Add a new Category. - * - * TODO: Not yet implemented + * executed on cancel button + * @param viewCategory */ - public onPlusButton(): void { - console.log('Add New Category'); + public onCancelButton(viewCategory: ViewCategory): void { + viewCategory.edit = false; + this.editMode = false; + } + + /** + * is executed, when the delete button is pressed + */ + public onDeleteButton(viewCategory: ViewCategory): void { + if (this.repo.osInDataStore(viewCategory) && viewCategory.id !== undefined) { + this.repo.delete(viewCategory).subscribe(); + } + const index = this.dataSource.indexOf(viewCategory, 0); + if (index > -1) { + this.dataSource.splice(index, 1); + } + // if no category is there, we setill have to be able to create one + if (this.dataSource.length < 1) { + this.editMode = false; + } + } + + /** + * Is executed when a mat-extension-panel is opened or closed + * @param open true if opened, false if being closed + * @param category the category in the panel + */ + public panelOpening(open: boolean, category: ViewCategory): void { + category.opened = open as boolean; + if (category.edit === true) { + this.onSaveButton(category); + this.onCancelButton(category); + } + if (!open) { + category.edit = false; + this.editMode = false; + } } } diff --git a/client/src/app/site/motions/components/motion-detail/motion-detail.component.html b/client/src/app/site/motions/components/motion-detail/motion-detail.component.html index d445f640b..501de114e 100644 --- a/client/src/app/site/motions/components/motion-detail/motion-detail.component.html +++ b/client/src/app/site/motions/components/motion-detail/motion-detail.component.html @@ -15,7 +15,7 @@ {{motion.title}} {{contentForm.get('title').value}}
-
+
by {{motion.submitters}}
@@ -148,7 +148,8 @@
- +
@@ -164,7 +165,8 @@
- +
@@ -218,11 +220,12 @@
-

Category

+

Category

{{motion.category}}
- +
diff --git a/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts b/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts index c4d387969..623512b4b 100644 --- a/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts +++ b/client/src/app/site/motions/components/motion-detail/motion-detail.component.ts @@ -10,6 +10,9 @@ import { MotionRepositoryService } from '../../services/motion-repository.servic import { ViewMotion } from '../../models/view-motion'; import { User } from '../../../../shared/models/users/user'; import { DataStoreService } from '../../../../core/services/data-store.service'; +import { TranslateService } from '@ngx-translate/core'; +import { Motion } from '../../../../shared/models/motions/motion'; +import { BehaviorSubject } from 'rxjs'; /** * Component for the motion detail view @@ -64,6 +67,21 @@ export class MotionDetailComponent extends BaseComponent implements OnInit { */ public motionCopy: ViewMotion; + /** + * Subject for the Categories + */ + public categoryObserver: BehaviorSubject>; + + /** + * Subject for the Submitters + */ + public submitterObserver: BehaviorSubject>; + + /** + * Subject for the Supporters + */ + public supporterObserver: BehaviorSubject>; + /** * Constuct the detail view. * @@ -72,6 +90,7 @@ export class MotionDetailComponent extends BaseComponent implements OnInit { * @param route determine if this is a new or an existing motion * @param formBuilder For reactive forms. Form Group and Form Control * @param repo: Motion Repository + * @param translate: Translation Service */ public constructor( public vp: ViewportService, @@ -79,7 +98,8 @@ export class MotionDetailComponent extends BaseComponent implements OnInit { private route: ActivatedRoute, private formBuilder: FormBuilder, private repo: MotionRepositoryService, - private DS: DataStoreService + private DS: DataStoreService, + protected translate: TranslateService ) { super(); this.createForm(); @@ -100,6 +120,21 @@ export class MotionDetailComponent extends BaseComponent implements OnInit { }); }); } + // Initial Filling of the Subjects + this.submitterObserver = new BehaviorSubject(DS.getAll(User)); + this.supporterObserver = new BehaviorSubject(DS.getAll(User)); + this.categoryObserver = new BehaviorSubject(DS.getAll(Category)); + + // Make sure the subjects are updated, when a new Model for the type arrives + this.DS.changeObservable.subscribe(newModel => { + if (newModel instanceof User) { + this.submitterObserver.next(DS.getAll(User)); + this.supporterObserver.next(DS.getAll(User)); + } + if (newModel instanceof Category) { + this.categoryObserver.next(DS.getAll(Category)); + } + }); } /** @@ -108,8 +143,8 @@ export class MotionDetailComponent extends BaseComponent implements OnInit { public patchForm(formMotion: ViewMotion): void { this.metaInfoForm.patchValue({ category_id: formMotion.categoryId, - supporters_id: formMotion.supporters, - submitters: formMotion.submitters, + supporters_id: formMotion.supporterIds, + submitters_id: formMotion.submitterIds, state_id: formMotion.stateId, recommendation_id: formMotion.recommendationId, identifier: formMotion.identifier, @@ -133,7 +168,7 @@ export class MotionDetailComponent extends BaseComponent implements OnInit { category_id: [''], state_id: [''], recommendation_id: [''], - submitters: [''], + submitters_id: [''], supporters_id: [''], origin: [''] }); @@ -157,22 +192,18 @@ export class MotionDetailComponent extends BaseComponent implements OnInit { */ public saveMotion(): void { const newMotionValues = { ...this.metaInfoForm.value, ...this.contentForm.value }; + const fromForm = new Motion(); + fromForm.deserialize(newMotionValues); + if (this.newMotion) { - this.repo.create(newMotionValues).subscribe(response => { + this.repo.create(fromForm).subscribe(response => { this.router.navigate(['./motions/' + response.id]); }); } else { - this.repo.save(newMotionValues, this.motionCopy).subscribe(); + this.repo.update(fromForm, this.motionCopy).subscribe(); } } - /** - * return all Categories - */ - public getMotionCategories(): Category[] { - return this.DS.getAll(Category); - } - /** * Click on the edit button (pen-symbol) */ @@ -215,13 +246,6 @@ export class MotionDetailComponent extends BaseComponent implements OnInit { }); } - /** - * returns all Possible supporters - */ - public getAllUsers(): User[] { - return this.DS.getAll(User); - } - /** * Init. Does nothing here. */ diff --git a/client/src/app/site/motions/models/view-category.ts b/client/src/app/site/motions/models/view-category.ts new file mode 100644 index 000000000..b9a1a7f73 --- /dev/null +++ b/client/src/app/site/motions/models/view-category.ts @@ -0,0 +1,98 @@ +import { Category } from '../../../shared/models/motions/category'; +import { TranslateService } from '@ngx-translate/core'; +import { BaseViewModel } from '../../base/base-view-model'; + +/** + * Category class for the View + * + * Stores a Category including all (implicit) references + * Provides "safe" access to variables and functions in {@link Category} + * @ignore + */ +export class ViewCategory extends BaseViewModel { + private _category: Category; + private _edit: boolean; + private _synced: boolean; + private _opened: boolean; + + public get category(): Category { + return this._category; + } + + public get id(): number { + return this.category ? this.category.id : null; + } + + public get name(): string { + return this.category ? this.category.name : null; + } + + public get prefix(): string { + return this.category ? this.category.prefix : null; + } + + public set synced(bol: boolean) { + this._synced = bol; + } + + public set edit(bol: boolean) { + this._edit = bol; + } + + public set opened(bol: boolean) { + this._opened = bol; + } + + public set prefix(pref: string) { + this._category.prefix = pref; + } + + public set name(nam: string) { + this._category.name = nam; + } + + public get opened(): boolean { + return this._opened; + } + + public get synced(): boolean { + return this._synced; + } + + public get edit(): boolean { + return this._edit; + } + + public constructor(category?: Category, id?: number, prefix?: string, name?: string) { + super(); + if (!category) { + category = new Category(); + category.id = id; + category.name = name; + category.prefix = prefix; + } + this._category = category; + this._edit = false; + this._synced = true; + this._opened = false; + } + + public getTitle(translate?: TranslateService): string { + return this.name; + } + + /** + * Updates the local objects if required + * @param update + */ + public updateValues(update: Category): void { + this._category = update; + } + + /** + * Duplicate this motion into a copy of itself + */ + public copy(): ViewCategory { + return new ViewCategory(this._category); + } +} diff --git a/client/src/app/site/motions/models/view-motion.ts b/client/src/app/site/motions/models/view-motion.ts index c1832f5f0..92d2addc1 100644 --- a/client/src/app/site/motions/models/view-motion.ts +++ b/client/src/app/site/motions/models/view-motion.ts @@ -6,7 +6,6 @@ import { WorkflowState } from '../../../shared/models/motions/workflow-state'; import { BaseModel } from '../../../shared/models/base/base-model'; import { BaseViewModel } from '../../base/base-view-model'; import { TranslateService } from '@ngx-translate/core'; - /** * Motion class for the View * @@ -58,10 +57,18 @@ export class ViewMotion extends BaseViewModel { return this._submitters; } + public get submitterIds(): number[] { + return this.motion ? this.motion.submitters_id : null; + } + public get supporters(): User[] { return this._supporters; } + public get supporterIds(): number[] { + return this.motion ? this.motion.supporters_id : null; + } + public get workflow(): Workflow { return this._workflow; } @@ -101,6 +108,32 @@ export class ViewMotion extends BaseViewModel { return this.state && this.workflow ? this.state.getNextStates(this.workflow) : null; } + public set supporters(users: User[]) { + const userIDArr: number[] = []; + users.forEach(user => { + userIDArr.push(user.id); + }); + this._supporters = users; + this._motion.supporters_id = userIDArr; + } + + public set submitters(users: User[]) { + // For the newer backend with weight: + // const submitterArr: MotionSubmitter[] = [] + // users.forEach(user => { + // const motionSub = new MotionSubmitter(); + // submitterArr.push(motionSub); + // }); + // this._motion.submitters = submitterArr; + this._submitters = users; + const submitterIDArr: number[] = []; + // for the older backend: + users.forEach(user => { + submitterIDArr.push(user.id); + }); + this._motion.submitters_id = submitterIDArr; + } + public constructor( motion?: Motion, category?: Category, @@ -129,18 +162,32 @@ export class ViewMotion extends BaseViewModel { */ public updateValues(update: BaseModel): void { if (update instanceof Workflow) { - if (this.motion && update.id === this.motion.workflow_id) { - this._workflow = update as Workflow; - } + this.updateWorkflow(update as Workflow); } else if (update instanceof Category) { - if (this.motion && update.id === this.motion.category_id) { - this._category = update as Category; - } + this.updateCategory(update as Category); } // TODO: There is no way (yet) to add Submitters to a motion // Thus, this feature could not be tested } + /** + * Updates the Category + */ + public updateCategory(update: Category): void { + if (this.motion && update.id === this.motion.category_id) { + this._category = update as Category; + } + } + + /** + * updates the Workflow + */ + public updateWorkflow(update: Workflow): void { + if (this.motion && update.id === this.motion.workflow_id) { + this._workflow = update as Workflow; + } + } + public hasSupporters(): boolean { return !!(this.supporters && this.supporters.length > 0); } diff --git a/client/src/app/site/motions/services/category-repository.service.spec.ts b/client/src/app/site/motions/services/category-repository.service.spec.ts new file mode 100644 index 000000000..0d8fa398b --- /dev/null +++ b/client/src/app/site/motions/services/category-repository.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { CategoryRepositoryService } from './category-repository.service'; + +describe('CategoryRepositoryService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [CategoryRepositoryService] + }); + }); + + it('should be created', inject([CategoryRepositoryService], (service: CategoryRepositoryService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/client/src/app/site/motions/services/category-repository.service.ts b/client/src/app/site/motions/services/category-repository.service.ts new file mode 100644 index 000000000..37ada08d9 --- /dev/null +++ b/client/src/app/site/motions/services/category-repository.service.ts @@ -0,0 +1,74 @@ +import { Injectable } from '@angular/core'; +import { Category } from '../../../shared/models/motions/category'; +import { ViewCategory } from '../models/view-category'; +import { DataSendService } from '../../../core/services/data-send.service'; +import { Observable } from 'rxjs'; +import { DataStoreService } from '../../../core/services/data-store.service'; +import { BaseRepository } from '../../base/base-repository'; + +/** + * Repository Services for Categories + * + * The repository is meant to process domain objects (those found under + * shared/models), so components can display them and interact with them. + * + * Rather than manipulating models directly, the repository is meant to + * inform the {@link DataSendService} about changes which will send + * them to the Server. + */ +@Injectable({ + providedIn: 'root' +}) +export class CategoryRepositoryService extends BaseRepository { + /** + * Creates a CategoryRepository + * Converts existing and incoming category to ViewCategories + * Handles CRUD using an observer to the DataStore + * @param DataSend + */ + public constructor(protected DS: DataStoreService, private dataSend: DataSendService) { + super(DS, Category); + } + + protected createViewModel(category: Category): ViewCategory { + return new ViewCategory(category); + } + + public create(update: Category, viewCategory?: ViewCategory): Observable { + console.log('update: ', update); + console.log('viewCategory: ', viewCategory); + if (this.osInDataStore(viewCategory)) { + return this.update(update, viewCategory); + } else { + return this.dataSend.saveModel(viewCategory.category); + } + } + + public update(update: Category, viewCategory?: ViewCategory): Observable { + let updateCategory: Category; + if (viewCategory) { + updateCategory = viewCategory.category; + } else { + updateCategory = new Category(); + } + updateCategory.patchValues(update); + return this.dataSend.saveModel(updateCategory); + } + + public delete(viewCategory: ViewCategory): Observable { + const category = viewCategory.category; + return this.dataSend.delete(category); + } + + /** + * Checks if a Catagory is on the server already + * @param viewCategory the category to check if it is already on the server + */ + public osInDataStore(viewCategory: ViewCategory): boolean { + const serverCategoryArray = this.DS.getAll(Category); + if (serverCategoryArray.find(cat => cat.id === viewCategory.id)) { + return true; + } + return false; + } +} diff --git a/client/src/app/site/motions/services/motion-repository.service.ts b/client/src/app/site/motions/services/motion-repository.service.ts index 0c3882e6f..b4cbfcc46 100644 --- a/client/src/app/site/motions/services/motion-repository.service.ts +++ b/client/src/app/site/motions/services/motion-repository.service.ts @@ -65,8 +65,8 @@ export class MotionRepositoryService extends BaseRepository * @param viewMotion The View Motion. If not present, a new motion will be created * TODO: Remove the viewMotion and make it actually distignuishable from save() */ - public create(update: any, viewMotion?: ViewMotion): Observable { - return this.save(update, viewMotion); + public create(motion: Motion): Observable { + return this.dataSend.saveModel(motion); } /** @@ -78,39 +78,10 @@ export class MotionRepositoryService extends BaseRepository * @param update the form data containing the update values * @param viewMotion The View Motion. If not present, a new motion will be created */ - public save(update: any, viewMotion?: ViewMotion): Observable { - let updateMotion: Motion; - if (viewMotion) { - // implies that an existing motion was updated - updateMotion = viewMotion.motion; - } else { - // implies that a new motion was created - updateMotion = new Motion(); - } - // submitters: User[] -> submitter: MotionSubmitter[] - const submitters = update.submitters as User[]; - // The server doesn't really accept MotionSubmitter arrays on create. - // We simply need to send an number[] on create. - // MotionSubmitter[] should be send on update - update.submitters = undefined; - const submitterIds: number[] = []; - if (submitters.length > 0) { - submitters.forEach(submitter => { - submitterIds.push(submitter.id); - }); - } - update.submitters_id = submitterIds; - // supporters[]: User -> supporters_id: number[]; - const supporters = update.supporters_id as User[]; - const supporterIds: number[] = []; - if (supporters.length > 0) { - supporters.forEach(supporter => { - supporterIds.push(supporter.id); - }); - } - update.supporters_id = supporterIds; - updateMotion.patchValues(update); - return this.dataSend.saveModel(updateMotion); + public update(update: Partial, viewMotion: ViewMotion): Observable { + const motion = viewMotion.motion; + motion.patchValues(update); + return this.dataSend.saveModel(motion); } /** diff --git a/client/src/app/site/settings/models/view-config.ts b/client/src/app/site/settings/models/view-config.ts index a531bf758..1e8714cf0 100644 --- a/client/src/app/site/settings/models/view-config.ts +++ b/client/src/app/site/settings/models/view-config.ts @@ -1,5 +1,4 @@ import { BaseViewModel } from '../../base/base-view-model'; -import { BaseModel } from '../../../shared/models/base/base-model'; import { Config } from '../../../shared/models/core/config'; export class ViewConfig extends BaseViewModel { @@ -30,9 +29,7 @@ export class ViewConfig extends BaseViewModel { return this.key; } - public updateValues(update: BaseModel): void { - if (update instanceof Config && this.id === update.id) { - this._config = update; - } + public updateValues(update: Config): void { + this._config = update; } } diff --git a/client/src/app/site/settings/services/config-repository.service.ts b/client/src/app/site/settings/services/config-repository.service.ts index 1e5958049..7580b07ea 100644 --- a/client/src/app/site/settings/services/config-repository.service.ts +++ b/client/src/app/site/settings/services/config-repository.service.ts @@ -27,7 +27,7 @@ export class ConfigRepositoryService extends BaseRepository * * TODO: used over not-yet-existing detail view */ - public save(config: Config, viewConfig: ViewConfig): Observable { + public update(config: Partial, viewConfig: ViewConfig): Observable { return null; } @@ -47,7 +47,7 @@ export class ConfigRepositoryService extends BaseRepository * * Function exists solely to correctly implement {@link BaseRepository} */ - public create(config: Config, viewConfig: ViewConfig): Observable { + public create(config: Config): Observable { return null; } diff --git a/client/src/app/site/users/models/view-user.ts b/client/src/app/site/users/models/view-user.ts index 1eabb7864..739c32f8b 100644 --- a/client/src/app/site/users/models/view-user.ts +++ b/client/src/app/site/users/models/view-user.ts @@ -7,6 +7,10 @@ export class ViewUser extends BaseViewModel { private _user: User; private _groups: Group[]; + public get id(): number { + return this._user ? this._user.id : null; + } + public get user(): User { return this._user; } @@ -47,22 +51,30 @@ export class ViewUser extends BaseViewModel { console.log('replace group - not yet implemented, ', newGroup); } + public updateValues(update: BaseModel): void { + if (update instanceof Group) { + this.updateGroup(update as Group); + } + if (update instanceof User) { + this.updateUser(update as User); + } + } + + public updateGroup(update: Group): void { + if (this.user && this.user.groups_id) { + if (this.user.containsGroupId(update.id)) { + this.replaceGroup(update); + } + } + } /** * Updates values. Triggered through observables. * * @param update a new User or Group */ - public updateValues(update: BaseModel): void { - if (update instanceof User) { - if (this.user.id === update.id) { - this._user = update; - } - } else if (update instanceof Group) { - if (this.user && this.user.groups_id) { - if (this.user.containsGroupId(update.id)) { - this.replaceGroup(update); - } - } + public updateUser(update: User): void { + if (this.user.id === update.id) { + this._user = update; } } } diff --git a/client/src/app/site/users/services/user-repository.service.ts b/client/src/app/site/users/services/user-repository.service.ts index e79e78da0..83adfa13e 100644 --- a/client/src/app/site/users/services/user-repository.service.ts +++ b/client/src/app/site/users/services/user-repository.service.ts @@ -28,7 +28,7 @@ export class UserRepositoryService extends BaseRepository { * * TODO: used over not-yet-existing detail view */ - public save(user: User, viewUser: ViewUser): Observable { + public update(user: Partial, viewUser: ViewUser): Observable { return null; } @@ -46,7 +46,7 @@ export class UserRepositoryService extends BaseRepository { * * TODO: used over not-yet-existing detail view */ - public create(user: User, viewFile: ViewUser): Observable { + public create(user: User): Observable { return null; } diff --git a/client/src/styles.scss b/client/src/styles.scss index 15d6640f6..ecb69e0ad 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -21,12 +21,6 @@ body { padding: 0; } -/**the plus button in Motion, Agenda, etc*/ -.generic-plus-button { - bottom: -30px; - z-index: 100; -} - .generic-mini-button { bottom: -28px; z-index: 100;