From 08e3d38b1269501d383aee0015e31962776a7238 Mon Sep 17 00:00:00 2001 From: Yanick Minder Date: Fri, 20 Dec 2024 15:35:27 +0100 Subject: [PATCH] apply eslint squash branch update eslint config run formatter fix tests revert to single quotes regen package-lock move eslint dependendencies to devDependencies and update comment in eslint-config remove not needed parent clings fix typo in comment in scoring component tests put both statements inside if statement change asignment of args in global ts add curly to eslint config put curly into quotes update comments to clarify that they are for lint replace multiple ifs with one switch replace multiple ifs with one switch replace multiple ifs with one switch turn no-non-null-assertion off and bring back all usages of add strict equality fix eslint errors remove not needed comment add todo for error handling oauth interceptor update comments so its clear that linter needs them revert change made accidentally fix frontend unit tests revert changes made accidentally bring back all not null assertions and create some switch statements in scoring component for readability --- frontend/cypress/e2e/check-in.cy.ts | 18 +- frontend/cypress/e2e/objective-backlog.cy.ts | 16 +- frontend/cypress/e2e/objective-crud.cy.ts | 14 +- frontend/cypress/e2e/objective.cy.ts | 18 +- frontend/cypress/e2e/teammanagement.cy.ts | 6 +- frontend/cypress/support/commands.ts | 34 +- frontend/cypress/support/component.ts | 2 +- .../dom-helper/dialogs/objectiveDialog.ts | 2 +- .../support/helper/dom-helper/filterHelper.ts | 4 +- .../helper/dom-helper/pages/overviewPage.ts | 4 +- .../cypress/support/helper/scoringSupport.ts | 82 ++-- frontend/cypress/support/helper/utils.ts | 4 +- frontend/eslint.config.mjs | 112 +++-- frontend/package-lock.json | 440 ++++++++++++++++-- frontend/package.json | 2 + frontend/src/app/app.component.spec.ts | 40 +- frontend/src/app/app.component.ts | 6 +- .../action-plan/action-plan.component.spec.ts | 4 +- .../action-plan/action-plan.component.ts | 21 +- .../metric-check-in-directive.spec.ts | 2 +- .../metric-check-in-directive.ts | 13 +- .../check-in-form-ordinal.component.html | 18 +- .../check-in-form/check-in-form.component.ts | 8 +- .../confidence/confidence.component.spec.ts | 6 +- .../key-result-form.component.html | 6 +- .../key-result-form.component.ts | 27 +- .../keyresult-detail.component.html | 11 +- .../keyresult-dialog.component.ts | 21 +- .../keyresult-type.component.ts | 9 +- .../keyresult/keyresult.component.html | 2 +- .../objective-detail.component.html | 6 +- .../objective/ObjectiveMenuActions.ts | 8 +- .../overview/overview.component.html | 2 +- .../overview/overview.component.spec.ts | 29 +- .../team-filter/team-filter.component.html | 2 +- .../team-filter/team-filter.component.spec.ts | 4 - .../team-filter/team-filter.component.ts | 3 +- .../src/app/components/team/team.component.ts | 4 +- .../interceptors/error-interceptor.service.ts | 34 +- .../interceptors/error.interceptor.spec.ts | 63 ++- .../src/app/interceptors/oauth.interceptor.ts | 27 +- frontend/src/app/services/action.service.ts | 2 +- .../src/app/services/check-in.service.spec.ts | 1 - .../src/app/services/customization.service.ts | 6 +- .../src/app/services/dialog.service.spec.ts | 8 +- .../src/app/services/keyresult.service.ts | 4 +- .../objective-menu-actions.service.ts | 6 +- .../src/app/services/overview.service.spec.ts | 2 +- frontend/src/app/services/team.service.ts | 3 +- .../src/app/services/user.service.spec.ts | 10 +- frontend/src/app/services/user.service.ts | 2 +- frontend/src/app/shared/common.spec.ts | 38 +- frontend/src/app/shared/common.ts | 31 +- .../custom/scoring/scoring.component.html | 2 +- .../custom/scoring/scoring.component.spec.ts | 4 +- .../custom/scoring/scoring.component.ts | 72 +-- .../complete-dialog.component.html | 4 +- .../complete-dialog.component.ts | 7 +- .../example-dialog.component.spec.ts | 2 +- .../objective-form.component.html | 5 +- .../objective-form.component.spec.ts | 133 +++--- .../objective-form.component.ts | 60 ++- .../unit-transformation.pipe.spec.ts | 2 +- .../unit-transformation.pipe.ts | 2 +- frontend/src/app/shared/routeUtils.spec.ts | 10 +- frontend/src/app/shared/routeUtils.ts | 2 +- .../shared/sidepanel/sidepanel.component.ts | 6 +- frontend/src/app/shared/types/menu-entry.ts | 11 - .../add-edit-team-dialog.component.spec.ts | 14 +- .../add-edit-team-dialog.component.ts | 27 +- .../add-member-to-team-dialog.component.ts | 18 +- .../add-user-team.component.spec.ts | 3 - .../add-user-team/add-user-team.component.ts | 22 +- .../delete-user/delete-user.component.ts | 38 +- .../member-detail/member-detail.component.ts | 12 +- .../member-list-mobile.component.ts | 6 +- .../member-list-table.component.ts | 6 +- .../member-list/member-list.component.spec.ts | 29 +- .../member-list/member-list.component.ts | 15 +- .../search-team-management.component.ts | 7 +- .../team-list/team-list.component.spec.ts | 4 - .../team-management-banner.component.spec.ts | 4 +- .../team-management-banner.component.ts | 6 +- .../team-management/team-management.module.ts | 4 +- frontend/src/global.ts | 5 +- 85 files changed, 1127 insertions(+), 662 deletions(-) delete mode 100644 frontend/src/app/shared/types/menu-entry.ts diff --git a/frontend/cypress/e2e/check-in.cy.ts b/frontend/cypress/e2e/check-in.cy.ts index a725b088da..c53320ec5d 100644 --- a/frontend/cypress/e2e/check-in.cy.ts +++ b/frontend/cypress/e2e/check-in.cy.ts @@ -18,7 +18,7 @@ describe('OKR Check-in e2e tests', () => { cy.loginAsUser(users.gl); }); - it(`Create checkin metric`, () => { + it('Create checkin metric', () => { overviewPage .addKeyResult() .fillKeyResultTitle('Very important keyresult') @@ -40,7 +40,7 @@ describe('OKR Check-in e2e tests', () => { cy.contains('We bought a new house'); }); - it(`Create checkin metric with confidence 0`, () => { + it('Create checkin metric with confidence 0', () => { overviewPage .addKeyResult() .fillKeyResultTitle('Very important keyresult') @@ -62,7 +62,7 @@ describe('OKR Check-in e2e tests', () => { cy.contains('We bought a new house'); }); - it(`Create checkin metric with value below baseline`, () => { + it('Create checkin metric with value below baseline', () => { overviewPage .addKeyResult() .fillKeyResultTitle('This will not be good') @@ -250,7 +250,7 @@ describe('OKR Check-in e2e tests', () => { cy.contains('STRETCH'); }); - it(`Should display confirm dialog when creating checkin on draft objective`, () => { + it('Should display confirm dialog when creating checkin on draft objective', () => { overviewPage.addObjective() .fillObjectiveTitle('draft objective title') .selectQuarter('3') @@ -271,7 +271,7 @@ describe('OKR Check-in e2e tests', () => { .checkDescription('Dein Objective befindet sich noch im DRAFT Status. Möchtest du das Check-in trotzdem erfassen?'); }); - it(`Should only display last value div if last checkin is present`, () => { + it('Should only display last value div if last checkin is present', () => { const objectiveName = uniqueSuffix('new objective'); overviewPage.addObjective() @@ -312,8 +312,12 @@ function getCurrentDate() { let dd_str = '' + dd; let mm_str = '' + mm; - if (dd < 10) dd_str = '0' + dd_str; - if (mm < 10) mm_str = '0' + mm_str; + if (dd < 10) { + dd_str = '0' + dd_str; + } + if (mm < 10) { + mm_str = '0' + mm_str; + } return dd_str + '.' + mm_str + '.' + yyyy; } diff --git a/frontend/cypress/e2e/objective-backlog.cy.ts b/frontend/cypress/e2e/objective-backlog.cy.ts index f14d53ba52..8772db6b35 100644 --- a/frontend/cypress/e2e/objective-backlog.cy.ts +++ b/frontend/cypress/e2e/objective-backlog.cy.ts @@ -10,7 +10,7 @@ describe('OKR Objective Backlog e2e tests', () => { cy.loginAsUser(users.gl); }); - it(`Create Objective in backlog quarter should not have save button`, () => { + it('Create Objective in backlog quarter should not have save button', () => { overviewPage .addObjective() .fillObjectiveTitle('Objective in quarter backlog') @@ -27,7 +27,7 @@ describe('OKR Objective Backlog e2e tests', () => { cy.contains('Objective in quarter backlog'); }); - it(`Edit Objective and move to backlog`, () => { + it('Edit Objective and move to backlog', () => { overviewPage.addObjective() .fillObjectiveTitle('Move to another quarter on edit') .submitDraftObjective(); @@ -50,7 +50,7 @@ describe('OKR Objective Backlog e2e tests', () => { cy.contains('This goes now to backlog'); }); - it(`Edit ongoing Objective can not choose backlog in quarter select`, () => { + it('Edit ongoing Objective can not choose backlog in quarter select', () => { overviewPage.addObjective() .fillObjectiveTitle('We can not move this to backlog') .submit(); @@ -67,7 +67,7 @@ describe('OKR Objective Backlog e2e tests', () => { .should('not.contain', 'Backlog'); }); - it(`Can release Objective to another quarter from backlog`, () => { + it('Can release Objective to another quarter from backlog', () => { overviewPage.visitBacklogQuarter(); overviewPage.addObjective() .fillObjectiveTitle('We can not release this') @@ -105,7 +105,7 @@ describe('OKR Objective Backlog e2e tests', () => { cy.contains('This is our first released objective'); }); - it(`Can edit Objective title in backlog`, () => { + it('Can edit Objective title in backlog', () => { overviewPage.visitBacklogQuarter(); overviewPage.addObjective() .fillObjectiveTitle('This is possible for edit') @@ -124,7 +124,7 @@ describe('OKR Objective Backlog e2e tests', () => { overviewPage.getObjectiveByNameAndState('My new title', 'draft'); }); - it(`Can edit Objective in backlog and change quarter`, () => { + it('Can edit Objective in backlog and change quarter', () => { overviewPage.visitBacklogQuarter(); overviewPage.addObjective() .fillObjectiveTitle('This goes to other quarter later') @@ -144,7 +144,7 @@ describe('OKR Objective Backlog e2e tests', () => { overviewPage.getObjectiveByNameAndState('This goes to other quarter later', 'draft'); }); - it(`Can duplicate in backlog`, () => { + it('Can duplicate in backlog', () => { overviewPage.visitBacklogQuarter(); overviewPage.addObjective() .fillObjectiveTitle('Ready for duplicate in backlog') @@ -189,7 +189,7 @@ describe('OKR Objective Backlog e2e tests', () => { .should('exist'); }); - it(`Can duplicate ongoing Objective to backlog`, () => { + it('Can duplicate ongoing Objective to backlog', () => { overviewPage.addObjective() .fillObjectiveTitle('Possible to duplicate into backlog') .submit(); diff --git a/frontend/cypress/e2e/objective-crud.cy.ts b/frontend/cypress/e2e/objective-crud.cy.ts index c2af9c5754..236a8b90f7 100644 --- a/frontend/cypress/e2e/objective-crud.cy.ts +++ b/frontend/cypress/e2e/objective-crud.cy.ts @@ -18,7 +18,7 @@ describe('CRUD operations', () => { 'draft-icon.svg']].forEach(([objectiveTitle, buttonTestId, icon]) => { - it(`Create objective, no keyresults`, () => { + it('Create objective, no keyresults', () => { overviewPage.addObjective() .fillObjectiveTitle(objectiveTitle) .selectQuarter('3'); @@ -32,7 +32,7 @@ describe('CRUD operations', () => { }); }); - it(`Create objective, should display error message`, () => { + it('Create objective, should display error message', () => { overviewPage.addObjective(); cy.getByTestId('title') .first() @@ -47,7 +47,7 @@ describe('CRUD operations', () => { .should('not.be.disabled'); }); - it(`Create objective, cancel`, () => { + it('Create objective, cancel', () => { const objectiveTitle = 'this is a canceled objective'; overviewPage.addObjective() .selectQuarter('3') @@ -57,7 +57,7 @@ describe('CRUD operations', () => { .should('not.exist'); }); - it(`Delete existing objective`, () => { + it('Delete existing objective', () => { overviewPage.getFirstObjective() .findByTestId('three-dot-menu') .click(); @@ -69,7 +69,7 @@ describe('CRUD operations', () => { .submit(); }); - it(`Open objective aside via click`, () => { + it('Open objective aside via click', () => { overviewPage.getFirstObjective() .find('.title') .click(); @@ -77,7 +77,7 @@ describe('CRUD operations', () => { .should('include', 'objective'); }); - it(`update objective`, () => { + it('update objective', () => { const updatedTitle = 'This is an updated title'; overviewPage.getFirstObjective() .findByTestId('three-dot-menu') @@ -90,7 +90,7 @@ describe('CRUD operations', () => { .should('exist'); }); - it(`Duplicate objective`, () => { + it('Duplicate objective', () => { const duplicatedTitle = 'This is a duplicated objective'; overviewPage.getFirstObjective() .findByTestId('three-dot-menu') diff --git a/frontend/cypress/e2e/objective.cy.ts b/frontend/cypress/e2e/objective.cy.ts index b7dec8295e..1ac6b70e5d 100644 --- a/frontend/cypress/e2e/objective.cy.ts +++ b/frontend/cypress/e2e/objective.cy.ts @@ -11,7 +11,7 @@ describe('OKR Objective e2e tests', () => { }); describe('tests via click', () => { - it(`Release Objective from Draft to Ongoing`, () => { + it('Release Objective from Draft to Ongoing', () => { overviewPage.addObjective() .fillObjectiveTitle('A objective in state draft') .submitDraftObjective(); @@ -31,7 +31,7 @@ describe('OKR Objective e2e tests', () => { .should('exist'); }); - it(`Complete Objective with Successful`, () => { + it('Complete Objective with Successful', () => { overviewPage.addObjective() .fillObjectiveTitle('We want to complete this successful') .submit(); @@ -58,7 +58,7 @@ describe('OKR Objective e2e tests', () => { overviewPage.getObjectiveByNameAndState('We want to complete this successful', 'successful'); }); - it(`Complete Objective with Not-Successful`, () => { + it('Complete Objective with Not-Successful', () => { overviewPage.addObjective() .fillObjectiveTitle('A not successful objective') .submit(); @@ -84,7 +84,7 @@ describe('OKR Objective e2e tests', () => { overviewPage.getObjectiveByNameAndState('A not successful objective', 'not-successful'); }); - it(`Reopen Successful Objective`, () => { + it('Reopen Successful Objective', () => { overviewPage.addObjective() .fillObjectiveTitle('This objective will be reopened after') .submit(); @@ -119,7 +119,7 @@ describe('OKR Objective e2e tests', () => { .should('exist'); }); - it(`Cancel Reopen Successful Objective`, () => { + it('Cancel Reopen Successful Objective', () => { overviewPage.addObjective() .fillObjectiveTitle('The reopening of this objective will be canceled') .submit(); @@ -198,7 +198,7 @@ describe('OKR Objective e2e tests', () => { .should('exist'); }); - it(`Search for Objective`, () => { + it('Search for Objective', () => { overviewPage.addObjective() .fillObjectiveTitle('Search after this objective') .submit(); @@ -258,7 +258,7 @@ describe('OKR Objective e2e tests', () => { .should('not.exist'); }); - it(`Create Objective in other quarter`, () => { + it('Create Objective in other quarter', () => { overviewPage.addObjective() .fillObjectiveTitle('Objective in quarter 3') .selectQuarter('3') @@ -272,7 +272,7 @@ describe('OKR Objective e2e tests', () => { cy.contains('Objective in quarter 3'); }); - it(`Edit Objective and move to other quarter`, () => { + it('Edit Objective and move to other quarter', () => { overviewPage.addObjective() .fillObjectiveTitle('Move to another quarter on edit') .submit(); @@ -296,7 +296,7 @@ describe('OKR Objective e2e tests', () => { }); describe('tests via keyboard', () => { - it(`Open objective aside via enter`, () => { + it('Open objective aside via enter', () => { cy.getByTestId('objective') .first() .find('[tabindex]') diff --git a/frontend/cypress/e2e/teammanagement.cy.ts b/frontend/cypress/e2e/teammanagement.cy.ts index 07432f14fc..f9ca5bfbef 100644 --- a/frontend/cypress/e2e/teammanagement.cy.ts +++ b/frontend/cypress/e2e/teammanagement.cy.ts @@ -304,7 +304,7 @@ describe('Team management tests', () => { return true; }) .then(() => { - expect(foundEsha).to.be.true; + expect(foundEsha).to.equal(true); }); }); @@ -461,7 +461,7 @@ describe('Team management tests', () => { .trim() !== 'Findus Peterson') { return; } - $row.find(`[data-testId='edit-role']`) + $row.find('[data-testId=\'edit-role\']') .click(); cy.wait(500); // wait for dialog to open }) @@ -495,7 +495,7 @@ describe('Team management tests', () => { ConfirmDialog.do() .checkTitle('Mitglied entfernen') - .checkDescription(`Möchtest du Findus Peterson wirklich aus dem Team '/BBT' entfernen?`) + .checkDescription('Möchtest du Findus Peterson wirklich aus dem Team \'/BBT\' entfernen?') .submit(); cy.get('app-member-detail') diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index 44e1c93e5a..825531899a 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -1,6 +1,6 @@ import { validateScoring } from './helper/scoringSupport'; import { keyCodeDefinitions } from 'cypress-real-events/keyCodeDefinitions'; -import { pressUntilContains, doUntilSelector } from './helper/utils'; +import { doUntilSelector, pressUntilContains } from './helper/utils'; import Chainable = Cypress.Chainable; Cypress.Commands.add('loginAsUser', (user: any) => { @@ -19,19 +19,17 @@ Cypress.Commands.add('getByTestId', (testId: string, text?: string): Chainable = } }); -Cypress.Commands.add('findByTestId', - { prevSubject: true }, - (subject: JQuery, testId: string, text?: string): Chainable => { - const selector = `[data-testId=${testId}]`; - if (text) { - return cy.wrap(subject) - .find(selector) - .contains(text); - } else { - return cy.wrap(subject) - .find(selector); - } - }); +Cypress.Commands.add('findByTestId', { prevSubject: true }, (subject: JQuery, testId: string, text?: string): Chainable => { + const selector = `[data-testId=${testId}]`; + if (text) { + return cy.wrap(subject) + .find(selector) + .contains(text); + } else { + return cy.wrap(subject) + .find(selector); + } +}); Cypress.Commands.add('pressUntilContains', (text: string, key: keyof typeof keyCodeDefinitions) => { pressUntilContains(text, key); @@ -66,8 +64,12 @@ function loginWithCredentials(username: string, password: string) { cy.visit('/'); cy.intercept('GET', '**/users/current') .as('getCurrentUser'); - cy.origin(Cypress.env('login_url'), { args: { username, - password } }, ({ username, password }) => { + cy.origin(Cypress.env('login_url'), { + args: { + username, + password + } + }, ({ username, password }) => { cy.get('input[name="username"]') .type(username); cy.get('input[name="password"]') diff --git a/frontend/cypress/support/component.ts b/frontend/cypress/support/component.ts index 2733f4b08b..3d45dba0b0 100644 --- a/frontend/cypress/support/component.ts +++ b/frontend/cypress/support/component.ts @@ -2,7 +2,7 @@ import './commands'; import { keyCodeDefinitions } from 'cypress-real-events/keyCodeDefinitions'; declare global { - namespace Cypress { + export namespace Cypress { interface Chainable { loginAsUser(user: any): Chainable; getByTestId(testsId: string, text?: string): Chainable; diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts index 4957e72663..6252040b00 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts @@ -21,7 +21,7 @@ export default class ObjectiveDialog extends Dialog { toggleCreateKeyResults() { cy.getByTestId('keyResult-checkbox') - .find("[type='checkbox']") + .find('[type=\'checkbox\']') .check(); return this; } diff --git a/frontend/cypress/support/helper/dom-helper/filterHelper.ts b/frontend/cypress/support/helper/dom-helper/filterHelper.ts index 36bb077a4a..577a4627f7 100644 --- a/frontend/cypress/support/helper/dom-helper/filterHelper.ts +++ b/frontend/cypress/support/helper/dom-helper/filterHelper.ts @@ -1,7 +1,9 @@ import { PageObjectMapperBase } from './pageObjectMapperBase'; export default class FilterHelper extends PageObjectMapperBase { - validatePage(): void {} + validatePage(): void { + // Does not need to be implemented this comment is for making linter happy + } optionShouldBeSelected(text: string, onOverview = true): this { if (onOverview) { diff --git a/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts b/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts index 7e302c890b..3ca643b988 100644 --- a/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts +++ b/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts @@ -196,7 +196,9 @@ export default class CyOverviewPage extends Page { return ''; } - validatePage(): void {} + validatePage(): void { + // Does not need to be implemented this comment is for making linter happy + } protected doVisit(): void { this.elements.logo() diff --git a/frontend/cypress/support/helper/scoringSupport.ts b/frontend/cypress/support/helper/scoringSupport.ts index ccb55625de..cfa2c75aca 100644 --- a/frontend/cypress/support/helper/scoringSupport.ts +++ b/frontend/cypress/support/helper/scoringSupport.ts @@ -20,7 +20,9 @@ export function validateScoring(isOverview: boolean, percentage: number) { validateScoringWidth('commit', scoringValue.commitPercent, isOverview); validateScoringWidth('target', scoringValue.targetPercent, isOverview); - if (percentage == 0) return; + if (percentage == 0) { + return; + } validateScoringColor('fail', rgbCode, isOverview); validateScoringColor('commit', rgbCode, isOverview); validateScoringColor('target', rgbCode, isOverview); @@ -30,15 +32,22 @@ export function getPercentageMetric(baseline: number, stretchGoal: number, value if (isLastCheckInNegative(baseline, stretchGoal, value)) { return -1; } - return (Math.abs(value - baseline) / Math.abs(stretchGoal - baseline)) * 100; + return Math.abs(value - baseline) / Math.abs(stretchGoal - baseline) * 100; } export function getPercentageOrdinal(zone: string) { - if (zone == 'stretch') return 101; - if (zone == 'target') return 99.99; - if (zone == 'commit') return 70; - if (zone == 'fail') return 30; - return 0; + switch (zone) { + case 'fail': + return 30; + case 'commit': + return 70; + case 'target': + return 99.99; + case 'stretch': + return 101; + default: + return 0; + } } function validateScoringWidth(zone: string, percent: number, isOverview: boolean) { @@ -46,7 +55,7 @@ function validateScoringWidth(zone: string, percent: number, isOverview: boolean .parent() .invoke('width') .then((parentWidth) => { - expect(parentWidth).not.to.be.undefined; + expect(parentWidth).not.to.equal(undefined); cy.getZone(zone, isOverview) .invoke('width') .should('be.within', parentWidth! * (percent / 100) - 3, parentWidth! * (percent / 100) + 3); @@ -77,30 +86,43 @@ function checkVisibilityOfScoringComponent(isOverview: boolean, displayProperty: } function colorFromPercentage(percentage: number) { - if (percentage >= 100) return 'rgba(0, 0, 0, 0)'; - if (percentage > 70) return 'rgb(30, 138, 41)'; - if (percentage > 30) return 'rgb(255, 214, 0)'; - return 'rgb(186, 56, 56)'; + switch (true) { + case percentage >= 100: + return 'rgba(0, 0, 0, 0)'; + case percentage > 70: + return 'rgb(30, 138, 41)'; + case percentage > 30: + return 'rgb(255, 214, 0)'; + default: + return 'rgb(186, 56, 56)'; + } } function scoringValueFromPercentage(percentage: number): ScoringValue { - if (percentage >= 100) { - return { failPercent: 0, - commitPercent: 0, - targetPercent: 0 }; - } else if (percentage > 70) { - const targetPercent = (percentage - 70) * (100 / 30); - return { failPercent: 100, - commitPercent: 100, - targetPercent: targetPercent }; - } else if (percentage > 30) { - const commitPercent = (percentage - 30) * (100 / 40); - return { failPercent: 100, - commitPercent: commitPercent, - targetPercent: -1 }; + switch (true) { + case percentage >= 100: + return { + failPercent: 0, + commitPercent: 0, + targetPercent: 0 + }; + case percentage > 70: + return { + failPercent: 100, + commitPercent: 100, + targetPercent: (percentage - 70) * (100 / 30) + }; + case percentage > 30: + return { + failPercent: 100, + commitPercent: (percentage - 30) * (100 / 40), + targetPercent: -1 + }; + default: + return { + failPercent: percentage * (100 / 30), + commitPercent: -1, + targetPercent: -1 + }; } - const failPercent = percentage * (100 / 30); - return { failPercent: failPercent, - commitPercent: -1, - targetPercent: -1 }; } diff --git a/frontend/cypress/support/helper/utils.ts b/frontend/cypress/support/helper/utils.ts index 454ba2433c..3600ff1b54 100644 --- a/frontend/cypress/support/helper/utils.ts +++ b/frontend/cypress/support/helper/utils.ts @@ -30,7 +30,9 @@ function doUntil( limit = 100, count = 0 ) { - if (count >= limit) return; + if (count >= limit) { + return; + } cy.focused() .then((element) => { diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs index 3b2afd4e25..bc3c1546ad 100644 --- a/frontend/eslint.config.mjs +++ b/frontend/eslint.config.mjs @@ -7,6 +7,9 @@ import angular from 'angular-eslint' import htmlParser from '@html-eslint/parser' export default tsEslint.config( + { + ignores: ['cypress/downloads/**/*'], + }, { files: ['**/*.ts'], extends: [ @@ -16,35 +19,83 @@ export default tsEslint.config( ...angular.configs.tsRecommended, ], processor: angular.processInlineTemplates, + languageOptions: { + globals: { + //Cypress things not recognized by eslint + cy: 'readonly', + Cypress: 'readonly', + it: 'readonly', + describe: 'readonly', + expect: 'readonly', + beforeEach: 'readonly', + before: 'readonly', + //Dom things not recognized by eslint + localStorage: 'readonly', + console: 'readonly', + window: 'readonly', + document: 'readonly', + //Event not recognized by eslint + MouseEvent: 'readonly', + KeyboardEvent: 'readonly', + Event: 'readonly', + //HTML Elements not recognized by eslint + HTMLDivElement: 'readonly', + HTMLInputElement: 'readonly', + HTMLSpanElement: 'readonly', + HTMLElement: 'readonly', + HTMLTitleElement: 'readonly', + HTMLHtmlElement: 'readonly', + //Others not recognized by eslint + ResizeObserver: 'readonly', + ResizeObserverEntry: 'readonly', + setTimeout: 'readonly', + JQuery: 'readonly', + Document: 'readonly', + URL: 'readonly', + }, + }, rules: { ...stylistic.configs['all-flat'].rules, + //eslint rules 'unused-imports/no-unused-imports': 'error', + 'no-undef': 'error', + curly: 'error', + 'prefer-rest-params': 'error', + 'space-before-function-paren': ['error', 'never'], - // ToDo: Disable rules so eslint passes, fix in followup ticket - '@typescript-eslint/no-unused-vars': 'off', - '@typescript-eslint/no-unused-expressions': 'off', - '@typescript-eslint/ban-ts-comment': 'off', - 'no-undef': 'off', + //Typescript eslint rules + '@typescript-eslint/ban-ts-comment': 'error', + '@typescript-eslint/no-unused-expressions': [ + 'error', + { + allowTernary: true, + }, + ], + + '@typescript-eslint/no-unused-vars': [ + 'error', + { + args: 'none', + }, + ], '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-namespace': 'off', - 'prefer-rest-params': 'off', - '@typescript-eslint/no-empty-function': ['off'], - '@stylistic/lines-around-comment': ['off'], - '@angular-eslint/no-empty-lifecycle-method': 'off', - '@angular-eslint/component-class-suffix': 'off', - '@angular-eslint/template/eqeqeq': 'off', - '@angular-eslint/template/interactive-supports-focus': 'off', - '@typescript-eslint/no-non-null-asserted-optional-chain': 'off', + '@typescript-eslint/no-namespace': [ + 'error', + { + allowDeclarations: true, + }, + ], + '@typescript-eslint/no-empty-function': ['error', { allow: ['arrowFunctions', 'constructors'] }], + //Turned off to allow ! in the code '@typescript-eslint/no-non-null-assertion': 'off', - '@stylistic/no-extra-parens': 'off', - '@typescript-eslint/no-confusing-non-null-assertion': 'off', - //Delete these rules after fixing all the issues and enabling the actual rules - '@stylistic/quotes': 'off', - '@stylistic/function-call-argument-newline': 'off', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'off', - //Actual formatting rules - // '@stylistic/function-call-argument-newline': ['error', 'never'], - // '@stylistic/quotes': ['error', 'double'], + '@typescript-eslint/no-confusing-non-null-assertion': 'error', + + //Stylistic eslint rules + '@stylistic/no-extra-parens': 'error', + '@stylistic/function-call-argument-newline': ['error', 'never'], + '@stylistic/quotes': ['error', 'single'], '@stylistic/padded-blocks': ['error', 'never'], '@stylistic/dot-location': ['error', 'property'], '@stylistic/newline-per-chained-call': ['error', { ignoreChainWithDepth: 1 }], @@ -55,10 +106,13 @@ export default tsEslint.config( '@stylistic/object-curly-spacing': ['error', 'always'], '@stylistic/array-bracket-newline': ['error', { minItems: 4 }], '@stylistic/semi-style': ['error'], - 'space-before-function-paren': ['error', 'never'], '@stylistic/function-paren-newline': ['error', { minItems: 4 }], '@stylistic/space-before-function-paren': ['error', 'never'], - + // Disabled because it's an unnecessary rule in our case + '@stylistic/lines-around-comment': 'off', + //Angular eslint rules + '@angular-eslint/no-empty-lifecycle-method': 'error', + '@angular-eslint/component-class-suffix': 'error', '@angular-eslint/directive-selector': [ 'error', { @@ -80,10 +134,14 @@ export default tsEslint.config( }, { files: ['**/*.spec.ts'], + extends: [...tsEslint.configs.recommended], rules: { + //Rules removed for Test files because they are unnecessary for tests '@typescript-eslint/no-explicit-any': 'off', 'prefer-rest-params': 'off', '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', }, }, @@ -96,11 +154,13 @@ export default tsEslint.config( }, rules: { ...html.configs['flat/recommended'].rules, + //Html eslint rules // Must be defined. If not, all recommended rules will be lost - '@html-eslint/indent': ['error', 2], '@html-eslint/require-img-alt': 'off', - '@html-eslint/element-newline': 'off', + '@html-eslint/indent': ['error', 2], '@html-eslint/require-closing-tags': ['error', { selfClosing: 'always' }], + //Doesn't work with Angular 17+ + '@html-eslint/element-newline': 'off', }, }, { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 26f879b242..db4c09294e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -30,6 +30,7 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^18.2.9", + "@angular-eslint/eslint-plugin-template": "^19.0.2", "@angular/cli": "~18.2.9", "@angular/compiler-cli": "^18.2.8", "@cypress/schematic": "^2.5.2", @@ -47,6 +48,7 @@ "cypress": "^13.15.0", "cypress-real-events": "^1.13.0", "eslint": "^9.16.0", + "eslint-plugin-i18n-json": "^4.0.0", "eslint-plugin-unused-imports": "^4.1.4", "jest": "^29.7.0", "jest-preset-angular": "^14.2.4", @@ -3620,6 +3622,62 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.1.tgz", + "integrity": "sha512-Ip9uV+/MpLXWRk03U/GzeJMuPeOXpJBSB5V1tjA6kJhvqssye5J5LoYLc7Z5IAHb7nR62sRoguzrFiVCP/hnzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "2.2.5", + "@formatjs/intl-localematcher": "0.5.9", + "decimal.js": "10", + "tslib": "2" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.5.tgz", + "integrity": "sha512-6PoewUMrrcqxSoBXAOJDiW1m+AmkrAj0RiXnOMD59GRaswjXhm3MDhgepXPBgonc09oSirAJTsAggzAGQf6A6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "2" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.9.7", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.9.7.tgz", + "integrity": "sha512-cuEHyRM5VqLQobANOjtjlgU7+qmk9Q3fDQuBiRRJ3+Wp3ZoZhpUPtUfuimZXsir6SaI2TaAJ+SLo9vLnV5QcbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.1", + "@formatjs/icu-skeleton-parser": "1.8.11", + "tslib": "2" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.11.tgz", + "integrity": "sha512-8LlHHE/yL/zVJZHAX3pbKaCjZKmBIO6aJY1mkVh4RMSEu/2WRZ4Ysvv3kKXJ9M8RJLBHdnk1/dUQFdod1Dt7Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.1", + "tslib": "2" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.9.tgz", + "integrity": "sha512-8zkGu/sv5euxbjfZ/xmklqLyDGQSxsLqg8XOq88JW3cmJtzhCP8EtSJXlaKZnVO4beEaoiT9wj4eIoCQ9smwxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "2" + } + }, "node_modules/@html-eslint/eslint-plugin": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.27.0.tgz", @@ -3808,9 +3866,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.8.tgz", - "integrity": "sha512-tKd+jsmhq21AP1LhexC0pPwsCxEhGgAkg28byjJAd+xhmIs8LUX8JbUc3vBf3PhLxWiB5EvyBE5X7JSPAqMAqg==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.9.tgz", + "integrity": "sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==", "dev": true, "license": "MIT", "engines": { @@ -6577,6 +6635,16 @@ "node": ">=8" } }, + "node_modules/aggregate-error/node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ajv": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", @@ -8947,6 +9015,16 @@ "dev": true, "license": "MIT" }, + "node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -9107,9 +9185,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.74", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.74.tgz", - "integrity": "sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw==", + "version": "1.5.75", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.75.tgz", + "integrity": "sha512-Lf3++DumRE/QmweGjU+ZcKqQ+3bKkU/qjaKYhIJKEOhgIO9Xs6IiAQFkfFoj+RhgDk4LUeNsLo6plExHqSyu6Q==", "dev": true, "license": "ISC" }, @@ -9189,9 +9267,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz", + "integrity": "sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9506,6 +9584,142 @@ } } }, + "node_modules/eslint-plugin-i18n-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-i18n-json/-/eslint-plugin-i18n-json-4.0.1.tgz", + "integrity": "sha512-LNQS2XeEy1fdCOn/n3Aeh7RWPVbwKL0tH4Q1c2Y/M1TN6Jo3uN6C3cTvtjzJEms7ul0rmCAPoGqM4IsVCOIxnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@formatjs/icu-messageformat-parser": "^2.0.18", + "chalk": "^2.3.2", + "indent-string": "^3.2.0", + "jest-diff": "^22.0.3", + "lodash": "^4.17.21", + "log-symbols": "^2.2.0", + "parse-json": "^5.2.0", + "plur": "^2.1.2", + "pretty-format": "^22.0.3" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=4.0.0" + } + }, + "node_modules/eslint-plugin-i18n-json/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-i18n-json/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-i18n-json/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-i18n-json/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/eslint-plugin-i18n-json/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-i18n-json/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-plugin-i18n-json/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-i18n-json/node_modules/log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-i18n-json/node_modules/pretty-format": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.4.3.tgz", + "integrity": "sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + } + }, + "node_modules/eslint-plugin-i18n-json/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/eslint-plugin-unused-imports": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz", @@ -11146,13 +11360,13 @@ } }, "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/inflight": { @@ -11208,6 +11422,16 @@ "node": ">= 10" } }, + "node_modules/irregular-plurals": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.4.0.tgz", + "integrity": "sha512-kniTIJmaZYiwa17eTtWIfm0K342seyugl6vuC8DiiyiRAJWAVlLkqGCI0Im0neo0TkXw+pRcKaBPRdcKHnQJ6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -11229,9 +11453,9 @@ } }, "node_modules/is-core-module": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.0.tgz", - "integrity": "sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { @@ -11894,19 +12118,122 @@ } }, "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-22.4.3.tgz", + "integrity": "sha512-/QqGvCDP5oZOF6PebDuLwrB2BMD8ffJv6TAGAdEVuDx1+uEgrHpSFrfrOiMRx2eJ1hgNjlQrOQEHetVwij90KA==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "chalk": "^2.0.1", + "diff": "^3.2.0", + "jest-get-type": "^22.4.3", + "pretty-format": "^22.4.3" + } + }, + "node_modules/jest-diff/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=4" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-diff/node_modules/jest-get-type": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", + "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "22.4.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.4.3.tgz", + "integrity": "sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, "node_modules/jest-docblock": { @@ -12051,6 +12378,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-matcher-utils/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-message-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", @@ -12328,6 +12671,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", @@ -13448,9 +13807,9 @@ } }, "node_modules/memfs": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.15.0.tgz", - "integrity": "sha512-q9MmZXd2rRWHS6GU3WEm3HyiXZyyoA1DqdOhEq0lxPBmKb5S7IAOwX0RgUCwJfqjelDCySa5h8ujOy24LqsWcw==", + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.15.1.tgz", + "integrity": "sha512-ufCzgFwiVnR6R9cCYuvwznJdhdYXEvFl0hpnM4cCtVaVkHuqBR+6fo2sqt1SSMdp+uiHw9GyPZr3OMM5tqjSmQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -14987,6 +15346,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/plur": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", + "integrity": "sha512-WhcHk576xg9y/iv6RWOuroZgsqvCbJN+XGvAypCJwLAYs2iWDp5LUmvaCdV6JR2O0SMBf8l6p7A94AyLCFVMlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "irregular-plurals": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/postcss": { "version": "8.4.41", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", @@ -17170,22 +17542,22 @@ "license": "MIT" }, "node_modules/tldts": { - "version": "6.1.68", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.68.tgz", - "integrity": "sha512-JKF17jROiYkjJPT73hUTEiTp2OBCf+kAlB+1novk8i6Q6dWjHsgEjw9VLiipV4KTJavazXhY1QUXyQFSem2T7w==", + "version": "6.1.69", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.69.tgz", + "integrity": "sha512-Oh/CqRQ1NXNY7cy9NkTPUauOWiTro0jEYZTioGbOmcQh6EC45oribyIMJp0OJO3677r13tO6SKdWoGZUx2BDFw==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^6.1.68" + "tldts-core": "^6.1.69" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.68", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.68.tgz", - "integrity": "sha512-85TdlS/DLW/gVdf2oyyzqp3ocS30WxjaL4la85EArl9cHUR/nizifKAJPziWewSZjDZS71U517/i6ciUeqtB5Q==", + "version": "6.1.69", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.69.tgz", + "integrity": "sha512-nygxy9n2PBUFQUtAXAc122gGo+04/j5qr5TGQFZTHafTKYvmARVXt2cA5rgero2/dnXUfkdPtiJoKmrd3T+wdA==", "dev": true, "license": "MIT" }, diff --git a/frontend/package.json b/frontend/package.json index 3e183315ea..fb2e149a98 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -53,6 +53,8 @@ "@angular/compiler-cli": "^18.2.8", "@cypress/schematic": "^2.5.2", "@cypress/skip-test": "^2.6.1", + "eslint-plugin-i18n-json": "^4.0.0", + "@angular-eslint/eslint-plugin-template": "^19.0.2", "@stylistic/eslint-plugin": "^2.11.0", "@typescript-eslint/eslint-plugin": "^8.15.0", "@eslint/js": "^9.15.0", diff --git a/frontend/src/app/app.component.spec.ts b/frontend/src/app/app.component.spec.ts index 3d1bda7afb..1560f812d3 100644 --- a/frontend/src/app/app.component.spec.ts +++ b/frontend/src/app/app.component.spec.ts @@ -3,51 +3,32 @@ import { RouterTestingModule } from '@angular/router/testing'; import { AppComponent } from './app.component'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { TranslateTestingModule } from 'ngx-translate-testing'; -import { AuthConfig, OAuthModule, OAuthService } from 'angular-oauth2-oidc'; +import { OAuthModule, OAuthService } from 'angular-oauth2-oidc'; import { HttpClientTestingModule } from '@angular/common/http/testing'; // @ts-ignore import * as de from '../assets/i18n/de.json'; -import { HarnessLoader } from '@angular/cdk/testing'; -import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { MatSidenavModule } from '@angular/material/sidenav'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { NavigationEnd, Routes } from '@angular/router'; -import { of } from 'rxjs'; +import { Routes } from '@angular/router'; import { OverviewComponent } from './components/overview/overview.component'; import { ObjectiveDetailComponent } from './components/objective-detail/objective-detail.component'; import { CommonModule } from '@angular/common'; -const oauthServiceMock = { - configure(environment: AuthConfig): void {}, - initCodeFlow(): void {}, - setupAutomaticSilentRefresh(): void {}, - hasValidAccessToken(): boolean { - return true; - }, - loadDiscoveryDocumentAndTryLogin(): Promise { - this.initCodeFlow(); - return Promise.resolve(); - } -}; - -const routerMock = { - root: jest.fn(), - // Router - events: of(new NavigationEnd(0, 'http://localhost:4200/objective/2', 'http://localhost:4200/objective/2')) -}; +const oauthServiceMock = {}; const routes: Routes = [{ path: '', component: OverviewComponent, - children: [{ path: 'objective/:id', + children: [{ + path: 'objective/:id', component: ObjectiveDetailComponent, - pathMatch: 'full' }] + pathMatch: 'full' + }] }]; describe('AppComponent', () => { let component: AppComponent; let fixture: ComponentFixture; - let loader: HarnessLoader; beforeEach(async() => { await TestBed.configureTestingModule({ @@ -62,8 +43,10 @@ describe('AppComponent', () => { NoopAnimationsModule, CommonModule ], - providers: [{ provide: OAuthService, - useValue: oauthServiceMock }], + providers: [{ + provide: OAuthService, + useValue: oauthServiceMock + }], declarations: [AppComponent, OverviewComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA] @@ -74,7 +57,6 @@ describe('AppComponent', () => { component = fixture.componentInstance; fixture.detectChanges(); - loader = TestbedHarnessEnvironment.loader(fixture); fixture.detectChanges(); }); }); diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index 8b2861a876..33a11643d9 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -13,9 +13,7 @@ export class AppComponent { constructor(private matIconRegistry: MatIconRegistry, private domSanitizer: DomSanitizer) { - this.matIconRegistry.addSvgIcon('pz-search', - this.domSanitizer.bypassSecurityTrustResourceUrl(this.PATH_PREFIX + 'search-icon.svg')); - this.matIconRegistry.addSvgIcon('pz-menu-icon', - this.domSanitizer.bypassSecurityTrustResourceUrl(this.PATH_PREFIX + 'three-dot-menu-icon.svg')); + this.matIconRegistry.addSvgIcon('pz-search', this.domSanitizer.bypassSecurityTrustResourceUrl(this.PATH_PREFIX + 'search-icon.svg')); + this.matIconRegistry.addSvgIcon('pz-menu-icon', this.domSanitizer.bypassSecurityTrustResourceUrl(this.PATH_PREFIX + 'three-dot-menu-icon.svg')); } } diff --git a/frontend/src/app/components/action-plan/action-plan.component.spec.ts b/frontend/src/app/components/action-plan/action-plan.component.spec.ts index 5259e2c93e..7d733991ac 100644 --- a/frontend/src/app/components/action-plan/action-plan.component.spec.ts +++ b/frontend/src/app/components/action-plan/action-plan.component.spec.ts @@ -116,7 +116,7 @@ describe('ActionPlanComponent', () => { action3]); component.handleKeyDown(keyEvent, 2); - expect((component.activeItem = 1)); + expect(component.activeItem = 1); expect(component.control.getValue()!.toString()) .toBe([action1, action3, @@ -136,7 +136,7 @@ describe('ActionPlanComponent', () => { ]); component.handleKeyDown(keyEvent, 2); - expect((component.activeItem = 3)); + expect(component.activeItem = 3); expect(component.control.getValue()!.toString()) .toBe([ action1, diff --git a/frontend/src/app/components/action-plan/action-plan.component.ts b/frontend/src/app/components/action-plan/action-plan.component.ts index 623055e1d8..674ddcf58d 100644 --- a/frontend/src/app/components/action-plan/action-plan.component.ts +++ b/frontend/src/app/components/action-plan/action-plan.component.ts @@ -22,7 +22,8 @@ export class ActionPlanComponent { listItems!: QueryList; constructor(private actionService: ActionService, - public dialogService: DialogService) {} + public dialogService: DialogService) { + } handleKeyDown(event: Event, currentIndex: number) { let newIndex = currentIndex; @@ -44,18 +45,18 @@ export class ActionPlanComponent { const currentActionPlan: Action[] = this.control.getValue()!; this.updateActionTexts(currentActionPlan); moveItemInArray(currentActionPlan, currentIndex, newIndex); - currentActionPlan.forEach((action: Action, index: number) => (action.priority = index)); + currentActionPlan.forEach((action: Action, index: number) => action.priority = index); this.control.next(currentActionPlan); } updateActionTexts(currentActionPlan: Action[]) { const texts = Array.from(this.listItems) .map((input: any) => input.nativeElement.value); - currentActionPlan.forEach((action: Action, index: number) => (action.action = texts[index])); + currentActionPlan.forEach((action: Action, index: number) => action.action = texts[index]); } increaseActiveItemWithTab() { - if (this.activeItem <= this.control.value!.length - 2) { + if (this.activeItem <= this.control.getValue()!.length - 2) { this.activeItem++; } } @@ -70,8 +71,10 @@ export class ActionPlanComponent { const value: string = (event.container.element.nativeElement.children[event.previousIndex].children[1] as HTMLInputElement).value; const actions: Action[] = this.control.getValue()!; if (actions[event.previousIndex].action == '' && value != '') { - actions[event.previousIndex] = { ...actions[event.previousIndex], - action: value }; + actions[event.previousIndex] = { + ...actions[event.previousIndex], + action: value + }; this.control.next(actions); } if (event.previousContainer === event.container) { @@ -122,9 +125,11 @@ export class ActionPlanComponent { addNewAction() { const actions: Action[] = this.control.getValue()!; - actions.push({ action: '', + actions.push({ + action: '', priority: actions.length, - keyResultId: this.keyResultId } as Action); + keyResultId: this.keyResultId + } as Action); this.control.next(actions); this.activeItem = actions.length - 1; } diff --git a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts index 8498b4133d..36b0cb5d76 100644 --- a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts +++ b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts @@ -12,7 +12,7 @@ describe('MetricCheckInDirective', () => { 200], ['200HelloWorld', 200], - ["200'000", + ['200\'000', 200000], ['1050&%ç*', 1050], diff --git a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts index 98f4638545..55375f93c5 100644 --- a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts +++ b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts @@ -1,4 +1,4 @@ -import { Directive, HostListener, forwardRef } from '@angular/core'; +import { Directive, forwardRef, HostListener } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Directive({ @@ -10,20 +10,21 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; }] }) export class MetricCheckInDirective implements ControlValueAccessor { - private onChange: (value: number | null) => void = () => {}; + private onChange: (value: number | null) => void = () => { + }; protected readonly CHAR_REGEX = /[^0-9.]/g; - writeValue(value: any): void { - // does not need to be implemented because the display value does not need to be modified + writeValue(): void { + // does not need to be implemented because the display value does not need to be modified comment is here to make linter happy } registerOnChange(fn: (value: number | null) => void): void { this.onChange = fn; } - registerOnTouched(fn: () => void): void { - // does not need to be implemented + registerOnTouched(): void { + // does not need to be implemented comment is here to make linter happy } @HostListener('input', ['$event.target.value']) diff --git a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html index a15793ca9b..99eec7cbc4 100644 --- a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html +++ b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html @@ -12,7 +12,8 @@ class="ordinal-zone" >
- Fail:  Commit / Target / Stretch noch nicht erreicht + Fail:  + Commit / Target / Stretch noch nicht erreicht
@@ -22,7 +23,10 @@ class="ordinal-zone" >
- Commit: {{ keyResult.commitZone }} + + Commit:  + {{ keyResult.commitZone }} +
@@ -32,7 +36,10 @@ class="ordinal-zone" >
- Target: {{ keyResult.targetZone }} + + Target:  + {{ keyResult.targetZone }} +
@@ -42,7 +49,10 @@ class="ordinal-zone" >
- Stretch: {{ keyResult.stretchZone }} + + Stretch:  + {{ keyResult.stretchZone }} +
diff --git a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts index b1e1343eb5..5c8398913f 100644 --- a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts +++ b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts @@ -74,6 +74,7 @@ export class CheckInFormComponent implements OnInit { this.dialogForm.controls.initiatives.setValue(this.checkIn.initiatives); return; } + /* If KeyResult has lastCheckIn set checkIn to this value */ if ((this.keyResult as KeyResultMetric | KeyResultOrdinal).lastCheckIn != null) { this.checkIn = { @@ -83,6 +84,7 @@ export class CheckInFormComponent implements OnInit { this.dialogForm.controls.confidence.setValue(this.checkIn.confidence); return; } + /* If Check-in is null set as object with confidence 5 default value */ this.checkIn = { confidence: 5 } as CheckInMin; } @@ -138,8 +140,10 @@ export class CheckInFormComponent implements OnInit { changeIsChecked(event: any, index: number) { const actions = this.dialogForm.value.actionList!; - actions[index] = { ...actions[index], - isChecked: event.checked }; + actions[index] = { + ...actions[index], + isChecked: event.checked + }; this.dialogForm.patchValue({ actionList: actions }); } diff --git a/frontend/src/app/components/confidence/confidence.component.spec.ts b/frontend/src/app/components/confidence/confidence.component.spec.ts index f29a6e0b80..867eddf454 100644 --- a/frontend/src/app/components/confidence/confidence.component.spec.ts +++ b/frontend/src/app/components/confidence/confidence.component.spec.ts @@ -1,8 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ConfidenceComponent } from './confidence.component'; -import { HarnessLoader } from '@angular/cdk/testing'; -import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { checkInMetric } from '../../shared/testData'; import { MatSliderModule } from '@angular/material/slider'; import { CheckInMin } from '../../shared/types/model/CheckInMin'; @@ -13,7 +11,6 @@ import { By } from '@angular/platform-browser'; describe('ConfidenceComponent', () => { let component: ConfidenceComponent; let fixture: ComponentFixture; - let loader: HarnessLoader; beforeEach(() => { TestBed.configureTestingModule({ @@ -25,7 +22,6 @@ describe('ConfidenceComponent', () => { fixture = TestBed.createComponent(ConfidenceComponent); component = fixture.componentInstance; - loader = TestbedHarnessEnvironment.loader(fixture); component.checkIn = checkInMetric; component.edit = true; }); @@ -45,7 +41,7 @@ describe('ConfidenceComponent', () => { }); fixture.detectChanges(); await fixture.whenStable(); - const textField = fixture.debugElement.query(By.css("[data-testid='confidence']")); + const textField = fixture.debugElement.query(By.css('[data-testid=\'confidence\']')); const expectedLabel = expected + '/' + component.max; const sliderInputField = fixture.debugElement.query(By.css('mat-slider > input ')); diff --git a/frontend/src/app/components/key-result-form/key-result-form.component.html b/frontend/src/app/components/key-result-form/key-result-form.component.html index 1697565fe0..50c1dbe270 100644 --- a/frontend/src/app/components/key-result-form/key-result-form.component.html +++ b/frontend/src/app/components/key-result-form/key-result-form.component.html @@ -15,11 +15,7 @@ - +
diff --git a/frontend/src/app/components/key-result-form/key-result-form.component.ts b/frontend/src/app/components/key-result-form/key-result-form.component.ts index 9f5fb36f00..32bbc076f3 100644 --- a/frontend/src/app/components/key-result-form/key-result-form.component.ts +++ b/frontend/src/app/components/key-result-form/key-result-form.component.ts @@ -38,13 +38,12 @@ export class KeyResultFormComponent implements OnInit, OnDestroy { constructor(public userService: UserService, private oauthService: OAuthService, - private translate: TranslateService) {} + private translate: TranslateService) { + } ngOnInit(): void { this.users$ = this.userService.getUsers(); - this.filteredUsers$ = this.keyResultForm.get('owner')?.valueChanges.pipe(startWith(''), - filter((value) => typeof value === 'string'), - switchMap((value) => this.filter(value as string))); + this.filteredUsers$ = this.keyResultForm.get('owner')?.valueChanges.pipe(startWith(''), filter((value) => typeof value === 'string'), switchMap((value) => this.filter(value as string))); if (this.keyResult) { this.keyResultForm.patchValue({ actionList: this.keyResult.actionList }); this.keyResultForm.controls['title'].setValue(this.keyResult.title); @@ -58,24 +57,30 @@ export class KeyResultFormComponent implements OnInit, OnDestroy { this.actionList$ = new BehaviorSubject(this.keyResult.actionList); } if (!this.keyResult) { - this.actionList$ = new BehaviorSubject([{ id: null, + this.actionList$ = new BehaviorSubject([{ + id: null, version: 1, action: '', priority: 0, keyResultId: null, - isChecked: false }, - { id: null, + isChecked: false + }, + { + id: null, version: 1, action: '', priority: 1, keyResultId: null, - isChecked: false }, - { id: null, + isChecked: false + }, + { + id: null, version: 1, action: '', priority: 2, keyResultId: null, - isChecked: false }]); + isChecked: false + }]); this.users$.pipe(takeUntil(this.unsubscribe$)) .subscribe((users) => { @@ -147,8 +152,6 @@ export class KeyResultFormComponent implements OnInit, OnDestroy { return this.keyResult ? this.keyResult.id : null; } - updateFormValidity() {} - getLoggedInUserName() { return this.getUserNameFromUser(this.userService.getCurrentUser()); } diff --git a/frontend/src/app/components/keyresult-detail/keyresult-detail.component.html b/frontend/src/app/components/keyresult-detail/keyresult-detail.component.html index f0d14bda8a..f4a7ae1eb6 100644 --- a/frontend/src/app/components/keyresult-detail/keyresult-detail.component.html +++ b/frontend/src/app/components/keyresult-detail/keyresult-detail.component.html @@ -52,7 +52,7 @@

Confidence

- +

Baseline: {{ keyResultMetric.baseline | unitTransformation: keyResultMetric.unit }} @@ -76,7 +76,7 @@

Confidence

- +

Commit

@@ -106,7 +106,7 @@

Beschrieb

{{ keyResult.description || "-" }}

-
+

Action Plan

@@ -120,7 +120,10 @@

Action Plan

-
- {{ action.action }}
+
+ - + {{ action.action }} +
diff --git a/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.ts b/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.ts index af9422eb4e..986e552522 100644 --- a/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.ts +++ b/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.ts @@ -35,12 +35,15 @@ export class KeyresultDialogComponent { }); constructor( - @Inject(MAT_DIALOG_DATA) public data: { objective: Objective; - keyResult: KeyResult; }, + @Inject(MAT_DIALOG_DATA) public data: { + objective: Objective; + keyResult: KeyResult; + }, private keyResultService: KeyresultService, public dialogService: DialogService, public dialogRef: MatDialogRef - ) {} + ) { + } isMetricKeyResult() { return this.keyResultForm.controls['keyResultType'].value === 'metric'; @@ -49,11 +52,15 @@ export class KeyresultDialogComponent { saveKeyResult(openNewDialog = false) { const value = this.keyResultForm.value; const keyResult = this.isMetricKeyResult() - ? ({ ...value, - objective: this.data.objective } as KeyResultMetricDTO) - : ({ ...value, + ? { + ...value, + objective: this.data.objective + } as KeyResultMetricDTO + : { + ...value, objective: this.data.objective, - id: this.data.keyResult?.id } as KeyResultOrdinalDTO); + id: this.data.keyResult?.id + } as KeyResultOrdinalDTO; keyResult.id = this.data.keyResult?.id; keyResult.version = this.data.keyResult?.version!; keyResult.actionList = keyResult.actionList!.filter((action: Action) => action.action !== ''); diff --git a/frontend/src/app/components/keyresult-type/keyresult-type.component.ts b/frontend/src/app/components/keyresult-type/keyresult-type.component.ts index e988cef30f..8ce304db71 100644 --- a/frontend/src/app/components/keyresult-type/keyresult-type.component.ts +++ b/frontend/src/app/components/keyresult-type/keyresult-type.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { KeyResult } from '../../shared/types/model/KeyResult'; import { FormGroup, Validators } from '@angular/forms'; import { KeyResultMetric } from '../../shared/types/model/KeyResultMetric'; @@ -17,7 +17,6 @@ export class KeyresultTypeComponent implements OnInit { @Input() keyresult!: KeyResult | null; - @Output() formValidityEmitter = new EventEmitter(); isMetric = true; @@ -29,7 +28,8 @@ export class KeyresultTypeComponent implements OnInit { protected readonly hasFormFieldErrors = hasFormFieldErrors; - constructor(private translate: TranslateService) {} + constructor(private translate: TranslateService) { + } ngOnInit(): void { if (this.keyresult) { @@ -65,7 +65,6 @@ export class KeyresultTypeComponent implements OnInit { async updateFormValidity() { await new Promise((r) => setTimeout(r, 100)); - this.formValidityEmitter.emit(this.keyResultForm.invalid); } setValidatorsMetric() { @@ -98,7 +97,7 @@ export class KeyresultTypeComponent implements OnInit { } switchKeyResultType(type: string) { - if (((type == 'metric' && !this.isMetric) || (type == 'ordinal' && this.isMetric)) && this.typeChangeAllowed) { + if ((type == 'metric' && !this.isMetric || type == 'ordinal' && this.isMetric) && this.typeChangeAllowed) { this.isMetric = !this.isMetric; const keyResultType = this.isMetric ? 'metric' : 'ordinal'; this.keyResultForm.controls['keyResultType'].setValue(keyResultType); diff --git a/frontend/src/app/components/keyresult/keyresult.component.html b/frontend/src/app/components/keyresult/keyresult.component.html index 6aa06cd6b1..8280b76f8d 100644 --- a/frontend/src/app/components/keyresult/keyresult.component.html +++ b/frontend/src/app/components/keyresult/keyresult.component.html @@ -15,7 +15,7 @@

{{ keyResult.title }}

Letztes Check-in

{{ - getKeyResultWithCorrectType().lastCheckIn == null + getKeyResultWithCorrectType().lastCheckIn === null ? "Keines" : (getKeyResultWithCorrectType().lastCheckIn!.createdOn | date: DATE_FORMAT) }} diff --git a/frontend/src/app/components/objective-detail/objective-detail.component.html b/frontend/src/app/components/objective-detail/objective-detail.component.html index d571c2477d..a8dc50cc5c 100644 --- a/frontend/src/app/components/objective-detail/objective-detail.component.html +++ b/frontend/src/app/components/objective-detail/objective-detail.component.html @@ -19,7 +19,9 @@

{{ objective.title }}

Beschrieb

-

-

+
+

-

+
Beschrieb

{{ objective.description }}

-
+
+ >Abbrechen +
-
+