From 0c04506bdb13893151c1434d23252986a12d2b65 Mon Sep 17 00:00:00 2001 From: Vignesh Sankar Iyer <68676914+vigneshsankariyer1234567890@users.noreply.github.com> Date: Sun, 5 Mar 2023 14:39:54 +0800 Subject: [PATCH] Merge master into release for V3.4.5 (#1150) Merge master into release to release V3.4.5 --- browserslist => .browserslistrc | 0 .github/dependabot.yml | 7 + .github/workflows/coverage-report.yml | 2 +- .github/workflows/github-actions.yml | 3 - README.md | 6 + angular.json | 21 +- electron-utils/oauth.ts | 4 +- package.json | 68 +++--- src/app/app.component.ts | 6 +- src/app/app.module.ts | 3 +- src/app/auth/auth.component.ts | 14 +- src/app/auth/auth.module.ts | 3 +- .../confirm-login/confirm-login.component.ts | 10 +- .../json-parse-error-dialog.component.ts | 2 +- src/app/auth/profiles/profiles.component.html | 1 + src/app/auth/profiles/profiles.component.ts | 2 +- .../session-selection.component.ts | 2 +- .../form-disable-control.directive.ts | 2 +- .../user-confirmation.component.ts | 2 +- src/app/core/models/issue.model.ts | 7 +- .../issue-dispute-section-parser.model.ts | 2 +- .../moderation-section-parser.model.ts | 2 +- .../tester-response-section-parser.model.ts | 2 +- .../core/models/templates/template.model.ts | 8 +- src/app/core/services/auth.service.ts | 9 +- src/app/core/services/dialog.service.ts | 20 +- .../core/services/error-handling.service.ts | 6 +- src/app/core/services/github.service.ts | 20 +- src/app/core/services/githubevent.service.ts | 4 +- src/app/core/services/issue.service.ts | 31 ++- src/app/core/services/label.service.ts | 15 +- .../core/services/mocks/mock.auth.service.ts | 2 +- .../core/services/mocks/mock.issue.service.ts | 10 +- src/app/core/services/phase.service.ts | 4 +- src/app/core/services/repo-creator.service.ts | 12 +- .../session-fix-confirmation.component.ts | 2 +- src/app/core/services/user.service.ts | 4 +- .../action-toasters/action-toasters.module.ts | 3 +- .../undo-action/undo-action.component.ts | 2 +- .../comment-editor.component.html | 2 + .../comment-editor.component.ts | 130 ++++++++++- .../comment-editor/comment-editor.module.ts | 8 +- .../markdown-toolbar.component.css | 0 .../markdown-toolbar.component.html | 66 ++++++ .../markdown-toolbar.component.ts | 13 ++ .../comment-editor/upload-text-insertor.ts | 2 +- .../error-toasters/error-toaster.module.ts | 3 +- .../form-error/form-error.component.ts | 2 +- .../general-message-error.component.ts | 2 +- .../invalid-credentials-error.component.ts | 2 +- .../toaster/toaster.component.ts | 2 +- .../shared/issue-tables/IssuesDataTable.ts | 7 +- .../shared/issue-tables/issue-paginator.ts | 2 +- src/app/shared/issue-tables/issue-sorter.ts | 2 +- .../issue-tables/issue-tables-columns.ts | 2 +- .../issue-tables/issue-tables.component.html | 10 +- .../issue-tables/issue-tables.component.ts | 22 +- .../issue/assignee/assignee.component.ts | 2 +- .../conflict-dialog.component.ts | 3 +- .../description/description.component.html | 9 +- .../description/description.component.ts | 15 +- .../duplicateOf/duplicate-of.component.ts | 5 +- .../shared/issue/issue-components.module.ts | 5 +- .../shared/issue/title/title.component.css | 1 + .../shared/issue/title/title.component.html | 9 +- src/app/shared/issue/title/title.component.ts | 10 + .../label-definition-popup.component.ts | 2 +- src/app/shared/layout/header.component.ts | 6 +- src/app/shared/lib/marked.ts | 2 - src/app/shared/material.module.ts | 104 +++++---- .../issue-dispute/issue-dispute.component.ts | 6 +- .../conflict-dialog.component.html | 6 +- .../conflict-dialog.component.ts | 3 +- .../new-team-response.component.html | 4 +- .../new-team-response.component.ts | 12 +- .../new-team-response.module.ts | 3 +- .../team-response.component.html | 9 +- .../team-response/team-response.component.ts | 38 +++- .../conflict-dialog.component.ts | 2 +- .../tester-response.component.html | 2 +- .../tester-response.component.ts | 59 ++++- .../tester-response/tester-response.module.ts | 1 - .../view-issue/view-issue.component.html | 2 +- src/polyfills.ts | 5 + src/test.ts | 2 +- src/tsconfig.app.json | 3 +- src/typings.d.ts | 2 +- .../auth/profiles/profiles.component.spec.ts | 106 +++++++++ .../session-selection.component.spec.ts | 102 +++++++++ .../issues-faulty.component.spec.ts | 2 +- .../issues-pending.component.spec.ts | 2 +- .../issues-responded.component.spec.ts | 2 +- .../comment-editor.component.spec.ts | 202 ++++++++++++++++++ .../upload-text-insertor.spec.ts | 169 +++++++++++++++ .../issue-tables/issue-paginator.spec.ts | 2 +- .../shared/issue-tables/issue-sorter.spec.ts | 2 +- .../shared/issue-tables/search-filter.spec.ts | 4 +- .../issue/assignee/assignee.component.spec.ts | 4 +- .../description/description.component.spec.ts | 2 +- .../duplicated-issues.component.spec.ts | 4 +- .../issue/title/title.component.spec.ts | 2 +- tests/constants/error.constants.ts | 22 ++ tests/constants/githubcomment.constants.ts | 10 +- tests/constants/githubissue.constants.ts | 6 +- tests/constants/label.constants.ts | 2 +- ...issue-dispute-section-parser.model.spec.ts | 2 +- .../moderation-section-parser.model.spec.ts | 3 +- ...ster-response-section-parser.model.spec.ts | 8 +- tests/services/error-handling.service.spec.ts | 74 +++++++ tests/services/label.service.spec.ts | 14 +- tests/services/logging.service.spec.ts | 70 +++--- tests/services/permissions.service.spec.ts | 2 +- tests/services/repo-creator.service.spec.ts | 2 +- tests/services/user.service.spec.ts | 6 +- tsconfig.json | 2 +- 115 files changed, 1440 insertions(+), 320 deletions(-) rename browserslist => .browserslistrc (100%) create mode 100644 .github/dependabot.yml create mode 100644 src/app/shared/comment-editor/markdown-toolbar/markdown-toolbar.component.css create mode 100644 src/app/shared/comment-editor/markdown-toolbar/markdown-toolbar.component.html create mode 100644 src/app/shared/comment-editor/markdown-toolbar/markdown-toolbar.component.ts create mode 100644 tests/app/auth/profiles/profiles.component.spec.ts create mode 100644 tests/app/auth/session-selection/session-selection.component.spec.ts create mode 100644 tests/app/shared/comment-editor/comment-editor.component.spec.ts create mode 100644 tests/app/shared/comment-editor/upload-text-insertor.spec.ts create mode 100644 tests/constants/error.constants.ts create mode 100644 tests/services/error-handling.service.spec.ts diff --git a/browserslist b/.browserslistrc similarity index 100% rename from browserslist rename to .browserslistrc diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..067368c9a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: 'npm' + directory: '/' + schedule: + interval: 'weekly' + open-pull-requests-limit: 0 diff --git a/.github/workflows/coverage-report.yml b/.github/workflows/coverage-report.yml index 63f8d3191..9cc7bb4fc 100644 --- a/.github/workflows/coverage-report.yml +++ b/.github/workflows/coverage-report.yml @@ -23,7 +23,7 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: npm install - - run: npm run test -- "--code-coverage" + - run: npm run test -- "--code-coverage" "--source-map=false" - uses: codecov/codecov-action@v3 with: directory: ./tests/coverage diff --git a/.github/workflows/github-actions.yml b/.github/workflows/github-actions.yml index 6f3a739f9..1fa667fd4 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/github-actions.yml @@ -24,7 +24,6 @@ jobs: node-version: ${{ matrix.node-version }} - run: npm install - run: npm update - - run: npm run electron:linux env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: npm run lint @@ -46,7 +45,6 @@ jobs: node-version: ${{ matrix.node-version }} - run: npm install - run: npm update - - run: npm run electron:mac env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: npm run lint @@ -65,6 +63,5 @@ jobs: node-version: ${{ matrix.node-version }} - run: npm install - run: npm update - - run: npm run electron:windows - run: npm run lint - run: npm test -- "--karma-config=./tests/karma.ci.conf.js" diff --git a/README.md b/README.md index bec98c299..8b7fe73c1 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,9 @@ * [Direct link to the **User Guide**](https://catcher-org.github.io/ug/) * [Direct link to the **Developer Guide**](https://catcher-org.github.io/dg/) + +This project is based in [NUS School of Computing](https://www.comp.nus.edu.sg/), and part of the [NUS-OSS initiative](https://nus-oss.github.io/). + +Licence: MIT + +Contact: `seer@comp.nus.edu.sg` diff --git a/angular.json b/angular.json index 5e9d63983..e1d0a42eb 100644 --- a/angular.json +++ b/angular.json @@ -11,6 +11,7 @@ "build": { "builder": "@angular-devkit/build-angular:browser", "options": { + "aot": true, "outputPath": "dist", "index": "src/index.html", "main": "src/main.ts", @@ -39,6 +40,12 @@ }, "configurations": { "staging": { + "budgets": [ + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ], "optimization": true, "outputHashing": "all", "sourceMap": false, @@ -56,6 +63,12 @@ ] }, "production": { + "budgets": [ + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ], "optimization": true, "outputHashing": "all", "sourceMap": false, @@ -73,6 +86,12 @@ ] }, "test": { + "budgets": [ + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ], "optimization": false, "outputHashing": "all", "sourceMap": true, @@ -145,7 +164,7 @@ "schematics": { "@schematics/angular:component": { "prefix": "app", - "styleext": "css" + "style": "css" }, "@schematics/angular:directive": { "prefix": "app" diff --git a/electron-utils/oauth.ts b/electron-utils/oauth.ts index f0229fc0b..0aea0337a 100644 --- a/electron-utils/oauth.ts +++ b/electron-utils/oauth.ts @@ -2,8 +2,8 @@ import { BrowserWindow, shell } from 'electron'; import { v4 as uuid } from 'uuid'; const nodeUrl = require('url'); -const fetch = require('node-fetch'); const Logger = require('electron-log'); +const fetch = require('node-fetch'); const CLIENT_ID = '6750652c0c9001314434'; const BASE_URL = 'https://github.com'; @@ -24,7 +24,7 @@ export function getAccessToken(window: BrowserWindow, repoPermissionLevel: strin const accessTokenUrl = `${ACCESS_TOKEN_URL}/${code}`; return fetch(accessTokenUrl) .then((res) => res.json()) - .then((data) => { + .then((data: { error }) => { if (data.error) { throw new Error(data.error); } diff --git a/package.json b/package.json index 2987e56ec..097af5188 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CATcher", - "version": "3.4.4", + "version": "3.4.5", "main": "main.js", "scripts": { "postinstall": "npm run postinstall:electron && electron-builder install-app-deps", @@ -40,16 +40,18 @@ } }, "dependencies": { - "@angular/animations": "^8.2.14", - "@angular/cdk": "^7.3.7", - "@angular/common": "^8.2.14", - "@angular/compiler": "^8.2.14", - "@angular/core": "^8.2.14", - "@angular/forms": "^8.2.14", - "@angular/material": "^7.3.7", - "@angular/platform-browser": "^8.2.14", - "@angular/platform-browser-dynamic": "^8.2.14", - "@angular/router": "^8.2.14", + "@angular/animations": "^10.2.5", + "@angular/cdk": "^10.2.7", + "@angular/common": "^10.2.5", + "@angular/compiler": "^10.2.5", + "@angular/core": "^10.2.5", + "@angular/forms": "^10.2.5", + "@angular/localize": "^10.2.5", + "@angular/material": "^10.2.7", + "@angular/platform-browser": "^10.2.5", + "@angular/platform-browser-dynamic": "^10.2.5", + "@angular/router": "^10.2.5", + "@github/markdown-toolbar-element": "^2.1.1", "@octokit/rest": "^16.37.0", "ajv": "^6.11.0", "apollo-angular": "^1.9.1", @@ -67,20 +69,20 @@ "graphql-tag": "2.11.0", "karma-spec-reporter": "0.0.32", "moment": "^2.24.0", - "ngx-markdown": "^8.2.1", - "ngx-mat-select-search": "^1.8.0", - "node-fetch": "^2.6.0", - "rxjs": "6.5.3", - "tslib": "^1.9.0", + "ngx-markdown": "^9.1.1", + "ngx-mat-select-search": "^3.3.3", + "node-fetch": "^2.6.8", + "rxjs": "6.6.7", + "tslib": "^2.0.0", "uuid": "7.0.3", - "zone.js": "~0.9.1" + "zone.js": "~0.10.2" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.803.29", - "@angular/cli": "^8.3.29", - "@angular/compiler-cli": "^8.2.14", - "@angular/language-service": "^8.2.14", - "@graphql-codegen/cli": "1.17.7", + "@angular-devkit/build-angular": "~0.1002.4", + "@angular/cli": "^10.2.4", + "@angular/compiler-cli": "^10.2.5", + "@angular/language-service": "^10.2.5", + "@graphql-codegen/cli": "^2.6.4", "@graphql-codegen/typescript": "1.17.7", "@graphql-codegen/typescript-document-nodes": "1.17.7", "@graphql-codegen/typescript-operations": "^1.18.4", @@ -91,30 +93,30 @@ "@types/jasminewd2": "2.0.8", "@types/node": "^15.6.1", "angular-cli-ghpages": "^1.0.0-rc.2", - "codelyzer": "^5.0.1", + "codelyzer": "^5.1.2", "electron": "11.4.8", "electron-builder": "22.2.0", "electron-reload": "1.5.0", "graphql-codegen-fragment-matcher": "^0.18.2", "husky": "^4.2.5", "jasmine": "^3.9.0", - "jasmine-core": "3.5.0", - "jasmine-spec-reporter": "4.2.1", - "karma": "^4.4.1", - "karma-chrome-launcher": "3.1.0", - "karma-coverage-istanbul-reporter": "2.1.1", + "jasmine-core": "~3.5.0", + "jasmine-spec-reporter": "~5.0.0", + "karma": "~5.0.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage-istanbul-reporter": "~3.0.2", "karma-firefox-launcher": "^2.1.1", - "karma-jasmine": "3.1.0", - "karma-jasmine-html-reporter": "1.5.1", + "karma-jasmine": "~4.0.0", + "karma-jasmine-html-reporter": "^1.5.0", "npm-run-all": "4.1.5", "prettier": "2.2.1", "pretty-quick": "^3.1.1", - "protractor": "5.4.2", + "protractor": "~7.0.0", "scuri": "^0.9.4", "ts-node": "^7.0.1", - "tslint": "5.20.1", + "tslint": "~6.1.0", "tslint-config-prettier": "^1.18.0", - "typescript": "3.5.3", + "typescript": "4.0.8", "wait-on": "3.3.0", "webdriver-manager": "12.1.7" } diff --git a/src/app/app.component.ts b/src/app/app.component.ts index f9ff2842a..42419f9bf 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -13,12 +13,12 @@ export class AppComponent implements AfterViewInit { NOT_CONNECTED_ERROR: Error = new Error('You are not connected to the internet.'); constructor(public electronService: ElectronService, logger: LoggingService, public errorHandlingService: ErrorHandlingService) { - logger.info('AppConfig', AppConfig); + logger.info('AppComponent: AppConfig', AppConfig); if (electronService.isElectron()) { - logger.info('Mode electron'); + logger.info('AppComponent: Mode electron'); } else { - logger.info('Mode web'); + logger.info('AppComponent: Mode web'); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 5989b1162..b86441cc8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -94,8 +94,7 @@ import { SharedModule } from './shared/shared.module'; useClass: ErrorHandlingService } ], - bootstrap: [AppComponent], - entryComponents: [UserConfirmationComponent, SessionFixConfirmationComponent, LabelDefinitionPopupComponent] + bootstrap: [AppComponent] }) export class AppModule { constructor( diff --git a/src/app/auth/auth.component.ts b/src/app/auth/auth.component.ts index 31e5a1d79..5195127d2 100644 --- a/src/app/auth/auth.component.ts +++ b/src/app/auth/auth.component.ts @@ -1,7 +1,7 @@ import { Component, NgZone, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { Observable, Subscription } from 'rxjs'; -import { filter, flatMap, map } from 'rxjs/operators'; +import { filter, map, mergeMap } from 'rxjs/operators'; import { AppConfig } from '../../environments/environment'; import { GithubUser } from '../core/models/github-user.model'; import { ApplicationService } from '../core/services/application.service'; @@ -72,7 +72,7 @@ export class AuthComponent implements OnInit, OnDestroy { // runs upon receiving oauthCode from the redirect this.authService.changeAuthState(AuthState.AwaitingAuthentication); this.restoreOrgDetailsFromLocalStorage(); - this.logger.info('Obtained authorisation code from Github'); + this.logger.info('AuthComponent: Obtained authorisation code from Github'); this.fetchAccessToken(oauthCode, state); } } @@ -84,11 +84,11 @@ export class AuthComponent implements OnInit, OnDestroy { */ fetchAccessToken(oauthCode: string, state: string) { if (!this.authService.isReturnedStateSame(state)) { - this.logger.info(`Received incorrect state ${state}, continue waiting for correct state`); + this.logger.info(`AuthComponent: Received incorrect state ${state}, continue waiting for correct state`); return; } - this.logger.info('Retrieving access token from Github'); + this.logger.info('AuthComponent: Retrieving access token from Github'); const accessTokenUrl = `${AppConfig.accessTokenUrl}/${oauthCode}/client_id/${AppConfig.clientId}`; fetch(accessTokenUrl) @@ -98,10 +98,10 @@ export class AuthComponent implements OnInit, OnDestroy { throw new Error(data.error); } this.authService.storeOAuthAccessToken(data.token); - this.logger.info('Sucessfully obtained access token'); + this.logger.info('AuthComponent: Sucessfully obtained access token'); }) .catch((err) => { - this.logger.info(`Error in data fetched from access token URL: ${err}`); + this.logger.info(`AuthComponent: Error in data fetched from access token URL: ${err}`); this.errorHandlingService.handleError(err); this.authService.changeAuthState(AuthState.NotAuthenticated); }); @@ -189,7 +189,7 @@ export class AuthComponent implements OnInit, OnDestroy { this.accessTokenSubscription = this.authService.accessToken .pipe( filter((token: string) => !!token), - flatMap(() => this.userService.getAuthenticatedUser()) + mergeMap(() => this.userService.getAuthenticatedUser()) ) .subscribe((user: GithubUser) => { this.ngZone.run(() => { diff --git a/src/app/auth/auth.module.ts b/src/app/auth/auth.module.ts index 1b7cdb094..901bc3916 100644 --- a/src/app/auth/auth.module.ts +++ b/src/app/auth/auth.module.ts @@ -10,7 +10,6 @@ import { SessionSelectionComponent } from './session-selection/session-selection @NgModule({ imports: [AuthRoutingModule, SharedModule, CommonModule], - declarations: [AuthComponent, ProfilesComponent, JsonParseErrorDialogComponent, ConfirmLoginComponent, SessionSelectionComponent], - entryComponents: [JsonParseErrorDialogComponent] + declarations: [AuthComponent, ProfilesComponent, JsonParseErrorDialogComponent, ConfirmLoginComponent, SessionSelectionComponent] }) export class AuthModule {} diff --git a/src/app/auth/confirm-login/confirm-login.component.ts b/src/app/auth/confirm-login/confirm-login.component.ts index b4350d800..71011d0cb 100644 --- a/src/app/auth/confirm-login/confirm-login.component.ts +++ b/src/app/auth/confirm-login/confirm-login.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit } from '@angular/core'; import { Router } from '@angular/router'; -import { flatMap } from 'rxjs/operators'; +import { mergeMap } from 'rxjs/operators'; import { AuthService, AuthState } from '../../core/services/auth.service'; import { ElectronService } from '../../core/services/electron.service'; import { ErrorHandlingService } from '../../core/services/error-handling.service'; @@ -37,7 +37,7 @@ export class ConfirmLoginComponent implements OnInit { } logIntoAnotherAccount() { - this.logger.info('Logging into another account'); + this.logger.info('ConfirmLoginComponent: Logging into another account'); this.electronService.clearCookies(); this.authService.startOAuthProcess(); } @@ -60,8 +60,8 @@ export class ConfirmLoginComponent implements OnInit { this.userService .createUserModel(this.username) .pipe( - flatMap(() => this.phaseService.sessionSetup()), - flatMap(() => this.githubEventService.setLatestChangeEvent()) + mergeMap(() => this.phaseService.sessionSetup()), + mergeMap(() => this.githubEventService.setLatestChangeEvent()) ) .subscribe( () => { @@ -70,7 +70,7 @@ export class ConfirmLoginComponent implements OnInit { (error) => { this.authService.changeAuthState(AuthState.NotAuthenticated); this.errorHandlingService.handleError(error); - this.logger.info(`Completion of login process failed with an error: ${error}`); + this.logger.info(`ConfirmLoginComponent: Completion of login process failed with an error: ${error}`); } ); } diff --git a/src/app/auth/profiles/json-parse-error-dialog/json-parse-error-dialog.component.ts b/src/app/auth/profiles/json-parse-error-dialog/json-parse-error-dialog.component.ts index b297194f6..923d3cb02 100644 --- a/src/app/auth/profiles/json-parse-error-dialog/json-parse-error-dialog.component.ts +++ b/src/app/auth/profiles/json-parse-error-dialog/json-parse-error-dialog.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { MatDialogRef } from '@angular/material'; +import { MatDialogRef } from '@angular/material/dialog'; import { ProfilesComponent } from '../profiles.component'; /** diff --git a/src/app/auth/profiles/profiles.component.html b/src/app/auth/profiles/profiles.component.html index ec5535f7f..74cac42e6 100644 --- a/src/app/auth/profiles/profiles.component.html +++ b/src/app/auth/profiles/profiles.component.html @@ -14,6 +14,7 @@ mat-icon-button (click)="this.fileSelectorInitiation(fileInput)" disableRipple="true" + matTooltip="Configure your custom settings" (mousedown)="this.animationActivated = true" (mouseleave)="this.animationActivated = false" > diff --git a/src/app/auth/profiles/profiles.component.ts b/src/app/auth/profiles/profiles.component.ts index f10dec9a7..1abfe13a9 100644 --- a/src/app/auth/profiles/profiles.component.ts +++ b/src/app/auth/profiles/profiles.component.ts @@ -1,6 +1,6 @@ import { animate, state, style, transition, trigger } from '@angular/animations'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { MatDialog } from '@angular/material'; +import { MatDialog } from '@angular/material/dialog'; import { isValidProfile, Profile } from '../../core/models/profile.model'; import { ErrorHandlingService } from '../../core/services/error-handling.service'; import { MALFORMED_PROFILES_ERROR, ProfileService } from '../../core/services/profile.service'; diff --git a/src/app/auth/session-selection/session-selection.component.ts b/src/app/auth/session-selection/session-selection.component.ts index 59e8a62fd..fd825aba2 100644 --- a/src/app/auth/session-selection/session-selection.component.ts +++ b/src/app/auth/session-selection/session-selection.component.ts @@ -57,7 +57,7 @@ export class SessionSelectionComponent implements OnInit { window.localStorage.setItem('dataRepo', dataRepo); this.githubService.storeOrganizationDetails(org, dataRepo); - this.logger.info(`Selected Settings Repo: ${sessionInformation}`); + this.logger.info(`SessionSelectionComponent: Selected Settings Repo: ${sessionInformation}`); this.phaseService.storeSessionData().subscribe( () => { diff --git a/src/app/core/directives/form-disable-control.directive.ts b/src/app/core/directives/form-disable-control.directive.ts index 911d131db..181ebdd1e 100644 --- a/src/app/core/directives/form-disable-control.directive.ts +++ b/src/app/core/directives/form-disable-control.directive.ts @@ -6,7 +6,7 @@ import { NgControl } from '@angular/forms'; }) export class FormDisableControlDirective { @Input() set disableControl(condition: boolean) { - condition ? this.ngControl.control.disable() : this.ngControl.control.enable(); + condition ? this.ngControl.control?.disable() : this.ngControl.control?.enable(); } constructor(private ngControl: NgControl) {} diff --git a/src/app/core/guards/user-confirmation/user-confirmation.component.ts b/src/app/core/guards/user-confirmation/user-confirmation.component.ts index 6f3ae9dd0..4070b5bdc 100644 --- a/src/app/core/guards/user-confirmation/user-confirmation.component.ts +++ b/src/app/core/guards/user-confirmation/user-confirmation.component.ts @@ -1,5 +1,5 @@ import { Component, Inject, OnInit } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { CanDeactivateIssueGuard } from '../can-deactivate-issue-guard.service'; /** diff --git a/src/app/core/models/issue.model.ts b/src/app/core/models/issue.model.ts index 5511074e7..3a68e6bb0 100644 --- a/src/app/core/models/issue.model.ts +++ b/src/app/core/models/issue.model.ts @@ -28,7 +28,7 @@ export class Issue { /** Fields derived from Labels */ severity: string; type: string; - responseTag?: string; + response?: string; // all instance of this should be renamed to response duplicated?: boolean; status?: string; pending?: string; @@ -52,6 +52,7 @@ export class Issue { /** Fields for error messages during parsing of Github's issue description */ teamResponseError: boolean; testerResponseError: boolean; + parseError: string; /** * Formats the text to create space at the end of the user input to prevent any issues with @@ -117,7 +118,7 @@ export class Issue { /** Fields derived from Labels */ this.severity = githubIssue.findLabel(GithubLabel.LABELS.severity); this.type = githubIssue.findLabel(GithubLabel.LABELS.type); - this.responseTag = githubIssue.findLabel(GithubLabel.LABELS.response); + this.response = githubIssue.findLabel(GithubLabel.LABELS.response); this.duplicated = !!githubIssue.findLabel(GithubLabel.LABELS.duplicated, false); this.status = githubIssue.findLabel(GithubLabel.LABELS.status); this.pending = githubIssue.findLabel(GithubLabel.LABELS.pending); @@ -136,6 +137,7 @@ export class Issue { issue.assignees = githubIssue.assignees.map((assignee) => assignee.login); issue.teamResponseError = template.parseFailure; + issue.parseError = template.parseError; issue.issueComment = template.comment; issue.teamResponse = template.teamResponse; issue.duplicateOf = template.duplicateOf; @@ -151,6 +153,7 @@ export class Issue { issue.githubComments = githubIssue.comments; issue.testerResponseError = testerResponseTemplate.parseFailure && teamAcceptedTemplate.parseFailure; + issue.parseError = testerResponseTemplate.parseError; issue.teamAccepted = teamAcceptedTemplate.teamAccepted; issue.issueComment = testerResponseTemplate.comment; issue.teamResponse = testerResponseTemplate.teamResponse; diff --git a/src/app/core/models/templates/section-parsers/issue-dispute-section-parser.model.ts b/src/app/core/models/templates/section-parsers/issue-dispute-section-parser.model.ts index 554e19b13..fec1f6900 100644 --- a/src/app/core/models/templates/section-parsers/issue-dispute-section-parser.model.ts +++ b/src/app/core/models/templates/section-parsers/issue-dispute-section-parser.model.ts @@ -4,7 +4,7 @@ const { coroutine, everyCharUntil, optionalWhitespace, str } = require('arcsecon const SECTION_TITLE_PREFIX = '## :question: '; const TEAM_SAYS_HEADER = '### Team says:'; -const LINE_SEPARATOR = '-------------------'; +const LINE_SEPARATOR = '
'; export const IssueDisputeSectionParser = coroutine(function* () { yield str(SECTION_TITLE_PREFIX); diff --git a/src/app/core/models/templates/section-parsers/moderation-section-parser.model.ts b/src/app/core/models/templates/section-parsers/moderation-section-parser.model.ts index 8b06501d9..20e7a7363 100644 --- a/src/app/core/models/templates/section-parsers/moderation-section-parser.model.ts +++ b/src/app/core/models/templates/section-parsers/moderation-section-parser.model.ts @@ -6,7 +6,7 @@ const { coroutine, everyCharUntil, lookAhead, optionalWhitespace, str, whitespac const SECTION_TITLE_PREFIX = '## :question: '; const DONE_CHECKBOX_DESCRIPTION = 'Done'; -const LINE_SEPARATOR = '-------------------'; +const LINE_SEPARATOR = '
'; export const DoneCheckboxParser = buildCheckboxParser(DONE_CHECKBOX_DESCRIPTION); diff --git a/src/app/core/models/templates/section-parsers/tester-response-section-parser.model.ts b/src/app/core/models/templates/section-parsers/tester-response-section-parser.model.ts index 9c7ef10db..c42ef42b1 100644 --- a/src/app/core/models/templates/section-parsers/tester-response-section-parser.model.ts +++ b/src/app/core/models/templates/section-parsers/tester-response-section-parser.model.ts @@ -18,7 +18,7 @@ const TEAM_CHOSE_PREFIX = 'Team chose '; const TESTER_CHOSE_PREFIX = 'Originally '; const DISAGREE_CHECKBOX_DESCRIPTION = 'I disagree'; const DISAGREEMENT_REASON_PREFIX = '**Reason for disagreement:** '; -const LINE_SEPARATOR = '-------------------'; +const LINE_SEPARATOR = '
'; const DUPLICATE_STATUS_MESSAGE = "Team chose to mark this issue as a duplicate of another issue (as explained in the _**Team's response**_ above)"; diff --git a/src/app/core/models/templates/template.model.ts b/src/app/core/models/templates/template.model.ts index 02576535d..8df67538b 100644 --- a/src/app/core/models/templates/template.model.ts +++ b/src/app/core/models/templates/template.model.ts @@ -3,6 +3,7 @@ import { GithubComment } from '../github/github-comment.model'; export abstract class Template { parser; parseResult; + parseError: string; parseFailure: boolean; protected constructor(parser) { @@ -14,9 +15,10 @@ export abstract class Template { */ findConformingComment(githubComments: GithubComment[]): GithubComment { let templateConformingComment: GithubComment; + let parsed: any; for (const comment of githubComments) { - const parsed = this.parser.run(comment.body); + parsed = this.parser.run(comment.body); if (!parsed.isError) { this.parseResult = parsed.result; templateConformingComment = comment; @@ -26,6 +28,10 @@ export abstract class Template { if (templateConformingComment === undefined) { this.parseFailure = true; + + if (parsed) { + this.parseError = parsed.error; + } } return templateConformingComment; } diff --git a/src/app/core/services/auth.service.ts b/src/app/core/services/auth.service.ts index 0f9e0d6ad..730236e90 100644 --- a/src/app/core/services/auth.service.ts +++ b/src/app/core/services/auth.service.ts @@ -61,6 +61,7 @@ export class AuthService { } reset(): void { + this.logger.info('AuthService: Clearing access token and setting AuthState to NotAuthenticated.'); this.accessToken.next(undefined); this.changeAuthState(AuthState.NotAuthenticated); this.ngZone.run(() => this.router.navigate([''])); @@ -82,12 +83,14 @@ export class AuthService { setTitleWithPhaseDetail(): void { const appSetting = require('../../../../package.json'); const title = `${appSetting.name} ${appSetting.version} - ${this.phaseService.getPhaseDetail()}`; + this.logger.info(`AuthService: Setting Title as ${title}`); this.titleService.setTitle(title); } setLandingPageTitle(): void { const appSetting = require('../../../../package.json'); const title = `${appSetting.name} ${appSetting.version}`; + this.logger.info(`AuthService: Setting LandingPageTitle as ${title}`); this.titleService.setTitle(title); } @@ -99,7 +102,7 @@ export class AuthService { if (newAuthState === AuthState.Authenticated) { const sessionId = generateSessionId(); this.issueService.setSessionId(sessionId); - this.logger.info(`Successfully authenticated with session: ${sessionId}`); + this.logger.info(`AuthService: Successfully authenticated with session: ${sessionId}`); } this.authStateSource.next(newAuthState); } @@ -121,7 +124,7 @@ export class AuthService { * Will start the Github OAuth web flow process. */ startOAuthProcess() { - this.logger.info('Starting authentication'); + this.logger.info('AuthService: Starting authentication'); const githubRepoPermission = this.phaseService.githubRepoPermissionLevel(); this.changeAuthState(AuthState.AwaitingAuthentication); @@ -134,7 +137,7 @@ export class AuthService { `${AppConfig.githubUrl}/login/oauth/authorize?client_id=${AppConfig.clientId}&scope=${githubRepoPermission},read:user&state=${this.state}` ) ); - this.logger.info('Redirecting for Github authentication'); + this.logger.info('AuthService: Redirecting for Github authentication'); } } diff --git a/src/app/core/services/dialog.service.ts b/src/app/core/services/dialog.service.ts index cd0dc929b..ad26a6ef2 100644 --- a/src/app/core/services/dialog.service.ts +++ b/src/app/core/services/dialog.service.ts @@ -1,7 +1,9 @@ import { Injectable } from '@angular/core'; -import { MatDialog } from '@angular/material'; +import { FormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; import { LabelDefinitionPopupComponent } from '../../shared/label-definition-popup/label-definition-popup.component'; import { UserConfirmationComponent } from '../guards/user-confirmation/user-confirmation.component'; +import { Issue } from '../models/issue.model'; @Injectable({ providedIn: 'root' @@ -27,4 +29,20 @@ export class DialogService { } }); } + + checkIfFieldIsModified(form: FormGroup, initialField: string, formField: string, issue: Issue) { + const issueTitleInitialValue = issue[initialField] || ''; + const isModified = form.get(formField).value !== issueTitleInitialValue; + return isModified; + } + + performActionIfModified(isModified: boolean, actionIfModified: () => void, actionIfNotModified: () => void) { + if (isModified) { + // if the field has been edited, request user to confirm the cancellation + actionIfModified(); + } else { + // if no changes have been made, simply cancel edit mode without getting confirmation + actionIfNotModified(); + } + } } diff --git a/src/app/core/services/error-handling.service.ts b/src/app/core/services/error-handling.service.ts index 3c7930236..e0f87ba42 100644 --- a/src/app/core/services/error-handling.service.ts +++ b/src/app/core/services/error-handling.service.ts @@ -1,6 +1,6 @@ import { HttpErrorResponse } from '@angular/common/http'; import { ErrorHandler, Injectable } from '@angular/core'; -import { MatSnackBar } from '@angular/material'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { RequestError } from '@octokit/request-error'; import { FormErrorComponent } from '../../shared/error-toasters/form-error/form-error.component'; import { GeneralMessageErrorComponent } from '../../shared/error-toasters/general-message-error/general-message-error.component'; @@ -17,9 +17,9 @@ export class ErrorHandlingService implements ErrorHandler { constructor(private snackBar: MatSnackBar, private logger: LoggingService) {} handleError(error: HttpErrorResponse | Error | RequestError, actionCallback?: () => void) { - this.logger.error(error); + this.logger.error('ErrorHandlingService: ' + error); if (error instanceof Error) { - this.logger.debug(this.cleanStack(error.stack)); + this.logger.debug('ErrorHandlingService: ' + this.cleanStack(error.stack)); } if (error instanceof HttpErrorResponse) { this.handleHttpError(error, actionCallback); diff --git a/src/app/core/services/github.service.ts b/src/app/core/services/github.service.ts index 61268c248..76167fdf1 100644 --- a/src/app/core/services/github.service.ts +++ b/src/app/core/services/github.service.ts @@ -4,7 +4,7 @@ import { Apollo, QueryRef } from 'apollo-angular'; import { ApolloQueryResult } from 'apollo-client'; import { DocumentNode } from 'graphql'; import { forkJoin, from, Observable, of, throwError } from 'rxjs'; -import { catchError, filter, flatMap, map, throwIfEmpty } from 'rxjs/operators'; +import { catchError, filter, map, mergeMap, throwIfEmpty } from 'rxjs/operators'; import { FetchIssue, FetchIssueQuery, @@ -75,11 +75,12 @@ export class GithubService { return `Token ${accessToken}`; }, log: { - debug: (message, ...otherInfo) => this.logger.debug(message, ...otherInfo), + debug: (message, ...otherInfo) => this.logger.debug('GithubService: ' + message, ...otherInfo), // Do not log info for HTTP response 304 due to repeated polling - info: (message, ...otherInfo) => (/304 in \d+ms$/.test(message) ? undefined : this.logger.info(message, ...otherInfo)), - warn: (message, ...otherInfo) => this.logger.warn(message, ...otherInfo), - error: (message, ...otherInfo) => this.logger.error(message, ...otherInfo) + info: (message, ...otherInfo) => + /304 in \d+ms$/.test(message) ? undefined : this.logger.info('GithubService: ' + message, ...otherInfo), + warn: (message, ...otherInfo) => this.logger.warn('GithubService: ' + message, ...otherInfo), + error: (message, ...otherInfo) => this.logger.error('GithubService: ' + message, ...otherInfo) } }); } @@ -106,7 +107,7 @@ export class GithubService { const graphqlFilter = issuesFilter.convertToGraphqlFilter(); return this.toFetchIssues(issuesFilter).pipe( filter((toFetch) => toFetch), - flatMap(() => { + mergeMap(() => { return this.fetchGraphqlList( FetchIssuesByTeam, { @@ -134,7 +135,7 @@ export class GithubService { const graphqlFilter = issuesFilter.convertToGraphqlFilter(); return this.toFetchIssues(issuesFilter).pipe( filter((toFetch) => toFetch), - flatMap(() => { + mergeMap(() => { return this.fetchGraphqlList( FetchIssues, { owner: ORG_NAME, name: REPO, filter: graphqlFilter }, @@ -158,7 +159,7 @@ export class GithubService { responseInFirstPage = response; return getNumberOfPages(response); }), - flatMap((numOfPages: number) => { + mergeMap((numOfPages: number) => { const apiCalls: Observable>[] = []; for (let i = 2; i <= numOfPages; i++) { apiCalls.push(this.getIssuesAPICall(filter, i)); @@ -227,7 +228,7 @@ export class GithubService { const queryRef = this.issueQueryRefs.get(id); return this.toFetchIssue(id).pipe( filter((toFetch) => toFetch), - flatMap(() => from(queryRef.refetch())), + mergeMap(() => from(queryRef.refetch())), map((value: ApolloQueryResult) => { return new GithubGraphqlIssue(value.data.repository.issue); }), @@ -434,6 +435,7 @@ export class GithubService { } reset(): void { + this.logger.info(`GithubService: Resetting issues cache`); this.issuesCacheManager.clear(); this.issuesLastModifiedManager.clear(); this.issueQueryRefs.clear(); diff --git a/src/app/core/services/githubevent.service.ts b/src/app/core/services/githubevent.service.ts index 9cc83dc7f..c085e45bf 100644 --- a/src/app/core/services/githubevent.service.ts +++ b/src/app/core/services/githubevent.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; -import { flatMap, map } from 'rxjs/operators'; +import { map, mergeMap } from 'rxjs/operators'; import { GithubService } from './github.service'; import { IssueService } from './issue.service'; @@ -37,7 +37,7 @@ export class GithubEventService { */ reloadPage(): Observable { return this.githubService.fetchEventsForRepo().pipe( - flatMap((response: any[]) => { + mergeMap((response: any[]) => { if (response.length === 0) { return of(false); } diff --git a/src/app/core/services/issue.service.ts b/src/app/core/services/issue.service.ts index 1121c5028..26a81a15a 100644 --- a/src/app/core/services/issue.service.ts +++ b/src/app/core/services/issue.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, EMPTY, forkJoin, Observable, of, Subscription, throwError, timer } from 'rxjs'; -import { catchError, exhaustMap, finalize, flatMap, map } from 'rxjs/operators'; +import { catchError, exhaustMap, finalize, map, mergeMap } from 'rxjs/operators'; import { IssueComment } from '../models/comment.model'; import { GithubComment } from '../models/github/github-comment.model'; import RestGithubIssueFilter from '../models/github/github-issue-filter.model'; @@ -146,7 +146,7 @@ export class IssueService { return this.createIssueModel(response); }), catchError((err) => { - this.logger.error(err); // Log full details of error first + this.logger.error('IssueService: ', err); // Log full details of error first return throwError(err.response.data.message); // More readable error message }) ); @@ -154,7 +154,7 @@ export class IssueService { updateIssueWithComment(issue: Issue, issueComment: IssueComment): Observable { return this.githubService.updateIssueComment(issueComment).pipe( - flatMap((updatedComment: GithubComment) => { + mergeMap((updatedComment: GithubComment) => { issue.githubComments = [updatedComment, ...issue.githubComments.filter((c) => c.id !== updatedComment.id)]; return this.updateIssue(issue); }) @@ -192,7 +192,7 @@ export class IssueService { createTeamResponse(issue: Issue): Observable { const teamResponse = issue.createGithubTeamResponse(); return this.githubService.createIssueComment(issue.id, teamResponse).pipe( - flatMap((githubComment: GithubComment) => { + mergeMap((githubComment: GithubComment) => { issue.githubComments = [githubComment, ...issue.githubComments.filter((c) => c.id !== githubComment.id)]; return this.updateIssue(issue); }) @@ -422,8 +422,8 @@ export class IssueService { result.push(this.createLabel('type', issue.type)); } - if (issue.responseTag) { - result.push(this.createLabel('response', issue.responseTag)); + if (issue.response) { + result.push(this.createLabel('response', issue.response)); } if (issue.duplicated) { @@ -456,18 +456,29 @@ export class IssueService { } private createIssueModel(githubIssue: GithubIssue): Issue { + let issue: Issue; + switch (this.phaseService.currentPhase) { case Phase.phaseBugReporting: - return Issue.createPhaseBugReportingIssue(githubIssue); + issue = Issue.createPhaseBugReportingIssue(githubIssue); + break; case Phase.phaseTeamResponse: - return Issue.createPhaseTeamResponseIssue(githubIssue, this.dataService.getTeam(this.extractTeamIdFromGithubIssue(githubIssue))); + issue = Issue.createPhaseTeamResponseIssue(githubIssue, this.dataService.getTeam(this.extractTeamIdFromGithubIssue(githubIssue))); + break; case Phase.phaseTesterResponse: - return Issue.createPhaseTesterResponseIssue(githubIssue); + issue = Issue.createPhaseTesterResponseIssue(githubIssue); + break; case Phase.phaseModeration: - return Issue.createPhaseModerationIssue(githubIssue, this.dataService.getTeam(this.extractTeamIdFromGithubIssue(githubIssue))); + issue = Issue.createPhaseModerationIssue(githubIssue, this.dataService.getTeam(this.extractTeamIdFromGithubIssue(githubIssue))); + break; default: return; } + + if (issue.parseError) { + this.logger.error('IssueService: ' + issue.parseError); + } + return issue; } setIssueTeamFilter(filterValue: string) { diff --git a/src/app/core/services/label.service.ts b/src/app/core/services/label.service.ts index 06b7125d6..50c56fe8b 100644 --- a/src/app/core/services/label.service.ts +++ b/src/app/core/services/label.service.ts @@ -1,9 +1,10 @@ import { Injectable } from '@angular/core'; import { Observable, pipe, UnaryFunction } from 'rxjs'; -import { flatMap, map } from 'rxjs/operators'; +import { map, mergeMap } from 'rxjs/operators'; import { GithubLabel } from '../models/github/github-label.model'; import { Label } from '../models/label.model'; import { GithubService } from './github.service'; +import { LoggingService } from './logging.service'; /* The threshold to decide if color is dark or light. A higher threshold value will result in more colors determined to be "dark". @@ -147,7 +148,7 @@ export class LabelService { type: LabelService.typeLabels }; - constructor(private githubService: GithubService) {} + constructor(private githubService: GithubService, private logger: LoggingService) {} public static getRequiredLabelsAsArray(needAllLabels: boolean): Label[] { let requiredLabels: Label[] = []; @@ -175,7 +176,7 @@ export class LabelService { * with the remote repository. */ syncLabels(needAllLabels: boolean): UnaryFunction, Observable> { - return pipe(flatMap(() => this.synchronizeRemoteLabels(needAllLabels))); + return pipe(mergeMap(() => this.synchronizeRemoteLabels(needAllLabels))); } /** @@ -202,10 +203,11 @@ export class LabelService { return LabelService.severityLabels; case 'type': return LabelService.typeLabels; - case 'responseTag': + // case 'responseTag': case 'response': return LabelService.responseLabels; } + this.logger.info(`LabelService: Unfiltered Attribute ${attributeName} in getLabelList`); } /** @@ -218,9 +220,10 @@ export class LabelService { return DISPLAY_NAME_SEVERITY; case 'type': return DISPLAY_NAME_BUG_TYPE; - case 'responseTag': + case 'response': return DISPLAY_NAME_RESPONSE; } + this.logger.info(`LabelService: Unfiltered Attribute ${attributeName} in getLabelTitle`); } /** @@ -230,6 +233,8 @@ export class LabelService { */ getColorOfLabel(labelCategory: LabelCategory, labelValue: string): string { if (labelValue === '' || !LabelService.allLabelArrays[labelCategory]) { + this.logger.info(`LabelService: Unfiltered Attribute, ${labelValue}: ${labelCategory} in getColorOfLabel`); + return COLOR_WHITE; } diff --git a/src/app/core/services/mocks/mock.auth.service.ts b/src/app/core/services/mocks/mock.auth.service.ts index 4ebc2a276..b70e2b2d9 100644 --- a/src/app/core/services/mocks/mock.auth.service.ts +++ b/src/app/core/services/mocks/mock.auth.service.ts @@ -75,7 +75,7 @@ export class MockAuthService { if (newAuthState === AuthState.Authenticated) { const sessionId = `${Date.now()}-${uuid()}`; this.issueService.setSessionId(sessionId); - this.logger.info(`Successfully authenticated with session: ${sessionId}`); + this.logger.info(`MockAuthService: Successfully authenticated with session: ${sessionId}`); } this.authStateSource.next(newAuthState); } diff --git a/src/app/core/services/mocks/mock.issue.service.ts b/src/app/core/services/mocks/mock.issue.service.ts index 0b4c01ee4..09868b073 100644 --- a/src/app/core/services/mocks/mock.issue.service.ts +++ b/src/app/core/services/mocks/mock.issue.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, forkJoin, Observable, of, Subscription } from 'rxjs'; -import { catchError, flatMap, map } from 'rxjs/operators'; +import { catchError, map, mergeMap } from 'rxjs/operators'; import { generateIssueWithRandomData } from '../../../../../tests/constants/githubissue.constants'; import { IssueComment } from '../../models/comment.model'; import { GithubComment } from '../../models/github/github-comment.model'; @@ -107,7 +107,7 @@ export class MockIssueService { updateIssueWithComment(issue: Issue, issueComment: IssueComment): Observable { return this.githubService.updateIssueComment(issueComment).pipe( - flatMap((updatedComment: GithubComment) => { + mergeMap((updatedComment: GithubComment) => { issue.githubComments = [updatedComment, ...issue.githubComments.filter((c) => c.id !== updatedComment.id)]; return this.updateIssue(issue); }) @@ -145,7 +145,7 @@ export class MockIssueService { createTeamResponse(issue: Issue): Observable { const teamResponse = issue.createGithubTeamResponse(); return this.githubService.createIssueComment(issue.id, teamResponse).pipe( - flatMap((githubComment: GithubComment) => { + mergeMap((githubComment: GithubComment) => { issue.githubComments = [githubComment, ...issue.githubComments.filter((c) => c.id !== githubComment.id)]; return this.updateIssue(issue); }) @@ -299,8 +299,8 @@ export class MockIssueService { result.push(this.createLabel('type', issue.type)); } - if (issue.responseTag) { - result.push(this.createLabel('response', issue.responseTag)); + if (issue.response) { + result.push(this.createLabel('response', issue.response)); } if (issue.duplicated) { diff --git a/src/app/core/services/phase.service.ts b/src/app/core/services/phase.service.ts index a8e0b247c..ada3c9bb4 100644 --- a/src/app/core/services/phase.service.ts +++ b/src/app/core/services/phase.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { Observable, pipe } from 'rxjs'; -import { flatMap, map, retry, tap } from 'rxjs/operators'; +import { map, mergeMap, retry, tap } from 'rxjs/operators'; import { throwIfFalse } from '../../shared/lib/custom-ops'; import { Phase } from '../models/phase.model'; import { assertSessionDataIntegrity, SessionData } from '../models/session.model'; @@ -135,7 +135,7 @@ export class PhaseService { return this.fetchSessionData().pipe( assertSessionDataIntegrity(), - flatMap((sessionData: SessionData) => { + mergeMap((sessionData: SessionData) => { this.updateSessionParameters(sessionData); return this.verifySessionAvailability(sessionData); }), diff --git a/src/app/core/services/repo-creator.service.ts b/src/app/core/services/repo-creator.service.ts index 032063c6d..d484782fe 100644 --- a/src/app/core/services/repo-creator.service.ts +++ b/src/app/core/services/repo-creator.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; -import { MatDialog, MatDialogRef } from '@angular/material'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; import { Observable, of, pipe, UnaryFunction } from 'rxjs'; -import { flatMap, tap } from 'rxjs/operators'; +import { mergeMap, tap } from 'rxjs/operators'; import { Phase } from '../models/phase.model'; import { UserRole } from '../models/user.model'; import { GithubService } from './github.service'; @@ -29,7 +29,7 @@ export class RepoCreatorService { phaseRepo: string ): UnaryFunction, Observable> { return pipe( - flatMap((isRepoPresent: boolean) => { + mergeMap((isRepoPresent: boolean) => { if (!isRepoPresent && currentPhase === Phase.phaseBugReporting) { return this.openRepoCreationConfirmation(phaseRepo); } else { @@ -85,13 +85,13 @@ export class RepoCreatorService { */ public attemptRepoCreation(phaseRepo: string): UnaryFunction, Observable> { return pipe( - flatMap((repoCreationPermission: boolean | null) => { + mergeMap((repoCreationPermission: boolean | null) => { if (repoCreationPermission === null) { // No Session Fix Necessary return of(null); } else { this.githubService.createRepository(phaseRepo); - return new Observable((subscriber) => { + return new Observable((subscriber) => { setTimeout(() => subscriber.next(true), 1000); }); } @@ -106,7 +106,7 @@ export class RepoCreatorService { */ public verifyRepoCreation(phaseOwner: string, phaseRepo: string): UnaryFunction, Observable> { return pipe( - flatMap((isFixAttempted: boolean | null) => { + mergeMap((isFixAttempted: boolean | null) => { if (!isFixAttempted) { // If no fix has been attempted, there is no need to verify fix outcome. return of(true); diff --git a/src/app/core/services/session-fix-confirmation/session-fix-confirmation.component.ts b/src/app/core/services/session-fix-confirmation/session-fix-confirmation.component.ts index c659a7c6f..57057c6fd 100644 --- a/src/app/core/services/session-fix-confirmation/session-fix-confirmation.component.ts +++ b/src/app/core/services/session-fix-confirmation/session-fix-confirmation.component.ts @@ -1,5 +1,5 @@ import { Component, Inject, OnInit } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; export interface RepositoryData { user: string; diff --git a/src/app/core/services/user.service.ts b/src/app/core/services/user.service.ts index a8c66159d..7e8eddf53 100644 --- a/src/app/core/services/user.service.ts +++ b/src/app/core/services/user.service.ts @@ -6,6 +6,7 @@ import { Team } from '../models/team.model'; import { User, UserRole } from '../models/user.model'; import { DataService } from './data.service'; import { GithubService } from './github.service'; +import { LoggingService } from './logging.service'; @Injectable({ providedIn: 'root' @@ -17,7 +18,7 @@ import { GithubService } from './github.service'; export class UserService { public currentUser: User; - constructor(private githubService: GithubService, private dataService: DataService) {} + constructor(private githubService: GithubService, private dataService: DataService, private logger: LoggingService) {} /** * Get the authenticated user if it exist. @@ -42,6 +43,7 @@ export class UserService { } reset() { + this.logger.info('UserService: Clearing current user'); this.currentUser = undefined; } diff --git a/src/app/shared/action-toasters/action-toasters.module.ts b/src/app/shared/action-toasters/action-toasters.module.ts index 7cc53f6b2..a1cd51831 100644 --- a/src/app/shared/action-toasters/action-toasters.module.ts +++ b/src/app/shared/action-toasters/action-toasters.module.ts @@ -6,7 +6,6 @@ import { UndoActionComponent } from './undo-action/undo-action.component'; @NgModule({ imports: [CommonModule, MaterialModule], declarations: [UndoActionComponent], - exports: [UndoActionComponent], - entryComponents: [UndoActionComponent] + exports: [UndoActionComponent] }) export class ActionToasterModule {} diff --git a/src/app/shared/action-toasters/undo-action/undo-action.component.ts b/src/app/shared/action-toasters/undo-action/undo-action.component.ts index dbd34dc1c..418edeb05 100644 --- a/src/app/shared/action-toasters/undo-action/undo-action.component.ts +++ b/src/app/shared/action-toasters/undo-action/undo-action.component.ts @@ -1,5 +1,5 @@ import { Component, Inject } from '@angular/core'; -import { MAT_SNACK_BAR_DATA, MatSnackBarRef } from '@angular/material'; +import { MatSnackBarRef, MAT_SNACK_BAR_DATA } from '@angular/material/snack-bar'; @Component({ selector: 'app-undo-action', diff --git a/src/app/shared/comment-editor/comment-editor.component.html b/src/app/shared/comment-editor/comment-editor.component.html index b9a7e9364..7fa8cd4db 100644 --- a/src/app/shared/comment-editor/comment-editor.component.html +++ b/src/app/shared/comment-editor/comment-editor.component.html @@ -9,10 +9,12 @@ (drop)="onDrop($event)" (dragover)="enableFileDrop($event)" > +