Skip to content

Commit 020d697

Browse files
talissoncostaclaude
andcommitted
fix(dependencies): read a change request's features from its change sets
The API has no list of features by change request, and the change request already says which features it changes. Features with no prerequisite changes get no panel. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 3b22d58 commit 020d697

7 files changed

Lines changed: 79 additions & 56 deletions

File tree

‎frontend/common/services/useFeatureDependency.ts‎

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { FetchBaseQueryError } from '@reduxjs/toolkit/query'
21
import { Req } from 'common/types/requests'
32
import { Res } from 'common/types/responses'
43
import { service } from 'common/service'
@@ -37,15 +36,6 @@ const dependencyUrl = (query: Req['createFeatureDependency']) =>
3736
query.changeRequestId,
3837
)
3938

40-
// The API cannot list these yet, so the pending views report an error rather
41-
// than claim nothing is pending.
42-
const notListedYet: { error: FetchBaseQueryError } = {
43-
error: {
44-
error: 'The API does not list staged dependencies yet.',
45-
status: 'CUSTOM_ERROR',
46-
},
47-
}
48-
4939
const pendingTags = (featureId: number): DependencyTag[] => [
5040
{ id: `PENDING-${featureId}`, type: 'FeatureDependency' },
5141
{ id: 'PENDING', type: 'FeatureDependency' },
@@ -134,14 +124,6 @@ export const featureDependencyService = service
134124
url: `environments/${query.environmentId}/features/${query.featureId}/dependents/`,
135125
}),
136126
}),
137-
// Will be the features a change request stages dependencies for.
138-
getFeatureIdsStaged: builder.query<
139-
Res['featureIdsStaged'],
140-
Req['getFeatureIdsStaged']
141-
>({
142-
providesTags: [{ id: 'PENDING', type: 'FeatureDependency' }],
143-
queryFn: () => notListedYet,
144-
}),
145127
// END OF ENDPOINTS
146128
}),
147129
})
@@ -209,7 +191,6 @@ export const {
209191
useDeleteFeatureDependencyMutation,
210192
useGetFeatureDependenciesQuery,
211193
useGetFeatureDependentsQuery,
212-
useGetFeatureIdsStagedQuery,
213194
// END OF EXPORTS
214195
} = featureDependencyService
215196

‎frontend/common/types/requests.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,6 @@ export type Req = {
908908
approvals: Approval[]
909909
}
910910
deleteChangeRequest: { id: number }
911-
getFeatureIdsStaged: { changeRequestId: number }
912911
getSamlConfiguration: { name: string }
913912
getSamlConfigurations: { organisation_id: number }
914913
getSamlConfigurationMetadata: { name: string }

‎frontend/common/types/responses.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1627,7 +1627,6 @@ export type Res = {
16271627
featureDependencies: { results: DependencyEdge[] }
16281628
featureDependents: { results: DependencyEdge[] }
16291629
featureDependency: DependencyEdge
1630-
featureIdsStaged: number[]
16311630
featureVersions: PagedResponse<FeatureVersion>
16321631
users: User[]
16331632
enableFeatureVersioning: { id: string }

‎frontend/web/components/feature-dependencies/ChangeRequestDependencyChanges.tsx‎

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { FC } from 'react'
2-
import { useGetFeatureDependenciesQuery } from 'common/services/useFeatureDependency'
3-
import { diffDependencies } from 'common/utils/diffDependencies'
42
import DependencyChangesTable from './DependencyChangesTable'
3+
import { useDependencyChanges } from './useDependencyChanges'
54
import ErrorMessage from 'components/ErrorMessage'
65

76
type ChangeRequestDependencyChangesProps = {
@@ -11,30 +10,25 @@ type ChangeRequestDependencyChangesProps = {
1110
isEnabled?: (prerequisiteId: number) => boolean
1211
}
1312

14-
// A feature's prerequisite changes in one change request: its dependencies
15-
// as if the change request were live, against today's.
1613
const ChangeRequestDependencyChanges: FC<
1714
ChangeRequestDependencyChangesProps
1815
> = ({ changeRequestId, environmentId, featureId, isEnabled }) => {
19-
const live = useGetFeatureDependenciesQuery({ environmentId, featureId })
20-
const scoped = useGetFeatureDependenciesQuery({
16+
const { changes, isError, isLoading } = useDependencyChanges({
2117
changeRequestId,
2218
environmentId,
2319
featureId,
2420
})
2521

26-
if (live.isLoading || scoped.isLoading) {
22+
if (isLoading) {
2723
return (
2824
<div className='text-center p-3'>
2925
<Loader />
3026
</div>
3127
)
3228
}
33-
if (live.isError || scoped.isError || !live.data || !scoped.data) {
29+
if (isError || !changes) {
3430
return <ErrorMessage error='Could not load the prerequisite changes.' />
3531
}
36-
37-
const changes = diffDependencies(live.data.results, scoped.data.results)
3832
if (!changes.length) {
3933
return (
4034
<p className='text-secondary px-3 py-2 mb-0'>No prerequisite changes.</p>

‎frontend/web/components/feature-dependencies/DiffDependencies.tsx‎

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,36 @@
11
import { FC } from 'react'
2-
import { useGetFeatureIdsStagedQuery } from 'common/services/useFeatureDependency'
2+
import { ChangeRequest } from 'common/types/responses'
33
import { useGetProjectFlagQuery } from 'common/services/useProjectFlag'
44
import { useFeatureStates } from 'common/hooks/useFeatureStates'
5-
import ChangeRequestDependencyChanges from './ChangeRequestDependencyChanges'
5+
import DependencyChangesTable from './DependencyChangesTable'
6+
import { useDependencyChanges } from './useDependencyChanges'
67
import Panel from 'components/base/grid/Panel'
78
import ErrorMessage from 'components/ErrorMessage'
89

910
type DiffDependenciesProps = {
11+
changeRequest: ChangeRequest
12+
environmentId: string
13+
projectId: string
14+
}
15+
16+
type FeatureDependencyChangesProps = {
1017
changeRequestId: number
1118
environmentId: string
19+
featureId: number
1220
projectId: string
1321
}
1422

15-
const FeatureDependencyChanges: FC<
16-
DiffDependenciesProps & { featureId: number }
17-
> = ({ changeRequestId, environmentId, featureId, projectId }) => {
23+
const FeatureDependencyChanges: FC<FeatureDependencyChangesProps> = ({
24+
changeRequestId,
25+
environmentId,
26+
featureId,
27+
projectId,
28+
}) => {
29+
const { changes, isError } = useDependencyChanges({
30+
changeRequestId,
31+
environmentId,
32+
featureId,
33+
})
1834
const { data: feature } = useGetProjectFlagQuery({
1935
id: featureId,
2036
project: Number(projectId),
@@ -25,6 +41,16 @@ const FeatureDependencyChanges: FC<
2541
environmentId,
2642
projectId: Number(projectId),
2743
})
44+
45+
if (isError) {
46+
return (
47+
<div className='mt-4'>
48+
<ErrorMessage error='Could not load the dependency changes in this change request.' />
49+
</div>
50+
)
51+
}
52+
// Most change sets only touch values or overrides, so no panel for those.
53+
if (!changes?.length) return null
2854
return (
2955
<Panel
3056
title={`Dependencies${feature ? `: ${feature.name}` : ''}`}
@@ -34,10 +60,8 @@ const FeatureDependencyChanges: FC<
3460
Prerequisite changes in this request. Nothing changes until it is
3561
published.
3662
</p>
37-
<ChangeRequestDependencyChanges
38-
environmentId={environmentId}
39-
featureId={featureId}
40-
changeRequestId={changeRequestId}
63+
<DependencyChangesTable
64+
changes={changes}
4165
// Until the states are known, no column rather than every row "No".
4266
isEnabled={
4367
states.isLoading || states.isError ? undefined : states.isEnabled
@@ -47,29 +71,22 @@ const FeatureDependencyChanges: FC<
4771
)
4872
}
4973

50-
// The prerequisite changes staged in a change request, per feature.
74+
// The prerequisite changes staged in a change request, per feature it
75+
// changes.
5176
const DiffDependencies: FC<DiffDependenciesProps> = ({
52-
changeRequestId,
77+
changeRequest,
5378
environmentId,
5479
projectId,
5580
}) => {
56-
const { data: featureIds, isError } = useGetFeatureIdsStagedQuery({
57-
changeRequestId,
58-
})
59-
// Otherwise a failed list reads as no dependency changes.
60-
if (isError) {
61-
return (
62-
<div className='mt-4'>
63-
<ErrorMessage error='Could not load the dependency changes in this change request.' />
64-
</div>
65-
)
66-
}
81+
const featureIds = [
82+
...new Set(changeRequest.change_sets?.map(({ feature }) => feature)),
83+
]
6784
return (
6885
<>
69-
{featureIds?.map((featureId) => (
86+
{featureIds.map((featureId) => (
7087
<FeatureDependencyChanges
7188
key={featureId}
72-
changeRequestId={changeRequestId}
89+
changeRequestId={changeRequest.id}
7390
environmentId={environmentId}
7491
featureId={featureId}
7592
projectId={projectId}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { useGetFeatureDependenciesQuery } from 'common/services/useFeatureDependency'
2+
import { diffDependencies } from 'common/utils/diffDependencies'
3+
4+
type UseDependencyChangesArgs = {
5+
environmentId: string
6+
featureId: number
7+
changeRequestId: number
8+
}
9+
10+
// A feature's prerequisite changes in one change request: its dependencies
11+
// as if the change request were live, against today's.
12+
export const useDependencyChanges = ({
13+
changeRequestId,
14+
environmentId,
15+
featureId,
16+
}: UseDependencyChangesArgs) => {
17+
const live = useGetFeatureDependenciesQuery({ environmentId, featureId })
18+
const scoped = useGetFeatureDependenciesQuery({
19+
changeRequestId,
20+
environmentId,
21+
featureId,
22+
})
23+
const isError = live.isError || scoped.isError
24+
const changes =
25+
live.data && scoped.data
26+
? diffDependencies(live.data.results, scoped.data.results)
27+
: undefined
28+
return {
29+
changes,
30+
isError,
31+
isLoading: !isError && !changes,
32+
}
33+
}

‎frontend/web/components/pages/ChangeRequestDetailPage.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ const ChangeRequestDetailPage: FC<ChangeRequestPageType> = ({ match }) => {
412412
'flag_dependencies_change_requests',
413413
) && (
414414
<DiffDependencies
415-
changeRequestId={changeRequest.id}
415+
changeRequest={changeRequest}
416416
environmentId={environmentId}
417417
projectId={projectId}
418418
/>

0 commit comments

Comments
 (0)