From 39729f0566512f83457c47e6453b83a5eda41ed4 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Wed, 6 Jun 2018 10:28:42 +0100 Subject: [PATCH 1/8] Test --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 705573f387..7526ff0f35 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "start": "npm run customize && ng serve", "start-prod": "ng serve --prod --aot=false --source-map=true", "test": "ng test --code-coverage", + "test-nocov": "ng test", "test-debug": "ng test --watch=true --source-map=true", "test-headless": "CI_ENV=true npm run test", "codecov": "codecov -f coverage/*.json", From 61929d7c0e10010e7137d8568b79f90d165127fb Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Wed, 6 Jun 2018 10:54:19 +0100 Subject: [PATCH 2/8] Don't run with coverage when running unit tests in Travis --- .travis.yml | 4 +++- deploy/ci/travis/run-e2e-tests.sh | 0 deploy/ci/travis/run-unit-tests.sh | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) mode change 100644 => 100755 deploy/ci/travis/run-e2e-tests.sh create mode 100755 deploy/ci/travis/run-unit-tests.sh diff --git a/.travis.yml b/.travis.yml index dc3a472516..424d54dc03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,8 +34,10 @@ jobs: - stage: Frontend Unit Tests env: - CI_ENV=true + before_script: + - chmod +x ./deploy/ci/travis/run-unit-tests.sh script: - - npm test + - "./deploy/ci/travis/run-unit-tests.sh" - npm run codecov - stage: Backend before_script: diff --git a/deploy/ci/travis/run-e2e-tests.sh b/deploy/ci/travis/run-e2e-tests.sh old mode 100644 new mode 100755 diff --git a/deploy/ci/travis/run-unit-tests.sh b/deploy/ci/travis/run-unit-tests.sh new file mode 100755 index 0000000000..73152842ae --- /dev/null +++ b/deploy/ci/travis/run-unit-tests.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -e + +echo "Stratos Unit tests" +echo "==================" + +if [ "${TRAVIS_EVENT_TYPE}" == "pull_request" ]; then + echo "Pull Request - running unit tests without code coverage" + npm run test-nocov +else + echo "Running unit tests with code coverage" + npm run test +fi + From 0fe99a63b518072eb7a558e18e1648f9bf075eb7 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Wed, 6 Jun 2018 12:03:25 +0100 Subject: [PATCH 3/8] Remove codecov reporter for now --- karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/karma.conf.js b/karma.conf.js index 0bb253ca4f..d2f45289a4 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -8,7 +8,7 @@ module.exports = function (config) { require('karma-jasmine'), require('karma-chrome-launcher'), require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), +// require('karma-coverage-istanbul-reporter'), require('karma-spec-reporter'), require('@angular-devkit/build-angular/plugins/karma'), require('./build/karma.test.reporter.js') From 2d2757c9d7119db7d3ed063a4bd3b8a80674828a Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Fri, 23 Nov 2018 16:14:18 +0000 Subject: [PATCH 4/8] Git Repo autocomplete --- .../deploy-application-step2.component.html | 7 ++- .../deploy-application-step2.component.ts | 36 ++++++++++++++- .../components/list/list.component.html | 4 +- .../components/list/list.component.scss | 4 ++ .../components/list/list.component.theme.scss | 8 ++++ .../shared/data-services/scm/github-scm.ts | 17 ++++++- .../shared/data-services/scm/gitlab-scm.ts | 14 ++++++ .../app/shared/data-services/scm/scm.ts | 1 + .../assets/fonts/stratos/stratos-icons.eot | Bin 24658 -> 23650 bytes .../assets/fonts/stratos/stratos-icons.svg | 43 +++++++----------- .../assets/fonts/stratos/stratos-icons.ttf | Bin 24476 -> 23468 bytes .../assets/fonts/stratos/stratos-icons.woff | Bin 14676 -> 14020 bytes .../assets/fonts/stratos/stratos-icons.woff2 | Bin 12504 -> 11928 bytes 13 files changed, 102 insertions(+), 32 deletions(-) diff --git a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.html b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.html index 98fa3e6c6c..b0082f1ff7 100644 --- a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.html +++ b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.html @@ -17,7 +17,12 @@
- + + + + {{repo}} + + Project does not exist diff --git a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts index 90eb87968d..b749508be5 100644 --- a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts +++ b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts @@ -2,8 +2,8 @@ import { AfterContentInit, Component, Inject, Input, OnDestroy, OnInit, ViewChil import { NgForm } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { Store } from '@ngrx/store'; -import { combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs'; -import { filter, map, take, tap, withLatestFrom } from 'rxjs/operators'; +import { combineLatest as observableCombineLatest, Observable, timer as observableTimer, of as observableOf, Subscription } from 'rxjs'; +import { filter, map, take, tap, withLatestFrom, switchMap } from 'rxjs/operators'; import { EntityServiceFactory } from '../../../../core/entity-service-factory.service'; import { StepOnNextFunction } from '../../../../shared/components/stepper/step/step.component'; @@ -76,9 +76,16 @@ export class DeployApplicationStep2Component scm: GitSCM; + // We don't have any repositories to suggest initially - need user to start typing + suggestedRepos$: Observable; + + cachedSuggestions = {}; + // Local FS data when file or folder upload // @Input('fsSourceData') fsSourceData; + lastProjectName: string = null; + @ViewChild('sourceSelectionForm') sourceSelectionForm: NgForm; subscriptions: Array = []; @@ -274,6 +281,31 @@ export class DeployApplicationStep2Component this.subscriptions.push(setInitialSourceType$.subscribe()); this.subscriptions.push(setSourceTypeModel$.subscribe()); this.subscriptions.push(setProjectName.subscribe()); + + this.subscriptions.push(this.sourceSelectionForm.valueChanges.subscribe(form => { + if (form.projectName !== this.lastProjectName) { + // Go and fetch the matching list of repositories and make that the auto-complete list + this.suggestedRepos$ = this.updateSuggestedRepositories(form.projectName); + } + this.lastProjectName = form.projectName; + })); + } + + updateSuggestedRepositories(name: string): Observable { + if (!name || name.length < 3) { + return observableOf([] as string[]); + } + + const cacheName = this.scm.getType() + ':' + name; + if (this.cachedSuggestions[cacheName]) { + return observableOf(this.cachedSuggestions[cacheName]); + } + + return observableTimer(500).pipe( + take(1), + switchMap(() => this.scm.getMacthingRepositories(name)), + tap(suggestions => this.cachedSuggestions[cacheName] = suggestions) + ); } setSourceType = event => this.store.dispatch(new SetAppSourceDetails(event)); diff --git a/src/frontend/app/shared/components/list/list.component.html b/src/frontend/app/shared/components/list/list.component.html index 5c68a99651..6deb43970d 100644 --- a/src/frontend/app/shared/components/list/list.component.html +++ b/src/frontend/app/shared/components/list/list.component.html @@ -14,7 +14,7 @@
{{dataSource.selectedRows.size}} Selected
- + All @@ -29,7 +29,7 @@
- +
diff --git a/src/frontend/app/shared/components/list/list.component.scss b/src/frontend/app/shared/components/list/list.component.scss index 3a0db2c14c..260b0a6371 100644 --- a/src/frontend/app/shared/components/list/list.component.scss +++ b/src/frontend/app/shared/components/list/list.component.scss @@ -74,6 +74,10 @@ justify-content: flex-end; } + &__right-filter { + width: auto; + } + &__left { flex: 1; diff --git a/src/frontend/app/shared/components/list/list.component.theme.scss b/src/frontend/app/shared/components/list/list.component.theme.scss index 6c51012b83..14b4833757 100644 --- a/src/frontend/app/shared/components/list/list.component.theme.scss +++ b/src/frontend/app/shared/components/list/list.component.theme.scss @@ -18,3 +18,11 @@ } } } + +.list-component__header__right-filter .mat-form-field-infix { + width: auto; +} + +#list-component__header-filter_cf .mat-form-field-infix { + width: 140px; +} diff --git a/src/frontend/app/shared/data-services/scm/github-scm.ts b/src/frontend/app/shared/data-services/scm/github-scm.ts index d89c94251d..648b6dd64b 100644 --- a/src/frontend/app/shared/data-services/scm/github-scm.ts +++ b/src/frontend/app/shared/data-services/scm/github-scm.ts @@ -1,6 +1,6 @@ import { GitSCM, SCMIcon } from './scm'; import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; +import { map, filter } from 'rxjs/operators'; import { Http } from '@angular/http'; import { GitSCMType } from './scm.service'; import { GitRepo, GitCommit, GitBranch } from '../../../store/types/git.types'; @@ -60,4 +60,19 @@ export class GitHubSCM implements GitSCM { return `https://github.com/${projectName}/compare/${commitSha1}...${commitSha2}`; } + getMacthingRepositories(projectName: string): Observable { + const prjParts = projectName.split('/'); + let url = `${this.gitHubURL}/search/repositories?q=${projectName}+in:name`; + if (prjParts.length > 1) { + url = `${this.gitHubURL}/search/repositories?q=${prjParts[1]}+in:name+user:${prjParts[0]}`; + } + return this.http.get(url).pipe( + map(response => response.json()), + filter(repos => !!repos.items), + map(repos => { + return repos.items.map(item => item.full_name); + }) + ); + } + } diff --git a/src/frontend/app/shared/data-services/scm/gitlab-scm.ts b/src/frontend/app/shared/data-services/scm/gitlab-scm.ts index a3d67ba532..81472de638 100644 --- a/src/frontend/app/shared/data-services/scm/gitlab-scm.ts +++ b/src/frontend/app/shared/data-services/scm/gitlab-scm.ts @@ -97,6 +97,20 @@ export class GitLabSCM implements GitSCM { return `https://gitlab.com/${projectName}/compare/${commitSha1}...${commitSha2}`; } + getMacthingRepositories(projectName: string): Observable { + const prjParts = projectName.split('/'); + let url = `${gitLabAPIUrl}/projects?search=${projectName}`; + if (prjParts.length > 1) { + url = `${gitLabAPIUrl}/users/${prjParts[0]}/projects?search=${prjParts[1]}`; + } + return this.http.get(url).pipe( + map(response => response.json()), + map(repos => { + return repos.map(item => item.path_with_namespace); + }) + ); + } + private convertProject(prj: any): GitRepo { return { ...prj, diff --git a/src/frontend/app/shared/data-services/scm/scm.ts b/src/frontend/app/shared/data-services/scm/scm.ts index bb971a70c6..e75722a368 100644 --- a/src/frontend/app/shared/data-services/scm/scm.ts +++ b/src/frontend/app/shared/data-services/scm/scm.ts @@ -19,4 +19,5 @@ export interface GitSCM { getCloneURL(projectName: string): string; getCommitURL(projectName: string, commitSha: string): string; getCompareCommitURL(projectName: string, commitSha1: string, commitSha2: string): string; + getMacthingRepositories(projectName: string): Observable; } diff --git a/src/frontend/assets/fonts/stratos/stratos-icons.eot b/src/frontend/assets/fonts/stratos/stratos-icons.eot index 28fec8c5404ca16e2c762728dd0e0c1e8b5f412c..55f47d72b705ccfdc841ac54e79b27776c0751c7 100644 GIT binary patch delta 2645 zcmb7GeQZm-Is-aD6nw0&X ziB@T%NPE}!-gAEE^B&*(?tAAFfA9*c6O%+2_McNF?b^o&uAdt_8(mz~$B4Lxh+4Lc z-?N!coqIoB`{xb$Q=l&rY2_VXUR&5%`bv>V{}5USr=}~_Ba7v45vg(L9Gd#td>e2) z+dje&I#NA4{ah*h7WkWB-J_McD)2D)_c5DCAO6OXr#q$;k?}*K(ZI38m4}?yX8uUD z`Dc)qjvYH(tH}3+1aKWd$Fb@8Q(wP(`ENv9;DkdD&rVgQUfXLEZEb`6$?3|es(3cM z5&Q-4Z8MeW!?Wv-ybk{N(7#xnotwYE5cY$GUMAWPfAl?cMyGeL zzI)A|ukPu1rso!c*%#U9E$9MG(kfsrw8?7|kLKiu6rnD9oPNt?KFE*qS$>XR;VU98 z4vGaCmK)`d=mKc3UzNVk>ptoD^XV1@2>le zkO4~t)TN^LiJn+B47o{Bcy#O9eheRRX`R=mT6w)Urc(Ee0g1q?pM?eulgjYqXW9g9 ze~}w7Mo~r|GielAI?x`emnB-ybEEgX%JL@fO*Oz*y??1u?(&9>9o)6_r12Z8c9Hk; zB}&m%HaW-RT-(q^pVDDEL^}~ur!W_}hZ7v48V%6^YN{h4|9?0O_YSDH=~;{xw0})6 zfHIMyPTP5ZXh`TYB$rT5OO8H*S=Y|H$Tu8GUPn3pA10z6+z1*MA-D*XE zL%DokE}zNgvU!!ov?2l0!dX|v6KL=V#Zqx_Evt-?jTuLkftFQ9rkndzzcTt90X-i? z3$f8>#N0l&;2Q%-fEb8l96%a{0W@ELHV_BvyS~*1O2Ck3X_S#iaj@Sz+nB5=V}yN$ zG8YGXxtlY}jm29z&BmRVj6Cj8kPjS}wQQz0lhv4GPLkcu)txSH(R8H?#-o(32Q&?D z9wAsr#)cD`rt4aRp-CxqOHRW5Jy=7Qx ztiwTh?{J^vFbAAeAtly~Isp-J_{8nkm%Kgvsoj(8S+568$1#KYdN8(|YHW>0TN`Vs z8-6`Bzbbwi1gZcAMe!ejJTdxR!%~=aqd_!8W9f7(8qh*QCYIFz~p zODPRQnJAY+sn~}BnWzoxh*MLVtOw8~6LO4Ydg045zp_c>WKy^M|%u7Dtnv9gWSlWu2ZI*VlEyk9${Sd!;{>1LZW??GskF`4@*j&hVrP4XoZdp!{bLmu9w$L0D zb|T)>B-k*`l+eS5QbxoM2xW@oA5UC1RvVYi&E{KHv?0*&OMBS9;ymVD z3EvyBBhN>lY7E65a+}=w_@5Hxrmkcm`BL&9%{N!gw~V!1Pd%8PX&r7|gmXX2xYxCP zL+viyX18K$c>k|kp>Xh~n9@2t=obpE_T>-b=~ zu|g|qW@m2xWMzJKZq4zj*_k;E-bdTBvbd(?IrlxS7x8&f@?N@c(ld6nG4k8-g!hXb X-&N}9@%dwqES=sN;HAY~Z-@Q^Vh(B2 delta 3680 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 -Created by FontForge 20180321 at Fri Nov 23 09:57:20 2018 +Created by FontForge 20180321 at Mon Jun 25 13:57:16 2018 By Neil MacDougall @@ -15,10 +15,10 @@ Created by FontForge 20180321 at Fri Nov 23 09:57:20 2018 panose-1="2 0 5 3 0 0 0 0 0 0" ascent="448" descent="-64" - bbox="-0.595506 -64 512 448" + bbox="-0.595506 -64.5 512 448" underline-thickness="25" underline-position="-76" - unicode-range="U+005F-F12C" + unicode-range="U+005F-F128" /> @@ -38,15 +38,15 @@ d="M7 -64v43h384v-43h-384zM199 192q52 0 91 -10.5t59.5 -27.5t32.5 -37.5t14 -41t1. v-43h256z" /> - + @@ -71,21 +71,10 @@ t-15.5 15.5t-22 5.5q-17 0 -29.5 -12.5t-12.5 -30t12.5 -30t30 -12.5t30 12.5t12.5 3 - - - - +d="M256 442q106 0 181 -75t75 -181q0 -84 -49 -150.5t-126 -92.5q-9 -2 -13.5 2t-4.5 10q0 1 0.5 25.5t0.5 44.5q0 33 -18 48q25 2 43.5 8.5t36.5 19.5t27.5 38t9.5 60q0 40 -26 69q12 30 -3 68q-21 6 -70 -27q-30 9 -64 9t-64 -9q-22 15 -39.5 21.5t-24.5 5.5h-6 +q-15 -38 -3 -68q-26 -29 -26 -69q0 -35 9.5 -60t27.5 -38t36.5 -19.5t42.5 -8.5q-13 -12 -16 -35q-49 -22 -74 22q-14 24 -40 26q-2 0 -5 -0.5t-6.5 -4t10.5 -11.5q16 -8 28 -37q1 -2 2.5 -4.5t7.5 -10.5t15 -11.5t25 -6.5t36 3v-15.5v-14.5t0.5 -11t0.5 -7q0 -6 -4.5 -10 +t-13.5 -2q-77 25 -126 92t-49 151q0 106 75 181t181 75z" /> @@ -235,5 +224,7 @@ d="M0 0z" /> d="M0 0z" /> + + diff --git a/src/frontend/assets/fonts/stratos/stratos-icons.ttf b/src/frontend/assets/fonts/stratos/stratos-icons.ttf index 9dd19a9475a8ae594f22ca60f9d27e8e96f0c62e..084fdf5f417073f980211789550319d7efee02f9 100644 GIT binary patch delta 2722 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 delta 12532 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 W3+3fS2KL>(sHkFf`Ur3 zSF>&pB(&ygeOll+FDS!Kp6Bt;|Ms~zc`tc@KQS;eX2z{iRDdh6rh2KGwes`tT;Dm@ za^p9Rw53QePm5V)fDwGm&@lntu6LOgG5gwIm*Hufe}|57le!Zy>ImyS#6XPVv=@Dc z^A{Fw9~SLzZq1@)73LQf&cA3}>Hi-W70zXIlJn!2cXz_w-|iWKAt3P*fZ*U2cs_L{7gfRveC3Bda)=y~ z7ZSc>DJb3UZBbuQyQ`jj{PXMlr!-V6QSYR|&SCIxn$0GqDh456&}+IsTalA}u+zg! z)zbSiWL?#Rc4HOGBy+bK%Rwc3VKx zm_Yj*)B1&!KBqB;G@}TphzJku+54?T03pz;X&=M{Pta|{+2EQNow#8M0ovDHLI7WU zdEp^~@a3_~*OG4!fi7SQC=gT*s#QU-xR$eehkAqXqSN>9fTZrNAgle*@Ry$-bVftmiR#c3z#2=DUTgSTCxjD$C`&%kT3d z4O>$uB19}1OhlqWXqyi8SI+1w$!qXy~UkqnH~yyBY03yAdXo4@n(4-H;9Q)J`Ug0~4>2?Mg0v&o07^ znD9Z&>Be!MG03Ca!$74{K#}=)sB}c>(=c!AMO9a$q!!~6_Qn;Yk(}k*)05_TY1}cH zhdSpYQonq-^FVUGPk|qEvb+tqAv{GBu5N%WqBWcuXd!)}g&>=QZn)`@f8vkmsc+S_YFit7bCU0bw3W6d#RPg1 z@8m>JZ}k5$B~}%h)D6=DyT?`iDL)9KbS4WmlkoMftDMmzz{xO-B41CyX@5oB{|XH5 z(eavQ(w%&Pcs`X$qOFPU7;AyEKt%^VAgUzqK#1$iK~U>1IVdvSr|akDe2Xth$rrNT z`qDaGfoNk-unoW2b@{i3-3 zJfEmEVSa-Xo;G8g<_JcN+LLGz)w+}D;K)#5o~MGQm4Id*X&!vWpREpI>j-Gbv}hAA zDNt9#R2{-Fus)o?$99pHbPm3EK1wp%3QmmGkXB4yi$SA}Lh(M(bpuJF8uK|c&{g$7 zT#WK{A?8(pW}hLG8TbQMw6Q}+G)1RQgz1tyL$Sv6R2nS4mO-ztrOMFXx2@)4Oj?m) zNoa(jKn3PWhFx=WsA_2&a?Wsw_bNEBngn&tgW}JPozPu#J%bAa;2wmfXn0D}tsmo= zS4WDk8=z>2s>uUJAo?scf>+ug7P$1QACR3|1*gRfDpaOAU+zVAcxT#{q z@JcAQ^I`70#tk+%)Yxj4fu~_uz@H+1#At*+Mrlkr8AqKO_thu>XLJAxnC?+(LvvH-Io4DAC(4!9q9BsP=9|M?`_Ja-=Cp zNJb(gD^XG-F_M!wsg(q&lQdE^IEZTRB9$8a>@!z(^rS40djGz#cX?ay z|DzN$M{m>?%;UWp?1F3`($I8T(jQD@syceT{9SZ04)R20eEGDclxpn=FrSXWf*B>to!d0P{}VHBh(if z$0(l%YQo!Kj6za$OKKSd&3$J4bNBSI*~=1kpokBe??*FkoW1WD2Z%_Uhxu9Msavd6 z##FW2^_fW1$vc|~l#+ULj3CSl))dxnf>68-`|Nl*HmgZlu8H2OU`V=V;fJZCgwT-P zlmv{qNx+n*3Rj+{c}&?n^)%j{tav!92(0L+c~PZ%BZyyB1(%p)Y3Ru62qogdJqIVt z!K6V2Bu5%1#?uq2IXXHfVMvNb;04Xl=A~mQIfcPWj(`%O0as1i4{D-;JQp|-YH8HY zx`_l`bV|6vL3rdWpTEIq4m`zy;fdS`5lnLy4U2tiA*8%@t9p0St~vE3BBA z^+%Q_)+Nb7u4xp| zH)SmI^@i3tRi%+yU&@|7M=@sH^PisW`9m@8z+etcVOFE#)QP*w8XI*a^BZ8i0t637 z#wIGOr-UI#)t??Q!ai^JFu0$UGd06w$5Gn&F$&<9#mLfIfUzrC3_~pl8_!S*??AhkQM!GBy)nY(azW5*v+u z3XB6lj_c+g|XjPnE-7l2+98;x5Ej5|Oc>lD}(f6l3l*8~`EfPNAijc*E!ACUdi zdp>U`7$Ww1HZ{iZz}&ix(O1YGdbYCnqW0W4IK(gXup?UhCw=nY`6vVJHR%7N@PF?9 z`TKnSQoEF)5TqE3+Z<2945UbX1?RRSXeqCu1O#0WRB@}L4tb8&l>V(ERcZ<1Yl7~2 zC59$L7rMsVrs|#h-zL|MTU+7%J%zWEQ$pI7y1q}kY(@Ry0p=BL-u!QtC2~Y7w~hDt zz0ZmI#cm)~F*~+0?wW;3mcD-JJT#Hn(D|b9|sHmHX(T?NSjg7XAP7lD;6$ ztG)V(cuZ6}t0@B8Iy> zUSxrA42rU$u%ihXQ}Jth$BQ!#1Kq!HU}oBJ#*$=q?$EitO{WxXq#%4cEFFpa{xH^e)+y53+4tkxu?ACQV+E5NtKV>Ps1d{~4#79gR z^%GC#1jx)}iDZX_6xjGQrSUBro@*TF|~<0sJI+lbrh15BwlALLgGnYJw3-j znNZ>w0O4A&U>pcG9WQt!2QQKN#8XJ{rd;fIj4RT$4!X*~{>2XT(WEjeeoJ9(x!BP}2gOLIMxQwicO z?4x&Xsf#HuLTp)T4SFe-k>lljcH?s9jYPb?7wy{TjF;e&6Oq42kn&#WKKHx^{%f;~ z-_-h-t?z_})WoJ~BCx^4rDYqlH00M!@xWyoQ&-pRLsCier?hPiv4Zgk35LqMC|`^( z>AraGIg=Xczu1)*RUv4J6}D6R^2Ha^v|2*pJl7Hz^s2ZkR~9izyBEZBK?kby9z7hO z{Q4OZ@@(!RNW6<%fiO|dDt!Do<1kQZ9(swy$JXVTLr#mK0AXlMB`7g|2gf0@2eKp+ zWdJp-9`Y+FQO>b0mq9pfg(q*ao&ll%Wp*lVw?Uj&{SVbfeL)Nc#@Wi~7yUTOx>+Uv z2ifiNoOq#&KNe#4=1F}>W`HQQY7~zu0s{ddA^VpAaUVNtF?Ey)ejq1$qz2Hu1_yVR zvr%gv&jwtPc`Atw2ewplSk0ea9d;MeOk72oqY{X0cxoM$Vy?b!D2w7~1woPph3bO| zbWF6=cjQYAy(t(YG?NH}ai9-2(smHoQE~b3>H|kIEmGJsaM}uW7Sxuhm6c=b2I~%m z)k8cL4`iD>42)CGwpaXws$PXu(45o}mYsGrXxUNa zY%`LG#*MaKxqM?n1?{+!>#S_;4|TVj zmtAS*K%5?2*(#JWR+oZr{3KGn%VG2(MFG7Zd^j{L*O3==+J&|tB4n7-7Dn2da8#ze z2W3K}Ov2q;W}Qw`XSXM6?#tXq!{6)fM@JWQy+4^NoReakI9VU{BMrjn?1_)>X^&9Y zS=y^9Au_zP_xlnA_C7nW21+#|tTJ?z_q9AD`UIQg-H(yPKOu;x}^jx{T&M^4JUZ&2haSY5loVSl=S;nGu zgcHz5QT!s$=wkjf)nA3HqGBq&gsP)mizLx=AveJ3Ci-&4)?M8=o-shOL&{m(oXaKN zy85YniY&@??XRg#_w*&}o;*l&DkX4UdQy1jtx?u`w=2gY1_EwX@w?`lMg_<%wgD!d4lUXmv1w*>MnJgnv zIa^+C-ME@3Nd0D%S&zrcg_U2ec%6y%{BKN#=T_Brm)-XA&VsMgJWUsxPIY>{VC@VB z(b5?XWBi)*`yp}V;sn@_$vDuw6kYEv;<;zrg4D;_`AnF2RKBo0n(6nq;K`>8!c)Ux zRTt;+=9vFGcmqy6DcZ90k!g5Qi_`#RKD65ZG?iY|pRXV8i6{$;Wh}=N7N(?lF*suRTqF$&_DG&}hJVWkwFQEXW|C z!3$7gg$Oe?583%y&@T9V!dcNsHg2kD*wYa73>U+-eNxk0kkxoF@-# z#Km!Ag(T&JXfb$n!A94{*5cX4t&Qv#91il8%KZu}^v6k@=gID-#H?-Y34498R?@+R z#(e&TuS3WXQA+Ku$6sHN)Y|?O!2X-?MX+ys*Svz9QKGM0KetwX$qw=laX%hZTKe(i z4Mz@oP%U2j)4iM-c}UaEBR)l-14A$P`XAM|KKyII^r`dTM-DOs9wgtt{k@+qjII3N z5c3~BLy*-E@sPIQ5Khc9HU4monDYSpx!4xxembKQ&(yCiXdjtiQ1+L^w+EV{Y*B$D zOhd;4@@mso17qj|P}w)NM;33G zFP1%vc_tIjPcWb|kNTU;$NV~|IQ~&wE9}3t2QYvhOV#~5!X`8`%_wX}*sySx%i4v2 zE|et=yAUX{1qVIW%`@=aV=ZKxN#UbEMY3nIfuukYLr8XC9Z-9)el(Txkb041X= zl$4?nrO=Kpsm76DoAnnJX^FTjxFkmno{d=7IlD$q$!CH{x6INgLuYdkbxUp34bvjy zWqr6a>3My)w;KOgxnR9yN=UCO=#p4xAmJEF(ji;FpfsxH3Y zkE&d5`5e|l*&=i0qIc)fi-3Wy%n<1$^f+-O+z#M znT7yvI!1#%p>wNi*1T}tavZJ9)kN>jI)?LIcATM?pFQ$I^jYN4A}4_NUPlrrt~he$ zM@>k*V_rykbQ3@by!bpNXN5=G3jy!keT4+EF#pu1f4sm@m6kw`_zWpKT`BI}#3`Xj zgiTbzRz7~jjSP%ctZqJuc$$R*g$i#z{>cf!{!OUzp{=P{I0-+|q!60!doBmC${#Ge zZZh+LY(0W8uKM_bYrQ<;qx#Gg(0#Sx4aq27`liQ}>8cYV99HUzQE5;?M+}9Hohxy|0 zjrrwbVp}N{d$b?pS00DX?&ta49kW@lqjdVsYq=J2Pn*!zb3@p&*wVgTSmm5ZO-#Er zMK(O4D#2(}nhFa}Yv1re*+#V^FU^*gXEbWl5+}=Y|2Gv-NAr#x$-6n#`?M#b9nMS3 z71J^fr`y+ewh4uW)h!=d<`25iyy(+DCWZvrUv(roqFQl7Ny3-pOGqkjD5^)0r0(lr zNX9Vxs%Mtsp5T0dOJ`o!J0wjURR08q=xz+f@b5Q(1v937+!YTnH}1wDwvX6{!T9!% zLnRzE`wzx_ZeOu5q?ONqzgmbw_6UB&pM!>z2I=yH@KXXjC@(3|k;wR;ipf*ivMayn z@;}a5O`g(*Qmec^)o#8nCMLr9X?1+uRYmYm<({U?Ps(@Dh558jH6tmbpG51Xt1g1P zAi;9v*L`64bj-x6=9Y#gtuYd-XT6obowbVK48Z!zOQ$Y~U1EAE z2Sp7)(EnJvS}H?17)jM>z0AGSUb~E@W$N?*b4l(l`w;&~Rkq2yey6=7FnM^HNb`$U;yZpEW>$6}hW3-;Zo(~+jBhivMI-I~nB$8zF(ZB_&n~@iFJ-X(JOgk4 zNUdAtPiOQNgN3QV=X5?k=eD_q=f+sgHKQqK55MiA8u@pjS*j|1|ydi#n=1|S6&p4oi z4O;D&^T40*_3ss4Aw+*$#_PG+r)%3Ef3yU`E*DG;y5yHY#f*v^3FO}e3NIX)#lu44 zL-&s$l#>y!6r$*Vx+GNbyi!AZqFxt+k5_*Nb5MxBAn6M#TlpwhwUv3$@yYE0yiZrWR_nn6{}pCuc>7nme2;bY6mHQ+KX3p5+2C z*6F_KhI79{|Wxv5spBBfn zNXyz_e~-COpK~kY=^!GI2vP(x^R~3lo7*vOUVByPsQxGAgjg?@vez!W2`#2d#Xn{Z zn7r+CW>alR;!blc);4BE zS8T_vVS4ciwpG~bnf<@f*KmcWHMutWTViml$M*j*SEKc=j`19Rd`=1=w`la3BCg@e z6ptChEm8wDw{XnZLhenC2@6}aOckTGPt%sz@1s>`tC&?1SH3brRPmN$a#HOjq^+en zT0l`i8yB&%eEw1`1puWLaVzG>@heXq%zqQHf@f3M*x5(#zfffi9hxDfhYVR6xDpSP z%g&d+3so>~0#yFL@Z(#Qm^Pl}kO)KgZNVQP zm(4p6QhEEowyyKqYP}Kdd!(`4^ITZq$pwGUf^U+csl=zOo~>p#Z9o(s6D`_jI1`(P zp~Am>!1aqWZx!9|B)8I1*Hs{XcK1jCWdZbDuOV_8DRA~aRPO)dLN7sbQwU^N_Z#*P z=u6>$o3iNu=zAbJAEtqx^dO@)u2Vbb0qRK0rU)kUa8A( zZI<(CK29%^LFBupPGyY57T;}uS0<9*vO6!h#___JWnRWV-7%8^j9r>xk^e;<~p)gTs>@^y8^*m1c!}w+qHWk;B?|1XBE2YAx!rP;ZMca^^)9D(pifj8?VqU9YBj24?TJiQ zOzS$X1bBiOH`HYDj;hPIe(*K$MmI`LSjR1?L@7mQnv(oy8aA{;s>++e>-j4=NI?+7JfGfv~aI3Q{Ox#V}=C`re~@PZbZK zcxjNzPN+BhJ*;e2VyjmD+Y7!VK6D|#4xSvpTy>O?0+@UoIIUMxY74e{NwAtd`rsmGr;;%zc>b`SQ z_b3YQ%f1)){joxaXFc=CeiD-7L@djRrEDiD=X4qb0ypBRVe7W-J9}_+FaAje@=?xs z3K?#g8fW=z_1~fM2-Nv9-{dwQ>c>|=AN?o(bC9(A3zt)Q%{INEzJfj6z#k|XA&>9a zD0d4IMc(g!zTmhY^n2Z=E(!J1YMCF4V>U@g!$IiVmaZwPJ=EXYb7|v-^m!dpkGIr& z<8>3L%2`H9xlDo7B25*9N>d*M>3B}r^oZfcKBkdMuQ zYth2;VHmouX{stA;s8F@Y55`v2XY*_0kdY7V;;?rYP76tgvyF6?m|dHNBfF?n5j$K z+v}zOyQ9~=#vvejDMvDwS*J4Xm6mjpEG(xpnxPbuc%4=peDTdZlm?&YMX+->H?xz= z7>ALJzk1G#_eX*~(=Bqk>ZNVl2(D!a|>uM!<* zf0fZ=2CKB1F161XWc?nKQ!||#WIM=4mVRFE82vDTaiaehYhkK(&rF|D(^tkkU85>$`g>VfZ}uHi zh(rfZe0fi@rb9)Ctk`twn=>$jri+ZCxl9HfrkF=q#Xzao=^N@tz0*_F>CB($SWlYR zzk)rkwY&lL&3d(5%-JTUN*+N7#RO{k{Qr+3Je^snn-VYV6*S6TY z;qJZDQK**%Kmu9_)I=AT5c&#zXAeHv%kM-NI2kVzBBxm7n?}BO4QcmUduL$dV>2Nl z`!k;Xl}jJ?HpX%>oeT%vj;@LVOBdIRx!;my7l~ZAHHL;l5^ydy zyRzO_!+AT0T)xB?AP+tuX_F_45^o_78`)MB{y?0#O7in46kK_ot4hVruDiG6ut9H| zK3#&Z6uFv!J*S*Ks^l1ZU;|GHLP@65YPmPC>55#pq1V*sQj#gHu!?NSr+ zfTY!+iiIE}2S^=>Ud3r`T(d2-66`>oQvGamAv)ba>vZ+;#~NFjTGp(ZJ11*0*Bl=9 zQzl{f=W0=7Y#^6qT#zjgp4-K%Ph4vv&Ngak4btIh8av(GjA@r?6>T{uBQ-Ofe{tk= zJ(4=V+h2o!o2q3l2UU}*S&OFb*UjBI^xJj6nM3bo2^TRd>dB5=Z9tFH>-Ah+z_g$% zJ#@7mU9hUIbrqWkhy04V%5I?N&toXn5e{6f%VeXljZy;Z1h1!OGN8?26yprEd zLPwQemvJzNn=BSxO0TLTv8M$W;`?dXbDqA(m4ZwqPt5dym|nWzvRby9_46Rsb-+Ka ze7`Ptw{*K6_RI6?JnA0dpYM!VO3-KhK2un2CAcy(1NG^^d&NPXlZaZhQcv($r={nEPNh7zc z0m-m^iPL?%TpnPM%tQy4>@6gux8TA~7;9??vO7PNJHHgTO{+9^h(c1y!nnh`_MVI8 z7=(Wc2p_P=#h{<={v8`LMQvEI;_0mQ^ zYh$#NI&{=CL2^m6_dxz3E&`=TS&XXVXbk-=9s25IdD4dOfYRFv@fr}*RKRZ5|8WG0Ut z_N9Z=(o5~%BsXbURtPnr$31Wg`bBxp77gJo4r6P_585qN5ryK~I21|5r|-4h5Coo{ z3`22v!3sNpUDZzW;G=B$Kew>K*4}I@flkpU+5->XoH+^uRYslU02)(1x|mtz-nFWj6gFXp{TrqgaVe2QX@Eo~Q@ zg(EelEZvVIf=QW4-I3|rPuS0bEO8x5IEm3DL z#`lS0ht)mEuIEe&VHMUXJyd>amt&p-UOr4!s@E*$Zzz*Qy@RHP9jEk$3OqLu5hjOHg7P!*8E%q7Una=eX{lJX?`A<$1H$u{)f${ z(W;;RPo22|_RhnF%Xtgee9*H%4(f>&=<;F!N5U4KN`bSV`|f?($}8_TQE)SOC` zXyAKnwJCrX-Wv!Ka(^Rd&6#)D5l0=fV9Bx-tJWNM!bzu`cE(xfTyQZI8FCb;p+x=f zuD=&7w9!EqRlKC)CrFqm>12{kO>(JCUFy@2IE`sab6V1xwzQ`soq5^Mao7X8Bgz6c zz=J&^(Qj}HR-&PDPFa}Eq3U@!MZmUJDMJ+;thId<@uq7hXCCS~0$AQ-C#4E6fd=}U zqSRZIt`h_)`o_VGJ3bFS#avbuI7Bd-Rc!6{#a*dg`_con?!N3;#{2KRAR{VGm7(HaK+*U4JtdNCzI zTW95-&3`&{&ni_x2f;j1wqgN0Fe6*NiFQg^j9rvb93_*YNK=D+Fw!?;6{h?ZP+GnU zrq=t)-8a8jfkGAKF zU^V$-19t(jI00bZfgF**{ ze++>f8xmCq#M2JphuR6W{$>@`I?1T0SCmtT?En9Sq~mbqRw1}wqcC?wH1rsWhL*k0 zTw-_R5pxnR5*)5BY^@n{8ire#FiC<2Gms>b<}WjjH%DMz1~Jil5{=>uV#-CwFGEsN zk|N+RJ)YV4KzXGrQ8cu;_UQS_FR@tJ`6&)qd|95<8_WJztkO#y#SmWG-s-M6YCR+= zisq4j{r6Sf)!;cET+IXL8uMVz+ubiXawx`&>;nukr+0YT=D!1EoFZ`o2F4NA9R}hV z#i?NQHV$$7zR%J+$2Rp!2uTMx*?kHKIbg50k37& z`~H6&Bs4*j-~zVOh38XO`T|7-q`+5x*dvF?AuT0*$5K$b-P@wxqIOq3`569F(b;Lx zr&>Pz5d*Fm=93PKLcn9a05Y{)&jW+ zlj6P@z2gsW_oEI> z0mYny^jBbc2Qs_8=ZBGjcjHa*Prekibe%n&`Chst)@DCbgl__;%{y;MO{#fKq^5C| z2B9LAynJ?aCRG^}B!NAglN{pt&BFvG*`;Nq-A1H{6j-H9gTyIZjZ}h4hs0$vwMwl- zawn~qvZQFQ{jPfGMYakA(!*-IQ502b+s?_vI4*0T={C26)mc+}xR4mRA!>@WdqdukGb< zp$$)sH#bU?U`fkm#?}zvt`m%LhDUAsAu>To5KGUTNmi;^E2Z>~S2dYSP1m{>OyQ}c zIBmOSvqFs=NgIw+x^puPKBtUFGxEv|wVF1g9z0$uu8o^l1nib<%|o}G(kxGFL6Fe~ zgHdbWyvQrr;-AtR=)iu0x9GZ;c-x994XQPl##-Yred<-I9Iv{8$IgUxt+LFd(7L7B zYtq*0brRuA0|6z`Os$#J?pR-G9mT5^&(uJivq4j+8!rtDMMjNUciK%4?K6#CYQm64 zsudcj>-j0T>pUCBB2vn2uQ=SDOrg_2sM3 zfSDith|FGQC$odu&SnTy{1O0wEw`PRCgqdtcCrs@{C^BbRik;z1;VjfX9x#`GA=6Z z8Oo-bebK=uz%-1a$k!tfJ$*&q{|e0Rv->s8rMvV3^L(t6_F$^p##&$rly%qx$ARP> z2%S22Fw|yD4vx%r`Np}*4=5xl`NB2^zU=58fN6apcss8ihB=vH{I0}&fZ*O@6BS-JGA&3rGRRKyRWm1Ele&fCZ))8D251pAfI4wLJF`BpIJ|y zC-eCf-OIonuPHDJKwA(kTQ*-Ao;MDk=c6=DW3T5(r28?>as(qr?MXDLD?Lnf2xKIX z=b50i98l)b=8aFqE7c*JIs_gvD{AH?0;;N;vcoY597a>b#LkP7F8*&VMVajHFiwh< zkd{qejX|T0LhnBCnK4PW9H(CHME82S6Q*E|kKFVek&UKk3LAx|>uwzU>j8`=VWYuI%5OE|M!1b5BD z>>rVk)MR^##{hk`PWnKi0HA(1tOCC-Af-_o?^{PgVVx=u+t86B)*wQnFNx{7YCe)O z(uk*BMX~~EgLra8=|Q0%H8LgX?w*jDS4Ym*^-$<{7;h5hx^NVHT?t>;LQG?~6UF6A z3djZhni(Nig@85`yngYt&(V!qDO_`CF%t>1&G9U{wC`&RVD>5u=G9sHjU9=T! zWNq#Sl?MF0WuDS88nL;a{JZC|%{wRm-#{HI8c|uO=j1+YPO6)~dGFHZW?!ifzh`wVcjwwVY(xzq2 zFLiQXdn_|GpPlaJa*2a#zl&mOQbbmc!oyg@hn#7eHN{tEk!M=Z%~9duOpAN^VCVt7 zGN|^zZW+GQmt{6r^?ZZOBdtty|6Kyg`K4ol=0fXO6mvmMMSCn!SgLPHBNKq$G6z3* zADCF&EMeOe=|S`TVn*fJ`;KJ*6%F%{?^Ti5;?sVd>YZ-fMA}Z>!&pHPK?!6>e$0-iCls?kI#$h)6VD+E zR%rXuu@+vy#^uI9j?jVI*P9P2q8a&cU=kW>)jo8yAxw12wu6my=Ak~nz-TRa%7LEk zD5~pIIySVJRa@l~eVFs=&a`i}he~5W|ColtvU#xn$kN89Oy;t7?2EbIRkQr?_orL4 z^ecP-mLoUcL0E}SFBo35LTe)tNHt7`<4|>BXzIo2hce!LwV`(|RcWQsm#UW^rq~|i z#UGUY`K*`>V5kpFVP>o2)QLl7r;R$2BYPlI8w8Is`?9rFD_fIo)t8Rx%3I#*;qHEi zoN1V!IF9oUo}d8d!(?IMo`j_nITZxeNTrc+r$csSoyM`f*(49V{?X^72i#}LFOvi~ z0~mw~5;_;~U>Gt;=Tp@HR!lU#Bh z&a40cD*`}D=K@}-ER$3?16YL$Ueif(PSnBU4FGr(0Nw(Cw*lZC0C*RG2lOZ~wjS>@ zCf3d5K(eu6gR4Zc?;BAVuaD<|iOCenbT>>2`HWGa&o2Od0r)5_vyu9W0Q5BgWV0J) zReZ~+(03Prz6U@$WFz$>0q7?H$ayy`s`!Obp6pLUdi_5#e>>))tAsEFxcFCB>&T~BHaK86CnNv_5Xr_(J!ALwdgc6 zgj3(f;)3Do8#5X~MmPfP4jh~Fgu8D}z&E_$8&+IcNR*pz+bR16!op|^>@A`r-dfAE z{IMpz*NXVe@c$Q`DC?v&;t6>Aaw?G0tKo}DsdfHzGw1SA%~^Ot)0YLV7_G>Fr#71k zYi?H3X*t{(j7NIaX^`B>imeOS7hWUCK=hoJ*KVF!c`z`5L6JU(2Udy%y zAgdxwwI92B`92##lCklU^h$nZcMD`ww^5z@)ed#d@0ZlzF`EsLQ5IyZobOOO^qqqk za>u~=imqH=Q@Vua1B2N*s{az{2UkF@dY-LWE6nhS?~f5wYBS-Z;o&M!mLC&69Y3BNt(TLB zlVc5JdG(>$7d;pb&HvPY^}pq^>A_ROMEJBC@K2x4J(aNTU%bSj8btY|h}iVvQ|or! zr)oC|ZO`Lu5X7lo{uV3XUJ{0wK;Oh#0GSGM4pC)6|D!5``>DR}0#vp${RMdSIUr=$ zAo}nYf{!uJO9RNm`<4iQG$Q~x)MG?7pbdP#7dcX;x4&C<{@O{`@$BL=xo4MhPcf>@ zSb+Jij6D?{7L2tZQ_{{fNPBk!$XVyRev_b3Xp$bQ$>V*c=AZN4-A-`Eb%htHdYg1t z_RJtj;viC14)cL*>5eWdi1hTSO=w%Gz_L8gKc9W_W3uq`S}jlpB@7Ob2(sS;97+HXp;n|x^OQ8B-ze6L!7W+LGHg?z3}V)a zFd7tu8WmzRl5o!NpG9!K5@p#w1u92QqyW;hU?COYdUy8wq@-!art&REBlQWthnB5p zghZYd=;;)$>=r}`(WpN(X-qvEj0Vh%8PUvHU_9j23)T~p5J*;2(2}I6K(k^Ms0^nV z*I>}PR$_TdIePoDvVbBq%JET6jfmS|fd1pX9%eibuw`Won1xuyqAmvPCAIw9PJXag z?9tiOcev+n9CRdU|K-8#OB#4@uI+xu=-+a@AEl(rr=~XFi8QHBpG=a1-%2Z2e@!|4 z+hdDJ+No^E?eI+%PQ^$t(f+1-CD}3~IXjz1h6b+;)TZ7acI5$kBYNtUSF)^JLMdju za>E=-2I^oIi;TA+XTzQq^CA6njB4qBNXTo&gTVQlXMxaZu`J)2O+{bEZ6sEHW<5?g z;;a%$kZGxIjzfjX`#1%$y;>mUbPDsHjq5=j6{>YMwHip#SGc>%m{pMMXEzb=-Dzy} zeBEO<(Py_X-O*mN4Gexe2gevm)L=8u^e!-u;*xn&PjyG;s)Re*tjkdU3n1IeWD z(3QwACiuaOP2jn9vqGaJ83m(pej-oWFfkL zjH(GY{Jb^|>_l>NY{-<2NBw=WtG}c7ZsIOOj9Dg;M^xKL>2zz!|tnqz5jIeJl?0z;l zv|ehLb=XVl#s0zWmB~h#`CBgkxoNiwq-WiH1)9NSz|Hr6tVB8>5}eBJ{vuN6ds|!b={w)}sAPpjvGb;mE#ivWMZ}fxPke>BTko z#yI#GtjiSxvJY6iefneLzF5{{wN$QnB8Vw;ZRfX9vGGdfR4DIHg&aM%&a@~2r_s;1 zm<^7B6~QHY=~rN^SRqA7pT@~6?sE_^f03DQqeGV~nerW%VY48n?ZXq~#qFAB?a0{db>cW9Hg27h{m& zwpU(|ceU%!&NBhj4`S{qwht$bWsJId_Q%F+;Koi`xjdl_x}Fg5TFmugz3lw3nrBQ! zGYY3SIqtZp2U{&L0@Vt&8S5pD50W&D@UunQTO}h-uBCBp4SgG=W1SWroUq; zE78jSPOI9(VYsr#<9K0DCJFhJj7AZ0eX|VqGfD+?w&LFpck%lF&V^Zk%_sTD`BdAO ziC0IXGkEX6JEHrONm+;e_vwUxIer`N{-6J;`ywB~8WlhCc< zp@IO4FaeJz)vp)R;OQqEJlR72}y+KB;HM<23$?>53)uXCy(97|l)(AKb7e zT}n%&Qx`5+r2hlIj!Wz~m|I!~o%-b6;r;2ZyQUd!K2WpoS?u)wcztB6n?=G?em^s} z{kXiuSA5=M>@$zgPV)7QxLxgu;37%z-T-+=%6ym<@7jf ztpE^0S`KOq8nsWBLJPDDw(LsGNC9C{Pe%j34h zJ0xP@z=>qmTHVwzrAhkdmu$0`in!%mAw{pn(^GE2hFiYLrPO*HMNN!<(uMP7I+RKd zUUKHDhp^`!1Z}<|jBJWz$!{N!3wt($EgkwGRu$D4k9c*=FwBsvt2@TTnN`ISZAU;| zgd-wgjJ8}QDUQ2BJE=<~aUB7*@~u~i8=5(lzDjeqW9Ql%hm>I+T0lS9CcBw37hsU= ztA>%Kn^%csPotj7M62S=kc`p%lX=-*$;-9>#~#CrH+W!X%wvP5xHDvO3)KSQEr2dP zu4=RQ0jv+ADdK$q37o-Yn$X2F^SUN9&<&%4|K|#2Pi3X3w^ELHqqU7Du|wRCxaT1K zVnH89%E$&%N|KOBbmH+fxzq1X-IqX*OTu+ldcfT< zXR;~WgV#;i=aic>^j*tUZHQ>w_Ug$-X@`*!4ucsfmxQ&%usm*DVX446yNM09A!d*Oida%?f!~KU*a5oP(l5ptLf-zib*bDj) zH4DNGlo&Z7nl=q$`O6In2D$p>Z;O6i>?xm~y32(zotx%NpedebXN*v8khk)z0HvI6 z#5B|_@?7WdDKdxj{EsfmZ1GsB%{!%Wam7;=4g(Ujp0#N>)$^eh)~6*6i&Jp=CRqcjF+vZv^DR-KN|Vo5X2@XmlgR}Ei&0+ zg5Eq-ygQzqD&1Lrez;=eFG+_MB_0YB%sLrZE=|q;S$wEi^gXalD2tZZ_tIhq@(6K= zNyLGWxC=K;tB7^(YD{m(Y1~d>P8?~%ZTM&tj^PKcn6R_KE2cMYecsmVI+Co2jy#uf zMV`GEVx3II!SmN;?PQVA65!hTmj!yU^%Yl@5Vy59!r9EH0}$VqQ7VfvE{#e;Ha^9S zI^h}Nj))%{Wsp(cjsod5m2T&dh6sy`qS(2L5o-8##=QhIuFL9qb}R|; zi_@W$-;a;PX-jx|0!grS{W=2ZA?_FOr9r>>vT=oB5Q@i*bP&U?(=4f0F;hD`1S~{G zEyS_q4pj~#K|mjJ?=BWfC@19RclEjmL~TR3Y)=hZz`Q-CrL)Nw<7opn9!^pj`R#vL z>)?HC;ac`@X@1`!Vxi!Lc^>q6`)}+4@qr4TSi~~l4}zN4H1J&h zST}25omq^ISMQh!b6H6Ct0~Hhd{O8wW3>o5Y9(VX7g4^|vCy(2W_DN9K|Mhd`h(lJ z4Wa=Kfn&hVV`5Q5#|c5bdkQ%vrFXt;WL$lm#iFXq%{k51k>iX#-DT*Vp$3aZml8is zmVK=*hdXb$bjfhDr?=`XqAM9vvgNddrBvsRA-Nzoclwd{N7jcr*S7X!D;0%enO_JL z9W`BfUxnf?&=)wWy04r*3Pp)8193EpYMs8sDrN%vrD$DpPw$fKXF+f)4B##pf~4QR z#%OHu!Vjml7~Cc9f^oPNX@zlZ$A`fZ7UX{%=B_Oi34)IC`NuQ@2>4$TU-Dx?(y3*H zQ7-<)TYUdk;$88SbLS|7+EHoxOc-A{D$xd&1BK1(*AK@?LAzNy(bFudJ@#e_C>)i#3|!=$s&E`SX5zR+eQw zx%(SOvQMB-vKIAO!Svf5_WtL~r(7%9LvBbn`UnI*Wrx7v;mnFSyC72nwUQl}<8+Ug z8ONvM_D{ocGe2Zn5x%KylQmB@PbyDyK1B2Eq`Y^|4?b_A{XMiE_bR~e;+Ct4IMw3D z@z1BW0w~7Y8nFhCZ$V#aG=-;v@xV%!!ExO!)tHp)V7?u1OCYK>d~{fB^MCJ*L!h-Ob_{sR(6Jxq6@7 zi94G*?2sf$jbm;M$DJLA;I5SD>lyKJot6eiwgvhzwt|9vl1U~x5`f5+0o2Mv9V=IK zu3Xunh|cN9lYSEEMN;}ShS$O6q*XLLqh#9APwD%2SH>TmRx)Du{`AP&@^K>TVN22o z0e2WG8n+&xWa_bx8O^&Zb;qWb4By?H5m~c2Xb;hgeqy77W6ZLz*&v$`X$s&&|_d8gB0R3Ax;}8W83l(NXo3&bd%m z>GbC7f3K%@Q*3opn6T!mN@XQGE9pQRvUC_pV!GI{rs`E2bR>q6IvJ;CRjl|>VNI)E zhi&3Hln#2?<$s>5(*_StlbQw%Y6@r)yUJx5rPo5WFct?ufByQBd4koz|3}==M#kcH zYoK<(|4TaYJL>!^jlH(rQ@kKUfnVo*K5QCtr>XssU~vzSR5AT`^PX4c=4&$bKb4_y zdR(XYbJ~f+{D3O0XnY$taoFhR&B)>-sIiO6mzLa!4%l zaMxub+JW_dD(C`F9-rayydM*ii)HgsF7l|FkGiBw^wdRHGXu1ylE9iYiK9>}2}k<0 zX^>JurEN%Q3cr{~LKx_&aiT7d;eg*(@8&7Igo$tigLXM2q(_~C;3&q!luc*4{` z>pG}}c; zCSoZ>QJ*dmj08j9+oZ6?S9IU^9t^n0Jm>D$Yp#mD+Zq45sn%IUh@Wf}aU$NqHhko* zUS+|INY{+NI!Z$Ter7A9kRNDftAHY%eDzhfz65*l(PEjzitR{b?DUK$oSw0U(=)ka zW){}WFPzdZNR;~XV;DQyTYH?zQBj$J=Wx4?2lQT!JW7r zYph@sKKFaz?DxO+l`VT;CQtO;aNPm>G>mIWNUcSG&{D2(x>AlAv$TN#bB8CPAPX!& z0dHeOAsL>1iPC$hz#Tx&Tqxtv@RmH^^)JhfRNd+Ovo#y3t0Dkvz)mDrH4iK^l2?i@ z(FWo`4#GnX17hfJ-GEz6_@Ji*Ko!=HFXzoz)Y0WhEJd)RJAgAz1iKQFXjgi&>+jK0 zE#P+$@PIy!)j*ZwOD_LkMZ2&(7!l$svzYgFY`~5tJzqU-OHX^SDDtSg;((>A{_k#=3tpC-yd<%?HAL#%LMM}8_XEk< z9;MJVOVaFb$>yW>W!(9+3SXAte9S{!(4o!~Ib26NyN!7DFcRHmq^8HQ1A%Qwm6taB z`YFi8ax^~80P_wr;Vv+ySIP6Cex&|8^xguJ;6D83);+7|BbZg#AN$V%-}75$LQq6M?#zQj z1%M6kq|ijVAsg+mHmiRLBZw>n9eJ_q-|JVUb$uYLB{yYZB|WWbhXPrn);0l@g=-53 z7J(`RX+U4f?Q7Q;r?oxLjN&iYF-nm`o4K{c+M7)$t{`d8Qwf4+YVT+Ug4Vb$935yu z8Vs@9pYtE;01J8vFyI>LYgpST3F@y}UgwRgC5-PNs*geKHb#rQ(Cp5%Zmh*(Wj7@k1IiaZQ;CCvuM>vK`8~h*@smliQ z&h1RgPIGHwOcY5;DMF(NuyejJJ8$x2G8?6IZpejXw4x%z86uegkFr2IhQPmQTJ=SE zw-~SVaxZnoMHfgM#)CK(hvQJJ!)H(1L-Q#5Sj0J;#!2|n4vOI7?-+p>ut_2Qif7_c z+|dvs8>iua&#-BcbTY;O$t(B7t1r^8Zu=H6;~p{GR z^7PCeIr&Ttw>UBM96531_E)-#yw@<`F3?lWqw$XDf-mp{!CL@mMbyK%A2;H9oQxCn zLNtndP$0v z=L>e9?HU(DW(sOT22U^zB7<0fc*DR)M--L~QF(_dKkDmpMkr{@3texvbwb(D5xaP0 z^F*$FV+q`bMY3bFngG4(`z^y3PnAH2FoGaSMHKQL6V71M3p*ad9UcD=m*Wjm{}p8Z z*VYtuxAWbNBv%rIOKJe5)xqQ?3DWv&;>P8riG!Z$AKe8mVqTp z(wh26NH+xVom(5>&cm&A=7<1mN5}ngZqhi?N^na0&bi@bjP#!Xj^A?`q>I}4zCmE4 zNdo}PfZyV%1|F2EPC&jvuE^xYH#P>=g$9bA(FW#qi%eIC~58LgOI5^a_Xa> z=j@eYzgw^7v+=0guGh+J`g+)-z{-5$@VN_#;a;$xek-I|1;sE+@{t^;Nn}|W1w^0N z4Na51&~tT?e(aW0KvX)!DuwXPWb8eIi&SG zEx}*K=%uZwA@_J6@zov*;40(^DtHJBk|9{&ALd);?Y9-4;R$+wxxCvSYgm91pd`7M z`}_TBrF8|)z18isn)%;cZaK!2RQw5g2)?-;#lsGt;n81n`$p%+O5Ny}pOqz#ib8+E@U9yuCIeN`5K0n=R41bT z|F79%gs!tcBynTp{`LrtTdKqd<(|UuaFOTgr%Wxo_xG>hS4eg96_A$n`elQhA2V(m zQz&!nWdqR5M{rUL>Uyg#M`RGs9Etr24JfOPvK*Fxud7ngbrew4i3Pp`|8`sjc~a%& z5YO1uq-F*u;gH2D_smp~%!E%v&c(&~`9@=AW_o&ZGC@csBGEuo=tP+-BU4(EUz8~< zFy>`)b21H??5uP$qt8fA^HNiYBw}U>iHpI)g90QfsWP5M$#iOo)MRe>%Xz3qT|GG@ zg|eEKWt#?HtkgaLRDrbr(^XJZs^Z_Iq=qG?T3B!mk_dlq&S5T!R%7&K|#X6p4MQ^n~#@9rM9nob^QU8*e zbivqFLdeKQTd&cBfCzz+L@W%9tp|cuw2b1S&a$fYE+TYl@1?*m58HJs-#?R(?%fdI z=mH|Ck644rG5R!w#1j^RB+FSMUA~{Qu#~o$_@gZ&cW|30oN6J~h9>_IzopsT(jczf z_Ts@mpo1R|zTXtgQd0AvKT4OPyGpBY{k{2kIOx!Z?;B0c7a3 zHO~7474I}_B!-bsA*j;zWEmX8CwjnzNK7)(%X7bZh2+nhD~381enLULLv^?VluS=< z9ZE8rQiXzyq0ow{* zd8Z9L-HPeqy*nEY+6m{L^i}90kMOH)?KU(x$bQhxD#!)i23Y~JU&xBG_?9a1|5qiD z){=D}v=G)*cph2HXQ%dx;BuQQegUZju01@MTD%fXr6;OxyGYRoYuowUIcwXw=#81( zc75Gk=c_sKwB5`dE|=2M>4zZWK|vw`#nt2SSe@jhs$9i)wd+w%PfNEoK`HX;yz$% zj_g-13JL0gcmsj75v zogW;(tk+dI`)0e9|4C-)wm!P^S(;=@MR**WVlfajt%Bp5F;*Kh3YRoPq7F}CpWw@J z{Vd@RFyZ6biX{zswj2H5Z{ZN(@1gvX#Xaq-gS)^!=|9xbAI}}%#$xdz01kh!Sp;7A zF%KRI{Miy{|G$s!QHxgRaF=zK19vO0OKyW^rPWeLJq_Sfe%%GIf1Z`wO7bDv)2MR@ z;)@@4*6(b-!7l(gqbCix#sTWIFz?=t9%4{(z&G9!!;S5||1|1wVgVeD*Qyq$WuExn zhXG&J19brJGX|YQL3$|wBZT)$xV`dANU(Z|5FNXIDY$~e;(*#7&MslBw_L(q^u9|- z+n+BH2K|2nQakc@H{4fR(6?wW4)eoa&L7dw#%G1GV=QHVM6D!3%F?)^xjn8ud|Eik z$*VsjMEXh#y1%{f_@EOh_Onq7&#+r-Os~cHwURhUb7b!kZSu9by=YiDD1~SRtr6K) zez`=O&w)QX{wM&%g5aP-4m%R~OdNCE2`8O)##!f_cfm!MTz17(*Iakgt>DNgs2INz zHJZO?_)_v1Fk*r!L^vRnaUqosqc};8&GN!crnC8Cxk~xr2K%%au`vfqmmC6qOk>?&_=5NY~K>3QxfQqmF|JtyUhv ze_nFrgK%Ic$n1~ss-pxB9u~D+aIgyE@ii>~ From 273c99aa3380d34b5434bf42a162a37a328e0ed3 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Thu, 24 Jan 2019 15:44:47 +0000 Subject: [PATCH 5/8] Fix getMatchingRepositories typo --- .../deploy-application-step2.component.ts | 2 +- src/frontend/app/shared/data-services/scm/github-scm.ts | 2 +- src/frontend/app/shared/data-services/scm/gitlab-scm.ts | 2 +- src/frontend/app/shared/data-services/scm/scm.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts index a8af219ec7..7ce524acf2 100644 --- a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts +++ b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts @@ -303,7 +303,7 @@ export class DeployApplicationStep2Component return observableTimer(500).pipe( take(1), - switchMap(() => this.scm.getMacthingRepositories(name)), + switchMap(() => this.scm.getMatchingRepositories(name)), tap(suggestions => this.cachedSuggestions[cacheName] = suggestions) ); } diff --git a/src/frontend/app/shared/data-services/scm/github-scm.ts b/src/frontend/app/shared/data-services/scm/github-scm.ts index 648b6dd64b..e751d8c9a7 100644 --- a/src/frontend/app/shared/data-services/scm/github-scm.ts +++ b/src/frontend/app/shared/data-services/scm/github-scm.ts @@ -60,7 +60,7 @@ export class GitHubSCM implements GitSCM { return `https://github.com/${projectName}/compare/${commitSha1}...${commitSha2}`; } - getMacthingRepositories(projectName: string): Observable { + getMatchingRepositories(projectName: string): Observable { const prjParts = projectName.split('/'); let url = `${this.gitHubURL}/search/repositories?q=${projectName}+in:name`; if (prjParts.length > 1) { diff --git a/src/frontend/app/shared/data-services/scm/gitlab-scm.ts b/src/frontend/app/shared/data-services/scm/gitlab-scm.ts index 82004a2346..ebd287f402 100644 --- a/src/frontend/app/shared/data-services/scm/gitlab-scm.ts +++ b/src/frontend/app/shared/data-services/scm/gitlab-scm.ts @@ -97,7 +97,7 @@ export class GitLabSCM implements GitSCM { return `https://gitlab.com/${projectName}/compare/${commitSha1}...${commitSha2}`; } - getMacthingRepositories(projectName: string): Observable { + getMatchingRepositories(projectName: string): Observable { const prjParts = projectName.split('/'); let url = `${gitLabAPIUrl}/projects?search=${projectName}`; if (prjParts.length > 1) { diff --git a/src/frontend/app/shared/data-services/scm/scm.ts b/src/frontend/app/shared/data-services/scm/scm.ts index e75722a368..598cfa4c79 100644 --- a/src/frontend/app/shared/data-services/scm/scm.ts +++ b/src/frontend/app/shared/data-services/scm/scm.ts @@ -19,5 +19,5 @@ export interface GitSCM { getCloneURL(projectName: string): string; getCommitURL(projectName: string, commitSha: string): string; getCompareCommitURL(projectName: string, commitSha1: string, commitSha2: string): string; - getMacthingRepositories(projectName: string): Observable; + getMatchingRepositories(projectName: string): Observable; } From 8b731034a2a4289aa53f2da8df3bf25b85b74dae Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Wed, 13 Feb 2019 17:35:14 +0000 Subject: [PATCH 6/8] Address PR Feedback --- .../deploy-application-step2.component.ts | 18 +++++------ .../shared/data-services/scm/github-scm.ts | 25 +++++---------- .../shared/data-services/scm/gitlab-scm.ts | 32 ++++++++----------- .../shared/data-services/scm/scm.service.ts | 8 ++--- 4 files changed, 34 insertions(+), 49 deletions(-) diff --git a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts index 7ce524acf2..7d1c77996d 100644 --- a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts +++ b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts @@ -3,7 +3,7 @@ import { NgForm } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { Store } from '@ngrx/store'; import { combineLatest as observableCombineLatest, Observable, timer as observableTimer, of as observableOf, Subscription } from 'rxjs'; -import { filter, map, take, tap, withLatestFrom, switchMap } from 'rxjs/operators'; +import { filter, map, take, tap, withLatestFrom, switchMap, startWith, pairwise } from 'rxjs/operators'; import { EntityServiceFactory } from '../../../../core/entity-service-factory.service'; import { StepOnNextFunction } from '../../../../shared/components/stepper/step/step.component'; @@ -84,8 +84,6 @@ export class DeployApplicationStep2Component // Local FS data when file or folder upload // @Input('fsSourceData') fsSourceData; - lastProjectName: string = null; - @ViewChild('sourceSelectionForm') sourceSelectionForm: NgForm; subscriptions: Array = []; @@ -282,13 +280,13 @@ export class DeployApplicationStep2Component this.subscriptions.push(setSourceTypeModel$.subscribe()); this.subscriptions.push(setProjectName.subscribe()); - this.subscriptions.push(this.sourceSelectionForm.valueChanges.subscribe(form => { - if (form.projectName !== this.lastProjectName) { - // Go and fetch the matching list of repositories and make that the auto-complete list - this.suggestedRepos$ = this.updateSuggestedRepositories(form.projectName); - } - this.lastProjectName = form.projectName; - })); + this.suggestedRepos$ = this.sourceSelectionForm.valueChanges.pipe( + map(form => form.projectName), + startWith(''), + pairwise(), + filter(([oldName, newName]) => oldName !== newName), + switchMap(([oldName, newName]) => this.updateSuggestedRepositories(newName)) + ); } updateSuggestedRepositories(name: string): Observable { diff --git a/src/frontend/app/shared/data-services/scm/github-scm.ts b/src/frontend/app/shared/data-services/scm/github-scm.ts index e751d8c9a7..0a9ea7cd49 100644 --- a/src/frontend/app/shared/data-services/scm/github-scm.ts +++ b/src/frontend/app/shared/data-services/scm/github-scm.ts @@ -1,13 +1,13 @@ import { GitSCM, SCMIcon } from './scm'; import { Observable } from 'rxjs'; import { map, filter } from 'rxjs/operators'; -import { Http } from '@angular/http'; +import { HttpClient } from '@angular/common/http'; import { GitSCMType } from './scm.service'; import { GitRepo, GitCommit, GitBranch } from '../../../store/types/git.types'; export class GitHubSCM implements GitSCM { - constructor(public http: Http, public gitHubURL: string) {} + constructor(public httpClient: HttpClient, public gitHubURL: string) {} getType(): GitSCMType { return 'github'; @@ -25,27 +25,19 @@ export class GitHubSCM implements GitSCM { } getRepository(projectName: string): Observable { - return this.http.get(`${this.gitHubURL}/repos/${projectName}`).pipe( - map(response => response.json()) - ); + return this.httpClient.get(`${this.gitHubURL}/repos/${projectName}`) as Observable; } getBranches(projectName: string): Observable { - return this.http.get(`${this.gitHubURL}/repos/${projectName}/branches`).pipe( - map(response => response.json()) - ); + return this.httpClient.get(`${this.gitHubURL}/repos/${projectName}/branches`) as Observable; } getCommit(projectName: string, commitSha: string): Observable { - return this.http.get(`${this.gitHubURL}/repos/${projectName}/commits/${commitSha}`).pipe( - map(response => response.json()) - ); + return this.httpClient.get(`${this.gitHubURL}/repos/${projectName}/commits/${commitSha}`) as Observable; } getCommits(projectName: string, commitSha: string): Observable { - return this.http.get(`${this.gitHubURL}/repos/${projectName}/commits?sha=${commitSha}`).pipe( - map(response => response.json()) - ); + return this.httpClient.get(`${this.gitHubURL}/repos/${projectName}/commits?sha=${commitSha}`) as Observable; } getCloneURL(projectName: string): string { @@ -66,9 +58,8 @@ export class GitHubSCM implements GitSCM { if (prjParts.length > 1) { url = `${this.gitHubURL}/search/repositories?q=${prjParts[1]}+in:name+user:${prjParts[0]}`; } - return this.http.get(url).pipe( - map(response => response.json()), - filter(repos => !!repos.items), + return this.httpClient.get(url).pipe( + filter((repos: any) => !!repos.items), map(repos => { return repos.items.map(item => item.full_name); }) diff --git a/src/frontend/app/shared/data-services/scm/gitlab-scm.ts b/src/frontend/app/shared/data-services/scm/gitlab-scm.ts index ebd287f402..d5750bb211 100644 --- a/src/frontend/app/shared/data-services/scm/gitlab-scm.ts +++ b/src/frontend/app/shared/data-services/scm/gitlab-scm.ts @@ -1,8 +1,7 @@ import { GitSCM, SCMIcon } from './scm'; import { Observable, of as observableOf } from 'rxjs'; -import { HttpErrorResponse } from '@angular/common/http'; import { map } from 'rxjs/operators'; -import { Http } from '@angular/http'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { GitSCMType } from './scm.service'; import { Md5 } from 'ts-md5/dist/md5'; import { GitRepo, GitCommit, GitBranch } from '../../../store/types/git.types'; @@ -11,7 +10,7 @@ const gitLabAPIUrl = 'https://gitlab.com/api/v4'; export class GitLabSCM implements GitSCM { - constructor(public http: Http) {} + constructor(public httpClient: HttpClient) {} getType(): GitSCMType { return 'gitlab'; @@ -31,14 +30,13 @@ export class GitLabSCM implements GitSCM { getRepository(projectName: string): Observable { const parts = projectName.split('/'); - let obs$ = this.http.get(`${gitLabAPIUrl}/users/${parts[0]}/projects?search=${parts[1]}`); + let obs$ = this.httpClient.get(`${gitLabAPIUrl}/users/${parts[0]}/projects?search=${parts[1]}`); if (parts.length !== 2) { obs$ = observableOf(null); } return obs$.pipe( - map((response: any) => { - const data = response.json(); + map((data: any) => { if (data.length !== 1) { throw new HttpErrorResponse({ status: 404 @@ -51,9 +49,8 @@ export class GitLabSCM implements GitSCM { getBranches(projectName: string): Observable { const prjNameEncoded = encodeURIComponent(projectName); - return this.http.get(`${gitLabAPIUrl}/projects/${prjNameEncoded}/repository/branches`).pipe( - map(response => { - const data = response.json(); + return this.httpClient.get(`${gitLabAPIUrl}/projects/${prjNameEncoded}/repository/branches`).pipe( + map((data: any) => { const branches = []; data.forEach(b => { const nb = { ...b }; @@ -67,19 +64,19 @@ export class GitLabSCM implements GitSCM { getCommit(projectName: string, commitSha: string): Observable { const prjNameEncoded = encodeURIComponent(projectName); - return this.http.get(`${gitLabAPIUrl}/projects/${prjNameEncoded}/repository/commits/${commitSha}`).pipe( - map(response => { - return this.convertCommit(projectName, response.json()); + return this.httpClient.get(`${gitLabAPIUrl}/projects/${prjNameEncoded}/repository/commits/${commitSha}`).pipe( + map(data => { + return this.convertCommit(projectName, data); }) ); } getCommits(projectName: string, commitSha: string): Observable { const prjNameEncoded = encodeURIComponent(projectName); - return this.http.get(`${gitLabAPIUrl}/projects/${prjNameEncoded}/repository/commits?ref_name=${commitSha}`).pipe( - map(response => { + return this.httpClient.get(`${gitLabAPIUrl}/projects/${prjNameEncoded}/repository/commits?ref_name=${commitSha}`).pipe( + map((data: any) => { const commits = []; - response.json().forEach(c => commits.push(this.convertCommit(projectName, c))); + data.forEach(c => commits.push(this.convertCommit(projectName, c))); return commits; }) ); @@ -103,9 +100,8 @@ export class GitLabSCM implements GitSCM { if (prjParts.length > 1) { url = `${gitLabAPIUrl}/users/${prjParts[0]}/projects?search=${prjParts[1]}`; } - return this.http.get(url).pipe( - map(response => response.json()), - map(repos => { + return this.httpClient.get(url).pipe( + map((repos: any) => { return repos.map(item => item.path_with_namespace); }) ); diff --git a/src/frontend/app/shared/data-services/scm/scm.service.ts b/src/frontend/app/shared/data-services/scm/scm.service.ts index 0d40bc15f1..a200c31f39 100644 --- a/src/frontend/app/shared/data-services/scm/scm.service.ts +++ b/src/frontend/app/shared/data-services/scm/scm.service.ts @@ -2,7 +2,7 @@ import { Injectable, Inject } from '@angular/core'; import { GitLabSCM } from './gitlab-scm'; import { GitHubSCM } from './github-scm'; import { GITHUB_API_URL } from '../../../core/github.helpers'; -import { Http } from '@angular/http'; +import { HttpClient } from '@angular/common/http'; import { GitSCM } from './scm'; // Supported Git SCM providers @@ -19,12 +19,12 @@ export class GitSCMService { private scms: GitSCMs; constructor( - private http: Http, + private httpClient: HttpClient, @Inject(GITHUB_API_URL) private gitHubURL: string ) { const scmArray = [ - new GitHubSCM(this.http, gitHubURL), - new GitLabSCM(this.http) + new GitHubSCM(this.httpClient, gitHubURL), + new GitLabSCM(this.httpClient) ]; this.scms = scmArray.reduce((obj, item) => { From f4a571a69f16056d3c8e6d2a200eb02455e23425 Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Thu, 14 Feb 2019 09:02:49 +0000 Subject: [PATCH 7/8] Front-end unit test fixes for switch to http client --- .../application-tabs-base.component.spec.ts | 12 ++++-------- .../tabs/build-tab/build-tab.component.spec.ts | 14 +++++--------- .../tabs/gitscm-tab/gitscm-tab.component.spec.ts | 12 ++++-------- .../commit-list-wrapper.component.spec.ts | 12 ++++-------- .../deploy-application-step2.component.spec.ts | 16 +++++----------- .../github-project-exists.directive.spec.ts | 6 ++++-- 6 files changed, 26 insertions(+), 46 deletions(-) diff --git a/src/frontend/app/features/applications/application/application-tabs-base/application-tabs-base.component.spec.ts b/src/frontend/app/features/applications/application/application-tabs-base/application-tabs-base.component.spec.ts index bde9dc870b..a74eac04aa 100644 --- a/src/frontend/app/features/applications/application/application-tabs-base/application-tabs-base.component.spec.ts +++ b/src/frontend/app/features/applications/application/application-tabs-base/application-tabs-base.component.spec.ts @@ -14,9 +14,9 @@ import { generateTestEntityServiceProvider } from '../../../../test-framework/en import { createBasicStoreModule } from '../../../../test-framework/store-test-helper'; import { ApplicationEnvVarsHelper } from './../application-tabs-base/tabs/build-tab/application-env-vars.service'; import { ApplicationTabsBaseComponent } from './application-tabs-base.component'; -import { HttpModule, Http, ConnectionBackend } from '@angular/http'; -import { MockBackend } from '@angular/http/testing'; import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../core/github.helpers'; +import { HttpClientModule } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; describe('ApplicationTabsBaseComponent', () => { let component: ApplicationTabsBaseComponent; @@ -38,7 +38,8 @@ describe('ApplicationTabsBaseComponent', () => { RouterTestingModule, MDAppModule, createBasicStoreModule(), - HttpModule + HttpClientModule, + HttpClientTestingModule ], providers: [ generateTestEntityServiceProvider( @@ -49,11 +50,6 @@ describe('ApplicationTabsBaseComponent', () => { generateTestApplicationServiceProvider(cfId, appId), ApplicationStateService, ApplicationEnvVarsHelper, - Http, - { - provide: ConnectionBackend, - useClass: MockBackend - }, { provide: GITHUB_API_URL, useFactory: getGitHubAPIURL } ] }) diff --git a/src/frontend/app/features/applications/application/application-tabs-base/tabs/build-tab/build-tab.component.spec.ts b/src/frontend/app/features/applications/application/application-tabs-base/tabs/build-tab/build-tab.component.spec.ts index 36ff210462..8216a2789b 100644 --- a/src/frontend/app/features/applications/application/application-tabs-base/tabs/build-tab/build-tab.component.spec.ts +++ b/src/frontend/app/features/applications/application/application-tabs-base/tabs/build-tab/build-tab.component.spec.ts @@ -15,9 +15,9 @@ import { ApplicationService } from '../../../../application.service'; import { ApplicationEnvVarsHelper } from './application-env-vars.service'; import { BuildTabComponent } from './build-tab.component'; import { ViewBuildpackComponent } from './view-buildpack/view-buildpack.component'; -import { HttpModule, Http, ConnectionBackend } from '@angular/http'; -import { MockBackend } from '@angular/http/testing'; -import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../../../core/github.helpers'; +import { GITHUB_API_URL } from '../../../../../../core/github.helpers'; +import { HttpClientModule } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; describe('BuildTabComponent', () => { let component: BuildTabComponent; @@ -41,18 +41,14 @@ describe('BuildTabComponent', () => { initialState } ), - HttpModule + HttpClientModule, + HttpClientTestingModule ], providers: [ { provide: ApplicationService, useClass: ApplicationServiceMock }, AppStoreModule, ApplicationStateService, ApplicationEnvVarsHelper, - Http, - { - provide: ConnectionBackend, - useClass: MockBackend - }, { provide: GITHUB_API_URL, useValue: null } ] }) diff --git a/src/frontend/app/features/applications/application/application-tabs-base/tabs/gitscm-tab/gitscm-tab.component.spec.ts b/src/frontend/app/features/applications/application/application-tabs-base/tabs/gitscm-tab/gitscm-tab.component.spec.ts index 8c8440f8a1..ff747ea863 100644 --- a/src/frontend/app/features/applications/application/application-tabs-base/tabs/gitscm-tab/gitscm-tab.component.spec.ts +++ b/src/frontend/app/features/applications/application/application-tabs-base/tabs/gitscm-tab/gitscm-tab.component.spec.ts @@ -12,8 +12,8 @@ import { GitSCMTabComponent } from './gitscm-tab.component'; import { DatePipe } from '@angular/common'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../../../core/github.helpers'; -import { HttpModule, Http, ConnectionBackend } from '@angular/http'; -import { MockBackend } from '@angular/http/testing'; +import { HttpClientModule } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; describe('GitSCMTabComponent', () => { let component: GitSCMTabComponent; @@ -34,17 +34,13 @@ describe('GitSCMTabComponent', () => { } ), NoopAnimationsModule, - HttpModule + HttpClientModule, + HttpClientTestingModule ], providers: [ { provide: ApplicationService, useClass: ApplicationServiceMock }, { provide: GITHUB_API_URL, useFactory: getGitHubAPIURL }, DatePipe, - Http, - { - provide: ConnectionBackend, - useClass: MockBackend - } ] }) .compileComponents(); diff --git a/src/frontend/app/features/applications/deploy-application/deploy-application-step2-1/commit-list-wrapper/commit-list-wrapper.component.spec.ts b/src/frontend/app/features/applications/deploy-application/deploy-application-step2-1/commit-list-wrapper/commit-list-wrapper.component.spec.ts index 5780006172..94ca9d4047 100644 --- a/src/frontend/app/features/applications/deploy-application/deploy-application-step2-1/commit-list-wrapper/commit-list-wrapper.component.spec.ts +++ b/src/frontend/app/features/applications/deploy-application/deploy-application-step2-1/commit-list-wrapper/commit-list-wrapper.component.spec.ts @@ -5,9 +5,9 @@ import { CommonModule, DatePipe } from '@angular/common'; import { CoreModule } from '../../../../../core/core.module'; import { SharedModule } from '../../../../../shared/shared.module'; import { createBasicStoreModule } from '../../../../../test-framework/store-test-helper'; -import { HttpModule, Http, ConnectionBackend } from '@angular/http'; import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../../core/github.helpers'; -import { MockBackend } from '@angular/http/testing'; +import { HttpClientModule } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; describe('CommitListWrapperComponent', () => { let component: CommitListWrapperComponent; @@ -21,16 +21,12 @@ describe('CommitListWrapperComponent', () => { CoreModule, SharedModule, createBasicStoreModule(), - HttpModule + HttpClientModule, + HttpClientTestingModule ], providers: [ DatePipe, { provide: GITHUB_API_URL, useFactory: getGitHubAPIURL }, - Http, - { - provide: ConnectionBackend, - useClass: MockBackend - } ] }) .compileComponents(); diff --git a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.spec.ts b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.spec.ts index 4a533a7b21..46436238a7 100644 --- a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.spec.ts +++ b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.spec.ts @@ -1,20 +1,18 @@ import { GitSCMService } from './../../../../shared/data-services/scm/scm.service'; import { CoreModule } from '../../../../core/core.module'; import { SharedModule } from '../../../../shared/shared.module'; -import { inject, TestBed, ComponentFixture, async, fakeAsync, tick } from '@angular/core/testing'; -import { Store, StoreModule } from '@ngrx/store'; +import { TestBed, ComponentFixture, async } from '@angular/core/testing'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { createBasicStoreModule } from '../../../../test-framework/store-test-helper'; import { RouterTestingModule } from '@angular/router/testing'; -import { MatDialogModule } from '@angular/material'; import { DeployApplicationStep2Component } from './deploy-application-step2.component'; import { DeployApplicationFsComponent } from './deploy-application-fs/deploy-application-fs.component'; import { GITHUB_API_URL, getGitHubAPIURL } from '../../../../core/github.helpers'; -import { HttpModule, Http, ConnectionBackend } from '@angular/http'; -import { MockBackend } from '@angular/http/testing'; import { GithubProjectExistsDirective } from '../github-project-exists.directive'; +import { HttpClientModule } from '@angular/common/http'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; describe('DeployApplicationStep2Component', () => { let component: DeployApplicationStep2Component; @@ -33,15 +31,11 @@ describe('DeployApplicationStep2Component', () => { RouterTestingModule, createBasicStoreModule(), BrowserAnimationsModule, - HttpModule + HttpClientModule, + HttpClientTestingModule ], providers: [ { provide: GITHUB_API_URL, useFactory: getGitHubAPIURL }, - Http, - { - provide: ConnectionBackend, - useClass: MockBackend - }, GitSCMService ] }) diff --git a/src/frontend/app/features/applications/deploy-application/github-project-exists.directive.spec.ts b/src/frontend/app/features/applications/deploy-application/github-project-exists.directive.spec.ts index 89a27a0e95..e6e8276340 100644 --- a/src/frontend/app/features/applications/deploy-application/github-project-exists.directive.spec.ts +++ b/src/frontend/app/features/applications/deploy-application/github-project-exists.directive.spec.ts @@ -1,4 +1,4 @@ -import { HttpModule } from '@angular/http'; +import { HttpClientModule } from '@angular/common/http'; import { Store } from '@ngrx/store'; import { inject, TestBed } from '@angular/core/testing'; import { CommonModule } from '@angular/common'; @@ -9,6 +9,7 @@ import { AppState } from '../../../store/app-state'; import { GitSCMService } from '../../../shared/data-services/scm/scm.service'; import { GithubProjectExistsDirective } from './github-project-exists.directive'; import { GITHUB_API_URL, getGitHubAPIURL } from '../../../core/github.helpers'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; describe('GithubProjectExistsDirective', () => { @@ -19,7 +20,8 @@ describe('GithubProjectExistsDirective', () => { CoreModule, SharedModule, createBasicStoreModule(), - HttpModule + HttpClientModule, + HttpClientTestingModule ], providers: [ { provide: GITHUB_API_URL, useFactory: getGitHubAPIURL } From d252631c6b29f1af70f17d5c10b050cc8d81bd0f Mon Sep 17 00:00:00 2001 From: Neil MacDougall Date: Thu, 14 Feb 2019 15:54:49 +0000 Subject: [PATCH 8/8] Fix issue where autocomplete stops working --- .../deploy-application-step2.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts index 7d1c77996d..9454437a24 100644 --- a/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts +++ b/src/frontend/app/features/applications/deploy-application/deploy-application-step2/deploy-application-step2.component.ts @@ -3,7 +3,7 @@ import { NgForm } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { Store } from '@ngrx/store'; import { combineLatest as observableCombineLatest, Observable, timer as observableTimer, of as observableOf, Subscription } from 'rxjs'; -import { filter, map, take, tap, withLatestFrom, switchMap, startWith, pairwise } from 'rxjs/operators'; +import { filter, map, take, tap, withLatestFrom, switchMap, startWith, pairwise, catchError } from 'rxjs/operators'; import { EntityServiceFactory } from '../../../../core/entity-service-factory.service'; import { StepOnNextFunction } from '../../../../shared/components/stepper/step/step.component'; @@ -302,6 +302,7 @@ export class DeployApplicationStep2Component return observableTimer(500).pipe( take(1), switchMap(() => this.scm.getMatchingRepositories(name)), + catchError(_e => observableOf(null)), tap(suggestions => this.cachedSuggestions[cacheName] = suggestions) ); }