Create more list views

Also:
- Update dependencies
- Clean up proxy file
This commit is contained in:
Sean Engelhardt 2018-09-11 16:38:23 +02:00 committed by sean
parent 582c2603a6
commit 80cfeaac35
42 changed files with 1223 additions and 341 deletions

203
client/package-lock.json generated
View File

@ -106,13 +106,36 @@
} }
}, },
"@angular-devkit/schematics": { "@angular-devkit/schematics": {
"version": "0.6.8", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.6.8.tgz", "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.8.1.tgz",
"integrity": "sha512-R4YqAUdo62wtrhX/5HSRGSKXNTWqfQb66ZE6m8jj6GEJNFKdNXMdxOchxr07LCiKTxfh1w6G3nGzxIsu/+D4KA==", "integrity": "sha512-ab3xeyTpPA9JO7oXgdfbQ/+5djddvoKjFaxFFcLD5GxgDDnvJcmhgDkluJY9JZHH2oSFaW8u1G5zg8uo1HrriA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@angular-devkit/core": "0.6.8", "@angular-devkit/core": "0.8.1",
"rxjs": "^6.0.0" "rxjs": "~6.2.0"
},
"dependencies": {
"@angular-devkit/core": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.1.tgz",
"integrity": "sha512-0TKjF/nHb7+wwWIQ5iuQRzDIF2CphmX9ZojBIGH6PWFgQNKG0yUWqSa+PTpr5eOcGYBOa1rHLf10iyPHDmBdBw==",
"dev": true,
"requires": {
"ajv": "~6.4.0",
"chokidar": "^2.0.3",
"rxjs": "~6.2.0",
"source-map": "^0.5.6"
}
},
"rxjs": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz",
"integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
}
} }
}, },
"@angular/animations": { "@angular/animations": {
@ -132,35 +155,71 @@
} }
}, },
"@angular/cli": { "@angular/cli": {
"version": "6.0.8", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.0.8.tgz", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.2.1.tgz",
"integrity": "sha512-DhH1Zq5Yonthw6zh6W07fhf+9XrAZbD1fcQ0MrmbxlieCfLlTAdBqyK2LavFCKwSZkUMLF6UHM3+jiNRVZSSIg==", "integrity": "sha512-4AO014PohYc/vbNaO6nPi/a6JqxdOHN2m0WLutgRGoBQswqSGn7aLEG1erZKRzbfq39E1a/efnNmEI3Okl3h1Q==",
"dev": true, "dev": true,
"requires": { "requires": {
"@angular-devkit/architect": "0.6.8", "@angular-devkit/architect": "0.8.1",
"@angular-devkit/core": "0.6.8", "@angular-devkit/core": "0.8.1",
"@angular-devkit/schematics": "0.6.8", "@angular-devkit/schematics": "0.8.1",
"@schematics/angular": "0.6.8", "@schematics/angular": "0.8.1",
"@schematics/update": "0.6.8", "@schematics/update": "0.8.1",
"opn": "~5.3.0", "json-schema-traverse": "^0.4.1",
"resolve": "^1.1.7", "opn": "^5.3.0",
"rxjs": "^6.0.0", "rxjs": "~6.2.0",
"semver": "^5.1.0", "semver": "^5.1.0",
"silent-error": "^1.0.0",
"symbol-observable": "^1.2.0", "symbol-observable": "^1.2.0",
"yargs-parser": "^10.0.0" "yargs-parser": "^10.0.0"
}, },
"dependencies": { "dependencies": {
"@angular-devkit/architect": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.8.1.tgz",
"integrity": "sha512-bf/8tg8X2y9f6wE2r48KAW2AVexfGd/rfTHRvl9+kSsFFtXVA233GNAL6Qs+wJ/G2t1NFddnE3ME2eyhJYxBwA==",
"dev": true,
"requires": {
"@angular-devkit/core": "0.8.1",
"rxjs": "~6.2.0"
}
},
"@angular-devkit/core": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.1.tgz",
"integrity": "sha512-0TKjF/nHb7+wwWIQ5iuQRzDIF2CphmX9ZojBIGH6PWFgQNKG0yUWqSa+PTpr5eOcGYBOa1rHLf10iyPHDmBdBw==",
"dev": true,
"requires": {
"ajv": "~6.4.0",
"chokidar": "^2.0.3",
"rxjs": "~6.2.0",
"source-map": "^0.5.6"
}
},
"camelcase": { "camelcase": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
"dev": true "dev": true
}, },
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
},
"rxjs": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz",
"integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
},
"yargs-parser": { "yargs-parser": {
"version": "10.0.0", "version": "10.1.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.0.0.tgz", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
"integrity": "sha512-+DHejWujTVYeMHLff8U96rLc4uE4Emncoftvn5AjhB1Jw1pWxLzgBUT/WYbPrHmy6YPEBTZQx5myHhVcuuu64g==", "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"camelcase": "^4.1.0" "camelcase": "^4.1.0"
@ -1065,28 +1124,74 @@
"dev": true "dev": true
}, },
"@schematics/angular": { "@schematics/angular": {
"version": "0.6.8", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.6.8.tgz", "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.8.1.tgz",
"integrity": "sha512-9kRphqTYG5Df/I8fvnT1zMsw0YNDPO9tl18tQZXj4am4raT7l9UCr+WkwJdlBoA5pwG6baWE9sL0iGWV/bzF/g==", "integrity": "sha512-AW7063IaYFIcskt+eI5k4drb/hDuY2wK3zLsW01E49WaBcRhXVIOVox7cbfwHCA6zch117WZ5xVZlbGHJ4pkMw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@angular-devkit/core": "0.6.8", "@angular-devkit/core": "0.8.1",
"@angular-devkit/schematics": "0.6.8", "@angular-devkit/schematics": "0.8.1",
"typescript": ">=2.6.2 <2.8" "typescript": ">=2.6.2 <2.10"
},
"dependencies": {
"@angular-devkit/core": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.1.tgz",
"integrity": "sha512-0TKjF/nHb7+wwWIQ5iuQRzDIF2CphmX9ZojBIGH6PWFgQNKG0yUWqSa+PTpr5eOcGYBOa1rHLf10iyPHDmBdBw==",
"dev": true,
"requires": {
"ajv": "~6.4.0",
"chokidar": "^2.0.3",
"rxjs": "~6.2.0",
"source-map": "^0.5.6"
}
},
"rxjs": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz",
"integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
}
} }
}, },
"@schematics/update": { "@schematics/update": {
"version": "0.6.8", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.6.8.tgz", "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.8.1.tgz",
"integrity": "sha512-1Uq7LYnwL2wBwGVCgNz76QAR13ghAk+2vDDHOi+VX5+usHManxydrpoMGeX66OBPd+y5D3D2MFb+8mYHE7mygg==", "integrity": "sha512-G5EU8nvqAC9fX09sV+UEM9EgR+PjGwguUatOk10uvwvZvCfO+W0FVeLmSap9A6mJ+e8YOH6XFpkwLG0AMuhYrw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@angular-devkit/core": "0.6.8", "@angular-devkit/core": "0.8.1",
"@angular-devkit/schematics": "0.6.8", "@angular-devkit/schematics": "0.8.1",
"npm-registry-client": "^8.5.1", "npm-registry-client": "^8.5.1",
"rxjs": "^6.0.0", "rxjs": "~6.2.0",
"semver": "^5.3.0", "semver": "^5.3.0",
"semver-intersect": "^1.1.2" "semver-intersect": "^1.1.2"
},
"dependencies": {
"@angular-devkit/core": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.1.tgz",
"integrity": "sha512-0TKjF/nHb7+wwWIQ5iuQRzDIF2CphmX9ZojBIGH6PWFgQNKG0yUWqSa+PTpr5eOcGYBOa1rHLf10iyPHDmBdBw==",
"dev": true,
"requires": {
"ajv": "~6.4.0",
"chokidar": "^2.0.3",
"rxjs": "~6.2.0",
"source-map": "^0.5.6"
}
},
"rxjs": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz",
"integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
}
} }
}, },
"@types/jasmine": { "@types/jasmine": {
@ -2068,7 +2173,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
} }
@ -6898,7 +7003,7 @@
}, },
"es6-promise": { "es6-promise": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz",
"integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=",
"dev": true "dev": true
}, },
@ -6910,7 +7015,7 @@
}, },
"readable-stream": { "readable-stream": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
"integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -8335,9 +8440,9 @@
} }
}, },
"npm-registry-client": { "npm-registry-client": {
"version": "8.5.1", "version": "8.6.0",
"resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-8.5.1.tgz", "resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-8.6.0.tgz",
"integrity": "sha512-7rjGF2eA7hKDidGyEWmHTiKfXkbrcQAsGL/Rh4Rt3x3YNRNHhwaTzVJfW3aNvvlhg4G62VCluif0sLCb/i51Hg==", "integrity": "sha512-Qs6P6nnopig+Y8gbzpeN/dkt+n7IyVd8f45NTMotGk6Qo7GfBmzwYx6jRLoOOgKiMnaQfYxsuyQlD8Mc3guBhg==",
"dev": true, "dev": true,
"requires": { "requires": {
"concat-stream": "^1.5.2", "concat-stream": "^1.5.2",
@ -9259,7 +9364,7 @@
}, },
"chalk": { "chalk": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -9272,7 +9377,7 @@
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
}, },
@ -9905,9 +10010,9 @@
} }
}, },
"rxjs": { "rxjs": {
"version": "6.3.2", "version": "6.2.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.2.tgz", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz",
"integrity": "sha512-hV7criqbR0pe7EeL3O66UYVg92IR0XsA97+9y+BWTePK9SKmEI5Qd3Zj6uPnGkNzXsBywBQWTvujPl+1Kn9Zjw==", "integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==",
"requires": { "requires": {
"tslib": "^1.9.0" "tslib": "^1.9.0"
} }
@ -10153,9 +10258,9 @@
} }
}, },
"semver-intersect": { "semver-intersect": {
"version": "1.3.1", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.3.1.tgz", "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz",
"integrity": "sha1-j6hKnhAovSOeRTDRo+GB5pjYhLo=", "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"semver": "^5.0.0" "semver": "^5.0.0"
@ -11470,9 +11575,9 @@
"dev": true "dev": true
}, },
"typescript": { "typescript": {
"version": "2.7.2", "version": "2.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
"integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==", "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
"dev": true "dev": true
}, },
"uglify-js": { "uglify-js": {

View File

@ -34,13 +34,13 @@
"@ngx-translate/http-loader": "^3.0.1", "@ngx-translate/http-loader": "^3.0.1",
"core-js": "^2.5.4", "core-js": "^2.5.4",
"ngx-mat-select-search": "^1.3.1", "ngx-mat-select-search": "^1.3.1",
"rxjs": "^6.3.2", "rxjs": "^6.2.2",
"uuid": "^3.3.2", "uuid": "^3.3.2",
"zone.js": "^0.8.26" "zone.js": "^0.8.26"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.6.8", "@angular-devkit/build-angular": "~0.6.8",
"@angular/cli": "~6.0.8", "@angular/cli": "^6.2.1",
"@angular/compiler-cli": "^6.1.7", "@angular/compiler-cli": "^6.1.7",
"@angular/language-service": "^6.1.7", "@angular/language-service": "^6.1.7",
"@biesbjerg/ngx-translate-extract": "^2.3.4", "@biesbjerg/ngx-translate-extract": "^2.3.4",
@ -63,6 +63,6 @@
"protractor": "^5.4.1", "protractor": "^5.4.1",
"ts-node": "~5.0.1", "ts-node": "~5.0.1",
"tslint": "~5.9.1", "tslint": "~5.9.1",
"typescript": "~2.7.2" "typescript": "~2.9.2"
} }
} }

View File

@ -1,25 +1,17 @@
{ {
"/apps/core/version": { "/apps/": {
"target": "http://localhost:8000", "target": "http://localhost:8000",
"secure": false "secure": false
}, },
"/apps/users/login": { "/media/": {
"target": "http://localhost:8000", "target": "http://localhost:8000",
"secure": false "secure": false
}, },
"/apps/users/logout": { "/rest/": {
"target": "http://localhost:8000", "target": "http://localhost:8000",
"secure": false "secure": false
}, },
"/apps/users/whoami": { "/ws/site/": {
"target": "http://localhost:8000",
"secure": false
},
"/rest": {
"target": "http://localhost:8000",
"secure": false
},
"/ws/site": {
"target": "ws://localhost:8000", "target": "ws://localhost:8000",
"secure": false, "secure": false,
"ws": true "ws": true

View File

@ -34,23 +34,6 @@ export class Item extends ProjectableBaseModel {
super('agenda/item', input); super('agenda/item', input);
} }
// Note: This has to be used in the agenda repository
/*public get contentObject(): AgendaBaseModel {
const contentObject = this.DS.get<BaseModel>(this.content_object.collection, this.content_object.id);
if (!contentObject) {
return null;
}
if (contentObject instanceof AgendaBaseModel) {
return contentObject as AgendaBaseModel;
} else {
throw new Error(
`The content object (${this.content_object.collection}, ${this.content_object.id}) of item ${
this.id
} is not a BaseProjectableModel.`
);
}
}*/
public deserialize(input: any): void { public deserialize(input: any): void {
Object.assign(this, input); Object.assign(this, input);
@ -61,26 +44,11 @@ export class Item extends ProjectableBaseModel {
} }
} }
// The repository has to check for the content object and choose which title to use.
// The code below is belongs to the repository
public getTitle(): string { public getTitle(): string {
/*const contentObject: AgendaBaseModel = this.contentObject;
if (contentObject) {
return contentObject.getAgendaTitle();
} else {
return this.title;
}*/
return this.title; return this.title;
} }
// Same here. See comment for getTitle()
public getListTitle(): string { public getListTitle(): string {
/*const contentObject: AgendaBaseModel = this.contentObject;
if (contentObject) {
return contentObject.getAgendaTitleWithType();
} else {
return this.title_with_type;
}*/
return this.title_with_type; return this.title_with_type;
} }

View File

@ -29,4 +29,4 @@ export class Mediafile extends ProjectableBaseModel {
} }
} }
ProjectableBaseModel.registerCollectionElement('amediafiles/mediafile', Mediafile); ProjectableBaseModel.registerCollectionElement('mediafiles/mediafile', Mediafile);

View File

@ -85,7 +85,7 @@ export class Motion extends AgendaBaseModel {
} }
public getDetailStateURL(): string { public getDetailStateURL(): string {
return 'TODO'; return `/motions/${this.id}`;
} }
public deserialize(input: any): void { public deserialize(input: any): void {

View File

@ -48,6 +48,10 @@ export class User extends ProjectableBaseModel {
return name.trim(); return name.trim();
} }
public containsGroupId(id: number): boolean {
return this.groups_id.some(groupId => groupId === id);
}
// TODO read config values for "users_sort_by" // TODO read config values for "users_sort_by"
public get short_name(): string { public get short_name(): string {
const title = this.title.trim(); const title = this.title.trim();

View File

@ -15,8 +15,7 @@ import {
MatSnackBarModule, MatSnackBarModule,
MatTableModule, MatTableModule,
MatPaginatorModule, MatPaginatorModule,
MatSortModule, MatSortModule
MatTabsModule
} from '@angular/material'; } from '@angular/material';
import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatChipsModule } from '@angular/material'; import { MatChipsModule } from '@angular/material';
@ -79,10 +78,10 @@ library.add(fas);
MatMenuModule, MatMenuModule,
MatDialogModule, MatDialogModule,
MatSnackBarModule, MatSnackBarModule,
MatChipsModule,
FontAwesomeModule, FontAwesomeModule,
TranslateModule.forChild(), TranslateModule.forChild(),
RouterModule, RouterModule,
MatChipsModule,
NgxMatSelectSearchModule NgxMatSelectSearchModule
], ],
exports: [ exports: [
@ -106,7 +105,7 @@ library.add(fas);
MatMenuModule, MatMenuModule,
MatDialogModule, MatDialogModule,
MatSnackBarModule, MatSnackBarModule,
MatTabsModule, MatChipsModule,
NgxMatSelectSearchModule, NgxMatSelectSearchModule,
FontAwesomeModule, FontAwesomeModule,
TranslateModule, TranslateModule,

View File

@ -1,16 +1,18 @@
<os-head-bar appName="Agenda" plusButton=true (plusButtonClicked)=onPlusButton()> <os-head-bar appName="Agenda" plusButton=true (plusButtonClicked)=onPlusButton()></os-head-bar>
</os-head-bar>
<mat-card class="os-card card-plus-distance"> <mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
<div class="app-content"> <!-- title column -->
Agenda Works <ng-container matColumnDef="title">
<br/> <mat-header-cell *matHeaderCellDef mat-sort-header> Topic </mat-header-cell>
<div> <mat-cell *matCellDef="let item"> {{item.getListTitle()}} </mat-cell>
everyone should see this </ng-container>
</div>
<br/> <ng-container matColumnDef="duration">
<div *osPerms="'agenda.can_see'"> <mat-header-cell *matHeaderCellDef mat-sort-header> Duration </mat-header-cell>
Only permitted users should see this <mat-cell *matCellDef="let item"> {{item.duration}} </mat-cell>
</div> </ng-container>
</div>
</mat-card> <mat-header-row *matHeaderRowDef="['title', 'duration']"></mat-header-row>
<mat-row (click)='selectAgendaItem(row)' *matRowDef="let row; columns: ['title', 'duration']"></mat-row>
</mat-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>

View File

@ -1,9 +1,10 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { BaseComponent } from 'app/base.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Item } from '../../../shared/models/agenda/item'; import { ViewItem } from '../models/view-item';
import { Topic } from '../../../shared/models/topics/topic'; import { ListViewBaseComponent } from '../../base/list-view-base';
import { AgendaRepositoryService } from '../services/agenda-repository.service';
import { Router } from '@angular/router';
/** /**
* List view for the agenda. * List view for the agenda.
@ -15,26 +16,43 @@ import { Topic } from '../../../shared/models/topics/topic';
templateUrl: './agenda-list.component.html', templateUrl: './agenda-list.component.html',
styleUrls: ['./agenda-list.component.css'] styleUrls: ['./agenda-list.component.css']
}) })
export class AgendaListComponent extends BaseComponent implements OnInit { export class AgendaListComponent extends ListViewBaseComponent<ViewItem> implements OnInit {
/** /**
* The usual constructor for components * The usual constructor for components
* @param titleService * @param titleService
* @param translate * @param translate
*/ */
public constructor(titleService: Title, protected translate: TranslateService) { public constructor(
titleService: Title,
translate: TranslateService,
private router: Router,
private repo: AgendaRepositoryService
) {
super(titleService, translate); super(titleService, translate);
} }
/** /**
* Init function. * Init function.
* Sets the title * Sets the title, initializes the table and calls the repository.
*/ */
public ngOnInit(): void { public ngOnInit(): void {
super.setTitle('Agenda'); super.setTitle('Agenda');
// tslint:disable-next-line this.initTable();
const i: Item = new Item(); // Needed, that the Item.ts is loaded. Can be removed, if something else creates/uses items. this.repo.getViewModelListObservable().subscribe(newAgendaItem => {
// tslint:disable-next-line this.dataSource.data = newAgendaItem;
const t: Topic = new Topic(); // Needed, that the Topic.ts is loaded. Can be removed, if something else creates/uses topics. });
}
/**
* Handler for click events on agenda item rows
* Links to the content object if any
*/
public selectAgendaItem(item: ViewItem): void {
if (item.contentObject) {
this.router.navigate([item.contentObject.getDetailStateURL()]);
} else {
console.error(`The selected item ${item} has no content object`);
}
} }
/** /**

View File

@ -0,0 +1,54 @@
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 {
private _item: Item;
private _contentObject: AgendaBaseModel;
public get item(): Item {
return this._item;
}
public get contentObject(): AgendaBaseModel {
return this._contentObject;
}
public get id(): number {
return this.item ? this.item.id : null;
}
public get duration(): number {
return this.item ? this.item.duration : null;
}
public constructor(item: Item, contentObject: AgendaBaseModel) {
super();
this._item = item;
this._contentObject = contentObject;
}
public getTitle(): string {
if (this.contentObject) {
return this.contentObject.getAgendaTitle();
} else {
return this.item ? this.item.title : null;
}
}
public getListTitle(): string {
const contentObject: AgendaBaseModel = this.contentObject;
if (contentObject) {
return contentObject.getAgendaTitleWithType();
} else {
return this.item ? this.item.title_with_type : null;
}
}
public updateValues(update: BaseModel): void {
if (update instanceof Item && this.id === update.id) {
this._item = update;
}
}
}

View File

@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { AgendaRepositoryService } from './agenda-repository.service';
describe('AgendaRepositoryService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [AgendaRepositoryService]
});
});
it('should be created', inject([AgendaRepositoryService], (service: AgendaRepositoryService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,79 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { BaseRepository } from '../../base/base-repository';
import { DataStoreService } from '../../../core/services/data-store.service';
import { Item } from '../../../shared/models/agenda/item';
import { ViewItem } from '../models/view-item';
import { AgendaBaseModel } from '../../../shared/models/base/agenda-base-model';
import { BaseModel } from '../../../shared/models/base/base-model';
/**
* Repository service for users
*
* Documentation partially provided in {@link BaseRepository}
*/
@Injectable({
providedIn: 'root'
})
export class AgendaRepositoryService extends BaseRepository<ViewItem, Item> {
public constructor(DS: DataStoreService) {
super(DS, Item);
}
/**
* Returns the corresponding content object to a given {@link Item} as an {@link AgendaBaseModel}
* @param agendaItem
*/
private getContentObject(agendaItem: Item): AgendaBaseModel {
const contentObject = this.DS.get<BaseModel>(
agendaItem.content_object.collection,
agendaItem.content_object.id
);
if (!contentObject) {
return null;
}
if (contentObject instanceof AgendaBaseModel) {
return contentObject as AgendaBaseModel;
} else {
throw new Error(
`The content object (${agendaItem.content_object.collection}, ${
agendaItem.content_object.id
}) of item ${agendaItem.id} is not a BaseProjectableModel.`
);
}
}
/**
* @ignore
*
* TODO: used over not-yet-existing detail view
*/
public save(item: Item, viewUser: ViewItem): Observable<Item> {
return null;
}
/**
* @ignore
*
* TODO: used over not-yet-existing detail view
*/
public delete(item: ViewItem): Observable<Item> {
return null;
}
/**
* @ignore
*
* TODO: used over not-yet-existing detail view
*/
public create(item: Item, viewItem: ViewItem): Observable<Item> {
return null;
}
public createViewModel(item: Item): ViewItem {
const contentObject = this.getContentObject(item);
return new ViewItem(item, contentObject);
}
}

View File

@ -1,21 +1,32 @@
<!-- <mat-toolbar color='primary'> <os-head-bar appName="Assignments" plusButton=true [menuList]=assignmentMenu (plusButtonClicked)=onPlusButton()
(ellipsisMenuItem)=onEllipsisItem($event)>
<button class='generic-plus-button on-transition-fade' mat-fab>
<fa-icon icon='plus'></fa-icon>
</button>
<span class='app-name on-transition-fade' translate>Assignments</span>
<span class='spacer'></span>
<button class='on-transition-fade' mat-icon-button (click)='downloadAssignmentButton()'>
<fa-icon icon='download'></fa-icon>
</button>
</mat-toolbar> -->
<os-head-bar appName="Assignments" plusButton=true [menuList]=assignmentMenu (plusButtonClicked)=onPlusButton() (ellipsisMenuItem)=onEllipsisItem($event)>
</os-head-bar> </os-head-bar>
<mat-card class="os-card card-plus-distance"> <mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
assignment-list works! <!-- name column -->
</mat-card> <ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header> Title </mat-header-cell>
<mat-cell *matCellDef="let assignment"> {{assignment.getTitle()}} </mat-cell>
</ng-container>
<ng-container matColumnDef="phase">
<mat-header-cell *matHeaderCellDef mat-sort-header> Phase </mat-header-cell>
<mat-cell *matCellDef="let assignment">
<mat-chip-list>
<mat-chip color="primary" selected>{{assignment.phase}} </mat-chip>
</mat-chip-list>
</mat-cell>
</ng-container>
<ng-container matColumnDef="candidates">
<mat-header-cell *matHeaderCellDef mat-sort-header> Candidates </mat-header-cell>
<mat-cell *matCellDef="let assignment">
<mat-chip-list>
<mat-chip color="accent" selected>{{assignment.candidateAmount}}</mat-chip>
</mat-chip-list>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['title', 'phase', 'candidates']"></mat-header-row>
<mat-row (click)='selectAssignment(row)' *matRowDef="let row; columns: ['title', 'phase', 'candidates']"></mat-row>
</mat-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>

View File

@ -1,20 +1,20 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { BaseComponent } from '../../../base.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { Assignment } from '../../../shared/models/assignments/assignment'; import { ViewAssignment } from '../models/view-assignment';
import { ListViewBaseComponent } from '../../base/list-view-base';
import { AssignmentRepositoryService } from '../services/assignment-repository.service';
/** /**
* Listview for the assignments * Listview for the assignments
* *
* TODO: not yet implemented
*/ */
@Component({ @Component({
selector: 'os-assignment-list', selector: 'os-assignment-list',
templateUrl: './assignment-list.component.html', templateUrl: './assignment-list.component.html',
styleUrls: ['./assignment-list.component.css'] styleUrls: ['./assignment-list.component.css']
}) })
export class AssignmentListComponent extends BaseComponent implements OnInit { export class AssignmentListComponent extends ListViewBaseComponent<ViewAssignment> implements OnInit {
/** /**
* Define the content of the ellipsis menu. * Define the content of the ellipsis menu.
* Give it to the HeadBar to display them. * Give it to the HeadBar to display them.
@ -29,13 +29,27 @@ export class AssignmentListComponent extends BaseComponent implements OnInit {
/** /**
* Constructor. * Constructor.
*
* @param repo the repository
* @param titleService * @param titleService
* @param translate * @param translate
*/ */
public constructor(titleService: Title, protected translate: TranslateService) { public constructor(private repo: AssignmentRepositoryService, titleService: Title, translate: TranslateService) {
super(titleService, translate); super(titleService, translate);
} }
/**
* Init function.
* Sets the title, inits the table and calls the repo.
*/
public ngOnInit(): void {
super.setTitle('Assignments');
this.initTable();
this.repo.getViewModelListObservable().subscribe(newAssignments => {
this.dataSource.data = newAssignments;
});
}
/** /**
* Click on the plus button delegated from head-bar * Click on the plus button delegated from head-bar
*/ */
@ -44,13 +58,11 @@ export class AssignmentListComponent extends BaseComponent implements OnInit {
} }
/** /**
* Init function. Sets the title. * Select an row in the table
* @param assignment
*/ */
public ngOnInit(): void { public selectAssignment(assignment: ViewAssignment): void {
super.setTitle('Assignments'); console.log('select assignment list: ', assignment);
// tslint:disable-next-line
const a: Assignment = new Assignment(); // Needed, that the Assignment.ts is loaded. Can be removed, if something else creates/uses assignments.
} }
/** /**
@ -60,15 +72,4 @@ export class AssignmentListComponent extends BaseComponent implements OnInit {
public downloadAssignmentButton(): void { public downloadAssignmentButton(): void {
console.log('Hello World'); console.log('Hello World');
} }
/**
* handler function for clicking on items in the ellipsis menu.
*
* @param event clicked entry from ellipsis menu
*/
public onEllipsisItem(event: any): void {
if (event.action) {
this[event.action]();
}
}
} }

View File

@ -0,0 +1,53 @@
import { BaseViewModel } from '../../base/base-view-model';
import { Assignment } from '../../../shared/models/assignments/assignment';
import { Tag } from '../../../shared/models/core/tag';
import { User } from '../../../shared/models/users/user';
import { Item } from '../../../shared/models/agenda/item';
export class ViewAssignment extends BaseViewModel {
private _assignment: Assignment;
private _relatedUser: User[];
private _agendaItem: Item;
private _tags: Tag[];
public get assignment(): Assignment {
return this._assignment;
}
public get candidates(): User[] {
return this._relatedUser;
}
public get agendaItem(): Item {
return this._agendaItem;
}
public get tags(): Tag[] {
return this._tags;
}
/**
* unknown where the identifier to the phase is get
*/
public get phase(): number {
return this.assignment ? this.assignment.phase : null;
}
public get candidateAmount(): number {
return this.candidates ? this.candidates.length : 0;
}
public constructor(assignment: Assignment, relatedUser: User[], agendaItem?: Item, tags?: Tag[]) {
super();
this._assignment = assignment;
this._relatedUser = relatedUser;
this._agendaItem = agendaItem;
this._tags = tags;
}
public updateValues(): void {}
public getTitle(): string {
return this.assignment ? this.assignment.title : null;
}
}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { AssignmentRepositoryService } from './assignment-repository.service';
describe('AssignmentRepositoryService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: AssignmentRepositoryService = TestBed.get(AssignmentRepositoryService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,47 @@
import { Injectable } from '@angular/core';
import { ViewAssignment } from '../models/view-assignment';
import { Assignment } from '../../../shared/models/assignments/assignment';
import { User } from '../../../shared/models/users/user';
import { Tag } from '../../../shared/models/core/tag';
import { Item } from '../../../shared/models/agenda/item';
import { Observable } from 'rxjs';
import { BaseRepository } from '../../base/base-repository';
import { DataStoreService } from '../../../core/services/data-store.service';
/**
* Repository Service for Assignments.
*
* Documentation partially provided in {@link BaseRepository}
*/
@Injectable({
providedIn: 'root'
})
export class AssignmentRepositoryService extends BaseRepository<ViewAssignment, Assignment> {
/**
* Constructor for the Assignment Repository.
*
*/
public constructor(DS: DataStoreService) {
super(DS, Assignment, [User, Item, Tag]);
}
public save(assignment: Assignment, viewAssignment: ViewAssignment): Observable<Assignment> {
return null;
}
public delete(viewAssignment: ViewAssignment): Observable<Assignment> {
return null;
}
public create(assignment: Assignment, viewAssignment: ViewAssignment): Observable<Assignment> {
return null;
}
public createViewModel(assignment: Assignment): ViewAssignment {
const relatedUser = this.DS.getMany(User, assignment.candidateIds);
const agendaItem = this.DS.get(Item, assignment.agenda_item_id);
const tags = this.DS.getMany(Tag, assignment.tags_id);
return new ViewAssignment(assignment, relatedUser, agendaItem, tags);
}
}

View File

@ -1,9 +1,9 @@
import { OpenSlidesComponent } from '../openslides.component'; import { OpenSlidesComponent } from '../../openslides.component';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { BaseViewModel } from './base-view-model'; import { BaseViewModel } from './base-view-model';
import { BaseModel, ModelConstructor } from '../shared/models/base/base-model'; import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
import { CollectionStringModelMapperService } from '../core/services/collectionStringModelMapper.service'; import { CollectionStringModelMapperService } from '../../core/services/collectionStringModelMapper.service';
import { DataStoreService } from '../core/services/data-store.service'; import { DataStoreService } from '../../core/services/data-store.service';
export abstract class BaseRepository<V extends BaseViewModel, M extends BaseModel> extends OpenSlidesComponent { export abstract class BaseRepository<V extends BaseViewModel, M extends BaseModel> extends OpenSlidesComponent {
/** /**
@ -30,7 +30,7 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
public constructor( public constructor(
protected DS: DataStoreService, protected DS: DataStoreService,
protected baseModelCtor: ModelConstructor<M>, protected baseModelCtor: ModelConstructor<M>,
protected depsModelCtors: ModelConstructor<BaseModel>[] protected depsModelCtors?: ModelConstructor<BaseModel>[]
) { ) {
super(); super();
@ -47,7 +47,7 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
// Add new and updated motions to the viewModelStore // Add new and updated motions to the viewModelStore
this.viewModelStore[model.id] = this.createViewModel(model as M); this.viewModelStore[model.id] = this.createViewModel(model as M);
this.updateAllObservables(model.id); this.updateAllObservables(model.id);
} else { } else if (this.depsModelCtors) {
const dependencyChanged: boolean = this.depsModelCtors.some(ctor => { const dependencyChanged: boolean = this.depsModelCtors.some(ctor => {
return model instanceof ctor; return model instanceof ctor;
}); });
@ -92,6 +92,13 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
*/ */
public abstract create(update: M, viewModel: V): Observable<M>; public abstract create(update: M, viewModel: V): Observable<M>;
/**
* Creates a view model out of a base model.
*
* Should read all necessary objects from the datastore
* that the viewmodel needs
* @param model
*/
protected abstract createViewModel(model: M): V; protected abstract createViewModel(model: M): V;
/** /**

View File

@ -1,5 +1,5 @@
import { BaseModel } from '../shared/models/base/base-model'; import { BaseModel } from '../../shared/models/base/base-model';
import { Displayable } from '../shared/models/base/displayable'; import { Displayable } from '../../shared/models/base/displayable';
/** /**
* Base class for view models. alls view models should have titles. * Base class for view models. alls view models should have titles.

View File

@ -0,0 +1,63 @@
import { ViewChild } from '@angular/core';
import { BaseComponent } from '../../base.component';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { MatTableDataSource, MatTable, MatSort, MatPaginator } from '@angular/material';
import { BaseViewModel } from './base-view-model';
export abstract class ListViewBaseComponent<V extends BaseViewModel> extends BaseComponent {
/**
* The data source for a table. Requires to be initialised with a BaseViewModel
*/
public dataSource: MatTableDataSource<V>;
/**
* The table itself
*/
@ViewChild(MatTable)
protected table: MatTable<V>;
/**
* Table paginator
*/
@ViewChild(MatPaginator)
protected paginator: MatPaginator;
/**
* Sorter for a table
*/
@ViewChild(MatSort)
protected sort: MatSort;
/**
* Constructor for list view bases
* @param titleService the title serivce
* @param translate the translate service
*/
public constructor(titleService: Title, translate: TranslateService) {
super(titleService, translate);
}
/**
* Children need to call this in their init-function.
* Calling these three functions in the constructor of this class
* would be too early, resulting in non-paginated tables
*/
public initTable(): void {
this.dataSource = new MatTableDataSource();
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
/**
* handler function for clicking on items in the ellipsis menu.
* Ellipsis menu comes from the HeadBarComponent is is implemented by most ListViews
*
* @param event clicked entry from ellipsis menu
*/
public onEllipsisItem(event: any): void {
if (event.action) {
this[event.action]();
}
}
}

View File

@ -2,6 +2,32 @@
</os-head-bar> </os-head-bar>
<mat-card class="os-card card-plus-distance"> <mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
mediafile-list works! <!-- name column -->
</mat-card> <ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
<mat-cell (click)='selectFile(file)' *matCellDef="let file"> {{file.title}} </mat-cell>
</ng-container>
<!-- prefix column -->
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef mat-sort-header> Group </mat-header-cell>
<mat-cell (click)='selectFile(file)' *matCellDef="let file">
{{file.type}}
<br>
{{file.size}}
</mat-cell>
</ng-container>
<!-- prefix column -->
<ng-container matColumnDef="download">
<mat-header-cell *matHeaderCellDef mat-sort-header> Download </mat-header-cell>
<mat-cell (click)="download(file)" *matCellDef="let file">
<fa-icon icon='download'></fa-icon>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['title', 'info', 'download']"></mat-header-row>
<mat-row *matRowDef="let row; columns: ['title', 'info', 'download']"></mat-row>
</mat-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>

View File

@ -3,19 +3,20 @@ import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { BaseComponent } from '../../../base.component'; import { ViewMediafile } from '../models/view-mediafile';
import { MediafileRepositoryService } from '../services/mediafile-repository.service';
import { ListViewBaseComponent } from '../../base/list-view-base';
/** /**
* Lists all the uploaded mediafiles. * Lists all the uploaded files.
* *
* Not yet implemented
*/ */
@Component({ @Component({
selector: 'os-mediafile-list', selector: 'os-mediafile-list',
templateUrl: './mediafile-list.component.html', templateUrl: './mediafile-list.component.html',
styleUrls: ['./mediafile-list.component.css'] styleUrls: ['./mediafile-list.component.css']
}) })
export class MediafileListComponent extends BaseComponent implements OnInit { export class MediafileListComponent extends ListViewBaseComponent<ViewMediafile> implements OnInit {
/** /**
* Define the content of the ellipsis menu. * Define the content of the ellipsis menu.
* Give it to the HeadBar to display them. * Give it to the HeadBar to display them.
@ -31,10 +32,15 @@ export class MediafileListComponent extends BaseComponent implements OnInit {
/** /**
* Constructor * Constructor
* *
* @param repo the repository for files
* @param titleService * @param titleService
* @param translate * @param translate
*/ */
public constructor(titleService: Title, protected translate: TranslateService) { public constructor(
private repo: MediafileRepositoryService,
protected titleService: Title,
protected translate: TranslateService
) {
super(titleService, translate); super(titleService, translate);
} }
@ -44,6 +50,10 @@ export class MediafileListComponent extends BaseComponent implements OnInit {
*/ */
public ngOnInit(): void { public ngOnInit(): void {
super.setTitle('Files'); super.setTitle('Files');
this.initTable();
this.repo.getViewModelListObservable().subscribe(newUsers => {
this.dataSource.data = newUsers;
});
} }
/** /**
@ -64,13 +74,18 @@ export class MediafileListComponent extends BaseComponent implements OnInit {
} }
/** /**
* handler function for clicking on items in the ellipsis menu. * Clicking on a list row
* * @param file the selected file
* @param event clicked entry from ellipsis menu
*/ */
public onEllipsisItem(event: any): void { public selectFile(file: ViewMediafile): void {
if (event.action) { console.log('The file: ', file);
this[event.action]();
} }
/**
* Directly download a mediafile using the download button on the table
* @param file
*/
public download(file: ViewMediafile): void {
window.open(file.downloadUrl);
} }
} }

View File

@ -0,0 +1,59 @@
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 mediafile(): Mediafile {
return this._mediafile;
}
public get uploader(): User {
return this._uploader;
}
public get title(): string {
return this.mediafile ? this.mediafile.title : null;
}
public get size(): string {
return this.mediafile ? this.mediafile.filesize : null;
}
public get type(): string {
return this.mediafile && this.mediafile.mediafile ? this.mediafile.mediafile.type : null;
}
public get prefix(): string {
return this.mediafile ? this.mediafile.media_url_prefix : null;
}
public get fileName(): string {
return this.mediafile && this.mediafile.mediafile ? this.mediafile.mediafile.name : null;
}
public get downloadUrl(): string {
return this.mediafile && this.mediafile.mediafile ? `${this.prefix}${this.fileName}` : null;
}
public constructor(mediafile?: Mediafile, uploader?: User) {
super();
this._mediafile = mediafile;
this._uploader = uploader;
}
public getTitle(): string {
return this.title;
}
public updateValues(update: BaseModel): void {
if (update instanceof Mediafile) {
if (this.mediafile.id === update.id) {
this._mediafile = update;
}
}
}
}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { MediafileRepositoryService } from './mediafile-repository.service';
describe('FileRepositoryService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: MediafileRepositoryService = TestBed.get(MediafileRepositoryService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,56 @@
import { Injectable } from '@angular/core';
import { BaseRepository } from '../../base/base-repository';
import { ViewMediafile } from '../models/view-mediafile';
import { Mediafile } from '../../../shared/models/mediafiles/mediafile';
import { User } from '../../../shared/models/users/user';
import { Observable } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service';
/**
* Repository for files
*/
@Injectable({
providedIn: 'root'
})
export class MediafileRepositoryService extends BaseRepository<ViewMediafile, Mediafile> {
/**
* Consturctor for the file repo
* @param DS the DataStore
*/
public constructor(DS: DataStoreService) {
super(DS, Mediafile, [User]);
}
/**
* Saves a config value.
*
* TODO: used over not-yet-existing detail view
*/
public save(file: Mediafile, viewFile: ViewMediafile): Observable<Mediafile> {
return null;
}
/**
* Saves a config value.
*
* TODO: used over not-yet-existing detail view
*/
public delete(file: ViewMediafile): Observable<Mediafile> {
return null;
}
/**
* Saves a config value.
*
* TODO: used over not-yet-existing detail view
*/
public create(file: Mediafile, viewFile: ViewMediafile): Observable<Mediafile> {
return null;
}
public createViewModel(file: Mediafile): ViewMediafile {
const uploader = this.DS.get(User, file.uploader_id);
return new ViewMediafile(file, uploader);
}
}

View File

@ -1,4 +1,5 @@
<os-head-bar appName="Motions" plusButton=true (plusButtonClicked)=onPlusButton() [menuList]=motionMenuList (ellipsisMenuItem)=onEllipsisItem($event)> <os-head-bar appName="Motions" plusButton=true (plusButtonClicked)=onPlusButton() [menuList]=motionMenuList
(ellipsisMenuItem)=onEllipsisItem($event)>
</os-head-bar> </os-head-bar>
<div class='custom-table-header on-transition-fade'> <div class='custom-table-header on-transition-fade'>
@ -10,7 +11,7 @@
</button> </button>
</div> </div>
<mat-table class='on-transition-fade' [dataSource]="dataSource" matSort> <mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
<!-- identifier column --> <!-- identifier column -->
<ng-container matColumnDef="identifier"> <ng-container matColumnDef="identifier">
<mat-header-cell *matHeaderCellDef mat-sort-header> Identifier </mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header> Identifier </mat-header-cell>

View File

@ -15,24 +15,7 @@
line-height: normal; line-height: normal;
} }
mat-table { .os-listview-table {
width: 100%;
/** hide mat header row */
.mat-header-row {
display: none;
}
/** size of the mat row */
mat-row {
height: 60px;
}
mat-row:hover {
cursor: pointer;
background-color: rgba(0, 0, 0, 0.025);
}
/** identifier */ /** identifier */
.mat-column-identifier { .mat-column-identifier {
padding-left: 10px; padding-left: 10px;

View File

@ -1,14 +1,13 @@
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router'; import { Router, ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { MatTable, MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { BaseComponent } from '../../../../base.component';
import { MotionRepositoryService } from '../../services/motion-repository.service'; import { MotionRepositoryService } from '../../services/motion-repository.service';
import { ViewMotion } from '../../models/view-motion'; import { ViewMotion } from '../../models/view-motion';
import { WorkflowState } from '../../../../shared/models/motions/workflow-state'; import { WorkflowState } from '../../../../shared/models/motions/workflow-state';
import { ListViewBaseComponent } from '../../../base/list-view-base';
/** /**
* Component that displays all the motions in a Table using DataSource. * Component that displays all the motions in a Table using DataSource.
@ -18,29 +17,7 @@ import { WorkflowState } from '../../../../shared/models/motions/workflow-state'
templateUrl: './motion-list.component.html', templateUrl: './motion-list.component.html',
styleUrls: ['./motion-list.component.scss'] styleUrls: ['./motion-list.component.scss']
}) })
export class MotionListComponent extends BaseComponent implements OnInit { export class MotionListComponent extends ListViewBaseComponent<ViewMotion> implements OnInit {
/**
* Will be processed by the mat-table
*
* Will represent the object that comes from the repository
*/
public dataSource: MatTableDataSource<ViewMotion>;
/**
* The table itself.
*/
@ViewChild(MatTable) public table: MatTable<ViewMotion>;
/**
* Pagination. Might be turned off to all motions at once.
*/
@ViewChild(MatPaginator) public paginator: MatPaginator;
/**
* Sort the Table
*/
@ViewChild(MatSort) public sort: MatSort;
/** /**
* Use for minimal width * Use for minimal width
*/ */
@ -78,8 +55,8 @@ export class MotionListComponent extends BaseComponent implements OnInit {
* @param repo Motion Repository * @param repo Motion Repository
*/ */
public constructor( public constructor(
protected titleService: Title, titleService: Title,
protected translate: TranslateService, translate: TranslateService,
private router: Router, private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private repo: MotionRepositoryService private repo: MotionRepositoryService
@ -88,15 +65,13 @@ export class MotionListComponent extends BaseComponent implements OnInit {
} }
/** /**
* Init function * Init function.
*
* Sets the title, inits the table and calls the repository
*/ */
public ngOnInit(): void { public ngOnInit(): void {
super.setTitle('Motions'); super.setTitle('Motions');
this.initTable();
this.dataSource = new MatTableDataSource();
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.repo.getViewModelListObservable().subscribe(newMotions => { this.repo.getViewModelListObservable().subscribe(newMotions => {
this.dataSource.data = newMotions; this.dataSource.data = newMotions;
}); });
@ -163,15 +138,4 @@ export class MotionListComponent extends BaseComponent implements OnInit {
public downloadMotions(): void { public downloadMotions(): void {
console.log('Download Motions Button'); console.log('Download Motions Button');
} }
/**
* handler function for clicking on items in the ellipsis menu.
*
* @param event clicked entry from ellipsis menu
*/
public onEllipsisItem(event: any): void {
if (event.action) {
this[event.action]();
}
}
} }

View File

@ -4,7 +4,7 @@ import { User } from '../../../shared/models/users/user';
import { Workflow } from '../../../shared/models/motions/workflow'; import { Workflow } from '../../../shared/models/motions/workflow';
import { WorkflowState } from '../../../shared/models/motions/workflow-state'; import { WorkflowState } from '../../../shared/models/motions/workflow-state';
import { BaseModel } from '../../../shared/models/base/base-model'; import { BaseModel } from '../../../shared/models/base/base-model';
import { BaseViewModel } from '../../base-view-model'; import { BaseViewModel } from '../../base/base-view-model';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
/** /**
@ -27,43 +27,23 @@ export class ViewMotion extends BaseViewModel {
} }
public get id(): number { public get id(): number {
if (this.motion) { return this.motion ? this.motion.id : null;
return this.motion.id;
} else {
return null;
}
} }
public get identifier(): string { public get identifier(): string {
if (this.motion) { return this.motion ? this.motion.identifier : null;
return this.motion.identifier;
} else {
return null;
}
} }
public get title(): string { public get title(): string {
if (this.motion) { return this.motion ? this.motion.title : null;
return this.motion.title;
} else {
return null;
}
} }
public get text(): string { public get text(): string {
if (this.motion) { return this.motion ? this.motion.text : null;
return this.motion.text;
} else {
return null;
}
} }
public get reason(): string { public get reason(): string {
if (this.motion) { return this.motion ? this.motion.reason : null;
return this.motion.reason;
} else {
return null;
}
} }
public get category(): Category { public get category(): Category {
@ -71,11 +51,7 @@ export class ViewMotion extends BaseViewModel {
} }
public get categoryId(): number { public get categoryId(): number {
if (this._motion && this._motion.category_id) { return this.motion && this.category ? this.motion.category_id : null;
return this._motion.category_id;
} else {
return null;
}
} }
public get submitters(): User[] { public get submitters(): User[] {
@ -95,15 +71,11 @@ export class ViewMotion extends BaseViewModel {
} }
public get stateId(): number { public get stateId(): number {
if (this._motion && this._motion.state_id) { return this.motion && this.motion.state_id ? this.motion.state_id : null;
return this._motion.state_id;
} else {
return null;
}
} }
public get recommendationId(): number { public get recommendationId(): number {
return this._motion.recommendation_id; return this.motion && this.motion.recommendation_id ? this.motion.recommendation_id : null;
} }
/** /**
@ -118,27 +90,15 @@ export class ViewMotion extends BaseViewModel {
} }
public get recommendation(): WorkflowState { public get recommendation(): WorkflowState {
if (this.recommendationId && this.workflow) { return this.recommendationId && this.workflow ? this.workflow.getStateById(this.recommendationId) : null;
return this.workflow.getStateById(this.recommendationId);
} else {
return null;
}
} }
public get origin(): string { public get origin(): string {
if (this.motion) { return this.motion ? this.motion.origin : null;
return this.motion.origin;
} else {
return null;
}
} }
public get nextStates(): WorkflowState[] { public get nextStates(): WorkflowState[] {
if (this.state && this.workflow) { return this.state && this.workflow ? this.state.getNextStates(this.workflow) : null;
return this.state.getNextStates(this.workflow);
} else {
return null;
}
} }
public constructor( public constructor(

View File

@ -8,7 +8,7 @@ import { Workflow } from '../../../shared/models/motions/workflow';
import { WorkflowState } from '../../../shared/models/motions/workflow-state'; import { WorkflowState } from '../../../shared/models/motions/workflow-state';
import { ViewMotion } from '../models/view-motion'; import { ViewMotion } from '../models/view-motion';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { BaseRepository } from '../../base-repository'; import { BaseRepository } from '../../base/base-repository';
import { DataStoreService } from '../../../core/services/data-store.service'; import { DataStoreService } from '../../../core/services/data-store.service';
/** /**

View File

@ -0,0 +1,38 @@
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 {
private _config: Config;
public get config(): Config {
return this._config;
}
public get id(): number {
return this.config ? this.config.id : null;
}
public get key(): string {
return this.config ? this.config.key : null;
}
public get value(): Object {
return this.config ? this.config.value : null;
}
public constructor(config: Config) {
super();
this._config = config;
}
public getTitle(): string {
return this.key;
}
public updateValues(update: BaseModel): void {
if (update instanceof Config && this.id === update.id) {
this._config = update;
}
}
}

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { ConfigRepositoryService } from './config-repository.service';
describe('SettingsRepositoryService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: ConfigRepositoryService = TestBed.get(ConfigRepositoryService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,61 @@
import { Injectable } from '@angular/core';
import { BaseRepository } from '../../base/base-repository';
import { ViewConfig } from '../models/view-config';
import { Config } from '../../../shared/models/core/config';
import { Observable } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service';
/**
* Repository for Configs.
*
* Documentation provided over {@link BaseRepository}
*/
@Injectable({
providedIn: 'root'
})
export class ConfigRepositoryService extends BaseRepository<ViewConfig, Config> {
/**
* Constructor for ConfigRepositoryService
*/
public constructor(DS: DataStoreService) {
super(DS, Config);
}
/**
* Saves a config value.
*
* TODO: used over not-yet-existing detail view
*/
public save(config: Config, viewConfig: ViewConfig): Observable<Config> {
return null;
}
/**
* This particular function should never be necessary since the creation of config
* values is not planed.
*
* Function exists solely to correctly implement {@link BaseRepository}
*/
public delete(config: ViewConfig): Observable<Config> {
return null;
}
/**
* This particular function should never be necessary since the creation of config
* values is not planed.
*
* Function exists solely to correctly implement {@link BaseRepository}
*/
public create(config: Config, viewConfig: ViewConfig): Observable<Config> {
return null;
}
/**
* Creates a new ViewConfig of a given Config object
* @param config
*/
public createViewModel(config: Config): ViewConfig {
return new ViewConfig(config);
}
}

View File

@ -1,20 +1,19 @@
<os-head-bar appName="Settings"> <os-head-bar appName="Settings"></os-head-bar>
</os-head-bar>
<mat-card class="os-card">
<div *osPerms="'core.can_manage_config'" class="app-content">
<mat-accordion> <mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
<mat-expansion-panel> <!-- name column -->
<mat-expansion-panel-header> <ng-container matColumnDef="key">
<mat-panel-title> <mat-header-cell *matHeaderCellDef mat-sort-header> Key </mat-header-cell>
Title <mat-cell *matCellDef="let config"> {{config.key}} </mat-cell>
</mat-panel-title> </ng-container>
</mat-expansion-panel-header>
<p> CONTENT </p> <!-- prefix column -->
</mat-expansion-panel> <ng-container matColumnDef="value">
</mat-accordion> <mat-header-cell *matHeaderCellDef mat-sort-header> Value </mat-header-cell>
<mat-cell *matCellDef="let config"> {{config.value}}</mat-cell>
</ng-container>
</div> <mat-header-row *matHeaderRowDef="['key', 'value']"></mat-header-row>
</mat-card> <mat-row (click)='selectConfig(row)' *matRowDef="let row; columns: ['key', 'value']"></mat-row>
</mat-table>

View File

@ -1,41 +1,61 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { BaseComponent } from '../../../base.component';
import { ConstantsService } from '../../../core/services/constants.service'; import { ConstantsService } from '../../../core/services/constants.service';
import { ListViewBaseComponent } from '../../base/list-view-base';
import { ConfigRepositoryService } from '../services/config-repository.service';
import { ViewConfig } from '../models/view-config';
/** /**
* List view for the global settings * List view for the global settings
* *
* TODO: Not yet implemented
*/ */
@Component({ @Component({
selector: 'os-settings-list', selector: 'os-settings-list',
templateUrl: './settings-list.component.html', templateUrl: './settings-list.component.html',
styleUrls: ['./settings-list.component.css'] styleUrls: ['./settings-list.component.css']
}) })
export class SettingsListComponent extends BaseComponent implements OnInit { export class SettingsListComponent extends ListViewBaseComponent<ViewConfig> implements OnInit {
/** /**
* The usual component constructor * The usual component constructor
* @param titleService * @param titleService
* @param translate * @param translate
*/ */
public constructor( public constructor(
titleService: Title, protected titleService: Title,
protected translate: TranslateService, protected translate: TranslateService,
private constantsService: ConstantsService private repo: ConfigRepositoryService,
private constantsService: ConstantsService,
) { ) {
super(titleService, translate); super(titleService, translate);
} }
/** /**
* Init function. Sets the title * Init function.
*
* Sets the title, inits the table and calls the repo
*
* TODO: Needs the constants to be working
*/ */
public ngOnInit(): void { public ngOnInit(): void {
super.setTitle('Settings'); super.setTitle('Settings');
this.initTable();
this.constantsService.get('OpenSlidesConfigVariables').subscribe(data => { this.constantsService.get('OpenSlidesConfigVariables').subscribe(data => {
console.log(data); console.log(data);
}); });
this.repo.getViewModelListObservable().subscribe(newConfig => {
this.dataSource.data = newConfig;
});
}
/**
* Triggers when user selects a row
* @param row
*
* TODO: This prints the clicked item in the log.
* Needs the constants to be working
*/
public selectConfig(row: ViewConfig): void {
console.log('change a config: ', row.value);
} }
} }

View File

@ -0,0 +1,68 @@
import { BaseViewModel } from '../../base/base-view-model';
import { User } from '../../../shared/models/users/user';
import { Group } from '../../../shared/models/users/group';
import { BaseModel } from '../../../shared/models/base/base-model';
export class ViewUser extends BaseViewModel {
private _user: User;
private _groups: Group[];
public get user(): User {
return this._user;
}
public get groups(): Group[] {
return this._groups;
}
public get fullName(): string {
return this.user ? this.user.full_name : null;
}
/**
* TODO: Make boolean, use function over view component.
*/
public get isActive(): string {
return this.user && this.user.is_active ? 'active' : 'inactive';
}
public get structureLevel(): string {
return this.user ? this.user.structure_level : null;
}
public constructor(user?: User, groups?: Group[]) {
super();
this._user = user;
this._groups = groups;
}
public getTitle(): string {
return this.user ? this.user.toString() : null;
}
/**
* TODO: Implement
*/
public replaceGroup(newGroup: Group): void {
console.log('replace group - not yet implemented, ', newGroup);
}
/**
* 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);
}
}
}
}
}

View File

@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { UserRepositoryService } from './user-repository.service';
describe('UserRepositoryService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [UserRepositoryService]
});
});
it('should be created', inject([UserRepositoryService], (service: UserRepositoryService) => {
expect(service).toBeTruthy();
}));
});

View File

@ -0,0 +1,57 @@
import { Injectable } from '@angular/core';
import { BaseRepository } from '../../base/base-repository';
import { ViewUser } from '../models/view-user';
import { User } from '../../../shared/models/users/user';
import { Group } from '../../../shared/models/users/group';
import { Observable } from 'rxjs';
import { DataStoreService } from '../../../core/services/data-store.service';
/**
* Repository service for users
*
* Documentation partially provided in {@link BaseRepository}
*/
@Injectable({
providedIn: 'root'
})
export class UserRepositoryService extends BaseRepository<ViewUser, User> {
/**
* Constructor calls the parent constructor
*/
public constructor(DS: DataStoreService) {
super(DS, User, [Group]);
}
/**
* @ignore
*
* TODO: used over not-yet-existing detail view
*/
public save(user: User, viewUser: ViewUser): Observable<User> {
return null;
}
/**
* @ignore
*
* TODO: used over not-yet-existing detail view
*/
public delete(user: ViewUser): Observable<User> {
return null;
}
/**
* @ignore
*
* TODO: used over not-yet-existing detail view
*/
public create(user: User, viewFile: ViewUser): Observable<User> {
return null;
}
public createViewModel(user: User): ViewUser {
const groups = this.DS.getMany(Group, user.groups_id);
return new ViewUser(user, groups);
}
}

View File

@ -1,6 +1,27 @@
<os-head-bar appName="Users"> <os-head-bar appName="Users" plusButton=true (plusButtonClicked)=onPlusButton() [menuList]=userMenuList
(ellipsisMenuItem)=onEllipsisItem($event)>
</os-head-bar> </os-head-bar>
<mat-card class="os-card"> <mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
UserList Works! <!-- name column -->
</mat-card> <ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.fullName}} </mat-cell>
</ng-container>
<!-- prefix column -->
<ng-container matColumnDef="group">
<mat-header-cell *matHeaderCellDef mat-sort-header> Group </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.groups}} {{user.structureLevel}} </mat-cell>
</ng-container>
<ng-container matColumnDef="presence">
<mat-header-cell *matHeaderCellDef mat-sort-header> Presence </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.isActive}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['name', 'group', 'presence']"></mat-header-row>
<mat-row (click)='selectUser(row)' *matRowDef="let row; columns: ['name', 'group', 'presence']"></mat-row>
</mat-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>

View File

@ -1,32 +1,98 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { BaseComponent } from '../../../base.component';
import { ViewUser } from '../models/view-user';
import { UserRepositoryService } from '../services/user-repository.service';
import { ListViewBaseComponent } from '../../base/list-view-base';
/** /**
* Component for the user list view. * Component for the user list view.
* *
* TODO: Not yet implemented
*/ */
@Component({ @Component({
selector: 'os-user-list', selector: 'os-user-list',
templateUrl: './user-list.component.html', templateUrl: './user-list.component.html',
styleUrls: ['./user-list.component.css'] styleUrls: ['./user-list.component.css']
}) })
export class UserListComponent extends BaseComponent implements OnInit { export class UserListComponent extends ListViewBaseComponent<ViewUser> implements OnInit {
/**
* content of the ellipsis menu
*/
public userMenuList = [
{
text: 'Groups',
icon: 'users',
action: 'toGroups'
},
{
text: 'Import',
icon: 'download',
action: 'toGroups'
},
{
text: 'Export',
icon: 'file-export',
action: 'toGroups'
}
];
/** /**
* The usual constructor for components * The usual constructor for components
* @param repo the user repository
* @param titleService * @param titleService
* @param translate * @param translate
*/ */
public constructor(titleService: Title, protected translate: TranslateService) { public constructor(
private repo: UserRepositoryService,
protected titleService: Title,
protected translate: TranslateService
) {
super(titleService, translate); super(titleService, translate);
} }
/** /**
* Init function, sets the title * Init function
*
* sets the title, inits the table and calls the repo
*/ */
public ngOnInit(): void { public ngOnInit(): void {
super.setTitle('Users'); super.setTitle('Users');
this.initTable();
this.repo.getViewModelListObservable().subscribe(newUsers => {
this.dataSource.data = newUsers;
});
}
/**
* Navigate to import page or do it inline
*
* TODO: implement importing of users
*/
public import(): void {
console.log('click on Import');
}
/**
* Navigate to groups page
* TODO: implement
*/
public toGroups(): void {
console.log('to Groups');
}
/**
* Handles the click on a user row
* @param row selected row
*/
public selectUser(row: ViewUser): void {
console.log('clicked the row for user: ', row);
}
/**
* Handles the click on the plus button
*/
public onPlusButton(): void {
console.log('new User');
} }
} }

View File

@ -39,6 +39,25 @@ body {
margin-right: auto; margin-right: auto;
} }
.os-listview-table {
width: 100%;
/** hide mat header row */
.mat-header-row {
display: none;
}
/** size of the mat row */
mat-row {
height: 60px;
}
mat-row:hover {
cursor: pointer;
background-color: rgba(0, 0, 0, 0.025);
}
}
.card-plus-distance { .card-plus-distance {
margin-top: 40px; margin-top: 40px;
} }