diff --git a/services/cd-service/pkg/service/overview.go b/services/cd-service/pkg/service/overview.go index 8ce41eab1..30fe5f57f 100644 --- a/services/cd-service/pkg/service/overview.go +++ b/services/cd-service/pkg/service/overview.go @@ -33,6 +33,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/timestamppb" + "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" "os" "sort" "sync" @@ -57,6 +58,9 @@ func (o *OverviewServiceServer) GetAppDetails( ctx context.Context, in *api.GetAppDetailsRequest) (*api.GetAppDetailsResponse, error) { + span, ctx := tracer.StartSpanFromContext(ctx, "GetAppDetails") + defer span.Finish() + var appName = in.AppName var response = &api.GetAppDetailsResponse{ Application: &api.Application{ diff --git a/services/frontend-service/src/ui/App/index.tsx b/services/frontend-service/src/ui/App/index.tsx index 90b0e98c3..daa1d583b 100644 --- a/services/frontend-service/src/ui/App/index.tsx +++ b/services/frontend-service/src/ui/App/index.tsx @@ -19,6 +19,8 @@ import { PageRoutes } from './PageRoutes'; import '../../assets/app-v2.scss'; import * as React from 'react'; import { + AppDetailsResponse, + AppDetailsState, EnableRolloutStatus, FlushRolloutStatus, PanicOverview, @@ -100,7 +102,16 @@ export const App: React.FC = () => { UpdateOverview.set(result); UpdateOverview.set({ loaded: true }); PanicOverview.set({ error: '' }); - updateAppDetails.set({}); + + const newDetails: { [p: string]: AppDetailsResponse } = {}; + result.lightweightApps?.forEach( + (elem) => + (newDetails[elem.name] = { + appDetailState: AppDetailsState.NOTREQUESTED, + details: undefined, + }) + ); + updateAppDetails.set(newDetails); }, (error) => { PanicOverview.set({ error: JSON.stringify({ msg: 'error in streamoverview', error }) }); diff --git a/services/frontend-service/src/ui/Pages/Home/Home.test.tsx b/services/frontend-service/src/ui/Pages/Home/Home.test.tsx index 803970bc4..fb9f93206 100644 --- a/services/frontend-service/src/ui/Pages/Home/Home.test.tsx +++ b/services/frontend-service/src/ui/Pages/Home/Home.test.tsx @@ -16,6 +16,8 @@ Copyright freiheit.com*/ import { render, renderHook } from '@testing-library/react'; import { Home } from './Home'; import { + AppDetailsResponse, + AppDetailsState, searchCustomFilter, updateAppDetails, UpdateOverview, @@ -25,7 +27,7 @@ import { import { Spy } from 'spy4js'; import { MemoryRouter } from 'react-router-dom'; import { Application, GetAppDetailsResponse, GetOverviewResponse, UndeploySummary } from '../../../api/api'; -import { fakeLoadEverything, enableDexAuth } from '../../../setupTests'; +import { enableDexAuth, fakeLoadEverything } from '../../../setupTests'; const mock_ServiceLane = Spy.mockReactComponents('../../components/ServiceLane/ServiceLane', 'ServiceLane'); @@ -70,22 +72,31 @@ describe('App', () => { }); updateAppDetails.set({ [sampleApps.app1.name]: { - application: sampleApps.app1, - deployments: {}, - appLocks: {}, - teamLocks: {}, + details: { + application: sampleApps.app1, + deployments: {}, + appLocks: {}, + teamLocks: {}, + }, + appDetailState: AppDetailsState.READY, }, [sampleApps.app2.name]: { - application: sampleApps.app2, - deployments: {}, - appLocks: {}, - teamLocks: {}, + details: { + application: sampleApps.app2, + deployments: {}, + appLocks: {}, + teamLocks: {}, + }, + appDetailState: AppDetailsState.READY, }, [sampleApps.app2.name]: { - application: sampleApps.app2, - deployments: {}, - appLocks: {}, - teamLocks: {}, + details: { + application: sampleApps.app2, + deployments: {}, + appLocks: {}, + teamLocks: {}, + }, + appDetailState: AppDetailsState.READY, }, }); fakeLoadEverything(true); @@ -155,22 +166,31 @@ describe('App', () => { }); updateAppDetails.set({ [sampleApps.app1.name]: { - application: sampleApps.app1, - deployments: {}, - appLocks: {}, - teamLocks: {}, + details: { + application: sampleApps.app1, + deployments: {}, + appLocks: {}, + teamLocks: {}, + }, + appDetailState: AppDetailsState.READY, }, [sampleApps.app2.name]: { - application: sampleApps.app2, - deployments: {}, - appLocks: {}, - teamLocks: {}, + details: { + application: sampleApps.app2, + deployments: {}, + appLocks: {}, + teamLocks: {}, + }, + appDetailState: AppDetailsState.READY, }, [sampleApps.app2.name]: { - application: sampleApps.app2, - deployments: {}, - appLocks: {}, - teamLocks: {}, + details: { + application: sampleApps.app2, + deployments: {}, + appLocks: {}, + teamLocks: {}, + }, + appDetailState: AppDetailsState.READY, }, }); fakeLoadEverything(true); @@ -452,7 +472,7 @@ describe('Get applications from selected teams (useApplicationsFilteredAndSorted selectedTeams: string[]; Overview: GetOverviewResponse; expectedNumOfTeams: number; - appDetails: { [key: string]: GetAppDetailsResponse }; + appDetails: { [key: string]: AppDetailsResponse }; } const data: dataT[] = [ @@ -485,56 +505,68 @@ describe('Get applications from selected teams (useApplicationsFilteredAndSorted }, appDetails: { foo: { - application: { - name: 'foo', - releases: [], - sourceRepoUrl: 'http://foo.com', - team: 'dummy', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'foo', + releases: [], + sourceRepoUrl: 'http://foo.com', + team: 'dummy', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, bar: { - application: { - name: 'bar', - releases: [], - sourceRepoUrl: 'http://bar.com', - team: 'test', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'bar', + releases: [], + sourceRepoUrl: 'http://bar.com', + team: 'test', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, example: { - application: { - name: 'example', - releases: [], - sourceRepoUrl: 'http://example.com', - team: 'test2', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'example', + releases: [], + sourceRepoUrl: 'http://example.com', + team: 'test2', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, team: { - application: { - name: 'team', - releases: [], - sourceRepoUrl: 'http://team.com', - team: 'foo', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'team', + releases: [], + sourceRepoUrl: 'http://team.com', + team: 'foo', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, }, expectedNumOfTeams: 2, @@ -565,43 +597,52 @@ describe('Get applications from selected teams (useApplicationsFilteredAndSorted expectedNumOfTeams: 2, appDetails: { foo: { - application: { - name: 'foo', - releases: [], - sourceRepoUrl: 'http://foo.com', - team: 'dummy', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'foo', + releases: [], + sourceRepoUrl: 'http://foo.com', + team: 'dummy', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, bar: { - application: { - name: 'bar', - releases: [], - sourceRepoUrl: 'http://bar.com', - team: 'test', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'bar', + releases: [], + sourceRepoUrl: 'http://bar.com', + team: 'test', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, team: { - application: { - name: 'team', - releases: [], - sourceRepoUrl: 'http://team.com', - team: 'foo', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'team', + releases: [], + sourceRepoUrl: 'http://team.com', + team: 'foo', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, }, }, @@ -634,43 +675,52 @@ describe('Get applications from selected teams (useApplicationsFilteredAndSorted }, appDetails: { foo: { - application: { - name: 'foo', - releases: [], - sourceRepoUrl: 'http://foo.com', - team: 'dummy', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'foo', + releases: [], + sourceRepoUrl: 'http://foo.com', + team: 'dummy', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, bar: { - application: { - name: 'bar', - releases: [], - sourceRepoUrl: 'http://bar.com', - team: 'test', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'bar', + releases: [], + sourceRepoUrl: 'http://bar.com', + team: 'test', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, team: { - application: { - name: 'team', - releases: [], - sourceRepoUrl: 'http://team.com', - team: 'foo', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'team', + releases: [], + sourceRepoUrl: 'http://team.com', + team: 'foo', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, }, expectedNumOfTeams: 4, @@ -696,30 +746,36 @@ describe('Get applications from selected teams (useApplicationsFilteredAndSorted }, appDetails: { foo: { - application: { - name: 'foo', - releases: [], - sourceRepoUrl: 'http://foo.com', - team: 'dummy', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'foo', + releases: [], + sourceRepoUrl: 'http://foo.com', + team: 'dummy', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, bar: { - application: { - name: 'bar', - releases: [], - sourceRepoUrl: 'http://bar.com', - team: 'test', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + details: { + application: { + name: 'bar', + releases: [], + sourceRepoUrl: 'http://bar.com', + team: 'test', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, + }, + appDetailState: AppDetailsState.READY, }, }, expectedNumOfTeams: 0, diff --git a/services/frontend-service/src/ui/Pages/ReleaseHistory/ReleaseHistoryPage.test.tsx b/services/frontend-service/src/ui/Pages/ReleaseHistory/ReleaseHistoryPage.test.tsx index faebd8f98..0c845a091 100644 --- a/services/frontend-service/src/ui/Pages/ReleaseHistory/ReleaseHistoryPage.test.tsx +++ b/services/frontend-service/src/ui/Pages/ReleaseHistory/ReleaseHistoryPage.test.tsx @@ -17,7 +17,7 @@ import { render } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; import { ReleaseHistoryPage } from './ReleaseHistoryPage'; import { fakeLoadEverything, enableDexAuth } from '../../../setupTests'; -import { updateAppDetails } from '../../utils/store'; +import { AppDetailsState, updateAppDetails } from '../../utils/store'; describe('ReleaseHistoryPage', () => { const getNode = (): JSX.Element | any => ( @@ -85,9 +85,12 @@ describe('ReleaseHistoryPage', () => { updateAppDetails.set({ '': { - deployments: {}, - appLocks: {}, - teamLocks: {}, + details: { + deployments: {}, + appLocks: {}, + teamLocks: {}, + }, + appDetailState: AppDetailsState.READY, }, }); const { container } = getWrapper(); diff --git a/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.test.tsx b/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.test.tsx index 11dc714da..db3b7c941 100644 --- a/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.test.tsx +++ b/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.test.tsx @@ -15,12 +15,17 @@ along with kuberpult. If not, see Copyright freiheit.com*/ import { ReleaseCard, ReleaseCardProps } from './ReleaseCard'; import { render } from '@testing-library/react'; -import { updateAppDetails, UpdateOverview, UpdateRolloutStatus } from '../../utils/store'; +import { + AppDetailsResponse, + AppDetailsState, + updateAppDetails, + UpdateOverview, + UpdateRolloutStatus, +} from '../../utils/store'; import { MemoryRouter } from 'react-router-dom'; import { Environment, EnvironmentGroup, - GetAppDetailsResponse, Priority, Release, RolloutStatus, @@ -47,7 +52,7 @@ describe('Release Card', () => { }; rels: Release[]; environments: { [key: string]: Environment }; - appDetails: { [key: string]: GetAppDetailsResponse }; + appDetails: { [key: string]: AppDetailsResponse }; }; const data: TestData[] = [ { @@ -55,30 +60,33 @@ describe('Release Card', () => { props: { app: 'test1', version: 2 }, appDetails: { test1: { - application: { - name: 'test1', - releases: [ - { - version: 2, - sourceMessage: 'test-rel', - undeployVersion: false, - sourceCommitId: 'commit123', - sourceAuthor: 'author', - prNumber: '666', - createdAt: new Date(2023, 6, 6), - displayVersion: '2', - isMinor: false, - isPrepublish: false, - }, - ], - team: 'test-team', - sourceRepoUrl: '', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], + details: { + application: { + name: 'test1', + releases: [ + { + version: 2, + sourceMessage: 'test-rel', + undeployVersion: false, + sourceCommitId: 'commit123', + sourceAuthor: 'author', + prNumber: '666', + createdAt: new Date(2023, 6, 6), + displayVersion: '2', + isMinor: false, + isPrepublish: false, + }, + ], + team: 'test-team', + sourceRepoUrl: '', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + deployments: {}, + appLocks: {}, + teamLocks: {}, }, - deployments: {}, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, rels: [ @@ -102,30 +110,33 @@ describe('Release Card', () => { props: { app: 'test2', version: 2 }, appDetails: { test2: { - application: { - name: 'test2', - releases: [ - { - undeployVersion: false, - version: 2, - sourceMessage: 'test-rel', - sourceCommitId: '12s3', - sourceAuthor: 'test-author', - prNumber: '666', - createdAt: new Date(2002), - displayVersion: '2', - isMinor: true, - isPrepublish: false, - }, - ], - team: 'test-team', - sourceRepoUrl: '', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], + details: { + application: { + name: 'test2', + releases: [ + { + undeployVersion: false, + version: 2, + sourceMessage: 'test-rel', + sourceCommitId: '12s3', + sourceAuthor: 'test-author', + prNumber: '666', + createdAt: new Date(2002), + displayVersion: '2', + isMinor: true, + isPrepublish: false, + }, + ], + team: 'test-team', + sourceRepoUrl: '', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + deployments: {}, + appLocks: {}, + teamLocks: {}, }, - deployments: {}, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, rels: [ @@ -149,36 +160,39 @@ describe('Release Card', () => { props: { app: 'test2', version: 2 }, appDetails: { test2: { - application: { - name: 'test2', - releases: [ - { - undeployVersion: false, + details: { + application: { + name: 'test2', + releases: [ + { + undeployVersion: false, + version: 2, + sourceMessage: 'test-rel', + sourceCommitId: '12s3', + sourceAuthor: 'test-author', + prNumber: '666', + createdAt: new Date(2002), + displayVersion: '2', + isMinor: true, + isPrepublish: false, + }, + ], + team: 'test-team', + sourceRepoUrl: '', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + deployments: { + foo: { version: 2, - sourceMessage: 'test-rel', - sourceCommitId: '12s3', - sourceAuthor: 'test-author', - prNumber: '666', - createdAt: new Date(2002), - displayVersion: '2', - isMinor: true, - isPrepublish: false, + queuedVersion: 0, + undeployVersion: false, }, - ], - team: 'test-team', - sourceRepoUrl: '', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - deployments: { - foo: { - version: 2, - queuedVersion: 0, - undeployVersion: false, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, rels: [ @@ -211,36 +225,39 @@ describe('Release Card', () => { props: { app: 'test2', version: 2 }, appDetails: { test2: { - application: { - name: 'test2', - releases: [ - { - undeployVersion: false, + details: { + application: { + name: 'test2', + releases: [ + { + undeployVersion: false, + version: 2, + sourceMessage: 'test-rel', + sourceCommitId: '12s3', + sourceAuthor: 'test-author', + prNumber: '666', + createdAt: new Date(2002), + displayVersion: '2', + isMinor: true, + isPrepublish: false, + }, + ], + team: 'test-team', + sourceRepoUrl: '', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + deployments: { + foo: { version: 2, - sourceMessage: 'test-rel', - sourceCommitId: '12s3', - sourceAuthor: 'test-author', - prNumber: '666', - createdAt: new Date(2002), - displayVersion: '2', - isMinor: true, - isPrepublish: false, + queuedVersion: 0, + undeployVersion: false, }, - ], - team: 'test-team', - sourceRepoUrl: '', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - deployments: { - foo: { - version: 2, - queuedVersion: 0, - undeployVersion: false, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, rels: [ @@ -273,36 +290,39 @@ describe('Release Card', () => { props: { app: 'test2', version: 2 }, appDetails: { test2: { - application: { - name: 'test2', - releases: [ - { + details: { + application: { + name: 'test2', + releases: [ + { + version: 2, + sourceMessage: 'test-rel', + sourceCommitId: 'commit123', + undeployVersion: false, + sourceAuthor: 'test-author', + prNumber: '666', + createdAt: new Date(2023, 6, 6), + displayVersion: '2', + isMinor: false, + isPrepublish: false, + }, + ], + team: 'test-team', + sourceRepoUrl: '', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + deployments: { + foo: { version: 2, - sourceMessage: 'test-rel', - sourceCommitId: 'commit123', + queuedVersion: 0, undeployVersion: false, - sourceAuthor: 'test-author', - prNumber: '666', - createdAt: new Date(2023, 6, 6), - displayVersion: '2', - isMinor: false, - isPrepublish: false, }, - ], - team: 'test-team', - sourceRepoUrl: '', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - deployments: { - foo: { - version: 2, - queuedVersion: 0, - undeployVersion: false, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, rels: [ @@ -335,36 +355,39 @@ describe('Release Card', () => { props: { app: 'test2', version: 2 }, appDetails: { test2: { - application: { - name: 'test2', - releases: [ - { - undeployVersion: false, + details: { + application: { + name: 'test2', + releases: [ + { + undeployVersion: false, + version: 2, + sourceMessage: 'test-rel', + sourceCommitId: '12s3', + sourceAuthor: 'test-author', + prNumber: '666', + createdAt: new Date(2002), + displayVersion: '2', + isMinor: true, + isPrepublish: true, + }, + ], + team: 'test-team', + sourceRepoUrl: '', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + deployments: { + foo: { version: 2, - sourceMessage: 'test-rel', - sourceCommitId: '12s3', - sourceAuthor: 'test-author', - prNumber: '666', - createdAt: new Date(2002), - displayVersion: '2', - isMinor: true, - isPrepublish: true, + queuedVersion: 0, + undeployVersion: false, }, - ], - team: 'test-team', - sourceRepoUrl: '', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - deployments: { - foo: { - version: 2, - queuedVersion: 0, - undeployVersion: false, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, rels: [ @@ -450,7 +473,7 @@ describe('Release Card Rollout Status', () => { rolloutStatus: StreamStatusResponse[]; expectedStatusIcon: RolloutStatus; expectedRolloutDetails: { [name: string]: RolloutStatus }; - appDetails: { [key: string]: GetAppDetailsResponse }; + appDetails: { [key: string]: AppDetailsResponse }; }; const data: TestData[] = [ { @@ -458,46 +481,49 @@ describe('Release Card Rollout Status', () => { props: { app: 'test1', version: 2 }, appDetails: { test1: { - application: { - name: '', - releases: [ - { + details: { + application: { + name: '', + releases: [ + { + version: 2, + sourceMessage: 'test-rel', + undeployVersion: false, + sourceCommitId: 'commit123', + sourceAuthor: 'author', + prNumber: '666', + createdAt: new Date(2023, 6, 6), + displayVersion: '2', + isMinor: false, + isPrepublish: false, + }, + ], + team: 'test-team', + sourceRepoUrl: '', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + deployments: { + development: { version: 2, - sourceMessage: 'test-rel', + queuedVersion: 0, + undeployVersion: false, + }, + development2: { + version: 2, + queuedVersion: 0, + undeployVersion: false, + }, + staging: { + version: 2, + queuedVersion: 0, undeployVersion: false, - sourceCommitId: 'commit123', - sourceAuthor: 'author', - prNumber: '666', - createdAt: new Date(2023, 6, 6), - displayVersion: '2', - isMinor: false, - isPrepublish: false, }, - ], - team: 'test-team', - sourceRepoUrl: '', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - deployments: { - development: { - version: 2, - queuedVersion: 0, - undeployVersion: false, - }, - development2: { - version: 2, - queuedVersion: 0, - undeployVersion: false, - }, - staging: { - version: 2, - queuedVersion: 0, - undeployVersion: false, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, rels: [ diff --git a/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.tsx b/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.tsx index 279a974c7..2eabf056e 100644 --- a/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.tsx +++ b/services/frontend-service/src/ui/components/ReleaseCard/ReleaseCard.tsx @@ -93,7 +93,7 @@ const useDeploymentStatus = ( const groups: { [envGroup: string]: RolloutStatus } = {}; deployedAt.forEach((envGroup) => { const status = envGroup.environments.reduce((cur: RolloutStatus | undefined, env) => { - const appVersion = appDetails.deployments[env.name].version; + const appVersion = appDetails.details?.deployments[env.name].version; const status = getter.getAppStatus(app, appVersion, env.name); if (cur === undefined) { return status; diff --git a/services/frontend-service/src/ui/components/ReleaseCardMini/ReleaseCardMini.test.tsx b/services/frontend-service/src/ui/components/ReleaseCardMini/ReleaseCardMini.test.tsx index ef6b255de..9e06fcf41 100644 --- a/services/frontend-service/src/ui/components/ReleaseCardMini/ReleaseCardMini.test.tsx +++ b/services/frontend-service/src/ui/components/ReleaseCardMini/ReleaseCardMini.test.tsx @@ -15,7 +15,7 @@ along with kuberpult. If not, see Copyright freiheit.com*/ import { ReleaseCardMini, ReleaseCardMiniProps } from './ReleaseCardMini'; import { render } from '@testing-library/react'; -import { updateAppDetails, UpdateOverview } from '../../utils/store'; +import { AppDetailsState, updateAppDetails, UpdateOverview } from '../../utils/store'; import { MemoryRouter } from 'react-router-dom'; import { Environment, Priority, Release, UndeploySummary } from '../../../api/api'; import { Spy } from 'spy4js'; @@ -127,23 +127,26 @@ describe('Release Card Mini', () => { updateAppDetails.set({ test2: { - application: { - name: 'test2', - releases: testcase.rels, - sourceRepoUrl: 'http://test2.com', - team: 'example', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - deployments: { - other: { - version: 2, - queuedVersion: 0, - undeployVersion: false, + details: { + application: { + name: 'test2', + releases: testcase.rels, + sourceRepoUrl: 'http://test2.com', + team: 'example', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], }, + deployments: { + other: { + version: 2, + queuedVersion: 0, + undeployVersion: false, + }, + }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }); const { container } = getWrapper(testcase.props); diff --git a/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.test.tsx b/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.test.tsx index 46ddeac8a..fa2e5029d 100644 --- a/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.test.tsx +++ b/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.test.tsx @@ -15,16 +15,15 @@ along with kuberpult. If not, see Copyright freiheit.com*/ import { EnvironmentListItem, ReleaseDialog, ReleaseDialogProps } from './ReleaseDialog'; import { fireEvent, render } from '@testing-library/react'; -import { UpdateAction, updateAppDetails, UpdateOverview, UpdateRolloutStatus } from '../../utils/store'; import { - Environment, - EnvironmentGroup, - GetAppDetailsResponse, - Priority, - Release, - RolloutStatus, - UndeploySummary, -} from '../../../api/api'; + AppDetailsResponse, + AppDetailsState, + UpdateAction, + updateAppDetails, + UpdateOverview, + UpdateRolloutStatus, +} from '../../utils/store'; +import { Environment, EnvironmentGroup, Priority, Release, RolloutStatus, UndeploySummary } from '../../../api/api'; import { Spy } from 'spy4js'; import { MemoryRouter } from 'react-router-dom'; @@ -41,7 +40,7 @@ describe('Release Dialog', () => { interface dataT { name: string; props: ReleaseDialogProps; - appDetails: { [p: string]: GetAppDetailsResponse }; + appDetails: { [p: string]: AppDetailsResponse }; rels: Release[]; envs: Environment[]; envGroups: EnvironmentGroup[]; @@ -61,7 +60,7 @@ describe('Release Dialog', () => { props: ReleaseDialogProps; rels: Release[]; envs: Environment[]; - appDetails: { [p: string]: GetAppDetailsResponse }; + appDetails: { [p: string]: AppDetailsResponse }; envGroups: EnvironmentGroup[]; expect_message: boolean; expect_queues: number; @@ -169,40 +168,43 @@ describe('Release Dialog', () => { }, appDetails: { test1: { - application: { - name: 'test1', - releases: [ - { - version: 2, - sourceMessage: 'test1', - sourceAuthor: 'test', - sourceCommitId: 'commit', - createdAt: new Date(2002), - undeployVersion: false, - prNumber: '#1337', - displayVersion: '2', - isMinor: false, - isPrepublish: false, + details: { + application: { + name: 'test1', + releases: [ + { + version: 2, + sourceMessage: 'test1', + sourceAuthor: 'test', + sourceCommitId: 'commit', + createdAt: new Date(2002), + undeployVersion: false, + prNumber: '#1337', + displayVersion: '2', + isMinor: false, + isPrepublish: false, + }, + ], + sourceRepoUrl: 'http://test2.com', + team: 'example', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: { + production: { + locks: [{ message: 'appLock', lockId: 'ui-applock' }], }, - ], - sourceRepoUrl: 'http://test2.com', - team: 'example', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: { - production: { - locks: [{ message: 'appLock', lockId: 'ui-applock' }], }, - }, - teamLocks: {}, - deployments: { - dev: { - version: 1, - queuedVersion: 0, - undeployVersion: false, + teamLocks: {}, + deployments: { + dev: { + version: 1, + queuedVersion: 0, + undeployVersion: false, + }, }, }, + appDetailState: AppDetailsState.READY, }, }, rels: [ @@ -255,40 +257,43 @@ describe('Release Dialog', () => { }, appDetails: { test1: { - application: { - name: 'test1', - releases: [ - { - version: 2, - sourceMessage: 'test1', - sourceAuthor: 'test', - sourceCommitId: 'commit', - createdAt: new Date(2002), - undeployVersion: false, - prNumber: '#1337', - displayVersion: '2', - isMinor: false, - isPrepublish: false, + details: { + application: { + name: 'test1', + releases: [ + { + version: 2, + sourceMessage: 'test1', + sourceAuthor: 'test', + sourceCommitId: 'commit', + createdAt: new Date(2002), + undeployVersion: false, + prNumber: '#1337', + displayVersion: '2', + isMinor: false, + isPrepublish: false, + }, + ], + sourceRepoUrl: 'http://test2.com', + team: 'example', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: { + production: { + locks: [{ message: 'appLock', lockId: 'ui-applock' }], }, - ], - sourceRepoUrl: 'http://test2.com', - team: 'example', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: { - production: { - locks: [{ message: 'appLock', lockId: 'ui-applock' }], }, - }, - teamLocks: {}, - deployments: { - dev: { - version: 1, - queuedVersion: 0, - undeployVersion: false, + teamLocks: {}, + deployments: { + dev: { + version: 1, + queuedVersion: 0, + undeployVersion: false, + }, }, }, + appDetailState: AppDetailsState.READY, }, }, rels: [ @@ -339,64 +344,67 @@ describe('Release Dialog', () => { }, appDetails: { test1: { - application: { - name: 'test1', - releases: [ - { - sourceCommitId: 'cafe', - sourceMessage: 'the other commit message 2', + details: { + application: { + name: 'test1', + releases: [ + { + sourceCommitId: 'cafe', + sourceMessage: 'the other commit message 2', + version: 2, + createdAt: new Date(2002), + undeployVersion: false, + prNumber: 'PR123', + sourceAuthor: 'nobody', + displayVersion: '2', + isMinor: false, + isPrepublish: false, + }, + { + sourceCommitId: 'cafe', + sourceMessage: 'the other commit message 3', + version: 3, + createdAt: new Date(2002), + undeployVersion: false, + prNumber: 'PR123', + sourceAuthor: 'nobody', + displayVersion: '3', + isMinor: false, + isPrepublish: false, + }, + ], + sourceRepoUrl: 'http://test2.com', + team: 'example', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: { + production: { + locks: [{ message: 'appLock', lockId: 'ui-applock' }], + }, + dev: { + locks: [{ message: 'appLock', lockId: 'ui-applock' }], + }, + }, + teamLocks: { + dev: { + locks: [{ message: 'teamLock', lockId: 'ui-teamlock' }], + }, + }, + deployments: { + prod: { version: 2, - createdAt: new Date(2002), + queuedVersion: 0, undeployVersion: false, - prNumber: 'PR123', - sourceAuthor: 'nobody', - displayVersion: '2', - isMinor: false, - isPrepublish: false, }, - { - sourceCommitId: 'cafe', - sourceMessage: 'the other commit message 3', + dev: { version: 3, - createdAt: new Date(2002), + queuedVersion: 666, undeployVersion: false, - prNumber: 'PR123', - sourceAuthor: 'nobody', - displayVersion: '3', - isMinor: false, - isPrepublish: false, }, - ], - sourceRepoUrl: 'http://test2.com', - team: 'example', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: { - production: { - locks: [{ message: 'appLock', lockId: 'ui-applock' }], - }, - dev: { - locks: [{ message: 'appLock', lockId: 'ui-applock' }], - }, - }, - teamLocks: { - dev: { - locks: [{ message: 'teamLock', lockId: 'ui-teamlock' }], - }, - }, - deployments: { - prod: { - version: 2, - queuedVersion: 0, - undeployVersion: false, - }, - dev: { - version: 3, - queuedVersion: 666, - undeployVersion: false, }, }, + appDetailState: AppDetailsState.READY, }, }, envs: [ @@ -491,30 +499,33 @@ describe('Release Dialog', () => { }, appDetails: { test1: { - application: { - name: 'test1', - releases: [ - { - version: 4, - sourceAuthor: 'test1', - sourceMessage: '', - sourceCommitId: '', - prNumber: '', - createdAt: new Date(2002), - undeployVersion: true, - displayVersion: '4', - isMinor: false, - isPrepublish: false, - }, - ], - sourceRepoUrl: 'http://test2.com', - team: 'example', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], + details: { + application: { + name: 'test1', + releases: [ + { + version: 4, + sourceAuthor: 'test1', + sourceMessage: '', + sourceCommitId: '', + prNumber: '', + createdAt: new Date(2002), + undeployVersion: true, + displayVersion: '4', + isMinor: false, + isPrepublish: false, + }, + ], + sourceRepoUrl: 'http://test2.com', + team: 'example', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + appDetailState: AppDetailsState.READY, }, }, rels: [ diff --git a/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.tsx b/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.tsx index eaa925556..8bd271239 100644 --- a/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.tsx +++ b/services/frontend-service/src/ui/components/ReleaseDialog/ReleaseDialog.tsx @@ -108,7 +108,7 @@ export type EnvironmentListItemProps = { }; type CommitIdProps = { - deployment: Deployment; + deployment: Deployment | undefined; app: string; env: Environment; otherRelease?: Release; @@ -191,7 +191,7 @@ export const EnvironmentListItem: React.FC = ({ ); const otherRelease = useReleaseOptional(app, env); const appDetails = useAppDetailsForApp(app); - const deployment = appDetails.deployments[env.name]; + const deployment = appDetails.details?.deployments[env.name]; const getDeploymentMetadata = (): [String, JSX.Element] => { if (!deployment) { @@ -353,7 +353,7 @@ export const ReleaseDialog: React.FC = (props) => { if (!appDetails) { return null; } - const release = appDetails.application?.releases.find((r) => r.version === version); + const release = appDetails.details?.application?.releases.find((r) => r.version === version); if (!release) { return null; @@ -558,7 +558,9 @@ export const EnvironmentGroupLane: React.FC<{ team={team} className={priorityClassName} queuedVersion={ - appDetails.deployments[env.name] ? appDetails.deployments[env.name].queuedVersion : 0 + appDetails.details?.deployments[env.name] + ? appDetails.details?.deployments[env.name].queuedVersion + : 0 } /> ))} diff --git a/services/frontend-service/src/ui/components/ReleaseTrainPrognosis/ReleaseTrainPrognosis.test.tsx b/services/frontend-service/src/ui/components/ReleaseTrainPrognosis/ReleaseTrainPrognosis.test.tsx index 6701138ee..2611e4467 100644 --- a/services/frontend-service/src/ui/components/ReleaseTrainPrognosis/ReleaseTrainPrognosis.test.tsx +++ b/services/frontend-service/src/ui/components/ReleaseTrainPrognosis/ReleaseTrainPrognosis.test.tsx @@ -19,13 +19,12 @@ import { ReleaseTrainPrognosis } from '../../components/ReleaseTrainPrognosis/Re import { render } from '@testing-library/react'; import { Application, - GetAppDetailsResponse, GetReleaseTrainPrognosisResponse, ReleaseTrainAppSkipCause, ReleaseTrainEnvSkipCause, UndeploySummary, } from '../../../api/api'; -import { updateAppDetails, UpdateOverview } from '../../utils/store'; +import { AppDetailsResponse, AppDetailsState, updateAppDetails, UpdateOverview } from '../../utils/store'; test('ReleaseTrain component does not render anything if the response is undefined', () => { const { container } = render( @@ -56,7 +55,7 @@ describe('ReleaseTrain component renders release train prognosis when the respon [key: string]: Application; }; appDetails: { - [key: string]: GetAppDetailsResponse; + [key: string]: AppDetailsResponse; }; }; @@ -252,54 +251,60 @@ describe('ReleaseTrain component renders release train prognosis when the respon name: 'prognosis with some deployed apps', appDetails: { 'app-1': { - application: { - name: 'app-1', - sourceRepoUrl: 'some url', - team: 'some team', - undeploySummary: UndeploySummary.UNRECOGNIZED, - warnings: [], - releases: [ - { - version: 1, - displayVersion: 'some display version', - prNumber: 'some pr number', - sourceAuthor: 'some source author', - sourceCommitId: 'aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd', - sourceMessage: 'some source message', - undeployVersion: false, - isMinor: false, - isPrepublish: false, - }, - ], + details: { + application: { + name: 'app-1', + sourceRepoUrl: 'some url', + team: 'some team', + undeploySummary: UndeploySummary.UNRECOGNIZED, + warnings: [], + releases: [ + { + version: 1, + displayVersion: 'some display version', + prNumber: 'some pr number', + sourceAuthor: 'some source author', + sourceCommitId: 'aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd', + sourceMessage: 'some source message', + undeployVersion: false, + isMinor: false, + isPrepublish: false, + }, + ], + }, + deployments: {}, + appLocks: {}, + teamLocks: {}, }, - deployments: {}, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, 'app-3': { - application: { - name: 'app-3', - sourceRepoUrl: 'some url', - team: 'some team', - undeploySummary: UndeploySummary.UNRECOGNIZED, - warnings: [], - releases: [ - { - version: 1, - displayVersion: 'some display version', - prNumber: 'some pr number', - sourceAuthor: 'some source author', - sourceCommitId: '0000000000111111111122222222223333333333', - sourceMessage: 'some source message', - undeployVersion: false, - isMinor: false, - isPrepublish: false, - }, - ], + details: { + application: { + name: 'app-3', + sourceRepoUrl: 'some url', + team: 'some team', + undeploySummary: UndeploySummary.UNRECOGNIZED, + warnings: [], + releases: [ + { + version: 1, + displayVersion: 'some display version', + prNumber: 'some pr number', + sourceAuthor: 'some source author', + sourceCommitId: '0000000000111111111122222222223333333333', + sourceMessage: 'some source message', + undeployVersion: false, + isMinor: false, + isPrepublish: false, + }, + ], + }, + deployments: {}, + appLocks: {}, + teamLocks: {}, }, - deployments: {}, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, applicationsOverview: { diff --git a/services/frontend-service/src/ui/components/Releases/Releases.test.tsx b/services/frontend-service/src/ui/components/Releases/Releases.test.tsx index f2a404fdd..08d799ad2 100644 --- a/services/frontend-service/src/ui/components/Releases/Releases.test.tsx +++ b/services/frontend-service/src/ui/components/Releases/Releases.test.tsx @@ -15,16 +15,15 @@ along with kuberpult. If not, see Copyright freiheit.com*/ import { Releases } from './Releases'; import { render } from '@testing-library/react'; -import { updateAppDetails, UpdateOverview } from '../../utils/store'; +import { AppDetailsResponse, AppDetailsState, updateAppDetails, UpdateOverview } from '../../utils/store'; import { Environment, EnvironmentGroup, Lock, + OverviewApplication, Priority, Release, UndeploySummary, - GetAppDetailsResponse, - OverviewApplication, } from '../../../api/api'; import { MemoryRouter } from 'react-router-dom'; @@ -36,7 +35,7 @@ describe('Release Dialog', () => { OverviewApps: OverviewApplication[]; envGroups: EnvironmentGroup[]; expectedAppLocksLength: number; - appDetails: { [p: string]: GetAppDetailsResponse }; + appDetails: { [p: string]: AppDetailsResponse }; }; const releases = [ @@ -97,28 +96,31 @@ describe('Release Dialog', () => { createdBy: { name: 'test', email: 'test' }, }; - const app1Details: GetAppDetailsResponse = { - application: { - name: 'test', - releases: releases, - sourceRepoUrl: 'http://test2.com', - team: 'example', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - appLocks: { - dev: { - locks: [testAppLock], + const app1Details: AppDetailsResponse = { + details: { + application: { + name: 'test', + releases: releases, + sourceRepoUrl: 'http://test2.com', + team: 'example', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], }, - }, - teamLocks: {}, - deployments: { - dev: { - version: 1, - queuedVersion: 0, - undeployVersion: false, + appLocks: { + dev: { + locks: [testAppLock], + }, + }, + teamLocks: {}, + deployments: { + dev: { + version: 1, + queuedVersion: 0, + undeployVersion: false, + }, }, }, + appDetailState: AppDetailsState.READY, }; const testEnv1: Environment = { @@ -168,8 +170,8 @@ describe('Release Dialog', () => { }, OverviewApps: [ { - name: app1Details.application?.name || '', - team: app1Details.application?.team || '', + name: app1Details.details?.application?.name || '', + team: app1Details.details?.application?.team || '', }, ], name: '3 releases in 3 days', @@ -226,54 +228,57 @@ describe('Release Dialog', () => { ], appDetails: { test: { - application: { - name: 'test', - releases: [ - { - version: 1, - sourceMessage: 'test1', - sourceAuthor: 'test', - sourceCommitId: 'commit', - createdAt: new Date('2022-12-04T12:30:12'), - undeployVersion: false, - prNumber: '666', - displayVersion: '1', - isMinor: false, - isPrepublish: false, - }, - { - version: 2, - sourceMessage: 'test1', - sourceAuthor: 'test', - sourceCommitId: 'commit', - createdAt: new Date('2022-12-04T15:30:12'), - undeployVersion: false, - prNumber: '666', - displayVersion: '2', - isMinor: false, - isPrepublish: false, - }, - { - version: 3, - sourceMessage: 'test1', - sourceAuthor: 'test', - sourceCommitId: 'commit', - createdAt: new Date('2022-12-06T12:30:12'), - undeployVersion: false, - prNumber: '666', - displayVersion: '3', - isMinor: false, - isPrepublish: false, - }, - ], - sourceRepoUrl: 'http://test2.com', - team: 'example', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], + details: { + application: { + name: 'test', + releases: [ + { + version: 1, + sourceMessage: 'test1', + sourceAuthor: 'test', + sourceCommitId: 'commit', + createdAt: new Date('2022-12-04T12:30:12'), + undeployVersion: false, + prNumber: '666', + displayVersion: '1', + isMinor: false, + isPrepublish: false, + }, + { + version: 2, + sourceMessage: 'test1', + sourceAuthor: 'test', + sourceCommitId: 'commit', + createdAt: new Date('2022-12-04T15:30:12'), + undeployVersion: false, + prNumber: '666', + displayVersion: '2', + isMinor: false, + isPrepublish: false, + }, + { + version: 3, + sourceMessage: 'test1', + sourceAuthor: 'test', + sourceCommitId: 'commit', + createdAt: new Date('2022-12-06T12:30:12'), + undeployVersion: false, + prNumber: '666', + displayVersion: '3', + isMinor: false, + isPrepublish: false, + }, + ], + sourceRepoUrl: 'http://test2.com', + team: 'example', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + appDetailState: AppDetailsState.READY, }, }, releases: [ @@ -328,17 +333,20 @@ describe('Release Dialog', () => { ], appDetails: { test: { - application: { - name: 'test', - releases: [], - sourceRepoUrl: 'http://test2.com', - team: 'example', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], + details: { + application: { + name: 'test', + releases: [], + sourceRepoUrl: 'http://test2.com', + team: 'example', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + appLocks: {}, + teamLocks: {}, + deployments: {}, }, - appLocks: {}, - teamLocks: {}, - deployments: {}, + appDetailState: AppDetailsState.READY, }, }, releases: [], diff --git a/services/frontend-service/src/ui/components/Releases/Releases.tsx b/services/frontend-service/src/ui/components/Releases/Releases.tsx index 413ade1c4..c62ee81aa 100644 --- a/services/frontend-service/src/ui/components/Releases/Releases.tsx +++ b/services/frontend-service/src/ui/components/Releases/Releases.tsx @@ -51,7 +51,7 @@ const getReleasesForAppGroupByDate = (releases: Array | undefined): [Re export const Releases: React.FC = (props) => { const { app, className } = props; - const releases = useAppDetailsForApp(app).application?.releases; + const releases = useAppDetailsForApp(app).details?.application?.releases; const displayAppLocks = useDisplayApplicationLocks(app); const rel = getReleasesForAppGroupByDate(releases); diff --git a/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.test.tsx b/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.test.tsx index c4cb3e66c..8276c19db 100644 --- a/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.test.tsx +++ b/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.test.tsx @@ -13,9 +13,9 @@ You should have received a copy of the MIT License along with kuberpult. If not, see . Copyright freiheit.com*/ -import { render, screen, fireEvent } from '@testing-library/react'; -import { ServiceLane, DiffElement } from './ServiceLane'; -import { UpdateOverview, updateAppDetails } from '../../utils/store'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { DiffElement, ServiceLane } from './ServiceLane'; +import { AppDetailsResponse, AppDetailsState, updateAppDetails, UpdateOverview } from '../../utils/store'; import { Spy } from 'spy4js'; import { Application, @@ -47,14 +47,42 @@ const extendRelease = (props: Partial): Release => ({ }); describe('Service Lane', () => { - const getNode = (overrides: { application: OverviewApplication }) => ( + const getNode = (overrides: { + application: OverviewApplication; + allAppDetails: { [p: string]: AppDetailsResponse }; + }) => ( ); - const getWrapper = (overrides: { application: OverviewApplication }) => render(getNode(overrides)); + const getWrapper = (overrides: { + application: OverviewApplication; + allAppDetails: { [p: string]: AppDetailsResponse }; + }) => render(getNode(overrides)); it('Renders a row of releases', () => { // when + const appDetails = { + test2: { + details: { + application: { + name: 'test2', + releases: [ + extendRelease({ version: 2 }), + extendRelease({ version: 3 }), + extendRelease({ version: 5 }), + ], + sourceRepoUrl: 'http://test2.com', + team: 'example', + undeploySummary: UndeploySummary.NORMAL, + warnings: [], + }, + deployments: {}, + appLocks: {}, + teamLocks: {}, + }, + appDetailState: AppDetailsState.READY, + }, + }; const sampleApp: Application = { name: 'test2', releases: [extendRelease({ version: 5 }), extendRelease({ version: 2 }), extendRelease({ version: 3 })], @@ -68,26 +96,8 @@ describe('Service Lane', () => { team: '', }; UpdateOverview.set({}); - updateAppDetails.set({ - test2: { - application: { - name: 'test2', - releases: [ - extendRelease({ version: 2 }), - extendRelease({ version: 3 }), - extendRelease({ version: 5 }), - ], - sourceRepoUrl: 'http://test2.com', - team: 'example', - undeploySummary: UndeploySummary.NORMAL, - warnings: [], - }, - deployments: {}, - appLocks: {}, - teamLocks: {}, - }, - }); - getWrapper({ application: sampleLightWeightApp }); + updateAppDetails.set(appDetails); + getWrapper({ application: sampleLightWeightApp, allAppDetails: appDetails }); // then releases are sorted and Release card is called with props: expect(mock_ReleaseCard.ReleaseCard.getCallArgument(0, 0)).toStrictEqual({ app: sampleApp.name, version: 5 }); @@ -102,7 +112,7 @@ type TestData = { envs: Environment[]; }; -type TestDataDiff = TestData & { diff: string; releases: Release[]; appDetails: GetAppDetailsResponse }; +type TestDataDiff = TestData & { diff: string; releases: Release[]; appDetails: AppDetailsResponse }; const data: TestDataDiff[] = [ { @@ -110,28 +120,31 @@ const data: TestDataDiff[] = [ diff: '-1', releases: [makeRelease(1)], appDetails: { - application: { - name: 'test2', - team: 'test-team', - releases: [makeRelease(1)], - sourceRepoUrl: '', - undeploySummary: UndeploySummary.MIXED, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: { - foo: { - version: 1, - queuedVersion: 0, - undeployVersion: false, + details: { + application: { + name: 'test2', + team: 'test-team', + releases: [makeRelease(1)], + sourceRepoUrl: '', + undeploySummary: UndeploySummary.MIXED, + warnings: [], }, - foo2: { - version: 1, - queuedVersion: 0, - undeployVersion: false, + appLocks: {}, + teamLocks: {}, + deployments: { + foo: { + version: 1, + queuedVersion: 0, + undeployVersion: false, + }, + foo2: { + version: 1, + queuedVersion: 0, + undeployVersion: false, + }, }, }, + appDetailState: AppDetailsState.READY, }, envs: [ { @@ -157,28 +170,31 @@ const data: TestDataDiff[] = [ diff: '0', releases: [makeRelease(1), makeRelease(2)], appDetails: { - application: { - name: 'test2', - team: 'test-team', - releases: [makeRelease(1), makeRelease(2)], - sourceRepoUrl: '', - undeploySummary: UndeploySummary.MIXED, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: { - foo: { - version: 1, - queuedVersion: 0, - undeployVersion: false, + details: { + application: { + name: 'test2', + team: 'test-team', + releases: [makeRelease(1), makeRelease(2)], + sourceRepoUrl: '', + undeploySummary: UndeploySummary.MIXED, + warnings: [], }, - foo2: { - version: 2, - queuedVersion: 0, - undeployVersion: false, + appLocks: {}, + teamLocks: {}, + deployments: { + foo: { + version: 1, + queuedVersion: 0, + undeployVersion: false, + }, + foo2: { + version: 2, + queuedVersion: 0, + undeployVersion: false, + }, }, }, + appDetailState: AppDetailsState.READY, }, envs: [ { @@ -204,28 +220,31 @@ const data: TestDataDiff[] = [ diff: '1', releases: [makeRelease(1), makeRelease(2), makeRelease(4)], appDetails: { - application: { - name: 'test2', - team: 'test-team', - releases: [makeRelease(4), makeRelease(2), makeRelease(1)], - sourceRepoUrl: '', - undeploySummary: UndeploySummary.MIXED, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: { - foo: { - version: 1, - queuedVersion: 0, - undeployVersion: false, + details: { + application: { + name: 'test2', + team: 'test-team', + releases: [makeRelease(4), makeRelease(2), makeRelease(1)], + sourceRepoUrl: '', + undeploySummary: UndeploySummary.MIXED, + warnings: [], }, - foo2: { - version: 4, - queuedVersion: 0, - undeployVersion: false, + appLocks: {}, + teamLocks: {}, + deployments: { + foo: { + version: 1, + queuedVersion: 0, + undeployVersion: false, + }, + foo2: { + version: 4, + queuedVersion: 0, + undeployVersion: false, + }, }, }, + appDetailState: AppDetailsState.READY, }, envs: [ { @@ -251,28 +270,31 @@ const data: TestDataDiff[] = [ diff: '2', releases: [makeRelease(2), makeRelease(4), makeRelease(3), makeRelease(5)], appDetails: { - application: { - name: 'test2', - team: 'test-team', - releases: [makeRelease(2), makeRelease(3), makeRelease(4), makeRelease(5)], - sourceRepoUrl: '', - undeploySummary: UndeploySummary.MIXED, - warnings: [], - }, - appLocks: {}, - teamLocks: {}, - deployments: { - foo: { - version: 2, - queuedVersion: 0, - undeployVersion: false, + details: { + application: { + name: 'test2', + team: 'test-team', + releases: [makeRelease(2), makeRelease(3), makeRelease(4), makeRelease(5)], + sourceRepoUrl: '', + undeploySummary: UndeploySummary.MIXED, + warnings: [], }, - foo2: { - version: 5, - queuedVersion: 0, - undeployVersion: false, + appLocks: {}, + teamLocks: {}, + deployments: { + foo: { + version: 2, + queuedVersion: 0, + undeployVersion: false, + }, + foo2: { + version: 5, + queuedVersion: 0, + undeployVersion: false, + }, }, }, + appDetailState: AppDetailsState.READY, }, envs: [ { @@ -447,16 +469,19 @@ describe('Service Lane Important Releases', () => { }); updateAppDetails.set({ test2: { - application: sampleApp, - deployments: { - foo: { - version: testcase.currentlyDeployedVersion, - undeployVersion: false, - queuedVersion: 0, + details: { + application: sampleApp, + deployments: { + foo: { + version: testcase.currentlyDeployedVersion, + undeployVersion: false, + queuedVersion: 0, + }, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }); // when @@ -583,10 +608,13 @@ describe('Service Lane ⋮ menu', () => { updateAppDetails.set({ test1: { - application: testcase.renderedApp, - deployments: {}, - appLocks: {}, - teamLocks: {}, + details: { + application: testcase.renderedApp, + deployments: {}, + appLocks: {}, + teamLocks: {}, + }, + appDetailState: AppDetailsState.READY, }, }); @@ -815,7 +843,10 @@ describe('Service Lane AppLockSummary', () => { }); updateAppDetails.set({ - test1: testcase.renderedApp, + test1: { + details: testcase.renderedApp, + appDetailState: AppDetailsState.READY, + }, }); const { container } = getWrapper({ diff --git a/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.tsx b/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.tsx index c51ddefa4..5e16286d0 100644 --- a/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.tsx +++ b/services/frontend-service/src/ui/components/ServiceLane/ServiceLane.tsx @@ -15,6 +15,8 @@ along with kuberpult. If not, see Copyright freiheit.com*/ import { addAction, + AppDetailsResponse, + AppDetailsState, EnvironmentGroupExtended, getAppDetails, showSnackbarError, @@ -33,7 +35,7 @@ import { AppLockSummary } from '../chip/EnvironmentGroupChip'; import { WarningBoxes } from './Warnings'; import { DotsMenu, DotsMenuButton } from './DotsMenu'; import { EnvSelectionDialog } from '../SelectionDialog/SelectionDialogs'; -import { useAzureAuthSub } from '../../utils/AzureAuthProvider'; +import { AuthHeader, useAzureAuthSub } from '../../utils/AzureAuthProvider'; import { SmallSpinner } from '../Spinner/Spinner'; // number of releases on home. based on design @@ -104,18 +106,34 @@ const deriveUndeployMessage = (undeploySummary: UndeploySummary | undefined): st } }; -export const ServiceLane: React.FC<{ application: OverviewApplication; hideMinors: boolean }> = (props) => { +export const ServiceLane: React.FC<{ + application: OverviewApplication; + hideMinors: boolean; +}> = (props) => { const { application, hideMinors } = props; const { authHeader } = useAzureAuthSub((auth) => auth); const appDetails = useAppDetailsForApp(application.name); + const componentRef: React.MutableRefObject = React.useRef(); + React.useEffect(() => { - getAppDetails(application.name, authHeader); - }, [application, authHeader]); + const handleScroll = (): void => { + getAppDetailsIfInView(componentRef, appDetails, authHeader, application.name); + }; + handleScroll(); + if (document.getElementsByClassName('mdc-drawer-app-content').length !== 0) { + document.getElementsByClassName('mdc-drawer-app-content')[0].addEventListener('scroll', handleScroll); + return () => { + document + .getElementsByClassName('mdc-drawer-app-content')[0] + .removeEventListener('scroll', handleScroll); + }; + } + }, [appDetails, application, authHeader]); - if (!appDetails) { + if (!appDetails || !appDetails.details) { return ( -
+
@@ -131,14 +149,32 @@ export const ServiceLane: React.FC<{ application: OverviewApplication; hideMinor } return ( - +
+ +
); }; +function getAppDetailsIfInView( + componentRef: React.MutableRefObject, + appDetails: AppDetailsResponse, + authHeader: AuthHeader, + appName: string +): void { + if (componentRef.current !== null) { + const rect = componentRef.current.getBoundingClientRect(); + if (rect.top >= 0 && rect.bottom <= window.innerHeight) { + if (appDetails.appDetailState === AppDetailsState.NOTREQUESTED) { + getAppDetails(appName, authHeader); + } + } + } +} + export const ReadyServiceLane: React.FC<{ application: OverviewApplication; hideMinors: boolean; @@ -267,8 +303,8 @@ export const ReadyServiceLane: React.FC<{ } const dotsMenu = ; - const appLocks = Object.values(useAppDetailsForApp(application.name).appLocks); - const teamLocks = Object.values(useAppDetailsForApp(application.name).teamLocks); + const appLocks = Object.values(props.appDetails.appLocks); + const teamLocks = Object.values(props.appDetails.teamLocks); const dialog = ( e.name)} diff --git a/services/frontend-service/src/ui/utils/store.test.tsx b/services/frontend-service/src/ui/utils/store.test.tsx index 08aacb6d5..91d6311a3 100644 --- a/services/frontend-service/src/ui/utils/store.test.tsx +++ b/services/frontend-service/src/ui/utils/store.test.tsx @@ -17,6 +17,8 @@ import { act, renderHook } from '@testing-library/react'; import { addAction, AllLocks, + AppDetailsResponse, + AppDetailsState, appendAction, DisplayLock, FlushRolloutStatus, @@ -37,7 +39,6 @@ import { BatchAction, Environment, EnvironmentGroup, - GetAppDetailsResponse, GetOverviewResponse, LockBehavior, OverviewApplication, @@ -1096,7 +1097,7 @@ describe('Test Calculate Release Difference', () => { type TestDataStore = { name: string; inputOverview: GetOverviewResponse; - inputAppDetails: { [p: string]: GetAppDetailsResponse }; + inputAppDetails: { [p: string]: AppDetailsResponse }; inputVersion: number; expectedDifference: number; }; @@ -1148,46 +1149,49 @@ describe('Test Calculate Release Difference', () => { name: 'environment does not exist in the envs', inputAppDetails: { 'example-app': { - application: { - name: 'example-app', - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - releases: [ - { - version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { + details: { + application: { + name: 'example-app', + undeploySummary: UndeploySummary.NORMAL, + sourceRepoUrl: '', + team: '', + warnings: [], + releases: [ + { + version: 10, + sourceCommitId: '', + sourceAuthor: '', + sourceMessage: '', + undeployVersion: false, + prNumber: '', + displayVersion: '', + isMinor: false, + isPrepublish: false, + }, + { + version: 12, + sourceCommitId: '', + sourceAuthor: '', + sourceMessage: '', + undeployVersion: false, + prNumber: '', + displayVersion: '', + isMinor: false, + isPrepublish: false, + }, + ], + }, + deployments: { + test: { version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', + queuedVersion: 0, undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, }, - ], - }, - deployments: { - test: { - version: 12, - queuedVersion: 0, - undeployVersion: false, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, inputOverview: { @@ -1225,57 +1229,60 @@ describe('Test Calculate Release Difference', () => { name: 'Simple diff calculation', inputAppDetails: { [appName]: { - application: { - name: appName, - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - releases: [ - { + details: { + application: { + name: appName, + undeploySummary: UndeploySummary.NORMAL, + sourceRepoUrl: '', + team: '', + warnings: [], + releases: [ + { + version: 10, + sourceCommitId: '', + sourceAuthor: '', + sourceMessage: '', + undeployVersion: false, + prNumber: '', + displayVersion: '', + isMinor: false, + isPrepublish: false, + }, + { + version: 12, + sourceCommitId: '', + sourceAuthor: '', + sourceMessage: '', + undeployVersion: false, + prNumber: '', + displayVersion: '', + isMinor: false, + isPrepublish: false, + }, + { + version: 15, + sourceCommitId: '', + sourceAuthor: '', + sourceMessage: '', + undeployVersion: false, + prNumber: '', + displayVersion: '', + isMinor: false, + isPrepublish: false, + }, + ], + }, + deployments: { + [envName]: { version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { - version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', + queuedVersion: 0, undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, }, - { - version: 15, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - ], - }, - deployments: { - [envName]: { - version: 10, - queuedVersion: 0, - undeployVersion: false, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, inputOverview: { @@ -1315,46 +1322,49 @@ describe('Test Calculate Release Difference', () => { name: 'negative diff', inputAppDetails: { [appName]: { - application: { - name: appName, - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - releases: [ - { - version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { + details: { + application: { + name: appName, + undeploySummary: UndeploySummary.NORMAL, + sourceRepoUrl: '', + team: '', + warnings: [], + releases: [ + { + version: 10, + sourceCommitId: '', + sourceAuthor: '', + sourceMessage: '', + undeployVersion: false, + prNumber: '', + displayVersion: '', + isMinor: false, + isPrepublish: false, + }, + { + version: 12, + sourceCommitId: '', + sourceAuthor: '', + sourceMessage: '', + undeployVersion: false, + prNumber: '', + displayVersion: '', + isMinor: false, + isPrepublish: false, + }, + ], + }, + deployments: { + [envName]: { version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', + queuedVersion: 0, undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, }, - ], - }, - deployments: { - [envName]: { - version: 12, - queuedVersion: 0, - undeployVersion: false, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, inputOverview: { @@ -1392,46 +1402,49 @@ describe('Test Calculate Release Difference', () => { name: 'the input version does not exist', inputAppDetails: { appName: { - application: { - name: appName, - undeploySummary: UndeploySummary.NORMAL, - sourceRepoUrl: '', - team: '', - warnings: [], - releases: [ - { - version: 10, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', - undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, - }, - { + details: { + application: { + name: appName, + undeploySummary: UndeploySummary.NORMAL, + sourceRepoUrl: '', + team: '', + warnings: [], + releases: [ + { + version: 10, + sourceCommitId: '', + sourceAuthor: '', + sourceMessage: '', + undeployVersion: false, + prNumber: '', + displayVersion: '', + isMinor: false, + isPrepublish: false, + }, + { + version: 12, + sourceCommitId: '', + sourceAuthor: '', + sourceMessage: '', + undeployVersion: false, + prNumber: '', + displayVersion: '', + isMinor: false, + isPrepublish: false, + }, + ], + }, + deployments: { + [envName]: { version: 12, - sourceCommitId: '', - sourceAuthor: '', - sourceMessage: '', + queuedVersion: 0, undeployVersion: false, - prNumber: '', - displayVersion: '', - isMinor: false, - isPrepublish: false, }, - ], - }, - deployments: { - [envName]: { - version: 12, - queuedVersion: 0, - undeployVersion: false, }, + appLocks: {}, + teamLocks: {}, }, - appLocks: {}, - teamLocks: {}, + appDetailState: AppDetailsState.READY, }, }, inputOverview: { diff --git a/services/frontend-service/src/ui/utils/store.tsx b/services/frontend-service/src/ui/utils/store.tsx index 58b17e968..f04467e33 100644 --- a/services/frontend-service/src/ui/utils/store.tsx +++ b/services/frontend-service/src/ui/utils/store.tsx @@ -91,21 +91,24 @@ export enum CommitInfoState { ERROR, NOTFOUND, } + +export enum AppDetailsState { + LOADING, + READY, + ERROR, + NOTFOUND, + NOTREQUESTED = 4, +} + export type CommitInfoResponse = { response: GetCommitInfoResponse | undefined; commitInfoReady: CommitInfoState; }; export type AppDetailsResponse = { - response: GetAppDetailsResponse | undefined; + details: GetAppDetailsResponse | undefined; appDetailState: AppDetailsState; }; -export enum AppDetailsState { - LOADING, - READY, - ERROR, - NOTFOUND, -} export enum FailedEslsState { LOADING, @@ -130,6 +133,7 @@ export type ReleaseTrainPrognosisResponse = { releaseTrainPrognosisReady: ReleaseTrainPrognosisState; }; const emptyBatch: BatchRequest & { [key: string]: unknown } = { actions: [] }; + export const [useAction, UpdateAction] = createStore(emptyBatch); const tagsResponse: GetGitTagsResponse = { tagData: [] }; export const refreshTags = (): void => { @@ -145,8 +149,8 @@ export const refreshTags = (): void => { }; export const [useTag, updateTag] = createStore({ response: tagsResponse, tagsReady: false }); -const emtpyDetails: { [key: string]: GetAppDetailsResponse } = {}; -export const [useAppDetails, updateAppDetails] = createStore<{ [key: string]: GetAppDetailsResponse }>(emtpyDetails); +export const emptyDetails: { [key: string]: AppDetailsResponse } = {}; +export const [useAppDetails, updateAppDetails] = createStore<{ [key: string]: AppDetailsResponse }>(emptyDetails); const emptyWarnings: { [key: string]: Warning[] } = {}; export const [useWarnings, updateWarnings] = createStore<{ [key: string]: Warning[] }>(emptyWarnings); @@ -154,16 +158,28 @@ export const [useWarnings, updateWarnings] = createStore<{ [key: string]: Warnin export const useAllWarningsAllApps = (): Warning => useWarnings((map) => map); export const getAppDetails = (appName: string, authHeader: AuthHeader): void => { + const details = updateAppDetails.get(); + details[appName] = { + details: details[appName] ? details[appName].details : undefined, + appDetailState: AppDetailsState.LOADING, + }; + updateAppDetails.set(details); useApi .overviewService() .GetAppDetails({ appName: appName }, authHeader) .then((result: GetAppDetailsResponse) => { - const details = updateAppDetails.get(); - details[appName] = result; - updateAppDetails.set(details); + const d = updateAppDetails.get(); + d[appName] = { details: result, appDetailState: AppDetailsState.READY }; + updateAppDetails.set(d); }) .catch((e) => { - PanicOverview.set(e); + const GrpcErrorNotFound = 5; + if (e.code === GrpcErrorNotFound) { + details[appName] = { details: undefined, appDetailState: AppDetailsState.NOTFOUND }; + } else { + details[appName] = { details: undefined, appDetailState: AppDetailsState.ERROR }; + } + updateAppDetails.set(details); showSnackbarError(e.message); }); }; @@ -440,7 +456,7 @@ export const useOpenReleaseDialog = (app: string, version: number): (() => void) }, [app, params, setParams, version]); }; -export const useAppDetailsForApp = (app: string): GetAppDetailsResponse => useAppDetails((map) => map[app]); +export const useAppDetailsForApp = (app: string): AppDetailsResponse => useAppDetails((map) => map[app]); export const useCloseReleaseDialog = (): (() => void) => { const [params, setParams] = useSearchParams(); @@ -456,10 +472,13 @@ export const useReleaseDialogParams = (): { app: string | null; version: number const app = params.get('dialog-app') ?? ''; const version = +(params.get('dialog-version') ?? ''); - const appDetails = useAppDetailsForApp(app); - if (!appDetails) { + const response = useAppDetailsForApp(app); + + if (!response || !response.details) { return { app: null, version: null }; } + const appDetails = response.details; + const valid = !!appDetails.application?.releases.find((r) => r.version === version); return valid ? { app, version } : { app: null, version: null }; }; @@ -498,10 +517,10 @@ export const useAllWarnings = (): Warning[] => { return names .map((name) => { const resp = allAppDetails[name]; - if (resp === undefined) { + if (resp === undefined || !allAppDetails[name].details) { return []; } else { - const app = resp.application; + const app = resp.details?.application; if (app === undefined) { return []; } else { @@ -589,10 +608,10 @@ export const applicationsWithWarnings = (applications: OverviewApplication[]): O applications .map((app) => { const d = updateAppDetails.get()[app.name]; - if (d === undefined) { + if (d === undefined || !updateAppDetails.get()[app.name].details) { return []; } else { - const currApp = d.application; + const currApp = d.details?.application; if (currApp === undefined) { return []; } else { @@ -918,8 +937,9 @@ export const sortLocks = (displayLocks: DisplayLock[], sorting: 'oldestToNewest' export const useRelease = (application: string, version: number): Release | undefined => { const appDetails = useAppDetailsForApp(application); - if (!appDetails) return undefined; - return appDetails.application?.releases.find((r) => r.version === version); + if (!appDetails || appDetails.appDetailState !== AppDetailsState.READY) return undefined; + + return appDetails.details ? appDetails.details.application?.releases.find((r) => r.version === version) : undefined; }; export const useReleaseOrLog = (application: string, version: number): Release | undefined => { @@ -933,7 +953,11 @@ export const useReleaseOrLog = (application: string, version: number): Release | }; export const useReleaseOptional = (application: string, env: Environment): Release | undefined => { - const appDetails = useAppDetailsForApp(application); + const response = useAppDetailsForApp(application); + const appDetails = response.details; + if (appDetails === undefined) { + return undefined; + } const deployment = appDetails.deployments[env.name]; if (!deployment) return undefined; return appDetails.application?.releases.find((r) => r.version === deployment.version); @@ -946,7 +970,8 @@ export type EnvironmentGroupExtended = EnvironmentGroup & { numberOfEnvsInGroup: */ export const useCurrentlyDeployedAtGroup = (application: string, version: number): EnvironmentGroupExtended[] => { const environmentGroups: EnvironmentGroup[] = useEnvironmentGroups(); - const appDetails = useAppDetailsForApp(application); + const response = useAppDetailsForApp(application); + const appDetails = response.details; return useMemo(() => { const envGroups: EnvironmentGroupExtended[] = []; environmentGroups.forEach((group: EnvironmentGroup) => { @@ -978,11 +1003,13 @@ export const useCurrentlyDeployedAtGroup = (application: string, version: number */ export const useCurrentlyExistsAtGroup = (application: string): EnvironmentGroupExtended[] => { const environmentGroups: EnvironmentGroup[] = useEnvironmentGroups(); - const appDetails = useAppDetailsForApp(application); + const response = useAppDetailsForApp(application); + const appDetails = response.details; + return useMemo(() => { const envGroups: EnvironmentGroupExtended[] = []; environmentGroups.forEach((group: EnvironmentGroup) => { - const envs = group.environments.filter((env) => appDetails.deployments[env.name]); + const envs = group.environments.filter((env) => (appDetails ? appDetails.deployments[env.name] : false)); if (envs.length > 0) { // we need to make a copy of the group here, because we want to remove some envs. // but that should not have any effect on the group saved in the store. @@ -1000,22 +1027,14 @@ export const useCurrentlyExistsAtGroup = (application: string): EnvironmentGroup }, [environmentGroups, appDetails]); }; -// Get all releases for an app -export const useReleasesForApp = (app: string): Release[] => { - const appDetails = useAppDetailsForApp(app); - if (!appDetails?.application?.releases) { - return []; - } else { - return appDetails.application?.releases; - } -}; - // Calculated release difference between a specific release and currently deployed release on a specific environment export const useReleaseDifference = (toDeployVersion: number, application: string, environment: string): number => { - const appDetails = useAppDetailsForApp(application); - if (!appDetails) { + const response = useAppDetailsForApp(application); + + if (!response || !response.details) { return 0; } + const appDetails = response.details; const deployment = appDetails.deployments[environment]; if (!deployment) { return 0; @@ -1038,7 +1057,7 @@ export const useReleaseDifference = (toDeployVersion: number, application: strin // Get all minor releases for an app export const useMinorsForApp = (app: string): number[] | undefined => useAppDetailsForApp(app) - .application?.releases.filter((rel) => rel.isMinor) + .details?.application?.releases.filter((rel) => rel.isMinor) .map((rel) => rel.version); // Navigate while keeping search params, returns new navigation url, and a callback function to navigate