Skip to content
Merged
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
11 changes: 10 additions & 1 deletion frontend/common/providers/FeatureListProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,16 @@ const FeatureListProvider = class extends React.Component {
newProjectFlag,
{
...environmentFlag,
multivariate_feature_state_values: flag.multivariate_options,
multivariate_feature_state_values: Utils.mapMvOptionsToStateValues(
newProjectFlag.multivariate_options?.map((opt, i) => ({
...opt,
default_percentage_allocation:
flag.multivariate_options?.[i]
?.default_percentage_allocation ??
opt.default_percentage_allocation,
})),
environmentFlag.multivariate_feature_state_values,
),
},
segmentOverrides,
changeRequest,
Expand Down
29 changes: 21 additions & 8 deletions frontend/common/stores/feature-list-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,18 @@ const convertSegmentOverrideToFeatureState = (
feature_state_value: override.value,
id: override.id,
live_from: changeRequest?.live_from,
multivariate_feature_state_values: override.multivariate_options,
multivariate_feature_state_values: changeRequest
? override.multivariate_options?.map((v) => ({
id: v.id,
multivariate_feature_option: v.multivariate_feature_option ?? v.id,
percentage_allocation:
v.percentage_allocation ?? v.default_percentage_allocation,
}))
: override.multivariate_options?.map((v) => ({
multivariate_feature_option: v.multivariate_feature_option ?? v.id,
percentage_allocation:
v.percentage_allocation ?? v.default_percentage_allocation,
})),
toRemove: override.toRemove,
} as Partial<FeatureState>
}
Expand Down Expand Up @@ -203,7 +214,6 @@ const controller = {
store.model && store.model.features
? store.model.features.find((v) => v.id === flag.id)
: flag

Promise.all(
(flag.multivariate_options || []).map((v, i) => {
const originalMV = v.id
Expand Down Expand Up @@ -631,13 +641,16 @@ const controller = {
(v.multivariate_feature_option || v.id) ===
(m.multivariate_feature_option || m.id),
)
return {
...v,
percentage_allocation: matching
? typeof matching.percentage_allocation === 'number'
let percentage_allocation = v.percentage_allocation
if (matching) {
percentage_allocation =
typeof matching.percentage_allocation === 'number'
? matching.percentage_allocation
: matching.default_percentage_allocation
: v.percentage_allocation,
}
return {
...v,
percentage_allocation,
}
},
)
Expand Down Expand Up @@ -733,7 +746,7 @@ const controller = {
getStore().dispatch(
projectFlagService.util.invalidateTags(['ProjectFlag']),
)
if(!store.model) {
if (!store.model) {
return
}
// Fetch and update the latest environment feature state
Expand Down
65 changes: 46 additions & 19 deletions frontend/common/utils/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,13 @@ const Utils = Object.assign({}, require('./base/_utils'), {
const variation =
variations &&
variations.find((env) => env.multivariate_feature_option === v.id)
total += variation
? variation.percentage_allocation
: typeof v.default_percentage_allocation === 'number'
? v.default_percentage_allocation
: (v as any).percentage_allocation
if (variation) {
total += variation.percentage_allocation
} else if (typeof v.default_percentage_allocation === 'number') {
total += v.default_percentage_allocation
} else {
total += (v as any).percentage_allocation
}
return null
})
return 100 - total
Expand Down Expand Up @@ -157,15 +159,21 @@ const Utils = Object.assign({}, require('./base/_utils'), {
displayLimitAlert(type: string, percentage: number | undefined) {
const envOrProject =
type === 'segment overrides' ? 'environment' : 'project'
return percentage >= 100 ? (
<ErrorMessage
error={`Your ${envOrProject} reached the limit of ${type}, please contact support to discuss increasing this limit.`}
/>
) : percentage ? (
<WarningMessage
warningMessage={`Your ${envOrProject} is using ${percentage}% of the total allowance of ${type}.`}
/>
) : null
if (percentage >= 100) {
return (
<ErrorMessage
error={`Your ${envOrProject} reached the limit of ${type}, please contact support to discuss increasing this limit.`}
/>
)
}
if (percentage) {
return (
<WarningMessage
warningMessage={`Your ${envOrProject} is using ${percentage}% of the total allowance of ${type}.`}
/>
)
}
return null
},
escapeHtml(html: string) {
const text = document.createTextNode(html)
Expand Down Expand Up @@ -477,11 +485,13 @@ const Utils = Object.assign({}, require('./base/_utils'), {
},
getPlansPermission: (feature: PaidFeature) => {
const isOrgPermission = feature !== '2FA'
const plans = isOrgPermission
? AccountStore.getActiveOrgPlan()
? [AccountStore.getActiveOrgPlan()]
: null
: AccountStore.getPlans()
let plans
if (isOrgPermission) {
const activeOrgPlan = AccountStore.getActiveOrgPlan()
plans = activeOrgPlan ? [activeOrgPlan] : null
} else {
plans = AccountStore.getPlans()
}

if (!plans || !plans.length) {
return false
Expand Down Expand Up @@ -669,6 +679,23 @@ const Utils = Object.assign({}, require('./base/_utils'), {
head.appendChild(script)
})
},
mapMvOptionsToStateValues(
mvOptions: MultivariateOption[],
existingMvFeatureStateValues: MultivariateFeatureStateValue[],
): MultivariateFeatureStateValue[] {
return mvOptions?.map((mvOption) => {
const existing = existingMvFeatureStateValues?.find(
(e) => e.multivariate_feature_option === mvOption.id,
)
return {
id: existing?.id,
multivariate_feature_option: mvOption.id,
percentage_allocation:
mvOption.default_percentage_allocation ??
existing?.percentage_allocation,
}
})
},

numberWithCommas(x: number) {
if (typeof x !== 'number') return ''
Expand Down
3 changes: 2 additions & 1 deletion frontend/web/components/diff/DiffFeature.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ const DiffFeature: FC<FeatureDiffType> = ({
<TabItem
className={'p-0'}
tabLabel={
<div>
<div className='d-flex justify-content-center gap-1 align-items-center'>
Variations{' '}
{variationDiffs.totalChanges ? (
<span className='unread'>
Expand Down Expand Up @@ -265,6 +265,7 @@ const DiffFeature: FC<FeatureDiffType> = ({
diffs={segmentDiffs.diffs}
projectId={projectId}
environmentId={environmentId}
projectFlag={projectFlag}
/>
</TabItem>
)}
Expand Down
14 changes: 13 additions & 1 deletion frontend/web/components/diff/DiffSegmentOverrides.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@ import Icon from 'components/Icon'
import Tooltip from 'components/Tooltip'
import { Link, useHistory } from 'react-router-dom'
import DiffVariations from './DiffVariations'
import { ProjectFlag } from 'common/types/responses'

type DiffSegmentOverride = {
diff: TDiffSegmentOverride
projectId: string
environmentId: string
projectFlag: ProjectFlag | undefined
}

const widths = [200, 80, 105]
const DiffSegmentOverride: FC<DiffSegmentOverride> = ({
diff,
environmentId,
projectFlag,
projectId,
}) => {
return (
Expand Down Expand Up @@ -71,7 +74,10 @@ const DiffSegmentOverride: FC<DiffSegmentOverride> = ({
</div>
<div className='px-3'>
{!!diff.variationDiff?.diffs && (
<DiffVariations diffs={diff.variationDiff.diffs} />
<DiffVariations
diffs={diff.variationDiff.diffs}
projectFlag={projectFlag}
/>
)}
</div>
</div>
Expand All @@ -82,10 +88,12 @@ type DiffSegmentOverridesType = {
diffs: TDiffSegmentOverride[] | undefined
projectId: string
environmentId: string
projectFlag: ProjectFlag | undefined
}
const DiffSegmentOverrides: FC<DiffSegmentOverridesType> = ({
diffs,
environmentId,
projectFlag,
projectId,
}) => {
const history = useHistory()
Expand Down Expand Up @@ -139,6 +147,7 @@ const DiffSegmentOverrides: FC<DiffSegmentOverridesType> = ({
{created.map((diff, i) => (
<DiffSegmentOverride
environmentId={environmentId}
projectFlag={projectFlag}
projectId={projectId}
key={i}
diff={diff}
Expand All @@ -159,6 +168,7 @@ const DiffSegmentOverrides: FC<DiffSegmentOverridesType> = ({
{deleted.map((diff, i) => (
<DiffSegmentOverride
environmentId={environmentId}
projectFlag={projectFlag}
projectId={projectId}
key={i}
diff={diff}
Expand All @@ -179,6 +189,7 @@ const DiffSegmentOverrides: FC<DiffSegmentOverridesType> = ({
{modified.map((diff, i) => (
<DiffSegmentOverride
environmentId={environmentId}
projectFlag={projectFlag}
projectId={projectId}
key={i}
diff={diff}
Expand All @@ -199,6 +210,7 @@ const DiffSegmentOverrides: FC<DiffSegmentOverridesType> = ({
{unChanged.map((diff, i) => (
<DiffSegmentOverride
environmentId={environmentId}
projectFlag={projectFlag}
projectId={projectId}
key={i}
diff={diff}
Expand Down
16 changes: 14 additions & 2 deletions frontend/web/components/diff/DiffVariations.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TDiffVariation } from './diff-utils'
import React, { FC } from 'react'
import React, { FC, useMemo } from 'react'
import DiffString from './DiffString'
import { DiffMethod } from 'react-diff-viewer-continued'
import { ProjectFlag } from 'common/types/responses'
Expand All @@ -12,6 +12,18 @@ type DiffVariationsType = {
projectFlag: ProjectFlag | undefined
}
const DiffVariations: FC<DiffVariationsType> = ({ diffs, projectFlag }) => {
const sortedDiffs = useMemo(() => {
if (!diffs || !projectFlag?.multivariate_options) return diffs
return [...diffs].sort((a, b) => {
const indexA = projectFlag.multivariate_options.findIndex(
(mv) => mv.id === a.variationOption,
)
const indexB = projectFlag.multivariate_options.findIndex(
(mv) => mv.id === b.variationOption,
)
return indexA - indexB
})
}, [diffs, projectFlag])
const tableHeader = (
<Row className='table-header mt-4'>
<div className='table-column flex-fill'>Value</div>
Expand All @@ -24,7 +36,7 @@ const DiffVariations: FC<DiffVariationsType> = ({ diffs, projectFlag }) => {
return (
<>
{tableHeader}
{diffs?.map((diff, i) => {
{sortedDiffs?.map((diff, i) => {
const variation = projectFlag?.multivariate_options?.find(
(v) => v.id === diff.variationOption,
)
Expand Down
60 changes: 40 additions & 20 deletions frontend/web/components/modals/CreateFlag.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,12 @@ const CreateFlag = class extends Component {
tags: this.state.tags,
},
projectFlag,
environmentFlag,
{
...environmentFlag,
multivariate_feature_state_values:
this.props.environmentVariations ||
environmentFlag?.multivariate_feature_state_values,
},
segmentOverrides,
)
}
Expand Down Expand Up @@ -1021,12 +1026,15 @@ const CreateFlag = class extends Component {
}),
])

let modalTitle = 'New Change Request'
if (schedule) {
modalTitle = 'New Scheduled Flag Update'
} else if (this.props.changeRequest) {
modalTitle = 'Update Change Request'
}

openModal2(
schedule
? 'New Scheduled Flag Update'
: this.props.changeRequest
? 'Update Change Request'
: 'New Change Request',
modalTitle,
<ChangeRequestModal
showIgnoreConflicts={true}
showAssignees={is4Eyes}
Expand Down Expand Up @@ -1534,6 +1542,30 @@ const CreateFlag = class extends Component {
permission:
manageSegmentsOverrides,
}) => {
const getButtonText =
() => {
if (isSaving) {
return existingChangeRequest
? 'Updating Change Request'
: 'Creating Change Request'
}
return existingChangeRequest
? 'Update Change Request'
: 'Create Change Request'
}

const getScheduleButtonText =
() => {
if (isSaving) {
return existingChangeRequest
? 'Updating Change Request'
: 'Scheduling Update'
}
return existingChangeRequest
? 'Update Change Request'
: 'Schedule Update'
}

if (
isVersioned &&
is4Eyes
Expand All @@ -1560,13 +1592,7 @@ const CreateFlag = class extends Component {
!savePermission
}
>
{isSaving
? existingChangeRequest
? 'Updating Change Request'
: 'Creating Change Request'
: existingChangeRequest
? 'Update Change Request'
: 'Create Change Request'}
{getButtonText()}
</Button>,
)
}
Expand Down Expand Up @@ -1599,13 +1625,7 @@ const CreateFlag = class extends Component {
!savePermission
}
>
{isSaving
? existingChangeRequest
? 'Updating Change Request'
: 'Scheduling Update'
: existingChangeRequest
? 'Update Change Request'
: 'Schedule Update'}
{getScheduleButtonText()}
</Button>
</>
)}
Expand Down
Loading