From ad100938a030f4bf6d969bbc70cefa0b54db6d0b Mon Sep 17 00:00:00 2001 From: Rob Brackett Date: Mon, 18 Dec 2017 14:09:26 -0800 Subject: [PATCH] Add really lame and minimal URL search This does not fully handle #64, but is a start and is a quick-and-dirty way to search by URL. It should probably be totally rewritten if we want to do a good job. --- src/components/page-list.jsx | 44 ++++++++++++++++++++++++++++ src/components/web-monitoring-ui.jsx | 10 ++++++- src/css/styles.css | 12 ++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/components/page-list.jsx b/src/components/page-list.jsx index a214bf48..9b9ebeea 100644 --- a/src/components/page-list.jsx +++ b/src/components/page-list.jsx @@ -5,6 +5,7 @@ import Loading from './loading'; * These props also inherit from React Router's RouteComponent props * @typedef {Object} PageListProps * @property {Page[]} pages + * @property {(any) => void} onSearch */ /** @@ -15,6 +16,12 @@ import Loading from './loading'; * @param {PageListProps} props */ export default class PageList extends React.Component { + constructor (props) { + super(props); + this._didSearch = this._didSearch.bind(this); + this._dispatchSearch = debounce(this._dispatchSearch.bind(this), 500); + } + render () { if (!this.props.pages) { return ; @@ -22,6 +29,13 @@ export default class PageList extends React.Component { return (
+
+ +
@@ -98,6 +112,28 @@ export default class PageList extends React.Component { this.props.history.push(`/page/${page.uuid}`); } + + _didSearch (event) { + this._dispatchSearch(event.target.value); + } + + _dispatchSearch (url) { + if (url) { + // If doesn't start with a protocol (or looks like it's going that way), + // prefix with an asterisk. + if (!/^(\*|\/\/|(h|ht|htt|https?|https?\/|https?\/\/))/.test(url)) { + url = url = `*//${url}`; + } + // If the search is for a domain + TLD, return all paths under it + if (/^[\w:*]+(\/\/)?[^/]+$/.test(url)) { + url = `${url}*`; + } + } + if (this.props.onSearch) { + const query = url ? {url} : null; + this.props.onSearch(query); + } + } } function isInAnchor (node) { @@ -109,3 +145,11 @@ function isInAnchor (node) { } return isInAnchor(node.parentNode); } + +function debounce (func, delay) { + let timer = null; + return function (...args) { + clearTimeout(timer); + timer = setTimeout(() => func(...args), delay); + }; +} diff --git a/src/components/web-monitoring-ui.jsx b/src/components/web-monitoring-ui.jsx index 562b96e2..b70c287f 100644 --- a/src/components/web-monitoring-ui.jsx +++ b/src/components/web-monitoring-ui.jsx @@ -37,6 +37,7 @@ export default class WebMonitoringUi extends React.Component { isLoading: true, pageFilter: '', // keeps track of which set of pages we are looking at pages: null, + search: null, showLogin: false, user: null, }; @@ -46,6 +47,7 @@ export default class WebMonitoringUi extends React.Component { this.logOut = this.logOut.bind(this); this.loadPages = this.loadPages.bind(this); this.setPageFilter = this.setPageFilter.bind(this); + this.search = this.search.bind(this); } setPageFilter (filter) { @@ -71,6 +73,11 @@ export default class WebMonitoringUi extends React.Component { this.loadPages('pages'); } + search (query) { + this.setState({search: query}); + this.loadPages('pages'); + } + /** * Load pages depending on whether we want all pages or assigned pages. * @private @@ -87,7 +94,7 @@ export default class WebMonitoringUi extends React.Component { return Promise.reject(new Error('You must be logged in to view pages')); } - const query = {include_latest: true}; + const query = Object.assign({include_latest: true}, this.state.search); if (pageFilter === 'assignedPages') { return localApi.getPagesForUser(api.userData.email, null, query); } @@ -137,6 +144,7 @@ export default class WebMonitoringUi extends React.Component { {...routeProps} pages={pages} user={this.state.user} + onSearch={this.search} />; }; }; diff --git a/src/css/styles.css b/src/css/styles.css index 4601216f..f20701a7 100644 --- a/src/css/styles.css +++ b/src/css/styles.css @@ -129,6 +129,18 @@ body { background-color: #EEE; } +.search-bar { + border-bottom: 1px solid #ccc; + margin-bottom: 0.5em; +} + +.search-bar input { + width: 100%; + border: none; + font-size: 1.25em; + padding: 0.5em 15px; +} + /* ===== Page Detail View ===== */ .page-title { font-size: 1.5em;