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
15 changes: 13 additions & 2 deletions frontend/web/components/CompareEnvironments.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { withRouter } from 'react-router-dom'
import { getDarkMode } from 'project/darkMode'
import { getStore } from 'common/store'
import { removeProjectFlag } from 'common/services/useProjectFlag'
import { hasMultivariateChange } from 'components/compare-multivariate-utils'

const featureNameWidth = 300

Expand Down Expand Up @@ -111,9 +112,14 @@ class CompareEnvironments extends Component {
}
change.enabledChanged = change.rightEnabled !== change.leftEnabled
change.valueChanged = change.rightValue !== change.leftValue
change.multivariateChanged = hasMultivariateChange(
leftSide,
rightSide,
)
if (
change.enabledChanged ||
change.valueChanged ||
change.multivariateChanged ||
projectFlagLeft.num_identity_overrides ||
projectFlagLeft.num_segment_overrides ||
projectFlagRight.num_identity_overrides ||
Expand Down Expand Up @@ -412,7 +418,12 @@ class CompareEnvironments extends Component {
className='no-pad mt-2'
items={this.filter(this.state.changes)}
renderRow={(p, i) =>
renderRow(p, i, !p.enabledChanged, !p.valueChanged)
renderRow(
p,
i,
!p.enabledChanged,
!(p.valueChanged || p.multivariateChanged),
)
}
/>
</div>
Expand Down Expand Up @@ -467,7 +478,7 @@ class CompareEnvironments extends Component {
p,
i,
!p.enabledChanged,
!p.valueChanged,
!(p.valueChanged || p.multivariateChanged),
)
}
/>
Expand Down
4 changes: 3 additions & 1 deletion frontend/web/components/CompareFeatures.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Permission from 'common/providers/Permission'
import { withRouter } from 'react-router-dom'
import { getStore } from 'common/store'
import { removeProjectFlag } from 'common/services/useProjectFlag'
import { hasMultivariateChange } from 'components/compare-multivariate-utils'

const featureNameWidth = 300

Expand Down Expand Up @@ -118,7 +119,8 @@ class CompareFeatures extends Component {
const flagB = compare[this.state.flagId]
const fadeEnabled = flagA.enabled === flagB.enabled
const fadeValue =
flagB.feature_state_value === flagA.feature_state_value
flagB.feature_state_value === flagA.feature_state_value &&
!hasMultivariateChange(flagA, flagB)
const changeRequestsEnabled = Utils.changeRequestsEnabled(
data.minimum_change_request_approvals,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { FeatureState } from 'common/types/responses'
import { hasMultivariateChange } from 'components/compare-multivariate-utils'

const featureState = (
multivariate_feature_state_values: FeatureState['multivariate_feature_state_values'],
): FeatureState =>
({
multivariate_feature_state_values,
}) as FeatureState

describe('hasMultivariateChange', () => {
it('returns false when both sides have no multivariate values', () => {
expect(hasMultivariateChange(featureState([]), featureState([]))).toBe(false)
expect(hasMultivariateChange(undefined, undefined)).toBe(false)
})

it('returns true when percentage allocations differ', () => {
const left = featureState([
{ id: 1, multivariate_feature_option: 10, percentage_allocation: 0 },
])
const right = featureState([
{ id: 2, multivariate_feature_option: 10, percentage_allocation: 100 },
])

expect(hasMultivariateChange(left, right)).toBe(true)
})

it('returns true when the number of multivariate options differs', () => {
const left = featureState([
{ id: 1, multivariate_feature_option: 10, percentage_allocation: 50 },
])
const right = featureState([
{ id: 2, multivariate_feature_option: 10, percentage_allocation: 50 },
{ id: 3, multivariate_feature_option: 11, percentage_allocation: 50 },
])

expect(hasMultivariateChange(left, right)).toBe(true)
})

it('returns false when values match regardless of array order', () => {
const left = featureState([
{ id: 1, multivariate_feature_option: 10, percentage_allocation: 0 },
{ id: 2, multivariate_feature_option: 11, percentage_allocation: 100 },
])
const right = featureState([
{ id: 3, multivariate_feature_option: 11, percentage_allocation: 100 },
{ id: 4, multivariate_feature_option: 10, percentage_allocation: 0 },
])

expect(hasMultivariateChange(left, right)).toBe(false)
})
})
40 changes: 40 additions & 0 deletions frontend/web/components/compare-multivariate-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { FeatureState } from 'common/types/responses'

const normaliseMultivariate = (featureState?: FeatureState) => {
const values = featureState?.multivariate_feature_state_values || []
return values
.map((v) => ({
multivariate_feature_option: Number(v?.multivariate_feature_option) || 0,
percentage_allocation: Number(v?.percentage_allocation) || 0,
}))
Comment thread
10done marked this conversation as resolved.
.sort((a, b) => {
if (a.multivariate_feature_option !== b.multivariate_feature_option) {
return a.multivariate_feature_option - b.multivariate_feature_option
}
return a.percentage_allocation - b.percentage_allocation
})
}

export const hasMultivariateChange = (
leftFeatureState?: FeatureState,
rightFeatureState?: FeatureState,
) => {
const left = normaliseMultivariate(leftFeatureState)
const right = normaliseMultivariate(rightFeatureState)

if (left.length !== right.length) {
return true
}

for (let i = 0; i < left.length; i++) {
if (
left[i].multivariate_feature_option !==
right[i].multivariate_feature_option ||
left[i].percentage_allocation !== right[i].percentage_allocation
) {
return true
}
}

return false
}
Loading