diff --git a/api/apib/army-management/awardings.apib b/api/apib/army-management/awardings.apib index fe62355..0816210 100644 --- a/api/apib/army-management/awardings.apib +++ b/api/apib/army-management/awardings.apib @@ -58,3 +58,16 @@ Create a new awarding proposal, that needs to be approved by higher permission l + Response 201 (application/json; charset=utf-8) + Attributes (Awarding, fixed-type) + +### Get Unprocessed Squad Awardings [GET /awardings/unprocessed/{squadId}] + +List all awardings that are requested and in pending decision status + +**Permission: 1** + ++ Parameters + + squadId: `5aba54eaeadcce6332c6a774` (string, required) - unique id of the squad in which awardings are requested + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (array[AwardingPopulated], fixed-type) diff --git a/api/apib/data_structures/_log.apib b/api/apib/data_structures/_log.apib index 7b44d5d..535e4e4 100644 --- a/api/apib/data_structures/_log.apib +++ b/api/apib/data_structures/_log.apib @@ -43,6 +43,9 @@ + `BLUFOR` + `OPFOR` + `NONE` ++ shooterVehicle: `FV-720 Mora` (string, optional) - vehicle in whiock the shooting player sat ++ targetVehicle: `Ifrit-GMG` (string, optional) - vehicle in which the target player sat ++ magazine: `30 mm APFSDS` (string, optional) - magazine name used to execute the kill #LogRespawn (Log) ## Properties @@ -84,3 +87,5 @@ + `HEAVY` + `AIR` + `UNKNOWN` ++ shooterVehicle: `FV-720 Mora` (string, optional) - vehicle in whiock the shooting player sat ++ magazine: `30 mm APFSDS` (string, optional) - magazine name used to execute the kill diff --git a/api/models/logs/kill.js b/api/models/logs/kill.js index 29e76a3..e695b24 100644 --- a/api/models/logs/kill.js +++ b/api/models/logs/kill.js @@ -24,6 +24,15 @@ const LogKillSchema = new Schema({ type: Boolean, required: true, }, + magazine: { + type: String, + }, + shooterVehicle: { + type: String, + }, + targetVehicle: { + type: String, + }, fraction: { type: String, enum: ['BLUFOR', 'OPFOR', 'NONE'], diff --git a/api/models/logs/vehicle.js b/api/models/logs/vehicle.js index e360e00..e2e5307 100644 --- a/api/models/logs/vehicle.js +++ b/api/models/logs/vehicle.js @@ -33,6 +33,12 @@ const LogVehicleKillSchema = new Schema({ enum: ['LIGHT', 'HEAVY', 'AIR', 'UNKNOWN'], required: true, }, + magazine: { + type: String, + }, + shooterVehicle: { + type: String, + }, }, { collection: 'logVehicle', }); diff --git a/api/routes/awardings.js b/api/routes/awardings.js index e256bf9..da5ae63 100644 --- a/api/routes/awardings.js +++ b/api/routes/awardings.js @@ -3,6 +3,8 @@ // modules const express = require('express'); +const mongoose = require('mongoose'); + // HTTP status codes by name const codes = require('./http-codes'); @@ -10,9 +12,11 @@ const routerHandling = require('../middleware/router-handling'); const apiAuthenticationMiddleware = require('../middleware/auth-middleware'); const checkHl = require('../middleware/permission-check').checkHl; +const checkSql = require('../middleware/permission-check').checkSql; // Mongoose Model using mongoDB const AwardingModel = require('../models/awarding'); +const UserModel = require('../models/user'); // result set for proposer(appUser) population const resultSet = { @@ -77,8 +81,26 @@ awarding.route('/') .all(routerHandling.httpMethodNotAllowed); -awarding.route('/:id') +awarding.route('/unprocessed/:squadId') + .get(apiAuthenticationMiddleware, checkSql, (req, res, next) => { + const filter = {squadId: req.params.squadId}; + UserModel.find(filter, (err, users) => { + if (!users || users.length === 0) { + return next(); + } + const squadUserIds = users.map((user) => new mongoose.Types.ObjectId(user._id)); + AwardingModel.find({userId: {$in: squadUserIds}, confirmed: 0}) + .populate('decorationId') + .populate('proposer', resultSet) + .populate('userId') + .exec((err, awards) => { + res.locals.items = awards; + next(); + }); + }); + }); +awarding.route('/:id') .patch(apiAuthenticationMiddleware, checkHl, (req, res, next) => { if (!req.body || (req.body._id && req.body._id !== req.params.id)) { // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js index 3d9f73b..44de371 100644 --- a/api/tools/log-parse-tool.js +++ b/api/tools/log-parse-tool.js @@ -17,9 +17,9 @@ const vehicleNameEndRegex = /\s\(\w+:/; const sideRegex = /(side:\s(.*?)\))/; -// const magazineRegex = /(magazine:\s(.*?)\))/; +const magazineRegex = /(magazine:\s(.*?)\))/; -// const vehicleRegex = /(vehicle:\s(.*?)\))/; +const vehicleRegex = /(vehicle:\s(.*?)\))/; const categoryRegex = /(category:\s(.*?)\))/; @@ -51,7 +51,7 @@ const parseWarLog = (lineArray, war) => { ]; const addPlayerIfNotExists = (inputPlayer, steamUUID) => { - const player = getPlayerAndFractionFromString(inputPlayer); + const player = getPlayerInfoFromString(inputPlayer); if (player && player.name && player.fraction && !playerArrayContains(stats.players, player)) { player['warId'] = war._id; player['steamUUID'] = steamUUID; @@ -74,7 +74,7 @@ const parseWarLog = (lineArray, war) => { stats.clean.push(line); const shooterString = line.substring(line.lastIndexOf(' von: ') + 6, line.search(/$/) - 1); - const shooter = getPlayerAndFractionFromString(shooterString); + const shooter = getPlayerInfoFromString(shooterString); if (line.includes('Fahrzeug:')) { const targetString = line.substring(line.lastIndexOf(' --- Fahrzeug: ') + 15, line.lastIndexOf(' von:')); @@ -93,19 +93,36 @@ const parseWarLog = (lineArray, war) => { } else { vehicleKill.shooter = shooter ? shooter.name : null; } + if (shooter.magazine) { + vehicleKill.magazine = shooter.magazine; + } + if (shooter.vehicle) { + vehicleKill.shooterVehicle = shooter.vehicle; + } + stats.vehicles.push(vehicleKill); } } else { const targetString = line.substring(line.lastIndexOf(' --- Einheit: ') + 14, line.lastIndexOf(' von:')); - const target = getPlayerAndFractionFromString(targetString); - stats.kills.push({ + const target = getPlayerInfoFromString(targetString); + const kill = { war: war._id, time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]), shooter: shooter ? shooter.name : null, target: target ? target.name : null, friendlyFire: shooter ? target.fraction === shooter.fraction : false, fraction: shooter ? shooter.fraction : 'NONE', - }); + }; + if (shooter.magazine) { + kill.magazine = shooter.magazine; + } + if (shooter.vehicle) { + kill.shooterVehicle = shooter.vehicle; + } + if (target.vehicle) { + kill.targetVehicle = target.vehicle; + } + stats.kills.push(kill); } } else if (line.includes('(Budget)')) { /** @@ -173,9 +190,9 @@ const parseWarLog = (lineArray, war) => { const stabilized = !!line.includes('stabilisiert."'); const medicName = line.substring(line.lastIndexOf('wurde von ') + 10, line.lastIndexOf(stabilized ? ' stabilisiert' : ' wiederbelebt')); - const medic = getPlayerAndFractionFromString(medicName); + const medic = getPlayerInfoFromString(medicName); const patientName = line.substring(line.lastIndexOf('--- ') + 4, line.lastIndexOf(' wurde von')); - const patient = getPlayerAndFractionFromString(patientName); + const patient = getPlayerInfoFromString(patientName); stats.revive.push({ war: war._id, @@ -191,9 +208,9 @@ const parseWarLog = (lineArray, war) => { */ stats.clean.push(line); const driverString = line.substring(line.lastIndexOf('wurde von ') + 10, line.lastIndexOf(' eingeflogen')); - const driver = getPlayerAndFractionFromString(driverString); + const driver = getPlayerInfoFromString(driverString); const passengerString = line.substring(line.lastIndexOf('--- ') + 3, line.lastIndexOf(' wurde von')); - const passenger = getPlayerAndFractionFromString(passengerString); + const passenger = getPlayerInfoFromString(passengerString); const distance = parseInt(line.substring(line.lastIndexOf('eingeflogen (') + 13, line.lastIndexOf('m)') - 1)); stats.transport.push({ @@ -285,15 +302,20 @@ const getBudgetEntry = (budg, warId, warDate) => { }; }; -const getPlayerAndFractionFromString = (inputString) => { +const getPlayerInfoFromString = (inputString) => { + const resPlayer = {}; const playerNameRegexMatch = playerNameRegex.exec(inputString); const sideMatch = sideRegex.exec(inputString); // SINGLE PLAYER NAME let name; if (playerNameRegexMatch && playerNameRegexMatch.length >= 2) { - // NAME name = playerNameRegexMatch[2].trim(); + // do not return player for 'Error: No unit' + if (!name && name === 'Error: No unit') { + return; + } + resPlayer.name = name; } // ADDITIONAL PLAYER NAMES let additionalPlayerMatch; @@ -317,34 +339,31 @@ const getPlayerAndFractionFromString = (inputString) => { } } - // const magazineMatch = magazineRegex.exec(inputString); - // const vehicleMatch = vehicleRegex.exec(inputString); + if (side && side !== 'ENEMY') { + resPlayer.fraction = side === 'WEST' ? 'BLUFOR' : 'OPFOR'; + } - // if (magazineMatch && magazineMatch.length >= 3) { // MAGAZINE - // console.log(magazineMatch[2]) - // } + const magazineMatch = magazineRegex.exec(inputString); + if (magazineMatch && magazineMatch.length >= 3) { + let magazine = magazineMatch[2]; + if (new RegExp('\\(.*$').test(magazine)) { + magazine = magazine.concat(')'); + } + resPlayer.magazine = magazine; + } - // if (vehicleMatch && vehicleMatch.length >= 3 && vehicleMatch[2]) { - // let vehicle = vehicleMatch[2]; - // if (new RegExp("\\(.*$").test(vehicle)) { - // vehicle = vehicle.concat(")"); - // } // VEHICLE - // console.log(vehicle) - // } - - let fraction; - if (side) { - fraction = side !== 'ENEMY' ? side === 'WEST' ? - 'BLUFOR' : 'OPFOR' : - undefined; + const vehicleMatch = vehicleRegex.exec(inputString); + if (vehicleMatch && vehicleMatch.length >= 3 && vehicleMatch[2]) { + let vehicle = vehicleMatch[2]; + if (new RegExp('\\(.*$').test(vehicle)) { + vehicle = vehicle.concat(')'); + } + resPlayer.vehicle = vehicle; } - // do not return player for 'Error: No unit' - if (name && name !== 'Error: No unit') { - return {name: name, fraction: fraction}; - } + return resPlayer; }; const getVehicleAndFractionFromString = (nameClassFractionString) => { diff --git a/package.json b/package.json index 9a46c82..23e7421 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opt-cc", - "version": "1.7.6", + "version": "1.7.7", "author": "Florian Hartwich ", "private": true, "scripts": { diff --git a/static/src/app/app.component.html b/static/src/app/app.component.html index 5a5f99c..e7c5c94 100644 --- a/static/src/app/app.component.html +++ b/static/src/app/app.component.html @@ -19,9 +19,6 @@
  • Zum Forum
  • -
  • - Login -
  • Armeeübersicht
  • @@ -48,6 +45,9 @@ diff --git a/static/src/app/app.config.ts b/static/src/app/app.config.ts index 69ed7f8..caf5810 100644 --- a/static/src/app/app.config.ts +++ b/static/src/app/app.config.ts @@ -5,6 +5,7 @@ export class AppConfig { public readonly apiAppUserPath = this.apiUrl + '/account/'; public readonly apiAuthenticationPath = this.apiUrl + '/authenticate'; public readonly apiAwardPath = this.apiUrl + '/awardings'; + public readonly apiAwardSquadPath = this.apiUrl + '/awardings/unprocessed'; public readonly apiCampaignPath = this.apiUrl + '/campaigns'; public readonly apiDecorationPath = this.apiUrl + '/decorations/'; public readonly apiLogsPath = this.apiUrl + '/logs'; @@ -17,7 +18,6 @@ export class AppConfig { public readonly apiSquadPath = this.apiUrl + '/squads/'; public readonly apiUserPath = this.apiUrl + '/users/'; public readonly apiWarPath = this.apiUrl + '/wars'; - } export const RouteConfig = { @@ -34,5 +34,6 @@ export const RouteConfig = { requestAwardPath: 'award', requestPromotionPath: 'promotion', confirmAwardPath: 'confirm-award', - confirmPromotionPath: 'confirm-promotion' + confirmPromotionPath: 'confirm-promotion', + sqlDashboardPath: 'sql-dashboard', }; diff --git a/static/src/app/login/login.component.html b/static/src/app/login/login.component.html index b66611c..92de22e 100644 --- a/static/src/app/login/login.component.html +++ b/static/src/app/login/login.component.html @@ -1,6 +1,6 @@
    -
    +
    @@ -23,7 +23,5 @@
    - - diff --git a/static/src/app/models/model-interfaces.ts b/static/src/app/models/model-interfaces.ts index bc7a72b..97232d0 100644 --- a/static/src/app/models/model-interfaces.ts +++ b/static/src/app/models/model-interfaces.ts @@ -94,6 +94,7 @@ export interface Promotion { oldRankLvl: number; newRankLvl: number; rejectReason?: string; + confirmed?: number; } export interface Decoration { diff --git a/static/src/app/request/request.module.ts b/static/src/app/request/request.module.ts index 1173550..593d2f4 100644 --- a/static/src/app/request/request.module.ts +++ b/static/src/app/request/request.module.ts @@ -8,10 +8,11 @@ import {ConfirmAwardComponent} from './confirm-award/confirm-award.component'; import {ConfirmPromotionComponent} from './confirm-promotion/confirm-promotion.component'; import {RequestAwardComponent} from './award/req-award.component'; import {RequestPromotionComponent} from './promotion/req-promotion.component'; +import {SqlDashboardComponent} from './sql-dashboard/sql-dashboard.component'; @NgModule({ declarations: [RequestComponent, RequestPromotionComponent, RequestAwardComponent, ConfirmPromotionComponent, - ConfirmAwardComponent, FilterRankPipe], + ConfirmAwardComponent, SqlDashboardComponent, FilterRankPipe], imports: [CommonModule, SharedModule, requestRouterModule] }) export class RequestModule { diff --git a/static/src/app/request/request.routing.ts b/static/src/app/request/request.routing.ts index 28ce09b..172bfa3 100644 --- a/static/src/app/request/request.routing.ts +++ b/static/src/app/request/request.routing.ts @@ -8,6 +8,7 @@ import {RequestPromotionComponent} from './promotion/req-promotion.component'; import {RequestComponent} from './request.component'; import {RouteConfig} from '../app.config'; import {LoginGuardHL, LoginGuardSQL} from '../login'; +import {SqlDashboardComponent} from './sql-dashboard/sql-dashboard.component'; export const requestRoutes: Routes = [{ @@ -23,6 +24,11 @@ export const requestRoutes: Routes = [{ component: RequestPromotionComponent, canActivate: [LoginGuardSQL] }, + { + path: RouteConfig.sqlDashboardPath, + component: SqlDashboardComponent, + canActivate: [LoginGuardSQL] + }, { path: RouteConfig.confirmAwardPath, component: ConfirmAwardComponent, @@ -32,7 +38,7 @@ export const requestRoutes: Routes = [{ path: RouteConfig.confirmPromotionPath, component: ConfirmPromotionComponent, canActivate: [LoginGuardHL] - } + }, ]; export const requestRouterModule: ModuleWithProviders = RouterModule.forChild(requestRoutes); diff --git a/static/src/app/request/sql-dashboard/sql-dashboard.component.css b/static/src/app/request/sql-dashboard/sql-dashboard.component.css new file mode 100644 index 0000000..45d7a13 --- /dev/null +++ b/static/src/app/request/sql-dashboard/sql-dashboard.component.css @@ -0,0 +1,24 @@ +.overview { + margin-left: 25px !important; +} + +.decoration-preview { + padding: 5px; +} + +.table { + overflow-wrap: break-word; + table-layout: fixed; +} + +.table-container { + margin-top: 40px; + overflow-x: auto; + width: 90%; + min-width: 800px; + padding: 5px; +} + +h3 { + margin: 80px 0 20px -20px; +} diff --git a/static/src/app/request/sql-dashboard/sql-dashboard.component.html b/static/src/app/request/sql-dashboard/sql-dashboard.component.html new file mode 100644 index 0000000..efe1c07 --- /dev/null +++ b/static/src/app/request/sql-dashboard/sql-dashboard.component.html @@ -0,0 +1,78 @@ +
    +

    SQL Dashboard

    + +
    + + + + + + + + + + + + + + + + + + + + +
    TeilnehmerAlter RangNeuer RangAntragstellerDatum
    + {{promotion.userId.username}} + + {{rank.name}} + + {{rank.name}} + + {{promotion.proposer.username}} + + {{promotion.timestamp | date: 'dd.MM.yyyy'}} +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    TeilnehmerBildBezeichnungBegründungAntragstellerDatum
    + {{award.userId.username}} + + + + + + {{award.decorationId.name}} + + {{award.reason}} + + {{award.proposer?.username}} + + {{award.date | date: 'dd.MM.yyyy'}} +
    +
    +
    diff --git a/static/src/app/request/sql-dashboard/sql-dashboard.component.ts b/static/src/app/request/sql-dashboard/sql-dashboard.component.ts new file mode 100644 index 0000000..39d21e4 --- /dev/null +++ b/static/src/app/request/sql-dashboard/sql-dashboard.component.ts @@ -0,0 +1,50 @@ +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; +import {Award, Promotion, Rank} from '../../models/model-interfaces'; +import {RankService} from '../../services/army-management/rank.service'; +import {PromotionService} from '../../services/army-management/promotion.service'; +import {LoginService} from '../../services/app-user-service/login-service'; +import {AwardingService} from '../../services/army-management/awarding.service'; + + +@Component({ + templateUrl: './sql-dashboard.component.html', + styleUrls: ['./sql-dashboard.component.css', '../../style/overview.css'], +}) +export class SqlDashboardComponent implements OnInit { + + ranks: Rank[]; + + promotions: Promotion[]; + + awards: Award[]; + + constructor(private router: Router, + private route: ActivatedRoute, + private rankService: RankService, + private promotionService: PromotionService, + private awardingService: AwardingService, + private loginService: LoginService) { + } + + ngOnInit() { + const currentUser = this.loginService.getCurrentUser(); + + this.promotionService.getSquadPromotions(currentUser.squad._id).subscribe(promotions => { + this.promotions = promotions.filter(promotion => promotion.confirmed === 0); + }); + + this.awardingService.getUnprocessedSquadAwards(currentUser.squad._id).subscribe(awards => { + this.awards = awards; + }); + + this.rankService.findRanks('', currentUser.squad.fraction).subscribe(ranks => { + this.ranks = ranks; + }); + } + + cancel() { + this.router.navigate(['..'], {relativeTo: this.route}); + return false; + } +} diff --git a/static/src/app/services/army-management/awarding.service.ts b/static/src/app/services/army-management/awarding.service.ts index 316f141..2fc3778 100644 --- a/static/src/app/services/army-management/awarding.service.ts +++ b/static/src/app/services/army-management/awarding.service.ts @@ -25,6 +25,11 @@ export class AwardingService { }); } + getUnprocessedSquadAwards(squadId?: string) { + return this.http.get(this.config.apiAwardSquadPath.concat('/').concat(squadId)) + .map(res => res.json()); + } + /** * get awards array with populated decorations */ diff --git a/static/src/app/statistic/war/fraction-stats/fraction-stats.component.ts b/static/src/app/statistic/war/fraction-stats/fraction-stats.component.ts index 3aa902f..9109b05 100644 --- a/static/src/app/statistic/war/fraction-stats/fraction-stats.component.ts +++ b/static/src/app/statistic/war/fraction-stats/fraction-stats.component.ts @@ -40,7 +40,8 @@ export class FractionStatsComponent implements OnInit, OnChanges { tmpFlagCaptureData; colorScheme = { - domain: [Fraction.COLOR_BLUFOR, Fraction.COLOR_OPFOR] + domain: [Fraction.COLOR_BLUFOR, Fraction.COLOR_OPFOR, Fraction.COLOR_BLUFOR_LIGHT, Fraction.COLOR_OPFOR_LIGHT, + Fraction.COLOR_BLUFOR_DARK, Fraction.COLOR_OPFOR_DARK, Fraction.COLOR_BLUFOR_GREY, Fraction.COLOR_OPFOR_GREY] }; labelPoints = 'Punkte'; @@ -259,7 +260,8 @@ export class FractionStatsComponent implements OnInit, OnChanges { if (this.initialized.vehicle) { return; } - let vehicleKillCountBlufor = 0, vehicleKillCountOpfor = 0; + let vehicleKillCountBlufor = 0, vehicleKillCountOpfor = 0, vehicleLightCountBlufor = 0, vehicleHeavyCountBlufor = 0, + vehicleAirCountBlufor = 0, vehicleLightCountOpfor = 0, vehicleHeavyCountOpfor = 0, vehicleAirCountOpfor = 0; for (const {transportEntry: vehicleEntry, index} of this.logData.vehicle.map((transport, pos) => ({ transportEntry: transport, index: pos @@ -267,12 +269,40 @@ export class FractionStatsComponent implements OnInit, OnChanges { const vehicleEntryDate = new Date(vehicleEntry.time); if (vehicleEntry.fraction === 'BLUFOR') { vehicleKillCountBlufor++; + switch (vehicleEntry.vehicleClass) { + case 'LIGHT': + vehicleLightCountBlufor++; + break; + case 'HEAVY': + vehicleHeavyCountBlufor++; + break; + case 'AIR': + vehicleAirCountBlufor++; + break; + } } else { vehicleKillCountOpfor++; + switch (vehicleEntry.vehicleClass) { + case 'LIGHT': + vehicleLightCountOpfor++; + break; + case 'HEAVY': + vehicleHeavyCountOpfor++; + break; + case 'AIR': + vehicleAirCountOpfor++; + break; + } } if (this.isTwoMinutesAhead(vehicleEntryDate, this.tmpVehicleData) || index === this.logData.vehicle.length - 1) { this.tmpVehicleData[0].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleKillCountBlufor)); this.tmpVehicleData[1].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleKillCountOpfor)); + this.tmpVehicleData[2].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleLightCountBlufor)); + this.tmpVehicleData[3].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleLightCountOpfor)); + this.tmpVehicleData[4].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleHeavyCountBlufor)); + this.tmpVehicleData[5].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleHeavyCountOpfor)); + this.tmpVehicleData[6].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleAirCountBlufor)); + this.tmpVehicleData[7].series.push(ChartUtils.getSeriesEntry(vehicleEntryDate, vehicleAirCountOpfor)); } } this.addFinalTimeData(this.tmpVehicleData); @@ -336,7 +366,9 @@ export class FractionStatsComponent implements OnInit, OnChanges { this.tmpBudgetData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpKillData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpFrienlyFireData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); - this.tmpVehicleData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); + this.tmpVehicleData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR, + Fraction.BLUFOR.concat(' Leicht'), Fraction.OPFOR.concat(' Leicht'), Fraction.BLUFOR.concat(' Schwer'), + Fraction.OPFOR.concat(' Schwer'), Fraction.BLUFOR.concat(' Luft'), Fraction.OPFOR.concat(' Luft')); this.tmpTransportData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpReviveData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpStabilizeData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); @@ -358,7 +390,7 @@ export class FractionStatsComponent implements OnInit, OnChanges { this.tmpBudgetData[0].series.push(ChartUtils.getSeriesEntry(endDate, this.war.endBudgetBlufor)); this.tmpBudgetData[1].series.push(ChartUtils.getSeriesEntry(endDate, this.war.endBudgetOpfor)); } else { - for (const j in [0, 1]) { + for (let j = 0; j < tmpCollection.length; j++) { if (tmpCollection[j].series[tmpCollection[j].series.length - 1].name < endDate) { tmpCollection[j].series.push( ChartUtils.getSeriesEntry(endDate, tmpCollection[j].series[tmpCollection[j].series.length - 1].value) @@ -367,5 +399,4 @@ export class FractionStatsComponent implements OnInit, OnChanges { } } } - } diff --git a/static/src/app/statistic/war/scoreboard/scoreboard.component.ts b/static/src/app/statistic/war/scoreboard/scoreboard.component.ts index ac2b5b3..aa05ffd 100644 --- a/static/src/app/statistic/war/scoreboard/scoreboard.component.ts +++ b/static/src/app/statistic/war/scoreboard/scoreboard.component.ts @@ -71,7 +71,7 @@ export class ScoreboardComponent implements OnChanges { exportCSV() { let csvOut = ''; for (let i = 0; i < this.tableHead.length; i++) { - csvOut += this.tableHead[i]; + csvOut += this.tableHead[i].head; if (i !== this.tableHead.length - 1) { csvOut += ','; } diff --git a/static/src/app/users/award-user/award-user.component.html b/static/src/app/users/award-user/award-user.component.html index 9ff5fdc..12633ab 100644 --- a/static/src/app/users/award-user/award-user.component.html +++ b/static/src/app/users/award-user/award-user.component.html @@ -73,7 +73,9 @@ Begründung Datum Status - + + Löschen + @@ -94,10 +96,15 @@ {{award.date | date: 'dd.MM.yyyy'}} - {{award.confirmed === 0? 'In Bearbeitung' : (award.confirmed === 1? 'Genehmigt' : 'Abgelehnt')}} + {{award.confirmed === 0 ? 'In Bearbeitung' : (award.confirmed === 1 ? 'Genehmigt' : 'Abgelehnt')}} - + diff --git a/static/src/app/users/award-user/award-user.component.ts b/static/src/app/users/award-user/award-user.component.ts index e826195..2429a42 100644 --- a/static/src/app/users/award-user/award-user.component.ts +++ b/static/src/app/users/award-user/award-user.component.ts @@ -51,7 +51,6 @@ export class AwardUserComponent implements OnInit { .subscribe(id => this.userId = id); } - toggleDecoPreview(descriptionField, decorationId, image) { if (decorationId !== '0') { this.decoPreviewDisplay = 'flex'; // visible & keep same height for all children @@ -72,10 +71,10 @@ export class AwardUserComponent implements OnInit { const reason = reasonField.value; if (decorationId && reason.length > 0) { const award = { - 'userId': this.userId, - 'decorationId': decorationId, - 'reason': reason, - 'date': Date.now() + userId: this.userId, + decorationId: decorationId, + reason: reason, + date: Date.now() }; this.awardingService.addAwarding(award).subscribe(() => { this.awardingService.getUserAwardings(this.userId) @@ -93,22 +92,28 @@ export class AwardUserComponent implements OnInit { } } - deleteAwarding(awardingId) { - this.awardingService.deleteAwarding(awardingId).subscribe((res) => { - this.awardingService.getUserAwardings(this.userId) - .subscribe((awards) => { - this.awards = awards; - this.showSuccessLabel = true; - setTimeout(() => { - this.showSuccessLabel = false; - }, 2000); - }); - }); + deleteAwarding() { + const checkedAwardings = this.awards.filter(award => award['checked'] === true); + + if (checkedAwardings.length > 0) { + checkedAwardings.forEach(awarding => { + this.awardingService.deleteAwarding(awarding._id).subscribe((res) => { + this.awardingService.getUserAwardings(this.userId) + .subscribe((awards) => { + this.awards = awards; + }); + }); + }); + + this.showSuccessLabel = true; + setTimeout(() => { + this.showSuccessLabel = false; + }, 4000); + } } cancel() { this.router.navigate(['../..'], {relativeTo: this.route}); return false; } - } diff --git a/static/src/app/users/edit-user/edit-user.component.ts b/static/src/app/users/edit-user/edit-user.component.ts index 733c5b9..1cad7ae 100644 --- a/static/src/app/users/edit-user/edit-user.component.ts +++ b/static/src/app/users/edit-user/edit-user.component.ts @@ -53,10 +53,12 @@ export class EditUserComponent implements OnInit { user.squadId = '0'; this.ranksDisplay = 'none'; } else { - this.rankService.findRanks('', user.squadId.fraction).subscribe(ranks => { - this.ranks = ranks; - this.ranksDisplay = 'block'; - }); + this.rankService + .findRanks('', user.squadId.fraction) + .subscribe(ranks => { + this.ranks = ranks; + this.ranksDisplay = 'block'; + }); } this.user = user; }); @@ -68,12 +70,14 @@ export class EditUserComponent implements OnInit { toggleRanks() { if (this.user.squadId !== '0') { - this.rankService.findRanks('', this.user.squadId.fraction).subscribe( - ranks => { - this.ranks = ranks; - this.ranksDisplay = 'block'; - } - ); + this.rankService + .findRanks('', this.user.squadId.fraction) + .subscribe( + ranks => { + this.ranks = ranks; + this.ranksDisplay = 'block'; + } + ); } else { this.ranksDisplay = 'none'; } diff --git a/static/src/app/users/user-list/user-item.component.ts b/static/src/app/users/user-list/user-item.component.ts index 122afa7..9da5bb6 100644 --- a/static/src/app/users/user-list/user-item.component.ts +++ b/static/src/app/users/user-list/user-item.component.ts @@ -34,6 +34,5 @@ export class UserItemComponent { delete() { this.userDelete.emit(this.user); } - } diff --git a/static/src/app/users/user-list/user-list.component.ts b/static/src/app/users/user-list/user-list.component.ts index 3f4aec7..a4be69f 100644 --- a/static/src/app/users/user-list/user-list.component.ts +++ b/static/src/app/users/user-list/user-list.component.ts @@ -41,7 +41,6 @@ export class UserListComponent implements OnInit { } ngOnInit() { - this.users$ = this.userService.users$; const paramsStream = this.route.queryParams @@ -106,5 +105,4 @@ export class UserListComponent implements OnInit { this.location.replaceState(absoluteUrl, queryPart); } - } diff --git a/static/src/app/utils/fraction.enum.ts b/static/src/app/utils/fraction.enum.ts index 83b0825..23aa8c1 100644 --- a/static/src/app/utils/fraction.enum.ts +++ b/static/src/app/utils/fraction.enum.ts @@ -2,5 +2,11 @@ export enum Fraction { BLUFOR = 'NATO', OPFOR = 'CSAT', COLOR_BLUFOR = '#0000FF', - COLOR_OPFOR = '#B22222' + COLOR_BLUFOR_LIGHT = '#6666dd', + COLOR_BLUFOR_DARK = '#0C0CA6', + COLOR_BLUFOR_GREY = '#515179', + COLOR_OPFOR = '#B22222', + COLOR_OPFOR_DARK = '#890F0F', + COLOR_OPFOR_LIGHT = '#fb5555', + COLOR_OPFOR_GREY = '#955c5f' }