Repository navigation
feat(Dependencies): Show dependency changes pending in change requests #8783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
talissoncosta
wants to merge
10
commits into
feat/flag-dependencies-cr-interactions-8450
from
feat/flag-dependencies-pending-section-8450
+301
−4
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
ceefa86
feat(Dependencies): Add a link that opens a change request in a new tab
talissoncosta f04d2f2
feat(dependencies): show dependency changes pending in change requests
talissoncosta f42d186
feat(Dependencies): List the pending change requests by feature
talissoncosta bef0b88
fix(Dependencies): Space and soften the pending change requests error
talissoncosta c112a5a
refactor(Dependencies): Read pending dependencies through the typed l…
talissoncosta 265b341
fix(Dependencies): Show pending change requests only where the API li…
talissoncosta 333cf80
fix(Dependencies): Load each pending change request's dependencies in…
talissoncosta a9d1f7b
fix(Dependencies): Make the pending change request's link smaller and…
talissoncosta 389b8d7
feat(Dependencies): Count each pending change request's changes in it…
talissoncosta e1ab738
refactor(Dependencies): Count the pending changes in a tested helper,…
talissoncosta File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
...nd/web/components/modals/create-feature/tabs/FeatureDependenciesTab/ChangeRequestLink.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { FC, ReactNode } from 'react' | ||
| import cn from 'classnames' | ||
| import Icon from 'components/icons/Icon' | ||
|
|
||
| type ChangeRequestLinkProps = { | ||
| projectId: number | ||
| environmentId: string | ||
| changeRequestId: number | ||
| children: ReactNode | ||
| className?: string | ||
| } | ||
|
|
||
| // A new tab, as leaving the page would drop the modal and anything staged in | ||
| // it without the close confirmation. | ||
| const ChangeRequestLink: FC<ChangeRequestLinkProps> = ({ | ||
| changeRequestId, | ||
| children, | ||
| className, | ||
| environmentId, | ||
| projectId, | ||
| }) => ( | ||
| <a | ||
| href={`/project/${projectId}/environment/${environmentId}/change-requests/${changeRequestId}`} | ||
| target='_blank' | ||
| rel='noopener noreferrer' | ||
| className={cn('d-inline-flex align-items-center gap-1', className)} | ||
| > | ||
| {children} | ||
| <Icon | ||
| name='open-external-link' | ||
| width={12} | ||
| role='img' | ||
| aria-label='opens in a new tab' | ||
| /> | ||
| </a> | ||
| ) | ||
|
|
||
| export default ChangeRequestLink |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
...create-feature/tabs/FeatureDependenciesTab/PendingChangeRequests/PendingChangeRequest.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| import { FC } from 'react' | ||
| import { ChangeRequestSummary } from 'common/types/responses' | ||
| import { colorIconSecondary } from 'common/theme/tokens' | ||
| import Accordion from 'components/base/Accordion' | ||
| import Banner from 'components/base/Banner' | ||
| import Icon from 'components/icons/Icon' | ||
| import Skeleton from 'components/Skeleton' | ||
| import DependencyChangesTable from 'components/feature-dependencies/DependencyChangesTable' | ||
| import { useDependencyChanges } from 'components/feature-dependencies/useDependencyChanges' | ||
| import { countDependencyChanges } from 'common/utils/diffDependencies' | ||
| import ChangeRequestLink from 'components/modals/create-feature/tabs/FeatureDependenciesTab/ChangeRequestLink' | ||
|
|
||
| type PendingChangeRequestProps = { | ||
| changeRequest: ChangeRequestSummary | ||
| environmentId: string | ||
| featureId: number | ||
| projectId: number | ||
| isEnabled: (prerequisiteId: number) => boolean | ||
| defaultOpen: boolean | ||
| } | ||
|
|
||
| // One open change request, shown only if it changes this feature's | ||
| // prerequisites. Each loads its own, as the change request page does. | ||
| const PendingChangeRequest: FC<PendingChangeRequestProps> = ({ | ||
| changeRequest, | ||
| defaultOpen, | ||
| environmentId, | ||
| featureId, | ||
| isEnabled, | ||
| projectId, | ||
| }) => { | ||
| const { changes, isClosed, isError } = useDependencyChanges({ | ||
| changeRequestId: changeRequest.id, | ||
| environmentId, | ||
| featureId, | ||
| }) | ||
|
|
||
| if (isClosed) return null | ||
| if (isError) { | ||
| return ( | ||
| <Banner type='error'> | ||
| Could not load the dependency changes in #{changeRequest.id}{' '} | ||
| {changeRequest.title}. | ||
| </Banner> | ||
| ) | ||
| } | ||
| if (!changes) return <Skeleton width='100%' height={56} aria-hidden /> | ||
| // Most change sets only touch values or overrides. | ||
| if (!changes.length) return null | ||
|
|
||
| const { added, label, removed } = countDependencyChanges(changes) | ||
|
|
||
| return ( | ||
| <Accordion | ||
| defaultOpen={defaultOpen} | ||
| flush | ||
| title={ | ||
| <> | ||
| <Icon | ||
| name='request' | ||
| width={16} | ||
| fill={colorIconSecondary} | ||
| aria-hidden | ||
| /> | ||
| <span className='pending-change-requests__title text-truncate'> | ||
| #{changeRequest.id} {changeRequest.title} | ||
| </span> | ||
| {/* Read out as words, as "+1 −2" means little to a screen reader. */} | ||
| <span | ||
| className='pending-change-requests__count d-flex flex-shrink-0 justify-content-end gap-2 ms-auto' | ||
| role='img' | ||
| aria-label={label} | ||
| > | ||
| {!!added && <span className='text-success'>+{added}</span>} | ||
| {!!removed && <span className='text-danger'>−{removed}</span>} | ||
| </span> | ||
| </> | ||
| } | ||
| > | ||
| <DependencyChangesTable changes={changes} isEnabled={isEnabled} /> | ||
| {/* In the body, as the header is the toggle and a link cannot | ||
| sit inside a button. */} | ||
| <div className='d-flex justify-content-end px-3 py-2'> | ||
| <ChangeRequestLink | ||
| className='pending-change-requests__link text-action' | ||
| projectId={projectId} | ||
| environmentId={environmentId} | ||
| changeRequestId={changeRequest.id} | ||
| > | ||
| Open #{changeRequest.id} | ||
| </ChangeRequestLink> | ||
| </div> | ||
| </Accordion> | ||
| ) | ||
| } | ||
|
|
||
| export default PendingChangeRequest | ||
21 changes: 21 additions & 0 deletions
21
...eate-feature/tabs/FeatureDependenciesTab/PendingChangeRequests/PendingChangeRequests.scss
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Each change request hides itself when it changes no prerequisite, so the | ||
| // heading goes too once none are left. | ||
| .pending-change-requests:not(:has(.pending-change-requests__list > *)) { | ||
| display: none; | ||
| } | ||
|
|
||
| // B2, as the accordion's title, so it reads as secondary to the table. | ||
| .pending-change-requests__link { | ||
| font-size: 0.8125rem; | ||
| } | ||
|
|
||
| // Lets a long title shrink and truncate beside the count. | ||
| .pending-change-requests__title { | ||
| min-width: 0; | ||
| } | ||
|
|
||
| // Close to a fixed width, so the counts line up down the list. | ||
| .pending-change-requests__count { | ||
| min-width: 4rem; | ||
| font-variant-numeric: tabular-nums; | ||
| } |
65 changes: 65 additions & 0 deletions
65
...reate-feature/tabs/FeatureDependenciesTab/PendingChangeRequests/PendingChangeRequests.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| import { FC } from 'react' | ||
| import { useGetChangeRequestsQuery } from 'common/services/useChangeRequest' | ||
| import Banner from 'components/base/Banner' | ||
| import PendingChangeRequest from './PendingChangeRequest' | ||
| import './PendingChangeRequests.scss' | ||
|
|
||
| type PendingChangeRequestsProps = { | ||
| environmentId: string | ||
| featureId: number | ||
| projectId: number | ||
| isEnabled: (prerequisiteId: number) => boolean | ||
| } | ||
|
|
||
| // Changes to this feature's prerequisites that are waiting in open change | ||
| // requests, one group per change request. Scheduled ones are left out, as | ||
| // the API refuses to list their dependencies. | ||
| const PendingChangeRequests: FC<PendingChangeRequestsProps> = ({ | ||
| environmentId, | ||
| featureId, | ||
| isEnabled, | ||
| projectId, | ||
| }) => { | ||
| // Matches any change request with a change set for this feature. | ||
| const { data, isError } = useGetChangeRequestsQuery({ | ||
| committed: false, | ||
| environmentId, | ||
| feature_id: featureId, | ||
| page_size: 100, | ||
| }) | ||
|
talissoncosta marked this conversation as resolved.
|
||
|
|
||
| if (isError) { | ||
| return ( | ||
| <Banner type='error' className='mt-4'> | ||
| Could not load the change requests waiting on this feature. | ||
| </Banner> | ||
| ) | ||
| } | ||
|
|
||
| if (!data?.results.length) return null | ||
|
|
||
| return ( | ||
| <div className='pending-change-requests mt-4'> | ||
| <h6 className='mb-1'>Pending in change requests</h6> | ||
| <p className='text-secondary mb-3'> | ||
| Not live yet. These go live when their change request is published. | ||
| </p> | ||
| <div className='pending-change-requests__list d-flex flex-column gap-3'> | ||
| {data.results.map((changeRequest) => ( | ||
| <PendingChangeRequest | ||
| key={changeRequest.id} | ||
| changeRequest={changeRequest} | ||
| environmentId={environmentId} | ||
| featureId={featureId} | ||
| projectId={projectId} | ||
| isEnabled={isEnabled} | ||
| // One stays open; more are collapsed, and their counts lead. | ||
| defaultOpen={data.results.length === 1} | ||
| /> | ||
| ))} | ||
| </div> | ||
| </div> | ||
| ) | ||
| } | ||
|
|
||
| export default PendingChangeRequests | ||
1 change: 1 addition & 0 deletions
1
...mponents/modals/create-feature/tabs/FeatureDependenciesTab/PendingChangeRequests/index.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export { default } from './PendingChangeRequests' |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: Flagsmith/flagsmith
Length of output: 6570
🏁 Script executed:
Repository: Flagsmith/flagsmith
Length of output: 9309
🏁 Script executed:
Repository: Flagsmith/flagsmith
Length of output: 1131
Make the dependency API honour
change_request.When this tab renders an open change request with staged dependency changes, the child requests live and change-request-scoped dependencies. The API ignores
change_requestand returns live dependencies for both requests. The diff is therefore empty, so the pending dependency changes are hidden. Update the dependency API to return dependencies as they would exist in the specified change request.