diff --git a/presto-ui/src/router/ClusterHUD.jsx b/presto-ui/src/router/ClusterHUD.jsx index 38bf01e9618bb..002b3ec0888ac 100755 --- a/presto-ui/src/router/ClusterHUD.jsx +++ b/presto-ui/src/router/ClusterHUD.jsx @@ -12,7 +12,7 @@ * limitations under the License. */ -import React from "react"; +import React, { useState, useEffect, useRef } from "react"; import { addExponentiallyWeightedToHistory, @@ -32,124 +32,136 @@ const SPARKLINE_PROPERTIES = { disableHiddenCheck: true, }; -export class ClusterHUD extends React.Component { - constructor(props) { - super(props); - this.state = { - runningQueries: [], - queuedQueries: [], - blockedQueries: [], - activeWorkers: [], - runningDrivers: [], - reservedMemory: [], - rowInputRate: [], - byteInputRate: [], - perWorkerCpuTimeRate: [], - clusterCount: [], +export const ClusterHUD = () => { + const [state, setState] = useState({ + runningQueries: [], + queuedQueries: [], + blockedQueries: [], + activeWorkers: [], + runningDrivers: [], + reservedMemory: [], + rowInputRate: [], + byteInputRate: [], + perWorkerCpuTimeRate: [], + clusterCount: [], - lastRender: null, - lastRefresh: null, + lastRender: null, + lastRefresh: null, - lastInputRows: null, - lastInputBytes: null, - lastCpuTime: null, + lastInputRows: null, + lastInputBytes: null, + lastCpuTime: null, - initialized: false, - }; + initialized: false, + }); - this.refreshLoop = this.refreshLoop.bind(this); - } + const timeoutId = useRef(null); - resetTimer() { - clearTimeout(this.timeoutId); - // stop refreshing when query finishes or fails - if (this.state.query === null || !this.state.ended) { - this.timeoutId = setTimeout(this.refreshLoop, 1000); - } - } + const resetTimer = () => { + clearTimeout(timeoutId.current); + timeoutId.current = setTimeout(refreshLoop, 1000); + }; - refreshLoop() { - clearTimeout(this.timeoutId); // to stop multiple series of refreshLoop from going on simultaneously + const refreshLoop = () => { + clearTimeout(timeoutId.current); // to stop multiple series of refreshLoop from going on simultaneously $.get('/v1/cluster', function (clusterState) { + setState(prevState => { + let newRowInputRate = []; + let newByteInputRate = []; + let newPerWorkerCpuTimeRate = []; + if (prevState.lastRefresh !== null) { + const rowsInputSinceRefresh = clusterState.totalInputRows - prevState.lastInputRows; + const bytesInputSinceRefresh = clusterState.totalInputBytes - prevState.lastInputBytes; + const cpuTimeSinceRefresh = clusterState.totalCpuTimeSecs - prevState.lastCpuTime; + const secsSinceRefresh = (Date.now() - prevState.lastRefresh) / 1000.0; - let newRowInputRate = []; - let newByteInputRate = []; - let newPerWorkerCpuTimeRate = []; - if (this.state.lastRefresh !== null) { - const rowsInputSinceRefresh = clusterState.totalInputRows - this.state.lastInputRows; - const bytesInputSinceRefresh = clusterState.totalInputBytes - this.state.lastInputBytes; - const cpuTimeSinceRefresh = clusterState.totalCpuTimeSecs - this.state.lastCpuTime; - const secsSinceRefresh = (Date.now() - this.state.lastRefresh) / 1000.0; - - newRowInputRate = addExponentiallyWeightedToHistory(rowsInputSinceRefresh / secsSinceRefresh, this.state.rowInputRate); - newByteInputRate = addExponentiallyWeightedToHistory(bytesInputSinceRefresh / secsSinceRefresh, this.state.byteInputRate); - newPerWorkerCpuTimeRate = addExponentiallyWeightedToHistory((cpuTimeSinceRefresh / clusterState.activeWorkers) / secsSinceRefresh, this.state.perWorkerCpuTimeRate); - } + newRowInputRate = addExponentiallyWeightedToHistory(rowsInputSinceRefresh / secsSinceRefresh, prevState.rowInputRate); + newByteInputRate = addExponentiallyWeightedToHistory(bytesInputSinceRefresh / secsSinceRefresh, prevState.byteInputRate); + newPerWorkerCpuTimeRate = addExponentiallyWeightedToHistory((cpuTimeSinceRefresh / clusterState.activeWorkers) / secsSinceRefresh, prevState.perWorkerCpuTimeRate); + } - this.setState({ - // instantaneous stats - runningQueries: addToHistory(clusterState.runningQueries, this.state.runningQueries), - queuedQueries: addToHistory(clusterState.queuedQueries, this.state.queuedQueries), - blockedQueries: addToHistory(clusterState.blockedQueries, this.state.blockedQueries), - activeWorkers: addToHistory(clusterState.activeWorkers, this.state.activeWorkers), - clusterCount: addToHistory(clusterState.clusterCount, this.state.clusterCount), + return { + ...prevState, + // instantaneous stats + runningQueries: addToHistory(clusterState.runningQueries, prevState.runningQueries), + queuedQueries: addToHistory(clusterState.queuedQueries, prevState.queuedQueries), + blockedQueries: addToHistory(clusterState.blockedQueries, prevState.blockedQueries), + activeWorkers: addToHistory(clusterState.activeWorkers, prevState.activeWorkers), + clusterCount: addToHistory(clusterState.clusterCount, prevState.clusterCount), - // moving averages - runningDrivers: addExponentiallyWeightedToHistory(clusterState.runningDrivers, this.state.runningDrivers), - reservedMemory: addExponentiallyWeightedToHistory(clusterState.reservedMemory, this.state.reservedMemory), + // moving averages + runningDrivers: addExponentiallyWeightedToHistory(clusterState.runningDrivers, prevState.runningDrivers), + reservedMemory: addExponentiallyWeightedToHistory(clusterState.reservedMemory, prevState.reservedMemory), - // moving averages for diffs - rowInputRate: newRowInputRate, - byteInputRate: newByteInputRate, - perWorkerCpuTimeRate: newPerWorkerCpuTimeRate, + // moving averages for diffs + rowInputRate: newRowInputRate, + byteInputRate: newByteInputRate, + perWorkerCpuTimeRate: newPerWorkerCpuTimeRate, - lastInputRows: clusterState.totalInputRows, - lastInputBytes: clusterState.totalInputBytes, - lastCpuTime: clusterState.totalCpuTimeSecs, + lastInputRows: clusterState.totalInputRows, + lastInputBytes: clusterState.totalInputBytes, + lastCpuTime: clusterState.totalCpuTimeSecs, - initialized: true, + initialized: true, - lastRefresh: Date.now() + lastRefresh: Date.now() + }; }); - this.resetTimer(); - }.bind(this)) + resetTimer(); + }) .fail(function () { - this.resetTimer(); - }.bind(this)); - } + resetTimer(); + }); + }; - componentDidMount() { - this.refreshLoop(); - } + useEffect(() => { + refreshLoop(); + + return () => { + clearTimeout(timeoutId.current); + }; + }, []); - componentDidUpdate() { + useEffect(() => { // prevent multiple calls to componentDidUpdate (resulting from calls to setState or otherwise) within the refresh interval from re-rendering sparklines/charts - if (this.state.lastRender === null || (Date.now() - this.state.lastRender) >= 1000) { + if (state.lastRender === null || (Date.now() - state.lastRender) >= 1000) { const renderTimestamp = Date.now(); - $('#running-queries-sparkline').sparkline(this.state.runningQueries, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); - $('#blocked-queries-sparkline').sparkline(this.state.blockedQueries, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); - $('#queued-queries-sparkline').sparkline(this.state.queuedQueries, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); + $('#running-queries-sparkline').sparkline(state.runningQueries, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); + $('#blocked-queries-sparkline').sparkline(state.blockedQueries, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); + $('#queued-queries-sparkline').sparkline(state.queuedQueries, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); - $('#active-workers-sparkline').sparkline(this.state.activeWorkers, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); - $('#cluster-count-sparkline').sparkline(this.state.clusterCount, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); + $('#active-workers-sparkline').sparkline(state.activeWorkers, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); + $('#cluster-count-sparkline').sparkline(state.clusterCount, $.extend({}, SPARKLINE_PROPERTIES, {chartRangeMin: 0})); - $('#running-drivers-sparkline').sparkline(this.state.runningDrivers, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: precisionRound})); - $('#reserved-memory-sparkline').sparkline(this.state.reservedMemory, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: formatDataSizeBytes})); + $('#running-drivers-sparkline').sparkline(state.runningDrivers, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: precisionRound})); + $('#reserved-memory-sparkline').sparkline(state.reservedMemory, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: formatDataSizeBytes})); - $('#row-input-rate-sparkline').sparkline(this.state.rowInputRate, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: formatCount})); - $('#byte-input-rate-sparkline').sparkline(this.state.byteInputRate, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: formatDataSizeBytes})); - $('#cpu-time-rate-sparkline').sparkline(this.state.perWorkerCpuTimeRate, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: precisionRound})); + $('#row-input-rate-sparkline').sparkline(state.rowInputRate, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: formatCount})); + $('#byte-input-rate-sparkline').sparkline(state.byteInputRate, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: formatDataSizeBytes})); + $('#cpu-time-rate-sparkline').sparkline(state.perWorkerCpuTimeRate, $.extend({}, SPARKLINE_PROPERTIES, {numberFormatter: precisionRound})); - this.setState({ + setState(prevState => ({ + ...prevState, lastRender: renderTimestamp - }); + })); } $('[data-bs-toggle="tooltip"]')?.tooltip?.(); - } + }, [ + state.runningQueries, + state.blockedQueries, + state.queuedQueries, + state.activeWorkers, + state.clusterCount, + state.runningDrivers, + state.reservedMemory, + state.rowInputRate, + state.byteInputRate, + state.perWorkerCpuTimeRate + ]); - render() { - return (
+ return ( +
@@ -171,7 +183,7 @@ export class ClusterHUD extends React.Component {
- {this.state.runningQueries[this.state.runningQueries.length - 1]} + {state.runningQueries[state.runningQueries.length - 1]}
Loading ...
@@ -179,7 +191,7 @@ export class ClusterHUD extends React.Component {
- {this.state.clusterCount[this.state.clusterCount.length - 1]} + {state.clusterCount[state.clusterCount.length - 1]}
Loading ...
@@ -205,7 +217,7 @@ export class ClusterHUD extends React.Component {
- {this.state.queuedQueries[this.state.queuedQueries.length - 1]} + {state.queuedQueries[state.queuedQueries.length - 1]}
Loading ...
@@ -213,7 +225,7 @@ export class ClusterHUD extends React.Component {
- {this.state.activeWorkers[this.state.activeWorkers.length - 1]} + {state.activeWorkers[state.activeWorkers.length - 1]}
Loading ...
@@ -240,7 +252,7 @@ export class ClusterHUD extends React.Component {
- {this.state.blockedQueries[this.state.blockedQueries.length - 1]} + {state.blockedQueries[state.blockedQueries.length - 1]}
Loading ...
@@ -248,13 +260,13 @@ export class ClusterHUD extends React.Component {
- {formatCount(this.state.runningDrivers[this.state.runningDrivers.length - 1])} + {formatCount(state.runningDrivers[state.runningDrivers.length - 1])}
Loading ...
-
); - } +
+ ); } diff --git a/presto-ui/src/router/PageTitle.jsx b/presto-ui/src/router/PageTitle.jsx index e35938a9b19a0..c32caf237cad4 100755 --- a/presto-ui/src/router/PageTitle.jsx +++ b/presto-ui/src/router/PageTitle.jsx @@ -12,79 +12,69 @@ * limitations under the License. */ //@flow -import React from "react"; +import React, { useState, useEffect, useRef } from "react"; -type Props = { - title: string -} +export const PageTitle = (): React.Node => { + const [state, setState] = useState({ + noConnection: false, + lightShown: false, + info: null, + lastSuccess: Date.now(), + modalShown: false, + errorText: null, + }); -type State = { - noConnection: boolean, - lightShown: boolean, - info: ?any, - lastSuccess: number, - modalShown: boolean, - errorText: ?string, -} + const timeoutId = useRef(null); -export class PageTitle extends React.Component { - timeoutId: TimeoutID; - - constructor(props: Props) { - super(props); - this.state = { - noConnection: false, - lightShown: false, - info: null, - lastSuccess: Date.now(), - modalShown: false, - errorText: null, - }; - } - - refreshLoop: () => void = () => { - clearTimeout(this.timeoutId); + const refreshLoop = () => { + clearTimeout(timeoutId.current); fetch("/v1/info") .then(response => response.json()) .then(info => { - this.setState({ + setState(prevState => ({ + ...prevState, info: info, noConnection: false, lastSuccess: Date.now(), modalShown: false, - }); + })); //$FlowFixMe$ Bootstrap 3 plugin $('#no-connection-modal').hide(); - this.resetTimer(); + resetTimer(); }) .catch(error => { - this.setState({ + setState(prevState => ({ + ...prevState, noConnection: true, - lightShown: !this.state.lightShown, + lightShown: !prevState.lightShown, errorText: error - }); - this.resetTimer(); + })); + resetTimer(); - if (!this.state.modalShown && (error || (Date.now() - this.state.lastSuccess) > 30 * 1000)) { + if (!state.modalShown && (error || (Date.now() - state.lastSuccess) > 30 * 1000)) { //$FlowFixMe$ Bootstrap 3 plugin $('#no-connection-modal').hide(); - this.setState({modalShown: true}); + setState(prevState => ({...prevState, modalShown: true})); } }); - } + }; - resetTimer() { - clearTimeout(this.timeoutId); - this.timeoutId = setTimeout(this.refreshLoop.bind(this), 1000); - } + const resetTimer = () => { + clearTimeout(timeoutId.current); + timeoutId.current = setTimeout(refreshLoop, 1000); + }; - componentDidMount() { - this.refreshLoop.bind(this)(); - } + useEffect(() => { + refreshLoop(); + + return () => { + clearTimeout(timeoutId.current); + }; + }, []); - renderStatusLight(): any { - if (this.state.noConnection) { - if (this.state.lightShown) { + const renderStatusLight = () => { + if (state.noConnection) { + if (state.lightShown) { return ; } else { @@ -92,67 +82,65 @@ export class PageTitle extends React.Component { } } return ; - } + }; - render(): any { - const info = this.state.info; - if (!info) { - return null; - } + const { info } = state; + if (!info) { + return null; + } - return ( -
- + - ); - } -} +
+ ); +}; diff --git a/presto-ui/src/router/QueryList.jsx b/presto-ui/src/router/QueryList.jsx index dafa1ae27887d..ee6f141e94a22 100755 --- a/presto-ui/src/router/QueryList.jsx +++ b/presto-ui/src/router/QueryList.jsx @@ -12,7 +12,7 @@ * limitations under the License. */ -import React from "react"; +import React, { useState, useEffect, useRef } from "react"; import { formatDataSizeBytes, @@ -28,220 +28,162 @@ import { truncateString } from "../utils"; -export class QueryListItem extends React.Component { - static stripQueryTextWhitespace(queryText) { - const lines = queryText.split("\n"); - let minLeadingWhitespace = -1; - for (let i = 0; i < lines.length; i++) { - if (minLeadingWhitespace === 0) { - break; - } +const stripQueryTextWhitespace = (queryText) => { + const lines = queryText.split("\n"); + let minLeadingWhitespace = -1; + for (let i = 0; i < lines.length; i++) { + if (minLeadingWhitespace === 0) { + break; + } - if (lines[i].trim().length === 0) { - continue; - } + if (lines[i].trim().length === 0) { + continue; + } - const leadingWhitespace = lines[i].search(/\S/); + const leadingWhitespace = lines[i].search(/\S/); - if (leadingWhitespace > -1 && ((leadingWhitespace < minLeadingWhitespace) || minLeadingWhitespace === -1)) { - minLeadingWhitespace = leadingWhitespace; - } + if (leadingWhitespace > -1 && ((leadingWhitespace < minLeadingWhitespace) || minLeadingWhitespace === -1)) { + minLeadingWhitespace = leadingWhitespace; } + } - let formattedQueryText = ""; + let formattedQueryText = ""; - for (let i = 0; i < lines.length; i++) { - const trimmedLine = lines[i].substring(minLeadingWhitespace).replace(/\s+$/g, ''); + for (let i = 0; i < lines.length; i++) { + const trimmedLine = lines[i].substring(minLeadingWhitespace).replace(/\s+$/g, ''); - if (trimmedLine.length > 0) { - formattedQueryText += trimmedLine; + if (trimmedLine.length > 0) { + formattedQueryText += trimmedLine; - if (i < (lines.length - 1)) { - formattedQueryText += "\n"; - } + if (i < (lines.length - 1)) { + formattedQueryText += "\n"; } } - - return truncateString(formattedQueryText, 300); } - render() { - const query = this.props.query; - const progressBarStyle = {width: getProgressBarPercentage(query) + "%", backgroundColor: getQueryStateColor(query)}; - - const driverDetails = ( -
- -    - {formatCount(query.progress.completedDrivers)} - - -    - {(query.queryState === "FINISHED" || query.queryState === "FAILED") ? 0 : query.progress.runningDrivers} - - -    - {(query.queryState === "FINISHED" || query.queryState === "FAILED") ? 0 : query.progress.queuedDrivers} - -
); - - const newDriverDetails = ( -
- -    - {formatCount(query.progress.completedNewDrivers)} - - -    - {(query.queryState === "FINISHED" || query.queryState === "FAILED") ? 0 : query.progress.runningNewDrivers} - - -    - {(query.queryState === "FINISHED" || query.queryState === "FAILED") ? 0 : query.progress.queuedNewDrivers} - -
); - - const splitDetails = ( -
- -    - {formatCount(query.progress.completedSplits)} - - -    - {(query.queryState === "FINISHED" || query.queryState === "FAILED") ? 0 : query.progress.runningSplits} - - -    - {(query.queryState === "FINISHED" || query.queryState === "FAILED") ? 0 : query.progress.queuedSplits} - -
); - - const timingDetails = ( -
- -    - {query.queryStats.executionTime} - - -    - {query.queryStats.elapsedTime} - - -    - {query.queryStats.totalCpuTime} - -
); + return truncateString(formattedQueryText, 300); +} - const memoryDetails = ( -
- -    - {query.queryStats.totalMemoryReservation} - - -    - {query.queryStats.peakTotalMemoryReservation} - - -    - {formatDataSizeBytes(query.queryStats.cumulativeUserMemory / 1000.0)} +export const QueryListItem = ({ query }) => { + const progressBarStyle = {width: getProgressBarPercentage(query) + "%", backgroundColor: getQueryStateColor(query)}; + + const splitDetails = ( +
+ +    + {query.queryStats.completedDrivers} + + +    + {(query.state === "FINISHED" || query.state === "FAILED") ? 0 : query.queryStats.runningDrivers} + + +    + {(query.state === "FINISHED" || query.state === "FAILED") ? 0 : query.queryStats.queuedDrivers} -
); - - let user = ({query.session.user}); - if (query.session.principal) { - user = ( - {query.session.user} - ); - } - - return ( -
-
-
-
- -
- {formatShortTime(new Date(Date.parse(query.queryStats.createTime)))} -
-
-
-
- -    - {truncateString(user, 35)} - -
+
); + + const timingDetails = ( +
+ +    + {query.queryStats.executionTime} + + +    + {query.queryStats.elapsedTime} + + +    + {query.queryStats.totalCpuTime} + +
); + + const memoryDetails = ( +
+ +    + {query.queryStats.totalMemoryReservation} + + +    + {query.queryStats.peakTotalMemoryReservation} + + +    + {formatDataSizeBytes(query.queryStats.cumulativeUserMemory / 1000.0)} + +
); + + let user = ({query.session.user}); + + return ( +
+
+
+
+ -
-
- -    - {truncateString(query.session.source, 35)} - -
+
+ {formatShortTime(new Date(Date.parse(query.queryStats.createTime)))}
- - { query.queryStats.completedSplits ? - <> -
- {newDriverDetails} -
-
- {splitDetails} -
- : -
- {driverDetails} -
- } -
- {timingDetails} +
+
+
+ +    + {truncateString(user, 35)} +
-
- {memoryDetails} +
+
+
+ +    + {truncateString(query.session.source, 35)} +
-
-
-
-
-
- {getProgressBarTitle(query)} -
+
+ {splitDetails} +
+
+ {timingDetails} +
+
+ {memoryDetails} +
+
+
+
+
+
+
+ {getProgressBarTitle(query)}
-
-
-
{QueryListItem.stripQueryTextWhitespace(query.query)}
-
+
+
+
+
{stripQueryTextWhitespace(query.query)}
- ); - } -} +
+ ); +}; -class DisplayedQueriesList extends React.Component { - render() { - const queryNodes = this.props.queries.map(function (query) { - return ( - - ); - }.bind(this)); - return ( -
- {queryNodes} -
- ); - } -} +const DisplayedQueriesList = ({ queries }) => ( + <> + {queries.map((query) => ( + + ))} + +); const FILTER_TYPE = { RUNNING: function (query) { @@ -272,41 +214,37 @@ const SORT_ORDER = { DESCENDING: function (value) {return -value} }; -export class QueryList extends React.Component { - constructor(props) { - super(props); - this.state = { - allQueries: [], - displayedQueries: [], - reorderInterval: 5000, - currentSortType: SORT_TYPE.CREATED, - currentSortOrder: SORT_ORDER.DESCENDING, - stateFilters: [FILTER_TYPE.RUNNING, FILTER_TYPE.QUEUED], - errorTypeFilters: [ERROR_TYPE.INTERNAL_ERROR, ERROR_TYPE.INSUFFICIENT_RESOURCES, ERROR_TYPE.EXTERNAL], - searchString: '', - maxQueries: 100, - lastRefresh: Date.now(), - lastReorder: Date.now(), - initialized: false - }; - - this.refreshLoop = this.refreshLoop.bind(this); - this.handleSearchStringChange = this.handleSearchStringChange.bind(this); - this.executeSearch = this.executeSearch.bind(this); - this.handleSortClick = this.handleSortClick.bind(this); - } - - sortAndLimitQueries(queries, sortType, sortOrder, maxQueries) { - queries.sort(function (queryA, queryB) { +export const QueryList = () => { + const [state, setState] = useState({ + allQueries: [], + displayedQueries: [], + reorderInterval: 5000, + currentSortType: SORT_TYPE.CREATED, + currentSortOrder: SORT_ORDER.DESCENDING, + stateFilters: [FILTER_TYPE.RUNNING, FILTER_TYPE.QUEUED], + errorTypeFilters: [ERROR_TYPE.INTERNAL_ERROR, ERROR_TYPE.INSUFFICIENT_RESOURCES, ERROR_TYPE.EXTERNAL], + searchString: '', + maxQueries: 100, + lastRefresh: Date.now(), + lastReorder: Date.now(), + initialized: false + }); + + const timeoutId = useRef(null); + const searchTimeoutId = useRef(null); + + const sortAndLimitQueries = (queries, sortType, sortOrder, maxQueries) => { + const sorted = [...queries].sort(function (queryA, queryB) { return sortOrder(sortType(queryA) - sortType(queryB)); - }, this); + }); - if (maxQueries !== 0 && queries.length > maxQueries) { - queries.splice(maxQueries, (queries.length - maxQueries)); + if (maxQueries !== 0 && sorted.length > maxQueries) { + return sorted.slice(0, maxQueries); } - } + return sorted; + }; - filterQueries(queries, stateFilters, errorTypeFilters, searchString) { + const filterQueries = (queries, stateFilters, errorTypeFilters, searchString) => { const stateFilteredQueries = queries.filter(function (query) { for (let i = 0; i < stateFilters.length; i++) { if (stateFilters[i](query)) { @@ -345,143 +283,160 @@ export class QueryList extends React.Component { return true; } - }, this); + }); } - } + }; - resetTimer() { - clearTimeout(this.timeoutId); - // stop refreshing when query finishes or fails - if (this.state.query === null || !this.state.ended) { - this.timeoutId = setTimeout(this.refreshLoop, 1000); - } - } + const resetTimer = () => { + clearTimeout(timeoutId.current); + timeoutId.current = setTimeout(refreshLoop, 1000); + }; - refreshLoop() { - clearTimeout(this.timeoutId); // to stop multiple series of refreshLoop from going on simultaneously - clearTimeout(this.searchTimeoutId); + const refreshLoop = () => { + clearTimeout(timeoutId.current); // to stop multiple series of refreshLoop from going on simultaneously + clearTimeout(searchTimeoutId.current); $.get('/v1/query', function (queryList) { - const queryMap = queryList.reduce(function (map, query) { - map[query.queryId] = query; - return map; - }, {}); - - let updatedQueries = []; - this.state.displayedQueries.forEach(function (oldQuery) { - if (oldQuery.queryId in queryMap) { - updatedQueries.push(queryMap[oldQuery.queryId]); - queryMap[oldQuery.queryId] = false; - } - }); + setState(prevState => { + const queryMap = queryList.reduce(function (map, query) { + map[query.queryId] = query; + return map; + }, {}); + + let updatedQueries = []; + prevState.displayedQueries.forEach(function (oldQuery) { + if (oldQuery.queryId in queryMap) { + updatedQueries.push(queryMap[oldQuery.queryId]); + queryMap[oldQuery.queryId] = false; + } + }); - let newQueries = []; - for (const queryId in queryMap) { - if (queryMap[queryId]) { - newQueries.push(queryMap[queryId]); + let newQueries = []; + for (const queryId in queryMap) { + if (queryMap[queryId]) { + newQueries.push(queryMap[queryId]); + } } - } - newQueries = this.filterQueries(newQueries, this.state.stateFilters, this.state.errorTypeFilters, this.state.searchString); + newQueries = filterQueries(newQueries, prevState.stateFilters, prevState.errorTypeFilters, prevState.searchString); - const lastRefresh = Date.now(); - let lastReorder = this.state.lastReorder; + const lastRefresh = Date.now(); + let { lastReorder } = prevState; - if (this.state.reorderInterval !== 0 && ((lastRefresh - lastReorder) >= this.state.reorderInterval)) { - updatedQueries = this.filterQueries(updatedQueries, this.state.stateFilters, this.state.errorTypeFilters, this.state.searchString); - updatedQueries = updatedQueries.concat(newQueries); - this.sortAndLimitQueries(updatedQueries, this.state.currentSortType, this.state.currentSortOrder, 0); - lastReorder = Date.now(); - } - else { - this.sortAndLimitQueries(newQueries, this.state.currentSortType, this.state.currentSortOrder, 0); - updatedQueries = updatedQueries.concat(newQueries); - } + if (prevState.reorderInterval !== 0 && ((lastRefresh - lastReorder) >= prevState.reorderInterval)) { + updatedQueries = filterQueries(updatedQueries, prevState.stateFilters, prevState.errorTypeFilters, prevState.searchString); + updatedQueries = updatedQueries.concat(newQueries); + updatedQueries = sortAndLimitQueries(updatedQueries, prevState.currentSortType, prevState.currentSortOrder, 0); + lastReorder = Date.now(); + } + else { + newQueries = sortAndLimitQueries(newQueries, prevState.currentSortType, prevState.currentSortOrder, 0); + updatedQueries = updatedQueries.concat(newQueries); + } - if (this.state.maxQueries !== 0 && (updatedQueries.length > this.state.maxQueries)) { - updatedQueries.splice(this.state.maxQueries, (updatedQueries.length - this.state.maxQueries)); - } + if (prevState.maxQueries !== 0 && (updatedQueries.length > prevState.maxQueries)) { + updatedQueries = updatedQueries.slice(0, prevState.maxQueries); + } - this.setState({ - allQueries: queryList, - displayedQueries: updatedQueries, - lastRefresh: lastRefresh, - lastReorder: lastReorder, - initialized: true + return { + ...prevState, + allQueries: queryList, + displayedQueries: updatedQueries, + lastRefresh: lastRefresh, + lastReorder: lastReorder, + initialized: true + }; }); - this.resetTimer(); - }.bind(this)) + resetTimer(); + }) .fail(function () { - this.setState({ + setState(prevState => ({ + ...prevState, initialized: true, - }); - this.resetTimer(); - }.bind(this)); - } - - componentDidMount() { - this.refreshLoop(); - } + })); + resetTimer(); + }); + }; + + useEffect(() => { + refreshLoop(); + + return () => { + clearTimeout(timeoutId.current); + clearTimeout(searchTimeoutId.current); + }; + }, []); - handleSearchStringChange(event) { + const handleSearchStringChange = (event) => { const newSearchString = event.target.value; - clearTimeout(this.searchTimeoutId); + clearTimeout(searchTimeoutId.current); - this.setState({ + setState({ + ...state, searchString: newSearchString }); - this.searchTimeoutId = setTimeout(this.executeSearch, 200); - } + searchTimeoutId.current = setTimeout(executeSearch, 200); + }; - executeSearch() { - clearTimeout(this.searchTimeoutId); + const executeSearch = () => { + clearTimeout(searchTimeoutId.current); - const newDisplayedQueries = this.filterQueries(this.state.allQueries, this.state.stateFilters, this.state.errorTypeFilters, this.state.searchString); - this.sortAndLimitQueries(newDisplayedQueries, this.state.currentSortType, this.state.currentSortOrder, this.state.maxQueries); + setState(prevState => { + let newDisplayedQueries = filterQueries(prevState.allQueries, prevState.stateFilters, prevState.errorTypeFilters, prevState.searchString); + newDisplayedQueries = sortAndLimitQueries(newDisplayedQueries, prevState.currentSortType, prevState.currentSortOrder, prevState.maxQueries); - this.setState({ - displayedQueries: newDisplayedQueries + return { + ...prevState, + displayedQueries: newDisplayedQueries + }; }); - } + }; - renderMaxQueriesListItem(maxQueries, maxQueriesText) { + const renderMaxQueriesListItem = (maxQueries, maxQueriesText) => { return ( -
  • {maxQueriesText} +
  • {maxQueriesText}
  • ); - } - - handleMaxQueriesClick(newMaxQueries) { - const filteredQueries = this.filterQueries(this.state.allQueries, this.state.stateFilters, this.state.errorTypeFilters, this.state.searchString); - this.sortAndLimitQueries(filteredQueries, this.state.currentSortType, this.state.currentSortOrder, newMaxQueries); - - this.setState({ - maxQueries: newMaxQueries, - displayedQueries: filteredQueries + }; + + const handleMaxQueriesClick = (newMaxQueries) => { + setState(prevState => { + let filteredQueries = filterQueries(prevState.allQueries, prevState.stateFilters, prevState.errorTypeFilters, prevState.searchString); + filteredQueries = sortAndLimitQueries(filteredQueries, prevState.currentSortType, prevState.currentSortOrder, newMaxQueries); + + return { + ...prevState, + maxQueries: newMaxQueries, + displayedQueries: filteredQueries + }; }); - } + }; - renderReorderListItem(interval, intervalText) { + const renderReorderListItem = (interval, intervalText) => { return ( -
  • {intervalText}
  • +
  • {intervalText}
  • ); - } - - handleReorderClick(interval) { - if (this.state.reorderInterval !== interval) { - this.setState({ - reorderInterval: interval, - }); - } - } + }; + + const handleReorderClick = (interval) => { + setState(prevState => { + if (prevState.reorderInterval !== interval) { + return { + ...prevState, + reorderInterval: interval, + }; + } + return prevState; + }); + }; - renderSortListItem(sortType, sortText) { - if (this.state.currentSortType === sortType) { - const directionArrow = this.state.currentSortOrder === SORT_ORDER.ASCENDING ? : + const renderSortListItem = (sortType, sortText) => { + if (state.currentSortType === sortType) { + const directionArrow = state.currentSortOrder === SORT_ORDER.ASCENDING ? : ; return (
  • - + {sortText} {directionArrow}
  • ); @@ -489,190 +444,197 @@ export class QueryList extends React.Component { else { return (
  • - - {sortText} + + {sortText}
  • ); } - } + }; - handleSortClick(sortType) { - const newSortType = sortType; - let newSortOrder = SORT_ORDER.DESCENDING; + const handleSortClick = (sortType) => { + setState(prevState => { + const newSortType = sortType; + let newSortOrder = SORT_ORDER.DESCENDING; - if (this.state.currentSortType === sortType && this.state.currentSortOrder === SORT_ORDER.DESCENDING) { - newSortOrder = SORT_ORDER.ASCENDING; - } + if (prevState.currentSortType === sortType && prevState.currentSortOrder === SORT_ORDER.DESCENDING) { + newSortOrder = SORT_ORDER.ASCENDING; + } - const newDisplayedQueries = this.filterQueries(this.state.allQueries, this.state.stateFilters, this.state.errorTypeFilters, this.state.searchString); - this.sortAndLimitQueries(newDisplayedQueries, newSortType, newSortOrder, this.state.maxQueries); + let newDisplayedQueries = filterQueries(prevState.allQueries, prevState.stateFilters, prevState.errorTypeFilters, prevState.searchString); + newDisplayedQueries = sortAndLimitQueries(newDisplayedQueries, newSortType, newSortOrder, prevState.maxQueries); - this.setState({ - displayedQueries: newDisplayedQueries, - currentSortType: newSortType, - currentSortOrder: newSortOrder + return { + ...prevState, + displayedQueries: newDisplayedQueries, + currentSortType: newSortType, + currentSortOrder: newSortOrder + }; }); - } + }; - renderFilterButton(filterType, filterText) { + const renderFilterButton = (filterType, filterText) => { let checkmarkStyle = {color: '#57aac7'}; let classNames = "btn btn-sm btn-info style-check rounded-0"; - if (this.state.stateFilters.indexOf(filterType) > -1) { + if (state.stateFilters.indexOf(filterType) > -1) { classNames += " active"; checkmarkStyle = {color: '#ffffff'}; } return ( - ); - } + }; - handleStateFilterClick(filter) { - const newFilters = this.state.stateFilters.slice(); - if (this.state.stateFilters.indexOf(filter) > -1) { - newFilters.splice(newFilters.indexOf(filter), 1); - } - else { - newFilters.push(filter); - } + const handleStateFilterClick = (filter) => { + setState(prevState => { + const newFilters = prevState.stateFilters.slice(); + if (prevState.stateFilters.indexOf(filter) > -1) { + newFilters.splice(newFilters.indexOf(filter), 1); + } + else { + newFilters.push(filter); + } - const filteredQueries = this.filterQueries(this.state.allQueries, newFilters, this.state.errorTypeFilters, this.state.searchString); - this.sortAndLimitQueries(filteredQueries, this.state.currentSortType, this.state.currentSortOrder); + let filteredQueries = filterQueries(prevState.allQueries, newFilters, prevState.errorTypeFilters, prevState.searchString); + filteredQueries = sortAndLimitQueries(filteredQueries, prevState.currentSortType, prevState.currentSortOrder, prevState.maxQueries); - this.setState({ - stateFilters: newFilters, - displayedQueries: filteredQueries + return { + ...prevState, + stateFilters: newFilters, + displayedQueries: filteredQueries + }; }); - } + }; - renderErrorTypeListItem(errorType, errorTypeText) { + const renderErrorTypeListItem = (errorType, errorTypeText) => { let checkmarkStyle = {color: '#ffffff'}; - if (this.state.errorTypeFilters.indexOf(errorType) > -1) { + if (state.errorTypeFilters.indexOf(errorType) > -1) { checkmarkStyle = {color: 'black'}; } return (
  • - +  {errorTypeText}
  • ); - } + }; - handleErrorTypeFilterClick(errorType) { - const newFilters = this.state.errorTypeFilters.slice(); - if (this.state.errorTypeFilters.indexOf(errorType) > -1) { - newFilters.splice(newFilters.indexOf(errorType), 1); - } - else { - newFilters.push(errorType); - } + const handleErrorTypeFilterClick = (errorType) => { + setState(prevState => { + const newFilters = prevState.errorTypeFilters.slice(); + if (prevState.errorTypeFilters.indexOf(errorType) > -1) { + newFilters.splice(newFilters.indexOf(errorType), 1); + } + else { + newFilters.push(errorType); + } - const filteredQueries = this.filterQueries(this.state.allQueries, this.state.stateFilters, newFilters, this.state.searchString); - this.sortAndLimitQueries(filteredQueries, this.state.currentSortType, this.state.currentSortOrder); + let filteredQueries = filterQueries(prevState.allQueries, prevState.stateFilters, newFilters, prevState.searchString); + filteredQueries = sortAndLimitQueries(filteredQueries, prevState.currentSortType, prevState.currentSortOrder, prevState.maxQueries); - this.setState({ - errorTypeFilters: newFilters, - displayedQueries: filteredQueries + return { + ...prevState, + errorTypeFilters: newFilters, + displayedQueries: filteredQueries + }; }); - } - - render() { - let queryList = ; - if (this.state.displayedQueries === null || this.state.displayedQueries.length === 0) { - let label = (
    Loading...
    ); - if (this.state.initialized) { - if (this.state.allQueries === null || this.state.allQueries.length === 0) { - label = "No queries"; - } - else { - label = "No queries matched filters"; - } + }; + + let queryList = ; + if (state.displayedQueries === null || state.displayedQueries.length === 0) { + let label = (
    Loading...
    ); + if (state.initialized) { + if (state.allQueries === null || state.allQueries.length === 0) { + label = "No queries"; + } + else { + label = "No queries matched filters"; } - queryList = ( -
    -
    {label}
    -
    - ); } + queryList = ( +
    +
    {label}
    +
    + ); + } - return ( -
    -
    -
    + return ( +
    +
    +
    + +
    + +
    - -
    -
    - State: + State: -
    -
    - {this.renderFilterButton(FILTER_TYPE.RUNNING, "Running")} - {this.renderFilterButton(FILTER_TYPE.QUEUED, "Queued")} - {this.renderFilterButton(FILTER_TYPE.FINISHED, "Finished")} - -
      - {this.renderErrorTypeListItem(ERROR_TYPE.INTERNAL_ERROR, "Internal Error")} - {this.renderErrorTypeListItem(ERROR_TYPE.EXTERNAL, "External Error")} - {this.renderErrorTypeListItem(ERROR_TYPE.INSUFFICIENT_RESOURCES, "Resources Error")} - {this.renderErrorTypeListItem(ERROR_TYPE.USER_ERROR, "User Error")} -
    - -
    -   -
    - -
      - {this.renderSortListItem(SORT_TYPE.CREATED, "Creation Time")} - {this.renderSortListItem(SORT_TYPE.ELAPSED, "Elapsed Time")} - {this.renderSortListItem(SORT_TYPE.CPU, "CPU Time")} - {this.renderSortListItem(SORT_TYPE.EXECUTION, "Execution Time")} - {this.renderSortListItem(SORT_TYPE.CURRENT_MEMORY, "Current Memory")} - {this.renderSortListItem(SORT_TYPE.CUMULATIVE_MEMORY, "Cumulative User Memory")} -
    -
    -   -
    - -
      - {this.renderReorderListItem(1000, "1s")} - {this.renderReorderListItem(5000, "5s")} - {this.renderReorderListItem(10000, "10s")} - {this.renderReorderListItem(30000, "30s")} -
      - {this.renderReorderListItem(0, "Off")} -
    -
    -   -
    - -
      - {this.renderMaxQueriesListItem(20, "20 queries")} - {this.renderMaxQueriesListItem(50, "50 queries")} - {this.renderMaxQueriesListItem(100, "100 queries")} -
      - {this.renderMaxQueriesListItem(0, "All queries")} -
    -
    +
    +
    + {renderFilterButton(FILTER_TYPE.RUNNING, "Running")} + {renderFilterButton(FILTER_TYPE.QUEUED, "Queued")} + {renderFilterButton(FILTER_TYPE.FINISHED, "Finished")} + +
      + {renderErrorTypeListItem(ERROR_TYPE.INTERNAL_ERROR, "Internal Error")} + {renderErrorTypeListItem(ERROR_TYPE.EXTERNAL, "External Error")} + {renderErrorTypeListItem(ERROR_TYPE.INSUFFICIENT_RESOURCES, "Resources Error")} + {renderErrorTypeListItem(ERROR_TYPE.USER_ERROR, "User Error")} +
    + +
    +   +
    + +
      + {renderSortListItem(SORT_TYPE.CREATED, "Creation Time")} + {renderSortListItem(SORT_TYPE.ELAPSED, "Elapsed Time")} + {renderSortListItem(SORT_TYPE.CPU, "CPU Time")} + {renderSortListItem(SORT_TYPE.EXECUTION, "Execution Time")} + {renderSortListItem(SORT_TYPE.CURRENT_MEMORY, "Current Memory")} + {renderSortListItem(SORT_TYPE.CUMULATIVE_MEMORY, "Cumulative User Memory")} +
    +
    +   +
    + +
      + {renderReorderListItem(1000, "1s")} + {renderReorderListItem(5000, "5s")} + {renderReorderListItem(10000, "10s")} + {renderReorderListItem(30000, "30s")} +
      + {renderReorderListItem(0, "Off")} +
    +
    +   +
    + +
      + {renderMaxQueriesListItem(20, "20 queries")} + {renderMaxQueriesListItem(50, "50 queries")} + {renderMaxQueriesListItem(100, "100 queries")} +
      + {renderMaxQueriesListItem(0, "All queries")} +
    - - {queryList} -
    - ); - } -} +
    + + {queryList} +
    + ); +};