Skip to content

Commit

Permalink
feat(QueryTracker): new columns to the list of queries [#267]
Browse files Browse the repository at this point in the history
  • Loading branch information
vitshev committed Feb 19, 2024
1 parent d84e271 commit 085e937
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 34 deletions.
2 changes: 2 additions & 0 deletions packages/ui/src/shared/constants/settings-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ interface AccountsSettings {

interface QueryTrackerSettings {
'global::queryTracker::queriesListSidebarVisibilityMode': boolean;
'local::queryTracker::history::AllColumns': string[];
'local::queryTracker::history::MyColumns': string[];
}

interface ChytSettings {
Expand Down
4 changes: 4 additions & 0 deletions packages/ui/src/ui/components/common/Timeline/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export const formatInterval = (from: MomentInput, to: MomentInput) => {
}
};

export const formatTime = (date: MomentInput) => {
return moment(date).format('HH:mm');
};

export const formatDateCompact = (date: MomentInput) => {
return moment(date).format('DD.MM.YY, HH:mm');
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,27 @@

&__name-edit {
visibility: hidden;
width: 0;
flex: 1px;
overflow: hidden;
z-index: 1;
margin: -14px 0;
}

&:hover &__name-edit {
flex: 1;
padding-left: 5px;
visibility: visible;
width: auto;
overflow: visible;
}

&_header {
padding: 8px 0;

&:hover {
background: transparent;
cursor: auto;
}
}
}

Expand Down Expand Up @@ -76,4 +88,8 @@
align-items: center;
padding: 8px 0;
}

&__row-header {
padding: 6px 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
import hammer from '../../../../common/hammer';
import moment from 'moment';
import groupBy from 'lodash/groupBy';
import noop from 'lodash/noop';
import {Text} from '@gravity-ui/uikit';
import block from 'bem-cn-lite';
import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import React, {useCallback, useContext, useEffect, useMemo, useRef} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import {QueryItem, QueryStatus} from '../../module/api';
import {refreshQueriesListIfNeeded} from '../../module/queries_list/actions';
import {getQueriesListTimestamp, getUncompletedItems} from '../../module/queries_list/selectors';
import {QueryStatusIcon} from '../../QueryStatus';
import hammer from '../../../../common/hammer';

import './index.scss';
import Pagination from '../../../../components/Pagination/Pagination';
import {noop} from 'lodash';
import {QueriesPoolingContext} from '../../hooks/QueriesPooling/context';
import {formatDateCompact} from '../../../../components/common/Timeline/util';
import {formatTime} from '../../../../components/common/Timeline/util';
import {QueryEnginesNames} from '../../utils/query';
import DataTableYT from '../../../../components/DataTableYT/DataTableYT';
import DataTable, {Column, Settings} from '@gravity-ui/react-data-table';
import {useQuriesHistoryFilter} from '../../hooks/QueryListFilter';
import {QueriesListAuthorFilter} from '../../module/queries_list/types';
import {QueryDuration} from '../../QueryDuration';
import {useQueryNavigation} from '../../hooks/Query';
import {useQueriesPagination, useQueryList} from '../../hooks/QueriesList';
import EditQueryNameModal from '../EditQueryNameModal/EditQueryNameModal';
import {UPDATE_QUERIES_LIST} from '../../module/query-tracker-contants';
import {useQueryHistoryListColumns} from './useQueryListColumns';

import './index.scss';

const b = block('queries-history-list');

Expand Down Expand Up @@ -81,11 +84,26 @@ function useQueryHistoryList() {
return useQueryList();
}

const NameColumns: Column<QueryItem> = {
type HeaderTableItem = {header: string};
type TableItem = QueryItem | HeaderTableItem;

const isQueryItem = (b: TableItem): b is QueryItem => {
return (b as QueryItem).id !== undefined;
};

const isHeaderTableItem = (b: TableItem): b is HeaderTableItem => {
return (b as HeaderTableItem).header !== undefined;
};

const NameColumns: Column<TableItem> = {
name: 'Name',
align: 'left',
className: itemBlock('name_row'),
render: ({row}) => {
if (isHeaderTableItem(row)) {
return null;
}

const name = row.annotations?.title;
return (
<div className={itemBlock('name')} title={name}>
Expand All @@ -103,11 +121,15 @@ const NameColumns: Column<QueryItem> = {
},
};

const TypeColumns: Column<QueryItem> = {
const TypeColumns: Column<TableItem> = {
name: 'Type',
align: 'center',
width: 60,
render: ({row}) => {
if (isHeaderTableItem(row)) {
return null;
}

return (
<Text variant="body-1" color="secondary">
{row.engine in QueryEnginesNames ? QueryEnginesNames[row.engine] : row.engine}
Expand All @@ -116,37 +138,49 @@ const TypeColumns: Column<QueryItem> = {
},
};

const DurationColumns: Column<QueryItem> = {
const DurationColumns: Column<TableItem> = {
name: 'Duration',
align: 'left',
width: 100,
render: ({row}) => {
if (isHeaderTableItem(row)) {
return null;
}

if (row.state === QueryStatus.RUNNING) {
return hammer.format.NO_VALUE;
}
return <QueryDuration query={row} />;
},
};

const StartedColumns: Column<QueryItem> = {
const StartedColumns: Column<TableItem> = {
name: 'Started',
align: 'left',
width: 120,
width: 60,
render: ({row}) => {
if (isHeaderTableItem(row)) {
return null;
}

return (
<Text variant="body-1" color="secondary">
{formatDateCompact(row.start_time)}
{formatTime(row.start_time)}
</Text>
);
},
};

const AuthorColumns: Column<QueryItem> = {
const AuthorColumns: Column<TableItem> = {
name: 'Author',
align: 'left',
width: 120,
className: itemBlock('author_row'),
render: ({row}) => {
if (isHeaderTableItem(row)) {
return null;
}

return (
<Text variant="body-1" ellipsis title={row.user}>
{row.user}
Expand All @@ -155,13 +189,38 @@ const AuthorColumns: Column<QueryItem> = {
},
};

const MyColumns: Column<QueryItem>[] = [NameColumns, TypeColumns, DurationColumns, StartedColumns];
const AllColumns: Column<QueryItem>[] = [
const ACOColumns: Column<TableItem> = {
name: 'ACO',
align: 'left',
width: 60,
className: itemBlock('access_control_object'),
render: ({row}) => {
if (isHeaderTableItem(row)) {
return null;
}

return (
<Text variant="body-1" ellipsis title={row.access_control_object}>
{row.access_control_object}
</Text>
);
},
};

export const MyColumns: Column<TableItem>[] = [
NameColumns,
TypeColumns,
DurationColumns,
StartedColumns,
ACOColumns,
];
export const AllColumns: Column<TableItem>[] = [
NameColumns,
TypeColumns,
DurationColumns,
AuthorColumns,
StartedColumns,
ACOColumns,
];

const tableSettings: Settings = {
Expand All @@ -173,54 +232,76 @@ const tableSettings: Settings = {

export function QueriesHistoryList() {
const [items, isLoading] = useQueryHistoryList();

const [filter] = useQuriesHistoryFilter();

const {columns} = useQueryHistoryListColumns({type: filter.user});
const timestamp = useSelector(getQueriesListTimestamp);

const {first, last, goBack, goNext, goFirst} = useQueriesPagination();

const [selectedId, goToQuery] = useQueryNavigation();

const [columns, setColumns] = useState<Column<QueryItem>[]>([]);

const scrollElemRef = useRef<HTMLDivElement | null>(null);

useEffect(() => {
if (!isLoading || !items?.length) {
setColumns(filter.user === QueriesListAuthorFilter.My ? MyColumns : AllColumns);
}
}, [items, setColumns, filter.user, isLoading]);

useEffect(() => {
if (scrollElemRef?.current) {
scrollElemRef.current.scrollTop = 0;
}
}, [scrollElemRef, timestamp]);

const setClassName = useCallback(
(item: QueryItem) => {
(item: TableItem) => {
if (isHeaderTableItem(item)) {
return itemBlock({
header: Boolean(item.header),
});
}

return itemBlock({
selected: item.id === selectedId,
});
},
[selectedId],
);

const itemsByDate = Object.entries(
groupBy(items, (item) => moment(item.start_time).format('DD MMMM YYYY')),
).reduce((ret, [header, items]) => {
ret.push({
header,
});

return ret.concat(items.map((item) => item));
}, [] as Array<QueryItem | {header: string}>);

return (
<div className={b()}>
<div className={b('list-wrapper')} ref={scrollElemRef}>
<DataTableYT
<DataTableYT<TableItem>
className={b('list')}
loading={isLoading}
columns={columns}
data={items}
data={itemsByDate}
useThemeYT={true}
rowKey={(row) => row.id}
onRowClick={goToQuery}
rowKey={(row) => (row as QueryItem).id}
onRowClick={(item) => goToQuery(item as QueryItem)}
disableRightGap={true}
settings={tableSettings}
rowClassName={setClassName}
renderRow={({defaultRender, columns, index, className}) => {
const item = itemsByDate[index];
if (isQueryItem(item)) {
return defaultRender();
}

if (isHeaderTableItem(item)) {
return (
<tr className={className} key={item.header}>
<td colSpan={columns.length} align="center">
<p className={b('row-header')}>{item.header}</p>
</td>
</tr>
);
}

return null;
}}
/>
<div className={b('pagination')}>
{(!first || !last) && (
Expand Down
Loading

0 comments on commit 085e937

Please # to comment.