1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00
lens/src/common/search-store.ts
Alex Andreev 16fb35e3f9
Log search (#1114)
* Moving logs to virtual list

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Introducing log search

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Setting ref for VirtualList to access its methods

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Introducing search store

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Centering overlay when scroll to it

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Using SearchInput in PodLogSearch

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Using Prev/Next icons for search

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* No trigger logs load when scrolled by method

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* SearchInput refactoring

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Adding find counters

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Clean search query on dock tab change

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Refresh search when logs get changed

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Case-insensitive search

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Improve logs scrolling experience

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Catching empty logs in various places

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Fixing downloading logs

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Clean up some duplicated styles

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Removing jump-to-bottom animation

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Fixing since label

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Reducing container selector size

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Scroll down to bottom after each reload

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Fix search within timestamps if they not provided

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Use log row hover color from theme

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Add search bindings for 'Esc' & 'Enter' hits

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Focus input fields on CmdOrCtrl+F

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Move search.store.ts in to /common folder

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* search.store.ts -> search-store.ts

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Adding test for search store

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Adding integration tests for logs

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Fixing scroll jumping bug

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Removing download icon check for testing purpose

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Removing clicking on nginx-create-pod-test

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Moving log tests before cluster operations

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Build extensions before integration tests

Signed-off-by: Lauri Nevala <lauri.nevala@gmail.com>

* Build also npm before integration tests

Signed-off-by: Lauri Nevala <lauri.nevala@gmail.com>

* Move npm build and extension build into own build step

Signed-off-by: Lauri Nevala <lauri.nevala@gmail.com>

* Removing separator sketches

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Horizontal scrolling to founded keyword

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

* Delaying horizontal scrolling

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>

Co-authored-by: Lauri Nevala <lauri.nevala@gmail.com>
2020-11-09 17:46:14 +03:00

126 lines
3.9 KiB
TypeScript

import { action, computed, observable } from "mobx";
import { autobind } from "../renderer/utils";
export class SearchStore {
@observable searchQuery = ""; // Text in the search input
@observable occurrences: number[] = []; // Array with line numbers, eg [0, 0, 10, 21, 21, 40...]
@observable activeOverlayIndex = -1; // Index withing the occurences array. Showing where is activeOverlay currently located
/**
* Sets default activeOverlayIndex
* @param text An array of any textual data (logs, for example)
* @param query Search query from input
*/
@action
onSearch(text: string[], query = this.searchQuery) {
this.searchQuery = query;
if (!query) {
this.reset();
return;
}
this.occurrences = this.findOccurences(text, query);
if (!this.occurrences.length) return;
// If new highlighted keyword in exact same place as previous one, then no changing in active overlay
if (this.occurrences[this.activeOverlayIndex] !== undefined) return;
this.activeOverlayIndex = this.getNextOverlay(true);
}
/**
* Does searching within text array, create a list of search keyword occurences.
* Each keyword "occurency" is saved as index of the the line where keyword founded
* @param text An array of any textual data (logs, for example)
* @param query Search query from input
* @returns {Array} Array of line indexes [0, 0, 14, 17, 17, 17, 20...]
*/
findOccurences(text: string[], query: string) {
if (!text) return [];
const occurences: number[] = [];
text.forEach((line, index) => {
const regex = new RegExp(this.escapeRegex(query), "gi");
const matches = [...line.matchAll(regex)];
matches.forEach(() => occurences.push(index));
});
return occurences;
}
/**
* Getting next overlay index within the occurences array
* @param loopOver Allows to jump from last element to first
* @returns {number} next overlay index
*/
getNextOverlay(loopOver = false) {
const next = this.activeOverlayIndex + 1;
if (next > this.occurrences.length - 1) {
return loopOver ? 0 : this.activeOverlayIndex;
}
return next;
}
/**
* Getting previous overlay index within the occurences array of occurences
* @param loopOver Allows to jump from first element to last one
* @returns {number} prev overlay index
*/
getPrevOverlay(loopOver = false) {
const prev = this.activeOverlayIndex - 1;
if (prev < 0) {
return loopOver ? this.occurrences.length - 1 : this.activeOverlayIndex;
}
return prev;
}
@autobind()
setNextOverlayActive() {
this.activeOverlayIndex = this.getNextOverlay(true);
}
@autobind()
setPrevOverlayActive() {
this.activeOverlayIndex = this.getPrevOverlay(true);
}
/**
* Gets line index of where active overlay is located
* @returns {number} A line index within the text/logs array
*/
@computed get activeOverlayLine(): number {
return this.occurrences[this.activeOverlayIndex];
}
@computed get activeFind(): number {
return this.activeOverlayIndex + 1;
}
@computed get totalFinds(): number {
return this.occurrences.length;
}
/**
* Checks if overlay is active (to highlight it with orange background usually)
* @param line Index of the line where overlay is located
* @param occurence Number of the overlay within one line
*/
@autobind()
isActiveOverlay(line: number, occurence: number) {
const firstLineIndex = this.occurrences.findIndex(item => item === line);
return firstLineIndex + occurence === this.activeOverlayIndex;
}
/**
* An utility methods escaping user string to safely pass it into new Regex(variable)
* @param value Unescaped string
*/
escapeRegex(value: string) {
return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
}
@action
reset() {
this.searchQuery = "";
this.activeOverlayIndex = -1;
this.occurrences = [];
}
}
export const searchStore = new SearchStore;