Skip to content

Commit

Permalink
ui: Add filter compaction UI (#4576)
Browse files Browse the repository at this point in the history
  • Loading branch information
adzshaf authored Nov 6, 2021
1 parent 65c5bc5 commit abc5d4c
Show file tree
Hide file tree
Showing 9 changed files with 285 additions and 6,668 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ We use *breaking :warning:* to mark changes that are not backward compatible (re
- [#4764](https://github.com/thanos-io/thanos/pull/4764) Compactor: add `block-viewer.global.sync-block-timeout` flag to set the timeout of synchronization block metas.
- [#4801](https://github.com/thanos-io/thanos/pull/4801) Compactor: added Prometheus metrics for tracking the progress of compaction and downsampling.
- [#4444](https://github.com/thanos-io/thanos/pull/4444) UI: add mark deletion and no compaction to the Block UI.
- [#4576](https://github.com/thanos-io/thanos/pull/4576) UI: add filter compaction level to the Block UI.

### Fixed

Expand Down
98 changes: 49 additions & 49 deletions pkg/ui/bindata.go

Large diffs are not rendered by default.

6,702 changes: 101 additions & 6,601 deletions pkg/ui/react-app/package-lock.json

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions pkg/ui/react-app/src/thanos/pages/blocks/BlockFilterCompaction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, { FC, ChangeEvent } from 'react';
import Checkbox from '../../../components/Checkbox';
import { Input } from 'reactstrap';
import styles from './blocks.module.css';

interface BlockFilterCompactionProps {
id: string;
defaultChecked: boolean;
onChangeCheckbox: ({ target }: ChangeEvent<HTMLInputElement>) => void;
onChangeInput: ({ target }: ChangeEvent<HTMLInputElement>) => void;
defaultValue: string;
}

export const BlockFilterCompaction: FC<BlockFilterCompactionProps> = ({
id,
defaultChecked,
onChangeCheckbox,
onChangeInput,
defaultValue,
}) => {
return (
<div className={styles.blockFilter} style={{ marginLeft: '24px' }}>
<Checkbox style={{ marginRight: '4px' }} id={id} defaultChecked={defaultChecked} onChange={onChangeCheckbox} />
<p style={{ marginRight: '4px' }}>Filter by compaction level</p>
<Input
type="number"
style={{ width: '80px', marginBottom: '1rem' }}
onChange={onChangeInput}
defaultValue={defaultValue}
min={0}
/>
</div>
);
};
80 changes: 67 additions & 13 deletions pkg/ui/react-app/src/thanos/pages/blocks/Blocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Block } from './block';
import { SourceView } from './SourceView';
import { BlockDetails } from './BlockDetails';
import { BlockSearchInput } from './BlockSearchInput';
import { BlockFilterCompaction } from './BlockFilterCompaction';
import { sortBlocks } from './helpers';
import styles from './blocks.module.css';
import TimeRange from './TimeRange';
Expand All @@ -24,6 +25,7 @@ export interface BlockListProps {
export const BlocksContent: FC<{ data: BlockListProps }> = ({ data }) => {
const [selectedBlock, selectBlock] = useState<Block>();
const [searchState, setSearchState] = useState<string>('');

const { blocks, label, err } = data;

const [gridMinTime, gridMaxTime] = useMemo(() => {
Expand All @@ -44,16 +46,28 @@ export const BlocksContent: FC<{ data: BlockListProps }> = ({ data }) => {
}, [blocks, err]);

const [
{ 'min-time': viewMinTime, 'max-time': viewMaxTime, ulid: blockSearchParam, 'find-overlapping': findOverlappingParam },
{
'min-time': viewMinTime,
'max-time': viewMaxTime,
ulid: blockSearchParam,
'find-overlapping': findOverlappingParam,
'filter-compaction': filterCompactionParam,
'compaction-level': compactionLevelParam,
},
setQuery,
] = useQueryParams({
'min-time': withDefault(NumberParam, gridMinTime),
'max-time': withDefault(NumberParam, gridMaxTime),
ulid: withDefault(StringParam, ''),
'find-overlapping': withDefault(BooleanParam, false),
'filter-compaction': withDefault(BooleanParam, false),
'compaction-level': withDefault(NumberParam, 0),
});

const [filterCompaction, setFilterCompaction] = useState<boolean>(filterCompactionParam);
const [findOverlappingBlocks, setFindOverlappingBlocks] = useState<boolean>(findOverlappingParam);
const [compactionLevel, setCompactionLevel] = useState<number>(compactionLevelParam);
const [compactionLevelInput, setCompactionLevelInput] = useState<string>(compactionLevelParam.toString());
const [blockSearch, setBlockSearch] = useState<string>(blockSearchParam);

const blockPools = useMemo(() => sortBlocks(blocks, label, findOverlappingBlocks), [blocks, label, findOverlappingBlocks]);
Expand All @@ -72,6 +86,34 @@ export const BlocksContent: FC<{ data: BlockListProps }> = ({ data }) => {
setBlockSearch(searchState);
};

const onChangeCompactionCheckbox = (target: EventTarget & HTMLInputElement) => {
setFilterCompaction(target.checked);
if (target.checked) {
let compactionLevel: number = parseInt(compactionLevelInput);
setQuery({
'filter-compaction': target.checked,
'compaction-level': compactionLevel,
});
setCompactionLevel(compactionLevel);
} else {
setQuery({
'filter-compaction': target.checked,
'compaction-level': 0,
});
setCompactionLevel(0);
}
};

const onChangeCompactionInput = (target: HTMLInputElement) => {
if (filterCompaction) {
setQuery({
'compaction-level': parseInt(target.value),
});
setCompactionLevel(parseInt(target.value));
}
setCompactionLevelInput(target.value);
};

if (err) return <UncontrolledAlert color="danger">{err.toString()}</UncontrolledAlert>;

return (
Expand All @@ -83,18 +125,29 @@ export const BlocksContent: FC<{ data: BlockListProps }> = ({ data }) => {
onClick={() => setBlockSearchInput(searchState)}
defaultValue={blockSearchParam}
/>
<Checkbox
id="find-overlap-block-checkbox"
onChange={({ target }) => {
setQuery({
'find-overlapping': target.checked,
});
setFindOverlappingBlocks(target.checked);
}}
defaultChecked={findOverlappingBlocks}
>
Enable finding overlapping blocks
</Checkbox>
<div className={styles.blockFilter}>
<Checkbox
id="find-overlap-block-checkbox"
onChange={({ target }) => {
setQuery({
'find-overlapping': target.checked,
});
setFindOverlappingBlocks(target.checked);
}}
defaultChecked={findOverlappingBlocks}
>
Enable finding overlapping blocks
</Checkbox>
<BlockFilterCompaction
id="filter-compaction-checkbox"
defaultChecked={filterCompaction}
onChangeCheckbox={({ target }) => onChangeCompactionCheckbox(target)}
onChangeInput={({ target }: ChangeEvent<HTMLInputElement>): void => {
onChangeCompactionInput(target);
}}
defaultValue={compactionLevelInput}
/>
</div>
<div className={styles.container}>
<div className={styles.grid}>
<div className={styles.sources}>
Expand All @@ -107,6 +160,7 @@ export const BlocksContent: FC<{ data: BlockListProps }> = ({ data }) => {
gridMinTime={viewMinTime}
gridMaxTime={viewMaxTime}
blockSearch={blockSearch}
compactionLevel={compactionLevel}
/>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe('Blocks SourceView', () => {
gridMinTime: 1596096000000,
gridMaxTime: 1595108031471,
blockSearch: '',
compactionLevel: 0,
};

const sourceView = mount(<SourceView {...defaultProps} />);
Expand Down
22 changes: 17 additions & 5 deletions pkg/ui/react-app/src/thanos/pages/blocks/SourceView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@ import React, { FC } from 'react';
import { Block, BlocksPool } from './block';
import { BlockSpan } from './BlockSpan';
import styles from './blocks.module.css';
import { getBlockByUlid } from './helpers';
import { getBlockByUlid, getBlocksByCompactionLevel } from './helpers';

export const BlocksRow: FC<{
blocks: Block[];
gridMinTime: number;
gridMaxTime: number;
selectBlock: React.Dispatch<React.SetStateAction<Block | undefined>>;
blockSearch: string;
}> = ({ blocks, gridMinTime, gridMaxTime, selectBlock, blockSearch }) => {
const blockSearchValue = getBlockByUlid(blocks, blockSearch);
compactionLevel: number;
}> = ({ blocks, gridMinTime, gridMaxTime, selectBlock, blockSearch, compactionLevel }) => {
let filteredBlocks = getBlockByUlid(blocks, blockSearch);
filteredBlocks = getBlocksByCompactionLevel(filteredBlocks, compactionLevel);

return (
<div className={styles.row}>
{blockSearchValue.map<JSX.Element>((b) => (
{filteredBlocks.map<JSX.Element>((b) => (
<BlockSpan selectBlock={selectBlock} block={b} gridMaxTime={gridMaxTime} gridMinTime={gridMinTime} key={b.ulid} />
))}
</div>
Expand All @@ -29,9 +31,18 @@ export interface SourceViewProps {
gridMaxTime: number;
selectBlock: React.Dispatch<React.SetStateAction<Block | undefined>>;
blockSearch: string;
compactionLevel: number;
}

export const SourceView: FC<SourceViewProps> = ({ data, title, gridMaxTime, gridMinTime, selectBlock, blockSearch }) => {
export const SourceView: FC<SourceViewProps> = ({
data,
title,
gridMaxTime,
gridMinTime,
selectBlock,
blockSearch,
compactionLevel,
}) => {
return (
<>
<div className={styles.source}>
Expand All @@ -49,6 +60,7 @@ export const SourceView: FC<SourceViewProps> = ({ data, title, gridMaxTime, grid
gridMaxTime={gridMaxTime}
gridMinTime={gridMinTime}
blockSearch={blockSearch}
compactionLevel={compactionLevel}
/>
))}
</React.Fragment>
Expand Down
6 changes: 6 additions & 0 deletions pkg/ui/react-app/src/thanos/pages/blocks/blocks.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,9 @@
.blockInput {
margin-bottom: 12px;
}

.blockFilter {
display: flex;
flex-direction: row;
align-items: center;
}
9 changes: 9 additions & 0 deletions pkg/ui/react-app/src/thanos/pages/blocks/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,12 @@ export const getBlockByUlid = (blocks: Block[], ulid: string): Block[] => {
const blockResult = blocks.filter((block, index) => resultIndex.includes(index));
return blockResult;
};

export const getBlocksByCompactionLevel = (blocks: Block[], compactionLevel: number): Block[] => {
if (compactionLevel === 0 || Number.isNaN(compactionLevel)) {
return blocks;
}

const blockResult = blocks.filter((block) => block.compaction.level === compactionLevel);
return blockResult;
};

0 comments on commit abc5d4c

Please sign in to comment.