mirror of
https://github.com/gosticks/web.git
synced 2026-10-06 22:57:01 +00:00
Convert the query log to TypeScript
Signed-off-by: Mcat12 <newtoncat12@yahoo.com>
This commit is contained in:
Generated
+65
@@ -1384,6 +1384,16 @@
|
||||
"integrity": "sha512-fOM/Jhv51iyugY7KOBZz2ThfT1gwvsGCfWxpLpZDgkGjpEO4Le9cld07OdskikLjDUQJ43dzDaVRSFwQlpdqVg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/daterangepicker": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/daterangepicker/-/daterangepicker-3.0.0.tgz",
|
||||
"integrity": "sha512-jxPTuNceIF1RoVLcjVzG0L7zM2gB/Zdc5WmiI7gdiPo7Jf9oWAUTQUI49/jmepRdxIBo/ThCw6K+0xZc2Tynvw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/jquery": "*",
|
||||
"moment": ">=2.14.0"
|
||||
}
|
||||
},
|
||||
"@types/enzyme": {
|
||||
"version": "3.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.1.15.tgz",
|
||||
@@ -1415,6 +1425,12 @@
|
||||
"integrity": "sha512-ui3WwXmjTaY73fOQ3/m3nnajU/Orhi6cEu5rzX+BrAAJxa3eITXZ5ch9suPqtM03OWhAHhPSyBGCN4UKoxO20Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/i18next-browser-languagedetector": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/i18next-browser-languagedetector/-/i18next-browser-languagedetector-2.0.1.tgz",
|
||||
"integrity": "sha512-9TwP0tw0PSXUtBtM12PFUjBsl9sP5bNHd54qdSXBrrZ4HJmtVdqbKvmXLH4Qd3KQzIS2g/Z7HhLhygL2LUSb8w==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/i18next-xhr-backend": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/i18next-xhr-backend/-/i18next-xhr-backend-1.4.1.tgz",
|
||||
@@ -1427,6 +1443,30 @@
|
||||
"integrity": "sha512-ePl4l+7dLLmCucIwgQHAgjiepY++qcI6nb8eAwGNkB6OxmTe3Z9rQU3rSpomqu42PCCnlThZbOoxsf+qylJsLA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/jquery": {
|
||||
"version": "3.3.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.29.tgz",
|
||||
"integrity": "sha512-FhJvBninYD36v3k6c+bVk1DSZwh7B5Dpb/Pyk3HKVsiohn0nhbefZZ+3JXbWQhFyt0MxSl2jRDdGQPHeOHFXrQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/sizzle": "*"
|
||||
}
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.120",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.120.tgz",
|
||||
"integrity": "sha512-jQ21kQ120mo+IrDs1nFNVm/AsdFxIx2+vZ347DbogHJPd/JzKNMOqU6HCYin1W6v8l5R9XSO2/e9cxmn7HAnVw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash.debounce": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.4.tgz",
|
||||
"integrity": "sha512-W3oJCQXSCmOE9uIqOdrUWT08YNSXyqXed8JhxJKCe4SH40yxz5HSdtStN1ZQYkvT7S/tae8PA34Y0TO5C7Z8Ng==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/lodash": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "10.12.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
|
||||
@@ -1455,6 +1495,16 @@
|
||||
"csstype": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@types/react-bootstrap-daterangepicker": {
|
||||
"version": "0.0.26",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-bootstrap-daterangepicker/-/react-bootstrap-daterangepicker-0.0.26.tgz",
|
||||
"integrity": "sha512-Y5XfjMtejmG3sH6HL/8sxSh5wXeODGd2P9A6SuPbJjVWrGGvuANLc/4tzff6LMH8dbqc/HGU6FCSkdts1lP6fw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/daterangepicker": "*",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"version": "16.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.0.11.tgz",
|
||||
@@ -1485,6 +1535,15 @@
|
||||
"@types/react-router": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-table": {
|
||||
"version": "6.7.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-table/-/react-table-6.7.21.tgz",
|
||||
"integrity": "sha512-XiYCcn/CBajrj18vLA3kO79AHr5yZTCJe2kl87ZNTRxLO14y9D0IGeGZ3xLsqhfYrJSkkVzAJV8v+bQ4nuKCRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/reactstrap": {
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/reactstrap/-/reactstrap-6.4.4.tgz",
|
||||
@@ -1504,6 +1563,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/sizzle": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
|
||||
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/tapable": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.2.tgz",
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
"@types/i18next-browser-languagedetector": "^2.0.1",
|
||||
"@types/i18next-xhr-backend": "^1.4.1",
|
||||
"@types/jest": "^23.3.13",
|
||||
"@types/lodash.debounce": "^4.0.4",
|
||||
"@types/node": "^10.12.18",
|
||||
"@types/react": "^16.7.20",
|
||||
"@types/react-bootstrap-daterangepicker": "0.0.26",
|
||||
"@types/react-dom": "^16.0.11",
|
||||
"@types/react-router-dom": "^4.3.1",
|
||||
"@types/react-table": "^6.7.21",
|
||||
"@types/reactstrap": "^6.4.4",
|
||||
"@types/sha.js": "^2.4.0",
|
||||
"enzyme": "^3.8.0",
|
||||
|
||||
@@ -9,21 +9,32 @@
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
import React, { Component, Fragment } from "react";
|
||||
import ReactTable from "react-table";
|
||||
import ReactTable, { Filter, ReactTableFunction, RowInfo, RowRenderProps } from "react-table";
|
||||
import DateRangePicker from "react-bootstrap-daterangepicker";
|
||||
import { Button } from "reactstrap";
|
||||
import i18n from "i18next";
|
||||
import { withNamespaces } from "react-i18next";
|
||||
import i18next from "i18next";
|
||||
import { WithNamespaces, withNamespaces } from "react-i18next";
|
||||
import debounce from "lodash.debounce";
|
||||
import moment from "moment";
|
||||
import { ignoreCancel, makeCancelable, padNumber } from "../../util";
|
||||
import api from "../../util/api";
|
||||
import moment, { Moment } from "moment";
|
||||
import { CancelablePromise, ignoreCancel, makeCancelable, padNumber } from "../../util";
|
||||
import api, { ApiHistoryResponse, ApiQuery } from "../../util/api";
|
||||
import "react-table/react-table.css";
|
||||
import "bootstrap-daterangepicker/daterangepicker.css";
|
||||
|
||||
class QueryLog extends Component {
|
||||
updateHandler = null;
|
||||
state = {
|
||||
export interface QueryLogState {
|
||||
history: Array<ApiQuery>;
|
||||
cursor: null | string;
|
||||
loading: boolean;
|
||||
atEnd: boolean;
|
||||
filtersChanged: boolean;
|
||||
filters: Array<Filter>;
|
||||
}
|
||||
|
||||
class QueryLog extends Component<WithNamespaces, QueryLogState> {
|
||||
private updateHandler: null | CancelablePromise<ApiHistoryResponse> = null;
|
||||
|
||||
state: QueryLogState = {
|
||||
history: [],
|
||||
cursor: null,
|
||||
loading: false,
|
||||
@@ -32,7 +43,7 @@ class QueryLog extends Component {
|
||||
filters: []
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: WithNamespaces) {
|
||||
super(props);
|
||||
|
||||
// This happens in the constructor to avoid using dateRanges before it's
|
||||
@@ -61,7 +72,7 @@ class QueryLog extends Component {
|
||||
* @param rowInfo the row information
|
||||
* @returns {*} props for the row
|
||||
*/
|
||||
getRowProps = (state, rowInfo) => {
|
||||
getRowProps = (state: any, rowInfo: RowInfo | undefined) => {
|
||||
// Check if the row is known to be blocked or allowed (not unknown)
|
||||
if (rowInfo && rowInfo.row.status !== 0) {
|
||||
// Blocked queries are red, allowed queries are green
|
||||
@@ -82,8 +93,8 @@ class QueryLog extends Component {
|
||||
* @param tableFilters the filters requested by the table
|
||||
* @return the filters converted for use by the API
|
||||
*/
|
||||
parseFilters = tableFilters => {
|
||||
let filters = {};
|
||||
parseFilters = (tableFilters: Array<Filter>) => {
|
||||
let filters: any = {};
|
||||
|
||||
for (const filter of tableFilters) {
|
||||
switch (filter.id) {
|
||||
@@ -171,7 +182,7 @@ class QueryLog extends Component {
|
||||
* @param page The page of the query log
|
||||
* @param pageSize The number of queries in the page
|
||||
*/
|
||||
fetchQueries = ({ page, pageSize }) => {
|
||||
fetchQueries = ({ page, pageSize }: { page: number; pageSize: number }) => {
|
||||
// Check if we've reached the end of the queries, or are still waiting for
|
||||
// the last fetch to finish
|
||||
if (this.state.atEnd || this.state.loading) {
|
||||
@@ -255,7 +266,7 @@ class QueryLog extends Component {
|
||||
* Convert a status code to a status message. The messages are translated, so
|
||||
* you must pass in the translation function before using the message array.
|
||||
*/
|
||||
const status = t => [
|
||||
const status = (t: i18next.TranslationFunction) => [
|
||||
t("Unknown"),
|
||||
t("Blocked (gravity)"),
|
||||
t("Allowed (forwarded)"),
|
||||
@@ -269,7 +280,7 @@ const status = t => [
|
||||
* Convert a DNSSEC code to a DNSSEC message. The messages are translated, so
|
||||
* you must pass in the translation function before using the message array.
|
||||
*/
|
||||
const dnssec = t => [
|
||||
const dnssec = (t: i18next.TranslationFunction) => [
|
||||
"N/A", // Unspecified, which means DNSSEC is off, so nothing should be shown
|
||||
t("Secure"),
|
||||
t("Insecure"),
|
||||
@@ -291,7 +302,7 @@ const dnssecColor = [
|
||||
* Convert a reply type code to a reply type. The unknown type is translated, so
|
||||
* you must pass in the translation function before using the message array.
|
||||
*/
|
||||
const replyTypes = t => [
|
||||
const replyTypes = (t: i18next.TranslationFunction) => [
|
||||
t("Unknown"),
|
||||
"NODATA",
|
||||
"NXDOMAIN",
|
||||
@@ -316,8 +327,18 @@ const queryTypes = ["A", "AAAA", "ANY", "SRV", "SOA", "PTR", "TXT"];
|
||||
* @returns {function({filter: *, onChange: *}): *} A select component with the
|
||||
* filter data
|
||||
*/
|
||||
const selectionFilter = (items, t, extras = []) => {
|
||||
return ({ filter, onChange }) => (
|
||||
const selectionFilter = (
|
||||
items: string[],
|
||||
t: i18next.TranslationFunction,
|
||||
extras: Array<{ name: string; value: any }> = []
|
||||
) => {
|
||||
return ({
|
||||
filter,
|
||||
onChange
|
||||
}: {
|
||||
filter: Filter;
|
||||
onChange: ReactTableFunction;
|
||||
}) => (
|
||||
<select
|
||||
onChange={event => onChange(event.target.value)}
|
||||
style={{ width: "100%" }}
|
||||
@@ -341,7 +362,7 @@ const selectionFilter = (items, t, extras = []) => {
|
||||
/**
|
||||
* Preconfigured date ranges listed in the date range picker
|
||||
*/
|
||||
const dateRanges = {
|
||||
const dateRanges: { [name: string]: [Moment, Moment] } = {
|
||||
Today: [moment().startOf("day"), moment()],
|
||||
Yesterday: [
|
||||
moment()
|
||||
@@ -370,13 +391,13 @@ const dateRanges = {
|
||||
* The columns of the Query Log. Some pieces are translated, so you must pass in
|
||||
* the translation function before using the columns.
|
||||
*/
|
||||
const columns = t => [
|
||||
const columns = (t: i18next.TranslationFunction) => [
|
||||
{
|
||||
Header: t("Time"),
|
||||
id: "time",
|
||||
accessor: r => r.timestamp,
|
||||
accessor: (r: ApiQuery) => r.timestamp,
|
||||
width: 70,
|
||||
Cell: row => {
|
||||
Cell: (row: RowRenderProps) => {
|
||||
const date = new Date(row.value * 1000);
|
||||
const month = date.toLocaleDateString(i18n.language, {
|
||||
month: "short"
|
||||
@@ -396,7 +417,13 @@ const columns = t => [
|
||||
},
|
||||
filterable: true,
|
||||
filterMethod: () => true, // Don't filter client side
|
||||
Filter: ({ filter, onChange }) => (
|
||||
Filter: ({
|
||||
filter,
|
||||
onChange
|
||||
}: {
|
||||
filter: Filter;
|
||||
onChange: ReactTableFunction;
|
||||
}) => (
|
||||
<DateRangePicker
|
||||
startDate={filter ? filter.value.start : dateRanges.Today[0]}
|
||||
endDate={filter ? filter.value.end : dateRanges.Today[1]}
|
||||
@@ -417,7 +444,7 @@ const columns = t => [
|
||||
{
|
||||
Header: t("Type"),
|
||||
id: "queryType",
|
||||
accessor: r => queryTypes[r.type - 1],
|
||||
accessor: (r: ApiQuery) => queryTypes[r.type - 1],
|
||||
width: 50,
|
||||
filterable: true,
|
||||
filterMethod: () => true, // Don't filter client side
|
||||
@@ -426,7 +453,7 @@ const columns = t => [
|
||||
{
|
||||
Header: t("Domain"),
|
||||
id: "domain",
|
||||
accessor: r => r.domain,
|
||||
accessor: (r: ApiQuery) => r.domain,
|
||||
minWidth: 150,
|
||||
className: "horizontal-scroll",
|
||||
filterable: true,
|
||||
@@ -435,7 +462,7 @@ const columns = t => [
|
||||
{
|
||||
Header: t("Client"),
|
||||
id: "client",
|
||||
accessor: r => r.client,
|
||||
accessor: (r: ApiQuery) => r.client,
|
||||
minWidth: 120,
|
||||
className: "horizontal-scroll",
|
||||
filterable: true,
|
||||
@@ -444,9 +471,9 @@ const columns = t => [
|
||||
{
|
||||
Header: t("Status"),
|
||||
id: "status",
|
||||
accessor: r => r.status,
|
||||
accessor: (r: ApiQuery) => r.status,
|
||||
width: 140,
|
||||
Cell: row => status(t)[row.value],
|
||||
Cell: (row: RowRenderProps) => status(t)[row.value],
|
||||
filterable: true,
|
||||
filterMethod: () => true, // Don't filter client side
|
||||
Filter: selectionFilter(status(t), t, [
|
||||
@@ -457,9 +484,9 @@ const columns = t => [
|
||||
{
|
||||
Header: "DNSSEC",
|
||||
id: "dnssec",
|
||||
accessor: r => r.dnssec,
|
||||
accessor: (r: ApiQuery) => r.dnssec,
|
||||
width: 90,
|
||||
Cell: row => (
|
||||
Cell: (row: RowRenderProps) => (
|
||||
<div style={{ color: dnssecColor[row.value] }}>
|
||||
{dnssec(t)[row.value]}
|
||||
</div>
|
||||
@@ -471,9 +498,9 @@ const columns = t => [
|
||||
{
|
||||
Header: t("Reply"),
|
||||
id: "reply",
|
||||
accessor: r => ({ type: r.reply, time: r.response_time }),
|
||||
accessor: (r: ApiQuery) => ({ type: r.reply, time: r.response_time }),
|
||||
width: 90,
|
||||
Cell: row => (
|
||||
Cell: (row: RowRenderProps) => (
|
||||
<div style={{ color: "black" }}>
|
||||
{replyTypes(t)[row.value.type]}
|
||||
<br />
|
||||
@@ -488,7 +515,7 @@ const columns = t => [
|
||||
Header: t("Action"),
|
||||
width: 100,
|
||||
filterable: false,
|
||||
Cell: data => {
|
||||
Cell: (data: { row: any }) => {
|
||||
// Blocked, but can whitelist
|
||||
if ([1, 4, 5].includes(data.row.status)) {
|
||||
return (
|
||||
+17
-1
@@ -11,6 +11,22 @@
|
||||
import http, { paramsToString } from "./http";
|
||||
import config from "../config";
|
||||
|
||||
export interface ApiQuery {
|
||||
timestamp: number;
|
||||
type: number;
|
||||
status: number;
|
||||
domain: string;
|
||||
client: string;
|
||||
dnssec: number;
|
||||
reply: number;
|
||||
response_time: number;
|
||||
}
|
||||
|
||||
export interface ApiHistoryResponse {
|
||||
cursor: null | string;
|
||||
history: Array<ApiQuery>
|
||||
}
|
||||
|
||||
export interface ApiDnsSettings {
|
||||
upstream_dns: Array<string>,
|
||||
options: {
|
||||
@@ -90,7 +106,7 @@ export default {
|
||||
getTopClients() {
|
||||
return http.get("stats/top_clients");
|
||||
},
|
||||
getHistory(params: any) {
|
||||
getHistory(params: any): Promise<ApiHistoryResponse> {
|
||||
return http.get("stats/history?" + paramsToString(params));
|
||||
},
|
||||
getWhitelist() {
|
||||
|
||||
Reference in New Issue
Block a user