diff --git a/redisinsight/ui/src/components/import-databases-dialog/ImportDatabasesDialog.spec.tsx b/redisinsight/ui/src/components/import-databases-dialog/ImportDatabasesDialog.spec.tsx index 61be09a4f4..ef6e712a3b 100644 --- a/redisinsight/ui/src/components/import-databases-dialog/ImportDatabasesDialog.spec.tsx +++ b/redisinsight/ui/src/components/import-databases-dialog/ImportDatabasesDialog.spec.tsx @@ -92,31 +92,25 @@ describe('ImportDatabasesDialog', () => { expect(screen.getByTestId('file-loading-indicator')).toBeInTheDocument() }) - it('should render success message when at least 1 database added', () => { + it('should not render error message without error', () => { (importInstancesSelector as jest.Mock).mockImplementation(() => ({ loading: false, - data: { - success: 1, - total: 2 - } + data: {} })) render() - expect(screen.getByTestId('result-success')).toBeInTheDocument() expect(screen.queryByTestId('result-failed')).not.toBeInTheDocument() }) it('should render error message when 0 success databases added', () => { (importInstancesSelector as jest.Mock).mockImplementation(() => ({ loading: false, - data: { - success: 0, - total: 2 - } + data: null, + error: 'Error message' })) render() expect(screen.getByTestId('result-failed')).toBeInTheDocument() - expect(screen.queryByTestId('result-success')).not.toBeInTheDocument() + expect(screen.getByTestId('result-failed')).toHaveTextContent('Error message') }) }) diff --git a/redisinsight/ui/src/components/import-databases-dialog/ImportDatabasesDialog.tsx b/redisinsight/ui/src/components/import-databases-dialog/ImportDatabasesDialog.tsx index 8215352ca8..9187411a36 100644 --- a/redisinsight/ui/src/components/import-databases-dialog/ImportDatabasesDialog.tsx +++ b/redisinsight/ui/src/components/import-databases-dialog/ImportDatabasesDialog.tsx @@ -24,6 +24,7 @@ import { } from 'uiSrc/slices/instances/instances' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { Nullable } from 'uiSrc/utils' +import ResultsLog from './components/ResultsLog' import styles from './styles.module.scss' @@ -49,9 +50,11 @@ const ImportDatabasesDialog = ({ onClose }: Props) => { } const handleOnClose = () => { - dispatch(resetImportInstances()) - data?.success && dispatch(fetchInstancesAction()) + if (data?.success?.length || data?.partial?.length) { + dispatch(fetchInstancesAction()) + } onClose(!data) + dispatch(resetImportInstances()) } const onSubmit = () => { @@ -72,17 +75,17 @@ const ImportDatabasesDialog = ({ onClose }: Props) => { - - Import Database Connections + + {(!data && !error) ? 'Import Database Connections' : 'Import Results'} - + {isShowForm && ( - <> + { File should not exceed {MAX_MB_FILE} MB )} - + )} {loading && ( @@ -107,29 +110,21 @@ const ImportDatabasesDialog = ({ onClose }: Props) => { Uploading... )} - - {data && data.success !== 0 && ( -
- - - Successfully added {data.success} of {data.total} database connections - -
- )} - - {(data?.success === 0 || error) && ( + {data && ()} + {error && (
- + Failed to add database connections + {error}
)}
- {data && data.success !== 0 && ( + {data && ( ({ + ...jest.requireActual('uiSrc/telemetry'), + sendEventTelemetry: jest.fn(), +})) + +const mockedError = { statusCode: 400, message: 'message', error: 'error' } +describe('ResultsLog', () => { + it('should render', () => { + const mockedData = { total: 0, fail: [], partial: [], success: [] } + render() + }) + + it('should be all collapsed nav groups', () => { + const mockedData: ImportDatabasesData = { + total: 3, + fail: [{ index: 0, status: 'fail', errors: [mockedError] }], + partial: [{ index: 2, status: 'fail', errors: [mockedError] }], + success: [{ index: 1, status: 'success', port: 1233, host: 'localhost' }] + } + render() + + expect(screen.getByTestId('success-results-closed')).toBeInTheDocument() + expect(screen.getByTestId('partial-results-closed')).toBeInTheDocument() + expect(screen.getByTestId('failed-results-closed')).toBeInTheDocument() + }) + + it('should open and collapse other groups', () => { + const mockedData: ImportDatabasesData = { + total: 3, + fail: [{ index: 0, status: 'fail', errors: [mockedError] }], + partial: [{ index: 2, status: 'fail', errors: [mockedError] }], + success: [{ index: 1, status: 'success', port: 1233, host: 'localhost' }] + } + render() + + fireEvent.click( + within(screen.getByTestId('success-results-closed')).getByRole('button') + ) + expect(screen.getByTestId('success-results-open')).toBeInTheDocument() + + expect(screen.getByTestId('partial-results-closed')).toBeInTheDocument() + expect(screen.getByTestId('failed-results-closed')).toBeInTheDocument() + + fireEvent.click( + within(screen.getByTestId('failed-results-closed')).getByRole('button') + ) + expect(screen.getByTestId('failed-results-open')).toBeInTheDocument() + + expect(screen.getByTestId('partial-results-closed')).toBeInTheDocument() + expect(screen.getByTestId('success-results-closed')).toBeInTheDocument() + + fireEvent.click( + within(screen.getByTestId('partial-results-closed')).getByRole('button') + ) + expect(screen.getByTestId('partial-results-open')).toBeInTheDocument() + + expect(screen.getByTestId('failed-results-closed')).toBeInTheDocument() + expect(screen.getByTestId('success-results-closed')).toBeInTheDocument() + }) + + it('should show proper items length', () => { + const mockedData: ImportDatabasesData = { + total: 4, + fail: [{ index: 0, status: 'fail', errors: [mockedError] }], + partial: [{ index: 2, status: 'fail', errors: [mockedError] }], + success: [ + { index: 1, status: 'success', port: 1233, host: 'localhost' }, + { index: 3, status: 'success', port: 1233, host: 'localhost' } + ] + } + render() + + expect( + within(screen.getByTestId('success-results-closed')).getByTestId('number-of-dbs') + ).toHaveTextContent('2') + expect( + within(screen.getByTestId('partial-results-closed')).getByTestId('number-of-dbs') + ).toHaveTextContent('1') + expect( + within(screen.getByTestId('failed-results-closed')).getByTestId('number-of-dbs') + ).toHaveTextContent('1') + }) + + it('should call proper telemetry event after click', () => { + const sendEventTelemetryMock = jest.fn(); + (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock) + + const mockedData: ImportDatabasesData = { + total: 3, + fail: [{ index: 0, status: 'fail', errors: [mockedError] }], + partial: [{ index: 2, status: 'fail', errors: [mockedError] }], + success: [{ index: 1, status: 'success', port: 1233, host: 'localhost' }] + } + render() + + fireEvent.click( + within(screen.getByTestId('success-results-closed')).getByRole('button') + ) + + expect(sendEventTelemetry).toBeCalledWith({ + event: TelemetryEvent.CONFIG_DATABASES_REDIS_IMPORT_LOG_VIEWED, + eventData: { + length: 1, + name: 'success' + } + }); + + (sendEventTelemetry as jest.Mock).mockRestore() + + fireEvent.click( + within(screen.getByTestId('success-results-open')).getByRole('button') + ) + + expect(sendEventTelemetry).not.toBeCalled() + }) +}) diff --git a/redisinsight/ui/src/components/import-databases-dialog/components/ResultsLog/ResultsLog.tsx b/redisinsight/ui/src/components/import-databases-dialog/components/ResultsLog/ResultsLog.tsx new file mode 100644 index 0000000000..3a0359445b --- /dev/null +++ b/redisinsight/ui/src/components/import-databases-dialog/components/ResultsLog/ResultsLog.tsx @@ -0,0 +1,87 @@ +import { EuiCollapsibleNavGroup } from '@elastic/eui' +import cx from 'classnames' +import React, { useState } from 'react' + +import { ImportDatabasesData } from 'uiSrc/slices/interfaces' +import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' +import TableResult from '../TableResult' + +import styles from './styles.module.scss' + +enum ResultsStatus { + Success = 'success', + Partial = 'partial', + Failed = 'failed' +} + +export interface Props { + data: ImportDatabasesData +} + +const ResultsLog = ({ data }: Props) => { + const [openedNav, setOpenedNav] = useState('') + + const onToggle = (length: number = 0, isOpen: boolean, name: string) => { + if (length === 0) return + setOpenedNav(isOpen ? name : '') + + if (isOpen) { + sendEventTelemetry({ + event: TelemetryEvent.CONFIG_DATABASES_REDIS_IMPORT_LOG_VIEWED, + eventData: { + length, + name + } + }) + } + } + + const CollapsibleNavTitle = ({ title, length = 0 }: { title: string, length: number }) => ( +
+ {title} + {length} +
+ ) + + const getNavGroupState = (name: ResultsStatus) => (openedNav === name ? 'open' : 'closed') + + return ( + <> + } + className={cx(styles.collapsibleNav, ResultsStatus.Success, { [styles.disabled]: !data?.success?.length })} + isCollapsible + initialIsOpen={false} + onToggle={(isOpen) => onToggle(data?.success?.length, isOpen, ResultsStatus.Success)} + forceState={getNavGroupState(ResultsStatus.Success)} + data-testid={`success-results-${getNavGroupState(ResultsStatus.Success)}`} + > + + + } + className={cx(styles.collapsibleNav, ResultsStatus.Partial, { [styles.disabled]: !data?.partial?.length })} + isCollapsible + initialIsOpen={false} + onToggle={(isOpen) => onToggle(data?.partial?.length, isOpen, ResultsStatus.Partial)} + forceState={getNavGroupState(ResultsStatus.Partial)} + data-testid={`partial-results-${getNavGroupState(ResultsStatus.Partial)}`} + > + + + } + className={cx(styles.collapsibleNav, ResultsStatus.Failed, { [styles.disabled]: !data?.fail?.length })} + isCollapsible + initialIsOpen={false} + onToggle={(isOpen) => onToggle(data?.fail?.length, isOpen, ResultsStatus.Failed)} + forceState={getNavGroupState(ResultsStatus.Failed)} + data-testid={`failed-results-${getNavGroupState(ResultsStatus.Failed)}`} + > + + + + ) +} + +export default ResultsLog diff --git a/redisinsight/ui/src/components/import-databases-dialog/components/ResultsLog/index.ts b/redisinsight/ui/src/components/import-databases-dialog/components/ResultsLog/index.ts new file mode 100644 index 0000000000..1eb9fdbb50 --- /dev/null +++ b/redisinsight/ui/src/components/import-databases-dialog/components/ResultsLog/index.ts @@ -0,0 +1,3 @@ +import ResultsLog from './ResultsLog' + +export default ResultsLog diff --git a/redisinsight/ui/src/components/import-databases-dialog/components/ResultsLog/styles.module.scss b/redisinsight/ui/src/components/import-databases-dialog/components/ResultsLog/styles.module.scss new file mode 100644 index 0000000000..8ce336e68f --- /dev/null +++ b/redisinsight/ui/src/components/import-databases-dialog/components/ResultsLog/styles.module.scss @@ -0,0 +1,85 @@ +.collapsibleNav { + width: 100%; + margin-top: 5px !important; + position: relative; + + &.disabled { + :global { + .euiAccordion__button { + cursor: auto; + pointer-events: none; + } + .euiAccordion__iconWrapper { + display: none; + } + } + } + + &:global(.euiAccordion-isOpen) { + :global { + .euiAccordion__triggerWrapper { + border-radius: 0; + border-color: transparent; + } + } + } + + &:global(.success) { + &:before { + background-color: var(--successBorderColor); + } + } + + &:global(.partial) { + &:before { + background-color: var(--warningBorderColor); + } + } + + &:global(.failed) { + &:before { + background-color: var(--errorBorderColor); + } + } + + &:before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 4px; + + border-radius: 4px 0 0 4px; + + z-index: 2; + } + + :global { + .euiCollapsibleNavGroup__title { + font-size: 12px !important; + font-weight: 400 !important; + color: var(--euiTextSubduedColor) !important; + } + .euiAccordion__triggerWrapper { + background-color: var(--euiColorEmptyShade); + padding: 12px 24px 12px 32px !important; + border-radius: 4px; + border: 1px solid var(--separatorColor); + } + .euiCollapsibleNavGroup__children { + padding: 0 !important; + } + + .euiIEFlexWrapFix { + flex-grow: 1; + padding-right: 4px; + } + } +} + +.collapsibleNavTitle { + display: flex; + justify-content: space-between; + align-items: center; +} diff --git a/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/TableResult.spec.tsx b/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/TableResult.spec.tsx new file mode 100644 index 0000000000..84aaded8a5 --- /dev/null +++ b/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/TableResult.spec.tsx @@ -0,0 +1,46 @@ +import React from 'react' +import { render, screen } from 'uiSrc/utils/test-utils' +import TableResult from './TableResult' + +const mockedError = { statusCode: 400, message: 'message', error: 'error' } + +describe('TableResult', () => { + it('should render', () => { + render() + }) + + it('should not render table for empty data', () => { + render() + + expect(screen.queryByTestId('result-log-table')).not.toBeInTheDocument() + }) + + it('should render table data with success messages', () => { + render( + + ) + + expect(screen.getByTestId('table-index-0')).toHaveTextContent('(0)') + expect(screen.getByTestId('table-index-1')).toHaveTextContent('(1)') + expect(screen.getByTestId('table-host-port-0')).toHaveTextContent('localhost:1233') + expect(screen.getByTestId('table-host-port-1')).toHaveTextContent('localhost2:5233') + expect(screen.getByTestId('table-result-0')).toHaveTextContent('Successful') + expect(screen.getByTestId('table-result-1')).toHaveTextContent('Successful') + }) + + it('should render table data with error messages', () => { + render( + + ) + expect(screen.getByTestId('table-result-0')).toHaveTextContent([mockedError, mockedError].map((e) => e.message).join('')) + expect(screen.getByTestId('table-result-1')).toHaveTextContent([mockedError].map((e) => e.message).join('')) + }) +}) diff --git a/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/TableResult.tsx b/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/TableResult.tsx new file mode 100644 index 0000000000..5fd5b112d4 --- /dev/null +++ b/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/TableResult.tsx @@ -0,0 +1,74 @@ +import { EuiBasicTableColumn, EuiInMemoryTable } from '@elastic/eui' +import cx from 'classnames' +import React from 'react' + +import { ErrorImportResult } from 'uiSrc/slices/interfaces' +import { Maybe } from 'uiSrc/utils' + +import styles from './styles.module.scss' + +export interface DataImportResult { + index: number + status: string + errors?: Array + host?: string + port?: number +} +export interface Props { + data: Array +} + +const TableResult = (props: Props) => { + const { data } = props + + const ErrorResult = ({ errors }: { errors: string[] }) => ( +
    + {errors.map((message, i) => ( +
  • {message}
  • + ))} +
+ ) + + const columns: EuiBasicTableColumn[] = [ + { + name: '#', + field: 'index', + width: '4%', + render: (index: number) => (({index})) + }, + { + name: 'Host:Port', + field: 'host', + width: '25%', + truncateText: true, + render: (_host, { host, port, index }) => (
{host}:{port}
) + }, + { + name: 'Result', + field: 'errors', + width: '25%', + render: (errors: Maybe, { index }) => ( +
+ {errors ? ( e.message)} />) : 'Successful'} +
+ ) + } + ] + + if (data?.length === 0) return null + + return ( +
+ +
+ ) +} + +export default TableResult diff --git a/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/index.ts b/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/index.ts new file mode 100644 index 0000000000..9e622e5f46 --- /dev/null +++ b/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/index.ts @@ -0,0 +1,3 @@ +import TableResult from './TableResult' + +export default TableResult diff --git a/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/styles.module.scss b/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/styles.module.scss new file mode 100644 index 0000000000..dad38b82f2 --- /dev/null +++ b/redisinsight/ui/src/components/import-databases-dialog/components/TableResult/styles.module.scss @@ -0,0 +1,29 @@ +@import "@elastic/eui/src/global_styling/mixins/helpers"; +@import "@elastic/eui/src/components/table/mixins"; +@import "@elastic/eui/src/global_styling/index"; + +.tableWrapper { + max-height: 200px; + @include euiScrollBar; + + overflow: auto; + + .table { + :global { + .euiTableHeaderCell { + background-color: var(--browserTableRowEven); + } + + .euiTableRowCell { + vertical-align: top !important; + } + + .euiTableCellContent { + white-space: normal !important; + font-size: 12px !important; + padding: 8px 14px; + } + } + } + +} diff --git a/redisinsight/ui/src/components/import-databases-dialog/styles.module.scss b/redisinsight/ui/src/components/import-databases-dialog/styles.module.scss index 3f240cd6bf..8fda92df89 100644 --- a/redisinsight/ui/src/components/import-databases-dialog/styles.module.scss +++ b/redisinsight/ui/src/components/import-databases-dialog/styles.module.scss @@ -1,11 +1,12 @@ .modal { background: var(--euiColorLightestShade) !important; min-width: 500px !important; + max-width: 700px !important; min-height: 270px !important; :global { .euiModalHeader { - padding: 4px 42px 42px 30px; + padding: 4px 42px 20px 30px; } .euiModalBody__overflow { diff --git a/redisinsight/ui/src/slices/instances/instances.ts b/redisinsight/ui/src/slices/instances/instances.ts index d523757f91..7fc52c2789 100644 --- a/redisinsight/ui/src/slices/instances/instances.ts +++ b/redisinsight/ui/src/slices/instances/instances.ts @@ -544,7 +544,6 @@ export function uploadInstancesFile( } catch (error) { const errorMessage = getApiErrorMessage(error) dispatch(importInstancesFromFileFailure(errorMessage)) - dispatch(addErrorNotification(error)) onFailAction?.() } } diff --git a/redisinsight/ui/src/slices/interfaces/instances.ts b/redisinsight/ui/src/slices/interfaces/instances.ts index 538900f412..61234c9b6a 100644 --- a/redisinsight/ui/src/slices/interfaces/instances.ts +++ b/redisinsight/ui/src/slices/interfaces/instances.ts @@ -285,13 +285,38 @@ export interface InitialStateInstances { importInstances: { loading: boolean error: string - data: Nullable<{ - success: number, - total: number - }> + data: Nullable } } +export interface ErrorImportResult { + statusCode: number + message: string + error: string +} + +export interface ImportDatabasesData { + fail: Array + partial: Array + success: Array + total: number +} + +export interface FailedImportStatusResult { + host?: string + port?: number + index: number + errors: Array + status: string +} + +export interface SuccessImportStatusResult { + host: string + port: number + index: number + status: string +} + export interface InitialStateEditedInstances { loading: boolean error: string diff --git a/redisinsight/ui/src/slices/tests/instances/instances.spec.ts b/redisinsight/ui/src/slices/tests/instances/instances.spec.ts index d148825388..24a5cff3dc 100644 --- a/redisinsight/ui/src/slices/tests/instances/instances.spec.ts +++ b/redisinsight/ui/src/slices/tests/instances/instances.spec.ts @@ -47,7 +47,8 @@ import reducer, { importInstancesFromFileSuccess, importInstancesFromFileFailure, resetImportInstances, - importInstancesSelector, uploadInstancesFile + importInstancesSelector, + uploadInstancesFile } from '../../instances/instances' import { addErrorNotification, addMessageNotification, IAddInstanceErrorPayload } from '../../app/notifications' import { ConnectionType, InitialStateInstances, Instance } from '../../interfaces' @@ -542,9 +543,12 @@ describe('instances slice', () => { describe('importInstancesFromFileSuccess', () => { it('should properly set state', () => { // Arrange + const mockedError = { statusCode: 400, message: 'message', error: 'error' } const data = { - success: 3, - total: 5 + total: 3, + fail: [{ index: 0, status: 'fail', errors: [mockedError] }], + partial: [{ index: 2, status: 'fail', errors: [mockedError] }], + success: [{ index: 1, status: 'success', port: 1233, host: 'localhost' }] } const state = { ...initialState.importInstances, @@ -591,13 +595,16 @@ describe('instances slice', () => { describe('resetImportInstances', () => { it('should properly set state', () => { // Arrange + const mockedError = { statusCode: 400, message: 'message', error: 'error' } const currentState = { ...initialState, importInstances: { ...initialState.importInstances, data: { - success: 1, - total: 2 + total: 3, + fail: [{ index: 0, status: 'fail', errors: [mockedError] }], + partial: [{ index: 2, status: 'fail', errors: [mockedError] }], + success: [{ index: 1, status: 'success', port: 1233, host: 'localhost' }] } } } @@ -1110,9 +1117,12 @@ describe('instances slice', () => { it('should call proper actions on success', async () => { // Arrange const formData = new FormData() + const mockedError = { statusCode: 400, message: 'message', error: 'error' } const data = { - success: 0, - total: 1 + total: 3, + fail: [{ index: 0, status: 'fail', errors: [mockedError] }], + partial: [{ index: 2, status: 'fail', errors: [mockedError] }], + success: [{ index: 1, status: 'success', port: 1233, host: 'localhost' }] } const responsePayload = { data, status: 200 } @@ -1150,7 +1160,6 @@ describe('instances slice', () => { const expectedActions = [ importInstancesFromFile(), importInstancesFromFileFailure(responsePayload.response.data.message), - addErrorNotification(responsePayload as AxiosError), ] expect(store.getActions()).toEqual(expectedActions) }) diff --git a/redisinsight/ui/src/styles/components/_table.scss b/redisinsight/ui/src/styles/components/_table.scss index b5173ee337..9b6aba7b3d 100644 --- a/redisinsight/ui/src/styles/components/_table.scss +++ b/redisinsight/ui/src/styles/components/_table.scss @@ -62,7 +62,7 @@ table { overflow: hidden; } - &.noHeaderBorders { + &.noHeaderBorders, &.noBorders { .euiTableRow { &:not(:first-child) { .euiTableRowCell { @@ -81,6 +81,35 @@ table { } } + &.noBorders { + .euiTableCaption { + height: 0; + } + .euiTableRowCell { + border-top: 0; + } + .euiTableRow:nth-child(odd) { + td { + &:first-child { + border-left: 1px solid var(--euiColorEmptyShade); + } + &:last-child { + border-right: 1px solid var(--euiColorEmptyShade); + } + } + } + .euiTableRow:nth-child(even) { + td { + &:first-child { + border-left: 1px solid var(--browserTableRowEven); + } + &:last-child { + border-right: 1px solid var(--browserTableRowEven); + } + } + } + } + &.stickyHeader { .euiTableHeaderCell { position: sticky; diff --git a/redisinsight/ui/src/styles/themes/dark_theme/_dark_theme.lazy.scss b/redisinsight/ui/src/styles/themes/dark_theme/_dark_theme.lazy.scss index 2dee6e4865..4311b3f876 100644 --- a/redisinsight/ui/src/styles/themes/dark_theme/_dark_theme.lazy.scss +++ b/redisinsight/ui/src/styles/themes/dark_theme/_dark_theme.lazy.scss @@ -131,6 +131,10 @@ --monacoBgColor: #{$monacoBgColor}; + --successBorderColor: #{$successBorderColor}; + --warningBorderColor: #{$warningBorderColor}; + --errorBorderColor: #{$errorBorderColor}; + // KeyTypes --typeHashColor: #{$typeHashColor}; --typeListColor: #{$typeListColor}; diff --git a/redisinsight/ui/src/styles/themes/dark_theme/_theme_color.scss b/redisinsight/ui/src/styles/themes/dark_theme/_theme_color.scss index bcfb32c4f2..f17f38159a 100644 --- a/redisinsight/ui/src/styles/themes/dark_theme/_theme_color.scss +++ b/redisinsight/ui/src/styles/themes/dark_theme/_theme_color.scss @@ -91,6 +91,10 @@ $overlayPromoNYColor: #0000001a; $monacoBgColor: #111; +$successBorderColor: #13A450; +$warningBorderColor: #9D6901; +$errorBorderColor: #AD0017; + // Types colors $typeHashColor: #364cff; $typeListColor: #008556; diff --git a/redisinsight/ui/src/styles/themes/light_theme/_light_theme.lazy.scss b/redisinsight/ui/src/styles/themes/light_theme/_light_theme.lazy.scss index a9fbfa450e..0d0b4ae649 100644 --- a/redisinsight/ui/src/styles/themes/light_theme/_light_theme.lazy.scss +++ b/redisinsight/ui/src/styles/themes/light_theme/_light_theme.lazy.scss @@ -133,6 +133,10 @@ --monacoBgColor: #{$monacoBgColor}; + --successBorderColor: #{$successBorderColor}; + --warningBorderColor: #{$warningBorderColor}; + --errorBorderColor: #{$errorBorderColor}; + // KeyTypes --typeHashColor: #{$typeHashColor}; --typeListColor: #{$typeListColor}; diff --git a/redisinsight/ui/src/styles/themes/light_theme/_theme_color.scss b/redisinsight/ui/src/styles/themes/light_theme/_theme_color.scss index e925a43fe6..3683d216f7 100644 --- a/redisinsight/ui/src/styles/themes/light_theme/_theme_color.scss +++ b/redisinsight/ui/src/styles/themes/light_theme/_theme_color.scss @@ -88,6 +88,10 @@ $overlayPromoNYColor: #ffffff1a; $monacoBgColor: #f0f2f7; +$successBorderColor: #5BC69B; +$warningBorderColor: #FFAF2B; +$errorBorderColor: #F74B57; + // Types colors $typeHashColor: #cdddf8; $typeListColor: #a5d4c3; diff --git a/redisinsight/ui/src/telemetry/events.ts b/redisinsight/ui/src/telemetry/events.ts index 1185656b4c..435ae4db64 100644 --- a/redisinsight/ui/src/telemetry/events.ts +++ b/redisinsight/ui/src/telemetry/events.ts @@ -30,6 +30,7 @@ export enum TelemetryEvent { CONFIG_DATABASES_REDIS_IMPORT_SUBMITTED = 'CONFIG_DATABASES_REDIS_IMPORT_SUBMITTED', CONFIG_DATABASES_REDIS_IMPORT_CANCELLED = 'CONFIG_DATABASES_REDIS_IMPORT_CANCELLED', CONFIG_DATABASES_REDIS_IMPORT_CLICKED = 'CONFIG_DATABASES_REDIS_IMPORT_CLICKED', + CONFIG_DATABASES_REDIS_IMPORT_LOG_VIEWED = 'CONFIG_DATABASES_REDIS_IMPORT_LOG_VIEWED', BUILD_FROM_SOURCE_CLICKED = 'BUILD_FROM_SOURCE_CLICKED', BUILD_USING_DOCKER_CLICKED = 'BUILD_USING_DOCKER_CLICKED',