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": {
|
"@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": {
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
public getDetailStateURL(): string {
|
||||||
return 'TODO';
|
return `/motions/${this.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public deserialize(input: any): void {
|
public deserialize(input: any): void {
|
||||||
|
@ -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();
|
||||||
|
@ -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,
|
||||||
|
@ -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>
|
||||||
|
@ -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`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
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'>
|
<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>
|
||||||
|
@ -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]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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 { 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;
|
||||||
|
|
||||||
/**
|
/**
|
@ -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.
|
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>
|
</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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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>
|
</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>
|
||||||
|
@ -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;
|
||||||
|
@ -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]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
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 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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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>
|
</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>
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user