Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 113 additions & 9 deletions frontend/common/providers/withSegmentOverrides.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import data from 'common/data/base/_data'
import ProjectStore from 'common/stores/project-store'
import FeatureListStore from 'common/stores/feature-list-store'
import { mergeChangeSets } from 'common/services/useChangeRequest'

export default (WrappedComponent) => {
class HOC extends React.Component {
Expand Down Expand Up @@ -28,6 +29,7 @@ export default (WrappedComponent) => {
getOverrides = () => {
if (this.props.projectFlag) {
//todo: migrate to useSegmentFeatureState
const projectId = this.props.projectFlag.project
Promise.all([
data.get(
`${
Expand All @@ -43,7 +45,12 @@ export default (WrappedComponent) => {
this.props.environmentId,
)}&feature=${this.props.projectFlag.id}`,
),
]).then(([res, res2]) => {
this.props.changeRequest?.change_sets
? data.get(
`${Project.api}projects/${projectId}/segments/?page_size=1000`,
)
: Promise.resolve({ results: [] }),
]).then(([res, res2, segmentsRes]) => {
const results = res.results
const featureStates = res2.results
const environmentOverride = res2.results.find(
Expand Down Expand Up @@ -72,18 +79,115 @@ export default (WrappedComponent) => {
}
}
})
const resResults = res.results || []
const segmentOverrides = results
.concat(

let segmentOverrides
if (this.props.changeRequest?.change_sets) {
// Add changesets to existing segment overrides
const mergedFeatureStates = mergeChangeSets(
this.props.changeRequest.change_sets,
featureStates,
this.props.changeRequest.conflicts,
)

// Get segment IDs marked for deletion
const segmentIdsToDelete =
this.props.changeRequest.change_sets?.flatMap(
(changeSet) => changeSet.segment_ids_to_delete_overrides || [],
) || []

segmentOverrides = results.map((currentSegmentOverride) => {
const changedFeatureState = mergedFeatureStates.find(
(featureState) =>
featureState.feature_segment?.segment ===
currentSegmentOverride.segment,
)

// Any segment_ids_to_delete_overrides should be marked as toRemove
const toRemove = segmentIdsToDelete.includes(
currentSegmentOverride.segment,
)

if (changedFeatureState) {
return {
...currentSegmentOverride,
...changedFeatureState,
id: changedFeatureState.id || currentSegmentOverride.id,
is_feature_specific:
changedFeatureState.feature_segment?.is_feature_specific,
multivariate_options:
changedFeatureState.multivariate_feature_state_values || [],
priority: changedFeatureState.feature_segment?.priority || 0,
segment: changedFeatureState.feature_segment?.segment,
segment_name:
changedFeatureState.feature_segment?.segment_name ||
currentSegmentOverride.segment_name,
toRemove,
uuid:
changedFeatureState.feature_segment?.uuid ||
currentSegmentOverride.uuid,
value: Utils.featureStateToValue(
changedFeatureState.feature_state_value,
),
}
}

return toRemove
? { ...currentSegmentOverride, toRemove }
: currentSegmentOverride
})

// Add any new segment overrides from the changesets
mergedFeatureStates
.filter(
(featureState) =>
!!featureState.feature_segment?.segment &&
!results.find(
(currentOverride) =>
currentOverride.segment ===
featureState.feature_segment.segment,
),
)
.forEach((newFeatureState) => {
// Look up segment metadata from segments API to get segment name
const segmentMetadata = segmentsRes.results?.find(
(segment) =>
segment.id === newFeatureState.feature_segment?.segment,
)

segmentOverrides.push({
enabled: newFeatureState.enabled,
environment: newFeatureState.environment,
feature: newFeatureState.feature,
id: newFeatureState.id,
is_feature_specific:
newFeatureState.feature_segment?.is_feature_specific,
multivariate_options:
newFeatureState.multivariate_feature_state_values || [],
priority: newFeatureState.feature_segment?.priority || 0,
segment: newFeatureState.feature_segment?.segment,
segment_name:
newFeatureState.feature_segment?.segment_name ||
segmentMetadata?.name ||
'Unknown Segment',
uuid: newFeatureState.feature_segment?.uuid,
value: Utils.featureStateToValue(
newFeatureState.feature_state_value,
),
})
})
} else {
segmentOverrides = results.concat(
(this.props.newSegmentOverrides || []).map((v, i) => ({
...v,
})),
)
.map((v, i) => ({
...v,
originalPriority: i,
priority: i,
}))
}
segmentOverrides = segmentOverrides.map((v, i) => ({
...v,
originalPriority: i,
priority: i,
}))

const originalSegmentOverrides = _.cloneDeep(segmentOverrides)
this.setState({
environmentVariations:
Expand Down
2 changes: 1 addition & 1 deletion frontend/web/components/diff/DiffSegmentOverrides.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ const DiffSegmentOverrides: FC<DiffSegmentOverridesType> = ({
<TabItem
className='p-0'
tabLabel={
<div className='d-flex gap-2'>
<div className='d-flex align-items-center'>
Created <div className='unread'>{created.length}</div>
</div>
}
Expand Down
11 changes: 9 additions & 2 deletions frontend/web/components/modals/CreateFlag/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ const Index = class extends Component {
projectFlag.multivariate_options.length &&
controlValue < 0
const existingChangeRequest = this.props.changeRequest
const isVersionedChangeRequest = existingChangeRequest && isVersioned
const hideIdentityOverridesTab = Utils.getShouldHideIdentityOverridesTab()
const noPermissions = this.props.noPermissions
let regexValid = true
Expand Down Expand Up @@ -570,6 +571,10 @@ const Index = class extends Component {
this.fetchChangeRequests(true)
this.fetchScheduledChangeRequests(true)
}

if (this.props.changeRequest) {
this.close()
}
}}
>
{(
Expand Down Expand Up @@ -672,7 +677,8 @@ const Index = class extends Component {
description,
featureStateId:
this.props.changeRequest &&
this.props.changeRequest.feature_states[0].id,
this.props.changeRequest.feature_states?.[0]
?.id,
id:
this.props.changeRequest &&
this.props.changeRequest.id,
Expand Down Expand Up @@ -839,7 +845,8 @@ const Index = class extends Component {
onSaveFeatureValue={saveFeatureValue}
/>
</TabItem>
{!existingChangeRequest && (
{(!existingChangeRequest ||
isVersionedChangeRequest) && (
<TabItem
data-test='segment_overrides'
tabLabelString='Segment Overrides'
Expand Down
63 changes: 52 additions & 11 deletions frontend/web/components/pages/ChangeRequestDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { useGetMyGroupsQuery } from 'common/services/useMyGroup'
import CreateFeatureModal from 'components/modals/CreateFlag'
import AccountStore from 'common/stores/account-store'
import AppActions from 'common/dispatcher/app-actions'
import { mergeChangeSets } from 'common/services/useChangeRequest'
import { getFeatureStates } from 'common/services/useFeatureState'
import { getStore } from 'common/store'
import {
ChangeRequest,
Environment,
Expand Down Expand Up @@ -156,29 +159,67 @@ const ChangeRequestDetailPage: FC<ChangeRequestPageType> = ({ match }) => {
})
}

const editChangeRequest = (
const editChangeRequest = async (
projectFlag: ProjectFlag,
environmentFlag: FeatureState,
) => {
if (!changeRequest) return

const environment: Environment = ProjectStore.getEnvironment(
environmentId,
) as any

const isVersioned = !!environment?.use_v2_feature_versioning
let changedEnvironmentFlag = environmentFlag

if (isVersioned && changeRequest.change_sets) {
// Convert the changesets into a feature state
const currentFeatureStatesResponse = await getFeatureStates(getStore(), {
environment: environment.id,
feature: projectFlag.id,
})
const mergedStates = mergeChangeSets(
changeRequest.change_sets,
currentFeatureStatesResponse.data.results,
changeRequest.conflicts,
)
const mergedEnvFlag = mergedStates.find(
(v) => !v.feature_segment?.segment,
)
if (mergedEnvFlag) {
changedEnvironmentFlag = {
...environmentFlag,
...mergedEnvFlag,
feature_state_value: Utils.featureStateToValue(
mergedEnvFlag.feature_state_value,
),
}
}
} else if (!isVersioned && changeRequest.feature_states?.[0]) {
changedEnvironmentFlag = {
...environmentFlag,
enabled: changeRequest.feature_states[0].enabled,
feature_state_value: Utils.featureStateToValue(
changeRequest.feature_states[0].feature_state_value,
),
}
}

openModal(
'Edit Change Request',
<CreateFeatureModal
history={history}
environmentId={environmentId}
projectId={projectId}
schangeRequest={changeRequest}
changeRequest={changeRequest}
projectFlag={projectFlag}
environmentFlag={changedEnvironmentFlag}
multivariate_options={
changeRequest.feature_states[0].multivariate_feature_state_values
!isVersioned
? changeRequest.feature_states?.[0]
?.multivariate_feature_state_values
: undefined
}
environmentFlag={{
...environmentFlag,
enabled: changeRequest.feature_states[0].enabled,
feature_state_value: Utils.featureStateToValue(
changeRequest.feature_states[0].feature_state_value,
),
}}
flagId={environmentFlag.id}
/>,
'side-modal create-feature-modal',
Expand Down Expand Up @@ -310,7 +351,7 @@ const ChangeRequestDetailPage: FC<ChangeRequestPageType> = ({ match }) => {
scheduledDate={getChangeRequestLiveDate(changeRequest)}
deleteChangeRequest={deleteChangeRequest}
editChangeRequest={
!isVersioned && !changeRequest?.committed_at
!changeRequest?.committed_at
? () => editChangeRequest(projectFlag, environmentFlag)
: undefined
}
Expand Down
Loading