diff --git a/frontend/src/component/common/util.js b/frontend/src/component/common/util.js
index 872c4f0c6f..86f0dd7493 100644
--- a/frontend/src/component/common/util.js
+++ b/frontend/src/component/common/util.js
@@ -1,3 +1,5 @@
+import { weightTypes } from '../feature/variant/enums';
+
const dateTimeOptions = {
day: '2-digit',
month: '2-digit',
@@ -22,11 +24,37 @@ export const trim = value => {
};
export function updateWeight(variants, totalWeight) {
- const size = variants.length;
- const percentage = parseInt((1 / size) * totalWeight);
+ const variantMetadata = variants.reduce(
+ ({ remainingPercentage, variableVariantCount }, variant) => {
+ if (variant.weight && variant.weightType === weightTypes.FIX) {
+ remainingPercentage -= Number(variant.weight);
+ } else {
+ variableVariantCount += 1;
+ }
+ return {
+ remainingPercentage,
+ variableVariantCount,
+ };
+ },
+ { remainingPercentage: totalWeight, variableVariantCount: 0 }
+ );
- variants.forEach(v => {
- v.weight = percentage;
+ const { remainingPercentage, variableVariantCount } = variantMetadata;
+
+ if (remainingPercentage < 0) {
+ throw new Error('The traffic distribution total must equal 100%');
+ }
+
+ if (!variableVariantCount) {
+ throw new Error('There must be atleast one variable variant');
+ }
+
+ const percentage = parseInt(remainingPercentage / variableVariantCount);
+
+ return variants.map(variant => {
+ if (variant.weightType !== weightTypes.FIX) {
+ variant.weight = percentage;
+ }
+ return variant;
});
- return variants;
}
diff --git a/frontend/src/component/feature/variant/__tests__/__snapshots__/update-variant-component-test.jsx.snap b/frontend/src/component/feature/variant/__tests__/__snapshots__/update-variant-component-test.jsx.snap
index 491fde6295..af0fb988c9 100644
--- a/frontend/src/component/feature/variant/__tests__/__snapshots__/update-variant-component-test.jsx.snap
+++ b/frontend/src/component/feature/variant/__tests__/__snapshots__/update-variant-component-test.jsx.snap
@@ -37,6 +37,9 @@ exports[`renders correctly with with variants 1`] = `
Weight
|
+
+ Weight Type
+ |
|
@@ -67,6 +70,9 @@ exports[`renders correctly with with variants 1`] = `
3.4
%
+
+ Variable
+ |
@@ -95,6 +101,9 @@ exports[`renders correctly with with variants 1`] = `
3.3
%
|
+
+ Variable
+ |
@@ -126,6 +135,9 @@ exports[`renders correctly with with variants 1`] = `
3.3
%
|
+
+ Fix
+ |
diff --git a/frontend/src/component/feature/variant/__tests__/update-variant-component-test.jsx b/frontend/src/component/feature/variant/__tests__/update-variant-component-test.jsx
index cad73143e1..028d752b33 100644
--- a/frontend/src/component/feature/variant/__tests__/update-variant-component-test.jsx
+++ b/frontend/src/component/feature/variant/__tests__/update-variant-component-test.jsx
@@ -4,6 +4,7 @@ import { MemoryRouter } from 'react-router-dom';
import UpdateVariant from './../update-variant-component';
import renderer from 'react-test-renderer';
import { UPDATE_FEATURE } from '../../../../permissions';
+import { weightTypes } from '../enums';
jest.mock('react-mdl');
@@ -72,6 +73,7 @@ test('renders correctly with with variants', () => {
{
name: 'orange',
weight: 33,
+ weightType: weightTypes.FIX,
payload: {
type: 'string',
value: '{"color": "blue", "animated": false}',
diff --git a/frontend/src/component/feature/variant/add-variant.jsx b/frontend/src/component/feature/variant/add-variant.jsx
index bf63b306c8..20d75c3d38 100644
--- a/frontend/src/component/feature/variant/add-variant.jsx
+++ b/frontend/src/component/feature/variant/add-variant.jsx
@@ -1,9 +1,11 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import Modal from 'react-modal';
-import { Button, Textfield, DialogActions, Grid, Cell, Icon } from 'react-mdl';
+import { Button, Textfield, DialogActions, Grid, Cell, Icon, Switch } from 'react-mdl';
+import styles from './variant.scss';
import MySelect from '../../common/select';
import { trim } from '../form/util';
+import { weightTypes } from './enums';
import OverrideConfig from './override-config';
Modal.setAppElement('#app');
@@ -46,7 +48,11 @@ function AddVariant({ showDialog, closeDialog, save, validateName, editVariant,
const clear = () => {
if (editVariant) {
- setData({ name: editVariant.name });
+ setData({
+ name: editVariant.name,
+ weight: editVariant.weight / 10,
+ weightType: editVariant.weightType || weightTypes.VARIABLE,
+ });
if (editVariant.payload) {
setPayload(editVariant.payload);
}
@@ -67,11 +73,20 @@ function AddVariant({ showDialog, closeDialog, save, validateName, editVariant,
clear();
}, [editVariant]);
- const setName = e => {
- e.preventDefault();
+ const setVariantValue = e => {
+ const { name, value } = e.target;
setData({
...data,
- [e.target.name]: trim(e.target.value),
+ [name]: trim(value),
+ });
+ };
+
+ const setVariantWeightType = e => {
+ const { checked, name } = e.target;
+ const weightType = checked ? weightTypes.FIX : weightTypes.VARIABLE;
+ setData({
+ ...data,
+ [name]: weightType,
});
};
@@ -88,6 +103,8 @@ function AddVariant({ showDialog, closeDialog, save, validateName, editVariant,
try {
const variant = {
name: data.name,
+ weight: data.weight * 10,
+ weightType: data.weightType,
payload: payload.value ? payload : undefined,
overrides: overrides
.map(o => ({
@@ -100,7 +117,7 @@ function AddVariant({ showDialog, closeDialog, save, validateName, editVariant,
clear();
closeDialog();
} catch (error) {
- const msg = error.error || 'Could not add variant';
+ const msg = error.message || 'Could not add variant';
setError({ general: msg });
}
};
@@ -152,6 +169,8 @@ function AddVariant({ showDialog, closeDialog, save, validateName, editVariant,
setOverrides([...overrides, ...[{ contextName: 'userId', values: [] }]]);
};
+ const isFixWeight = data.weightType === weightTypes.FIX;
+
return (
{title}
@@ -167,10 +186,33 @@ function AddVariant({ showDialog, closeDialog, save, validateName, editVariant,
value={data.name}
error={error.name}
type="name"
- onChange={setName}
+ onChange={setVariantValue}
/>
-
+
+
+
+ %
+ |
+
+
+ Custom percentage
+
+ |
+
Payload
@@ -198,13 +240,11 @@ function AddVariant({ showDialog, closeDialog, save, validateName, editVariant,
/>
- {overrides.length > 0 ? (
+ {overrides.length > 0 && (
Overrides
- ) : (
- undefined
)}
Variant name
|
Weight |
+ Weight Type |
|
diff --git a/frontend/src/component/feature/variant/variant-view-component.jsx b/frontend/src/component/feature/variant/variant-view-component.jsx
index 8206261ab7..5ded86d604 100644
--- a/frontend/src/component/feature/variant/variant-view-component.jsx
+++ b/frontend/src/component/feature/variant/variant-view-component.jsx
@@ -1,11 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
-
import { IconButton, Chip } from 'react-mdl';
import styles from './variant.scss';
import { UPDATE_FEATURE } from '../../../permissions';
+import { weightTypes } from './enums';
function VariantViewComponent({ variant, editVariant, removeVariant, hasPermission }) {
+ const { FIX } = weightTypes;
return (
{variant.name} |
@@ -18,6 +19,7 @@ function VariantViewComponent({ variant, editVariant, removeVariant, hasPermissi
)}
{variant.weight / 10.0} % |
+ {variant.weightType === FIX ? 'Fix' : 'Variable'} |
{hasPermission(UPDATE_FEATURE) ? (
diff --git a/frontend/src/component/feature/variant/variant.scss b/frontend/src/component/feature/variant/variant.scss
index 9097083a92..829e5ba9df 100644
--- a/frontend/src/component/feature/variant/variant.scss
+++ b/frontend/src/component/feature/variant/variant.scss
@@ -2,11 +2,13 @@
width: 100%;
max-width: 700px;
- th, td {
+ th,
+ td {
text-align: center;
width: 100px;
}
- th:first-of-type, td:first-of-type {
+ th:first-of-type,
+ td:first-of-type {
text-align: left;
width: 100%;
}
@@ -16,10 +18,10 @@
}
@media (max-width: 600px) {
- th.labels {
+ th.labels {
display: none;
}
- td.labels {
+ td.labels {
display: none;
}
}
@@ -58,4 +60,23 @@ td.actions {
i {
font-size: 18px;
}
-}
\ No newline at end of file
+}
+
+.inputWeight {
+ text-align: right;
+}
+
+.flexCenter {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.flex {
+ display: flex;
+ align-items: center;
+}
+
+.marginL10 {
+ margin-left: 10px;
+}
| |