diff --git a/.github/workflows/argo.yml b/.github/workflows/argo.yml index 71ab4a62dc..eb0dc9a7e4 100644 --- a/.github/workflows/argo.yml +++ b/.github/workflows/argo.yml @@ -30,32 +30,32 @@ on: type: choice description: Which Environment required: true - options: + options: - Dev/Test - E2E-A/E2E-B - int-a/int-b - testdata_version: + testdata_version: description: Which Testdata Version CX_Testdata_MessagingTest_v.json required: true argo_token: description: Argo Token - required: true - api-token: - description: Api Token required: true - + api_token: + description: Api Token + required: true + env: ARGO_TEST_REGISTRY: "https://argo.dev.demo.catena-x.net/api/v1/applications/tracex-dt-registry-test" ARGO_TEST_EDC_PROVIDER: "https://argo.dev.demo.catena-x.net/api/v1/applications/tracex-test-edc-provider" ARGO_TEST_TRACE_X_INSTANCE: "https://argo.dev.demo.catena-x.net/api/v1/applications/traceability-foss-test" ARGO_TEST_RegistryReload: "https://traceability-test.dev.demo.catena-x.net/api/registry/reload" - + ARGO_DEV_REGISTRY: "https://argo.dev.demo.catena-x.net/api/v1/applications/tracex-dt-registry-dev" ARGO_DEV_EDC_PROVIDER: "https://argo.dev.demo.catena-x.net/api/v1/applications/tracex-edc-provider" ARGO_DEV_TRACE_X_INSTANCE: "https://argo.dev.demo.catena-x.net/api/v1/applications/traceability-foss-dev" ARGO_DEV_RegistryReload: "https://traceability.dev.demo.catena-x.net/api/registry/reload" - - ARGO_E2E_A_REGISTRY: "https://argo.dev.demo.catena-x.net/api/v1/applications/tracex-dt-registry-e2e-a" + + ARGO_E2E_A_REGISTRY: "https://argo.dev.demo.catena-x.net/api/v1/applications/tracex-dt-registry-e2e-a" ARGO_E2E_A_EDC_PROVIDER: "https://argo.dev.demo.catena-x.net/api/v1/applications/tracex-edc-provider-e2e-a" ARGO_E2E_A_TRACE_X_INSTANCE: "https://argo.dev.demo.catena-x.net/api/v1/applications/traceability-foss-e2e-a" ARGO_E2E_A_RegistryReload: "https://traceability-e2e-a.dev.demo.catena-x.net/api/registry/reload" @@ -64,8 +64,8 @@ env: ARGO_E2E_B_EDC_PROVIDER: "https://argo.dev.demo.catena-x.net/api/v1/applications/tracex-edc-provider-e2e-b" ARGO_E2E_B_TRACE_X_INSTANCE: "https://argo.dev.demo.catena-x.net/api/v1/applications/traceability-foss-e2e-b" ARGO_E2E_B_RegistryReload: "https://traceability-e2e-b.dev.demo.catena-x.net/api/registry/reload" - - ARGO_INT_A_REGISTRY: "https://argo.int.demo.catena-x.net/api/v1/applications/tx-registry-int-a" + + ARGO_INT_A_REGISTRY: "https://argo.int.demo.catena-x.net/api/v1/applications/tx-registry-int-a" ARGO_INT_A_EDC_PROVIDER: "https://argo.int.demo.catena-x.net/api/v1/applications/tx-edc-provider-int-a" ARGO_INT_A_TRACE_X_INSTANCE: "https://argo.int.demo.catena-x.net/api/v1/applications/traceability-foss-int-a" ARGO_INT_A_RegistryReload: "https://traceability-int-a.int.demo.catena-x.net/api/registry/reload" @@ -74,8 +74,8 @@ env: ARGO_INT_B_EDC_PROVIDER: "https://argo.int.demo.catena-x.net/api/v1/applications/tx-edc-provider-int-b" ARGO_INT_B_TRACE_X_INSTANCE: "https://argo.int.demo.catena-x.net/api/v1/applications/traceability-foss-int-b" ARGO_INT_B_RegistryReload: "https://traceability-int-b.int.demo.catena-x.net/api/registry/reload" - -jobs: + +jobs: print_environment: runs-on: ubuntu-latest @@ -84,25 +84,25 @@ jobs: run: | echo "### inputs" >> $GITHUB_STEP_SUMMARY echo "- environment: ${{ github.event.inputs.environment }}" >> $GITHUB_STEP_SUMMARY - + hard_refresh_environment: needs: print_environment runs-on: ubuntu-latest steps: - + - name: Checkout-Repository uses: actions/checkout@v4 - + - name: mask token run: | ARGO_TOKEN=$(jq -r '.inputs.argo_token' $GITHUB_EVENT_PATH) echo ::add-mask::$ARGO_TOKEN echo ARGO_TOKEN=$ARGO_TOKEN >> $GITHUB_ENV - + - name: Hard refresh environment ${{ github.event.inputs.environment }} run: | source ./.github/argo/argo_config.sh - + if [ "${{ github.event.inputs.environment }}" == "Dev/Test" ]; then resources=("${DEV_TEST_RESOURCES[@]}") elif [ "${{ github.event.inputs.environment }}" == "E2E-A/E2E-B" ]; then @@ -110,7 +110,7 @@ jobs: elif [ "${{ github.event.inputs.environment }}" == "int-a/int-b" ]; then resources=("${INT_RESOURCES[@]}") fi - + for resource in "${resources[@]}"; do curl -X GET -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" "$resource?refresh=hard&appNamespace=argocd" done @@ -120,20 +120,20 @@ jobs: needs: hard_refresh_environment runs-on: ubuntu-latest steps: - + - name: Checkout-Repository uses: actions/checkout@v4 - + - name: mask token run: | ARGO_TOKEN=$(jq -r '.inputs.argo_token' $GITHUB_EVENT_PATH) echo ::add-mask::$ARGO_TOKEN echo ARGO_TOKEN=$ARGO_TOKEN >> $GITHUB_ENV - + - name: Delete Argo Environment run: | source ./.github/argo/argo_config.sh - + if [ "${{ github.event.inputs.environment }}" == "Dev/Test" ]; then resources=("${DELETE_DEV_TEST_RESOURCES[@]}") elif [ "${{ github.event.inputs.environment }}" == "E2E-A/E2E-B" ]; then @@ -141,30 +141,30 @@ jobs: elif [ "${{ github.event.inputs.environment }}" == "int-a/int-b" ]; then resources=("${DELETE_INT_RESOURCES[@]}") fi - + for resource in "${resources[@]}"; do curl -X DELETE -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" "$resource" sleep 2 done sleep 10 - + change_target_revision: needs: delete_environment runs-on: ubuntu-latest steps: - + - name: mask token run: | ARGO_TOKEN=$(jq -r '.inputs.argo_token' $GITHUB_EVENT_PATH) echo ::add-mask::$ARGO_TOKEN echo ARGO_TOKEN=$ARGO_TOKEN >> $GITHUB_ENV - - - name: Change TargetRevison - run: | + + - name: Change TargetRevison + run: | new_target_revision=${{ github.ref_name }} - + if [ "${{ github.event.inputs.environment }}" == "Dev/Test" ]; then - + json_data1=$(curl -X GET -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" "$ARGO_TEST_TRACE_X_INSTANCE") old_TargetRevision1=$(echo "$json_data1" | jq -r '.spec.source.targetRevision') json_data2=$(curl -X GET -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" "$ARGO_DEV_TRACE_X_INSTANCE") @@ -175,16 +175,16 @@ jobs: curl -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" -d "$updated_json" "$ARGO_TEST_TRACE_X_INSTANCE" echo "Target Revision for Test overwritten" fi - + if [ "$old_TargetRevision2" != "$new_target_revision" ]; then updated_json=$(echo "$json_data2" | jq ".spec.source.targetRevision = \"$new_target_revision\"") curl -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" -d "$updated_json" "$ARGO_DEV_TRACE_X_INSTANCE" echo "Target Revision for Dev overwritten" fi - + elif [ "${{ github.event.inputs.environment }}" == "E2E-A/E2E-B" ]; then - + json_data1=$(curl -X GET -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" "$ARGO_E2E_A_TRACE_X_INSTANCE") old_TargetRevision1=$(echo "$json_data1" | jq -r '.spec.source.targetRevision') json_data2=$(curl -X GET -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" "$ARGO_E2E_B_TRACE_X_INSTANCE") @@ -195,62 +195,62 @@ jobs: curl -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" -d "$updated_json" "$ARGO_E2E_A_TRACE_X_INSTANCE" echo "Target Revision for e2e-a overwritten" fi - + if [ "$old_TargetRevision2" != "$new_target_revision" ]; then updated_json=$(echo "$json_data2" | jq ".spec.source.targetRevision = \"$new_target_revision\"") curl -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" -d "$updated_json" "$ARGO_E2E_B_TRACE_X_INSTANCE" echo "Target Revision for e2e-b overwritten" fi - + fi - sync_environment: + sync_environment: needs: change_target_revision runs-on: ubuntu-latest steps: - + - name: Checkout-Repository uses: actions/checkout@v4 - + - name: mask token run: | ARGO_TOKEN=$(jq -r '.inputs.argo_token' $GITHUB_EVENT_PATH) echo ::add-mask::$ARGO_TOKEN echo ARGO_TOKEN=$ARGO_TOKEN >> $GITHUB_ENV - + - name: Sync Argo Environment run: | source ./.github/argo/argo_config.sh - + if [ "${{ github.event.inputs.environment }}" == "Dev/Test" ]; then resources=("${SYNC_DEV_TEST_RESOURCES[@]}") elif [ "${{ github.event.inputs.environment }}" == "E2E-A/E2E-B" ]; then resources=("${SYNC_E2E_RESOURCES[@]}") elif [ "${{ github.event.inputs.environment }}" == "int-a/int-b" ]; then resources=("${SYNC_INT_RESOURCES[@]}") - fi - + fi + for resource in "${resources[@]}"; do curl -X POST -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" "$resource" - done + done sleep 20 - + test_state: needs: sync_environment runs-on: ubuntu-latest timeout-minutes: 15 steps: - + - name: Checkout code uses: actions/checkout@v4 - + - name: mask token run: | ARGO_TOKEN=$(jq -r '.inputs.argo_token' $GITHUB_EVENT_PATH) echo ::add-mask::$ARGO_TOKEN echo ARGO_TOKEN=$ARGO_TOKEN >> $GITHUB_ENV - + - name: test apps state run: | source ./.github/argo/argo_config.sh @@ -260,8 +260,8 @@ jobs: resources=("${E2E_RESOURCES[@]}") elif [ "${{ github.event.inputs.environment }}" == "int-a/int-b" ]; then resources=("${INT_RESOURCES[@]}") - fi - + fi + for resource in "${resources[@]}"; do while true; do json_data=$(curl -X GET -H "Authorization: Bearer ${{ env.ARGO_TOKEN }}" "$resource") @@ -286,28 +286,28 @@ jobs: sleep 10 fi done - done - sleep 120 + done + sleep 120 upload_testdata: needs: test_state runs-on: ubuntu-latest steps: - + - name: Checkout code uses: actions/checkout@v4 - + - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - + - name: mask token run: | - API_TOKEN=$(jq -r '.inputs.api-token' $GITHUB_EVENT_PATH) + API_TOKEN=$(jq -r '.inputs.api_token' $GITHUB_EVENT_PATH) echo ::add-mask::$API_TOKEN echo API_TOKEN=$API_TOKEN >> $GITHUB_ENV - + - name: Upload testdata run: | python -m pip install requests @@ -329,13 +329,13 @@ jobs: sleep 10 fi registry_reload: - needs: + needs: - upload_testdata runs-on: ubuntu-latest - steps: + steps: - name: reload the registry run: | - + if [ "${{ github.event.inputs.environment }}" == "Dev/Test" ]; then curl -X GET "$ARGO_TEST_RegistryReload" curl -X GET "$ARGO_DEV_RegistryReload" diff --git a/CHANGELOG.md b/CHANGELOG.md index 0847a88ed7..d134c9b633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - new filtering capabilities ( receivedQualityAlertIdsInStatusActive, sentQualityAlertIdsInStatusActive, receivedQualityInvestigationIdsInStatusActive, sentQualityInvestigationIdsInStatusActive ) - Validation check if table-settings correct and reset on invalid state - Added Api-Input in Argo Workflow to fix bugs +- Added implementation for cucumber tests for quality investigations ### Changed - Filter configuration for tables to be resuable and easy to adapt - Realigned some mappings e.g. (manufacturer / manufacturerName) to be more clear @@ -26,6 +27,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added - Added new dashboard layout and additional widgets - Refactored dashboard response +- Added new fields to dashboard response ## [9.0.0-rc3 - 27.11.2023] ### Added diff --git a/frontend/cypress/integration/pages/QualityInvestigationsPage.ts b/frontend/cypress/integration/pages/QualityInvestigationsPage.ts new file mode 100644 index 0000000000..63cf5b71c6 --- /dev/null +++ b/frontend/cypress/integration/pages/QualityInvestigationsPage.ts @@ -0,0 +1,24 @@ +/******************************************************************************** + * Copyright (c) 2022, 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * Copyright (c) 2022, 2023 ZF Friedrichshafen AG + * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +export class QualityInvestigationsPage { +//TBD if necessary +} diff --git a/frontend/cypress/support/step_definitions/dashboard.ts b/frontend/cypress/support/step_definitions/dashboard.ts index 8d9aa52866..e9a33fff49 100644 --- a/frontend/cypress/support/step_definitions/dashboard.ts +++ b/frontend/cypress/support/step_definitions/dashboard.ts @@ -19,7 +19,7 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'; +import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'; import { DashboardPage } from '../../integration/pages/DashboardPage'; @@ -47,6 +47,7 @@ Then(/^should be visible "Dashboard" header$/, () => { Then(/^should be visible "TOTAL OF PARTS" section$/, () => { cy.get('section').contains('Total of parts').should('be.visible'); }); + Then(/^should be visible "TOTAL OF OTHER PARTS" section$/, () => { cy.get('section').contains('Total of other parts').should('be.visible'); }); diff --git a/frontend/cypress/support/step_definitions/login.ts b/frontend/cypress/support/step_definitions/login.ts index 06b9be9863..40135f36f1 100644 --- a/frontend/cypress/support/step_definitions/login.ts +++ b/frontend/cypress/support/step_definitions/login.ts @@ -26,18 +26,13 @@ Given('user logged in as {string}', function(userType) { cy.visit('https://centralidp.dev.demo.catena-x.net/auth/realms/CX-Central/protocol/openid-connect/auth?client_id=Cl17-CX-Part&redirect_uri=https%3A%2F%2Ftraceability-portal-e2e-a.dev.demo.catena-x.net%2Fdashboard&state=0aaee615-388e-400c-8b0c-81ac443a2cf3&response_mode=fragment&response_type=code&scope=openid&nonce=4104d5ab-b2bd-43a1-b6c2-7adf30543579&code_challenge=uXHR3gDRnSyjPEu8yWNdzm6Izsd7cKzEryfvRAtJTjU&code_challenge_method=S256'); cy.get('.search').click(); cy.get('.search').type('CX-Test-Access'); - cy.wait(5000); cy.get('.CX_Test_Access').click(); - cy.wait(5000); - cy.get('input[name="username"]').type(loginMail,{log:false}); - cy.wait(5000); + cy.get('input[name="username"]').type(loginMail); cy.get('input[name="password"]').click().focus().type(loginPW, {log:false}); - cy.wait(5000); cy.get('input[type="submit"]').click(); }); Given('user is directed to the {string}', function(value) { - cy.wait(5000); cy.get('div.layout-content').should('exist'); }); diff --git a/frontend/cypress/support/step_definitions/menu.ts b/frontend/cypress/support/step_definitions/menu.ts new file mode 100644 index 0000000000..8bb0435632 --- /dev/null +++ b/frontend/cypress/support/step_definitions/menu.ts @@ -0,0 +1,63 @@ +/******************************************************************************** + * Copyright (c) 2022, 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * Copyright (c) 2022, 2023 ZF Friedrichshafen AG + * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'; + + +When("user navigate to {string}", function(desiredMenu) { +matched = false; + switch (desiredMenu) { + case 'Other parts': { + matched = true; + cy.get('[href="/otherParts"]').click(); + break; + } + case 'Parts': { + matched = true; + cy.get('[href="/parts"]').click(); + break; + } + case 'Dashboard': { + matched = true; + cy.get('[href="/dashboard"]').click(); + break; + } + case 'Quality investigations': { + matched = true; + cy.get('[href="/investigations"]').click(); + break; + } + case 'Quality alerts': { + matched = true; + cy.get('[href="/alerts"]').click(); + break; + } + case 'About': { + matched = true; + cy.get('[href="/about"]').click(); + break; + } + default: { + throw new Error("Set header menu '" + desiredMenu + "' is not one of valid status [Dashboard, Parts, Other parts, Quality investigations, Quality alerts, About]."); + break; + } + } +}); diff --git a/frontend/cypress/support/step_definitions/quality-investigations.ts b/frontend/cypress/support/step_definitions/quality-investigations.ts new file mode 100644 index 0000000000..ce4b4af421 --- /dev/null +++ b/frontend/cypress/support/step_definitions/quality-investigations.ts @@ -0,0 +1,257 @@ +/******************************************************************************** + * Copyright (c) 2022, 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * Copyright (c) 2022, 2023 ZF Friedrichshafen AG + * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +import { When, Then, Given } from '@badeball/cypress-cucumber-preprocessor'; +import { QualityInvestigationsPage } from '../../integration/pages/QualityInvestigationsPage'; + +let notificationDescription = null; + +Then("select {string} other part", (partAmount) => { +//since IDs of desired asset are not shown in FE the selection has to be done by other number. + cy.get('span').contains('As Planned').click(); // This has to be done to avoid asPlanned selection + cy.get('#mat-mdc-checkbox-38*').click(); //---TBD--- this is only a method to make it run, has to be changed to selected part. + +}); + + +Then("start investigation creation with description {string}", function (description) { + const date = new Date().getTime(); + notificationDescription = description + "_" + date; + cy.get('div').contains('Start investigation').click(); + cy.get('mat-label').contains('Description').click().type(notificationDescription); +}); + + +When("severity {string}", function (severity) { + cy.get('#mat-select-56').click(); // First the dropdown has to be opened. + cy.get('p').contains(severity).click(); +}); + + +When("{string} deadline", function (deadline) { + if (deadline == 'no') { + // do nothing + } else { + // ---TBD--- implement timepicker once it´s necessary. + } +}); + + +When("request the investigation", () => { + cy.get('span').contains('ADD TO QUEUE').click(); +}); + + +Then("selected parts are marked as investigated", () => { + //cy.get('class').contains('highlighted'); + //---TBD--- to check the desired assets, have to be adjusted with desired asset selection +}); + + +When("popup with information about queued investigation is shown", () => { + cy.contains(/You queued an investigation for 1 part/i).should('be.visible'); +}); + + +When("user navigate to {string} with button in popup", (popupClick) => { + cy.get('a').contains('Go to Queue').click(); +}); + + +When("open details of created investigation", () => { + cy.get('[data-testid="table-menu-button"]').first().click(); //the first investigation will be opened + cy.get('[data-testid="table-menu-button--actions.viewDetails"]').first().click(); +}); + + +// --- TBD --- check id, description, status, created, createdby, text +// --- TBD --- #check: popup on the right sight is shown +When("user confirm cancelation of selected investigation with entering {string} id", (input) => { + let investigationId = ''; + switch (input) { + case 'no': { + cy.get('span').contains('Confirm cancellation').click(); + break; + } + case 'wrong': { + cy.get('#mat-mdc-form-field-label-4').click().focus().type('000'); + cy.get('span').contains('Confirm cancellation').click(); + break; + } + case 'correct': { + cy.get('mat-label').invoke('text').as('cancelId'); + cy.get('@cancelId').then((cancelId) => { + cy.get('#mat-input-0').click().type(cancelId); + }); + cy.get('span').contains('Confirm cancellation').click(); + break; + } + default: { + throw new Error("Set cancelation id '" + input + "' is not one of valid actions [no, wrong, correct]."); + break; + } + } +}); + + +Then("cancelation is not possible due to {string} id", (id) => { + switch (id) { + case 'no': { + cy.contains(/This field is required!/i).should('be.visible'); + break; + } + case 'wrong': { + cy.contains(/Please enter data that matches this pattern:/i).should('be.visible'); + break; + } + default: { + throw new Error("Set cancelation action '" + id + "' is not one of valid actions [no, wrong]."); + break; + } + } +}); + + +When("user {string} selected investigation", (action) => { +//within opened detail view of quality investigation + switch (action) { + case 'approve': { + cy.get('div').contains('Approve').click(); + break; + } + case 'cancel': { + cy.get('div').contains('Cancel').click(); + break; + } + case 'close': { + cy.get('div').contains('Close').click(); + break; + } + case 'acknowledge': { + cy.get('div').contains('Acknowledge').click(); + break; + } + case 'accept': { + cy.get('div').contains('Accept').click(); + break; + } + case 'decline': { + cy.get('div').contains('Decline').click(); + break; + } + default: { + throw new Error("Set action '" + action + "' is not one of valid actions [approve, cancel, close, acknowledge, accept, decline]."); + break; + } + } +}); + + +When("user confirm approval of selected investigation", (action) => { + cy.get('app-confirm').find('span').contains('Approve').click(); +}); + + +Then("informations for selected investigation are displayed as expected", () => { +// --- TBD --- include: overview, supplier parts, STATUS +}); + + +Then("selected {string} has been {string} as expected", (notificationType, expectedStatus) => { +matched = false; + switch (expectedStatus) { + case 'canceled': { + matched = true; + cy.get('[title="Cancelled"]').should('be.visible'); + break; + } + case 'approved': { + // same as "requested" + matched = true; + cy.get('[title="Requested"]', { timeout: 10000 }).should('be.visible'); + break; + } + case 'accepted': { + matched = true; + cy.get('[title="Accepted"]', { timeout: 10000 }).should('be.visible'); + break; + } + case 'declined': { + matched = true; + cy.get('[title="Declined"]', { timeout: 10000 }).should('be.visible'); + break; + } + case 'acknowledged': { + matched = true; + cy.get('[title="Acknowledged"]', { timeout: 10000 }).should('be.visible'); + break; + } + case 'closed': { + matched = true; + cy.get('[title="Closed"]', { timeout: 10000 }).should('be.visible'); + break; + } + default: { + throw new Error("Set expected status '" + expectedStatus + "' is not one of valid status [canceled, approved, accepted, declined, acknowledged, closed]."); + break; + } + } +}); + + +When("selected {string} is not allowed to be {string}", (notificationType, status) => { +matched = false; + switch (status) { + case 'canceled': { + matched = true; + cy.get('div').contains('/^Cancel$/', {matchCase: true}).should('not.exist'); + break; + } + case 'approved': { + matched = true; + cy.get('div').contains('/^Approve$/', {matchCase: true}).should('not.exist'); + break; + } + case 'accepted': { + matched = true; + cy.get('div').contains('/^Accept$/', {matchCase: true}).should('not.exist'); + break; + } + case 'declined': { + matched = true; + cy.get('div').contains('/^Decline$/', {matchCase: true}).should('not.exist'); + break; + } + case 'acknowledged': { + matched = true; + cy.get('div').contains('/^Acknowledge$/', {matchCase: true}).should('not.exist'); + break; + } + case 'closed': { + matched = true; + cy.get('div').contains('/^Close$/', {matchCase: true}).should('not.exist'); + break; + } + default: { + throw new Error("Set status '" + status + "' is not one of valid status [canceled, approved, accepted, declined, acknowledged, closed]."); + break; + } + } +}); diff --git a/frontend/src/app/mocks/services/dashboard-mock/dashboard.model.ts b/frontend/src/app/mocks/services/dashboard-mock/dashboard.model.ts index e1fa20dd51..75fd7cd2d7 100644 --- a/frontend/src/app/mocks/services/dashboard-mock/dashboard.model.ts +++ b/frontend/src/app/mocks/services/dashboard-mock/dashboard.model.ts @@ -36,5 +36,9 @@ export const mockDashboardStats: DashboardStatsResponse = { asBuiltSupplierParts: 163000, asPlannedSupplierParts: 2563, asBuiltOwnParts: 5300000, - asPlannedOwnParts: 11203 + asPlannedOwnParts: 11203, + receivedActiveAlerts: 5000, + receivedActiveInvestigations: 2000, + sentActiveAlerts: 7000, + sentActiveInvestigations: 5 }; diff --git a/frontend/src/app/modules/page/dashboard/core/dashboard.assembler.spec.ts b/frontend/src/app/modules/page/dashboard/core/dashboard.assembler.spec.ts index de43371dfb..ac57c41257 100644 --- a/frontend/src/app/modules/page/dashboard/core/dashboard.assembler.spec.ts +++ b/frontend/src/app/modules/page/dashboard/core/dashboard.assembler.spec.ts @@ -19,46 +19,54 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -import { DashboardAssembler } from './dashboard.assembler'; +import {DashboardAssembler} from './dashboard.assembler'; describe('DashboardAssembler', () => { - describe('assembleDashboard', () => { - it('should map response', () => { - expect( - DashboardAssembler.assembleDashboard({ - asBuiltOwnParts: 200, - asBuiltCustomerParts: 0, - asBuiltSupplierParts: 10, - asPlannedCustomerParts: 0, - asPlannedOwnParts: 0, - asPlannedSupplierParts: 0, - customerPartsWithOpenAlerts: 0, - customerPartsWithOpenInvestigations: 0, - myPartsWithOpenAlerts: 0, - myPartsWithOpenInvestigations: 0, - supplierPartsWithOpenAlerts: 0, - supplierPartsWithOpenInvestigations: 0, + describe('assembleDashboard', () => { + it('should map response', () => { + expect( + DashboardAssembler.assembleDashboard({ + asBuiltOwnParts: 200, + asBuiltCustomerParts: 0, + asBuiltSupplierParts: 10, + asPlannedCustomerParts: 0, + asPlannedOwnParts: 0, + asPlannedSupplierParts: 0, + customerPartsWithOpenAlerts: 0, + customerPartsWithOpenInvestigations: 0, + myPartsWithOpenAlerts: 0, + myPartsWithOpenInvestigations: 0, + supplierPartsWithOpenAlerts: 0, + supplierPartsWithOpenInvestigations: 0, + receivedActiveAlerts: 0, + receivedActiveInvestigations: 0, + sentActiveInvestigations: 0, + sentActiveAlerts: 0 - }), - ).toEqual({ - asBuiltCustomerParts: 0, - asBuiltSupplierParts: 10, - asPlannedCustomerParts: 0, - asPlannedOwnParts: 0, - asPlannedSupplierParts: 0, - asBuiltOwnParts: 200, + }), + ).toEqual({ + asBuiltCustomerParts: 0, + asBuiltSupplierParts: 10, + asPlannedCustomerParts: 0, + asPlannedOwnParts: 0, + asPlannedSupplierParts: 0, + asBuiltOwnParts: 200, - totalOwnParts: 200, - totalOtherParts: 10, + totalOwnParts: 200, + totalOtherParts: 10, - ownOpenInvestigationsReceived: 0, - ownOpenInvestigationsCreated: 0, - ownOpenAlertsReceived: 0, - ownOpenAlertsCreated: 0, + ownOpenInvestigationsReceived: 0, + ownOpenInvestigationsCreated: 0, + ownOpenAlertsReceived: 0, + ownOpenAlertsCreated: 0, - myPartsWithOpenAlerts: 0, - myPartsWithOpenInvestigations: 0 - }); + myPartsWithOpenAlerts: 0, + myPartsWithOpenInvestigations: 0, + receivedActiveAlerts: 0, + receivedActiveInvestigations: 0, + sentActiveAlerts: 0, + sentActiveInvestigations: 0 + }); + }); }); - }); }); diff --git a/frontend/src/app/modules/page/dashboard/core/dashboard.assembler.ts b/frontend/src/app/modules/page/dashboard/core/dashboard.assembler.ts index 92224bd407..b5918aefed 100644 --- a/frontend/src/app/modules/page/dashboard/core/dashboard.assembler.ts +++ b/frontend/src/app/modules/page/dashboard/core/dashboard.assembler.ts @@ -43,6 +43,10 @@ export class DashboardAssembler { ownOpenInvestigationsCreated: dashboard.supplierPartsWithOpenInvestigations + dashboard.customerPartsWithOpenInvestigations, ownOpenAlertsReceived: dashboard.supplierPartsWithOpenAlerts + dashboard.customerPartsWithOpenAlerts, ownOpenAlertsCreated: dashboard.myPartsWithOpenAlerts, + receivedActiveAlerts: dashboard.receivedActiveAlerts, + sentActiveAlerts: dashboard.sentActiveAlerts, + receivedActiveInvestigations: dashboard.receivedActiveInvestigations, + sentActiveInvestigations: dashboard.sentActiveInvestigations }; } diff --git a/frontend/src/app/modules/page/dashboard/model/dashboard.model.ts b/frontend/src/app/modules/page/dashboard/model/dashboard.model.ts index a95a635f47..a4e319536c 100644 --- a/frontend/src/app/modules/page/dashboard/model/dashboard.model.ts +++ b/frontend/src/app/modules/page/dashboard/model/dashboard.model.ts @@ -38,7 +38,11 @@ export interface DashboardStats { ownOpenInvestigationsReceived: number, ownOpenInvestigationsCreated: number, ownOpenAlertsReceived: number, - ownOpenAlertsCreated: number + ownOpenAlertsCreated: number, + receivedActiveAlerts: number, + receivedActiveInvestigations: number, + sentActiveAlerts: number, + sentActiveInvestigations: number } @@ -57,5 +61,10 @@ export interface DashboardStatsResponse { asBuiltSupplierParts: number, asPlannedSupplierParts: number, asBuiltOwnParts: number, - asPlannedOwnParts: number + asPlannedOwnParts: number, + + receivedActiveAlerts: number, + receivedActiveInvestigations: number, + sentActiveAlerts: number, + sentActiveInvestigations: number } diff --git a/frontend/src/app/modules/page/dashboard/presentation/dashboard.component.ts b/frontend/src/app/modules/page/dashboard/presentation/dashboard.component.ts index a80709ab28..6ea9ed4e3a 100644 --- a/frontend/src/app/modules/page/dashboard/presentation/dashboard.component.ts +++ b/frontend/src/app/modules/page/dashboard/presentation/dashboard.component.ts @@ -95,12 +95,12 @@ export class DashboardComponent implements OnInit, OnDestroy { this.investigationsMetricData = [ { metricName: 'amountReceived', - value: this.dashboardStats$.pipe(map(dashboardStats => dashboardStats.data.ownOpenInvestigationsReceived)), + value: this.dashboardStats$.pipe(map(dashboardStats => dashboardStats.data.receivedActiveInvestigations)), metricUnit: 'investigations' }, { metricName: 'amountCreated', - value: this.dashboardStats$.pipe(map(dashboardStats => dashboardStats.data.ownOpenInvestigationsCreated)), + value: this.dashboardStats$.pipe(map(dashboardStats => dashboardStats.data.sentActiveInvestigations)), metricUnit: 'investigations' } ]; @@ -109,12 +109,12 @@ export class DashboardComponent implements OnInit, OnDestroy { this.alertsMetricData = [ { metricName: 'amountReceived', - value: this.dashboardStats$.pipe(map(dashboardStats => dashboardStats.data.ownOpenAlertsReceived)), + value: this.dashboardStats$.pipe(map(dashboardStats => dashboardStats.data.receivedActiveAlerts)), metricUnit: 'alerts' }, { metricName: 'amountCreated', - value: this.dashboardStats$.pipe(map(dashboardStats => dashboardStats.data.ownOpenAlertsCreated)), + value: this.dashboardStats$.pipe(map(dashboardStats => dashboardStats.data.sentActiveAlerts)), metricUnit: 'alerts' } ]; diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/dashboard/mapper/DashboardResponseMapper.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/dashboard/mapper/DashboardResponseMapper.java index 3846a69ee5..4f2620e4b8 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/dashboard/mapper/DashboardResponseMapper.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/application/dashboard/mapper/DashboardResponseMapper.java @@ -36,7 +36,11 @@ public static DashboardResponse from(final Dashboard dashboard) { dashboard.getSupplierPartsWithOpenAlerts(), dashboard.getCustomerPartsWithOpenAlerts(), dashboard.getSupplierPartsWithOpenInvestigations(), - dashboard.getCustomerPartsWithOpenInvestigations() + dashboard.getCustomerPartsWithOpenInvestigations(), + dashboard.getReceivedActiveAlerts(), + dashboard.getReceivedActiveInvestigations(), + dashboard.getSentActiveAlerts(), + dashboard.getSentActiveInvestigations() ); } } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/dashboard/model/Dashboard.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/dashboard/model/Dashboard.java index f8e22a4157..e768cdcf06 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/dashboard/model/Dashboard.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/dashboard/model/Dashboard.java @@ -39,4 +39,8 @@ public class Dashboard { long customerPartsWithOpenAlerts; long supplierPartsWithOpenInvestigations; long customerPartsWithOpenInvestigations; + long receivedActiveAlerts; + long receivedActiveInvestigations; + long sentActiveAlerts; + long sentActiveInvestigations; } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/dashboard/service/DashboardServiceImpl.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/dashboard/service/DashboardServiceImpl.java index 5bb9e85235..42f74e566e 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/dashboard/service/DashboardServiceImpl.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/domain/dashboard/service/DashboardServiceImpl.java @@ -29,6 +29,7 @@ import org.eclipse.tractusx.traceability.assets.domain.dashboard.model.Dashboard; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.AlertRepository; import org.eclipse.tractusx.traceability.qualitynotification.domain.base.InvestigationRepository; +import org.eclipse.tractusx.traceability.qualitynotification.domain.base.model.QualityNotificationSide; import org.springframework.stereotype.Component; import java.util.List; @@ -62,6 +63,12 @@ public Dashboard getDashboard() { long customerPartsWithOpenReceivedAlerts = alertRepository.countOpenNotificationsByOwnership(List.of(Owner.CUSTOMER)); long customerPartsWithOpenSentInvestigations = investigationsRepository.countOpenNotificationsByOwnership(List.of(Owner.CUSTOMER)); + long receivedActiveInvestigations = investigationsRepository.countQualityNotificationEntitiesBySide(QualityNotificationSide.RECEIVER); + long sentActiveInvestigations = investigationsRepository.countQualityNotificationEntitiesBySide(QualityNotificationSide.SENDER); + + long receivedActiveAlerts = alertRepository.countQualityNotificationEntitiesBySide(QualityNotificationSide.RECEIVER); + long sentActiveAlerts = alertRepository.countQualityNotificationEntitiesBySide(QualityNotificationSide.SENDER); + return Dashboard.builder() .asBuiltCustomerParts(asBuiltCustomerParts) .asPlannedCustomerParts(asPlannedCustomerParts) @@ -75,6 +82,10 @@ public Dashboard getDashboard() { .customerPartsWithOpenAlerts(customerPartsWithOpenReceivedAlerts) .supplierPartsWithOpenInvestigations(supplierPartsWithOpenSentInvestigations) .customerPartsWithOpenInvestigations(customerPartsWithOpenSentInvestigations) + .receivedActiveAlerts(receivedActiveAlerts) + .receivedActiveInvestigations(receivedActiveInvestigations) + .sentActiveAlerts(sentActiveAlerts) + .sentActiveInvestigations(sentActiveInvestigations) .build(); } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/repository/QualityNotificationRepository.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/repository/QualityNotificationRepository.java index 58615c2d0b..1f916cd33a 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/repository/QualityNotificationRepository.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/qualitynotification/domain/repository/QualityNotificationRepository.java @@ -55,4 +55,5 @@ public interface QualityNotificationRepository { PageResult getNotifications(Pageable pageable, SearchCriteria searchCriteria); long countOpenNotificationsByOwnership(List owners); + } diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/assets/application/rest/DashboardControllerTest.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/assets/application/rest/DashboardControllerTest.java index 5a15ab01a8..40592b7a04 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/assets/application/rest/DashboardControllerTest.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/assets/application/rest/DashboardControllerTest.java @@ -52,6 +52,10 @@ void dashboard() { .customerPartsWithOpenAlerts(1111L) .supplierPartsWithOpenInvestigations(1111L) .customerPartsWithOpenInvestigations(1111L) + .sentActiveInvestigations(5000L) + .sentActiveAlerts(2000L) + .receivedActiveInvestigations(2500L) + .receivedActiveAlerts(3000L) .build(); Mockito.when(dashboardService.getDashboard()).thenReturn(dashboard); Dashboard testDashboard = dashboardService.getDashboard(); @@ -67,6 +71,11 @@ void dashboard() { assertEquals(1111, testDashboard.getCustomerPartsWithOpenAlerts()); assertEquals(1111, testDashboard.getSupplierPartsWithOpenInvestigations()); assertEquals(1111, testDashboard.getCustomerPartsWithOpenInvestigations()); + assertEquals(5000, testDashboard.getSentActiveInvestigations()); + assertEquals(2000, testDashboard.getSentActiveAlerts()); + assertEquals(3000, testDashboard.getReceivedActiveAlerts()); + assertEquals(2500, testDashboard.getReceivedActiveInvestigations()); + } } diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/DashboardControllerIT.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/DashboardControllerIT.java index 7a0edf977a..3f8c489cec 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/DashboardControllerIT.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/DashboardControllerIT.java @@ -98,7 +98,11 @@ void givenRoles_whenGetDashboard_thenReturnResponse(final List roles) t .body("supplierPartsWithOpenAlerts", equalTo(0)) .body("customerPartsWithOpenAlerts", equalTo(0)) .body("supplierPartsWithOpenInvestigations", equalTo(0)) - .body("customerPartsWithOpenInvestigations", equalTo(0)); + .body("customerPartsWithOpenInvestigations", equalTo(0)) + .body("receivedActiveAlerts", equalTo(0)) + .body("receivedActiveInvestigations", equalTo(0)) + .body("sentActiveAlerts", equalTo(0)) + .body("sentActiveInvestigations", equalTo(0)); } @Test @@ -134,7 +138,11 @@ void givenAlertsWithAssets_whenGetDashboard_thenReturnResponse() throws JoseExce .body("supplierPartsWithOpenAlerts", equalTo(12)) .body("customerPartsWithOpenAlerts", equalTo(0)) .body("supplierPartsWithOpenInvestigations", equalTo(0)) - .body("customerPartsWithOpenInvestigations", equalTo(0)); + .body("customerPartsWithOpenInvestigations", equalTo(0)) + .body("receivedActiveAlerts", equalTo(2)) + .body("receivedActiveInvestigations", equalTo(0)) + .body("sentActiveAlerts", equalTo(0)) + .body("sentActiveInvestigations", equalTo(0)); } @Test @@ -192,7 +200,11 @@ void givenPendingInvestigation_whenGetDashboard_thenReturnPendingInvestigation() .body("supplierPartsWithOpenAlerts", equalTo(0)) .body("customerPartsWithOpenAlerts", equalTo(0)) .body("supplierPartsWithOpenInvestigations", equalTo(1)) - .body("customerPartsWithOpenInvestigations", equalTo(0)); + .body("customerPartsWithOpenInvestigations", equalTo(0)) + .body("receivedActiveAlerts", equalTo(0)) + .body("receivedActiveInvestigations", equalTo(1)) + .body("sentActiveAlerts", equalTo(0)) + .body("sentActiveInvestigations", equalTo(1)); } private static Stream roles() { diff --git a/tx-models/src/main/java/assets/response/DashboardResponse.java b/tx-models/src/main/java/assets/response/DashboardResponse.java index 0992419891..23dbaedd64 100644 --- a/tx-models/src/main/java/assets/response/DashboardResponse.java +++ b/tx-models/src/main/java/assets/response/DashboardResponse.java @@ -45,6 +45,19 @@ public record DashboardResponse( @ApiModelProperty(example = "2") Long supplierPartsWithOpenInvestigations, @ApiModelProperty(example = "2") - Long customerPartsWithOpenInvestigations) { + Long customerPartsWithOpenInvestigations, + + @ApiModelProperty(example = "2") + Long receivedActiveAlerts, + + @ApiModelProperty(example = "2") + Long receivedActiveInvestigations, + + @ApiModelProperty(example = "2") + Long sentActiveAlerts, + + @ApiModelProperty(example = "2") + Long sentActiveInvestigations) { + }