From 02fb136d8b55a78aa6c41b9ae98b01a854481e74 Mon Sep 17 00:00:00 2001 From: Alexis SOUQUIERE Date: Sun, 17 Dec 2023 22:12:18 +0100 Subject: [PATCH] feat(topicdata): adding end timestamp filter (#1629) --- .../src/components/DatePicker/DatePicker.jsx | 13 +- .../Topic/Topic/TopicData/TopicData.jsx | 113 +++++++++++++----- .../org/akhq/controllers/TopicController.java | 8 ++ .../akhq/repositories/RecordRepository.java | 14 +++ 4 files changed, 115 insertions(+), 33 deletions(-) diff --git a/client/src/components/DatePicker/DatePicker.jsx b/client/src/components/DatePicker/DatePicker.jsx index 61913c8ff..bc8dbd66d 100644 --- a/client/src/components/DatePicker/DatePicker.jsx +++ b/client/src/components/DatePicker/DatePicker.jsx @@ -43,11 +43,19 @@ class DatePicker extends Component { render = () => { const { value } = this.state; - const { showDateTimeInput, showTimeInput, showTimeSelect, onClear } = this.props; + const { showDateTimeInput, showTimeInput, showTimeSelect, onClear, label } = this.props; return (
{showDateTimeInput && ( -
+
+ {label &&
{label}
} 0 ? moment(datetime) : ''; - timestamp = - formatDateTime( - { - year: timestamp.year(), - monthValue: timestamp.month(), - dayOfMonth: timestamp.date(), - hour: timestamp.hour(), - minute: timestamp.minute(), - second: timestamp.second(), - milli: timestamp.millisecond() - }, - 'YYYY-MM-DDTHH:mm:ss.SSS' - ) + 'Z'; - filters.push(`timestamp=${timestamp}`); + filters.push(`timestamp=${this._buildTimestampFilter(datetime)}`); + } + + if (endDatetime) { + filters.push(`endTimestamp=${this._buildTimestampFilter(endDatetime)}`); } Object.keys(search) @@ -297,6 +292,24 @@ class TopicData extends Root { return filters.join('&'); } + _buildTimestampFilter(datetime) { + let timestamp = datetime.toString().length > 0 ? moment(datetime) : ''; + return ( + formatDateTime( + { + year: timestamp.year(), + monthValue: timestamp.month(), + dayOfMonth: timestamp.date(), + hour: timestamp.hour(), + minute: timestamp.minute(), + second: timestamp.second(), + milli: timestamp.millisecond() + }, + 'YYYY-MM-DDTHH:mm:ss.SSS' + ) + 'Z' + ); + } + _searchMessages(changePage = false) { this._stopEventSource(); if (this._hasAnyFilterFilled()) { @@ -769,6 +782,7 @@ class TopicData extends Root { recordCount, showFilters, datetime, + endDatetime, isSearching, canDeleteRecords, canDownload, @@ -783,6 +797,7 @@ class TopicData extends Root { if (canDownload) actions.push(constants.TABLE_DOWNLOAD); let date = moment(datetime); + let endDate = moment(endDatetime); const { history } = this.props; const firstColumns = [ { colName: 'Key', colSpan: 1 }, @@ -868,7 +883,7 @@ class TopicData extends Root { Timestamp UTC: {datetime !== '' && - ' ' + + ' From ' + formatDateTime( { year: date.year(), @@ -880,23 +895,59 @@ class TopicData extends Root { }, 'DD-MM-YYYY HH:mm' )} + {endDatetime !== '' && + ' To ' + + formatDateTime( + { + year: endDate.year(), + monthValue: endDate.month(), + dayOfMonth: endDate.date(), + hour: endDate.hour(), + minute: endDate.minute(), + second: endDate.second() + }, + 'DD-MM-YYYY HH:mm' + )} {!loading && ( -
- { - this.setState({ datetime: '' }); - }} - showDateTimeInput - showTimeSelect - value={datetime} - onChange={value => { - this.setState({ datetime: value }, () => { - this._searchMessages(); - }); - }} - /> +
+
+ { + this.setState({ datetime: '' }, () => { + this._searchMessages(); + }); + }} + showDateTimeInput + showTimeSelect + value={datetime} + onChange={value => { + this.setState({ datetime: value }, () => { + this._searchMessages(); + }); + }} + /> +
+
+ { + this.setState({ endDatetime: '' }, () => { + this._searchMessages(); + }); + }} + showDateTimeInput + showTimeSelect + value={endDatetime} + onChange={value => { + this.setState({ endDatetime: value }, () => { + this._searchMessages(); + }); + }} + /> +
)} diff --git a/src/main/java/org/akhq/controllers/TopicController.java b/src/main/java/org/akhq/controllers/TopicController.java index 002dc23d3..003be7043 100644 --- a/src/main/java/org/akhq/controllers/TopicController.java +++ b/src/main/java/org/akhq/controllers/TopicController.java @@ -203,6 +203,7 @@ public ResultNextList data( Optional partition, Optional sort, Optional timestamp, + Optional endTimestamp, Optional searchByKey, Optional searchByValue, Optional searchByHeaderKey, @@ -220,6 +221,7 @@ public ResultNextList data( partition, sort, timestamp, + endTimestamp, searchByKey, searchByValue, searchByHeaderKey, @@ -389,6 +391,7 @@ public Publisher> sse( Optional partition, Optional sort, Optional timestamp, + Optional endTimestamp, Optional searchByKey, Optional searchByValue, Optional searchByHeaderKey, @@ -405,6 +408,7 @@ public Publisher> sse( partition, sort, timestamp, + endTimestamp, searchByKey, searchByValue, searchByHeaderKey, @@ -460,6 +464,7 @@ public ResultNextList record( Optional.empty(), Optional.empty(), Optional.empty(), + Optional.empty(), Optional.empty() ); @@ -538,6 +543,7 @@ public RecordRepository.CopyResult copy( Optional.empty(), Optional.empty(), Optional.empty(), + Optional.empty(), Optional.empty() ); @@ -558,6 +564,7 @@ private RecordRepository.Options dataSearchOptions( Optional partition, Optional sort, Optional timestamp, + Optional endTimestamp, Optional searchByKey, Optional searchByValue, Optional searchByHeaderKey, @@ -571,6 +578,7 @@ private RecordRepository.Options dataSearchOptions( partition.ifPresent(options::setPartition); sort.ifPresent(options::setSort); timestamp.map(r -> Instant.parse(r).toEpochMilli()).ifPresent(options::setTimestamp); + endTimestamp.map(r -> Instant.parse(r).toEpochMilli()).ifPresent(options::setEndTimestamp); after.ifPresent(options::setAfter); searchByKey.ifPresent(options::setSearchByKey); searchByValue.ifPresent(options::setSearchByValue); diff --git a/src/main/java/org/akhq/repositories/RecordRepository.java b/src/main/java/org/akhq/repositories/RecordRepository.java index 41b41cff1..98f05ad94 100644 --- a/src/main/java/org/akhq/repositories/RecordRepository.java +++ b/src/main/java/org/akhq/repositories/RecordRepository.java @@ -784,6 +784,19 @@ private boolean matchFilters(BaseOptions options, Record record) { return true; } + private boolean matchFilters(Options options, Record record) { + if (!matchFilters((BaseOptions) options, record)) { + return false; + } + + if (options.getEndTimestamp() != null) { + return record.getTimestamp().toInstant().toEpochMilli() <= options.getEndTimestamp(); + } + + return true; + } + + private boolean matchFilter(Search searchFilter, Collection stringsToSearch) { switch (searchFilter.searchMatchType) { case EQUALS: @@ -1251,6 +1264,7 @@ public enum Sort { private Sort sort; private Integer partition; private Long timestamp; + private Long endTimestamp; public Options(Environment environment, String clusterId, String topic) { this.sort = Sort.OLDEST;