From bd0489d6c2e5b5d4015fa72a675d709531d0ecfb Mon Sep 17 00:00:00 2001 From: HardiReady Date: Sun, 22 Apr 2018 13:31:38 +0200 Subject: [PATCH 01/28] Use custom table header for scoreboard --- .../scoreboard/scoreboard.component.css | 2 +- .../scoreboard/scoreboard.component.html | 92 ++++++++++++++++-- .../scoreboard/scoreboard.component.ts | 2 + .../war-detail/war-detail.component.css | 2 +- static/src/assets/tank.png | Bin 0 -> 546 bytes 5 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 static/src/assets/tank.png diff --git a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.css b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.css index 741bd71..97c9a5f 100644 --- a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.css +++ b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.css @@ -5,7 +5,7 @@ /* ########### DATATABLE ########### */ ngx-datatable { - width: 1040px; + width: 940px; margin: auto; height: 68vh; } diff --git a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html index 061f789..d1e9c46 100644 --- a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html +++ b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html @@ -18,20 +18,92 @@ - + {{value === 'BLUFOR' ? fraction.BLUFOR : fraction.OPFOR}} - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts index a1dbfa6..316a561 100644 --- a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts +++ b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts @@ -26,6 +26,8 @@ export class ScoreboardComponent implements OnChanges { cellHeight = 40; + columnWidth = 65; + rows = []; reorderable = false; diff --git a/static/src/app/statistic/war-detail/war-detail.component.css b/static/src/app/statistic/war-detail/war-detail.component.css index c656ac1..9f7a896 100644 --- a/static/src/app/statistic/war-detail/war-detail.component.css +++ b/static/src/app/statistic/war-detail/war-detail.component.css @@ -28,7 +28,7 @@ span.tab-control { } .nav-tabs { - width: 980px; + width: 920px; margin: auto; clear: both; border-bottom: 0; diff --git a/static/src/assets/tank.png b/static/src/assets/tank.png new file mode 100644 index 0000000000000000000000000000000000000000..4d03cc9ff65184912750d9463882c164d337445d GIT binary patch literal 546 zcmV+-0^R+IP)2c_z{8}T8K>=3$aroHi8h;%EBrjmI18= zZS2HWu~1793Hk>pVzALBpddl3NQj6YNG_2CH4%c3g>&IG-r*JAVevlA&hF0a&hF0s zproXvqzlybwq>`Q?{yOOg1t|@pbq!z?#6rgeR3f5f*MMq7EZhA9e*<0uw}218BJd>>2;h4} zG&crSTI)vy>V7qVNnlDH08Rk+fa$*^Fa=BiW56gd5)tnsq7e}vBcj>yENWG~>%Zr# zI+8^@)Ug)Si}sdfbxyrm*fWX=oV33@U9Y=B682f&h9Y9AQW!V@%=JoAHuTrBSpTSn zJB4eSP?ywc^{Vm*`qI1;BzY9?(~}lex!WQ kM8t!3id#}rQu1H$6H7t)&9Cq_&Hw-a07*qoM6N<$f*p(cIsgCw literal 0 HcmV?d00001 From 835af7b2d349b9866a2e184947ffa319a196365e Mon Sep 17 00:00:00 2001 From: HardiReady Date: Tue, 24 Apr 2018 19:14:10 +0200 Subject: [PATCH 02/28] Add vehicle icons --- .../scoreboard/scoreboard.component.html | 6 +++--- static/src/assets/scoreboard/vair.png | Bin 0 -> 716 bytes static/src/assets/scoreboard/vheavy.png | Bin 0 -> 457 bytes static/src/assets/scoreboard/vlight.png | Bin 0 -> 498 bytes 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 static/src/assets/scoreboard/vair.png create mode 100644 static/src/assets/scoreboard/vheavy.png create mode 100644 static/src/assets/scoreboard/vlight.png diff --git a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html index d1e9c46..7f80d9b 100644 --- a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html +++ b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html @@ -45,7 +45,7 @@ - + @@ -54,7 +54,7 @@ - + @@ -63,7 +63,7 @@ - + diff --git a/static/src/assets/scoreboard/vair.png b/static/src/assets/scoreboard/vair.png new file mode 100644 index 0000000000000000000000000000000000000000..b3c409755f288b5c7d807f54e8a9c6e0993866a4 GIT binary patch literal 716 zcmV;-0yF)IP)kdg00002VoOIv0RM-N z%)bBt0)S_p~pJ(Th9QH$31pT4`izNJ;47NgrSV z*VO-EdUlf*hguf=J~sM**B#DvaD>X3^`QrIlIcv~erN&%7Z^edSHtD5QziW9E~X24 zmD}e_UFR?WXM57yw%XxM;#J$O(KtNO>AI2!9;o%auw9(;cd6gCl&*E$j4Si zPhW$peHH;fW3yMS^{`1WVSl1_QpUg{52{~mu_MF1(zLO6)%u8y)q5Q{-x~M$qf5a= z00;TVCB1CVT_{2|mv~JZ%SrN`PKqdDM0l4ynEne83#lj{imb8}tg^;&j&hB+Oyu6y ykY2X_>r>V(HVdLLYVnS(Z2x~PB%xOkdg00002VoOIv0RM-N z%)bBt0fI?HK~zY`?Ulbvl~EYSKj%o@!W1(oaj-k6NjU{YQ&?M5)X)?-1#UX^54bdl zOH0ubZ7vZwMOZ^qLnd5_Z$u!>fdF_ z5`Zlmyz+}r>;}kMGC1Zl*VN|@Wk*}3=yb%7>ayc4jkAsJE$7s#_bu<#dmV7l{&QqlX?MoAhy}Cg3`YeBfo6-Ai!U!pctO1mGIog~RWN8xR4ifk%Ze zPbCa{Iwt^MbFC->KX@AQXiiX}T$tlcWG9TU!FiSn8_b1$R5!WA7^j+SuX^<_7aDwE zVrtqj$rX>++E3Zr-fL)Zz0v!etkYceF=T{#DW#!pg6Thso6IxMdlpz{g{@G}03?vM z$A`32VUf@8K3&P5;xCRgv*z@G<O|Ca06817q;p$00000NkvXXu0mjfoMF=_ literal 0 HcmV?d00001 diff --git a/static/src/assets/scoreboard/vlight.png b/static/src/assets/scoreboard/vlight.png new file mode 100644 index 0000000000000000000000000000000000000000..f96487b0e6e01d9f5af5ed93015674445a27dce8 GIT binary patch literal 498 zcmVkdg00002VoOIv0RM-N z%)bBt0jo(wK~zY`-Ic#f)NvTcU!U*y$h*2sL$p(rh#&`TD#9s*2-<4x4~Phd7Kf&2 zZfHqpa%gC1u^}8XaA>e1sAz}~8>E^dql@tFtGpWSI{aGad0%zu89$%rdGUFEyq^#3 zy}1jB{YEgEMwyL7elCeRr_! z-V1m`O?>6F`OTiWW~K2u52(^h!Sh^3V&-_l5m)HrOZd4(5hVaF(t-4m&brJu26)I* z-h|iw9bS97C!Fx3bE^Jw-GAHFR0=g(0G#9k<9y{*i$V=;02nji7-N(uGEM>Lsk;@n zrsM#;!URJcYO}u)2=-exo4s@dA_A)!MS7ZB5RveMwTxS1#C;K6yx=`aCP0b)9D`gU zpMBXxJfoLN#^{(h3RNm>Po($gVVL7wYn;4gwWhY)8=AA^ly_WCHEhv$&f49W+67e; z3-uxPm@9SHHID*#HU&77(o685k9_XMx^@IS=}qr@*U^TcmKx!YTW$?E9ST@-!DT-= oZ?TObF@>?q!-ie?oBnJ24O1FEc4|^c6aWAK07*qoM6N<$f Date: Thu, 26 Apr 2018 12:26:07 +0200 Subject: [PATCH 03/28] loop over scoreboard values from array --- .../scoreboard/scoreboard.component.html | 92 +++--------------- .../scoreboard/scoreboard.component.ts | 9 +- .../scoreboard/{vair.png => vehicleAir.png} | Bin static/src/assets/scoreboard/vehicleHeavy.png | Bin 0 -> 567 bytes .../{vlight.png => vehicleLight.png} | Bin static/src/assets/scoreboard/vheavy.png | Bin 457 -> 0 bytes 6 files changed, 19 insertions(+), 82 deletions(-) rename static/src/assets/scoreboard/{vair.png => vehicleAir.png} (100%) create mode 100644 static/src/assets/scoreboard/vehicleHeavy.png rename static/src/assets/scoreboard/{vlight.png => vehicleLight.png} (100%) delete mode 100644 static/src/assets/scoreboard/vheavy.png diff --git a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html index 7f80d9b..5284f6e 100644 --- a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html +++ b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html @@ -10,7 +10,7 @@ [columnMode]="'force'" [scrollbarV]="true" [selectionType]="'single'"> - + @@ -18,92 +18,24 @@ - + {{value === 'BLUFOR' ? fraction.BLUFOR : fraction.OPFOR}} - - + +
+ + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
+ diff --git a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts index 316a561..0ced99b 100644 --- a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts +++ b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.ts @@ -19,8 +19,13 @@ export class ScoreboardComponent implements OnChanges { @Output() playerTabSwitch = new EventEmitter(); - tableHead = ['Spieler', 'Fraktion', 'Kills', 'FF', 'Fzg(L)', 'Fzg(H)', 'Fzg(A)', - 'Revive', 'Flagge', 'Tod', 'Respawn']; + tableHead = [ + {prop: 'name', head: 'Spieler'}, {prop: 'fraction', head: 'Fraktion'}, {prop: 'kill', head: 'Kills'}, + {prop: 'friendlyFire', head: 'FriendlyFire'}, {prop: 'vehicleLight', head: 'Fahrzeug (leicht)'}, + {prop: 'vehicleHeavy', head: 'Fahrzeug (schwer)'}, {prop: 'vehicleAir', head: 'Fahrzeug (Luft)'}, + {prop: 'revive', head: 'Revive'}, {prop: 'flagTouch', head: 'Flagge'}, {prop: 'death', head: 'Tod'}, + {prop: 'respawn', head: 'Respawn'} + ]; isSteamUUID = PlayerUtils.isSteamUUID; diff --git a/static/src/assets/scoreboard/vair.png b/static/src/assets/scoreboard/vehicleAir.png similarity index 100% rename from static/src/assets/scoreboard/vair.png rename to static/src/assets/scoreboard/vehicleAir.png diff --git a/static/src/assets/scoreboard/vehicleHeavy.png b/static/src/assets/scoreboard/vehicleHeavy.png new file mode 100644 index 0000000000000000000000000000000000000000..f0ec30cb6ff408d39946a359f07148b9c481f238 GIT binary patch literal 567 zcmV-70?7S|P)X4$%!G6fPn;TEEEK>Rg0*FU}dFNimi>H z{sKE8rH#FfKOkMIAYzeND2kFsf?yDX8178&ZokJOdm2pQnS=w2ePG#b=9~AMnRgZ{ zDk>`eH`==A*iISS*~J-=^c3(ASQTb7m>0eaU-F3Nc0ub(00R--gogsg1#1zDy^t@(2Xq2Ht1H3_U>10p;A<_Sai9!t=^$`EgS)^bV7Abkz(@u^3WyAj z7qF0nLMMYpM5JF8*sN?#2M1t6m<%`_a2c2c#(+A|1eSnz!t;PR;b6cFFe)?yhPJyj z&?-M3=MneI3-s>MM~y;93LQ^+QazjWj=JCmZFfPT)7`V}CE!nmP0b4(OB*6u?u{k& zbt;Q{kvyWYrHr)*+Ipgo$#KI8jkMDcc62!DZTmo>Pdhriqq<^~szPt5AJnwZ zyr0x(Ej_wr758#Mp@##`0LOs3keBVbSUO@l;NA|Uej_{pUgZ(XU2At&_`Vs_D0lmH zbx~bbSJZj+N?-q)t7WU&zu!Yi#|xc&Ukakdg00002VoOIv0RM-N z%)bBt0fI?HK~zY`?Ulbvl~EYSKj%o@!W1(oaj-k6NjU{YQ&?M5)X)?-1#UX^54bdl zOH0ubZ7vZwMOZ^qLnd5_Z$u!>fdF_ z5`Zlmyz+}r>;}kMGC1Zl*VN|@Wk*}3=yb%7>ayc4jkAsJE$7s#_bu<#dmV7l{&QqlX?MoAhy}Cg3`YeBfo6-Ai!U!pctO1mGIog~RWN8xR4ifk%Ze zPbCa{Iwt^MbFC->KX@AQXiiX}T$tlcWG9TU!FiSn8_b1$R5!WA7^j+SuX^<_7aDwE zVrtqj$rX>++E3Zr-fL)Zz0v!etkYceF=T{#DW#!pg6Thso6IxMdlpz{g{@G}03?vM z$A`32VUf@8K3&P5;xCRgv*z@G<O|Ca06817q;p$00000NkvXXu0mjfoMF=_ From dd7bce59e375d4aa84216be20695e143e1d76a27 Mon Sep 17 00:00:00 2001 From: HardiReady Date: Fri, 27 Apr 2018 09:03:57 +0200 Subject: [PATCH 04/28] Simplify logic for player campaign detail page init --- package.json | 2 +- .../campaign-player-detail.component.html | 168 +----------------- .../campaign-player-detail.component.ts | 124 ++++++------- .../scoreboard/scoreboard.component.html | 8 +- 4 files changed, 70 insertions(+), 232 deletions(-) diff --git a/package.json b/package.json index 5658cf1..68b3332 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opt-cc", - "version": "1.7.3", + "version": "1.7.4", "author": "Florian Hartwich ", "private": true, "scripts": { diff --git a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.html b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.html index 2e682c5..51fb3e7 100644 --- a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.html +++ b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.html @@ -41,12 +41,12 @@
-
+
- -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- diff --git a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts index acecd7d..938579b 100644 --- a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts +++ b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts @@ -20,16 +20,8 @@ export class CampaignPlayerDetailComponent implements OnInit { campaignPlayer: CampaignPlayer = {campaign: {}, players: []}; + graphData: any[] = []; sumData: any[] = []; - killData: any[] = []; - friendlyFireData: any[] = []; - vehicleLightData: any[] = []; - vehicleHeavyData: any[] = []; - vehicleAirData: any[] = []; - deathData: any[] = []; - respawnData: any[] = []; - reviveData: any[] = []; - captureData: any[] = []; yAxisKill = 'Kills'; yAxisFriendlyFire = 'FriendlyFire'; @@ -96,15 +88,63 @@ export class CampaignPlayerDetailComponent implements OnInit { this.playerService.getCampaignPlayer(this.campaignId, encodeURIComponent(this.playerName)) .subscribe(campaignPlayer => { this.campaignPlayer = campaignPlayer; - this.killData = this.assignData(this.yAxisKill, 'kill'); - this.friendlyFireData = this.assignData(this.yAxisFriendlyFire, 'friendlyFire'); - this.deathData = this.assignData(this.yAxisDeath, 'death'); - this.respawnData = this.assignData(this.yAxisRespawn, 'respawn'); - this.reviveData = this.assignData(this.yAxisRevive, 'revive'); - this.captureData = this.assignData(this.yAxisCapture, 'flagTouch'); - this.vehicleLightData = this.assignData(this.yAxisVehicleLight, 'vehicleLight'); - this.vehicleHeavyData = this.assignData(this.yAxisVehicleHeavy, 'vehicleHeavy'); - this.vehicleAirData = this.assignData(this.yAxisVehicleAir, 'vehicleAir'); + + this.graphData = [ + { + data: this.assignData(this.yAxisKill, 'kill'), + refLine: this.killRefLines, + label: this.yAxisKill, + total: this.totalKills + }, + { + data: this.assignData(this.yAxisFriendlyFire, 'friendlyFire'), + refLine: this.friendlyFireRefLines, + label: this.yAxisFriendlyFire, + total: this.totalFriendlyFire + }, + { + data: this.assignData(this.yAxisDeath, 'death'), + refLine: this.deathRefLines, + label: this.yAxisDeath, + total: this.totalDeath + }, + { + data: this.assignData(this.yAxisRespawn, 'respawn'), + refLine: this.respawnRefLines, + label: this.yAxisRespawn, + total: this.totalRespawn + }, + { + data: this.assignData(this.yAxisRevive, 'revive'), + refLine: this.reviveRefLines, + label: this.yAxisRevive, + total: this.totalRevive + }, + { + data: this.assignData(this.yAxisCapture, 'flagTouch'), + refLine: this.captureRefLines, + label: this.yAxisCapture, + total: this.totalCapture + }, + { + data: this.assignData(this.yAxisVehicleLight, 'vehicleLight'), + refLine: this.vehicleLightRefLines, + label: this.yAxisVehicleLight, + total: this.totalVehicleLight + }, + { + data: this.assignData(this.yAxisVehicleHeavy, 'vehicleHeavy'), + refLine: this.vehicleHeavyRefLines, + label: this.yAxisVehicleHeavy, + total: this.totalVehicleHeavy + }, + { + data: this.assignData(this.yAxisVehicleAir, 'vehicleAir'), + refLine: this.vehicleAirRefLines, + label: this.yAxisVehicleAir, + total: this.totalVehicleAir + }, + ]; const totalDeathDiv = this.totalDeath === 0 ? 1 : this.totalDeath; this.kdRatio = parseFloat((this.totalKills / totalDeathDiv).toFixed(2)); @@ -114,48 +154,12 @@ export class CampaignPlayerDetailComponent implements OnInit { this.respawnDeathRatio = parseFloat((this.totalRespawn / totalDeathDiv).toFixed(2)); - this.sumData = [ - { - name: this.yAxisKill, - value: this.totalKills - }, - { - name: this.yAxisFriendlyFire, - value: this.totalFriendlyFire - }, - { - name: this.yAxisDeath, - value: this.totalDeath - }, - { - name: this.yAxisRespawn, - value: this.totalRespawn - }, - { - name: this.yAxisRevive, - value: this.totalRevive - }, - { - name: this.yAxisCapture, - value: this.totalCapture - }, - { - name: this.yAxisVehicleLight, - value: this.totalVehicleLight - }, - { - name: this.yAxisVehicleHeavy, - value: this.totalVehicleHeavy - }, - { - name: this.yAxisVehicleAir, - value: this.totalVehicleAir - }, - ]; - - Object.assign(this, [this.sumData, this.killData, this.friendlyFireData, this.vehicleLightData, - this.vehicleHeavyData, this.vehicleAirData, this.deathData, this.respawnData, this.reviveData, - this.captureData]); + // we can not directly push to target array, since only full reference changes trigger the refresh of data + const tmpSumData = []; + this.graphData.forEach(dataSet => { + tmpSumData.push({name: dataSet.label, value: dataSet.total}) + }); + this.sumData = tmpSumData; }); } diff --git a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html index 5284f6e..5a8595b 100644 --- a/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html +++ b/static/src/app/statistic/war-detail/scoreboard/scoreboard.component.html @@ -29,18 +29,12 @@ - + {{column.head}}
- - - - - - Date: Fri, 27 Apr 2018 09:23:43 +0200 Subject: [PATCH 05/28] Simplify logic for player campaign detail page init --- .../campaign-player-detail.component.ts | 179 ++++-------------- 1 file changed, 37 insertions(+), 142 deletions(-) diff --git a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts index 938579b..9990006 100644 --- a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts +++ b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts @@ -23,15 +23,6 @@ export class CampaignPlayerDetailComponent implements OnInit { graphData: any[] = []; sumData: any[] = []; - yAxisKill = 'Kills'; - yAxisFriendlyFire = 'FriendlyFire'; - yAxisVehicleLight = 'Fahrzeug (Light)'; - yAxisVehicleHeavy = 'Fahrzeug (Heavy)'; - yAxisVehicleAir = 'Fahrzeug (Air)'; - yAxisDeath = 'Tode'; - yAxisRespawn = 'Respawn'; - yAxisRevive = 'Revive'; - yAxisCapture = 'Eroberungen'; avgLabel = 'Durchschnitt'; colorScheme = { @@ -44,16 +35,6 @@ export class CampaignPlayerDetailComponent implements OnInit { }; showRefLines = true; showRefLabels = true; - killRefLines = []; - vehicleLightRefLines = []; - vehicleHeavyRefLines = []; - vehicleAirRefLines = []; - deathRefLines = []; - captureRefLines = []; - friendlyFireRefLines = []; - reviveRefLines = []; - respawnRefLines = []; - gradient = false; xAxis = true; yAxis = true; @@ -64,23 +45,12 @@ export class CampaignPlayerDetailComponent implements OnInit { timeline = false; roundDomains = true; - totalKills; - totalFriendlyFire; - totalVehicleLight; - totalVehicleHeavy; - totalVehicleAir; - totalDeath; - totalRespawn; - totalRevive; - totalCapture; - kdRatio = 0; maxKd = 1.7; respawnDeathRatio = 0; maxRespawnDeathRatio = 1; - constructor(private playerService: PlayerService) { } @@ -90,69 +60,26 @@ export class CampaignPlayerDetailComponent implements OnInit { this.campaignPlayer = campaignPlayer; this.graphData = [ - { - data: this.assignData(this.yAxisKill, 'kill'), - refLine: this.killRefLines, - label: this.yAxisKill, - total: this.totalKills - }, - { - data: this.assignData(this.yAxisFriendlyFire, 'friendlyFire'), - refLine: this.friendlyFireRefLines, - label: this.yAxisFriendlyFire, - total: this.totalFriendlyFire - }, - { - data: this.assignData(this.yAxisDeath, 'death'), - refLine: this.deathRefLines, - label: this.yAxisDeath, - total: this.totalDeath - }, - { - data: this.assignData(this.yAxisRespawn, 'respawn'), - refLine: this.respawnRefLines, - label: this.yAxisRespawn, - total: this.totalRespawn - }, - { - data: this.assignData(this.yAxisRevive, 'revive'), - refLine: this.reviveRefLines, - label: this.yAxisRevive, - total: this.totalRevive - }, - { - data: this.assignData(this.yAxisCapture, 'flagTouch'), - refLine: this.captureRefLines, - label: this.yAxisCapture, - total: this.totalCapture - }, - { - data: this.assignData(this.yAxisVehicleLight, 'vehicleLight'), - refLine: this.vehicleLightRefLines, - label: this.yAxisVehicleLight, - total: this.totalVehicleLight - }, - { - data: this.assignData(this.yAxisVehicleHeavy, 'vehicleHeavy'), - refLine: this.vehicleHeavyRefLines, - label: this.yAxisVehicleHeavy, - total: this.totalVehicleHeavy - }, - { - data: this.assignData(this.yAxisVehicleAir, 'vehicleAir'), - refLine: this.vehicleAirRefLines, - label: this.yAxisVehicleAir, - total: this.totalVehicleAir - }, + {key: 'kill', label: 'Kills',}, + {key: 'friendlyFire', label: 'Friendly Fire',}, + {key: 'death', label: 'Tode',}, + {key: 'respawn', label: 'Respawn',}, + {key: 'revive', label: 'Revive',}, + {key: 'flagTouch', label: 'Eroberungen',}, + {key: 'vehicleLight', label: 'Fahrzeug (Leicht)',}, + {key: 'vehicleHeavy', label: 'Fahrzeug (Schwer)',}, + {key: 'vehicleAir', label: 'Fahrzeug (Luft)',}, ]; - const totalDeathDiv = this.totalDeath === 0 ? 1 : this.totalDeath; - this.kdRatio = parseFloat((this.totalKills / totalDeathDiv).toFixed(2)); + this.initDataArray(); + + const totalDeathDiv = this.graphData[2].total === 0 ? 1 : this.graphData[2].total; + this.kdRatio = parseFloat((this.graphData[0].total / totalDeathDiv).toFixed(2)); if (this.kdRatio > 1) { this.maxKd = this.kdRatio * 1.7; } - this.respawnDeathRatio = parseFloat((this.totalRespawn / totalDeathDiv).toFixed(2)); + this.respawnDeathRatio = parseFloat((this.graphData[3].total / totalDeathDiv).toFixed(2)); // we can not directly push to target array, since only full reference changes trigger the refresh of data const tmpSumData = []; @@ -163,61 +90,29 @@ export class CampaignPlayerDetailComponent implements OnInit { }); } - private assignData(label, field) { - const killObj = { - name: label, - series: [] - }; - const playerLength = this.campaignPlayer.players.length; - let total = 0; - for (let i = 0; i < playerLength; i++) { - const warDateString = ChartUtils.getShortDateString(this.campaignPlayer.players[i].warId.date); - const value = this.campaignPlayer.players[i][field]; - killObj.series.push({ - name: warDateString, - value: value - }); - total += value; - } - switch (field) { - case 'kill': - this.killRefLines.push({value: total / playerLength, name: this.avgLabel}); - this.totalKills = total; - break; - case 'friendlyFire': - this.friendlyFireRefLines.push({value: total / playerLength, name: this.avgLabel}); - this.totalFriendlyFire = total; - break; - case 'death': - this.deathRefLines.push({value: total / playerLength, name: this.avgLabel}); - this.totalDeath = total; - break; - case 'respawn': - this.respawnRefLines.push({value: total / playerLength, name: this.avgLabel}); - this.totalRespawn = total; - break; - case 'revive': - this.reviveRefLines.push({value: total / playerLength, name: this.avgLabel}); - this.totalRevive = total; - break; - case 'flagTouch': - this.captureRefLines.push({value: total / playerLength, name: this.avgLabel}); - this.totalCapture = total; - break; - case 'vehicleLight': - this.vehicleLightRefLines.push({value: total / playerLength, name: this.avgLabel}); - this.totalVehicleLight = total; - break; - case 'vehicleHeavy': - this.vehicleHeavyRefLines.push({value: total / playerLength, name: this.avgLabel}); - this.totalVehicleHeavy = total; - break; - case 'vehicleAir': - this.vehicleAirRefLines.push({value: total / playerLength, name: this.avgLabel}); - this.totalVehicleAir = total; - break; - } - return [killObj]; + private initDataArray() { + + this.graphData.forEach(dataSet => { + const killObj = { + name: dataSet.label, + series: [] + }; + const playerLength = this.campaignPlayer.players.length; + let total = 0; + for (let i = 0; i < playerLength; i++) { + const warDateString = ChartUtils.getShortDateString(this.campaignPlayer.players[i].warId.date); + const value = this.campaignPlayer.players[i][dataSet.key]; + killObj.series.push({ + name: warDateString, + value: value + }); + total += value; + } + + dataSet.data = [killObj]; + dataSet.refLine = [{value: total / playerLength, name: this.avgLabel}] + dataSet.total = total; + }) } navigateBack() { From 2cd7541ca6c77f006a466f0827ba52abc7504e93 Mon Sep 17 00:00:00 2001 From: HardiReady Date: Fri, 27 Apr 2018 09:29:30 +0200 Subject: [PATCH 06/28] Fix linting, update codestyle file --- ...ellij-idea-javascript-typescript-style.xml | 4 ++- .../campaign-player-detail.component.ts | 26 +++++++++---------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml b/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml index c75b1af..e1c7def 100644 --- a/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml +++ b/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml @@ -1,6 +1,7 @@ + \ No newline at end of file diff --git a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts index 9990006..7329f6e 100644 --- a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts +++ b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts @@ -18,7 +18,7 @@ export class CampaignPlayerDetailComponent implements OnInit { @Output() switchTab = new EventEmitter(); - campaignPlayer: CampaignPlayer = {campaign: {}, players: []}; + campaignPlayer: CampaignPlayer = { campaign: {}, players: [] }; graphData: any[] = []; sumData: any[] = []; @@ -60,15 +60,15 @@ export class CampaignPlayerDetailComponent implements OnInit { this.campaignPlayer = campaignPlayer; this.graphData = [ - {key: 'kill', label: 'Kills',}, - {key: 'friendlyFire', label: 'Friendly Fire',}, - {key: 'death', label: 'Tode',}, - {key: 'respawn', label: 'Respawn',}, - {key: 'revive', label: 'Revive',}, - {key: 'flagTouch', label: 'Eroberungen',}, - {key: 'vehicleLight', label: 'Fahrzeug (Leicht)',}, - {key: 'vehicleHeavy', label: 'Fahrzeug (Schwer)',}, - {key: 'vehicleAir', label: 'Fahrzeug (Luft)',}, + { key: 'kill', label: 'Kills', }, + { key: 'friendlyFire', label: 'Friendly Fire', }, + { key: 'death', label: 'Tode', }, + { key: 'respawn', label: 'Respawn', }, + { key: 'revive', label: 'Revive', }, + { key: 'flagTouch', label: 'Eroberungen', }, + { key: 'vehicleLight', label: 'Fahrzeug (Leicht)', }, + { key: 'vehicleHeavy', label: 'Fahrzeug (Schwer)', }, + { key: 'vehicleAir', label: 'Fahrzeug (Luft)', }, ]; this.initDataArray(); @@ -84,7 +84,7 @@ export class CampaignPlayerDetailComponent implements OnInit { // we can not directly push to target array, since only full reference changes trigger the refresh of data const tmpSumData = []; this.graphData.forEach(dataSet => { - tmpSumData.push({name: dataSet.label, value: dataSet.total}) + tmpSumData.push({ name: dataSet.label, value: dataSet.total }); }); this.sumData = tmpSumData; }); @@ -110,9 +110,9 @@ export class CampaignPlayerDetailComponent implements OnInit { } dataSet.data = [killObj]; - dataSet.refLine = [{value: total / playerLength, name: this.avgLabel}] + dataSet.refLine = [{ value: total / playerLength, name: this.avgLabel }]; dataSet.total = total; - }) + }); } navigateBack() { From 6381c1ca86d026f4c0baab720538b33353e1254f Mon Sep 17 00:00:00 2001 From: HardiReady Date: Fri, 27 Apr 2018 15:19:23 +0200 Subject: [PATCH 07/28] Add button for edit campaign --- .../campaign-player-detail.component.ts | 1 - .../statistic/war-list/war-list.component.html | 15 ++++++++++----- .../app/statistic/war-list/war-list.component.ts | 3 +++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts index 7329f6e..d4f112d 100644 --- a/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts +++ b/static/src/app/statistic/campaign-player-detail/campaign-player-detail.component.ts @@ -91,7 +91,6 @@ export class CampaignPlayerDetailComponent implements OnInit { } private initDataArray() { - this.graphData.forEach(dataSet => { const killObj = { name: dataSet.label, diff --git a/static/src/app/statistic/war-list/war-list.component.html b/static/src/app/statistic/war-list/war-list.component.html index 721ef16..c4c1d73 100644 --- a/static/src/app/statistic/war-list/war-list.component.html +++ b/static/src/app/statistic/war-list/war-list.component.html @@ -11,13 +11,18 @@
- {{campaign.title}} - - + + + {{campaign.title}} +
Date: Sat, 28 Apr 2018 10:44:52 +0200 Subject: [PATCH 08/28] Add edit campaign frontend --- .../src/app/services/logs/campaign.service.ts | 17 +++++++++++++---- .../campaign-submit.component.html | 3 ++- .../campaign-submit.component.ts | 11 +++++++++++ static/src/app/statistic/stats.routing.ts | 7 ++++++- .../statistic/war-list/war-list.component.ts | 4 ++-- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/static/src/app/services/logs/campaign.service.ts b/static/src/app/services/logs/campaign.service.ts index 0b5ae55..6d4e806 100644 --- a/static/src/app/services/logs/campaign.service.ts +++ b/static/src/app/services/logs/campaign.service.ts @@ -14,18 +14,27 @@ export class CampaignService { getAllCampaigns() { return this.http.get(this.config.apiWarPath) - .map(res => res.json()); + .map(res => res.json()); } submitCampaign(campaign: Campaign) { - return this.http.post(this.config.apiCampaignPath, campaign) - .map(res => res.json()); + if (campaign._id) { + return this.http.patch(this.config.apiCampaignPath + '/' + campaign._id, campaign); + } else { + return this.http.post(this.config.apiCampaignPath, campaign) + .map(res => res.json()); + } + } deleteCampaign(id: string) { return this.http.delete(this.config.apiCampaignPath + '/' + id) - .map(res => res.json()); + .map(res => res.json()); } + getCampaign(id: string) { + return this.http.get(this.config.apiCampaignPath + '/' + id) + .map(res => res.json()); + } } diff --git a/static/src/app/statistic/campaign-submit/campaign-submit.component.html b/static/src/app/statistic/campaign-submit/campaign-submit.component.html index 771736b..4bd7b3d 100644 --- a/static/src/app/statistic/campaign-submit/campaign-submit.component.html +++ b/static/src/app/statistic/campaign-submit/campaign-submit.component.html @@ -1,5 +1,6 @@
-

Kampagne hinzufügen

+

Kampagne editieren

+

Neue Kampagne hinzufügen

diff --git a/static/src/app/statistic/campaign-submit/campaign-submit.component.ts b/static/src/app/statistic/campaign-submit/campaign-submit.component.ts index 34a9561..588a905 100644 --- a/static/src/app/statistic/campaign-submit/campaign-submit.component.ts +++ b/static/src/app/statistic/campaign-submit/campaign-submit.component.ts @@ -1,6 +1,7 @@ import {Component, ViewChild} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {NgForm} from '@angular/forms'; +import {Subscription} from 'rxjs/Subscription'; import {Campaign} from '../../models/model-interfaces'; import {CampaignService} from '../../services/logs/campaign.service'; @@ -18,11 +19,21 @@ export class CampaignSubmitComponent { error; + subscription: Subscription; + @ViewChild(NgForm) form: NgForm; constructor(private route: ActivatedRoute, private router: Router, private campaignService: CampaignService) { + + this.subscription = this.route.params + .map(params => params['id']) + .filter(id => id !== undefined) + .flatMap(id => this.campaignService.getCampaign(id)) + .subscribe(campaign => { + this.campaign = campaign; + }); } saveCampaign() { diff --git a/static/src/app/statistic/stats.routing.ts b/static/src/app/statistic/stats.routing.ts index 6e39806..8e1823c 100644 --- a/static/src/app/statistic/stats.routing.ts +++ b/static/src/app/statistic/stats.routing.ts @@ -33,7 +33,12 @@ export const statsRoutes: Routes = [{ outlet: 'right' }, { - path: 'new-campaign', + path: 'campaign', + component: CampaignSubmitComponent, + outlet: 'right' + }, + { + path: 'campaign/:id', component: CampaignSubmitComponent, outlet: 'right' }, diff --git a/static/src/app/statistic/war-list/war-list.component.ts b/static/src/app/statistic/war-list/war-list.component.ts index cfd40f2..fb4ebba 100644 --- a/static/src/app/statistic/war-list/war-list.component.ts +++ b/static/src/app/statistic/war-list/war-list.component.ts @@ -46,7 +46,7 @@ export class WarListComponent implements OnInit { selectNewCampaign() { this.selectedWarId = null; - this.router.navigate([{outlets: {'right': ['new-campaign']}}], {relativeTo: this.route}); + this.router.navigate([{outlets: {'right': ['campaign']}}], {relativeTo: this.route}); } selectNewWar() { @@ -100,6 +100,6 @@ export class WarListComponent implements OnInit { } editCampaign(selectCampaign) { - this.router.navigate([{outlets: {'right': ['overview', selectCampaign._id]}}], {relativeTo: this.route}); + this.router.navigate([{outlets: {'right': ['campaign', selectCampaign._id]}}], {relativeTo: this.route}); } } From b40c664bce3aa17b18e5faadde279934f2af223e Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Sat, 28 Apr 2018 11:55:58 +0200 Subject: [PATCH 09/28] add functional endpoint for update campaign and unhappy frontend processing --- api/apib/dredd/data/campaign.json | 1 + api/apib/statistics/campaigns.apib | 19 ++++++++++ api/routes/campaigns.js | 35 +++++++++++++++++-- .../src/app/services/logs/campaign.service.ts | 11 +++--- .../campaign-submit.component.ts | 6 +++- 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/api/apib/dredd/data/campaign.json b/api/apib/dredd/data/campaign.json index 2c31b97..51442c2 100644 --- a/api/apib/dredd/data/campaign.json +++ b/api/apib/dredd/data/campaign.json @@ -1,2 +1,3 @@ {"_id":{"$oid":"5abd55ea9e30a76bfef747d6"},"title":"Ein Kessel Buntes","timestamp":{"$date":"2018-03-29T21:08:58.123Z"},"updatedAt":{"$date":"2018-03-29T21:08:58.123Z"},"__v":0} {"_id":{"$oid":"5abd58989e30a76bfef747e6"},"title":"This Is The End","timestamp":{"$date":"2018-03-29T21:20:24.558Z"},"updatedAt":{"$date":"2018-03-29T21:20:24.558Z"},"__v":0} +{"_id":{"$oid":"5abd58es9e30a76bfef347e4"},"title":"Edit me","timestamp":{"$date":"2018-03-29T21:20:24.558Z"},"updatedAt":{"$date":"2018-03-29T21:20:24.558Z"},"__v":0} diff --git a/api/apib/statistics/campaigns.apib b/api/apib/statistics/campaigns.apib index 915aa26..7915294 100644 --- a/api/apib/statistics/campaigns.apib +++ b/api/apib/statistics/campaigns.apib @@ -24,6 +24,25 @@ Create a new campaign + Attributes (Campaign, fixed-type) +### Update Campaign [PUT /campaigns/{id}] + +Update a campaign, identified by its id + +**Permission: 3** + ++ Parameters + + id: `5abd58es9e30a76bfef347e4` (string, required) - unique id of campaign + ++ Request (application/json) + + + Attributes + + _id: `5abd58es9e30a76bfef347e4` (string, required) - unique id of campaign + + title: `Operation Pandora` (string, optional) - display name of the campaign + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (Campaign, fixed-type) + ### Delete Campaign [DELETE /campaigns/{id}] Delete a campaign diff --git a/api/routes/campaigns.js b/api/routes/campaigns.js index 0cb9c85..f42bb4a 100644 --- a/api/routes/campaigns.js +++ b/api/routes/campaigns.js @@ -16,12 +16,10 @@ const idValidator = require('../middleware/validators').idValidator; const CampaignModel = require('../models/campaign'); const WarModel = require('../models/war'); - const campaigns = new express.Router(); // routes ********************** campaigns.route('/') - .post(apiAuthenticationMiddleware, checkMT, (req, res, next) => { const campaign = new CampaignModel(req.body); // timestamp and default are set automatically by Mongoose Schema Validation @@ -57,6 +55,37 @@ campaigns.route('/:id') }); }) + .patch(apiAuthenticationMiddleware, checkMT, (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 + const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + + req.body._id); + err.status = codes.notfound; + next(err); + return; // prevent node to process this function further after next() has finished. + } + + req.body.updatedAt = new Date(); + req.body.$inc = { __v: 1 }; + if (req.body.hasOwnProperty('__v')) { + delete req.body.__v; + } + + // PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to + // reset attributes that are missing. + CampaignModel.findByIdAndUpdate(req.params.id, req.body, { new: true }, (err, item) => { + if (err) { + err.status = codes.wrongrequest; + } else if (!item) { + err = new Error('item not found'); + err.status = codes.notfound; + } else { + res.locals.items = item; + } + next(err); + }); + }) + .delete((req, res, next) => { CampaignModel.findByIdAndRemove(req.params.id, (err, item) => { if (err) { @@ -67,7 +96,7 @@ campaigns.route('/:id') err.status = codes.notfound; return next(err); } - WarModel.find({campaign: req.params.id}).remove().exec(); + WarModel.find({ campaign: req.params.id }).remove().exec(); // TODO: remove all the war logs from fs here!!! res.locals.processed = true; next(); diff --git a/static/src/app/services/logs/campaign.service.ts b/static/src/app/services/logs/campaign.service.ts index 6d4e806..d4cc7ef 100644 --- a/static/src/app/services/logs/campaign.service.ts +++ b/static/src/app/services/logs/campaign.service.ts @@ -14,27 +14,28 @@ export class CampaignService { getAllCampaigns() { return this.http.get(this.config.apiWarPath) - .map(res => res.json()); + .map(res => res.json()); } submitCampaign(campaign: Campaign) { if (campaign._id) { - return this.http.patch(this.config.apiCampaignPath + '/' + campaign._id, campaign); + return this.http.patch(this.config.apiCampaignPath + '/' + campaign._id, campaign) + .map(res => res.json()); } else { return this.http.post(this.config.apiCampaignPath, campaign) - .map(res => res.json()); + .map(res => res.json()); } } deleteCampaign(id: string) { return this.http.delete(this.config.apiCampaignPath + '/' + id) - .map(res => res.json()); + .map(res => res.json()); } getCampaign(id: string) { return this.http.get(this.config.apiCampaignPath + '/' + id) - .map(res => res.json()); + .map(res => res.json()); } } diff --git a/static/src/app/statistic/campaign-submit/campaign-submit.component.ts b/static/src/app/statistic/campaign-submit/campaign-submit.component.ts index 588a905..0d5d9f5 100644 --- a/static/src/app/statistic/campaign-submit/campaign-submit.component.ts +++ b/static/src/app/statistic/campaign-submit/campaign-submit.component.ts @@ -39,7 +39,11 @@ export class CampaignSubmitComponent { saveCampaign() { this.campaignService.submitCampaign(this.campaign) .subscribe(campaign => { - this.router.navigate(['../overview/' + campaign._id], {relativeTo: this.route}); + let redirectSuccessUrl = '../overview/'; + if (this.campaign._id) { + redirectSuccessUrl = '../' + redirectSuccessUrl + } + this.router.navigate([redirectSuccessUrl + campaign._id], {relativeTo: this.route}); }, error => { this.error = error._body.error.message; From 8600eb5f3c631cceb3dbab06b069ce6bd8417043 Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Sat, 28 Apr 2018 16:31:14 +0200 Subject: [PATCH 10/28] clean new war file extension check --- .../src/app/services/logs/campaign.service.ts | 1 - .../war-submit/war-submit.component.html | 2 +- .../war-submit/war-submit.component.ts | 17 +++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/static/src/app/services/logs/campaign.service.ts b/static/src/app/services/logs/campaign.service.ts index d4cc7ef..2fbda1f 100644 --- a/static/src/app/services/logs/campaign.service.ts +++ b/static/src/app/services/logs/campaign.service.ts @@ -25,7 +25,6 @@ export class CampaignService { return this.http.post(this.config.apiCampaignPath, campaign) .map(res => res.json()); } - } deleteCampaign(id: string) { diff --git a/static/src/app/statistic/war-submit/war-submit.component.html b/static/src/app/statistic/war-submit/war-submit.component.html index 1b37492..4cebf76 100644 --- a/static/src/app/statistic/war-submit/war-submit.component.html +++ b/static/src/app/statistic/war-submit/war-submit.component.html @@ -29,7 +29,7 @@ - + Logfile muss im Format RPT, LOG oder TXT vorliegen
diff --git a/static/src/app/statistic/war-submit/war-submit.component.ts b/static/src/app/statistic/war-submit/war-submit.component.ts index 74b3525..5e78590 100644 --- a/static/src/app/statistic/war-submit/war-submit.component.ts +++ b/static/src/app/statistic/war-submit/war-submit.component.ts @@ -18,7 +18,9 @@ export class WarSubmitComponent { fileList: FileList; - showImageError = false; + readonly validExtensions = ['.rpt', '.log', '.txt']; + + showFileError = false; showErrorLabel = false; @@ -35,14 +37,13 @@ export class WarSubmitComponent { } fileChange(event) { - if (!event.target.files[0].name.endsWith('.rpt') - && !event.target.files[0].name.endsWith('.log') - && !event.target.files[0].name.endsWith('.txt')) { - this.showImageError = true; - this.fileList = undefined; - } else { - this.showImageError = false; + if (this.validExtensions.filter(ext => event.target.files[0] && + event.target.files[0].name.endsWith(ext)).length == 1) { + this.showFileError = false; this.fileList = event.target.files; + } else { + this.showFileError = true; + this.fileList = undefined; } } From da29c39b88711a56809714441050f9de84aaf124 Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Sat, 28 Apr 2018 16:54:35 +0200 Subject: [PATCH 11/28] add working capaign update apib test --- api/apib/dredd/data/campaign.json | 2 +- api/apib/statistics/campaigns.apib | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/apib/dredd/data/campaign.json b/api/apib/dredd/data/campaign.json index 51442c2..92098d0 100644 --- a/api/apib/dredd/data/campaign.json +++ b/api/apib/dredd/data/campaign.json @@ -1,3 +1,3 @@ {"_id":{"$oid":"5abd55ea9e30a76bfef747d6"},"title":"Ein Kessel Buntes","timestamp":{"$date":"2018-03-29T21:08:58.123Z"},"updatedAt":{"$date":"2018-03-29T21:08:58.123Z"},"__v":0} {"_id":{"$oid":"5abd58989e30a76bfef747e6"},"title":"This Is The End","timestamp":{"$date":"2018-03-29T21:20:24.558Z"},"updatedAt":{"$date":"2018-03-29T21:20:24.558Z"},"__v":0} -{"_id":{"$oid":"5abd58es9e30a76bfef347e4"},"title":"Edit me","timestamp":{"$date":"2018-03-29T21:20:24.558Z"},"updatedAt":{"$date":"2018-03-29T21:20:24.558Z"},"__v":0} +{"_id":{"$oid":"5abd55ea9e32a76afef777d6"},"title":"Placeholder","timestamp":{"$date":"2018-03-30T21:08:58.123Z"},"updatedAt":{"$date":"2018-03-30T21:08:58.123Z"},"__v":0} diff --git a/api/apib/statistics/campaigns.apib b/api/apib/statistics/campaigns.apib index 7915294..8b028b0 100644 --- a/api/apib/statistics/campaigns.apib +++ b/api/apib/statistics/campaigns.apib @@ -24,19 +24,19 @@ Create a new campaign + Attributes (Campaign, fixed-type) -### Update Campaign [PUT /campaigns/{id}] +### Update Campaign [PATCH /campaigns/{id}] Update a campaign, identified by its id **Permission: 3** + Parameters - + id: `5abd58es9e30a76bfef347e4` (string, required) - unique id of campaign + + id: `5abd55ea9e32a76afef777d6` (string, required) - unique id of campaign + Request (application/json) + Attributes - + _id: `5abd58es9e30a76bfef347e4` (string, required) - unique id of campaign + + _id: `5abd55ea9e32a76afef777d6` (string, required) - unique id of campaign + title: `Operation Pandora` (string, optional) - display name of the campaign + Response 200 (application/json; charset=utf-8) From 0bf730e0d47d8233d5887307773fc538a1fc6c1e Mon Sep 17 00:00:00 2001 From: HardiReady Date: Sun, 29 Apr 2018 09:51:28 +0200 Subject: [PATCH 12/28] Fix code style --- api/apib/dredd/populate-data.sh | 2 +- api/routes/campaigns.js | 6 +++--- .../cc-intellij-idea-javascript-typescript-style.xml | 1 - .../statistic/campaign-submit/campaign-submit.component.ts | 2 +- static/src/app/statistic/war-submit/war-submit.component.ts | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/api/apib/dredd/populate-data.sh b/api/apib/dredd/populate-data.sh index 47dc954..3544f4d 100755 --- a/api/apib/dredd/populate-data.sh +++ b/api/apib/dredd/populate-data.sh @@ -4,7 +4,7 @@ ###-------------------------------------------------------------### ###------------------- HOW TO USE THIS FILE --------------------### ###-------------------------------------------------------------### -### 1. start express server with `npm run start-test` ### +### 1. start express server with `npm run start-api-test` ### ### 2. import data by executing script: `./populate-data.sh` ### ### 3. change data in app as you need for tests ### ### 4. export data state with: `./populate-data.sh -m save` ### diff --git a/api/routes/campaigns.js b/api/routes/campaigns.js index f42bb4a..c992cbf 100644 --- a/api/routes/campaigns.js +++ b/api/routes/campaigns.js @@ -66,14 +66,14 @@ campaigns.route('/:id') } req.body.updatedAt = new Date(); - req.body.$inc = { __v: 1 }; + req.body.$inc = {__v: 1}; if (req.body.hasOwnProperty('__v')) { delete req.body.__v; } // PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to // reset attributes that are missing. - CampaignModel.findByIdAndUpdate(req.params.id, req.body, { new: true }, (err, item) => { + CampaignModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { if (err) { err.status = codes.wrongrequest; } else if (!item) { @@ -96,7 +96,7 @@ campaigns.route('/:id') err.status = codes.notfound; return next(err); } - WarModel.find({ campaign: req.params.id }).remove().exec(); + WarModel.find({campaign: req.params.id}).remove().exec(); // TODO: remove all the war logs from fs here!!! res.locals.processed = true; next(); diff --git a/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml b/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml index e1c7def..185cecc 100644 --- a/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml +++ b/docs/infra/codestyle/cc-intellij-idea-javascript-typescript-style.xml @@ -1,7 +1,6 @@
- - - - Logfile muss im Format RPT, LOG oder TXT vorliegen - + + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + +
diff --git a/static/src/app/statistic/war/war-list/war-item.component.ts b/static/src/app/statistic/war/war-list/war-item.component.ts index 20c874b..dcc33d0 100644 --- a/static/src/app/statistic/war/war-list/war-item.component.ts +++ b/static/src/app/statistic/war/war-list/war-item.component.ts @@ -16,6 +16,8 @@ export class WarItemComponent implements OnInit { @Output() warSelected = new EventEmitter(); + @Output() warEdit = new EventEmitter(); + @Output() warDelete = new EventEmitter(); constructor(public loginService: LoginService) { @@ -28,6 +30,10 @@ export class WarItemComponent implements OnInit { this.warSelected.emit(this.war._id); } + edit() { + this.warEdit.emit(this.war._id); + } + delete() { this.warDelete.emit(this.war); } diff --git a/static/src/app/statistic/war/war-list/war-list.component.html b/static/src/app/statistic/war/war-list/war-list.component.html index c4c1d73..8d604ad 100644 --- a/static/src/app/statistic/war/war-list/war-list.component.html +++ b/static/src/app/statistic/war/war-list/war-list.component.html @@ -47,6 +47,7 @@
diff --git a/static/src/app/statistic/war/war-list/war-list.component.ts b/static/src/app/statistic/war/war-list/war-list.component.ts index e18d329..bb18ed0 100644 --- a/static/src/app/statistic/war/war-list/war-list.component.ts +++ b/static/src/app/statistic/war/war-list/war-list.component.ts @@ -49,11 +49,6 @@ export class WarListComponent implements OnInit { this.router.navigate([{outlets: {'right': ['campaign']}}], {relativeTo: this.route}); } - selectNewWar() { - this.selectedWarId = null; - this.router.navigate([{outlets: {'right': ['submit-war']}}], {relativeTo: this.route}); - } - selectWar(warId) { if (this.selectedWarId !== warId) { this.selectedWarId = warId; @@ -75,6 +70,16 @@ export class WarListComponent implements OnInit { } } + selectNewWar() { + this.selectedWarId = null; + this.router.navigate([{outlets: {'right': ['submit-war']}}], {relativeTo: this.route}); + } + + editWar(warId) { + this.selectedWarId = warId; + this.router.navigate([{outlets: {'right': ['submit-war', warId]}}], {relativeTo: this.route}); + } + deleteWar(war: War) { if (confirm('Soll die Schlacht ' + war.title + ' wirklich gelöscht werden?')) { this.warService.deleteWar(war._id) @@ -82,7 +87,9 @@ export class WarListComponent implements OnInit { if (this.selectedWarId === war._id) { this.selectOverview('all'); } - this.campaigns.splice(this.campaigns.indexOf(war), 1); + this.campaigns.forEach(campaign => { + campaign.wars.splice(campaign.wars.indexOf(war),1) + }) }); } } From 63a89ebf7b0ac65e0f6a11a25e34dd586faa66fc Mon Sep 17 00:00:00 2001 From: HardiReady Date: Sun, 29 Apr 2018 11:30:40 +0200 Subject: [PATCH 19/28] Add apib doc for update war --- api/apib/dredd/data/war.json | 1 + api/apib/statistics/wars.apib | 29 +++++++++++++++++++ static/src/app/statistic/stats.routing.ts | 6 ++-- .../war/war-edit/war-edit.component.ts | 2 +- .../war/war-list/war-list.component.ts | 4 +-- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/api/apib/dredd/data/war.json b/api/apib/dredd/data/war.json index ec8d2ee..4978a30 100644 --- a/api/apib/dredd/data/war.json +++ b/api/apib/dredd/data/war.json @@ -1,2 +1,3 @@ {"_id":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"playersBlufor":4,"playersOpfor":4,"budgetBlufor":4535500,"budgetOpfor":4221250,"endBudgetBlufor":997000,"endBudgetOpfor":512000,"title":"Battle #1","campaign":{"$oid":"5abd55ea9e30a76bfef747d6"},"date":{"$date":"2018-03-19T23:00:00.000Z"},"endDate":{"$date":"2018-03-20T01:30:00.000Z"},"ptBlufor":34,"ptOpfor":25,"timestamp":{"$date":"2018-03-31T10:41:28.451Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.451Z"},"__v":0} {"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"playersBlufor":4,"playersOpfor":4,"budgetBlufor":4535500,"budgetOpfor":4221250,"endBudgetBlufor":997000,"endBudgetOpfor":512000,"title":"Test Battle #0","campaign":{"$oid":"5abd55ea9e30a76bfef747d6"},"date":{"$date":"2018-03-19T23:00:00.000Z"},"endDate":{"$date":"2018-03-20T01:30:00.000Z"},"ptBlufor":34,"ptOpfor":25,"timestamp":{"$date":"2018-03-31T10:40:46.695Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.695Z"},"__v":0} +{"_id":{"$oid":"5abf65ae2df5fa349ffd5ca3"},"playersBlufor":20,"playersOpfor":20,"budgetBlufor":4535500,"budgetOpfor":4535500,"endBudgetBlufor":0,"endBudgetOpfor":20000,"title":"Test Battle XY","campaign":{"$oid":"5abd55ea9e30a76bfef747d6"},"date":{"$date":"2018-03-02T23:00:00.000Z"},"endDate":{"$date":"2018-03-02T01:30:00.000Z"},"ptBlufor":34,"ptOpfor":25,"timestamp":{"$date":"2018-03-02T10:40:46.695Z"},"updatedAt":{"$date":"2018-03-02T10:40:46.695Z"},"__v":0} diff --git a/api/apib/statistics/wars.apib b/api/apib/statistics/wars.apib index 6ce40bb..c370a9c 100644 --- a/api/apib/statistics/wars.apib +++ b/api/apib/statistics/wars.apib @@ -76,6 +76,35 @@ Create a new war + Attributes (War, fixed-type) +### Update War [PATCH /wars/{id}] + +Update a war, identified by its id + +**Permission: 3** + ++ Parameters + + id: `5abf65ae2df5fa349ffd5ca3` (string, required) - unique id of campaign + ++ Request (application/json) + + + Attributes + + _id: `5abf65ae2df5fa349ffd5ca3` (string, required) - unique id of war + + title: `Final Touchdown` (string, optional) - display name of the war + + date: `2017-05-11T20:00:00.471Z` (string, optional) - starting date + + endDate: `2017-05-12T00:30:32.471Z` (string, optional) - end date + + ptBlufor: 5 (number, optional) - points Blufor + + ptOpfor: 5 (number, optional) - points Opfor + + playersBlufor: 20 (number, optional) - number of players Blufor + + playersOpfor: 20 (number, optional) - number of players Opfor + + budgetBlufor: 3000000 (number, optional) - start budget Blufor + + budgetOpfor: 3000000 (number, optional) - start budget Opfor + + endBudgetBlufor: 10000 (number, optional) - end budget Blufor + + endBudgetOpfor: 12000 (number, optional) - end budget Opfor + ++ Response 200 (application/json; charset=utf-8) + + + Attributes (War, fixed-type) + ### Delete War [DELETE /wars/{id}] Delete a war diff --git a/static/src/app/statistic/stats.routing.ts b/static/src/app/statistic/stats.routing.ts index f020788..b2f7302 100644 --- a/static/src/app/statistic/stats.routing.ts +++ b/static/src/app/statistic/stats.routing.ts @@ -10,9 +10,9 @@ import {ScoreboardComponent} from './war/scoreboard/scoreboard.component'; import {WarSubmitComponent} from './war/war-submit/war-submit.component'; import {FractionStatsComponent} from './war/fraction-stats/fraction-stats.component'; import {StatisticHighScoreComponent} from './campaign/highscore/highscore.component'; -import {WarHeaderComponent} from "./war/war-header/war-header.component"; -import {WarEditComponent} from "./war/war-edit/war-edit.component"; -import {LoginGuardMT} from "../login"; +import {WarHeaderComponent} from './war/war-header/war-header.component'; +import {WarEditComponent} from './war/war-edit/war-edit.component'; +import {LoginGuardMT} from '../login'; export const statsRoutes: Routes = [{ diff --git a/static/src/app/statistic/war/war-edit/war-edit.component.ts b/static/src/app/statistic/war/war-edit/war-edit.component.ts index 254241b..96be8cf 100644 --- a/static/src/app/statistic/war/war-edit/war-edit.component.ts +++ b/static/src/app/statistic/war/war-edit/war-edit.component.ts @@ -3,7 +3,7 @@ import {ActivatedRoute, Router} from '@angular/router'; import {NgForm} from '@angular/forms'; import {WarService} from '../../../services/logs/war.service'; import {War} from '../../../models/model-interfaces'; -import {CampaignService} from "../../../services/logs/campaign.service"; +import {CampaignService} from '../../../services/logs/campaign.service'; import {Subscription} from 'rxjs/Subscription'; diff --git a/static/src/app/statistic/war/war-list/war-list.component.ts b/static/src/app/statistic/war/war-list/war-list.component.ts index bb18ed0..b64fc1c 100644 --- a/static/src/app/statistic/war/war-list/war-list.component.ts +++ b/static/src/app/statistic/war/war-list/war-list.component.ts @@ -88,8 +88,8 @@ export class WarListComponent implements OnInit { this.selectOverview('all'); } this.campaigns.forEach(campaign => { - campaign.wars.splice(campaign.wars.indexOf(war),1) - }) + campaign.wars.splice(campaign.wars.indexOf(war), 1); + }); }); } } From f0e5b1105496f7f3b7ae8bc0e6dd90e4ea5aeaee Mon Sep 17 00:00:00 2001 From: HardiReady Date: Sun, 29 Apr 2018 12:00:21 +0200 Subject: [PATCH 20/28] Fix respawn log parsing (CC-22) --- api/tools/log-parse-tool.js | 13 ++++++------- .../war/scoreboard/scoreboard.component.html | 2 +- .../statistic/war/war-edit/war-edit.component.html | 7 ++----- .../statistic/war/war-edit/war-edit.component.ts | 4 +--- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/api/tools/log-parse-tool.js b/api/tools/log-parse-tool.js index 299016c..4ef4d99 100644 --- a/api/tools/log-parse-tool.js +++ b/api/tools/log-parse-tool.js @@ -106,6 +106,12 @@ const parseWarLog = (lineArray, war) => { stats.war['endBudgetBlufor'] = transformMoneyString(budg[9]); stats.war['endBudgetOpfor'] = transformMoneyString(budg[12].slice(0, -2)); stats.war.endDate = getFullTimeDate(war.date, budg[5]); + } else if (line.includes('Respawn von ')) { + /** + * RESPAWN + */ + const playerName = line.substring(line.lastIndexOf('Respawn von ') + 12, line.lastIndexOf('"')); + stats.respawn.push(getRespawnEntry(budg, playerName, war._id, war.date)); } else { stats.budget.push(getBudgetEntry(budg, war._id, war.date)); } @@ -140,13 +146,6 @@ const parseWarLog = (lineArray, war) => { } else { stats.points.push(getPointsEntry(pt, line, war._id, war.date)); } - } else if (line.includes('(Respawn)')) { - /** - * RESPAWN - */ - const resp = line.split(WHITESPACE); - const playerName = line.substring(line.lastIndexOf('Spieler:') + 9, line.lastIndexOf('- Kosten') - 1); - stats.respawn.push(getRespawnEntry(resp, playerName, war._id, war.date)); } else if (line.includes('(Revive)')) { /** * REVIVE diff --git a/static/src/app/statistic/war/scoreboard/scoreboard.component.html b/static/src/app/statistic/war/scoreboard/scoreboard.component.html index 5a8595b..e2559ea 100644 --- a/static/src/app/statistic/war/scoreboard/scoreboard.component.html +++ b/static/src/app/statistic/war/scoreboard/scoreboard.component.html @@ -24,7 +24,7 @@ -
+
diff --git a/static/src/app/statistic/war/war-edit/war-edit.component.html b/static/src/app/statistic/war/war-edit/war-edit.component.html index 0fb5bc1..ff08c34 100644 --- a/static/src/app/statistic/war/war-edit/war-edit.component.html +++ b/static/src/app/statistic/war/war-edit/war-edit.component.html @@ -50,7 +50,7 @@ [(ngModel)]="war.endBudgetBlufor" name="endBudgetBlufor" id="endBudgetBlufor" - required /> + required/>
@@ -60,26 +60,23 @@ [(ngModel)]="war.endBudgetOpfor" name="endBudgetOpfor" id="endBudgetOpfor" - required /> + required/>
- {{error}} diff --git a/static/src/app/statistic/war/war-edit/war-edit.component.ts b/static/src/app/statistic/war/war-edit/war-edit.component.ts index 96be8cf..e84e42b 100644 --- a/static/src/app/statistic/war/war-edit/war-edit.component.ts +++ b/static/src/app/statistic/war/war-edit/war-edit.component.ts @@ -19,8 +19,6 @@ export class WarEditComponent { subscription: Subscription; - showFileError = false; - showErrorLabel = false; error; @@ -30,7 +28,7 @@ export class WarEditComponent { constructor(private route: ActivatedRoute, private router: Router, private warService: WarService, - private campaignService: CampaignService) { + public campaignService: CampaignService) { this.subscription = this.route.params .map(params => params['id']) .filter(id => id !== undefined) From bdb07ecc1ef6010bbaf8e867bbcf5af3a4029999 Mon Sep 17 00:00:00 2001 From: HardiReady Date: Fri, 4 May 2018 20:37:35 +0200 Subject: [PATCH 21/28] Add generic patch method for reuse --- api/routes/_generic.js | 37 ++++++++++++++++ api/routes/campaigns.js | 32 ++------------ api/routes/wars.js | 32 ++------------ api/tools/signature-tool.js | 85 +++++++++++++++++++------------------ api/tools/util.js | 1 - 5 files changed, 88 insertions(+), 99 deletions(-) create mode 100644 api/routes/_generic.js diff --git a/api/routes/_generic.js b/api/routes/_generic.js new file mode 100644 index 0000000..0d466cd --- /dev/null +++ b/api/routes/_generic.js @@ -0,0 +1,37 @@ +"use strict"; + +// HTTP status codes by name +const codes = require('./http-codes'); + +const genericPatch = (req, res, next, modelClass) => { + 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 + const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + + req.body._id); + err.status = codes.notfound; + next(err); + return; // prevent node to process this function further after next() has finished. + } + + req.body.updatedAt = new Date(); + req.body.$inc = {__v: 1}; + if (req.body.hasOwnProperty('__v')) { + delete req.body.__v; + } + + // PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to + // reset attributes that are missing. + modelClass.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { + if (err) { + err.status = codes.wrongrequest; + } else if (!item) { + err = new Error('item not found'); + err.status = codes.notfound; + } else { + res.locals.items = item; + } + next(err); + }); +}; + +exports.genericPatch = genericPatch; diff --git a/api/routes/campaigns.js b/api/routes/campaigns.js index c992cbf..136b2ce 100644 --- a/api/routes/campaigns.js +++ b/api/routes/campaigns.js @@ -16,6 +16,9 @@ const idValidator = require('../middleware/validators').idValidator; const CampaignModel = require('../models/campaign'); const WarModel = require('../models/war'); +// util +const genericPatch = require('./_generic').genericPatch; + const campaigns = new express.Router(); // routes ********************** @@ -56,34 +59,7 @@ campaigns.route('/:id') }) .patch(apiAuthenticationMiddleware, checkMT, (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 - const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + - req.body._id); - err.status = codes.notfound; - next(err); - return; // prevent node to process this function further after next() has finished. - } - - req.body.updatedAt = new Date(); - req.body.$inc = {__v: 1}; - if (req.body.hasOwnProperty('__v')) { - delete req.body.__v; - } - - // PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to - // reset attributes that are missing. - CampaignModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { - if (err) { - err.status = codes.wrongrequest; - } else if (!item) { - err = new Error('item not found'); - err.status = codes.notfound; - } else { - res.locals.items = item; - } - next(err); - }); + return genericPatch(req, res, next, CampaignModel); }) .delete((req, res, next) => { diff --git a/api/routes/wars.js b/api/routes/wars.js index eb42cf9..65b04d2 100644 --- a/api/routes/wars.js +++ b/api/routes/wars.js @@ -35,6 +35,9 @@ const LogFlagModel = require('../models/logs/flag'); const LogBudgetModel = require('../models/logs/budget'); const LogPointsModel = require('../models/logs/points'); +// util +const genericPatch = require('./_generic').genericPatch; + const wars = new express.Router(); // routes ********************** @@ -169,34 +172,7 @@ wars.route('/:id') }) .patch(apiAuthenticationMiddleware, checkMT, (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 - const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + ' ' + - req.body._id); - err.status = codes.notfound; - next(err); - return; // prevent node to process this function further after next() has finished. - } - - req.body.updatedAt = new Date(); - req.body.$inc = {__v: 1}; - if (req.body.hasOwnProperty('__v')) { - delete req.body.__v; - } - - // PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to - // reset attributes that are missing. - WarModel.findByIdAndUpdate(req.params.id, req.body, {new: true}, (err, item) => { - if (err) { - err.status = codes.wrongrequest; - } else if (!item) { - err = new Error('item not found'); - err.status = codes.notfound; - } else { - res.locals.items = item; - } - next(err); - }); + return genericPatch(req, res, next, WarModel); }) .delete(apiAuthenticationMiddleware, checkMT, (req, res, next) => { diff --git a/api/tools/signature-tool.js b/api/tools/signature-tool.js index 8fe9b7e..86a0010 100644 --- a/api/tools/signature-tool.js +++ b/api/tools/signature-tool.js @@ -137,48 +137,7 @@ let addDecorationsAndSave = (userId, loadedImage, res, next) => { return next(err); } if (awardings.length > 0) { - // TODO: simplify this sorting hell - awardings.sort((a1, a2) => { - if (!a1.decorationId.isMedal && !a2.decorationId.isMedal) { - if (a1.decorationId.fraction === a2.decorationId.fraction) { - if (a1.date !== a2.date) { - if (a1.date < a2.date) { - return -1; - } - if (a1.date > a2.date) { - return 1; - } - } - return 0; - } else { - if (a1.decorationId.fraction === 'GLOBAL' && a2.decorationId.fraction !== 'GLOBAL') { - return -1; - } - if (a2.decorationId.fraction === 'GLOBAL' && a1.decorationId.fraction !== 'GLOBAL') { - return 1; - } - } - } - if (a1.decorationId.isMedal !== a2.decorationId.isMedal) { - if (a1.decorationId.isMedal && !a2.decorationId.isMedal) { - return 1; - } - if (!a1.decorationId.isMedal && a2.decorationId.isMedal) { - return -1; - } - } - if (a1.decorationId.isMedal && a2.decorationId.isMedal) { - if (a1.date !== a2.date) { - if (a1.date < a2.date) { - return -1; - } - if (a1.date > a2.date) { - return 1; - } - } - return 0; - } - }); + awardings.sort((a1, a2) => sortAwardingsForSignature(a1, a2)); // use synchronized call to keep correct order of decorations async.eachSeries(awardings, (award, callback) => { @@ -262,5 +221,47 @@ let saveJimpImageAndCompress = (image, userId, res, next) => { }, 3000); }; +const sortAwardingsForSignature = (a1, a2) => { + if (!a1.decorationId.isMedal && !a2.decorationId.isMedal) { + if (a1.decorationId.fraction === a2.decorationId.fraction) { + if (a1.date !== a2.date) { + if (a1.date < a2.date) { + return -1; + } + if (a1.date > a2.date) { + return 1; + } + } + return 0; + } else { + if (a1.decorationId.fraction === 'GLOBAL' && a2.decorationId.fraction !== 'GLOBAL') { + return -1; + } + if (a2.decorationId.fraction === 'GLOBAL' && a1.decorationId.fraction !== 'GLOBAL') { + return 1; + } + } + } + if (a1.decorationId.isMedal !== a2.decorationId.isMedal) { + if (a1.decorationId.isMedal && !a2.decorationId.isMedal) { + return 1; + } + if (!a1.decorationId.isMedal && a2.decorationId.isMedal) { + return -1; + } + } + if (a1.decorationId.isMedal && a2.decorationId.isMedal) { + if (a1.date !== a2.date) { + if (a1.date < a2.date) { + return -1; + } + if (a1.date > a2.date) { + return 1; + } + } + return 0; + } +}; + module.exports = createSignature; diff --git a/api/tools/util.js b/api/tools/util.js index 155ac34..86f699e 100644 --- a/api/tools/util.js +++ b/api/tools/util.js @@ -39,7 +39,6 @@ const timeStringToDecimal = (timeString) => { return hour + (sek / 3600); }; - const decimalToTimeString = (decimal) => { const hours = parseInt(decimal.toString().split('.')[0]); const minutesFloat = ((decimal % 1) * 3600) / 60; From 8a78b695b7a9632a016c55b249bdce9cda6485b3 Mon Sep 17 00:00:00 2001 From: HardiReady Date: Fri, 4 May 2018 20:49:45 +0200 Subject: [PATCH 22/28] Add generic method for get by id --- api/routes/_generic.js | 16 ++++++++++++++++ api/routes/campaigns.js | 14 ++------------ api/routes/decorations.js | 16 ++++------------ api/routes/ranks.js | 16 ++++------------ api/routes/squads.js | 16 ++++------------ 5 files changed, 30 insertions(+), 48 deletions(-) diff --git a/api/routes/_generic.js b/api/routes/_generic.js index 0d466cd..6843bb1 100644 --- a/api/routes/_generic.js +++ b/api/routes/_generic.js @@ -3,6 +3,21 @@ // HTTP status codes by name const codes = require('./http-codes'); +const genericGetById = (req, res, next, modelClass) => { + modelClass.findById(req.params.id, (err, item) => { + if (err) { + err.status = codes.servererror; + return next(err); + } else if (!item) { + err = new Error('item not found'); + err.status = codes.notfound; + return next(err); + } + res.locals.items = item; + return next(); + }); +}; + const genericPatch = (req, res, next, modelClass) => { 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 @@ -34,4 +49,5 @@ const genericPatch = (req, res, next, modelClass) => { }); }; +exports.genericGetById = genericGetById; exports.genericPatch = genericPatch; diff --git a/api/routes/campaigns.js b/api/routes/campaigns.js index 136b2ce..573b74b 100644 --- a/api/routes/campaigns.js +++ b/api/routes/campaigns.js @@ -17,6 +17,7 @@ const CampaignModel = require('../models/campaign'); const WarModel = require('../models/war'); // util +const genericGetById = require('./_generic').genericGetById; const genericPatch = require('./_generic').genericPatch; const campaigns = new express.Router(); @@ -44,18 +45,7 @@ campaigns.route('/') campaigns.route('/:id') .get(idValidator, (req, res, next) => { - CampaignModel.findById(req.params.id, (err, item) => { - if (err) { - err.status = codes.servererror; - return next(err); - } else if (!item) { - err = new Error('item not found'); - err.status = codes.notfound; - return next(err); - } - res.locals.items = item; - return next(); - }); + return genericGetById(req, res, next, CampaignModel); }) .patch(apiAuthenticationMiddleware, checkMT, (req, res, next) => { diff --git a/api/routes/decorations.js b/api/routes/decorations.js index 2302217..6bd782a 100644 --- a/api/routes/decorations.js +++ b/api/routes/decorations.js @@ -21,6 +21,9 @@ const resourceLocation = require('../middleware/resource-location').resourceLoca const DecorationModel = require('../models/decoration'); const AwardingsModel = require('../models/awarding'); +// util +const genericGetById = require('./_generic').genericGetById; + const decoration = new express.Router(); // routes ********************** @@ -81,18 +84,7 @@ decoration.route('/') decoration.route('/:id') .get(idValidator, (req, res, next) => { - DecorationModel.findById(req.params.id, (err, item) => { - if (err) { - err.status = codes.servererror; - return next(err); - } else if (!item) { - err = new Error('item not found'); - err.status = codes.notfound; - return next(err); - } - res.locals.items = item; - next(); - }); + return genericGetById(req, res, next, DecorationModel); }) .patch(apiAuthenticationMiddleware, checkHl, upload.single('image'), (req, res, next) => { diff --git a/api/routes/ranks.js b/api/routes/ranks.js index 390bb70..2853a34 100644 --- a/api/routes/ranks.js +++ b/api/routes/ranks.js @@ -20,6 +20,9 @@ const resourceLocation = require('../middleware/resource-location').resourceLoca // Mongoose Model using mongoDB const RankModel = require('../models/rank'); +// util +const genericGetById = require('./_generic').genericGetById; + const ranks = new express.Router(); // routes ********************** @@ -73,18 +76,7 @@ ranks.route('/') ranks.route('/:id') .get(idValidator, (req, res, next) => { - RankModel.findById(req.params.id, (err, item) => { - if (err) { - err.status = codes.servererror; - return next(err); - } else if (!item) { - err = new Error('item not found'); - err.status = codes.notfound; - return next(err); - } - res.locals.items = item; - next(); - }); + return genericGetById(req, res, next, RankModel); }) .patch(apiAuthenticationMiddleware, checkHl, upload.single('image'), (req, res, next) => { diff --git a/api/routes/squads.js b/api/routes/squads.js index 80582ab..8764f4f 100644 --- a/api/routes/squads.js +++ b/api/routes/squads.js @@ -20,6 +20,9 @@ const resourceLocation = require('../middleware/resource-location').resourceLoca // Mongoose Model using mongoDB const SquadModel = require('../models/squad'); +// util +const genericGetById = require('./_generic').genericGetById; + const squads = new express.Router(); // routes ********************** @@ -77,18 +80,7 @@ squads.route('/') squads.route('/:id') .get(idValidator, (req, res, next) => { - SquadModel.findById(req.params.id, (err, item) => { - if (err) { - err.status = codes.servererror; - return next(err); - } else if (!item) { - err = new Error('item not found'); - err.status = codes.notfound; - return next(err); - } - res.locals.items = item; - next(); - }); + return genericGetById(req, res, next, SquadModel); }) .patch(apiAuthenticationMiddleware, checkHl, upload.single('image'), (req, res, next) => { From e8ea7dc6a9a48466b9f16c5772c4b1a38cf47893 Mon Sep 17 00:00:00 2001 From: HardiReady Date: Fri, 4 May 2018 21:42:12 +0200 Subject: [PATCH 23/28] Finish icons for scoreboard --- .../war/scoreboard/scoreboard.component.ts | 6 +++--- static/src/assets/scoreboard/death.png | Bin 0 -> 659 bytes static/src/assets/scoreboard/flagTouch.png | Bin 0 -> 3509 bytes static/src/assets/scoreboard/friendlyFire.png | Bin 0 -> 3764 bytes static/src/assets/scoreboard/kill.png | Bin 0 -> 3665 bytes static/src/assets/scoreboard/respawn.png | Bin 0 -> 678 bytes static/src/assets/scoreboard/revive.png | Bin 0 -> 3645 bytes 7 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 static/src/assets/scoreboard/death.png create mode 100644 static/src/assets/scoreboard/flagTouch.png create mode 100644 static/src/assets/scoreboard/friendlyFire.png create mode 100644 static/src/assets/scoreboard/kill.png create mode 100644 static/src/assets/scoreboard/respawn.png create mode 100644 static/src/assets/scoreboard/revive.png diff --git a/static/src/app/statistic/war/scoreboard/scoreboard.component.ts b/static/src/app/statistic/war/scoreboard/scoreboard.component.ts index 0ced99b..972b02e 100644 --- a/static/src/app/statistic/war/scoreboard/scoreboard.component.ts +++ b/static/src/app/statistic/war/scoreboard/scoreboard.component.ts @@ -20,10 +20,10 @@ export class ScoreboardComponent implements OnChanges { @Output() playerTabSwitch = new EventEmitter(); tableHead = [ - {prop: 'name', head: 'Spieler'}, {prop: 'fraction', head: 'Fraktion'}, {prop: 'kill', head: 'Kills'}, - {prop: 'friendlyFire', head: 'FriendlyFire'}, {prop: 'vehicleLight', head: 'Fahrzeug (leicht)'}, + {prop: 'name', head: 'Spieler'}, {prop: 'fraction', head: 'Fraktion'}, {prop: 'kill', head: 'Abschüsse'}, + {prop: 'friendlyFire', head: 'Friendly Fire'}, {prop: 'vehicleLight', head: 'Fahrzeug (leicht)'}, {prop: 'vehicleHeavy', head: 'Fahrzeug (schwer)'}, {prop: 'vehicleAir', head: 'Fahrzeug (Luft)'}, - {prop: 'revive', head: 'Revive'}, {prop: 'flagTouch', head: 'Flagge'}, {prop: 'death', head: 'Tod'}, + {prop: 'revive', head: 'Revive'}, {prop: 'flagTouch', head: 'Eroberungen'}, {prop: 'death', head: 'Tode'}, {prop: 'respawn', head: 'Respawn'} ]; diff --git a/static/src/assets/scoreboard/death.png b/static/src/assets/scoreboard/death.png new file mode 100644 index 0000000000000000000000000000000000000000..8b5e5bb61e51adfbb883779b5f6b8f089880c379 GIT binary patch literal 659 zcmV;E0&M+>P)Dq}HU?s|X(eQf)UOIk*dVerakFl&aeNyeG4h2O|SY~IX!BSX-E!+qTIopaAU_ndRz z4U*_5Mf92eEeC3~+7K`WJO)aD%q7oF8PhpQ>XdIuT2(r&8rzZGR6x004w4omRn$3E zBrRAsp97K>m7NyT?1z*xyaIgAnP&yyOV%V@?m?n2=c$4_J#e6{jkF_Z0wJdZYPZp} z2!tL)AmllMQeqcbcAm76$$>SGdx^QXKzsr=wv1ysYk4~1jHJ42`lY0~dcA&C(xjw~ zM7?iFnzU@rSXp-_Pb0b^X#wCp+7`q~GTG*1R!e*4ej>zpgQuas;0o%3r`< zp-@QX!VgzT>-(_l9Ab`iY$Nj#tT>caN%tg8G#ZVfq-ja-kMXo+6UJ7pyOJjYXFZ++ z9s%1?6b%4lz%X#z@>js~D2igB0gPHFX(Ll3x(MvFkzevyZi5*CzGW@LUEra=8$R=v z$Lqj=c|B44O=Gd{Zk`CVXcTw=6oH$-b)W)lSw0S&2i^g1fDisd+V15a(Gw@tGf4+0 z-2DfZ$=HtU4tCL6zdOXk?ry_Q##R^n={XtO*+tRCyI=(P3cLWSuJfX0o4}AW|1NMj zC3%min+WUxPl5ZuN9VwRWf#17(U_gnhyaqtLkOE~s;4RGS_on5RNe(PywnD=)Xn1E tRzZu;NSZz2Hk`GrD|_Mph?;1ElMg302r;d#O&$C~MJ;xc)WlF@I+&E1Oea=Qqj5qT`u4uSRHA8{ zn>lXxz2EzP{NC^Xe~+~V`Ew_vK9Gta$OLC@b`ktVwQus>@UK!^`z3770 zK#S(iK{H8)u|A3*nVYt5Je+r|;J)U=({j3BD^33FLU3kbf$wbBdgtPGsJq?K@|M%F z)pKuPPyN?v8v@gx{^Xg2nRC1Bms9EzyW1KazZ`$pvwdIg=wlvySGUvCyJL0X>Z|Vd z>JK*U`TX>`$=+=V4f)&NsBW)9(q^tWKBaFUxuMt9dC7EQsGdsSm6w=N-Z>3Cye9Si z!)My=CX@d3>MP6Ae%#QO|1q65e|Fo8L(>XU zSy`bV$1eve>H!sEz@{JQJgi4W!KPnGy9ig%0V>7ZS{W4A=9lob%Xvo7XFY+=3bD|D zAE+D}^7{e`8?x!cc3JqW4dZ$=3{jWc^pOp9y9!W;Bmpcuc@gq)EEttT!BNeFgQWs z6oo+qrmPI8TnGy&88HjlK;dOEsESem)hu!zsYU7kC`_fFA@@1!BoK7P91W#o@O!>-WdeikedmBZ}sBOSDq5G6?V@ zph#6R4|1xZ$BbBDidqClsJVmX5FTF~tdvwqsg%YbAwGQ*6{_eR!=W~F6BLBRF`(K^ z92#UDGT>B6E|DZ(Ogja!*ieT9&0Hu31gS=OR7*Pw2icqoYSYzw6CB90N zl(s%nU4q0z8}Yqh86I$?QSe|SCD0gUG%=XfED)I2W90>tnPMoKj#-;8i?F~s-)O5^ zR06apcsMg4EEddT1Rjh4Ff@JB_*Q1&ySQrLOiPNgkriVtugKkaGzN*NekqCcqQu~Pl%5Dc3nO_hP;bu^J zRMQn3jDgQp%`N;!ZT$z&uAS_t7JA;RG>CjMtf2* zSP^~liD|L;=)JV6*e1Uza*87Y=yM-|Eb^m$;k$ z(c8J~{=zBUm;2UE-qN7E=i&05U2_`kb-F@(68_w0#=qRS_fXTuSCdz*D?i?Iv}ex6 z@ed@M?HOx!6+J!4xXE#!ly2AAjhd z4-Oq_Ja27c>W(=MboWx1k|(WrD68jl;iu=?TIXGPvu^3Uy)DGd!HP;Mn%P zo7H>L4L>9T}hulwr8`!!c~A%jUXS0}kYx={Z2*9%`-lJ^xi{p96?^BZ<$432wy z#c$s0_amA4Cr>|ByZNuiD|y8XG2JAN_zde`v! cYTY*p{rLI&SG~wx*ZwPT=HzGZnNz;%-`xMn&;S4c literal 0 HcmV?d00001 diff --git a/static/src/assets/scoreboard/friendlyFire.png b/static/src/assets/scoreboard/friendlyFire.png new file mode 100644 index 0000000000000000000000000000000000000000..e69f7c5db07ae7f86864994e38806d938644f1ea GIT binary patch literal 3764 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 literal 0 HcmV?d00001 diff --git a/static/src/assets/scoreboard/kill.png b/static/src/assets/scoreboard/kill.png new file mode 100644 index 0000000000000000000000000000000000000000..478172716bd91960234f1ef369bc2d1d3f03b98a GIT binary patch literal 3665 zcmcIn32+nF8D7fg(S{J*_Ay&QDK$A{9Z9bW4GG27IE@o!lS(`f6+MB1nRcHo8TnJt z2?RyyCnCs%hIOwr7yh|q=(6Tfd51U8PQG^4Gk$uB>+GSIEx-IVYTsd6yUSu)=lH3x zyY8!u)xwx(FD;Ud&p(uVD`jEg;cfM%m(u#J4Bve{OpQK~@TTM3>r1CEy<^`IINh-O z@5jy$cQ(pG#f@77JF1Y3@e4i}5x$umI%jRVp+53;9hv!7VPaNU(LPXcfNnG?i<74 zb9aESDL>gb$uPV$H@I0*H*3V?-&}XJdPWYq$<*4oCY|TKgn{qn?VG#g_OR?hbx6yR zY4`8U%sC1pnc^uZ^&yBNOS%(+TXO;kl3LH(?0&m-D$R;+1tY~*5p;VX8bPvif*yvg z1b);3%6Y*czuD9*M|sX5pQEwjR*wl(@CCJAFtfJU#@1G{6erJl8qE&UP=Fiw88qm2 z2|hY#kVoXw@Ld{K%FzhKUulp>6Kc1XpeE4^P>n*1v4omLb(Dh8;uNW#gpxR+Q{p-$ zp~7&2#`Zs=TgKHMA6mFosw?bP?HIrFozd7vD!CLayteGX2uT;a!4aRhO04>vJo1ZAZSAS z6i(7O9)(&VF*(N1^ag7n-bNBMsioDb2f!l7J8K>Zb3 zv_v4kPIGqY32$crYYSb*I$0-&Aq*kqC9aQVM(x{nEbzu_cBYAKR}Y@sLubL!PNrq?he=AlTuSEOrxXp7(=Pmm_w=}mI6*Sqvo6}8P8$w96Ypb z{9j#RMIivZy(r~jybRoGf!Ak{JH4VCWjr1i&qgXs84$SG4i+z3)GwkvEvnCualp&> z%71SyaTCxVQQsrk_IMq$54L@~v;SBrQc4GiX!$F@-5H|a=4c$Bkunq6nCXZ0fXC$@ z+^K2U{Nvlf4{O{}{o?<+0Z5#QINs|d)jb4{XVPo@TnInnCrco}D)qv1<8y%w;PRL!8Jxurco^VZ5_=V~=Us?O*_2;XvT)cRBe-Uza z;%oDdf0L8(=}uhNbz?1wf;nY#7Q0)+<4$Jrwo?bT9F}#h-NIYujIGLhQ%2CqliDV2 z%3c)uyv3Lnn0kBipboibO#6VlR3Kql=(U#e)~DyLYrzJ%(mq|Vutv6CNPLn$xC5kY zlzp83Nnmj}-)NLwQiYXQ%}q&ks9$36lNBk0j}{!jyDCTJ57CzoX->TVi76M+*`I%b~~wf!|(RpI-U9#RgL4bP9Wm^m$s}AHJeUNzuwF@{Hrmi=+5qqNx!0+ zp06ug*1A!a(26-PcZ_FO|8=AFj|UQx1p7y}$*mpx_hv2Lx~jo^s^)sm%9?)bpB(%C zl!Ozr?TZKBc{^e9O2?F<>hQR?k>`st^l3XcbnRA7TW(Z#e2iRa`0YizEWe;g*D~qk ztfj_(4?WiZ?kfLGVNgbU>a&S2G~Q3-4IO{0$TPMilwGjwOUp(S)IO$c^cUCK-wIvc z)xjnww@>+M@4JPSU(Vlga%BCOBJ{LyRfbPr6C6E4-f?iHdfvbb4RgB&YNu}R9J#Lc i+JQ3%WqXHwk$!fk{!feT<1(dxES9`t^X@5SFa8HM=mCEK literal 0 HcmV?d00001 diff --git a/static/src/assets/scoreboard/respawn.png b/static/src/assets/scoreboard/respawn.png new file mode 100644 index 0000000000000000000000000000000000000000..40c8020545590c8c8cee954bdfd635a48784f7d1 GIT binary patch literal 678 zcmV;X0$KfuP)Lq)C7Rdl6oY4GsZlR&Fzr1PtsmV zJ0%sJ=}^+7q(_p*B~2J(=F&tr3;YCL135dE2QC3K_}M)00yvn4z$eF10ayz>Tx6m5 zz4(5m-~`Z-fGq+gU@Aspv|6p^dGfh#c* z7kmlqN=RcJ7zWM&w}GKXeu5w<0B3>7`uG71_z>9OQDmbF1?u7Nu7kUov~_Vnmq)eV z0P;<2N6o?ZxbsO-%uAY%o$r^Du1h*4X@3}o!*;x}&=~VU(lux3kPquV;3%*q2!a(r zyVZiU%DLUiz>{Usd|Su>wMJX;KNinPnzh{yF9JX}urfm)1z)yn99eyrQ3l$a8u;v! z0qnOISd{^XJx=>^BLcrAO*s9N84wt8+G9Q`JMN@x5-2Vq{ezCLufTd=Iez5;F9U@X zi+9@q7VIL><_kU&li%}AE?xx29sCTiwb=+tj)Mre2W<1e9R{Xj0Su$(76H9I)Ef&fA2`>%daZumR2iUlzF;e_2vVHU;d?M8={h>I1F>gt0y1rwS7m@8%f`dF;VO3)v`wR56mg4bjt0yUH||9 M07*qoM6N<$f-FZSn*aa+ literal 0 HcmV?d00001 diff --git a/static/src/assets/scoreboard/revive.png b/static/src/assets/scoreboard/revive.png new file mode 100644 index 0000000000000000000000000000000000000000..e8b826f2658c7d0f2613a6456faa75c1af261ad0 GIT binary patch literal 3645 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 K^Y+PQ3;zRpDFfF4 literal 0 HcmV?d00001 From 819f8ee469192a290a1c319536d70fcb797cc909 Mon Sep 17 00:00:00 2001 From: HardiReady Date: Sat, 5 May 2018 08:08:33 +0200 Subject: [PATCH 24/28] simplify code for highscore and use icons in highscore --- api/routes/_generic.js | 2 +- .../highscore/highscore.component.html | 210 +++--------------- .../campaign/highscore/highscore.component.ts | 5 +- .../fraction-stats.component.ts | 6 +- .../war/scoreboard/scoreboard.component.ts | 8 +- static/src/app/utils/player-utils.ts | 8 + 6 files changed, 46 insertions(+), 193 deletions(-) diff --git a/api/routes/_generic.js b/api/routes/_generic.js index 6843bb1..7cd0cb7 100644 --- a/api/routes/_generic.js +++ b/api/routes/_generic.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; // HTTP status codes by name const codes = require('./http-codes'); diff --git a/static/src/app/statistic/campaign/highscore/highscore.component.html b/static/src/app/statistic/campaign/highscore/highscore.component.html index a62c187..e739427 100644 --- a/static/src/app/statistic/campaign/highscore/highscore.component.html +++ b/static/src/app/statistic/campaign/highscore/highscore.component.html @@ -15,194 +15,42 @@
- - - - +
+ + + + {{value}} - - - - + + - - - - - + + + + + {{attributeMap.head}} + + + + + {{value}} - - - - - - - - - - - {{value}} - - - - - - - - - - - - {{value}} - - - - - - - - - - - - {{value}} - - - - - - - - - - - - {{value}} - - - - - - - - - - - - {{value}} - - - - - - - - - - - - {{value}} - - - - - - - - - - - - {{value}} - - - - - + + + +
diff --git a/static/src/app/statistic/campaign/highscore/highscore.component.ts b/static/src/app/statistic/campaign/highscore/highscore.component.ts index 32a3d82..b8064d0 100644 --- a/static/src/app/statistic/campaign/highscore/highscore.component.ts +++ b/static/src/app/statistic/campaign/highscore/highscore.component.ts @@ -6,6 +6,7 @@ import {Fraction} from '../../../utils/fraction.enum'; import {FormControl} from '@angular/forms'; import {Observable} from 'rxjs/Observable'; import {Player} from '../../../models/model-interfaces'; +import {PlayerUtils} from "../../../utils/player-utils"; @Component({ @@ -27,13 +28,15 @@ export class StatisticHighScoreComponent implements OnInit { playersStored = {}; + playerAttributeDisplayNames = PlayerUtils.attributeDisplayNames; + cellHeight = 40; numberColWidth = 60; nameColWidth = 210; - valueColWidth = 110; + valueColWidth = 50; emptyMessage = {emptyMessage: 'Keine Einträge'}; 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 cfb8cf5..3aa902f 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 @@ -45,9 +45,9 @@ export class FractionStatsComponent implements OnInit, OnChanges { labelPoints = 'Punkte'; labelBudget = 'Budget'; - labelKill = 'Kills'; - labelFriendlyFire = 'FriendlyFire'; - labelVehicle = 'Fahrzeug-Kills'; + labelKill = 'Abschüsse'; + labelFriendlyFire = 'Friendly Fire'; + labelVehicle = 'Fahrzeug Abschüsse'; labelTransport = 'Lufttransport'; labelRevive = 'Revive'; labelStabilize = 'Stabilisiert'; diff --git a/static/src/app/statistic/war/scoreboard/scoreboard.component.ts b/static/src/app/statistic/war/scoreboard/scoreboard.component.ts index 972b02e..ac2b5b3 100644 --- a/static/src/app/statistic/war/scoreboard/scoreboard.component.ts +++ b/static/src/app/statistic/war/scoreboard/scoreboard.component.ts @@ -19,13 +19,7 @@ export class ScoreboardComponent implements OnChanges { @Output() playerTabSwitch = new EventEmitter(); - tableHead = [ - {prop: 'name', head: 'Spieler'}, {prop: 'fraction', head: 'Fraktion'}, {prop: 'kill', head: 'Abschüsse'}, - {prop: 'friendlyFire', head: 'Friendly Fire'}, {prop: 'vehicleLight', head: 'Fahrzeug (leicht)'}, - {prop: 'vehicleHeavy', head: 'Fahrzeug (schwer)'}, {prop: 'vehicleAir', head: 'Fahrzeug (Luft)'}, - {prop: 'revive', head: 'Revive'}, {prop: 'flagTouch', head: 'Eroberungen'}, {prop: 'death', head: 'Tode'}, - {prop: 'respawn', head: 'Respawn'} - ]; + tableHead = PlayerUtils.attributeDisplayNames; isSteamUUID = PlayerUtils.isSteamUUID; diff --git a/static/src/app/utils/player-utils.ts b/static/src/app/utils/player-utils.ts index 9a192df..7f530d7 100644 --- a/static/src/app/utils/player-utils.ts +++ b/static/src/app/utils/player-utils.ts @@ -1,5 +1,13 @@ export class PlayerUtils { + public static readonly attributeDisplayNames = [ + {prop: 'name', head: 'Spieler'}, {prop: 'fraction', head: 'Fraktion'}, {prop: 'kill', head: 'Abschüsse'}, + {prop: 'friendlyFire', head: 'Friendly Fire'}, {prop: 'vehicleLight', head: 'Fahrzeug (leicht)'}, + {prop: 'vehicleHeavy', head: 'Fahrzeug (schwer)'}, {prop: 'vehicleAir', head: 'Fahrzeug (Luft)'}, + {prop: 'revive', head: 'Revive'}, {prop: 'flagTouch', head: 'Eroberungen'}, {prop: 'death', head: 'Tode'}, + {prop: 'respawn', head: 'Respawn'} + ]; + public static isSteamUUID(input: string): boolean { const steamUIDPattern = new RegExp('[0-9]{17}'); return steamUIDPattern.test(input); From e54168ec2264672be0b178ce34d2c5e6004f8766 Mon Sep 17 00:00:00 2001 From: HardiReady Date: Sat, 5 May 2018 08:17:17 +0200 Subject: [PATCH 25/28] Fix linting --- .../src/app/statistic/campaign/highscore/highscore.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/src/app/statistic/campaign/highscore/highscore.component.ts b/static/src/app/statistic/campaign/highscore/highscore.component.ts index b8064d0..519bab5 100644 --- a/static/src/app/statistic/campaign/highscore/highscore.component.ts +++ b/static/src/app/statistic/campaign/highscore/highscore.component.ts @@ -6,7 +6,7 @@ import {Fraction} from '../../../utils/fraction.enum'; import {FormControl} from '@angular/forms'; import {Observable} from 'rxjs/Observable'; import {Player} from '../../../models/model-interfaces'; -import {PlayerUtils} from "../../../utils/player-utils"; +import {PlayerUtils} from '../../../utils/player-utils'; @Component({ From d6703f715df18bdf7c9ad64063ea60028ee78421 Mon Sep 17 00:00:00 2001 From: HardiReady Date: Sat, 5 May 2018 09:14:49 +0200 Subject: [PATCH 26/28] Simplify highscore code and adjust font in table head --- .../campaign-player-detail.component.ts | 2 +- .../highscore/highscore.component.css | 4 ++++ .../highscore/highscore.component.html | 2 +- .../campaign/highscore/highscore.component.ts | 20 +++++++------------ .../war/scoreboard/scoreboard.component.css | 4 ++++ 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/static/src/app/statistic/campaign/campaign-player-detail/campaign-player-detail.component.ts b/static/src/app/statistic/campaign/campaign-player-detail/campaign-player-detail.component.ts index a84c77f..c0f6953 100644 --- a/static/src/app/statistic/campaign/campaign-player-detail/campaign-player-detail.component.ts +++ b/static/src/app/statistic/campaign/campaign-player-detail/campaign-player-detail.component.ts @@ -60,7 +60,7 @@ export class CampaignPlayerDetailComponent implements OnInit { this.campaignPlayer = campaignPlayer; this.graphData = [ - { key: 'kill', label: 'Kills', }, + { key: 'kill', label: 'Abschüsse', }, { key: 'friendlyFire', label: 'Friendly Fire', }, { key: 'death', label: 'Tode', }, { key: 'respawn', label: 'Respawn', }, diff --git a/static/src/app/statistic/campaign/highscore/highscore.component.css b/static/src/app/statistic/campaign/highscore/highscore.component.css index 6e8508b..da5284b 100644 --- a/static/src/app/statistic/campaign/highscore/highscore.component.css +++ b/static/src/app/statistic/campaign/highscore/highscore.component.css @@ -57,6 +57,10 @@ ngx-datatable { background-color: #f7f7f7; } +:host /deep/ .ngx-datatable.fixed-header .datatable-header .datatable-header-inner .datatable-header-cell { + margin: auto; +} + /* Table Scrollbar BEGIN */ :host /deep/ .ngx-datatable.scroll-vertical .datatable-body::-webkit-scrollbar { diff --git a/static/src/app/statistic/campaign/highscore/highscore.component.html b/static/src/app/statistic/campaign/highscore/highscore.component.html index e739427..475e567 100644 --- a/static/src/app/statistic/campaign/highscore/highscore.component.html +++ b/static/src/app/statistic/campaign/highscore/highscore.component.html @@ -15,7 +15,7 @@ -
+
Date: Sat, 5 May 2018 09:32:16 +0200 Subject: [PATCH 27/28] Adjust player stat attribute order; improve code for player campaign stats init --- .../campaign-player-detail.component.ts | 28 ++++++++----------- static/src/app/utils/player-utils.ts | 14 +++++++--- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/static/src/app/statistic/campaign/campaign-player-detail/campaign-player-detail.component.ts b/static/src/app/statistic/campaign/campaign-player-detail/campaign-player-detail.component.ts index c0f6953..9ac834a 100644 --- a/static/src/app/statistic/campaign/campaign-player-detail/campaign-player-detail.component.ts +++ b/static/src/app/statistic/campaign/campaign-player-detail/campaign-player-detail.component.ts @@ -2,6 +2,7 @@ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {CampaignPlayer} from '../../../models/model-interfaces'; import {PlayerService} from '../../../services/logs/player.service'; import {ChartUtils} from '../../../utils/chart-utils'; +import {PlayerUtils} from '../../../utils/player-utils'; @Component({ @@ -18,7 +19,7 @@ export class CampaignPlayerDetailComponent implements OnInit { @Output() switchTab = new EventEmitter(); - campaignPlayer: CampaignPlayer = { campaign: {}, players: [] }; + campaignPlayer: CampaignPlayer = {campaign: {}, players: []}; graphData: any[] = []; sumData: any[] = []; @@ -51,6 +52,8 @@ export class CampaignPlayerDetailComponent implements OnInit { respawnDeathRatio = 0; maxRespawnDeathRatio = 1; + playerAttributeNameMap = PlayerUtils.attributeDisplayNames.slice(2, PlayerUtils.attributeDisplayNames.length); + constructor(private playerService: PlayerService) { } @@ -59,32 +62,25 @@ export class CampaignPlayerDetailComponent implements OnInit { .subscribe(campaignPlayer => { this.campaignPlayer = campaignPlayer; - this.graphData = [ - { key: 'kill', label: 'Abschüsse', }, - { key: 'friendlyFire', label: 'Friendly Fire', }, - { key: 'death', label: 'Tode', }, - { key: 'respawn', label: 'Respawn', }, - { key: 'revive', label: 'Revive', }, - { key: 'flagTouch', label: 'Eroberungen', }, - { key: 'vehicleLight', label: 'Fahrzeug (Leicht)', }, - { key: 'vehicleHeavy', label: 'Fahrzeug (Schwer)', }, - { key: 'vehicleAir', label: 'Fahrzeug (Luft)', }, - ]; + for (let i = 0; i < this.playerAttributeNameMap.length; i++) { + const attr = this.playerAttributeNameMap[i]; + this.graphData.push({key: attr.prop, label: attr.head}); + } this.initDataArray(); - const totalDeathDiv = this.graphData[2].total === 0 ? 1 : this.graphData[2].total; + const totalDeathDiv = this.graphData[7].total === 0 ? 1 : this.graphData[7].total; this.kdRatio = parseFloat((this.graphData[0].total / totalDeathDiv).toFixed(2)); if (this.kdRatio > 1) { this.maxKd = this.kdRatio * 1.7; } - this.respawnDeathRatio = parseFloat((this.graphData[3].total / totalDeathDiv).toFixed(2)); + this.respawnDeathRatio = parseFloat((this.graphData[8].total / totalDeathDiv).toFixed(2)); // we can not directly push to target array, since only full reference changes trigger the refresh of data const tmpSumData = []; this.graphData.forEach(dataSet => { - tmpSumData.push({ name: dataSet.label, value: dataSet.total }); + tmpSumData.push({name: dataSet.label, value: dataSet.total}); }); this.sumData = tmpSumData; }); @@ -109,7 +105,7 @@ export class CampaignPlayerDetailComponent implements OnInit { } dataSet.data = [killObj]; - dataSet.refLine = [{ value: total / playerLength, name: this.avgLabel }]; + dataSet.refLine = [{value: total / playerLength, name: this.avgLabel}]; dataSet.total = total; }); } diff --git a/static/src/app/utils/player-utils.ts b/static/src/app/utils/player-utils.ts index 7f530d7..b2957ab 100644 --- a/static/src/app/utils/player-utils.ts +++ b/static/src/app/utils/player-utils.ts @@ -1,10 +1,16 @@ export class PlayerUtils { public static readonly attributeDisplayNames = [ - {prop: 'name', head: 'Spieler'}, {prop: 'fraction', head: 'Fraktion'}, {prop: 'kill', head: 'Abschüsse'}, - {prop: 'friendlyFire', head: 'Friendly Fire'}, {prop: 'vehicleLight', head: 'Fahrzeug (leicht)'}, - {prop: 'vehicleHeavy', head: 'Fahrzeug (schwer)'}, {prop: 'vehicleAir', head: 'Fahrzeug (Luft)'}, - {prop: 'revive', head: 'Revive'}, {prop: 'flagTouch', head: 'Eroberungen'}, {prop: 'death', head: 'Tode'}, + {prop: 'name', head: 'Spieler'}, + {prop: 'fraction', head: 'Fraktion'}, + {prop: 'kill', head: 'Abschüsse'}, + {prop: 'friendlyFire', head: 'Friendly Fire'}, + {prop: 'revive', head: 'Revive'}, + {prop: 'flagTouch', head: 'Eroberungen'}, + {prop: 'vehicleLight', head: 'Fahrzeug (leicht)'}, + {prop: 'vehicleHeavy', head: 'Fahrzeug (schwer)'}, + {prop: 'vehicleAir', head: 'Fahrzeug (Luft)'}, + {prop: 'death', head: 'Tode'}, {prop: 'respawn', head: 'Respawn'} ]; From be9bdc23d471c90302f742d347076216b45903bd Mon Sep 17 00:00:00 2001 From: HardiReady Date: Sat, 5 May 2018 09:43:14 +0200 Subject: [PATCH 28/28] clean up import --- static/src/app/app.routing.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/static/src/app/app.routing.ts b/static/src/app/app.routing.ts index bf03c99..1bc7229 100644 --- a/static/src/app/app.routing.ts +++ b/static/src/app/app.routing.ts @@ -1,7 +1,6 @@ import {RouterModule, Routes} from '@angular/router'; -import {LoginComponent, LoginGuardMT} from './login'; import {NotFoundComponent} from './common/not-found'; -import {LoginGuardAdmin, LoginGuardHL} from './login'; +import {LoginComponent, LoginGuardAdmin, LoginGuardHL, LoginGuardMT} from './login'; import {armyRoutes, armyRoutingComponents} from './army/army.routing'; import {SignupComponent} from './login/signup.component'; import {RouteConfig} from './app.config';