diff --git a/redisinsight/ui/src/pages/slow-log/SlowLogPage.styles.ts b/redisinsight/ui/src/pages/slow-log/SlowLogPage.styles.ts new file mode 100644 index 0000000000..01c9be7811 --- /dev/null +++ b/redisinsight/ui/src/pages/slow-log/SlowLogPage.styles.ts @@ -0,0 +1,6 @@ +import styled from 'styled-components' +import { RiSelect } from 'uiSrc/components/base/forms/select/RiSelect' + +export const StyledSelect = styled(RiSelect)` + border: none; +` diff --git a/redisinsight/ui/src/pages/slow-log/SlowLogPage.tsx b/redisinsight/ui/src/pages/slow-log/SlowLogPage.tsx index b39621eb3a..49ec63e57e 100644 --- a/redisinsight/ui/src/pages/slow-log/SlowLogPage.tsx +++ b/redisinsight/ui/src/pages/slow-log/SlowLogPage.tsx @@ -32,17 +32,15 @@ import { import { AnalyticsViewTab } from 'uiSrc/slices/interfaces/analytics' import { FormatedDate } from 'uiSrc/components' -import { FlexItem, Row } from 'uiSrc/components/base/layout/flex' -import { Text } from 'uiSrc/components/base/text' -import { - defaultValueRender, - RiSelect, -} from 'uiSrc/components/base/forms/select/RiSelect' +import { Col, FlexItem, Row } from 'uiSrc/components/base/layout/flex' +import { Text, Title } from 'uiSrc/components/base/text' +import { defaultValueRender } from 'uiSrc/components/base/forms/select/RiSelect' import { SlowLog } from 'apiSrc/modules/slow-log/models' import { Actions, EmptySlowLog, SlowLogTable } from './components' import styles from './styles.module.scss' +import { StyledSelect } from './SlowLogPage.styles' const HIDE_TIMESTAMP_FROM_WIDTH = 850 const DEFAULT_COUNT_VALUE = '50' @@ -144,61 +142,78 @@ const SlowLogPage = () => { const isEmptySlowLog = !data.length return ( -
- - - - - - - {connectionType !== ConnectionType.Cluster && config && ( - - Execution time:{' '} - {numberWithSpaces( - convertNumberByUnits(slowlogLogSlowerThan, durationUnit), - )} -   - {durationUnit === DurationUnits.milliSeconds - ? DurationUnits.mSeconds - : DurationUnits.microSeconds} - , Max length: {numberWithSpaces(slowlogMaxLen)} - - )} - - - + {({ width }) => (
+ + + + + + + + {connectionType !== ConnectionType.Cluster && config && ( + + Execution time:{' '} + {numberWithSpaces( + convertNumberByUnits( + slowlogLogSlowerThan, + durationUnit, + ), + )} +   + {durationUnit === DurationUnits.milliSeconds + ? DurationUnits.mSeconds + : DurationUnits.microSeconds} + , Max length: {numberWithSpaces(slowlogMaxLen)} + + )} + + + + + + - + + Slow Log + + + + - + {connectionType === ConnectionType.Cluster ? 'Display per node:' : 'Display up to:'} - setCount(value)} - className={styles.countSelect} data-testid="count-select" /> {width > HIDE_TIMESTAMP_FROM_WIDTH && ( ({data.length} entries @@ -214,15 +229,6 @@ const SlowLogPage = () => { )} - - -
)} @@ -239,7 +245,7 @@ const SlowLogPage = () => { durationUnit={durationUnit} /> )} -
+ ) } diff --git a/redisinsight/ui/src/pages/slow-log/components/Actions/Actions.styles.ts b/redisinsight/ui/src/pages/slow-log/components/Actions/Actions.styles.ts new file mode 100644 index 0000000000..180b106bd4 --- /dev/null +++ b/redisinsight/ui/src/pages/slow-log/components/Actions/Actions.styles.ts @@ -0,0 +1,7 @@ +import styled from 'styled-components' + +export const StyledInfoIconWrapper = styled.span` + display: flex; + align-self: center; + cursor: pointer; +` diff --git a/redisinsight/ui/src/pages/slow-log/components/Actions/Actions.tsx b/redisinsight/ui/src/pages/slow-log/components/Actions/Actions.tsx index 1a27d903bc..fa9eb7e63b 100644 --- a/redisinsight/ui/src/pages/slow-log/components/Actions/Actions.tsx +++ b/redisinsight/ui/src/pages/slow-log/components/Actions/Actions.tsx @@ -1,6 +1,5 @@ import React, { useState } from 'react' import { useSelector } from 'react-redux' -import cx from 'classnames' import { useParams } from 'react-router-dom' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import { DurationUnits } from 'uiSrc/constants' @@ -13,15 +12,14 @@ import { FlexItem, Row } from 'uiSrc/components/base/layout/flex' import { Spacer } from 'uiSrc/components/base/layout/spacer' import { EraserIcon, SettingsIcon } from 'uiSrc/components/base/icons' import { - DestructiveButton, IconButton, SecondaryButton, } from 'uiSrc/components/base/forms/buttons' -import { Text } from 'uiSrc/components/base/text' import { RiIcon } from 'uiSrc/components/base/icons/RiIcon' import SlowLogConfig from '../SlowLogConfig' -import styles from './styles.module.scss' +import { StyledInfoIconWrapper } from './Actions.styles' +import { ClearSlowLogModal } from '../ClearSlowLogModal/ClearSlowLogModal' export interface Props { width: number @@ -45,15 +43,15 @@ const Actions = (props: Props) => { const { name = '' } = useSelector(connectedInstanceSelector) const { loading, lastRefreshTime } = useSelector(slowLogSelector) - const [isPopoverClearOpen, setIsPopoverClearOpen] = useState(false) + const [isClearModalOpen, setIsClearModalOpen] = useState(false) const [isPopoverConfigOpen, setIsPopoverConfigOpen] = useState(false) - const showClearPopover = () => { - setIsPopoverClearOpen((isPopoverClearOpen) => !isPopoverClearOpen) + const showClearModal = () => { + setIsClearModalOpen((isClearModalOpen) => !isClearModalOpen) } - const closePopoverClear = () => { - setIsPopoverClearOpen(false) + const closeClearModal = () => { + setIsClearModalOpen(false) } const showConfigPopover = () => { setIsPopoverConfigOpen((isPopoverConfigOpen) => !isPopoverConfigOpen) @@ -63,11 +61,6 @@ const Actions = (props: Props) => { setIsPopoverConfigOpen(false) } - const handleClearClick = () => { - onClear() - closePopoverClear() - } - const handleEnableAutoRefresh = ( enableAutoRefresh: boolean, refreshRate: string, @@ -98,66 +91,32 @@ const Actions = (props: Props) => { } } - const ToolTipContent = ( -
- -
- -

- Clear Slow Log? -

- - Slow Log will be cleared for  - {name} -
- NOTE: This is server configuration -
-
-
- handleClearClick()} - className={styles.popoverDeleteBtn} - data-testid="reset-confirm-btn" - > - Clear - -
-
-
- ) - return ( - - + + HIDE_REFRESH_LABEL_WIDTH} lastRefreshTime={lastRefreshTime} - containerClassName={styles.refreshContainer} onRefresh={() => onRefresh()} onEnableAutoRefresh={handleEnableAutoRefresh} onChangeAutoRefreshRate={handleChangeAutoRefreshRate} testid="slowlog" /> - + + {}} - panelClassName={cx('popover-without-top-tail', styles.configWrapper)} button={ showConfigPopover()} @@ -173,38 +132,29 @@ const Actions = (props: Props) => { /> + {!isEmptySlowLog && ( - - - showClearPopover()} - data-testid="clear-btn" - /> - - } - > - {ToolTipContent} - - + <> + showClearModal()} + data-testid="clear-btn" + /> + + + )} - + + Slow Log is a list of slow operations for your Redis instance. @@ -218,12 +168,9 @@ const Actions = (props: Props) => { } > - + + + diff --git a/redisinsight/ui/src/pages/slow-log/components/Actions/styles.module.scss b/redisinsight/ui/src/pages/slow-log/components/Actions/styles.module.scss deleted file mode 100644 index 65c3be58f2..0000000000 --- a/redisinsight/ui/src/pages/slow-log/components/Actions/styles.module.scss +++ /dev/null @@ -1,68 +0,0 @@ -@include global.insights-open(1200px) { - .actions { - width: auto !important; - } -} - -.actions { - width: 370px; - - @media only screen and (max-width: 870px) { - width: 300px; - } - - .icon { - color: var(--iconsDefaultColor); - width: 24px; - height: 24px; - display: flex; - align-items: center; - justify-content: center; - - &:hover { - color: var(--iconsDefaultHoverColor); - } - - :global(.euiIcon) { - width: 18px; - height: 18px; - } - - .infoIcon { - width: 20px; - height: 20px; - } - } -} - -.popoverContainer { - display: flex; - align-items: flex-start; - - .warningIcon { - margin: 2px 6px 2px; - } - - .popoverTitle { - font: - normal normal 500 13px/22px Graphik, - sans-serif; - color: var(--euiColorFullShade) !important; - } - - .popoverFooter { - display: flex; - justify-content: flex-end; - margin-top: 12px; - } - - .popoverDBName { - color: var(--htmlColor); - } -} - -.configWrapper { - padding: 24px !important; - box-shadow: 0px 3px 15px #00000099; - background-color: var(--euiColorLightestShade) !important; -} diff --git a/redisinsight/ui/src/pages/slow-log/components/ClearSlowLogModal/ClearSlowLogModal.spec.tsx b/redisinsight/ui/src/pages/slow-log/components/ClearSlowLogModal/ClearSlowLogModal.spec.tsx new file mode 100644 index 0000000000..f01857e7f7 --- /dev/null +++ b/redisinsight/ui/src/pages/slow-log/components/ClearSlowLogModal/ClearSlowLogModal.spec.tsx @@ -0,0 +1,86 @@ +import React from 'react' + +import { ClearSlowLogModal, ClearSlowLogModalProps } from './ClearSlowLogModal' +import { render, screen, fireEvent } from 'uiSrc/utils/test-utils' + +const renderClearSlowLogModal = (props?: Partial) => { + const defaultProps: ClearSlowLogModalProps = { + name: 'test-database', + isOpen: true, + onClose: jest.fn(), + onClear: jest.fn(), + } + + return render() +} + +describe('ClearSlowLogModal', () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + it('should render the modal when isOpen is true', () => { + const props: Partial = { + name: 'test-database', + isOpen: true, + } + + renderClearSlowLogModal(props) + + const title = screen.getByText('Clear slow log') + expect(title).toBeInTheDocument() + + const message = screen.getByText( + /Slow Log will be cleared for\s+test-database/, + ) + expect(message).toBeInTheDocument() + + const note = screen.getByText('NOTE: This is server configuration') + expect(note).toBeInTheDocument() + + const cancelButton = screen.getByTestId('reset-cancel-btn') + expect(cancelButton).toBeInTheDocument() + expect(cancelButton).toHaveTextContent('Cancel') + + const clearButton = screen.getByTestId('reset-confirm-btn') + expect(clearButton).toBeInTheDocument() + expect(clearButton).toHaveTextContent('Clear') + }) + + it('should not render the modal when isOpen is false', () => { + renderClearSlowLogModal({ isOpen: false }) + + const modal = screen.queryByTestId('clear-slow-log-modal') + expect(modal).not.toBeInTheDocument() + }) + + it('should call onClose when Cancel button is clicked', () => { + const props: Partial = { + onClose: jest.fn(), + onClear: jest.fn(), + } + + renderClearSlowLogModal(props) + + const cancelButton = screen.getByTestId('reset-cancel-btn') + fireEvent.click(cancelButton) + + expect(props.onClose).toHaveBeenCalledTimes(1) + expect(props.onClear).not.toHaveBeenCalled() + }) + + it('should call onClear and onClose when Clear button is clicked', () => { + const props: Partial = { + onClose: jest.fn(), + onClear: jest.fn(), + } + + renderClearSlowLogModal(props) + + const clearButton = screen.getByTestId('reset-confirm-btn') + fireEvent.click(clearButton) + + expect(props.onClear).toHaveBeenCalledTimes(1) + expect(props.onClose).toHaveBeenCalledTimes(1) + }) +}) diff --git a/redisinsight/ui/src/pages/slow-log/components/ClearSlowLogModal/ClearSlowLogModal.styles.ts b/redisinsight/ui/src/pages/slow-log/components/ClearSlowLogModal/ClearSlowLogModal.styles.ts new file mode 100644 index 0000000000..fada3bc1f0 --- /dev/null +++ b/redisinsight/ui/src/pages/slow-log/components/ClearSlowLogModal/ClearSlowLogModal.styles.ts @@ -0,0 +1,7 @@ +import styled from 'styled-components' +import FormDialog from 'uiSrc/components/form-dialog/FormDialog' + +export const StyledFormDialog = styled(FormDialog)` + width: 402px; + height: auto; +` diff --git a/redisinsight/ui/src/pages/slow-log/components/ClearSlowLogModal/ClearSlowLogModal.tsx b/redisinsight/ui/src/pages/slow-log/components/ClearSlowLogModal/ClearSlowLogModal.tsx new file mode 100644 index 0000000000..5318bde055 --- /dev/null +++ b/redisinsight/ui/src/pages/slow-log/components/ClearSlowLogModal/ClearSlowLogModal.tsx @@ -0,0 +1,69 @@ +import React from 'react' + +import { Button, DestructiveButton } from 'uiSrc/components/base/forms/buttons' +import { Col, FlexGroup, Row } from 'uiSrc/components/base/layout/flex' +import { Title, Text } from 'uiSrc/components/base/text' +import { EraserIcon } from 'uiSrc/components/base/icons' +import { Spacer } from 'uiSrc/components/base/layout' + +import { StyledFormDialog } from './ClearSlowLogModal.styles' + +export interface ClearSlowLogModalProps { + name: string + isOpen: boolean + onClose: () => void + onClear: () => void +} + +export const ClearSlowLogModal = ({ + name, + isOpen, + onClose, + onClear, +}: ClearSlowLogModalProps) => { + const handleClearClick = () => { + onClear() + onClose() + } + + return ( + Clear slow log} + footer={ + + + handleClearClick()} + data-testid="reset-confirm-btn" + > + Clear + + + } + > + + + + + Slow Log will be cleared for {name} + + + NOTE: This is server configuration + + + + + ) +} diff --git a/redisinsight/ui/src/pages/slow-log/components/EmptySlowLog/EmptySlowLog.styles.ts b/redisinsight/ui/src/pages/slow-log/components/EmptySlowLog/EmptySlowLog.styles.ts new file mode 100644 index 0000000000..181255de19 --- /dev/null +++ b/redisinsight/ui/src/pages/slow-log/components/EmptySlowLog/EmptySlowLog.styles.ts @@ -0,0 +1,5 @@ +import styled from 'styled-components' + +export const StyledImage = styled.img` + max-width: 120px; +` diff --git a/redisinsight/ui/src/pages/slow-log/components/EmptySlowLog/EmptySlowLog.tsx b/redisinsight/ui/src/pages/slow-log/components/EmptySlowLog/EmptySlowLog.tsx index 5b3818ca98..1ccdf2b4aa 100644 --- a/redisinsight/ui/src/pages/slow-log/components/EmptySlowLog/EmptySlowLog.tsx +++ b/redisinsight/ui/src/pages/slow-log/components/EmptySlowLog/EmptySlowLog.tsx @@ -4,8 +4,10 @@ import { Title } from 'uiSrc/components/base/text/Title' import { convertNumberByUnits } from 'uiSrc/pages/slow-log/utils' import { numberWithSpaces } from 'uiSrc/utils/numbers' import { Text } from 'uiSrc/components/base/text' +import { Col } from 'uiSrc/components/base/layout/flex' +import NoQueryResultsIcon from 'uiSrc/assets/img/vector-search/no-query-results.svg' -import styles from '../styles.module.scss' +import { StyledImage } from './EmptySlowLog.styles' export interface Props { durationUnit: DurationUnits @@ -16,24 +18,27 @@ const EmptySlowLog = (props: Props) => { const { durationUnit, slowlogLogSlowerThan } = props return ( -
-
- - No Slow Logs found - - - Either no commands exceeding  - {numberWithSpaces( - convertNumberByUnits(slowlogLogSlowerThan, durationUnit), - )} -   - {durationUnit === DurationUnits.milliSeconds - ? DurationUnits.mSeconds - : DurationUnits.microSeconds} -  were found or Slow Log is disabled on the server. - -
-
+ + + + + + No Slow Logs found + + + Either no commands exceeding  + {numberWithSpaces( + convertNumberByUnits(slowlogLogSlowerThan, durationUnit), + )} +   + {durationUnit === DurationUnits.milliSeconds + ? DurationUnits.mSeconds + : DurationUnits.microSeconds} +  were found or Slow Log is disabled on the server. + + + + ) } diff --git a/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/SlowLogConfig.styles.ts b/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/SlowLogConfig.styles.ts new file mode 100644 index 0000000000..6079ae5133 --- /dev/null +++ b/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/SlowLogConfig.styles.ts @@ -0,0 +1,14 @@ +import styled from 'styled-components' +import { Col } from 'uiSrc/components/base/layout/flex' +import { TextInput } from 'uiSrc/components/base/inputs' +import { theme } from '@redis-ui/styles' + +export const StyledContainer = styled(Col)<{ $isCluster?: boolean }>` + width: ${({ $isCluster }) => ($isCluster ? '394px' : '550px')}; + padding: ${theme.core.space.space200}; + border-radius: ${theme.core.space.space050}; +` + +export const StyledInput = styled(TextInput)` + width: 160px; +` diff --git a/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/SlowLogConfig.tsx b/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/SlowLogConfig.tsx index abafa624e7..c50ad848ae 100644 --- a/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/SlowLogConfig.tsx +++ b/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/SlowLogConfig.tsx @@ -2,7 +2,6 @@ import { toNumber } from 'lodash' import React, { useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { useParams } from 'react-router-dom' -import cx from 'classnames' import { DEFAULT_SLOWLOG_DURATION_UNIT, DEFAULT_SLOWLOG_MAX_LEN, @@ -34,9 +33,8 @@ import { defaultValueRender, RiSelect, } from 'uiSrc/components/base/forms/select/RiSelect' -import { TextInput } from 'uiSrc/components/base/inputs' import { convertNumberByUnits } from '../../utils' -import styles from './styles.module.scss' +import { StyledContainer, StyledInput } from './SlowLogConfig.styles' export interface Props { closePopover: () => void @@ -121,7 +119,7 @@ const SlowLogConfig = ({ closePopover, onRefresh }: Props) => { const clusterContent = () => ( <> - + Each node can have different Slow Log configuration in a clustered database. @@ -131,15 +129,14 @@ const SlowLogConfig = ({ closePopover, onRefresh }: Props) => { CONFIG SET slowlog-max-len {' for a specific node in redis-cli to configure it.'} - - - - Ok - + + + Ok + + ) @@ -167,101 +164,95 @@ const SlowLogConfig = ({ closePopover, onRefresh }: Props) => { } return ( - {connectionType === ConnectionType.Cluster && clusterContent()} {connectionType !== ConnectionType.Cluster && ( <>
- slowlog-log-slower-than - } - additionalText={ -
-
{unitConverter()}
-
- Execution time to exceed in order to log the command. -
- -1 disables Slow Log. 0 logs each command. -
-
- } - > - + slowlog-log-slower-than} + additionalText={ + + + {unitConverter()} + + + Execution time to exceed in order to log the command. +
+ -1 disables Slow Log. 0 logs each command. +
+
+ } > -
- + { - setSlowerThan( - validateNumber(value.trim(), -1, Infinity), - ) + onChange={(value) => { + setSlowerThan(validateNumber(value.trim(), -1, Infinity)) }} placeholder={`${convertNumberByUnits(DEFAULT_SLOWLOG_SLOWER_THAN, durationUnit)}`} autoComplete="off" data-testid="slower-than-input" /> -
- -
-
- slowlog-max-len} - additionalText={ -
- The length of the Slow Log. When a new command is logged the - oldest -
- one is removed from the queue of logged commands. -
- } - > - <> -
- { - setMaxLen(validateNumber(value.trim())) - }} - autoComplete="off" - data-testid="max-len-input" + -
- -
- + + + slowlog-max-len} + additionalText={ + + The length of the Slow Log. When a new command is logged the + oldest +
+ one is removed from the queue of logged commands. +
+ } + > + { + setMaxLen(validateNumber(value.trim())) + }} + autoComplete="off" + data-testid="max-len-input" + /> +
+ - - - NOTE: This is server configuration + + + + NOTE: This is server configuration + - + { )} - + ) } diff --git a/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/styles.module.scss b/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/styles.module.scss deleted file mode 100644 index 829dae177b..0000000000 --- a/redisinsight/ui/src/pages/slow-log/components/SlowLogConfig/styles.module.scss +++ /dev/null @@ -1,112 +0,0 @@ -.container { - width: 550px; - height: 280px; - background-color: var(--euiColorLightestShade); - border-radius: 4px; -} - -.containerCluster { - width: 394px; - height: 150px; -} - -.selectWrapper { - display: inline-block !important; - width: 60px !important; - margin-top: -4px; - - :global(.euiFormControlLayout__childrenWrapper) { - height: 42px !important; - width: 74px; - } -} - -.input { - width: 120px !important; -} - -.formRow { - width: 600px !important; - max-width: 600px !important; - padding-bottom: 2px; -} - -.rowFields { - width: 400px; -} - -.rowLabel { - min-width: 156px; - font-size: 13px; -} - -.helpText { - display: inline-block; - font-size: 12px; - line-height: 18px; - letter-spacing: -0.12px; - color: var(--euiColorMediumShade); - padding-top: 6px; - - div { - display: inline-block; - padding-bottom: 6px; - width: 100%; - } -} - -.footer { - padding-top: 6px; - - .helpText { - padding-top: 12px; - } -} - -.actions { - display: inline-block; - right: 24px; - position: absolute; - - :global { - .euiButton, - .euiButtonEmpty { - margin-right: 12px !important; - width: 100px; - height: 42px; - - .euiButtonEmpty__text { - color: var(--euiColorFullShade) !important; - } - } - } -} - -.clusterText :global(.euiTextColor) { - font-size: 13px !important; - line-height: 18px !important; - letter-spacing: -0.13px !important; - - a { - color: var(--euiColorFullShade) !important; - } - - code { - font-size: 13px; - line-height: 18px; - padding-left: 4px; - padding-right: 4px; - color: var(--inputTextColor); - - &:last-of-type { - padding-left: 0 !important; - } - } -} - -.clusterBtn { - margin-top: 8px; - position: absolute; - right: 24px; - bottom: 18px; -} diff --git a/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.spec.tsx b/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.spec.tsx index f78d09b476..2d908abfb1 100644 --- a/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.spec.tsx +++ b/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.spec.tsx @@ -31,9 +31,13 @@ describe('SlowLogTable', () => { }) it('should render data', () => { - expect( - render(), - ).toBeTruthy() - expect(screen.getAllByLabelText(/^row$/)).toHaveLength(mockedData.length) + const { container } = render( + , + ) + + expect(container).toBeTruthy() + + const rows = container.querySelectorAll('[data-row-type="regular"]') + expect(rows).toHaveLength(mockedData.length) }) }) diff --git a/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.styles.ts b/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.styles.ts new file mode 100644 index 0000000000..f582295568 --- /dev/null +++ b/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.styles.ts @@ -0,0 +1,11 @@ +import { Table } from '@redis-ui/table' +import styled from 'styled-components' +import { Col } from 'uiSrc/components/base/layout/flex' + +export const StyledTableWrapper = styled(Col)` + height: calc(100% - 100px); +` + +export const StyledTable = styled(Table)` + max-height: 100%; +` diff --git a/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.tsx b/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.tsx index 22bda3f182..553bb09fcc 100644 --- a/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.tsx +++ b/redisinsight/ui/src/pages/slow-log/components/SlowLogTable/SlowLogTable.tsx @@ -1,102 +1,81 @@ -import React, { useEffect, useState } from 'react' +import React from 'react' import { useParams } from 'react-router-dom' -import { ITableColumn } from 'uiSrc/components/virtual-table/interfaces' -import VirtualTable from 'uiSrc/components/virtual-table/VirtualTable' -import { - DURATION_UNITS, - DurationUnits, - SortOrder, - TableCellAlignment, - TableCellTextAlignment, -} from 'uiSrc/constants' +import { DURATION_UNITS, DurationUnits, SortOrder } from 'uiSrc/constants' import { convertNumberByUnits } from 'uiSrc/pages/slow-log/utils' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { numberWithSpaces } from 'uiSrc/utils/numbers' import { Text } from 'uiSrc/components/base/text' +import { + Table, + ColumnDef, + SortingState, +} from 'uiSrc/components/base/layout/table' import { FormatedDate, RiTooltip } from 'uiSrc/components' -import styles from '../styles.module.scss' + +import { SlowLog } from 'apiSrc/modules/slow-log/models' +import { StyledTableWrapper } from './SlowLogTable.styles' export const DATE_FORMAT = 'HH:mm:ss d LLL yyyy' export interface Props { - items: any + items: SlowLog[] loading: boolean durationUnit: DurationUnits } -const sortByTimeStamp = (items = [], order: SortOrder) => - [...items].sort((a: any, b: any) => - order === SortOrder.DESC ? b.time - a.time : a.time - b.time, - ) - const SlowLogTable = (props: Props) => { - const { items = [], loading = false, durationUnit } = props - const [table, setTable] = useState([]) - const [sortedColumnName, setSortedColumnName] = useState('time') - const [sortedColumnOrder, setSortedColumnOrder] = useState(SortOrder.DESC) + const { items = [], durationUnit } = props const { instanceId } = useParams<{ instanceId: string }>() - const sortedColumn = { - column: sortedColumnName, - order: sortedColumnOrder, - } - - useEffect(() => { - setTable(sortByTimeStamp(items, sortedColumnOrder)) - }, [items, sortedColumnOrder]) - const columns: ITableColumn[] = [ + const columns: ColumnDef[] = [ { id: 'time', - label: 'Timestamp', - absoluteWidth: 190, - minWidth: 190, - isSortable: true, - render: (timestamp) => ( - - - - ), + header: 'Timestamp', + accessorKey: 'time', + size: 15, + cell: ({ getValue }) => { + const date = (getValue() as number) * 1000 + + return + }, }, { id: 'durationUs', - label: `Duration, ${DURATION_UNITS.find(({ value }) => value === durationUnit)?.inputDisplay}`, - minWidth: 110, - absoluteWidth: 'auto', - textAlignment: TableCellTextAlignment.Right, - alignment: TableCellAlignment.Right, - render: (duration) => ( - - {numberWithSpaces(convertNumberByUnits(duration, durationUnit))} - - ), + header: `Duration, ${DURATION_UNITS.find(({ value }) => value === durationUnit)?.inputDisplay}`, + accessorKey: 'durationUs', + size: 15, + cell: ({ getValue }) => { + const duration = getValue() as number + + return ( + + {numberWithSpaces(convertNumberByUnits(duration, durationUnit))} + + ) + }, }, { id: 'args', - label: 'Command', - render: (command) => ( - - - {command} - - - ), + header: 'Command', + accessorKey: 'args', + cell: ({ getValue }) => { + const command = getValue() as string + + return ( + + {command} + + ) + }, }, ] - const onChangeSorting = (column: any, order: SortOrder) => { - setSortedColumnName(column) - setSortedColumnOrder(order) + const handleSortingChange = (state: SortingState) => { + const { desc } = state[0] || { desc: true } + const order = desc ? SortOrder.DESC : SortOrder.ASC + sendEventTelemetry({ event: TelemetryEvent.SLOWLOG_SORTED, eventData: { @@ -107,17 +86,15 @@ const SlowLogTable = (props: Props) => { } return ( -
- + - + ) } diff --git a/redisinsight/ui/src/pages/slow-log/components/styles.module.scss b/redisinsight/ui/src/pages/slow-log/components/styles.module.scss deleted file mode 100644 index d2861b0dbc..0000000000 --- a/redisinsight/ui/src/pages/slow-log/components/styles.module.scss +++ /dev/null @@ -1,65 +0,0 @@ -.tableWrapper { - flex-grow: 1; - height: calc(100% - 100px); - - @media screen and (max-width: 1024px) { - height: calc(100% - 120px); - } - - :global { - .ReactVirtualized__Table__row { - border: 1px solid var(--tableDarkestBorderColor) !important; - - &:first-of-type { - border-top: 0 !important; - } - - &:not(:last-of-type) { - border-bottom: 0 !important; - } - } - - .ReactVirtualized__Table__rowColumn { - &:not(:last-of-type) { - border-right: 1px solid var(--tableDarkestBorderColor) !important; - } - } - } - - .commandTooltip { - max-width: 100%; - } - - .commandText { - display: block; - text-overflow: ellipsis; - max-width: 100%; - white-space: nowrap; - overflow: hidden; - line-height: 1.4; - } -} - -.noSlowLogWrapper { - border: 1px solid var(--tableDarkestBorderColor); - min-height: 152px; - width: 100%; - display: flex; - align-items: center; - padding: 18px; - - .noFoundTitle { - font: normal normal 500 18px/24px Graphik, sans-serif; - margin-bottom: 12px; - } - - .noSlowLogText { - margin: 0 auto; - max-width: 882px; - width: 100%; - } -} - -.timestampCell { - overflow: hidden; -}