{
+ this.props.setSearch("label:" + label);
+ }
+
isSelected = c=>{
return _.includes(this.state.selected, c.client_id);
}
@@ -693,14 +697,18 @@ class VeloClientList extends Component {
| {c && c.os_info && c.os_info.fqdn} |
{c && c.os_info && c.os_info.release} |
{_.map(c.labels, (label, idx)=>{
- return ;
+
+ ;
})} |
);
})}
diff --git a/gui/velociraptor/src/components/clients/search.jsx b/gui/velociraptor/src/components/clients/search.jsx
index ed65a6fd2d1..d01725eb369 100644
--- a/gui/velociraptor/src/components/clients/search.jsx
+++ b/gui/velociraptor/src/components/clients/search.jsx
@@ -1,4 +1,5 @@
import "./search.css";
+import _ from 'lodash';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
@@ -8,7 +9,6 @@ import Button from 'react-bootstrap/Button';
import ButtonGroup from 'react-bootstrap/ButtonGroup';
import FormGroup from 'react-bootstrap/FormGroup';
import Form from 'react-bootstrap/Form';
-import { withRouter } from "react-router-dom";
import Autosuggest from 'react-autosuggest';
import Dropdown from 'react-bootstrap/Dropdown';
import UserConfig from '../core/user.jsx';
@@ -18,26 +18,28 @@ import {CancelToken} from 'axios';
import T from '../i8n/i8n.jsx';
-class VeloClientSearch extends Component {
+export default class VeloClientSearch extends Component {
static contextType = UserConfig;
static propTypes = {
// Update the applications's search parameter.
setSearch: PropTypes.func.isRequired,
-
- // React router props.
- match: PropTypes.object,
- history: PropTypes.object,
};
componentDidMount = () => {
this.source = CancelToken.source();
- let query = this.props.match && this.props.match.params &&
- this.props.match.params.query;
+ let query = this.getQueryFromLocation();
if (query && query !== this.state.query) {
- this.this.setState({query: query});
+ this.setState({query: query});
};
};
+ componentDidUpdate = (prevProps, prevState, rootNode) => {
+ let query = this.getQueryFromLocation();
+ if (query && query !== this.state.query) {
+ this.setQuery(query);
+ };
+ }
+
componentWillUnmount() {
this.source.cancel("unmounted");
}
@@ -45,16 +47,35 @@ class VeloClientSearch extends Component {
state = {
// query used to update suggestions.
query: "",
+
+ // When the user begins editing the query string we set the
+ // new query here. When the user submits the query, we clear
+ // this and set the query in the upstream component.
+
+ // When the edit box is editing, we block automatic updates of
+ // the query content from the URL.
+ pending_query: null,
options: [],
}
+ getQueryFromLocation = ()=>{
+ let hash = window.location.hash || "";
+ if(hash.startsWith("#/search/")) {
+ return hash.substring(9);
+ };
+ return "";
+ }
+
showAll = () => {
this.setState({query: "all"});
this.props.setSearch("all");
}
setQuery = (query) => {
- this.setState({query: query});
+ if(_.isString(this.state.pending_query)) {
+ query = this.state.pending_query;
+ }
+ this.setState({query: query, pending_query: null});
this.props.setSearch(query);
}
@@ -75,6 +96,17 @@ class VeloClientSearch extends Component {
});
}
+ // Ensure the query string is a string.
+ getQuery = ()=>{
+ if(_.isString(this.state.pending_query)) {
+ return this.state.pending_query;
+ }
+ if(_.isString(this.state.query)) {
+ return this.state.query;
+ }
+ return "";
+ };
+
render() {
return (