From 35e0c3af7e9f2c14b830ebbb2c1e71a611538d03 Mon Sep 17 00:00:00 2001 From: Mcat12 Date: Wed, 23 Jan 2019 20:59:13 -0800 Subject: [PATCH] Convert the query log to TypeScript Signed-off-by: Mcat12 --- package-lock.json | 65 +++++++++++++ package.json | 3 + .../log/{QueryLog.js => QueryLog.tsx} | 93 ++++++++++++------- src/util/api.tsx | 18 +++- 4 files changed, 145 insertions(+), 34 deletions(-) rename src/components/log/{QueryLog.js => QueryLog.tsx} (85%) diff --git a/package-lock.json b/package-lock.json index 741761e..da88342 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index fbdcce3..af45a0b 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/log/QueryLog.js b/src/components/log/QueryLog.tsx similarity index 85% rename from src/components/log/QueryLog.js rename to src/components/log/QueryLog.tsx index 840ca53..32d467a 100644 --- a/src/components/log/QueryLog.js +++ b/src/components/log/QueryLog.tsx @@ -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; + cursor: null | string; + loading: boolean; + atEnd: boolean; + filtersChanged: boolean; + filters: Array; +} + +class QueryLog extends Component { + private updateHandler: null | CancelablePromise = 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) => { + 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; + }) => (