diff --git a/public/locales/en-US.json b/public/locales/en-US.json
index b172403a0..563128c43 100644
--- a/public/locales/en-US.json
+++ b/public/locales/en-US.json
@@ -49,12 +49,20 @@
"tableSkeletonAriaLabel": "Loading"
},
"curiosity-toolbar": {
+ "category": "Filter by",
+ "categoryPlaceholder": "Filter by",
"slaCategory": "SLA",
"slaNone": "No SLA",
"slaPlaceholder": "Filter by SLA",
"slaPremium": "Premium",
"slaSelfSupport": "Self-Support",
- "slaStandard": "Standard"
+ "slaStandard": "Standard",
+ "usageCategory": "Usage",
+ "usagePlaceholder": "Filter by usage",
+ "usageDevelopment": "Development/Test",
+ "usageDisaster": "Disaster Recovery",
+ "usageProduction": "Production",
+ "usageUnspecified": "Unspecified"
},
"curiosity-optin": {
"buttonActivate": "Activate {{appName}}",
diff --git a/src/components/c3GraphCard/c3GraphCard.js b/src/components/c3GraphCard/c3GraphCard.js
index 56c2fb258..ec520ac91 100644
--- a/src/components/c3GraphCard/c3GraphCard.js
+++ b/src/components/c3GraphCard/c3GraphCard.js
@@ -67,7 +67,7 @@ class C3GraphCard extends React.Component {
const { viewId } = this.props;
store.dispatch({
- type: reduxTypes.rhsm.SET_FILTER_GRANULARITY_RHSM,
+ type: reduxTypes.query.SET_QUERY_GRANULARITY_RHSM,
viewId,
[rhsmApiTypes.RHSM_API_QUERY_GRANULARITY]: value
});
diff --git a/src/components/graphCard/graphCard.js b/src/components/graphCard/graphCard.js
index 48f46e576..d616f5836 100644
--- a/src/components/graphCard/graphCard.js
+++ b/src/components/graphCard/graphCard.js
@@ -67,7 +67,7 @@ class GraphCard extends React.Component {
const { viewId } = this.props;
store.dispatch({
- type: reduxTypes.rhsm.SET_FILTER_GRANULARITY_RHSM,
+ type: reduxTypes.query.SET_QUERY_GRANULARITY_RHSM,
viewId,
[rhsmApiTypes.RHSM_API_QUERY_GRANULARITY]: value
});
diff --git a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
index d4ac3e31e..5ba1f50ab 100644
--- a/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
+++ b/src/components/i18n/__tests__/__snapshots__/i18n.test.js.snap
@@ -330,6 +330,14 @@ Array [
Object {
"file": "./src/components/toolbar/toolbar.js",
"keys": Array [
+ Object {
+ "key": "curiosity-toolbar.category",
+ "match": "t('curiosity-toolbar.category')",
+ },
+ Object {
+ "key": "curiosity-toolbar.categoryPlaceholder",
+ "match": "t('curiosity-toolbar.categoryPlaceholder')",
+ },
Object {
"key": "curiosity-toolbar.slaCategory",
"match": "t('curiosity-toolbar.slaCategory')",
@@ -342,6 +350,18 @@ Array [
"key": "curiosity-toolbar.slaPlaceholder",
"match": "t('curiosity-toolbar.slaPlaceholder')",
},
+ Object {
+ "key": "curiosity-toolbar.usageCategory",
+ "match": "t('curiosity-toolbar.usageCategory')",
+ },
+ Object {
+ "key": "curiosity-toolbar.usageCategory",
+ "match": "t('curiosity-toolbar.usageCategory')",
+ },
+ Object {
+ "key": "curiosity-toolbar.usagePlaceholder",
+ "match": "t('curiosity-toolbar.usagePlaceholder')",
+ },
],
},
Object {
@@ -363,6 +383,30 @@ Array [
"key": "curiosity-toolbar.slaNone",
"match": "translate('curiosity-toolbar.slaNone')",
},
+ Object {
+ "key": "curiosity-toolbar.usageDevelopment",
+ "match": "translate('curiosity-toolbar.usageDevelopment')",
+ },
+ Object {
+ "key": "curiosity-toolbar.usageDisaster",
+ "match": "translate('curiosity-toolbar.usageDisaster')",
+ },
+ Object {
+ "key": "curiosity-toolbar.usageProduction",
+ "match": "translate('curiosity-toolbar.usageProduction')",
+ },
+ Object {
+ "key": "curiosity-toolbar.usageUnspecified",
+ "match": "translate('curiosity-toolbar.usageUnspecified')",
+ },
+ Object {
+ "key": "curiosity-toolbar.slaCategory",
+ "match": "translate('curiosity-toolbar.slaCategory')",
+ },
+ Object {
+ "key": "curiosity-toolbar.usageCategory",
+ "match": "translate('curiosity-toolbar.usageCategory')",
+ },
],
},
Object {
diff --git a/src/components/openshiftView/__tests__/__snapshots__/openshiftView.test.js.snap b/src/components/openshiftView/__tests__/__snapshots__/openshiftView.test.js.snap
index 3e9ec782c..9166c4638 100644
--- a/src/components/openshiftView/__tests__/__snapshots__/openshiftView.test.js.snap
+++ b/src/components/openshiftView/__tests__/__snapshots__/openshiftView.test.js.snap
@@ -9,14 +9,12 @@ exports[`OpenshiftView Component should display an alternate graph on query-stri
t(curiosity-view.OpenShiftTitle, Subscription Watch)
-
@@ -85,14 +83,12 @@ exports[`OpenshiftView Component should have a fallback title: title 1`] = `
t(curiosity-view.OpenShiftTitle, Subscription Watch)
-
@@ -161,14 +157,12 @@ exports[`OpenshiftView Component should render a non-connected component: non-co
t(curiosity-view.OpenShiftTitle, Subscription Watch)
-
diff --git a/src/components/rhelView/__tests__/__snapshots__/rhelView.test.js.snap b/src/components/rhelView/__tests__/__snapshots__/rhelView.test.js.snap
index 27039a9d6..861171c79 100644
--- a/src/components/rhelView/__tests__/__snapshots__/rhelView.test.js.snap
+++ b/src/components/rhelView/__tests__/__snapshots__/rhelView.test.js.snap
@@ -9,14 +9,12 @@ exports[`RhelView Component should display an alternate graph on query-string up
t(curiosity-view.RHELTitle, Subscription Watch)
-
@@ -71,14 +69,12 @@ exports[`RhelView Component should have a fallback title: title 1`] = `
t(curiosity-view.RHELTitle, Subscription Watch)
-
@@ -133,14 +129,12 @@ exports[`RhelView Component should render a non-connected component: non-connect
t(curiosity-view.RHELTitle, Subscription Watch)
-
diff --git a/src/components/toolbar/__tests__/__snapshots__/toolbar.test.js.snap b/src/components/toolbar/__tests__/__snapshots__/toolbar.test.js.snap
index 78d949573..cacd02dfa 100644
--- a/src/components/toolbar/__tests__/__snapshots__/toolbar.test.js.snap
+++ b/src/components/toolbar/__tests__/__snapshots__/toolbar.test.js.snap
@@ -1,65 +1,672 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Toolbar Component should handle updating state and dispatching an sla filter: clear filters 1`] = `null`;
-
-exports[`Toolbar Component should handle updating state and dispatching an sla filter: sla selected 1`] = `null`;
+exports[`Toolbar Component should handle adding and clearing filters from redux state: dispatch filter 1`] = `
+[MockFunction] {
+ "calls": Array [
+ Array [
+ Object {
+ "data": Object {
+ "currentFilter": "sla",
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ ],
+ Array [
+ Array [
+ Object {
+ "data": Object {
+ "activeFilters": Set {
+ "sla",
+ },
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "sla": "premium",
+ },
+ "type": "SET_QUERY_SLA_RHSM",
+ },
+ ],
+ ],
+ Array [
+ Array [
+ Object {
+ "data": Object {
+ "activeFilters": Set {
+ "sla",
+ },
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "sla": "standard",
+ },
+ "type": "SET_QUERY_SLA_RHSM",
+ },
+ ],
+ ],
+ Array [
+ Array [
+ Object {
+ "data": Object {
+ "currentFilter": null,
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ Object {
+ "data": Object {
+ "activeFilters": Set {},
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "clearFilters": Object {
+ "sla": null,
+ },
+ },
+ "type": "SET_QUERY_CLEAR",
+ },
+ ],
+ ],
+ Array [
+ Object {
+ "data": Object {
+ "currentFilter": "usage",
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ ],
+ Array [
+ Array [
+ Object {
+ "data": Object {
+ "activeFilters": Set {
+ "usage",
+ },
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "usage": "Development/Test",
+ },
+ "type": "SET_QUERY_USAGE_RHSM",
+ },
+ ],
+ ],
+ Array [
+ Array [
+ Object {
+ "data": Object {
+ "activeFilters": Set {
+ "usage",
+ },
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "usage": "Disaster Recovery",
+ },
+ "type": "SET_QUERY_USAGE_RHSM",
+ },
+ ],
+ ],
+ Array [
+ Array [
+ Object {
+ "data": Object {
+ "currentFilter": null,
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ Object {
+ "data": Object {
+ "activeFilters": Set {},
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "clearFilters": Object {
+ "usage": null,
+ },
+ },
+ "type": "SET_QUERY_CLEAR",
+ },
+ ],
+ ],
+ Array [
+ Array [
+ Object {
+ "data": Object {
+ "currentFilter": null,
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ Object {
+ "data": Object {
+ "activeFilters": Set {},
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "clearFilters": Object {
+ "sla": null,
+ "usage": null,
+ },
+ },
+ "type": "SET_QUERY_CLEAR",
+ },
+ ],
+ ],
+ ],
+ "results": Array [
+ Object {
+ "type": "return",
+ "value": Object {
+ "data": undefined,
+ "type": Object {
+ "data": Object {
+ "currentFilter": "sla",
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ },
+ },
+ Object {
+ "type": "return",
+ "value": Object {
+ "data": undefined,
+ "type": Array [
+ Object {
+ "data": Object {
+ "activeFilters": Set {
+ "sla",
+ },
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "sla": "premium",
+ },
+ "type": "SET_QUERY_SLA_RHSM",
+ },
+ ],
+ },
+ },
+ Object {
+ "type": "return",
+ "value": Object {
+ "data": undefined,
+ "type": Array [
+ Object {
+ "data": Object {
+ "activeFilters": Set {
+ "sla",
+ },
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "sla": "standard",
+ },
+ "type": "SET_QUERY_SLA_RHSM",
+ },
+ ],
+ },
+ },
+ Object {
+ "type": "return",
+ "value": Object {
+ "data": undefined,
+ "type": Array [
+ Object {
+ "data": Object {
+ "currentFilter": null,
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ Object {
+ "data": Object {
+ "activeFilters": Set {},
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "clearFilters": Object {
+ "sla": null,
+ },
+ },
+ "type": "SET_QUERY_CLEAR",
+ },
+ ],
+ },
+ },
+ Object {
+ "type": "return",
+ "value": Object {
+ "data": undefined,
+ "type": Object {
+ "data": Object {
+ "currentFilter": "usage",
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ },
+ },
+ Object {
+ "type": "return",
+ "value": Object {
+ "data": undefined,
+ "type": Array [
+ Object {
+ "data": Object {
+ "activeFilters": Set {
+ "usage",
+ },
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "usage": "Development/Test",
+ },
+ "type": "SET_QUERY_USAGE_RHSM",
+ },
+ ],
+ },
+ },
+ Object {
+ "type": "return",
+ "value": Object {
+ "data": undefined,
+ "type": Array [
+ Object {
+ "data": Object {
+ "activeFilters": Set {
+ "usage",
+ },
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "usage": "Disaster Recovery",
+ },
+ "type": "SET_QUERY_USAGE_RHSM",
+ },
+ ],
+ },
+ },
+ Object {
+ "type": "return",
+ "value": Object {
+ "data": undefined,
+ "type": Array [
+ Object {
+ "data": Object {
+ "currentFilter": null,
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ Object {
+ "data": Object {
+ "activeFilters": Set {},
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "clearFilters": Object {
+ "usage": null,
+ },
+ },
+ "type": "SET_QUERY_CLEAR",
+ },
+ ],
+ },
+ },
+ Object {
+ "type": "return",
+ "value": Object {
+ "data": undefined,
+ "type": Array [
+ Object {
+ "data": Object {
+ "currentFilter": null,
+ },
+ "type": "SET_FILTER_TYPE",
+ },
+ Object {
+ "data": Object {
+ "activeFilters": Set {},
+ },
+ "type": "SET_ACTIVE_FILTERS",
+ },
+ Object {
+ "data": Object {
+ "clearFilters": Object {
+ "sla": null,
+ "usage": null,
+ },
+ },
+ "type": "SET_QUERY_CLEAR",
+ },
+ ],
+ },
+ },
+ ],
+}
+`;
exports[`Toolbar Component should render a non-connected component: non-connected 1`] = `
+
+
+ }
+ >
+
+
+
+ }
+ variant="single"
+ />
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Toolbar Component should render filters when props are populated: props 1`] = `
+
-
+ }
>
-
-
-
+ deleteChip={[Function]}
+ showToolbarItem={true}
+ >
+
+
+
+
+
+
+
`;
diff --git a/src/components/toolbar/__tests__/__snapshots__/toolbarTypes.test.js.snap b/src/components/toolbar/__tests__/__snapshots__/toolbarTypes.test.js.snap
index 5da73d547..f085e9fcb 100644
--- a/src/components/toolbar/__tests__/__snapshots__/toolbarTypes.test.js.snap
+++ b/src/components/toolbar/__tests__/__snapshots__/toolbarTypes.test.js.snap
@@ -10,20 +10,12 @@ exports[`ToolbarTypes should return an output for options selection: getOptionsT
Object {
"options": Array [
Object {
- "title": "t(curiosity-toolbar.slaPremium)",
- "value": "premium",
- },
- Object {
- "title": "t(curiosity-toolbar.slaStandard)",
- "value": "standard",
- },
- Object {
- "title": "t(curiosity-toolbar.slaSelfSupport)",
- "value": "self-support",
+ "title": "t(curiosity-toolbar.slaCategory)",
+ "value": "sla",
},
Object {
- "title": "t(curiosity-toolbar.slaNone)",
- "value": "",
+ "title": "t(curiosity-toolbar.usageCategory)",
+ "value": "usage",
},
],
"selected": null,
@@ -32,7 +24,17 @@ Object {
exports[`ToolbarTypes should return an output for options selection: getOptionsType:null 1`] = `
Object {
- "options": Array [],
+ "options": Array [
+ Object {
+ "title": "t(curiosity-toolbar.slaCategory)",
+ "value": "sla",
+ },
+ Object {
+ "title": "t(curiosity-toolbar.usageCategory)",
+ "value": "usage",
+ },
+ ],
+ "selected": null,
}
`;
@@ -59,3 +61,27 @@ Object {
"selected": null,
}
`;
+
+exports[`ToolbarTypes should return an output for options selection: getOptionsType:usage 1`] = `
+Object {
+ "options": Array [
+ Object {
+ "title": "t(curiosity-toolbar.usageDevelopment)",
+ "value": "Development/Test",
+ },
+ Object {
+ "title": "t(curiosity-toolbar.usageDisaster)",
+ "value": "Disaster Recovery",
+ },
+ Object {
+ "title": "t(curiosity-toolbar.usageProduction)",
+ "value": "Production",
+ },
+ Object {
+ "title": "t(curiosity-toolbar.usageUnspecified)",
+ "value": "",
+ },
+ ],
+ "selected": null,
+}
+`;
diff --git a/src/components/toolbar/__tests__/toolbar.test.js b/src/components/toolbar/__tests__/toolbar.test.js
index c71bab0c1..1a127d4f3 100644
--- a/src/components/toolbar/__tests__/toolbar.test.js
+++ b/src/components/toolbar/__tests__/toolbar.test.js
@@ -2,8 +2,19 @@ import React from 'react';
import { mount, shallow } from 'enzyme';
import { Toolbar } from '../toolbar';
import { toolbarTypes } from '../toolbarTypes';
+import { RHSM_API_QUERY_SLA, RHSM_API_QUERY_USAGE } from '../../../types/rhsmApiTypes';
describe('Toolbar Component', () => {
+ let mockDispatch;
+
+ beforeEach(() => {
+ mockDispatch = jest.spyOn(Toolbar.prototype, 'setDispatch').mockImplementation((type, data) => ({ type, data }));
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
it('should render a non-connected component', () => {
const props = {};
const component = shallow();
@@ -11,29 +22,52 @@ describe('Toolbar Component', () => {
expect(component).toMatchSnapshot('non-connected');
});
- it('should handle updating state and dispatching an sla filter', () => {
- const props = {};
+ it('should return an empty render when disabled', () => {
+ const props = {
+ isDisabled: true
+ };
+ const component = shallow();
+
+ expect(component).toMatchSnapshot('disabled component');
+ });
- const dispatchFilter = jest.spyOn(Toolbar.prototype, 'dispatchFilter');
+ it('should render filters when props are populated', () => {
+ const [optionOne] = toolbarTypes.getOptions(RHSM_API_QUERY_SLA).options;
+
+ const props = {
+ activeFilters: new Set([RHSM_API_QUERY_SLA]),
+ currentFilter: RHSM_API_QUERY_SLA,
+ query: {
+ [RHSM_API_QUERY_SLA]: optionOne.value
+ }
+ };
+ const component = shallow();
+
+ expect(component).toMatchSnapshot('props');
+ });
+
+ it('should handle adding and clearing filters from redux state', () => {
+ const props = {};
const component = mount();
const componentInstance = component.instance();
- const slaOption = toolbarTypes.getOptions('sla').options[0];
- componentInstance.onSlaSelect({ selected: { ...slaOption }, value: slaOption.value });
- expect(componentInstance.state).toMatchSnapshot('sla selected');
+ const filters = [
+ { category: RHSM_API_QUERY_SLA, method: 'onSlaSelect' },
+ { category: RHSM_API_QUERY_USAGE, method: 'onUsageSelect' }
+ ];
- componentInstance.onClear();
- expect(componentInstance.state).toMatchSnapshot('clear filters');
+ filters.forEach(({ category, method }) => {
+ componentInstance.onCategorySelect({ value: category });
- expect(dispatchFilter).toHaveBeenCalledTimes(2);
- });
+ const [optionOne, optionTwo] = toolbarTypes.getOptions(category).options;
+ componentInstance[method]({ value: optionOne.value });
+ componentInstance[method]({ value: optionTwo.value });
- it('should return an empty render when disabled', () => {
- const props = {
- isDisabled: true
- };
- const component = shallow();
+ const { title: categoryTitle } = toolbarTypes.getOptions().options.find(({ value }) => value === category);
+ componentInstance.onClearFilter(categoryTitle);
+ });
- expect(component).toMatchSnapshot('disabled component');
+ componentInstance.onClear();
+ expect(mockDispatch).toMatchSnapshot('dispatch filter');
});
});
diff --git a/src/components/toolbar/__tests__/toolbarTypes.test.js b/src/components/toolbar/__tests__/toolbarTypes.test.js
index 8fb2c481e..a4eb99cc5 100644
--- a/src/components/toolbar/__tests__/toolbarTypes.test.js
+++ b/src/components/toolbar/__tests__/toolbarTypes.test.js
@@ -7,6 +7,7 @@ describe('ToolbarTypes', () => {
it('should return an output for options selection', () => {
expect(getOptionsType('sla')).toMatchSnapshot('getOptionsType:sla');
+ expect(getOptionsType('usage')).toMatchSnapshot('getOptionsType:usage');
expect(getOptionsType()).toMatchSnapshot('getOptionsType');
expect(getOptionsType(null)).toMatchSnapshot('getOptionsType:null');
});
diff --git a/src/components/toolbar/toolbar.js b/src/components/toolbar/toolbar.js
index 5db6b1320..b4c019792 100644
--- a/src/components/toolbar/toolbar.js
+++ b/src/components/toolbar/toolbar.js
@@ -1,8 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { Toolbar as PfToolbar, ToolbarContent, ToolbarFilter, ToolbarGroup } from '@patternfly/react-core';
+import {
+ Toolbar as PfToolbar,
+ ToolbarContent,
+ ToolbarFilter,
+ ToolbarGroup,
+ ToolbarItem,
+ ToolbarToggleGroup
+} from '@patternfly/react-core';
+import { FilterIcon } from '@patternfly/react-icons';
import { Select } from '../form/select';
-import { reduxTypes, store } from '../../redux';
+import { connect, reduxTypes, store } from '../../redux';
import { rhsmApiTypes } from '../../types/rhsmApiTypes';
import { toolbarTypes } from './toolbarTypes';
import { helpers } from '../../common';
@@ -13,16 +21,77 @@ import { translate } from '../i18n/i18n';
*
* @augments React.Component
* @fires onClear
+ * @fires onClearFilter
+ * @fires onCategorySelect
* @fires onSlaSelect
+ * @fires onUsageSelect
*/
class Toolbar extends React.Component {
/**
- * Clear filters' state.
+ * Clear all filters' state.
*
* @event onClear
*/
onClear = () => {
- this.dispatchFilter(reduxTypes.rhsm.SET_FILTER_SLA_RHSM, { [rhsmApiTypes.RHSM_API_QUERY_SLA]: null });
+ this.setDispatch([
+ { type: reduxTypes.toolbar.SET_FILTER_TYPE, data: { currentFilter: null } },
+ { type: reduxTypes.toolbar.SET_ACTIVE_FILTERS, data: { activeFilters: new Set() } },
+ {
+ type: reduxTypes.query.SET_QUERY_CLEAR,
+ data: {
+ clearFilters: {
+ [rhsmApiTypes.RHSM_API_QUERY_SLA]: null,
+ [rhsmApiTypes.RHSM_API_QUERY_USAGE]: null
+ }
+ }
+ }
+ ]);
+ };
+
+ /**
+ * Clear individual filter state.
+ *
+ * @event onClearFilter
+ * @param {string} categoryTitle
+ */
+ onClearFilter = categoryTitle => {
+ const { activeFilters, currentFilter } = this.props;
+
+ const categoryOptions = toolbarTypes.getOptions();
+ const { value: categoryValue } = categoryOptions.options.find(({ title }) => title === categoryTitle) || {};
+
+ if (!categoryValue) {
+ return;
+ }
+
+ const updatedActiveFilters = new Set(activeFilters);
+ updatedActiveFilters.delete(categoryValue);
+
+ const updatedCurrentFilter = (updatedActiveFilters.size > 0 && currentFilter) || null;
+
+ this.setDispatch([
+ { type: reduxTypes.toolbar.SET_FILTER_TYPE, data: { currentFilter: updatedCurrentFilter } },
+ { type: reduxTypes.toolbar.SET_ACTIVE_FILTERS, data: { activeFilters: updatedActiveFilters } },
+ {
+ type: reduxTypes.query.SET_QUERY_CLEAR,
+ data: {
+ clearFilters: {
+ [categoryValue]: null
+ }
+ }
+ }
+ ]);
+ };
+
+ /**
+ * Set Category selection.
+ *
+ * @event onCategorySelect
+ * @param {object} event
+ */
+ onCategorySelect = event => {
+ const { value } = event;
+ this.setDispatch({ type: reduxTypes.toolbar.SET_FILTER_TYPE, data: { currentFilter: value } });
};
/**
@@ -32,47 +101,82 @@ class Toolbar extends React.Component {
* @param {object} event
*/
onSlaSelect = event => {
+ const { activeFilters } = this.props;
const { value } = event;
+ const updatedActiveFilters = new Set(activeFilters).add(rhsmApiTypes.RHSM_API_QUERY_SLA);
- this.dispatchFilter(reduxTypes.rhsm.SET_FILTER_SLA_RHSM, { [rhsmApiTypes.RHSM_API_QUERY_SLA]: value });
+ this.setDispatch([
+ {
+ type: reduxTypes.toolbar.SET_ACTIVE_FILTERS,
+ data: { activeFilters: updatedActiveFilters }
+ },
+ {
+ type: reduxTypes.query.SET_QUERY_SLA_RHSM,
+ data: { [rhsmApiTypes.RHSM_API_QUERY_SLA]: value }
+ }
+ ]);
+ };
+
+ /**
+ * Set Usage filter selection.
+ *
+ * @event onUsageSelect
+ * @param {object} event
+ */
+ onUsageSelect = event => {
+ const { activeFilters } = this.props;
+ const { value } = event;
+ const updatedActiveFilters = new Set(activeFilters).add(rhsmApiTypes.RHSM_API_QUERY_USAGE);
+
+ this.setDispatch([
+ {
+ type: reduxTypes.toolbar.SET_ACTIVE_FILTERS,
+ data: { activeFilters: updatedActiveFilters }
+ },
+ {
+ type: reduxTypes.query.SET_QUERY_USAGE_RHSM,
+ data: { [rhsmApiTypes.RHSM_API_QUERY_USAGE]: value }
+ }
+ ]);
};
/**
* Dispatch a Redux store type.
*
- * @param {string} type
- * @param {object} data
+ * @param {Array|object} actions
*/
- dispatchFilter(type, data = {}) {
+ setDispatch(actions) {
const { viewId } = this.props;
+ const updatedActions = ((Array.isArray(actions) && actions) || [actions]).map(({ type, data }) => ({
+ type,
+ viewId,
+ ...data
+ }));
- if (type) {
- store.dispatch({
- type,
- viewId,
- ...data
- });
- }
+ store.dispatch(updatedActions);
}
- // ToDo: API to provide SLA options from endpoint.
/**
- * Available and selected SLA options.
+ * Available, and selected filter options.
*
- * @returns {{slaOptionsSelected: Array, slaOptions: object}}
+ * @param {string} filterType
+ * @returns {{optionsSelected: Array, options: Array }}
*/
- filterSla() {
- const { query } = this.props;
+ setFilter(filterType) {
+ const { currentFilter, query } = this.props;
+ const options = toolbarTypes.getOptions(filterType);
+ let filter;
- const slaOptions = toolbarTypes.getOptions();
- const filterSla =
- typeof query[rhsmApiTypes.RHSM_API_QUERY_SLA] === 'string' &&
- slaOptions.options.find(val => val.value === query[rhsmApiTypes.RHSM_API_QUERY_SLA]);
+ if (filterType) {
+ filter =
+ typeof query?.[filterType] === 'string' && options.options.find(({ value }) => value === query?.[filterType]);
+ } else {
+ filter = options.options.find(({ value }) => value === currentFilter);
+ }
- const slaOptionsSelected =
- (filterSla && filterSla.title && [filterSla.title]) || (slaOptions.selected && [slaOptions.selected]) || [];
+ const optionsSelected = (filter?.title && [filter.title]) || (options?.selected && [options.selected]) || [];
- return { slaOptions, slaOptionsSelected };
+ return { options, optionsSelected };
}
/**
@@ -81,37 +185,71 @@ class Toolbar extends React.Component {
* @returns {Node}
*/
render() {
- const { isDisabled, t } = this.props;
+ const { currentFilter, isDisabled, t } = this.props;
if (isDisabled) {
return null;
}
- const { slaOptions, slaOptionsSelected } = this.filterSla();
+ const { options: categoryOptions, optionsSelected: categoryOptionsSelected } = this.setFilter();
+
+ const { options: slaOptions, optionsSelected: slaOptionsSelected } = this.setFilter(
+ rhsmApiTypes.RHSM_API_QUERY_SLA
+ );
+ const { options: usageOptions, optionsSelected: usageOptionsSelected } = this.setFilter(
+ rhsmApiTypes.RHSM_API_QUERY_USAGE
+ );
return (
-
-
-
-
-
+ } breakpoint="md">
+
+
+ }
+ />
+
+
+
+
+
+
+
+
+
);
@@ -121,12 +259,15 @@ class Toolbar extends React.Component {
/**
* Prop types
*
- * @type {{viewId: string, t: Function, query: object, isDisabled: boolean }}
+ * @type {{viewId: string, t: Function, activeFilters, query, currentFilter: string, isDisabled: boolean}}
*/
Toolbar.propTypes = {
query: PropTypes.shape({
- [rhsmApiTypes.RHSM_API_QUERY_SLA]: PropTypes.string
+ [rhsmApiTypes.RHSM_API_QUERY_SLA]: PropTypes.string,
+ [rhsmApiTypes.RHSM_API_QUERY_USAGE]: PropTypes.string
}),
+ activeFilters: PropTypes.instanceOf(Set),
+ currentFilter: PropTypes.oneOf([rhsmApiTypes.RHSM_API_QUERY_SLA, rhsmApiTypes.RHSM_API_QUERY_USAGE]),
isDisabled: PropTypes.bool,
t: PropTypes.func,
viewId: PropTypes.string
@@ -135,13 +276,28 @@ Toolbar.propTypes = {
/**
* Default props.
*
- * @type {{viewId: string, t: translate, query: {}, isDisabled: boolean}}
+ * @type {{viewId: string, t: translate, activeFilters: Set, query: {}, currentFilter: null, isDisabled: boolean}}
*/
Toolbar.defaultProps = {
query: {},
+ activeFilters: new Set(),
+ currentFilter: null,
isDisabled: helpers.UI_DISABLED_TOOLBAR,
t: translate,
viewId: 'toolbar'
};
-export { Toolbar as default, Toolbar };
+/**
+ * Apply state to props.
+ *
+ * @param {object} state
+ * @param {object} state.toolbar
+ * @param {object} props
+ * @param {string} props.viewId
+ * @returns {object}
+ */
+const mapStateToProps = ({ toolbar }, { viewId }) => ({ ...toolbar.filters?.[viewId] });
+
+const ConnectedToolbar = connect(mapStateToProps)(Toolbar);
+
+export { ConnectedToolbar as default, ConnectedToolbar, Toolbar };
diff --git a/src/components/toolbar/toolbarTypes.js b/src/components/toolbar/toolbarTypes.js
index f9c84cd44..69aa56d7b 100644
--- a/src/components/toolbar/toolbarTypes.js
+++ b/src/components/toolbar/toolbarTypes.js
@@ -1,5 +1,10 @@
import { translate } from '../i18n/i18n';
-import { RHSM_API_QUERY_SLA_TYPES as SLA_TYPES } from '../../types/rhsmApiTypes';
+import {
+ RHSM_API_QUERY_SLA,
+ RHSM_API_QUERY_SLA_TYPES as SLA_TYPES,
+ RHSM_API_QUERY_USAGE,
+ RHSM_API_QUERY_USAGE_TYPES as USAGE_TYPES
+} from '../../types/rhsmApiTypes';
/**
* Get filter options to display by type.
@@ -7,32 +12,67 @@ import { RHSM_API_QUERY_SLA_TYPES as SLA_TYPES } from '../../types/rhsmApiTypes'
* @param {string} optionsType
* @returns {object}
*/
-const getOptionsType = (optionsType = 'sla') => {
- if (optionsType === 'sla') {
- return {
- selected: null,
- options: [
- {
- title: translate('curiosity-toolbar.slaPremium'),
- value: SLA_TYPES.PREMIUM
- },
- {
- title: translate('curiosity-toolbar.slaStandard'),
- value: SLA_TYPES.STANDARD
- },
- {
- title: translate('curiosity-toolbar.slaSelfSupport'),
- value: SLA_TYPES.SELF
- },
- {
- title: translate('curiosity-toolbar.slaNone'),
- value: SLA_TYPES.NONE
- }
- ]
- };
+const getOptionsType = optionsType => {
+ switch (optionsType) {
+ case RHSM_API_QUERY_SLA:
+ return {
+ selected: null,
+ options: [
+ {
+ title: translate('curiosity-toolbar.slaPremium'),
+ value: SLA_TYPES.PREMIUM
+ },
+ {
+ title: translate('curiosity-toolbar.slaStandard'),
+ value: SLA_TYPES.STANDARD
+ },
+ {
+ title: translate('curiosity-toolbar.slaSelfSupport'),
+ value: SLA_TYPES.SELF
+ },
+ {
+ title: translate('curiosity-toolbar.slaNone'),
+ value: SLA_TYPES.NONE
+ }
+ ]
+ };
+ case RHSM_API_QUERY_USAGE:
+ return {
+ selected: null,
+ options: [
+ {
+ title: translate('curiosity-toolbar.usageDevelopment'),
+ value: USAGE_TYPES.DEVELOPMENT
+ },
+ {
+ title: translate('curiosity-toolbar.usageDisaster'),
+ value: USAGE_TYPES.DISASTER
+ },
+ {
+ title: translate('curiosity-toolbar.usageProduction'),
+ value: USAGE_TYPES.PRODUCTION
+ },
+ {
+ title: translate('curiosity-toolbar.usageUnspecified'),
+ value: USAGE_TYPES.UNSPECIFIED
+ }
+ ]
+ };
+ default:
+ return {
+ selected: null,
+ options: [
+ {
+ title: translate('curiosity-toolbar.slaCategory'),
+ value: RHSM_API_QUERY_SLA
+ },
+ {
+ title: translate('curiosity-toolbar.usageCategory'),
+ value: RHSM_API_QUERY_USAGE
+ }
+ ]
+ };
}
-
- return { options: [] };
};
const toolbarTypes = {
diff --git a/src/redux/middleware/index.js b/src/redux/middleware/index.js
index 87394e045..cdd947c27 100644
--- a/src/redux/middleware/index.js
+++ b/src/redux/middleware/index.js
@@ -2,6 +2,7 @@ import { createLogger } from 'redux-logger';
import promiseMiddleware from 'redux-promise-middleware';
import thunkMiddleware from 'redux-thunk';
import { notificationsMiddleware } from '@redhat-cloud-services/frontend-components-notifications/cjs';
+import { multiActionMiddleware } from './multiActionMiddleware';
import { statusMiddleware } from './statusMiddleware';
import { reduxHelpers } from '../common/reduxHelpers';
@@ -31,6 +32,7 @@ const notificationsOptions = {
const reduxMiddleware = [
thunkMiddleware,
statusMiddleware(),
+ multiActionMiddleware,
promiseMiddleware,
notificationsMiddleware(notificationsOptions)
];
diff --git a/src/redux/middleware/multiActionMiddleware.js b/src/redux/middleware/multiActionMiddleware.js
new file mode 100644
index 000000000..df92cacc5
--- /dev/null
+++ b/src/redux/middleware/multiActionMiddleware.js
@@ -0,0 +1,10 @@
+/**
+ * Allow passing an array of actions for batch dispatch.
+ *
+ * @param {object} store
+ * @returns {Function}
+ */
+const multiActionMiddleware = store => next => action =>
+ (Array.isArray(action) && action.map(a => store.dispatch(a))) || next(action);
+
+export { multiActionMiddleware as default, multiActionMiddleware };
diff --git a/src/redux/reducers/__tests__/__snapshots__/toolbarReducer.test.js.snap b/src/redux/reducers/__tests__/__snapshots__/toolbarReducer.test.js.snap
new file mode 100644
index 000000000..3e84f3437
--- /dev/null
+++ b/src/redux/reducers/__tests__/__snapshots__/toolbarReducer.test.js.snap
@@ -0,0 +1,29 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ToolbarReducer should handle specific defined types: defined type SET_ACTIVE_FILTERS 1`] = `
+Object {
+ "result": Object {
+ "filters": Object {
+ "test_id": Object {
+ "activeFilters": Set {
+ "lorem",
+ },
+ },
+ },
+ },
+ "type": "SET_ACTIVE_FILTERS",
+}
+`;
+
+exports[`ToolbarReducer should handle specific defined types: defined type SET_FILTER_TYPE 1`] = `
+Object {
+ "result": Object {
+ "filters": Object {
+ "test_id": Object {
+ "currentFilter": "lorem",
+ },
+ },
+ },
+ "type": "SET_FILTER_TYPE",
+}
+`;
diff --git a/src/redux/reducers/__tests__/__snapshots__/viewReducer.test.js.snap b/src/redux/reducers/__tests__/__snapshots__/viewReducer.test.js.snap
index 7feb4940d..8073de507 100644
--- a/src/redux/reducers/__tests__/__snapshots__/viewReducer.test.js.snap
+++ b/src/redux/reducers/__tests__/__snapshots__/viewReducer.test.js.snap
@@ -1,17 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`ViewReducer should handle specific defined types: defined type SET_CLEAR_FILTERS 1`] = `
+exports[`ViewReducer should handle specific defined types: defined type SET_QUERY_CLEAR 1`] = `
Object {
"result": Object {
"query": Object {
"test_id": Object {},
},
},
- "type": "SET_CLEAR_FILTERS",
+ "type": "SET_QUERY_CLEAR",
}
`;
-exports[`ViewReducer should handle specific defined types: defined type SET_FILTER_GRANULARITY_RHSM 1`] = `
+exports[`ViewReducer should handle specific defined types: defined type SET_QUERY_GRANULARITY_RHSM 1`] = `
Object {
"result": Object {
"query": Object {
@@ -20,58 +20,58 @@ Object {
},
},
},
- "type": "SET_FILTER_GRANULARITY_RHSM",
+ "type": "SET_QUERY_GRANULARITY_RHSM",
}
`;
-exports[`ViewReducer should handle specific defined types: defined type SET_FILTER_SLA_RHSM 1`] = `
+exports[`ViewReducer should handle specific defined types: defined type SET_QUERY_PAGE_LIMIT_RHSM 1`] = `
Object {
"result": Object {
"query": Object {
"test_id": Object {
- "sla": "lorem sla",
+ "limit": 10,
},
},
},
- "type": "SET_FILTER_SLA_RHSM",
+ "type": "SET_QUERY_PAGE_LIMIT_RHSM",
}
`;
-exports[`ViewReducer should handle specific defined types: defined type SET_FILTER_USAGE_RHSM 1`] = `
+exports[`ViewReducer should handle specific defined types: defined type SET_QUERY_PAGE_OFFSET_RHSM 1`] = `
Object {
"result": Object {
"query": Object {
"test_id": Object {
- "usage": undefined,
+ "offset": 10,
},
},
},
- "type": "SET_FILTER_USAGE_RHSM",
+ "type": "SET_QUERY_PAGE_OFFSET_RHSM",
}
`;
-exports[`ViewReducer should handle specific defined types: defined type SET_PAGE_LIMIT_RHSM 1`] = `
+exports[`ViewReducer should handle specific defined types: defined type SET_QUERY_SLA_RHSM 1`] = `
Object {
"result": Object {
"query": Object {
"test_id": Object {
- "limit": undefined,
+ "sla": "lorem sla",
},
},
},
- "type": "SET_PAGE_LIMIT_RHSM",
+ "type": "SET_QUERY_SLA_RHSM",
}
`;
-exports[`ViewReducer should handle specific defined types: defined type SET_PAGE_OFFSET_RHSM 1`] = `
+exports[`ViewReducer should handle specific defined types: defined type SET_QUERY_USAGE_RHSM 1`] = `
Object {
"result": Object {
"query": Object {
"test_id": Object {
- "offset": undefined,
+ "usage": "ipsum usage",
},
},
},
- "type": "SET_PAGE_OFFSET_RHSM",
+ "type": "SET_QUERY_USAGE_RHSM",
}
`;
diff --git a/src/redux/reducers/__tests__/toolbarReducer.test.js b/src/redux/reducers/__tests__/toolbarReducer.test.js
new file mode 100644
index 000000000..db2bf1ae5
--- /dev/null
+++ b/src/redux/reducers/__tests__/toolbarReducer.test.js
@@ -0,0 +1,25 @@
+import toolbarReducer from '../toolbarReducer';
+import { toolbarTypes as types } from '../../types';
+
+describe('ToolbarReducer', () => {
+ it('should return the initial state', () => {
+ expect(toolbarReducer.initialState).toBeDefined();
+ });
+
+ it('should handle specific defined types', () => {
+ const specificTypes = [types.SET_ACTIVE_FILTERS, types.SET_FILTER_TYPE];
+
+ specificTypes.forEach(value => {
+ const dispatched = {
+ type: value,
+ activeFilters: new Set(['lorem']),
+ currentFilter: 'lorem',
+ viewId: 'test_id'
+ };
+
+ const resultState = toolbarReducer(undefined, dispatched);
+
+ expect({ type: value, result: resultState }).toMatchSnapshot(`defined type ${value}`);
+ });
+ });
+});
diff --git a/src/redux/reducers/__tests__/viewReducer.test.js b/src/redux/reducers/__tests__/viewReducer.test.js
index 1a6e4dda5..e9969e03f 100644
--- a/src/redux/reducers/__tests__/viewReducer.test.js
+++ b/src/redux/reducers/__tests__/viewReducer.test.js
@@ -1,5 +1,12 @@
import viewReducer from '../viewReducer';
-import { rhsmTypes as types } from '../../types';
+import { queryTypes as types } from '../../types';
+import {
+ RHSM_API_QUERY_GRANULARITY,
+ RHSM_API_QUERY_LIMIT,
+ RHSM_API_QUERY_OFFSET,
+ RHSM_API_QUERY_SLA,
+ RHSM_API_QUERY_USAGE
+} from '../../../types/rhsmApiTypes';
describe('ViewReducer', () => {
it('should return the initial state', () => {
@@ -8,19 +15,22 @@ describe('ViewReducer', () => {
it('should handle specific defined types', () => {
const specificTypes = [
- types.SET_FILTER_GRANULARITY_RHSM,
- types.SET_FILTER_SLA_RHSM,
- types.SET_FILTER_USAGE_RHSM,
- types.SET_CLEAR_FILTERS,
- types.SET_PAGE_LIMIT_RHSM,
- types.SET_PAGE_OFFSET_RHSM
+ types.SET_QUERY_GRANULARITY_RHSM,
+ types.SET_QUERY_SLA_RHSM,
+ types.SET_QUERY_USAGE_RHSM,
+ types.SET_QUERY_CLEAR,
+ types.SET_QUERY_PAGE_LIMIT_RHSM,
+ types.SET_QUERY_PAGE_OFFSET_RHSM
];
specificTypes.forEach(value => {
const dispatched = {
type: value,
- granularity: 'lorem granularity',
- sla: 'lorem sla',
+ [RHSM_API_QUERY_GRANULARITY]: 'lorem granularity',
+ [RHSM_API_QUERY_SLA]: 'lorem sla',
+ [RHSM_API_QUERY_USAGE]: 'ipsum usage',
+ [RHSM_API_QUERY_LIMIT]: 10,
+ [RHSM_API_QUERY_OFFSET]: 10,
viewId: 'test_id'
};
diff --git a/src/redux/reducers/index.js b/src/redux/reducers/index.js
index 01ac46f51..5d20a8944 100644
--- a/src/redux/reducers/index.js
+++ b/src/redux/reducers/index.js
@@ -2,17 +2,27 @@ import { combineReducers } from 'redux';
import { notifications } from '@redhat-cloud-services/frontend-components-notifications/cjs';
import graphReducer from './graphReducer';
import inventoryReducer from './inventoryReducer';
-import viewReducer from './viewReducer';
+import toolbarReducer from './toolbarReducer';
import userReducer from './userReducer';
+import viewReducer from './viewReducer';
const reducers = {
notifications,
graph: graphReducer,
inventory: inventoryReducer,
+ toolbar: toolbarReducer,
user: userReducer,
view: viewReducer
};
const reduxReducers = combineReducers(reducers);
-export { reduxReducers as default, reduxReducers, graphReducer, inventoryReducer, userReducer, viewReducer };
+export {
+ reduxReducers as default,
+ reduxReducers,
+ graphReducer,
+ inventoryReducer,
+ toolbarReducer,
+ userReducer,
+ viewReducer
+};
diff --git a/src/redux/reducers/toolbarReducer.js b/src/redux/reducers/toolbarReducer.js
new file mode 100644
index 000000000..8a3dbc60c
--- /dev/null
+++ b/src/redux/reducers/toolbarReducer.js
@@ -0,0 +1,58 @@
+import { reduxTypes } from '../types';
+import { reduxHelpers } from '../common/reduxHelpers';
+
+/**
+ * Initial state.
+ *
+ * @private
+ * @type {{filters: {}}}
+ */
+const initialState = {
+ filters: {}
+};
+
+/**
+ * Apply user observer/reducer logic for toolbar to state, against actions.
+ *
+ * @param {object} state
+ * @param {object} action
+ * @returns {object|{}}
+ */
+const toolbarReducer = (state = initialState, action) => {
+ switch (action.type) {
+ case reduxTypes.toolbar.SET_ACTIVE_FILTERS:
+ return reduxHelpers.setStateProp(
+ 'filters',
+ {
+ [action.viewId]: {
+ ...state.filters[action.viewId],
+ activeFilters: action.activeFilters
+ }
+ },
+ {
+ state,
+ reset: false
+ }
+ );
+ case reduxTypes.toolbar.SET_FILTER_TYPE:
+ return reduxHelpers.setStateProp(
+ 'filters',
+ {
+ [action.viewId]: {
+ ...state.filters[action.viewId],
+ currentFilter: action.currentFilter
+ }
+ },
+ {
+ state,
+ reset: false
+ }
+ );
+ default:
+ return state;
+ }
+};
+
+toolbarReducer.initialState = initialState;
+
+export { toolbarReducer as default, initialState, toolbarReducer };
diff --git a/src/redux/reducers/viewReducer.js b/src/redux/reducers/viewReducer.js
index 565f4fbd6..89a72318b 100644
--- a/src/redux/reducers/viewReducer.js
+++ b/src/redux/reducers/viewReducer.js
@@ -27,13 +27,13 @@ const initialState = {
*/
const viewReducer = (state = initialState, action) => {
switch (action.type) {
- case reduxTypes.rhsm.SET_FILTER_GRANULARITY_RHSM:
+ case reduxTypes.query.SET_QUERY_CLEAR:
return reduxHelpers.setStateProp(
'query',
{
[action.viewId]: {
...state.query[action.viewId],
- [RHSM_API_QUERY_GRANULARITY]: action[RHSM_API_QUERY_GRANULARITY]
+ ...action.clearFilters
}
},
{
@@ -41,13 +41,13 @@ const viewReducer = (state = initialState, action) => {
reset: false
}
);
- case reduxTypes.rhsm.SET_FILTER_SLA_RHSM:
+ case reduxTypes.query.SET_QUERY_GRANULARITY_RHSM:
return reduxHelpers.setStateProp(
'query',
{
[action.viewId]: {
...state.query[action.viewId],
- [RHSM_API_QUERY_SLA]: action[RHSM_API_QUERY_SLA]
+ [RHSM_API_QUERY_GRANULARITY]: action[RHSM_API_QUERY_GRANULARITY]
}
},
{
@@ -55,13 +55,13 @@ const viewReducer = (state = initialState, action) => {
reset: false
}
);
- case reduxTypes.rhsm.SET_FILTER_USAGE_RHSM:
+ case reduxTypes.query.SET_QUERY_SLA_RHSM:
return reduxHelpers.setStateProp(
'query',
{
[action.viewId]: {
...state.query[action.viewId],
- [RHSM_API_QUERY_USAGE]: action[RHSM_API_QUERY_USAGE]
+ [RHSM_API_QUERY_SLA]: action[RHSM_API_QUERY_SLA]
}
},
{
@@ -69,13 +69,13 @@ const viewReducer = (state = initialState, action) => {
reset: false
}
);
- case reduxTypes.rhsm.SET_CLEAR_FILTERS:
+ case reduxTypes.query.SET_QUERY_USAGE_RHSM:
return reduxHelpers.setStateProp(
'query',
{
[action.viewId]: {
...state.query[action.viewId],
- ...action.clearFilters
+ [RHSM_API_QUERY_USAGE]: action[RHSM_API_QUERY_USAGE]
}
},
{
@@ -83,7 +83,7 @@ const viewReducer = (state = initialState, action) => {
reset: false
}
);
- case reduxTypes.rhsm.SET_PAGE_LIMIT_RHSM:
+ case reduxTypes.query.SET_QUERY_PAGE_LIMIT_RHSM:
return reduxHelpers.setStateProp(
'query',
{
@@ -97,7 +97,7 @@ const viewReducer = (state = initialState, action) => {
reset: false
}
);
- case reduxTypes.rhsm.SET_PAGE_OFFSET_RHSM:
+ case reduxTypes.query.SET_QUERY_PAGE_OFFSET_RHSM:
return reduxHelpers.setStateProp(
'query',
{
diff --git a/src/redux/types/__tests__/__snapshots__/index.test.js.snap b/src/redux/types/__tests__/__snapshots__/index.test.js.snap
index 77b9b0700..4fef8a138 100644
--- a/src/redux/types/__tests__/__snapshots__/index.test.js.snap
+++ b/src/redux/types/__tests__/__snapshots__/index.test.js.snap
@@ -23,18 +23,24 @@ Object {
"PLATFORM_REMOVE_NOTIFICATION": "@@INSIGHTS-CORE/NOTIFICATIONS/REMOVE_NOTIFICATION",
"PLATFORM_SET_NAV": "PLATFORM_SET_NAV",
},
+ "query": Object {
+ "SET_QUERY_CLEAR": "SET_QUERY_CLEAR",
+ "SET_QUERY_GRANULARITY_RHSM": "SET_QUERY_GRANULARITY_RHSM",
+ "SET_QUERY_PAGE_LIMIT_RHSM": "SET_QUERY_PAGE_LIMIT_RHSM",
+ "SET_QUERY_PAGE_OFFSET_RHSM": "SET_QUERY_PAGE_OFFSET_RHSM",
+ "SET_QUERY_SLA_RHSM": "SET_QUERY_SLA_RHSM",
+ "SET_QUERY_USAGE_RHSM": "SET_QUERY_USAGE_RHSM",
+ },
"rhsm": Object {
"GET_GRAPH_CAPACITY_RHSM": "GET_GRAPH_CAPACITY_RHSM",
"GET_GRAPH_REPORT_CAPACITY_RHSM": "GET_GRAPH_REPORT_CAPACITY_RHSM",
"GET_GRAPH_REPORT_RHSM": "GET_GRAPH_REPORT_RHSM",
"GET_HOSTS_INVENTORY_GUESTS_RHSM": "GET_HOSTS_INVENTORY_GUESTS_RHSM",
"GET_HOSTS_INVENTORY_RHSM": "GET_HOSTS_INVENTORY_RHSM",
- "SET_CLEAR_FILTERS": "SET_CLEAR_FILTERS",
- "SET_FILTER_GRANULARITY_RHSM": "SET_FILTER_GRANULARITY_RHSM",
- "SET_FILTER_SLA_RHSM": "SET_FILTER_SLA_RHSM",
- "SET_FILTER_USAGE_RHSM": "SET_FILTER_USAGE_RHSM",
- "SET_PAGE_LIMIT_RHSM": "SET_PAGE_LIMIT_RHSM",
- "SET_PAGE_OFFSET_RHSM": "SET_PAGE_OFFSET_RHSM",
+ },
+ "toolbar": Object {
+ "SET_ACTIVE_FILTERS": "SET_ACTIVE_FILTERS",
+ "SET_FILTER_TYPE": "SET_FILTER_TYPE",
},
"user": Object {
"DELETE_USER_OPTIN": "DELETE_USER_OPTIN",
@@ -57,6 +63,14 @@ Object {
"PLATFORM_REMOVE_NOTIFICATION": "@@INSIGHTS-CORE/NOTIFICATIONS/REMOVE_NOTIFICATION",
"PLATFORM_SET_NAV": "PLATFORM_SET_NAV",
},
+ "queryTypes": Object {
+ "SET_QUERY_CLEAR": "SET_QUERY_CLEAR",
+ "SET_QUERY_GRANULARITY_RHSM": "SET_QUERY_GRANULARITY_RHSM",
+ "SET_QUERY_PAGE_LIMIT_RHSM": "SET_QUERY_PAGE_LIMIT_RHSM",
+ "SET_QUERY_PAGE_OFFSET_RHSM": "SET_QUERY_PAGE_OFFSET_RHSM",
+ "SET_QUERY_SLA_RHSM": "SET_QUERY_SLA_RHSM",
+ "SET_QUERY_USAGE_RHSM": "SET_QUERY_USAGE_RHSM",
+ },
"reduxTypes": Object {
"app": Object {
"STATUS_4XX": "4XX",
@@ -74,18 +88,24 @@ Object {
"PLATFORM_REMOVE_NOTIFICATION": "@@INSIGHTS-CORE/NOTIFICATIONS/REMOVE_NOTIFICATION",
"PLATFORM_SET_NAV": "PLATFORM_SET_NAV",
},
+ "query": Object {
+ "SET_QUERY_CLEAR": "SET_QUERY_CLEAR",
+ "SET_QUERY_GRANULARITY_RHSM": "SET_QUERY_GRANULARITY_RHSM",
+ "SET_QUERY_PAGE_LIMIT_RHSM": "SET_QUERY_PAGE_LIMIT_RHSM",
+ "SET_QUERY_PAGE_OFFSET_RHSM": "SET_QUERY_PAGE_OFFSET_RHSM",
+ "SET_QUERY_SLA_RHSM": "SET_QUERY_SLA_RHSM",
+ "SET_QUERY_USAGE_RHSM": "SET_QUERY_USAGE_RHSM",
+ },
"rhsm": Object {
"GET_GRAPH_CAPACITY_RHSM": "GET_GRAPH_CAPACITY_RHSM",
"GET_GRAPH_REPORT_CAPACITY_RHSM": "GET_GRAPH_REPORT_CAPACITY_RHSM",
"GET_GRAPH_REPORT_RHSM": "GET_GRAPH_REPORT_RHSM",
"GET_HOSTS_INVENTORY_GUESTS_RHSM": "GET_HOSTS_INVENTORY_GUESTS_RHSM",
"GET_HOSTS_INVENTORY_RHSM": "GET_HOSTS_INVENTORY_RHSM",
- "SET_CLEAR_FILTERS": "SET_CLEAR_FILTERS",
- "SET_FILTER_GRANULARITY_RHSM": "SET_FILTER_GRANULARITY_RHSM",
- "SET_FILTER_SLA_RHSM": "SET_FILTER_SLA_RHSM",
- "SET_FILTER_USAGE_RHSM": "SET_FILTER_USAGE_RHSM",
- "SET_PAGE_LIMIT_RHSM": "SET_PAGE_LIMIT_RHSM",
- "SET_PAGE_OFFSET_RHSM": "SET_PAGE_OFFSET_RHSM",
+ },
+ "toolbar": Object {
+ "SET_ACTIVE_FILTERS": "SET_ACTIVE_FILTERS",
+ "SET_FILTER_TYPE": "SET_FILTER_TYPE",
},
"user": Object {
"DELETE_USER_OPTIN": "DELETE_USER_OPTIN",
@@ -102,12 +122,10 @@ Object {
"GET_GRAPH_REPORT_RHSM": "GET_GRAPH_REPORT_RHSM",
"GET_HOSTS_INVENTORY_GUESTS_RHSM": "GET_HOSTS_INVENTORY_GUESTS_RHSM",
"GET_HOSTS_INVENTORY_RHSM": "GET_HOSTS_INVENTORY_RHSM",
- "SET_CLEAR_FILTERS": "SET_CLEAR_FILTERS",
- "SET_FILTER_GRANULARITY_RHSM": "SET_FILTER_GRANULARITY_RHSM",
- "SET_FILTER_SLA_RHSM": "SET_FILTER_SLA_RHSM",
- "SET_FILTER_USAGE_RHSM": "SET_FILTER_USAGE_RHSM",
- "SET_PAGE_LIMIT_RHSM": "SET_PAGE_LIMIT_RHSM",
- "SET_PAGE_OFFSET_RHSM": "SET_PAGE_OFFSET_RHSM",
+ },
+ "toolbarTypes": Object {
+ "SET_ACTIVE_FILTERS": "SET_ACTIVE_FILTERS",
+ "SET_FILTER_TYPE": "SET_FILTER_TYPE",
},
"userTypes": Object {
"DELETE_USER_OPTIN": "DELETE_USER_OPTIN",
@@ -138,18 +156,24 @@ Object {
"PLATFORM_REMOVE_NOTIFICATION": "@@INSIGHTS-CORE/NOTIFICATIONS/REMOVE_NOTIFICATION",
"PLATFORM_SET_NAV": "PLATFORM_SET_NAV",
},
+ "query": Object {
+ "SET_QUERY_CLEAR": "SET_QUERY_CLEAR",
+ "SET_QUERY_GRANULARITY_RHSM": "SET_QUERY_GRANULARITY_RHSM",
+ "SET_QUERY_PAGE_LIMIT_RHSM": "SET_QUERY_PAGE_LIMIT_RHSM",
+ "SET_QUERY_PAGE_OFFSET_RHSM": "SET_QUERY_PAGE_OFFSET_RHSM",
+ "SET_QUERY_SLA_RHSM": "SET_QUERY_SLA_RHSM",
+ "SET_QUERY_USAGE_RHSM": "SET_QUERY_USAGE_RHSM",
+ },
"rhsm": Object {
"GET_GRAPH_CAPACITY_RHSM": "GET_GRAPH_CAPACITY_RHSM",
"GET_GRAPH_REPORT_CAPACITY_RHSM": "GET_GRAPH_REPORT_CAPACITY_RHSM",
"GET_GRAPH_REPORT_RHSM": "GET_GRAPH_REPORT_RHSM",
"GET_HOSTS_INVENTORY_GUESTS_RHSM": "GET_HOSTS_INVENTORY_GUESTS_RHSM",
"GET_HOSTS_INVENTORY_RHSM": "GET_HOSTS_INVENTORY_RHSM",
- "SET_CLEAR_FILTERS": "SET_CLEAR_FILTERS",
- "SET_FILTER_GRANULARITY_RHSM": "SET_FILTER_GRANULARITY_RHSM",
- "SET_FILTER_SLA_RHSM": "SET_FILTER_SLA_RHSM",
- "SET_FILTER_USAGE_RHSM": "SET_FILTER_USAGE_RHSM",
- "SET_PAGE_LIMIT_RHSM": "SET_PAGE_LIMIT_RHSM",
- "SET_PAGE_OFFSET_RHSM": "SET_PAGE_OFFSET_RHSM",
+ },
+ "toolbar": Object {
+ "SET_ACTIVE_FILTERS": "SET_ACTIVE_FILTERS",
+ "SET_FILTER_TYPE": "SET_FILTER_TYPE",
},
"user": Object {
"DELETE_USER_OPTIN": "DELETE_USER_OPTIN",
diff --git a/src/redux/types/index.js b/src/redux/types/index.js
index c9047eff6..f0b1aa765 100644
--- a/src/redux/types/index.js
+++ b/src/redux/types/index.js
@@ -1,15 +1,29 @@
import { appTypes } from './appTypes';
import { graphTypes } from './graphTypes';
import { platformTypes } from './platformTypes';
+import { queryTypes } from './queryTypes';
import { rhsmTypes } from './rhsmTypes';
+import { toolbarTypes } from './toolbarTypes';
import { userTypes } from './userTypes';
const reduxTypes = {
app: appTypes,
graph: graphTypes,
platform: platformTypes,
+ query: queryTypes,
rhsm: rhsmTypes,
+ toolbar: toolbarTypes,
user: userTypes
};
-export { reduxTypes as default, reduxTypes, appTypes, graphTypes, platformTypes, rhsmTypes, userTypes };
+export {
+ reduxTypes as default,
+ reduxTypes,
+ appTypes,
+ graphTypes,
+ platformTypes,
+ queryTypes,
+ rhsmTypes,
+ toolbarTypes,
+ userTypes
+};
diff --git a/src/redux/types/queryTypes.js b/src/redux/types/queryTypes.js
new file mode 100644
index 000000000..c674c125f
--- /dev/null
+++ b/src/redux/types/queryTypes.js
@@ -0,0 +1,33 @@
+const SET_QUERY_CLEAR = 'SET_QUERY_CLEAR';
+const SET_QUERY_GRANULARITY_RHSM = 'SET_QUERY_GRANULARITY_RHSM';
+const SET_QUERY_PAGE_LIMIT_RHSM = 'SET_QUERY_PAGE_LIMIT_RHSM';
+const SET_QUERY_PAGE_OFFSET_RHSM = 'SET_QUERY_PAGE_OFFSET_RHSM';
+const SET_QUERY_SLA_RHSM = 'SET_QUERY_SLA_RHSM';
+const SET_QUERY_USAGE_RHSM = 'SET_QUERY_USAGE_RHSM';
+
+/**
+ * Query/filter reducer types.
+ *
+ * @type {{SET_QUERY_PAGE_OFFSET_RHSM: string, SET_QUERY_USAGE_RHSM: string,
+ * SET_QUERY_PAGE_LIMIT_RHSM: string, SET_QUERY_CLEAR: string, SET_QUERY_SLA_RHSM: string,
+ * SET_QUERY_GRANULARITY_RHSM: string}}
+ */
+const queryTypes = {
+ SET_QUERY_CLEAR,
+ SET_QUERY_GRANULARITY_RHSM,
+ SET_QUERY_PAGE_LIMIT_RHSM,
+ SET_QUERY_PAGE_OFFSET_RHSM,
+ SET_QUERY_SLA_RHSM,
+ SET_QUERY_USAGE_RHSM
+};
+
+export {
+ queryTypes as default,
+ queryTypes,
+ SET_QUERY_CLEAR,
+ SET_QUERY_GRANULARITY_RHSM,
+ SET_QUERY_PAGE_LIMIT_RHSM,
+ SET_QUERY_PAGE_OFFSET_RHSM,
+ SET_QUERY_SLA_RHSM,
+ SET_QUERY_USAGE_RHSM
+};
diff --git a/src/redux/types/rhsmTypes.js b/src/redux/types/rhsmTypes.js
index 2cecbb8c4..5fcba5a9b 100644
--- a/src/redux/types/rhsmTypes.js
+++ b/src/redux/types/rhsmTypes.js
@@ -4,33 +4,18 @@ const GET_GRAPH_REPORT_CAPACITY_RHSM = 'GET_GRAPH_REPORT_CAPACITY_RHSM';
const GET_HOSTS_INVENTORY_RHSM = 'GET_HOSTS_INVENTORY_RHSM';
const GET_HOSTS_INVENTORY_GUESTS_RHSM = 'GET_HOSTS_INVENTORY_GUESTS_RHSM';
-const SET_PAGE_LIMIT_RHSM = 'SET_PAGE_LIMIT_RHSM';
-const SET_PAGE_OFFSET_RHSM = 'SET_PAGE_OFFSET_RHSM';
-const SET_CLEAR_FILTERS = 'SET_CLEAR_FILTERS';
-const SET_FILTER_GRANULARITY_RHSM = 'SET_FILTER_GRANULARITY_RHSM';
-const SET_FILTER_SLA_RHSM = 'SET_FILTER_SLA_RHSM';
-const SET_FILTER_USAGE_RHSM = 'SET_FILTER_USAGE_RHSM';
-
/**
* RHSM API action, reducer types.
*
- * @type {{GET_GRAPH_REPORT_CAPACITY_RHSM: string, SET_FILTER_GRANULARITY_RHSM: string,
- * GET_HOSTS_INVENTORY_GUESTS_RHSM: string, SET_FILTER_SLA_RHSM: string, GET_GRAPH_CAPACITY_RHSM: string,
- * SET_PAGE_OFFSET_RHSM: string, SET_CLEAR_FILTERS: string, GET_HOSTS_INVENTORY_RHSM: string,
- * SET_PAGE_LIMIT_RHSM: string, GET_GRAPH_REPORT_RHSM: string, SET_FILTER_USAGE_RHSM: string}}
+ * @type {{GET_GRAPH_REPORT_CAPACITY_RHSM: string, GET_HOSTS_INVENTORY_GUESTS_RHSM: string,
+ * GET_GRAPH_CAPACITY_RHSM: string, GET_HOSTS_INVENTORY_RHSM: string, GET_GRAPH_REPORT_RHSM: string}}
*/
const rhsmTypes = {
GET_GRAPH_CAPACITY_RHSM,
GET_GRAPH_REPORT_RHSM,
GET_GRAPH_REPORT_CAPACITY_RHSM,
GET_HOSTS_INVENTORY_RHSM,
- GET_HOSTS_INVENTORY_GUESTS_RHSM,
- SET_PAGE_LIMIT_RHSM,
- SET_PAGE_OFFSET_RHSM,
- SET_CLEAR_FILTERS,
- SET_FILTER_GRANULARITY_RHSM,
- SET_FILTER_SLA_RHSM,
- SET_FILTER_USAGE_RHSM
+ GET_HOSTS_INVENTORY_GUESTS_RHSM
};
export {
@@ -40,11 +25,5 @@ export {
GET_GRAPH_REPORT_RHSM,
GET_GRAPH_REPORT_CAPACITY_RHSM,
GET_HOSTS_INVENTORY_RHSM,
- GET_HOSTS_INVENTORY_GUESTS_RHSM,
- SET_PAGE_LIMIT_RHSM,
- SET_PAGE_OFFSET_RHSM,
- SET_CLEAR_FILTERS,
- SET_FILTER_GRANULARITY_RHSM,
- SET_FILTER_SLA_RHSM,
- SET_FILTER_USAGE_RHSM
+ GET_HOSTS_INVENTORY_GUESTS_RHSM
};
diff --git a/src/redux/types/toolbarTypes.js b/src/redux/types/toolbarTypes.js
new file mode 100644
index 000000000..8e4f626a0
--- /dev/null
+++ b/src/redux/types/toolbarTypes.js
@@ -0,0 +1,14 @@
+const SET_ACTIVE_FILTERS = 'SET_ACTIVE_FILTERS';
+const SET_FILTER_TYPE = 'SET_FILTER_TYPE';
+
+/**
+ * Filter, toolbar reducer types.
+ *
+ * @type {{SET_FILTER_TYPE: string, SET_ACTIVE_FILTERS: string}}
+ */
+const toolbarTypes = {
+ SET_ACTIVE_FILTERS,
+ SET_FILTER_TYPE
+};
+
+export { toolbarTypes as default, toolbarTypes, SET_ACTIVE_FILTERS, SET_FILTER_TYPE };
diff --git a/src/styles/_form.scss b/src/styles/_form.scss
index ffe9c9a3f..ce9487d78 100644
--- a/src/styles/_form.scss
+++ b/src/styles/_form.scss
@@ -1,11 +1,9 @@
-.curiosity-toolbar {
- .curiosity-select__no-toggle-text {
- span.pf-c-select__toggle-arrow {
- margin-left: var(--pf-c-select__toggle-arrow--MarginRight);
- }
+.curiosity-select__no-toggle-text {
+ span.pf-c-select__toggle-arrow {
+ margin-left: var(--pf-c-select__toggle-arrow--MarginRight);
+ }
- span.pf-c-select__toggle-text {
- display: none;
- }
+ span.pf-c-select__toggle-text {
+ display: none;
}
}
diff --git a/src/styles/_toolbar.scss b/src/styles/_toolbar.scss
new file mode 100644
index 000000000..580b479a8
--- /dev/null
+++ b/src/styles/_toolbar.scss
@@ -0,0 +1,9 @@
+.curiosity-toolbar {
+ padding-left: var(--pf-c-page__main-section--PaddingLeft);
+ padding-right: var(--pf-c-page__main-section--PaddingRight);
+
+ .pf-c-toolbar__content {
+ padding-left: 0;
+ padding-right: 0;
+ }
+}
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 4943f31e1..c6e0b3b26 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -16,3 +16,4 @@
@import 'skeleton';
@import 'table';
@import 'form';
+@import 'toolbar';