Merge pull request #3890 from FinnStutzenstein/plugins3
App initialization
This commit is contained in:
commit
19d78a3361
@ -1,7 +1,7 @@
|
||||
// angular modules
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { HttpClientModule, HttpClient, HttpClientXsrfModule } from '@angular/common/http';
|
||||
|
||||
// Elementary App Components
|
||||
@ -13,6 +13,7 @@ import { CoreModule } from './core/core.module';
|
||||
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
||||
import { PruningTranslationLoader } from './core/pruning-loader';
|
||||
import { LoginModule } from './site/login/login.module';
|
||||
import { AppLoadService } from './core/services/app-load.service';
|
||||
|
||||
/**
|
||||
* For the translation module. Loads a Custom 'translation loader' and provides it as loader.
|
||||
@ -21,6 +22,15 @@ import { LoginModule } from './site/login/login.module';
|
||||
export function HttpLoaderFactory(http: HttpClient): PruningTranslationLoader {
|
||||
return new PruningTranslationLoader(http);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that returns a promis that will be resolved, if all apps are loaded.
|
||||
* @param appLoadService The service that loads the apps.
|
||||
*/
|
||||
export function AppLoaderFactory(appLoadService: AppLoadService): () => Promise<void> {
|
||||
return () => appLoadService.loadApps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Global App Module. Keep it as clean as possible.
|
||||
*/
|
||||
@ -45,6 +55,7 @@ export function HttpLoaderFactory(http: HttpClient): PruningTranslationLoader {
|
||||
CoreModule,
|
||||
LoginModule
|
||||
],
|
||||
providers: [{ provide: APP_INITIALIZER, useFactory: AppLoaderFactory, deps: [AppLoadService], multi: true }],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {}
|
||||
|
12
client/src/app/core/services/app-load.service.spec.ts
Normal file
12
client/src/app/core/services/app-load.service.spec.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
import { NotifyService } from './notify.service';
|
||||
describe('NotifyService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [NotifyService]
|
||||
});
|
||||
});
|
||||
it('should be created', inject([NotifyService], (service: NotifyService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
61
client/src/app/core/services/app-load.service.ts
Normal file
61
client/src/app/core/services/app-load.service.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { plugins } from '../../../plugins';
|
||||
import { CommonAppConfig } from '../../site/common/common.config';
|
||||
import { ModelConstructor, BaseModel } from '../../shared/models/base/base-model';
|
||||
import { AppConfig } from '../../site/base/app-config';
|
||||
import { CollectionStringModelMapperService } from './collectionStringModelMapper.service';
|
||||
import { MediafileAppConfig } from '../../site/mediafiles/mediafile.config';
|
||||
import { MotionsAppConfig } from '../../site/motions/motions.config';
|
||||
import { SettingsAppConfig } from '../../site/settings/settings.config';
|
||||
import { AgendaAppConfig } from '../../site/agenda/agenda.config';
|
||||
import { AssignmentsAppConfig } from '../../site/assignments/assignments.config';
|
||||
import { UsersAppConfig } from '../../site/users/users.config';
|
||||
import { MainMenuService } from './main-menu.service';
|
||||
|
||||
/**
|
||||
* A list of all app configurations of all delivered apps.
|
||||
*/
|
||||
const appConfigs: AppConfig[] = [
|
||||
CommonAppConfig,
|
||||
SettingsAppConfig,
|
||||
AgendaAppConfig,
|
||||
AssignmentsAppConfig,
|
||||
MotionsAppConfig,
|
||||
MediafileAppConfig,
|
||||
UsersAppConfig
|
||||
];
|
||||
|
||||
/**
|
||||
* Handles all incoming and outgoing notify messages via {@link WebsocketService}.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AppLoadService {
|
||||
public constructor(
|
||||
private modelMapper: CollectionStringModelMapperService,
|
||||
private mainMenuService: MainMenuService
|
||||
) {}
|
||||
|
||||
public async loadApps(): Promise<void> {
|
||||
if (plugins.length) {
|
||||
console.log('plugins: ', plugins);
|
||||
}
|
||||
/*for (const pluginName of plugins) {
|
||||
const plugin = await import('../../../../../plugins/' + pluginName + '/' + pluginName);
|
||||
plugin.main();
|
||||
}*/
|
||||
appConfigs.forEach((config: AppConfig) => {
|
||||
if (config.models) {
|
||||
config.models.forEach(entry => {
|
||||
this.modelMapper.registerCollectionElement(entry.collectionString, entry.model);
|
||||
});
|
||||
}
|
||||
if (config.mainMenuEntries) {
|
||||
this.mainMenuService.registerEntries(config.mainMenuEntries);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private registerModels(models?: { collectionString: string; model: ModelConstructor<BaseModel> }[]): void {}
|
||||
}
|
@ -21,7 +21,11 @@ export class AutoupdateService extends OpenSlidesComponent {
|
||||
* Constructor to create the AutoupdateService. Calls the constructor of the parent class.
|
||||
* @param websocketService
|
||||
*/
|
||||
public constructor(websocketService: WebsocketService, private DS: DataStoreService) {
|
||||
public constructor(
|
||||
websocketService: WebsocketService,
|
||||
private DS: DataStoreService,
|
||||
private modelMapper: CollectionStringModelMapperService
|
||||
) {
|
||||
super();
|
||||
websocketService.getOberservable<any>('autoupdate').subscribe(response => {
|
||||
this.storeResponse(response);
|
||||
@ -61,7 +65,7 @@ export class AutoupdateService extends OpenSlidesComponent {
|
||||
|
||||
// Add the objects to the DataStore.
|
||||
Object.keys(autoupdate.changed).forEach(collection => {
|
||||
const targetClass = CollectionStringModelMapperService.getModelConstructor(collection);
|
||||
const targetClass = this.modelMapper.getModelConstructor(collection);
|
||||
if (!targetClass) {
|
||||
// TODO: throw an error later..
|
||||
/*throw new Error*/ console.log(`Unregistered resource ${collection}`);
|
||||
|
@ -1,8 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ModelConstructor, BaseModel } from '../../shared/models/base/base-model';
|
||||
|
||||
/**
|
||||
* Registeres the mapping of collection strings <--> actual types. Every Model should register itself here.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CollectionStringModelMapperService {
|
||||
/**
|
||||
* Mapps collection strings to model constructors. Accessed by {@method registerCollectionElement} and
|
||||
@ -10,26 +14,10 @@ export class CollectionStringModelMapperService {
|
||||
*/
|
||||
private static collectionStringsTypeMapping: { [collectionString: string]: ModelConstructor<BaseModel> } = {};
|
||||
|
||||
/**
|
||||
* Registers the type to the collection string
|
||||
* @param collectionString
|
||||
* @param type
|
||||
*/
|
||||
public static registerCollectionElement(collectionString: string, type: ModelConstructor<BaseModel>): void {
|
||||
CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString] = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the constructor of the requested collection or undefined, if it is not registered.
|
||||
* @param collectionString the requested collection
|
||||
*/
|
||||
public static getModelConstructor(collectionString: string): ModelConstructor<BaseModel> {
|
||||
return CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection string of a given ModelConstructor or undefined, if it is not registered.
|
||||
* @param ctor
|
||||
* @deprecated Should inject this service and don't use the static functions.
|
||||
*/
|
||||
public static getCollectionString(ctor: ModelConstructor<BaseModel>): string {
|
||||
return Object.keys(CollectionStringModelMapperService.collectionStringsTypeMapping).find(
|
||||
@ -44,4 +32,33 @@ export class CollectionStringModelMapperService {
|
||||
* @param websocketService
|
||||
*/
|
||||
public constructor() {}
|
||||
|
||||
/**
|
||||
* Registers the type to the collection string
|
||||
* @param collectionString
|
||||
* @param type
|
||||
*/
|
||||
public registerCollectionElement(collectionString: string, type: ModelConstructor<BaseModel>): void {
|
||||
CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString] = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the constructor of the requested collection or undefined, if it is not registered.
|
||||
* @param collectionString the requested collection
|
||||
*/
|
||||
public getModelConstructor(collectionString: string): ModelConstructor<BaseModel> {
|
||||
return CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection string of a given ModelConstructor or undefined, if it is not registered.
|
||||
* @param ctor
|
||||
*/
|
||||
public getCollectionString(ctor: ModelConstructor<BaseModel>): string {
|
||||
return Object.keys(CollectionStringModelMapperService.collectionStringsTypeMapping).find(
|
||||
(collectionString: string) => {
|
||||
return ctor === CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString];
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ export class DataStoreService {
|
||||
* Empty constructor for dataStore
|
||||
* @param cacheService use CacheService to cache the DataStore.
|
||||
*/
|
||||
public constructor(private cacheService: CacheService) {
|
||||
public constructor(private cacheService: CacheService, private modelMapper: CollectionStringModelMapperService) {
|
||||
if (DataStoreService.wasInstantiated) {
|
||||
throw new Error('The Datastore should just be instantiated once!');
|
||||
}
|
||||
@ -158,7 +158,7 @@ export class DataStoreService {
|
||||
const storage: ModelStorage = {};
|
||||
Object.keys(serializedStore).forEach(collectionString => {
|
||||
storage[collectionString] = {} as ModelCollection;
|
||||
const target = CollectionStringModelMapperService.getModelConstructor(collectionString);
|
||||
const target = this.modelMapper.getModelConstructor(collectionString);
|
||||
if (target) {
|
||||
Object.keys(serializedStore[collectionString]).forEach(id => {
|
||||
const data = JSON.parse(serializedStore[collectionString][id]);
|
||||
@ -186,7 +186,7 @@ export class DataStoreService {
|
||||
if (typeof collectionType === 'string') {
|
||||
return collectionType;
|
||||
} else {
|
||||
return CollectionStringModelMapperService.getCollectionString(collectionType);
|
||||
return this.modelMapper.getCollectionString(collectionType);
|
||||
}
|
||||
}
|
||||
|
||||
|
15
client/src/app/core/services/main-menu.service.spec.ts
Normal file
15
client/src/app/core/services/main-menu.service.spec.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { MainMenuService } from './main-menu.service';
|
||||
|
||||
describe('MainMenuService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [MainMenuService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([MainMenuService], (service: MainMenuService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
61
client/src/app/core/services/main-menu.service.ts
Normal file
61
client/src/app/core/services/main-menu.service.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
/**
|
||||
* This represents one entry in the main menu
|
||||
*/
|
||||
export interface MainMenuEntry {
|
||||
/**
|
||||
* The route for the router to navigate to on click.
|
||||
*/
|
||||
route: string;
|
||||
/**
|
||||
* The display string to be shown.
|
||||
*/
|
||||
displayName: string;
|
||||
|
||||
/**
|
||||
* The font awesom icon to display.
|
||||
*/
|
||||
icon: string;
|
||||
|
||||
/**
|
||||
* For sorting the entries.
|
||||
*/
|
||||
weight: number;
|
||||
|
||||
/**
|
||||
* The permission to see the entry.
|
||||
*/
|
||||
permission: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects main menu entries and provides them to the main menu component.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MainMenuService {
|
||||
/**
|
||||
* A list of sorted entries.
|
||||
*/
|
||||
private _entries: MainMenuEntry[] = [];
|
||||
|
||||
/**
|
||||
* Make the entries public.
|
||||
*/
|
||||
public get entries(): MainMenuEntry[] {
|
||||
return this._entries;
|
||||
}
|
||||
|
||||
public constructor() {}
|
||||
|
||||
/**
|
||||
* Adds entries to the mainmenu.
|
||||
* @param entries The entries to add
|
||||
*/
|
||||
public registerEntries(entries: MainMenuEntry[]): void {
|
||||
this._entries.push(...entries);
|
||||
this._entries = this._entries.sort((a, b) => a.weight - b.weight);
|
||||
}
|
||||
}
|
@ -56,5 +56,3 @@ export class Item extends ProjectableBaseModel {
|
||||
return this.getListTitle();
|
||||
}
|
||||
}
|
||||
|
||||
ProjectableBaseModel.registerCollectionElement('agenda/item', Item);
|
||||
|
@ -56,5 +56,3 @@ export class Assignment extends AgendaBaseModel {
|
||||
return 'TODO';
|
||||
}
|
||||
}
|
||||
|
||||
AgendaBaseModel.registerCollectionElement('assignments/assignment', Assignment);
|
||||
|
@ -1,6 +1,5 @@
|
||||
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';
|
||||
|
||||
@ -14,15 +13,6 @@ export interface ModelConstructor<T extends BaseModel<T>> {
|
||||
*/
|
||||
export abstract class BaseModel<T = object> extends OpenSlidesComponent
|
||||
implements Deserializable, Displayable, Identifiable {
|
||||
/**
|
||||
* Register the collection string to the type.
|
||||
* @param collectionString
|
||||
* @param type
|
||||
*/
|
||||
public static registerCollectionElement(collectionString: string, type: any): void {
|
||||
CollectionStringModelMapperService.registerCollectionElement(collectionString, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* force children of BaseModel to have a collectionString.
|
||||
*
|
||||
|
@ -18,5 +18,3 @@ export class ChatMessage extends BaseModel<ChatMessage> {
|
||||
return 'Chatmessage';
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('core/chat-message', ChatMessage);
|
||||
|
@ -17,5 +17,3 @@ export class Config extends BaseModel {
|
||||
return this.key;
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('core/config', Config);
|
||||
|
@ -19,5 +19,3 @@ export class Countdown extends ProjectableBaseModel {
|
||||
return this.description;
|
||||
}
|
||||
}
|
||||
|
||||
ProjectableBaseModel.registerCollectionElement('core/countdown', Countdown);
|
||||
|
@ -16,5 +16,3 @@ export class ProjectorMessage extends ProjectableBaseModel {
|
||||
return 'Projectormessage';
|
||||
}
|
||||
}
|
||||
|
||||
ProjectableBaseModel.registerCollectionElement('core/projector-message', ProjectorMessage);
|
||||
|
@ -23,5 +23,3 @@ export class Projector extends BaseModel<Projector> {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('core/projector', Projector);
|
||||
|
@ -16,5 +16,3 @@ export class Tag extends BaseModel<Tag> {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('core/tag', Tag);
|
||||
|
@ -28,5 +28,3 @@ export class Mediafile extends ProjectableBaseModel {
|
||||
return this.title;
|
||||
}
|
||||
}
|
||||
|
||||
ProjectableBaseModel.registerCollectionElement('mediafiles/mediafile', Mediafile);
|
||||
|
@ -17,5 +17,3 @@ export class Category extends BaseModel<Category> {
|
||||
return this.prefix + ' - ' + this.name;
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('motions/category', Category);
|
||||
|
@ -21,5 +21,3 @@ export class MotionBlock extends AgendaBaseModel {
|
||||
return 'TODO';
|
||||
}
|
||||
}
|
||||
|
||||
AgendaBaseModel.registerCollectionElement('motions/motion-block', MotionBlock);
|
||||
|
@ -23,5 +23,3 @@ export class MotionChangeReco extends BaseModel<MotionChangeReco> {
|
||||
return 'Changerecommendation';
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('motions/motion-change-recommendation', MotionChangeReco);
|
||||
|
@ -18,5 +18,3 @@ export class MotionCommentSection extends BaseModel<MotionCommentSection> {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('motions/motion-comment-section', MotionCommentSection);
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { MotionSubmitter } from './motion-submitter';
|
||||
import { MotionLog } from './motion-log';
|
||||
import { Category } from './category';
|
||||
import { MotionComment } from './motion-comment';
|
||||
import { Workflow } from './workflow';
|
||||
import { AgendaBaseModel } from '../base/agenda-base-model';
|
||||
|
||||
/**
|
||||
@ -99,10 +97,3 @@ export class Motion extends AgendaBaseModel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hack to get them loaded at last
|
||||
*/
|
||||
AgendaBaseModel.registerCollectionElement('motions/motion', Motion);
|
||||
AgendaBaseModel.registerCollectionElement('motions/category', Category);
|
||||
AgendaBaseModel.registerCollectionElement('motions/workflow', Workflow);
|
||||
|
@ -58,5 +58,3 @@ export class Workflow extends BaseModel<Workflow> {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('motions/workflow', Workflow);
|
||||
|
@ -28,5 +28,3 @@ export class Topic extends AgendaBaseModel {
|
||||
return 'TODO';
|
||||
}
|
||||
}
|
||||
|
||||
AgendaBaseModel.registerCollectionElement('topics/topic', Topic);
|
||||
|
@ -17,5 +17,3 @@ export class Group extends BaseModel<Group> {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('users/group', Group);
|
||||
|
@ -17,5 +17,3 @@ export class PersonalNote extends BaseModel<PersonalNote> {
|
||||
return 'Personal note';
|
||||
}
|
||||
}
|
||||
|
||||
BaseModel.registerCollectionElement('users/personal-note', PersonalNote);
|
||||
|
@ -89,5 +89,3 @@ export class User extends ProjectableBaseModel {
|
||||
return this.short_name;
|
||||
}
|
||||
}
|
||||
|
||||
ProjectableBaseModel.registerCollectionElement('users/user', User);
|
||||
|
17
client/src/app/site/agenda/agenda.config.ts
Normal file
17
client/src/app/site/agenda/agenda.config.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { AppConfig } from '../base/app-config';
|
||||
import { Item } from '../../shared/models/agenda/item';
|
||||
import { Topic } from '../../shared/models/topics/topic';
|
||||
|
||||
export const AgendaAppConfig: AppConfig = {
|
||||
name: 'agenda',
|
||||
models: [{ collectionString: 'agenda/item', model: Item }, { collectionString: 'topics/topic', model: Topic }],
|
||||
mainMenuEntries: [
|
||||
{
|
||||
route: '/agenda',
|
||||
displayName: 'Agenda',
|
||||
icon: 'calendar',
|
||||
weight: 200,
|
||||
permission: 'agenda.can_see'
|
||||
}
|
||||
]
|
||||
};
|
16
client/src/app/site/assignments/assignments.config.ts
Normal file
16
client/src/app/site/assignments/assignments.config.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { AppConfig } from '../base/app-config';
|
||||
import { Assignment } from '../../shared/models/assignments/assignment';
|
||||
|
||||
export const AssignmentsAppConfig: AppConfig = {
|
||||
name: 'assignments',
|
||||
models: [{ collectionString: 'assignments/assignment', model: Assignment }],
|
||||
mainMenuEntries: [
|
||||
{
|
||||
route: '/assignments',
|
||||
displayName: 'Elections',
|
||||
icon: 'chart-pie',
|
||||
weight: 400,
|
||||
permission: 'assignments.can_see'
|
||||
}
|
||||
]
|
||||
};
|
25
client/src/app/site/base/app-config.ts
Normal file
25
client/src/app/site/base/app-config.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { ModelConstructor, BaseModel } from '../../shared/models/base/base-model';
|
||||
import { MainMenuEntry } from '../../core/services/main-menu.service';
|
||||
|
||||
/**
|
||||
* The configuration of an app.
|
||||
*/
|
||||
export interface AppConfig {
|
||||
/**
|
||||
* The name.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* All models, that should be registered.
|
||||
*/
|
||||
models?: {
|
||||
collectionString: string;
|
||||
model: ModelConstructor<BaseModel>;
|
||||
}[];
|
||||
|
||||
/**
|
||||
* Main menu entries.
|
||||
*/
|
||||
mainMenuEntries?: MainMenuEntry[];
|
||||
}
|
26
client/src/app/site/common/common-routing.module.ts
Normal file
26
client/src/app/site/common/common-routing.module.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component';
|
||||
import { StartComponent } from './components/start/start.component';
|
||||
import { LegalNoticeComponent } from './components/legal-notice/legal-notice.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: StartComponent
|
||||
},
|
||||
{
|
||||
path: 'legalnotice',
|
||||
component: LegalNoticeComponent
|
||||
},
|
||||
{
|
||||
path: 'privacypolicy',
|
||||
component: PrivacyPolicyComponent
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class CommonRoutingModule {}
|
26
client/src/app/site/common/common.config.ts
Normal file
26
client/src/app/site/common/common.config.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { AppConfig } from '../base/app-config';
|
||||
import { Projector } from '../../shared/models/core/projector';
|
||||
import { Countdown } from '../../shared/models/core/countdown';
|
||||
import { ChatMessage } from '../../shared/models/core/chat-message';
|
||||
import { ProjectorMessage } from '../../shared/models/core/projector-message';
|
||||
import { Tag } from '../../shared/models/core/tag';
|
||||
|
||||
export const CommonAppConfig: AppConfig = {
|
||||
name: 'common',
|
||||
models: [
|
||||
{ collectionString: 'core/projector', model: Projector },
|
||||
{ collectionString: 'core/chat-message', model: ChatMessage },
|
||||
{ collectionString: 'core/countdown', model: Countdown },
|
||||
{ collectionString: 'core/projector-message', model: ProjectorMessage },
|
||||
{ collectionString: 'core/tag', model: Tag }
|
||||
],
|
||||
mainMenuEntries: [
|
||||
{
|
||||
route: '/',
|
||||
displayName: 'Home',
|
||||
icon: 'home',
|
||||
weight: 100,
|
||||
permission: 'core.can_see_frontpage'
|
||||
}
|
||||
]
|
||||
};
|
13
client/src/app/site/common/common.module.spec.ts
Normal file
13
client/src/app/site/common/common.module.spec.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { CommonModule } from './common.module';
|
||||
|
||||
describe('CommonModule', () => {
|
||||
let commonModule: CommonModule;
|
||||
|
||||
beforeEach(() => {
|
||||
commonModule = new CommonModule();
|
||||
});
|
||||
|
||||
it('should create an instance', () => {
|
||||
expect(commonModule).toBeTruthy();
|
||||
});
|
||||
});
|
14
client/src/app/site/common/common.module.ts
Normal file
14
client/src/app/site/common/common.module.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule as AngularCommonModule } from '@angular/common';
|
||||
|
||||
import { CommonRoutingModule } from './common-routing.module';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component';
|
||||
import { StartComponent } from './components/start/start.component';
|
||||
import { LegalNoticeComponent } from './components/legal-notice/legal-notice.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [AngularCommonModule, CommonRoutingModule, SharedModule],
|
||||
declarations: [PrivacyPolicyComponent, StartComponent, LegalNoticeComponent]
|
||||
})
|
||||
export class CommonModule {}
|
@ -7,8 +7,6 @@
|
||||
<h4> {{welcomeTitle | translate}} </h4>
|
||||
<span> {{welcomeText | translate}} </span>
|
||||
|
||||
<button mat-button (click)="DataStoreTest()">DataStoreTest</button>
|
||||
<br/>
|
||||
<button mat-button (click)="TranslateTest()">Translate in console</button>
|
||||
<br/>
|
||||
<button mat-button (click)="giveDataStore()">print the dataStore</button>
|
@ -5,11 +5,10 @@ import { BaseComponent } from 'app/base.component';
|
||||
import { TranslateService } from '@ngx-translate/core'; // showcase
|
||||
|
||||
// for testing the DS and BaseModel
|
||||
import { User } from 'app/shared/models/users/user';
|
||||
import { Config } from '../../shared/models/core/config';
|
||||
import { Motion } from '../../shared/models/motions/motion';
|
||||
import { MotionSubmitter } from '../../shared/models/motions/motion-submitter';
|
||||
import { DataStoreService } from '../../core/services/data-store.service';
|
||||
import { Config } from '../../../../shared/models/core/config';
|
||||
import { Motion } from '../../../../shared/models/motions/motion';
|
||||
import { MotionSubmitter } from '../../../../shared/models/motions/motion-submitter';
|
||||
import { DataStoreService } from '../../../../core/services/data-store.service';
|
||||
|
||||
@Component({
|
||||
selector: 'os-start',
|
||||
@ -74,36 +73,6 @@ export class StartComponent extends BaseComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* test data store
|
||||
*/
|
||||
public DataStoreTest(): void {
|
||||
console.log('add a user to dataStore');
|
||||
this.DS.add(new User({ id: 100 }));
|
||||
console.log('add three users to dataStore');
|
||||
this.DS.add(new User({ id: 200 }), new User({ id: 201 }), new User({ id: 202 }));
|
||||
console.log('use the spread operator "..." to add an array');
|
||||
const userArray = [];
|
||||
for (let i = 300; i < 400; i++) {
|
||||
userArray.push(new User({ id: i }));
|
||||
}
|
||||
this.DS.add(...userArray);
|
||||
|
||||
console.log('try to get user with ID 1:');
|
||||
const user1fromStore = this.DS.get<User>(User, 1);
|
||||
console.log('the user: ', user1fromStore);
|
||||
|
||||
console.log('remove a single user:');
|
||||
this.DS.remove('users/user', 100);
|
||||
console.log('remove more users');
|
||||
this.DS.remove('users/user', 200, 201, 202);
|
||||
console.log('remove an array of users');
|
||||
this.DS.remove('users/user', ...[321, 363, 399]);
|
||||
|
||||
console.log('test filter: ');
|
||||
console.log(this.DS.filter<User>(User, user => user.id === 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* function to print datastore
|
||||
*/
|
16
client/src/app/site/mediafiles/mediafile.config.ts
Normal file
16
client/src/app/site/mediafiles/mediafile.config.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { AppConfig } from '../base/app-config';
|
||||
import { Mediafile } from '../../shared/models/mediafiles/mediafile';
|
||||
|
||||
export const MediafileAppConfig: AppConfig = {
|
||||
name: 'mediafiles',
|
||||
models: [{ collectionString: 'mediafiles/mediafile', model: Mediafile }],
|
||||
mainMenuEntries: [
|
||||
{
|
||||
route: '/mediafiles',
|
||||
displayName: 'Files',
|
||||
icon: 'paperclip',
|
||||
weight: 600,
|
||||
permission: 'mediafiles.can_see'
|
||||
}
|
||||
]
|
||||
};
|
28
client/src/app/site/motions/motions.config.ts
Normal file
28
client/src/app/site/motions/motions.config.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { AppConfig } from '../base/app-config';
|
||||
import { Motion } from '../../shared/models/motions/motion';
|
||||
import { Category } from '../../shared/models/motions/category';
|
||||
import { Workflow } from '../../shared/models/motions/workflow';
|
||||
import { MotionCommentSection } from '../../shared/models/motions/motion-comment-section';
|
||||
import { MotionChangeReco } from '../../shared/models/motions/motion-change-reco';
|
||||
import { MotionBlock } from '../../shared/models/motions/motion-block';
|
||||
|
||||
export const MotionsAppConfig: AppConfig = {
|
||||
name: 'motions',
|
||||
models: [
|
||||
{ collectionString: 'motions/motion', model: Motion },
|
||||
{ collectionString: 'motions/category', model: Category },
|
||||
{ collectionString: 'motions/workflow', model: Workflow },
|
||||
{ collectionString: 'motions/motion-comment-section', model: MotionCommentSection },
|
||||
{ collectionString: 'motions/motion-change-recommendation', model: MotionChangeReco },
|
||||
{ collectionString: 'motions/motion-block', model: MotionBlock }
|
||||
],
|
||||
mainMenuEntries: [
|
||||
{
|
||||
route: '/motions',
|
||||
displayName: 'Motions',
|
||||
icon: 'file-alt',
|
||||
weight: 300,
|
||||
permission: 'motions.can_see'
|
||||
}
|
||||
]
|
||||
};
|
16
client/src/app/site/settings/settings.config.ts
Normal file
16
client/src/app/site/settings/settings.config.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { AppConfig } from '../base/app-config';
|
||||
import { Config } from '../../shared/models/core/config';
|
||||
|
||||
export const SettingsAppConfig: AppConfig = {
|
||||
name: 'settings',
|
||||
models: [{ collectionString: 'core/config', model: Config }],
|
||||
mainMenuEntries: [
|
||||
{
|
||||
route: '/settings',
|
||||
displayName: 'Settings',
|
||||
icon: 'cog',
|
||||
weight: 700,
|
||||
permission: 'core.can_manage_config'
|
||||
}
|
||||
]
|
||||
};
|
@ -3,9 +3,6 @@ import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { SiteComponent } from './site.component';
|
||||
|
||||
import { StartComponent } from './start/start.component';
|
||||
import { PrivacyPolicyComponent } from './privacy-policy/privacy-policy.component';
|
||||
import { LegalNoticeComponent } from './legal-notice/legal-notice.component';
|
||||
import { AuthGuard } from '../core/services/auth-guard.service';
|
||||
|
||||
/**
|
||||
@ -20,15 +17,7 @@ const routes: Routes = [
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: StartComponent
|
||||
},
|
||||
{
|
||||
path: 'legalnotice',
|
||||
component: LegalNoticeComponent
|
||||
},
|
||||
{
|
||||
path: 'privacypolicy',
|
||||
component: PrivacyPolicyComponent
|
||||
loadChildren: './common/common.module#CommonModule'
|
||||
},
|
||||
{
|
||||
path: 'agenda',
|
||||
|
@ -45,35 +45,13 @@
|
||||
|
||||
<!-- navigation -->
|
||||
<mat-nav-list class='main-nav'>
|
||||
<a [@navItemAnim] *osPerms="'core.can_see_frontpage'" mat-list-item routerLink='/' routerLinkActive='active' [routerLinkActiveOptions]="{exact: true}"
|
||||
(click)='toggleSideNav()'>
|
||||
<fa-icon icon='home'></fa-icon>
|
||||
<span translate>Home</span>
|
||||
</a>
|
||||
<a [@navItemAnim] *osPerms="'agenda.can_see'" mat-list-item routerLink='/agenda' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||
<fa-icon icon='calendar'></fa-icon>
|
||||
<span translate>Agenda</span>
|
||||
</a>
|
||||
<a [@navItemAnim] *osPerms="'motions.can_see'" mat-list-item routerLink='/motions' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||
<fa-icon icon='file-alt'></fa-icon>
|
||||
<span translate>Motions</span>
|
||||
</a>
|
||||
<a [@navItemAnim] *osPerms="'assignments.can_see'" mat-list-item routerLink='/assignments' routerLinkActive='active' (click)='vp.isMobile ? sideNav.toggle() : null'>
|
||||
<fa-icon icon='chart-pie'></fa-icon>
|
||||
<span translate>Assignments</span>
|
||||
</a>
|
||||
<a [@navItemAnim] *osPerms="'users.can_see_name'" mat-list-item routerLink='/users' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||
<fa-icon icon='user'></fa-icon>
|
||||
<span translate>Participants</span>
|
||||
</a>
|
||||
<a [@navItemAnim] *osPerms="'mediafiles.can_see'" mat-list-item routerLink='/mediafiles' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||
<fa-icon icon='paperclip'></fa-icon>
|
||||
<span translate>Files</span>
|
||||
</a>
|
||||
<a [@navItemAnim] *osPerms="'core.can_manage_config'" mat-list-item routerLink='/settings' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||
<fa-icon icon='cog'></fa-icon>
|
||||
<span translate>Settings</span>
|
||||
<span *ngFor="let entry of mainMenuService.entries">
|
||||
<a [@navItemAnim] *osPerms="entry.permission" mat-list-item (click)='toggleSideNav()'
|
||||
[routerLink]='entry.route' routerLinkActive='active' [routerLinkActiveOptions]="{exact: true}">
|
||||
<fa-icon [icon]='entry.icon'></fa-icon>
|
||||
{{ entry.displayName | translate}}
|
||||
</a>
|
||||
</span>
|
||||
<mat-divider></mat-divider>
|
||||
<a [@navItemAnim] *osPerms="'core.can_see_projector'" mat-list-item routerLink='/projector' routerLinkActive='active' (click)='toggleSideNav()'>
|
||||
<fa-icon icon='video'></fa-icon>
|
||||
|
@ -9,8 +9,7 @@ import { BaseComponent } from 'app/base.component';
|
||||
import { pageTransition, navItemAnim } from 'app/shared/animations';
|
||||
import { MatDialog, MatSidenav } from '@angular/material';
|
||||
import { ViewportService } from '../core/services/viewport.service';
|
||||
import { Projector } from '../shared/models/core/projector';
|
||||
import { Tag } from '../shared/models/core/tag';
|
||||
import { MainMenuService } from '../core/services/main-menu.service';
|
||||
|
||||
@Component({
|
||||
selector: 'os-site',
|
||||
@ -51,7 +50,8 @@ export class SiteComponent extends BaseComponent implements OnInit {
|
||||
public operator: OperatorService,
|
||||
public vp: ViewportService,
|
||||
public translate: TranslateService,
|
||||
public dialog: MatDialog
|
||||
public dialog: MatDialog,
|
||||
public mainMenuService: MainMenuService // used in the component
|
||||
) {
|
||||
super();
|
||||
|
||||
@ -75,11 +75,6 @@ export class SiteComponent extends BaseComponent implements OnInit {
|
||||
// this.translate.get('Motions').subscribe((res: string) => {
|
||||
// console.log('translation of motions in the target language: ' + res);
|
||||
// });
|
||||
|
||||
// tslint:disable-next-line
|
||||
const p: Projector = new Projector(); // Needed, that the Projector.ts is loaded. Can be removed, if something else creates/uses projectors.
|
||||
// tslint:disable-next-line
|
||||
const t: Tag = new Tag(); // Needed, that the Tag.ts is loaded. Can be removed, if something else creates/uses tags.
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,16 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { SiteRoutingModule } from './site-routing.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
|
||||
import { SiteComponent } from './site.component';
|
||||
import { StartComponent } from './start/start.component';
|
||||
import { LegalNoticeComponent } from './legal-notice/legal-notice.component';
|
||||
import { PrivacyPolicyComponent } from './privacy-policy/privacy-policy.component';
|
||||
import { SiteRoutingModule } from './site-routing.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, SharedModule, SiteRoutingModule],
|
||||
declarations: [SiteComponent, StartComponent, LegalNoticeComponent, PrivacyPolicyComponent]
|
||||
declarations: [SiteComponent]
|
||||
})
|
||||
export class SiteModule {}
|
||||
|
22
client/src/app/site/users/users.config.ts
Normal file
22
client/src/app/site/users/users.config.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { AppConfig } from '../base/app-config';
|
||||
import { User } from '../../shared/models/users/user';
|
||||
import { Group } from '../../shared/models/users/group';
|
||||
import { PersonalNote } from '../../shared/models/users/personal-note';
|
||||
|
||||
export const UsersAppConfig: AppConfig = {
|
||||
name: 'users',
|
||||
models: [
|
||||
{ collectionString: 'users/user', model: User },
|
||||
{ collectionString: 'users/group', model: Group },
|
||||
{ collectionString: 'users/personal-note', model: PersonalNote }
|
||||
],
|
||||
mainMenuEntries: [
|
||||
{
|
||||
route: '/users',
|
||||
displayName: 'Participants',
|
||||
icon: 'user',
|
||||
weight: 500,
|
||||
permission: 'users.can_see_name'
|
||||
}
|
||||
]
|
||||
};
|
1
client/src/plugins.ts
Normal file
1
client/src/plugins.ts
Normal file
@ -0,0 +1 @@
|
||||
export const plugins: string[] = [];
|
Loading…
Reference in New Issue
Block a user