Create more list views
Also: - Update dependencies - Clean up proxy file
This commit is contained in:
parent
582c2603a6
commit
80cfeaac35
203
client/package-lock.json
generated
203
client/package-lock.json
generated
@ -106,13 +106,36 @@
|
||||
}
|
||||
},
|
||||
"@angular-devkit/schematics": {
|
||||
"version": "0.6.8",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.6.8.tgz",
|
||||
"integrity": "sha512-R4YqAUdo62wtrhX/5HSRGSKXNTWqfQb66ZE6m8jj6GEJNFKdNXMdxOchxr07LCiKTxfh1w6G3nGzxIsu/+D4KA==",
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.8.1.tgz",
|
||||
"integrity": "sha512-ab3xeyTpPA9JO7oXgdfbQ/+5djddvoKjFaxFFcLD5GxgDDnvJcmhgDkluJY9JZHH2oSFaW8u1G5zg8uo1HrriA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@angular-devkit/core": "0.6.8",
|
||||
"rxjs": "^6.0.0"
|
||||
"@angular-devkit/core": "0.8.1",
|
||||
"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": {
|
||||
@ -132,35 +155,71 @@
|
||||
}
|
||||
},
|
||||
"@angular/cli": {
|
||||
"version": "6.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.0.8.tgz",
|
||||
"integrity": "sha512-DhH1Zq5Yonthw6zh6W07fhf+9XrAZbD1fcQ0MrmbxlieCfLlTAdBqyK2LavFCKwSZkUMLF6UHM3+jiNRVZSSIg==",
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.2.1.tgz",
|
||||
"integrity": "sha512-4AO014PohYc/vbNaO6nPi/a6JqxdOHN2m0WLutgRGoBQswqSGn7aLEG1erZKRzbfq39E1a/efnNmEI3Okl3h1Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@angular-devkit/architect": "0.6.8",
|
||||
"@angular-devkit/core": "0.6.8",
|
||||
"@angular-devkit/schematics": "0.6.8",
|
||||
"@schematics/angular": "0.6.8",
|
||||
"@schematics/update": "0.6.8",
|
||||
"opn": "~5.3.0",
|
||||
"resolve": "^1.1.7",
|
||||
"rxjs": "^6.0.0",
|
||||
"@angular-devkit/architect": "0.8.1",
|
||||
"@angular-devkit/core": "0.8.1",
|
||||
"@angular-devkit/schematics": "0.8.1",
|
||||
"@schematics/angular": "0.8.1",
|
||||
"@schematics/update": "0.8.1",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"opn": "^5.3.0",
|
||||
"rxjs": "~6.2.0",
|
||||
"semver": "^5.1.0",
|
||||
"silent-error": "^1.0.0",
|
||||
"symbol-observable": "^1.2.0",
|
||||
"yargs-parser": "^10.0.0"
|
||||
},
|
||||
"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": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
|
||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
|
||||
"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": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.0.0.tgz",
|
||||
"integrity": "sha512-+DHejWujTVYeMHLff8U96rLc4uE4Emncoftvn5AjhB1Jw1pWxLzgBUT/WYbPrHmy6YPEBTZQx5myHhVcuuu64g==",
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
|
||||
"integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^4.1.0"
|
||||
@ -1065,28 +1124,74 @@
|
||||
"dev": true
|
||||
},
|
||||
"@schematics/angular": {
|
||||
"version": "0.6.8",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.6.8.tgz",
|
||||
"integrity": "sha512-9kRphqTYG5Df/I8fvnT1zMsw0YNDPO9tl18tQZXj4am4raT7l9UCr+WkwJdlBoA5pwG6baWE9sL0iGWV/bzF/g==",
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.8.1.tgz",
|
||||
"integrity": "sha512-AW7063IaYFIcskt+eI5k4drb/hDuY2wK3zLsW01E49WaBcRhXVIOVox7cbfwHCA6zch117WZ5xVZlbGHJ4pkMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@angular-devkit/core": "0.6.8",
|
||||
"@angular-devkit/schematics": "0.6.8",
|
||||
"typescript": ">=2.6.2 <2.8"
|
||||
"@angular-devkit/core": "0.8.1",
|
||||
"@angular-devkit/schematics": "0.8.1",
|
||||
"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": {
|
||||
"version": "0.6.8",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.6.8.tgz",
|
||||
"integrity": "sha512-1Uq7LYnwL2wBwGVCgNz76QAR13ghAk+2vDDHOi+VX5+usHManxydrpoMGeX66OBPd+y5D3D2MFb+8mYHE7mygg==",
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.8.1.tgz",
|
||||
"integrity": "sha512-G5EU8nvqAC9fX09sV+UEM9EgR+PjGwguUatOk10uvwvZvCfO+W0FVeLmSap9A6mJ+e8YOH6XFpkwLG0AMuhYrw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@angular-devkit/core": "0.6.8",
|
||||
"@angular-devkit/schematics": "0.6.8",
|
||||
"@angular-devkit/core": "0.8.1",
|
||||
"@angular-devkit/schematics": "0.8.1",
|
||||
"npm-registry-client": "^8.5.1",
|
||||
"rxjs": "^6.0.0",
|
||||
"rxjs": "~6.2.0",
|
||||
"semver": "^5.3.0",
|
||||
"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": {
|
||||
@ -2068,7 +2173,7 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"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=",
|
||||
"dev": true
|
||||
}
|
||||
@ -6898,7 +7003,7 @@
|
||||
},
|
||||
"es6-promise": {
|
||||
"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=",
|
||||
"dev": true
|
||||
},
|
||||
@ -6910,7 +7015,7 @@
|
||||
},
|
||||
"readable-stream": {
|
||||
"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=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@ -8335,9 +8440,9 @@
|
||||
}
|
||||
},
|
||||
"npm-registry-client": {
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-8.5.1.tgz",
|
||||
"integrity": "sha512-7rjGF2eA7hKDidGyEWmHTiKfXkbrcQAsGL/Rh4Rt3x3YNRNHhwaTzVJfW3aNvvlhg4G62VCluif0sLCb/i51Hg==",
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-8.6.0.tgz",
|
||||
"integrity": "sha512-Qs6P6nnopig+Y8gbzpeN/dkt+n7IyVd8f45NTMotGk6Qo7GfBmzwYx6jRLoOOgKiMnaQfYxsuyQlD8Mc3guBhg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"concat-stream": "^1.5.2",
|
||||
@ -9259,7 +9364,7 @@
|
||||
},
|
||||
"chalk": {
|
||||
"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=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@ -9272,7 +9377,7 @@
|
||||
},
|
||||
"minimist": {
|
||||
"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=",
|
||||
"dev": true
|
||||
},
|
||||
@ -9905,9 +10010,9 @@
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "6.3.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.2.tgz",
|
||||
"integrity": "sha512-hV7criqbR0pe7EeL3O66UYVg92IR0XsA97+9y+BWTePK9SKmEI5Qd3Zj6uPnGkNzXsBywBQWTvujPl+1Kn9Zjw==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.2.tgz",
|
||||
"integrity": "sha512-0MI8+mkKAXZUF9vMrEoPnaoHkfzBPP4IGwUYRJhIRJF6/w3uByO1e91bEHn8zd43RdkTMKiooYKmwz7RH6zfOQ==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
@ -10153,9 +10258,9 @@
|
||||
}
|
||||
},
|
||||
"semver-intersect": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.3.1.tgz",
|
||||
"integrity": "sha1-j6hKnhAovSOeRTDRo+GB5pjYhLo=",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz",
|
||||
"integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "^5.0.0"
|
||||
@ -11470,9 +11575,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz",
|
||||
"integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==",
|
||||
"version": "2.9.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz",
|
||||
"integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
|
@ -34,13 +34,13 @@
|
||||
"@ngx-translate/http-loader": "^3.0.1",
|
||||
"core-js": "^2.5.4",
|
||||
"ngx-mat-select-search": "^1.3.1",
|
||||
"rxjs": "^6.3.2",
|
||||
"rxjs": "^6.2.2",
|
||||
"uuid": "^3.3.2",
|
||||
"zone.js": "^0.8.26"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.6.8",
|
||||
"@angular/cli": "~6.0.8",
|
||||
"@angular/cli": "^6.2.1",
|
||||
"@angular/compiler-cli": "^6.1.7",
|
||||
"@angular/language-service": "^6.1.7",
|
||||
"@biesbjerg/ngx-translate-extract": "^2.3.4",
|
||||
@ -63,6 +63,6 @@
|
||||
"protractor": "^5.4.1",
|
||||
"ts-node": "~5.0.1",
|
||||
"tslint": "~5.9.1",
|
||||
"typescript": "~2.7.2"
|
||||
"typescript": "~2.9.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,17 @@
|
||||
{
|
||||
"/apps/core/version": {
|
||||
"/apps/": {
|
||||
"target": "http://localhost:8000",
|
||||
"secure": false
|
||||
},
|
||||
"/apps/users/login": {
|
||||
"/media/": {
|
||||
"target": "http://localhost:8000",
|
||||
"secure": false
|
||||
},
|
||||
"/apps/users/logout": {
|
||||
"/rest/": {
|
||||
"target": "http://localhost:8000",
|
||||
"secure": false
|
||||
},
|
||||
"/apps/users/whoami": {
|
||||
"target": "http://localhost:8000",
|
||||
"secure": false
|
||||
},
|
||||
"/rest": {
|
||||
"target": "http://localhost:8000",
|
||||
"secure": false
|
||||
},
|
||||
"/ws/site": {
|
||||
"/ws/site/": {
|
||||
"target": "ws://localhost:8000",
|
||||
"secure": false,
|
||||
"ws": true
|
||||
|
@ -34,23 +34,6 @@ export class Item extends ProjectableBaseModel {
|
||||
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 {
|
||||
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 {
|
||||
/*const contentObject: AgendaBaseModel = this.contentObject;
|
||||
if (contentObject) {
|
||||
return contentObject.getAgendaTitle();
|
||||
} else {
|
||||
return this.title;
|
||||
}*/
|
||||
return this.title;
|
||||
}
|
||||
|
||||
// Same here. See comment for getTitle()
|
||||
public getListTitle(): string {
|
||||
/*const contentObject: AgendaBaseModel = this.contentObject;
|
||||
if (contentObject) {
|
||||
return contentObject.getAgendaTitleWithType();
|
||||
} else {
|
||||
return this.title_with_type;
|
||||
}*/
|
||||
return this.title_with_type;
|
||||
}
|
||||
|
||||
|
@ -29,4 +29,4 @@ export class Mediafile extends ProjectableBaseModel {
|
||||
}
|
||||
}
|
||||
|
||||
ProjectableBaseModel.registerCollectionElement('amediafiles/mediafile', Mediafile);
|
||||
ProjectableBaseModel.registerCollectionElement('mediafiles/mediafile', Mediafile);
|
||||
|
@ -85,7 +85,7 @@ export class Motion extends AgendaBaseModel {
|
||||
}
|
||||
|
||||
public getDetailStateURL(): string {
|
||||
return 'TODO';
|
||||
return `/motions/${this.id}`;
|
||||
}
|
||||
|
||||
public deserialize(input: any): void {
|
||||
|
@ -48,6 +48,10 @@ export class User extends ProjectableBaseModel {
|
||||
return name.trim();
|
||||
}
|
||||
|
||||
public containsGroupId(id: number): boolean {
|
||||
return this.groups_id.some(groupId => groupId === id);
|
||||
}
|
||||
|
||||
// TODO read config values for "users_sort_by"
|
||||
public get short_name(): string {
|
||||
const title = this.title.trim();
|
||||
|
@ -15,8 +15,7 @@ import {
|
||||
MatSnackBarModule,
|
||||
MatTableModule,
|
||||
MatPaginatorModule,
|
||||
MatSortModule,
|
||||
MatTabsModule
|
||||
MatSortModule
|
||||
} from '@angular/material';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatChipsModule } from '@angular/material';
|
||||
@ -79,10 +78,10 @@ library.add(fas);
|
||||
MatMenuModule,
|
||||
MatDialogModule,
|
||||
MatSnackBarModule,
|
||||
MatChipsModule,
|
||||
FontAwesomeModule,
|
||||
TranslateModule.forChild(),
|
||||
RouterModule,
|
||||
MatChipsModule,
|
||||
NgxMatSelectSearchModule
|
||||
],
|
||||
exports: [
|
||||
@ -106,7 +105,7 @@ library.add(fas);
|
||||
MatMenuModule,
|
||||
MatDialogModule,
|
||||
MatSnackBarModule,
|
||||
MatTabsModule,
|
||||
MatChipsModule,
|
||||
NgxMatSelectSearchModule,
|
||||
FontAwesomeModule,
|
||||
TranslateModule,
|
||||
|
@ -1,16 +1,18 @@
|
||||
<os-head-bar appName="Agenda" plusButton=true (plusButtonClicked)=onPlusButton()>
|
||||
</os-head-bar>
|
||||
<os-head-bar appName="Agenda" plusButton=true (plusButtonClicked)=onPlusButton()></os-head-bar>
|
||||
|
||||
<mat-card class="os-card card-plus-distance">
|
||||
<div class="app-content">
|
||||
Agenda Works
|
||||
<br/>
|
||||
<div>
|
||||
everyone should see this
|
||||
</div>
|
||||
<br/>
|
||||
<div *osPerms="'agenda.can_see'">
|
||||
Only permitted users should see this
|
||||
</div>
|
||||
</div>
|
||||
</mat-card>
|
||||
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
|
||||
<!-- title column -->
|
||||
<ng-container matColumnDef="title">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Topic </mat-header-cell>
|
||||
<mat-cell *matCellDef="let item"> {{item.getListTitle()}} </mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="duration">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Duration </mat-header-cell>
|
||||
<mat-cell *matCellDef="let item"> {{item.duration}} </mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<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>
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { BaseComponent } from 'app/base.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Item } from '../../../shared/models/agenda/item';
|
||||
import { Topic } from '../../../shared/models/topics/topic';
|
||||
import { ViewItem } from '../models/view-item';
|
||||
import { ListViewBaseComponent } from '../../base/list-view-base';
|
||||
import { AgendaRepositoryService } from '../services/agenda-repository.service';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
/**
|
||||
* List view for the agenda.
|
||||
@ -15,26 +16,43 @@ import { Topic } from '../../../shared/models/topics/topic';
|
||||
templateUrl: './agenda-list.component.html',
|
||||
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
|
||||
* @param titleService
|
||||
* @param translate
|
||||
*/
|
||||
public constructor(titleService: Title, protected translate: TranslateService) {
|
||||
public constructor(
|
||||
titleService: Title,
|
||||
translate: TranslateService,
|
||||
private router: Router,
|
||||
private repo: AgendaRepositoryService
|
||||
) {
|
||||
super(titleService, translate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init function.
|
||||
* Sets the title
|
||||
* Sets the title, initializes the table and calls the repository.
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
super.setTitle('Agenda');
|
||||
// tslint:disable-next-line
|
||||
const i: Item = new Item(); // Needed, that the Item.ts is loaded. Can be removed, if something else creates/uses items.
|
||||
// tslint:disable-next-line
|
||||
const t: Topic = new Topic(); // Needed, that the Topic.ts is loaded. Can be removed, if something else creates/uses topics.
|
||||
this.initTable();
|
||||
this.repo.getViewModelListObservable().subscribe(newAgendaItem => {
|
||||
this.dataSource.data = newAgendaItem;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
54
client/src/app/site/agenda/models/view-item.ts
Normal file
54
client/src/app/site/agenda/models/view-item.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}));
|
||||
});
|
@ -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);
|
||||
}
|
||||
}
|
@ -1,21 +1,32 @@
|
||||
<!-- <mat-toolbar color='primary'>
|
||||
|
||||
<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 appName="Assignments" plusButton=true [menuList]=assignmentMenu (plusButtonClicked)=onPlusButton()
|
||||
(ellipsisMenuItem)=onEllipsisItem($event)>
|
||||
</os-head-bar>
|
||||
|
||||
<mat-card class="os-card card-plus-distance">
|
||||
assignment-list works!
|
||||
</mat-card>
|
||||
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
|
||||
<!-- name column -->
|
||||
<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>
|
||||
|
@ -1,20 +1,20 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { BaseComponent } from '../../../base.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
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
|
||||
*
|
||||
* TODO: not yet implemented
|
||||
*/
|
||||
@Component({
|
||||
selector: 'os-assignment-list',
|
||||
templateUrl: './assignment-list.component.html',
|
||||
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.
|
||||
* Give it to the HeadBar to display them.
|
||||
@ -29,13 +29,27 @@ export class AssignmentListComponent extends BaseComponent implements OnInit {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param repo the repository
|
||||
* @param titleService
|
||||
* @param translate
|
||||
*/
|
||||
public constructor(titleService: Title, protected translate: TranslateService) {
|
||||
public constructor(private repo: AssignmentRepositoryService, titleService: Title, translate: TranslateService) {
|
||||
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
|
||||
*/
|
||||
@ -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 {
|
||||
super.setTitle('Assignments');
|
||||
|
||||
// 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.
|
||||
public selectAssignment(assignment: ViewAssignment): void {
|
||||
console.log('select assignment list: ', assignment);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,15 +72,4 @@ export class AssignmentListComponent extends BaseComponent implements OnInit {
|
||||
public downloadAssignmentButton(): void {
|
||||
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]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
53
client/src/app/site/assignments/models/view-assignment.ts
Normal file
53
client/src/app/site/assignments/models/view-assignment.ts
Normal 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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
});
|
||||
});
|
@ -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);
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
import { OpenSlidesComponent } from '../openslides.component';
|
||||
import { OpenSlidesComponent } from '../../openslides.component';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { BaseViewModel } from './base-view-model';
|
||||
import { BaseModel, ModelConstructor } from '../shared/models/base/base-model';
|
||||
import { CollectionStringModelMapperService } from '../core/services/collectionStringModelMapper.service';
|
||||
import { DataStoreService } from '../core/services/data-store.service';
|
||||
import { BaseModel, ModelConstructor } from '../../shared/models/base/base-model';
|
||||
import { CollectionStringModelMapperService } from '../../core/services/collectionStringModelMapper.service';
|
||||
import { DataStoreService } from '../../core/services/data-store.service';
|
||||
|
||||
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(
|
||||
protected DS: DataStoreService,
|
||||
protected baseModelCtor: ModelConstructor<M>,
|
||||
protected depsModelCtors: ModelConstructor<BaseModel>[]
|
||||
protected depsModelCtors?: ModelConstructor<BaseModel>[]
|
||||
) {
|
||||
super();
|
||||
|
||||
@ -47,7 +47,7 @@ export abstract class BaseRepository<V extends BaseViewModel, M extends BaseMode
|
||||
// Add new and updated motions to the viewModelStore
|
||||
this.viewModelStore[model.id] = this.createViewModel(model as M);
|
||||
this.updateAllObservables(model.id);
|
||||
} else {
|
||||
} else if (this.depsModelCtors) {
|
||||
const dependencyChanged: boolean = this.depsModelCtors.some(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>;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
@ -1,5 +1,5 @@
|
||||
import { BaseModel } from '../shared/models/base/base-model';
|
||||
import { Displayable } from '../shared/models/base/displayable';
|
||||
import { BaseModel } from '../../shared/models/base/base-model';
|
||||
import { Displayable } from '../../shared/models/base/displayable';
|
||||
|
||||
/**
|
||||
* Base class for view models. alls view models should have titles.
|
63
client/src/app/site/base/list-view-base.ts
Normal file
63
client/src/app/site/base/list-view-base.ts
Normal 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]();
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,32 @@
|
||||
</os-head-bar>
|
||||
|
||||
|
||||
<mat-card class="os-card card-plus-distance">
|
||||
mediafile-list works!
|
||||
</mat-card>
|
||||
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
|
||||
<!-- name column -->
|
||||
<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>
|
||||
|
@ -3,19 +3,20 @@ import { Title } from '@angular/platform-browser';
|
||||
|
||||
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({
|
||||
selector: 'os-mediafile-list',
|
||||
templateUrl: './mediafile-list.component.html',
|
||||
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.
|
||||
* Give it to the HeadBar to display them.
|
||||
@ -31,10 +32,15 @@ export class MediafileListComponent extends BaseComponent implements OnInit {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param repo the repository for files
|
||||
* @param titleService
|
||||
* @param translate
|
||||
*/
|
||||
public constructor(titleService: Title, protected translate: TranslateService) {
|
||||
public constructor(
|
||||
private repo: MediafileRepositoryService,
|
||||
protected titleService: Title,
|
||||
protected translate: TranslateService
|
||||
) {
|
||||
super(titleService, translate);
|
||||
}
|
||||
|
||||
@ -44,6 +50,10 @@ export class MediafileListComponent extends BaseComponent implements OnInit {
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
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.
|
||||
*
|
||||
* @param event clicked entry from ellipsis menu
|
||||
* Clicking on a list row
|
||||
* @param file the selected file
|
||||
*/
|
||||
public onEllipsisItem(event: any): void {
|
||||
if (event.action) {
|
||||
this[event.action]();
|
||||
}
|
||||
public selectFile(file: ViewMediafile): void {
|
||||
console.log('The file: ', file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly download a mediafile using the download button on the table
|
||||
* @param file
|
||||
*/
|
||||
public download(file: ViewMediafile): void {
|
||||
window.open(file.downloadUrl);
|
||||
}
|
||||
}
|
||||
|
59
client/src/app/site/mediafiles/models/view-mediafile.ts
Normal file
59
client/src/app/site/mediafiles/models/view-mediafile.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
});
|
||||
});
|
@ -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);
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
||||
<div class='custom-table-header on-transition-fade'>
|
||||
@ -10,7 +11,7 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-table class='on-transition-fade' [dataSource]="dataSource" matSort>
|
||||
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
|
||||
<!-- identifier column -->
|
||||
<ng-container matColumnDef="identifier">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Identifier </mat-header-cell>
|
||||
|
@ -15,24 +15,7 @@
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
mat-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);
|
||||
}
|
||||
|
||||
.os-listview-table {
|
||||
/** identifier */
|
||||
.mat-column-identifier {
|
||||
padding-left: 10px;
|
||||
|
@ -1,14 +1,13 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { MatTable, MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseComponent } from '../../../../base.component';
|
||||
import { MotionRepositoryService } from '../../services/motion-repository.service';
|
||||
import { ViewMotion } from '../../models/view-motion';
|
||||
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.
|
||||
@ -18,29 +17,7 @@ import { WorkflowState } from '../../../../shared/models/motions/workflow-state'
|
||||
templateUrl: './motion-list.component.html',
|
||||
styleUrls: ['./motion-list.component.scss']
|
||||
})
|
||||
export class MotionListComponent extends BaseComponent 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;
|
||||
|
||||
export class MotionListComponent extends ListViewBaseComponent<ViewMotion> implements OnInit {
|
||||
/**
|
||||
* Use for minimal width
|
||||
*/
|
||||
@ -78,8 +55,8 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
||||
* @param repo Motion Repository
|
||||
*/
|
||||
public constructor(
|
||||
protected titleService: Title,
|
||||
protected translate: TranslateService,
|
||||
titleService: Title,
|
||||
translate: TranslateService,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
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 {
|
||||
super.setTitle('Motions');
|
||||
|
||||
this.dataSource = new MatTableDataSource();
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
|
||||
this.initTable();
|
||||
this.repo.getViewModelListObservable().subscribe(newMotions => {
|
||||
this.dataSource.data = newMotions;
|
||||
});
|
||||
@ -163,15 +138,4 @@ export class MotionListComponent extends BaseComponent implements OnInit {
|
||||
public downloadMotions(): void {
|
||||
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]();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import { User } from '../../../shared/models/users/user';
|
||||
import { Workflow } from '../../../shared/models/motions/workflow';
|
||||
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
|
||||
import { BaseModel } from '../../../shared/models/base/base-model';
|
||||
import { BaseViewModel } from '../../base-view-model';
|
||||
import { BaseViewModel } from '../../base/base-view-model';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
/**
|
||||
@ -27,43 +27,23 @@ export class ViewMotion extends BaseViewModel {
|
||||
}
|
||||
|
||||
public get id(): number {
|
||||
if (this.motion) {
|
||||
return this.motion.id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.motion ? this.motion.id : null;
|
||||
}
|
||||
|
||||
public get identifier(): string {
|
||||
if (this.motion) {
|
||||
return this.motion.identifier;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.motion ? this.motion.identifier : null;
|
||||
}
|
||||
|
||||
public get title(): string {
|
||||
if (this.motion) {
|
||||
return this.motion.title;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.motion ? this.motion.title : null;
|
||||
}
|
||||
|
||||
public get text(): string {
|
||||
if (this.motion) {
|
||||
return this.motion.text;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.motion ? this.motion.text : null;
|
||||
}
|
||||
|
||||
public get reason(): string {
|
||||
if (this.motion) {
|
||||
return this.motion.reason;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.motion ? this.motion.reason : null;
|
||||
}
|
||||
|
||||
public get category(): Category {
|
||||
@ -71,11 +51,7 @@ export class ViewMotion extends BaseViewModel {
|
||||
}
|
||||
|
||||
public get categoryId(): number {
|
||||
if (this._motion && this._motion.category_id) {
|
||||
return this._motion.category_id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.motion && this.category ? this.motion.category_id : null;
|
||||
}
|
||||
|
||||
public get submitters(): User[] {
|
||||
@ -95,15 +71,11 @@ export class ViewMotion extends BaseViewModel {
|
||||
}
|
||||
|
||||
public get stateId(): number {
|
||||
if (this._motion && this._motion.state_id) {
|
||||
return this._motion.state_id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.motion && this.motion.state_id ? this.motion.state_id : null;
|
||||
}
|
||||
|
||||
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 {
|
||||
if (this.recommendationId && this.workflow) {
|
||||
return this.workflow.getStateById(this.recommendationId);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.recommendationId && this.workflow ? this.workflow.getStateById(this.recommendationId) : null;
|
||||
}
|
||||
|
||||
public get origin(): string {
|
||||
if (this.motion) {
|
||||
return this.motion.origin;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.motion ? this.motion.origin : null;
|
||||
}
|
||||
|
||||
public get nextStates(): WorkflowState[] {
|
||||
if (this.state && this.workflow) {
|
||||
return this.state.getNextStates(this.workflow);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.state && this.workflow ? this.state.getNextStates(this.workflow) : null;
|
||||
}
|
||||
|
||||
public constructor(
|
||||
|
@ -8,7 +8,7 @@ import { Workflow } from '../../../shared/models/motions/workflow';
|
||||
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
import { Observable } from 'rxjs';
|
||||
import { BaseRepository } from '../../base-repository';
|
||||
import { BaseRepository } from '../../base/base-repository';
|
||||
import { DataStoreService } from '../../../core/services/data-store.service';
|
||||
|
||||
/**
|
||||
|
38
client/src/app/site/settings/models/view-config.ts
Normal file
38
client/src/app/site/settings/models/view-config.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
});
|
||||
});
|
@ -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);
|
||||
}
|
||||
}
|
@ -1,20 +1,19 @@
|
||||
<os-head-bar appName="Settings">
|
||||
</os-head-bar>
|
||||
<os-head-bar appName="Settings"></os-head-bar>
|
||||
|
||||
<mat-card class="os-card">
|
||||
<div *osPerms="'core.can_manage_config'" class="app-content">
|
||||
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
Title
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
|
||||
<!-- name column -->
|
||||
<ng-container matColumnDef="key">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Key </mat-header-cell>
|
||||
<mat-cell *matCellDef="let config"> {{config.key}} </mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<p> CONTENT </p>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
<!-- prefix column -->
|
||||
<ng-container matColumnDef="value">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Value </mat-header-cell>
|
||||
<mat-cell *matCellDef="let config"> {{config.value}}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
</mat-card>
|
||||
<mat-header-row *matHeaderRowDef="['key', 'value']"></mat-header-row>
|
||||
<mat-row (click)='selectConfig(row)' *matRowDef="let row; columns: ['key', 'value']"></mat-row>
|
||||
</mat-table>
|
||||
|
@ -1,41 +1,61 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { BaseComponent } from '../../../base.component';
|
||||
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
|
||||
*
|
||||
* TODO: Not yet implemented
|
||||
*/
|
||||
@Component({
|
||||
selector: 'os-settings-list',
|
||||
templateUrl: './settings-list.component.html',
|
||||
styleUrls: ['./settings-list.component.css']
|
||||
})
|
||||
export class SettingsListComponent extends BaseComponent implements OnInit {
|
||||
export class SettingsListComponent extends ListViewBaseComponent<ViewConfig> implements OnInit {
|
||||
/**
|
||||
* The usual component constructor
|
||||
* @param titleService
|
||||
* @param translate
|
||||
*/
|
||||
public constructor(
|
||||
titleService: Title,
|
||||
protected titleService: Title,
|
||||
protected translate: TranslateService,
|
||||
private constantsService: ConstantsService
|
||||
private repo: ConfigRepositoryService,
|
||||
private constantsService: ConstantsService,
|
||||
) {
|
||||
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 {
|
||||
super.setTitle('Settings');
|
||||
|
||||
this.initTable();
|
||||
this.constantsService.get('OpenSlidesConfigVariables').subscribe(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);
|
||||
}
|
||||
}
|
||||
|
68
client/src/app/site/users/models/view-user.ts
Normal file
68
client/src/app/site/users/models/view-user.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}));
|
||||
});
|
@ -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);
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
||||
<mat-card class="os-card">
|
||||
UserList Works!
|
||||
</mat-card>
|
||||
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
|
||||
<!-- name column -->
|
||||
<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>
|
||||
|
@ -1,32 +1,98 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
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.
|
||||
*
|
||||
* TODO: Not yet implemented
|
||||
*/
|
||||
@Component({
|
||||
selector: 'os-user-list',
|
||||
templateUrl: './user-list.component.html',
|
||||
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
|
||||
* @param repo the user repository
|
||||
* @param titleService
|
||||
* @param translate
|
||||
*/
|
||||
public constructor(titleService: Title, protected translate: TranslateService) {
|
||||
public constructor(
|
||||
private repo: UserRepositoryService,
|
||||
protected titleService: Title,
|
||||
protected translate: TranslateService
|
||||
) {
|
||||
super(titleService, translate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init function, sets the title
|
||||
* Init function
|
||||
*
|
||||
* sets the title, inits the table and calls the repo
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,25 @@ body {
|
||||
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 {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user