Skip to content

Commit

Permalink
add pagination to results table (#96)
Browse files Browse the repository at this point in the history
* Add pagination to results table
  • Loading branch information
KWMORALE authored Apr 20, 2020
1 parent cfc00f9 commit fe49b19
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 37 deletions.
5 changes: 3 additions & 2 deletions src/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,18 +162,19 @@ def execute_yara(job: JobId, files: List[str]) -> None:
return

rule = compile_yara(job)

len_matches = 0
for sample in files:
try:
matches = rule.match(sample)
if matches:
len_matches += 1
update_metadata(job, sample, [r.rule for r in matches])
except yara.Error:
logging.exception(f"Yara failed to check file {sample}")
except FileNotFoundError:
logging.exception(f"Failed to open file for yara check: {sample}")

db.update_job(job, len(files))
db.update_job(job, len(files), len_matches)


def execute_search(job_id: JobId) -> None:
Expand Down
11 changes: 8 additions & 3 deletions src/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,16 @@ def set_job_to_processing(
"status": "processing",
"iterator": iterator,
"files_processed": 0,
"files_matched": 0,
"total_files": file_count,
},
)

def update_job(self, job: JobId, files_processed: int) -> None:
def update_job(
self, job: JobId, files_processed: int, files_matched: int
) -> None:
self.redis.hincrby(job.key, "files_processed", files_processed)
self.redis.hincrby(job.key, "files_matched", files_matched)

def set_job_to_parsing(self, job: JobId) -> None:
""" Sets the job status to parsing """
Expand Down Expand Up @@ -168,8 +172,9 @@ def get_job(self, job: JobId) -> JobSchema:
raw_yara=data.get("raw_yara", "ERROR"),
submitted=data.get("submitted", 0),
priority=data.get("priority", "medium"),
files_processed=data.get("files_processed", 0),
total_files=data.get("total_files", 0),
files_processed=int(data.get("files_processed", 0)),
files_matched=int(data.get("files_matched", 0)),
total_files=int(data.get("total_files", 0)),
iterator=data.get("iterator", None),
taint=data.get("taint", None),
)
Expand Down
3 changes: 2 additions & 1 deletion src/mqueryfront/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"react-dom": "^16.7.0",
"react-router-dom": "^4.3.1",
"react-scripts": "1.1.4",
"webpack-dev-server": "^3.1.14"
"webpack-dev-server": "^3.1.14",
"react-js-pagination": "^3.0.3"
},
"scripts": {
"start": "react-scripts start",
Expand Down
71 changes: 42 additions & 29 deletions src/mqueryfront/src/QueryPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class QueryPage extends Component {
queryPlan: null,
queryError: null,
datasets: {},
activePage: 1,
};

this.updateQhash = this.updateQhash.bind(this);
Expand Down Expand Up @@ -78,12 +79,14 @@ class QueryPage extends Component {
qhash: newQhash,
matches: [],
job: [],
activePage: 1,
});
this.loadMatches();
this.loadJob();
}

loadMatches() {
const LIMIT = 50;
loadJob() {
const LIMIT = 20;
let OFFSET = (this.state.activePage - 1) * 20;

if (!this.state.qhash) {
return;
Expand All @@ -95,40 +98,48 @@ class QueryPage extends Component {
"/matches/" +
this.state.qhash +
"?offset=" +
this.state.matches.length +
OFFSET +
"&limit=" +
LIMIT
)
.then((response) => {
let newShouldRequest = true;

if (
["done", "cancelled", "failed", "expired"].indexOf(
response.data.job.status
) !== -1
) {
if (!response.data.matches.length) {
newShouldRequest = false;
}
}

let job = response.data.job;
this.setState({
matches: [...this.state.matches, ...response.data.matches],
job: response.data.job,
job: job,
matches: response.data.matches,
});

if (newShouldRequest) {
let nextTimeout =
response.data.matches.length >= LIMIT ? 50 : 1000;
this.timeout = setTimeout(
() => this.loadMatches(),
nextTimeout
);
let doneStatuses = ["cancelled", "failed", "expired"];
let isDone = doneStatuses.indexOf(job.status) !== -1;
let processedAll = job.files_processed >= job.total_files;
if (isDone || processedAll) {
return;
}
})
.catch(() => {
this.timeout = setTimeout(() => this.loadJob(), 1000);
});
}

callbackResultsActivePage = (pageNumber) => {
this.setState({ activePage: pageNumber }, () => {
this.loadMatches();
});
};

loadMatches() {
const LIMIT = 20;
let OFFSET = (this.state.activePage - 1) * 20;
axios
.get(
API_URL +
"/matches/" +
this.state.qhash +
"?offset=" +
OFFSET +
"&limit=" +
LIMIT
)
.then((response) => {
this.setState({
shouldRequest: false,
matches: response.data.matches,
});
});
}
Expand Down Expand Up @@ -169,6 +180,7 @@ class QueryPage extends Component {
queryError={this.state.queryError}
/>
);

var queryResults = (
<div>
<button
Expand All @@ -183,6 +195,7 @@ class QueryPage extends Component {
qhash={this.state.qhash}
job={this.state.job}
matches={this.state.matches}
parentCallback={this.callbackResultsActivePage}
/>
</div>
);
Expand Down
35 changes: 33 additions & 2 deletions src/mqueryfront/src/QueryResultsStatus.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Component } from "react";
import axios from "axios/index";
import { API_URL } from "./config";
import Pagination from "react-js-pagination";

function MatchItem(props) {
const metadata = Object.values(props.meta).map((v) => (
Expand Down Expand Up @@ -63,13 +64,27 @@ class QueryResultsStatus extends Component {
constructor(props) {
super(props);

this.state = {
activePage: 1,
itemsPerPage: 20,
};

this.handleCancelJob = this.handleCancelJob.bind(this);
}

handleCancelJob() {
axios.delete(API_URL + "/job/" + this.props.qhash);
}

sendResultsActivePage = (pageNumber) => {
this.props.parentCallback(pageNumber);
};

handlePageChange(pageNumber) {
this.setState({ activePage: pageNumber });
this.sendResultsActivePage(pageNumber);
}

renderSwitchStatus(status) {
switch (status) {
case "done":
Expand All @@ -86,6 +101,12 @@ class QueryResultsStatus extends Component {
}
}

componentDidUpdate(prevProps) {
if (prevProps.qhash !== this.props.qhash) {
this.setState({ activePage: 1 });
}
}

render() {
if (this.props.job && this.props.job.error) {
return (
Expand Down Expand Up @@ -142,12 +163,11 @@ class QueryResultsStatus extends Component {
cancel = <span />;
}

const lenMatches = this.props.matches.length;
const lenMatches = this.props.job.files_matched;

if (this.props.job.status === "expired") {
return ReturnExpiredJob(this.props.job.error);
}

let results = <div />;

if (lenMatches === 0 && this.props.job.status === "done") {
Expand All @@ -164,6 +184,17 @@ class QueryResultsStatus extends Component {
</thead>
<tbody>{matches}</tbody>
</table>
{lenMatches > 0 && (
<Pagination
activePage={this.state.activePage}
itemsCountPerPage={this.state.itemsPerPage}
totalItemsCount={lenMatches}
pageRangeDisplayed={5}
onChange={this.handlePageChange.bind(this)}
itemClass="page-item"
linkClass="page-link"
/>
)}
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class JobSchema(BaseModel):
submitted: int
priority: str
files_processed: int
files_matched: int
total_files: int
iterator: Optional[str]
taint: Optional[str]
Expand Down

0 comments on commit fe49b19

Please sign in to comment.