From 130110f5a4347213f957a5e0fb40f7285cec3bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivar=20Conradi=20=C3=98sthus?= Date: Thu, 24 Sep 2020 19:31:49 +0200 Subject: [PATCH] feat: add search for applications --- .../application/application-list-component.js | 17 ++++- .../application/application-list-container.js | 16 ++++- frontend/src/component/common/common.scss | 13 ++++ frontend/src/component/common/index.js | 4 +- .../src/component/common/search-field.jsx | 50 +++++++++++++++ .../list-component-test.jsx.snap | 62 +++++++++++++------ frontend/src/component/feature/feature.scss | 12 ---- .../src/component/feature/list-component.jsx | 18 +++--- 8 files changed, 144 insertions(+), 48 deletions(-) create mode 100644 frontend/src/component/common/search-field.jsx diff --git a/frontend/src/component/application/application-list-component.js b/frontend/src/component/application/application-list-component.js index 81be64eb43..976d5de7a4 100644 --- a/frontend/src/component/application/application-list-component.js +++ b/frontend/src/component/application/application-list-component.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { ProgressBar, Card, CardText, Icon } from 'react-mdl'; import { AppsLinkList, styles as commonStyles } from '../common'; +import SearchField from '../common/search-field'; const Empty = () => ( @@ -22,6 +23,8 @@ class ClientStrategies extends Component { static propTypes = { applications: PropTypes.array, fetchAll: PropTypes.func.isRequired, + settings: PropTypes.object.isRequired, + updateSetting: PropTypes.func.isRequired, }; componentDidMount() { @@ -35,9 +38,17 @@ class ClientStrategies extends Component { return ; } return ( - - {applications.length > 0 ? : } - +
+
+ +
+ + {applications.length > 0 ? : } + +
); } } diff --git a/frontend/src/component/application/application-list-container.js b/frontend/src/component/application/application-list-container.js index eb3809c078..e8d3ff6f88 100644 --- a/frontend/src/component/application/application-list-container.js +++ b/frontend/src/component/application/application-list-container.js @@ -1,9 +1,21 @@ import { connect } from 'react-redux'; import ApplicationList from './application-list-component'; import { fetchAll } from './../../store/application/actions'; +import { updateSettingForGroup } from '../../store/settings/actions'; -const mapStateToProps = state => ({ applications: state.applications.get('list').toJS() }); +const mapStateToProps = state => { + const applications = state.applications.get('list').toJS(); + const settings = state.settings.toJS().application || {}; -const Container = connect(mapStateToProps, { fetchAll })(ApplicationList); + const regex = new RegExp(settings.filter, 'i'); + + return { + applications: settings.filter ? applications.filter(a => regex.test(a.appName)) : applications, + settings, + }; +}; +const mapDispatchToProps = { fetchAll, updateSetting: updateSettingForGroup('application') }; + +const Container = connect(mapStateToProps, mapDispatchToProps)(ApplicationList); export default Container; diff --git a/frontend/src/component/common/common.scss b/frontend/src/component/common/common.scss index 487a3a0a14..6b55a7665d 100644 --- a/frontend/src/component/common/common.scss +++ b/frontend/src/component/common/common.scss @@ -85,4 +85,17 @@ .toggleName { color: #37474f !important; font-weight: 500; +} + +.toolbar { + position: relative; + padding: 0 24px 16px 24px; + text-align: center; +} + +.toolbarButton { + position: absolute; + top: 56px; + right: 24px; + z-index: 2; } \ No newline at end of file diff --git a/frontend/src/component/common/index.js b/frontend/src/component/common/index.js index 1daa5a6bfc..0a9247c6ea 100644 --- a/frontend/src/component/common/index.js +++ b/frontend/src/component/common/index.js @@ -11,14 +11,14 @@ export const shorten = (str, len = 50) => (str && str.length > len ? `${str.subs export const AppsLinkList = ({ apps }) => ( {apps.length > 0 && - apps.map(({ appName, description = '-', icon }) => ( + apps.map(({ appName, description, icon }) => ( {appName} - {description} + {description || 'No descriptionn'} diff --git a/frontend/src/component/common/search-field.jsx b/frontend/src/component/common/search-field.jsx new file mode 100644 index 0000000000..e6130a0c53 --- /dev/null +++ b/frontend/src/component/common/search-field.jsx @@ -0,0 +1,50 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { debounce } from 'debounce'; +import { FABButton, Icon, Textfield } from 'react-mdl'; + +function SearchField({ value, updateValue }) { + const [localValue, setLocalValue] = useState(value); + const debounceUpdateValue = debounce(updateValue, 500); + + const handleCange = e => { + e.preventDefault(); + const v = e.target.value || ''; + setLocalValue(v); + debounceUpdateValue(v); + }; + + const handleKeyPress = e => { + if (e.key === 'Enter') { + updateValue(localValue); + } + }; + + const updateNow = () => { + updateValue(localValue); + }; + + return ( +
+ + + + +
+ ); +} + +SearchField.propTypes = { + value: PropTypes.string.isRequired, + updateValue: PropTypes.func.isRequired, +}; + +export default SearchField; 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 e8573c6320..c18023ed3f 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 @@ -5,16 +5,29 @@ exports[`renders correctly with one feature 1`] = `
- + + /> + + + +
- + + /> + + + + -
- { - this.setFilter(e.target.value); - }} - label="Search" - style={{ width: '100%' }} +
+ {hasPermission(CREATE_FEATURE) ? ( - +