From f5ed3eaa1f7a5c531f7641e2ee6f8cab8a64ba3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivar=20Conradi=20=C3=98sthus?= Date: Fri, 7 Aug 2020 09:36:32 +0200 Subject: [PATCH 1/6] feat: Add stale marking of feature toggles --- frontend/src/component/common/index.js | 4 +- .../feature-list-item-component-test.jsx.snap | 4 +- .../view-component-test.jsx.snap | 46 +++++++++++++++++++ .../feature/feature-list-item-component.jsx | 9 ++-- frontend/src/component/feature/feature.scss | 5 +- .../component/feature/status-component.jsx | 28 +++++++++++ .../feature/status-update-component.jsx | 37 +++++++++++++++ .../src/component/feature/view-component.jsx | 16 +++++++ .../src/component/feature/view-container.jsx | 2 + frontend/src/data/feature-api.js | 12 +++++ frontend/src/store/feature-actions.js | 22 +++++++++ 11 files changed, 176 insertions(+), 9 deletions(-) create mode 100644 frontend/src/component/feature/status-component.jsx create mode 100644 frontend/src/component/feature/status-update-component.jsx diff --git a/frontend/src/component/common/index.js b/frontend/src/component/common/index.js index 8493bc2567..1daa5a6bfc 100644 --- a/frontend/src/component/common/index.js +++ b/frontend/src/component/common/index.js @@ -140,8 +140,8 @@ IconLink.propTypes = { icon: PropTypes.string, }; -export const DropdownButton = ({ label, id }) => ( - diff --git a/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap b/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap index 9e510db3ea..719d267548 100644 --- a/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap +++ b/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap @@ -47,7 +47,7 @@ exports[`renders correctly with one feature 1`] = ` className="listItemStrategies hideLt920" > @@ -100,7 +100,7 @@ exports[`renders correctly with one feature without permission 1`] = ` className="listItemStrategies hideLt920" > diff --git a/frontend/src/component/feature/__tests__/__snapshots__/view-component-test.jsx.snap b/frontend/src/component/feature/__tests__/__snapshots__/view-component-test.jsx.snap index effe2d0ec1..75e93cb14f 100644 --- a/frontend/src/component/feature/__tests__/__snapshots__/view-component-test.jsx.snap +++ b/frontend/src/component/feature/__tests__/__snapshots__/view-component-test.jsx.snap @@ -10,6 +10,19 @@ exports[`renders correctly with one feature 1`] = ` } } > + + Active +
+ + + Status + + + + + Set toggle Active + + + Mark toggle as Stale + + + { - const { name, description, enabled, type } = feature; + const { name, description, enabled, type, stale } = feature; const { showLastHour = false } = settings; const isStale = showLastHour ? metricsLastHour.isFallback : metricsLastMinute.isFallback; const percent = @@ -25,7 +26,6 @@ const Feature = ({ (showLastHour ? calc(metricsLastHour.yes, metricsLastHour.yes + metricsLastHour.no, 0) : calc(metricsLastMinute.yes, metricsLastMinute.yes + metricsLastMinute.no, 0)); - const typeChip = {type}; const featureUrl = toggleFeature === undefined ? `/archive/strategies/${name}` : `/features/strategies/${name}`; return ( @@ -51,7 +51,10 @@ const Feature = ({ {description} - {typeChip} + + + {type} + {revive && hasPermission(UPDATE_FEATURE) ? ( revive(feature.name)}> diff --git a/frontend/src/component/feature/feature.scss b/frontend/src/component/feature/feature.scss index bba65140ce..a8e127f020 100644 --- a/frontend/src/component/feature/feature.scss +++ b/frontend/src/component/feature/feature.scss @@ -35,6 +35,7 @@ } .typeChip { - margin-left: 8px !important; - background: #d3c1ff; + margin: 0 8px !important; + box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); + background-color: #cfd8dc !important; } \ No newline at end of file diff --git a/frontend/src/component/feature/status-component.jsx b/frontend/src/component/feature/status-component.jsx new file mode 100644 index 0000000000..75afb8f3a8 --- /dev/null +++ b/frontend/src/component/feature/status-component.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { Chip } from 'react-mdl'; +import PropTypes from 'prop-types'; + +export default function StatusComponent({ stale, style, showActive = true }) { + if (!stale && !showActive) { + return null; + } + + const className = stale + ? 'mdl-color--red mdl-color-text--white mdl-shadow--2dp' + : 'mdl-color--light-green-500 mdl-color-text--white mdl-shadow--2dp'; + + const title = stale ? 'Feature toggle is deprecated.' : 'Feature toggle is active.'; + const value = stale ? 'Stale' : 'Active'; + + return ( + + {value} + + ); +} + +StatusComponent.propTypes = { + stale: PropTypes.bool.isRequired, + style: PropTypes.object, + showActive: PropTypes.bool, +}; diff --git a/frontend/src/component/feature/status-update-component.jsx b/frontend/src/component/feature/status-update-component.jsx new file mode 100644 index 0000000000..f5dfbbea8e --- /dev/null +++ b/frontend/src/component/feature/status-update-component.jsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { Menu, MenuItem } from 'react-mdl'; +import { DropdownButton } from '../common'; +import PropTypes from 'prop-types'; + +export default function StatusUpdateComponent({ stale, updateStale }) { + function setStatus(field) { + if (field === 'active') { + updateStale(false); + } else { + updateStale(true); + } + } + + return ( + + + setStatus(e.target.getAttribute('data-target'))} + style={{ width: '168px' }} + > + + Set toggle Active + + + Mark toggle as Stale + + + + ); +} + +StatusUpdateComponent.propTypes = { + stale: PropTypes.bool.isRequired, + updateStale: PropTypes.func.isRequired, +}; diff --git a/frontend/src/component/feature/view-component.jsx b/frontend/src/component/feature/view-component.jsx index 37ac1cf42d..f8f5ecfeda 100644 --- a/frontend/src/component/feature/view-component.jsx +++ b/frontend/src/component/feature/view-component.jsx @@ -12,6 +12,8 @@ import FeatureTypeSelect from './form/feature-type-select-container'; import UpdateDescriptionComponent from './form/update-description-component'; import { styles as commonStyles } from '../common'; import { CREATE_FEATURE, DELETE_FEATURE, UPDATE_FEATURE } from '../../permissions'; +import StatusComponent from './status-component'; +import StatusUpdateComponent from './status-update-component'; const TABS = { strategies: 0, @@ -32,6 +34,7 @@ export default class ViewFeatureToggleComponent extends React.Component { featureToggleName: PropTypes.string.isRequired, features: PropTypes.array.isRequired, toggleFeature: PropTypes.func, + setStale: PropTypes.func, removeFeatureToggle: PropTypes.func, revive: PropTypes.func, fetchArchive: PropTypes.func, @@ -159,8 +162,20 @@ export default class ViewFeatureToggleComponent extends React.Component { this.props.editFeatureToggle(feature); }; + const updateStale = stale => { + this.props.setStale(stale, featureToggleName); + }; + return ( + {featureToggle.name} + response.json()); +} + function remove(featureToggleName) { return fetch(`${URI}/${featureToggleName}`, { method: 'DELETE', @@ -75,5 +86,6 @@ export default { validate, update, toggle, + setStale, remove, }; diff --git a/frontend/src/store/feature-actions.js b/frontend/src/store/feature-actions.js index 5ad8d57bd6..39d978e273 100644 --- a/frontend/src/store/feature-actions.js +++ b/frontend/src/store/feature-actions.js @@ -26,6 +26,13 @@ export function toggleFeature(enable, name) { }; } +export function setStale(stale, name) { + debug('Set stale property on feature toggle ', name); + return dispatch => { + dispatch(requestSetStaleFeatureToggle(stale, name)); + }; +} + export function editFeatureToggle(featureToggle) { debug('Update feature toggle ', featureToggle); return dispatch => { @@ -76,6 +83,21 @@ export function requestToggleFeatureToggle(enable, name) { }; } +export function requestSetStaleFeatureToggle(stale, name) { + return dispatch => { + dispatch({ type: START_UPDATE_FEATURE_TOGGLE }); + + return api + .setStale(stale, name) + .then(featureToggle => { + const info = `${name} marked as ${stale ? 'Stale' : 'Active'}.`; + setTimeout(() => dispatch({ type: MUTE_ERROR, error: info }), 1000); + dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle, info }); + }) + .catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE)); + }; +} + export function requestUpdateFeatureToggle(featureToggle) { return dispatch => { dispatch({ type: START_UPDATE_FEATURE_TOGGLE }); From 303b6edb994f1617fbc421ca6e8b51618d7d2b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivar=20Conradi=20=C3=98sthus?= Date: Fri, 7 Aug 2020 10:08:23 +0200 Subject: [PATCH 2/6] feat: added time-ago to toggle-list --- frontend/package.json | 4 +++- frontend/src/component/common/common.scss | 5 +++++ .../src/component/feature/feature-list-item-component.jsx | 8 ++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index cdbf4c62d5..11b4fddc30 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -38,7 +38,9 @@ "prepublish": "npm run build" }, "main": "./index.js", - "dependencies": {}, + "dependencies": { + "react-timeago": "^4.4.0" + }, "devDependencies": { "@babel/core": "^7.9.0", "@babel/plugin-proposal-class-properties": "^7.8.3", diff --git a/frontend/src/component/common/common.scss b/frontend/src/component/common/common.scss index 0cc41bb254..487a3a0a14 100644 --- a/frontend/src/component/common/common.scss +++ b/frontend/src/component/common/common.scss @@ -81,3 +81,8 @@ text-transform: none; font-weight: normal; } + +.toggleName { + color: #37474f !important; + font-weight: 500; +} \ No newline at end of file diff --git a/frontend/src/component/feature/feature-list-item-component.jsx b/frontend/src/component/feature/feature-list-item-component.jsx index 1197c3469e..28cfe751a1 100644 --- a/frontend/src/component/feature/feature-list-item-component.jsx +++ b/frontend/src/component/feature/feature-list-item-component.jsx @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Link } from 'react-router-dom'; import { Switch, Chip, ListItem, ListItemAction, Icon } from 'react-mdl'; +import TimeAgo from 'react-timeago'; import Progress from './progress'; import { UPDATE_FEATURE } from '../../permissions'; import { calc, styles as commonStyles } from '../common'; @@ -18,7 +19,7 @@ const Feature = ({ revive, hasPermission, }) => { - const { name, description, enabled, type, stale } = feature; + const { name, description, enabled, type, stale, createdAt } = feature; const { showLastHour = false } = settings; const isStale = showLastHour ? metricsLastHour.isFallback : metricsLastMinute.isFallback; const percent = @@ -47,7 +48,10 @@ const Feature = ({ - {name} + {name}  + + + {description} From a0bad364e8a9996ee6650c89eebe3d7fb6bc4b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivar=20Conradi=20=C3=98sthus?= Date: Fri, 7 Aug 2020 10:12:05 +0200 Subject: [PATCH 3/6] feat: stort by stale --- .../feature-list-item-component-test.jsx.snap | 34 +++++++++++++++++-- .../list-component-test.jsx.snap | 12 +++++++ .../src/component/feature/list-component.jsx | 3 ++ .../src/component/feature/list-container.jsx | 5 +++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap b/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap index 719d267548..f379b078d6 100644 --- a/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap +++ b/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap @@ -35,7 +35,22 @@ exports[`renders correctly with one feature 1`] = ` href="/features/strategies/Another" onClick={[Function]} > - Another + + Another +   + + + + @@ -88,7 +103,22 @@ exports[`renders correctly with one feature without permission 1`] = ` href="/features/strategies/Another" onClick={[Function]} > - Another + + Another +   + + + + diff --git a/frontend/src/component/feature/__tests__/__snapshots__/list-component-test.jsx.snap b/frontend/src/component/feature/__tests__/__snapshots__/list-component-test.jsx.snap index a9045b9eac..e445dfd8e7 100644 --- a/frontend/src/component/feature/__tests__/__snapshots__/list-component-test.jsx.snap +++ b/frontend/src/component/feature/__tests__/__snapshots__/list-component-test.jsx.snap @@ -136,6 +136,12 @@ exports[`renders correctly with one feature 1`] = ` > Enabled + + Stale + Enabled + + Stale + Enabled + + Stale + Created diff --git a/frontend/src/component/feature/list-container.jsx b/frontend/src/component/feature/list-container.jsx index 54b5733a92..47b5d6f9d6 100644 --- a/frontend/src/component/feature/list-container.jsx +++ b/frontend/src/component/feature/list-container.jsx @@ -33,6 +33,11 @@ export const mapStateToPropsConfigurable = isFeature => state => { // eslint-disable-next-line a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1 ); + } else if (settings.sort === 'stale') { + features = features.sort((a, b) => + // eslint-disable-next-line + a.stale === b.stale ? 0 : a.stale ? -1 : 1 + ); } else if (settings.sort === 'created') { features = features.sort((a, b) => (new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1)); } else if (settings.sort === 'name') { From 1ac720267ca2c4800db592465207baaf8255915f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivar=20Conradi=20=C3=98sthus?= Date: Fri, 7 Aug 2020 10:27:26 +0200 Subject: [PATCH 4/6] fix: yarn.lock --- frontend/yarn.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 9ca0713b81..9b0a966187 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -7965,6 +7965,11 @@ react-test-renderer@^16.0.0-0, react-test-renderer@^16.13.1: react-is "^16.8.6" scheduler "^0.19.1" +react-timeago@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/react-timeago/-/react-timeago-4.4.0.tgz#4520dd9ba63551afc4d709819f52b14b9343ba2b" + integrity sha512-Zj8RchTqZEH27LAANemzMR2RpotbP2aMd+UIajfYMZ9KW4dMcViUVKzC7YmqfiqlFfz8B0bjDw2xUBjmcxDngA== + react-transition-group@^4.3.0: version "4.4.1" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" From bf4ac6ab6d82ad2700064eb1bda7fed910ec6388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivar=20Conradi=20=C3=98sthus?= Date: Fri, 7 Aug 2020 10:27:39 +0200 Subject: [PATCH 5/6] fix: imporve type-chip color --- frontend/src/component/feature/feature.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/component/feature/feature.scss b/frontend/src/component/feature/feature.scss index a8e127f020..4526f638f9 100644 --- a/frontend/src/component/feature/feature.scss +++ b/frontend/src/component/feature/feature.scss @@ -37,5 +37,5 @@ .typeChip { margin: 0 8px !important; box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); - background-color: #cfd8dc !important; + background-color: #b0bec5 !important; } \ No newline at end of file From 571adc5803f1a0e41099fa7680d686a0fe18ab2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivar=20Conradi=20=C3=98sthus?= Date: Fri, 7 Aug 2020 10:35:00 +0200 Subject: [PATCH 6/6] fix: dependencies --- frontend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/package.json b/frontend/package.json index 11b4fddc30..aa7a2b05c6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -39,7 +39,6 @@ }, "main": "./index.js", "dependencies": { - "react-timeago": "^4.4.0" }, "devDependencies": { "@babel/core": "^7.9.0", @@ -86,6 +85,7 @@ "react-redux": "^7.2.0", "react-router-dom": "^5.1.2", "react-select": "^3.1.0", + "react-timeago": "^4.4.0", "react-test-renderer": "^16.13.1", "redux": "^4.0.5", "redux-devtools": "^3.5.0",